diff --git a/.idea/modules/ChameleonMiniLiveDebugger.main.iml b/.idea/modules/ChameleonMiniLiveDebugger.main.iml new file mode 100644 index 0000000..b3e2629 --- /dev/null +++ b/.idea/modules/ChameleonMiniLiveDebugger.main.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/ChameleonMiniLiveDebugger.test.iml b/.idea/modules/ChameleonMiniLiveDebugger.test.iml new file mode 100644 index 0000000..db7f9be --- /dev/null +++ b/.idea/modules/ChameleonMiniLiveDebugger.test.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/app/ChameleonMiniLiveDebugger.app.androidTest.iml b/.idea/modules/app/ChameleonMiniLiveDebugger.app.androidTest.iml new file mode 100644 index 0000000..cdb62d1 --- /dev/null +++ b/.idea/modules/app/ChameleonMiniLiveDebugger.app.androidTest.iml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/app/ChameleonMiniLiveDebugger.app.main.iml b/.idea/modules/app/ChameleonMiniLiveDebugger.app.main.iml new file mode 100644 index 0000000..6f329db --- /dev/null +++ b/.idea/modules/app/ChameleonMiniLiveDebugger.app.main.iml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules/app/ChameleonMiniLiveDebugger.app.unitTest.iml b/.idea/modules/app/ChameleonMiniLiveDebugger.app.unitTest.iml new file mode 100644 index 0000000..b978245 --- /dev/null +++ b/.idea/modules/app/ChameleonMiniLiveDebugger.app.unitTest.iml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index e813bb8..4d24473 100755 --- a/app/build.gradle +++ b/app/build.gradle @@ -92,12 +92,13 @@ clean.dependsOn cleanPreBuildGenAntlr4JavaSources android { def configBuildTimeStamp = getDateTimestamp() + defaultConfig { applicationId "com.maxieds.chameleonminilivedebugger" - versionCode 120 + 8080 - versionName "1.5.0" + versionCode 121 + 8080 + versionName "1.5.1" minSdkVersion 26 targetSdkVersion 30 @@ -107,6 +108,7 @@ android { buildConfigField "String", "GIT_COMMIT_HASH", "\"" + getGitCommitHash() + "\"" buildConfigField "String", "GIT_COMMIT_DATE", "\"" + getGitCommitDate() + "\"" + buildConfigField "java.util.Locale", "DEFAULT_LOCALE", "java.util.Locale.ENGLISH" setProperty("archivesBaseName", "ChameleonMiniLiveDebugger-v$versionName-$versionCode-$configBuildTimeStamp") @@ -133,12 +135,18 @@ android { } + aaptOptions { + + noCompress '...' + + } + buildTypes { release { minifyEnabled true - shrinkResources true + shrinkResources false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' crunchPngs false debuggable false @@ -163,12 +171,12 @@ android { free { - versionNameSuffix "-free" + versionNameSuffix "-free" + dimension "mode" - buildConfigField "boolean", "PAID_APP_VERSION", "false" - buildConfigField "boolean", "REPORT_CRASHES", "false" buildConfigField "String", "BUILD_TIMESTAMP", "\"" + configBuildTimeStamp + "\"" + buildConfigField "boolean", "PAID_APP_VERSION", "false" resConfigs 'en', 'en_US', 'en_UK', 'de', 'fr', 'ru' @@ -178,7 +186,8 @@ android { appRoundIcon : "@mipmap/chameleon_app_icon_round", appTheme : "@style/AppThemeGreen", appDebug : "false", - installLocation : "preferExternal" + bluetoothRequired : "false", + installLocation : "auto" ] } @@ -186,22 +195,22 @@ android { paid { applicationIdSuffix ".paid" - versionNameSuffix "-paid" + versionNameSuffix "-paid" + + dimension "mode" - buildConfigField "boolean", "PAID_APP_VERSION", "true" - buildConfigField "boolean", "REPORT_CRASHES", "false" buildConfigField "String", "BUILD_TIMESTAMP", "\"" + configBuildTimeStamp + "\"" + buildConfigField "boolean", "PAID_APP_VERSION", "true" resConfigs 'en', 'en_US', 'en_UK', 'de', 'fr', 'ru' - dimension "mode" - manifestPlaceholders = [ appLabelDesc : "@string/app_display_short_name_paid", appIcon : "@mipmap/chameleon_app_icon_round_paid", appRoundIcon : "@mipmap/chameleon_app_icon_round_paid", appTheme : "@style/AppThemeGreenPaid", appDebug : "false", + bluetoothRequired : "false", installLocation : "auto" ] diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 07ea7bb..6fdd04c 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -89,28 +89,103 @@ + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + @@ -212,8 +292,12 @@ android:clearTaskOnLaunch="true" android:hardwareAccelerated="true" android:uiOptions="none" + android:configChanges="uiMode" android:stateNotNeeded="true" android:exported="true" + android:resizeableActivity="false" + android:maxAspectRatio="2.4" + android:supportsPictureInPicture="false" > diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidFileChooser.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidFileChooser.java index 943e0b1..fa15c75 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidFileChooser.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidFileChooser.java @@ -20,7 +20,6 @@ This program (The Chameleon Mini Live Debugger) is free software written by import android.content.Intent; import android.os.Looper; import android.provider.Settings; -import android.util.Log; import androidx.annotation.NonNull; @@ -29,8 +28,6 @@ This program (The Chameleon Mini Live Debugger) is free software written by import com.maxieds.androidfilepickerlightlibrary.FileChooserBuilder; import com.maxieds.androidfilepickerlightlibrary.FileUtils; -import java.util.Locale; - public class AndroidFileChooser { private static final String TAG = AndroidFileChooser.class.getSimpleName(); @@ -141,7 +138,7 @@ public static String runFileChooserForResult(FileChooserBuilder.SelectionModeTyp Looper.loop(); } catch(RuntimeException ie) { String excptMsg = ie.getMessage(); - String replaceRegex = String.format(Locale.getDefault(), getFileNotifySelectExceptionFormat(), ""); + String replaceRegex = String.format(BuildConfig.DEFAULT_LOCALE, getFileNotifySelectExceptionFormat(), ""); String[] excptMsgComponents = excptMsg.split(replaceRegex); if(excptMsgComponents.length != 2) { AndroidLog.i(TAG, "USER SELECTED <__NO__> PATH! ... " + ie.getMessage()); @@ -154,7 +151,7 @@ public static String runFileChooserForResult(FileChooserBuilder.SelectionModeTyp } String fileChooserBaseFolder = getInitialFileChooserBaseFolder(); excptMsg = excptMsg.replaceFirst(fileChooserBaseFolder, STORAGE_HOME_PREFIX_SUBST); - excptMsg = excptMsg.replaceAll(String.format(Locale.getDefault(), "[%s]+", PATH_SEP), "/"); + excptMsg = excptMsg.replaceAll(String.format(BuildConfig.DEFAULT_LOCALE, "[%s]+", PATH_SEP), "/"); AndroidLog.i(TAG, "USER SELECTED PATH: \"" + excptMsg + "\" ..."); return excptMsg; } @@ -181,7 +178,7 @@ public static boolean isFileContentsTextBased(String filePath) { } String fileMimeType = docRef.getDocumentType(); AndroidLog.i(TAG, "MIME TYPE: " + fileMimeType); - return fileMimeType.toLowerCase(Locale.getDefault()).startsWith("text"); + return fileMimeType.toLowerCase(BuildConfig.DEFAULT_LOCALE).startsWith("text"); } catch(Exception ex) { AndroidLog.printStackTrace(ex); return false; diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidLog.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidLog.java index 5f99fb8..ef431f8 100644 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidLog.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidLog.java @@ -211,7 +211,7 @@ public static String downloadCurrentLogFile(boolean updateGUIWithStatus) { private static final int LINE_WRAP_CHARACTERS = 80; private static String wrapDataAt(String linePrefix, String data) { - Locale defaultLocale = Locale.getDefault(); + Locale defaultLocale = BuildConfig.DEFAULT_LOCALE; int lineWrapNumChars = (int) (LINE_WRAP_CHARACTERS - linePrefix.length()); String wrapRegexFmt = String.format(defaultLocale, ".{%d}(?=.)", lineWrapNumChars); String replaceLineFmt = String.format(defaultLocale, "%s$0\n", linePrefix); @@ -238,7 +238,7 @@ private static void logAtLevel(LogLevel level, String tag, String msg) { String logTimeStamp = Utils.getTimestamp(); String logLevelDesc = level.name(); StringBuilder logDataBuilder = new StringBuilder(); - Locale defaultLocale = Locale.getDefault(); + Locale defaultLocale = BuildConfig.DEFAULT_LOCALE; logDataBuilder.append(String.format(defaultLocale, "%s LOG ENTRY @ %s\n", LOGDATA_START_ENTRY_DELIMITER, logTimeStamp)); logDataBuilder.append(String.format(defaultLocale, "%s LEVEL %s / %s\n", LOGDATA_ITEM_DELIMITER, logLevelDesc, tag)); logDataBuilder.append(String.format(defaultLocale, wrapDataAt(msg))); @@ -280,7 +280,7 @@ public static void printStackTrace(@NonNull Exception e) { PrintStream outStream = openLogDataOutputFile(); if(outStream != null) { String excptTimeStamp = Utils.getTimestamp(); - String excptMsgPrefix = String.format(Locale.getDefault(), "%s EXCEPTION STACK TRACE @ %s\n\n", LOGDATA_START_ENTRY_DELIMITER, excptTimeStamp); + String excptMsgPrefix = String.format(BuildConfig.DEFAULT_LOCALE, "%s EXCEPTION STACK TRACE @ %s\n\n", LOGDATA_START_ENTRY_DELIMITER, excptTimeStamp); outStream.print(excptMsgPrefix); outStream.flush(); e.printStackTrace(outStream); diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidSettingsStorage.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidSettingsStorage.java index ac1254d..560aa55 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidSettingsStorage.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/AndroidSettingsStorage.java @@ -383,7 +383,7 @@ else if(prefsKey.equals(PROFILE_SERIALID_PREFERENCE)) { return sharedPrefs.getString(prefsKey, ChameleonSettings.chameleonDeviceSerialNumber); } else if(prefsKey.equals(SERIAL_BAUDRATE_PREFERENCE)) { - return String.format(Locale.getDefault(), "%d", sharedPrefs.getInt(prefsKey, ChameleonSettings.serialBaudRate)); + return String.format(BuildConfig.DEFAULT_LOCALE, "%d", sharedPrefs.getInt(prefsKey, ChameleonSettings.serialBaudRate)); } else if(prefsKey.equals(ALLOW_USB_PREFERENCE)) { return sharedPrefs.getBoolean(prefsKey, ChameleonSettings.allowWiredUSB) ? "true" : "false"; @@ -395,20 +395,20 @@ else if(prefsKey.equals(BLUETOOTH_DEVICE_PIN_DATA)) { return sharedPrefs.getString(prefsKey, new String(BluetoothGattConnector.btDevicePinDataBytes, StandardCharsets.UTF_8)); } else if(prefsKey.equals(SNIFFING_MODE_PREFERENCE)) { - return String.format(Locale.getDefault(), "%d", sharedPrefs.getInt(prefsKey, ChameleonSettings.sniffingMode)); + return String.format(BuildConfig.DEFAULT_LOCALE, "%d", sharedPrefs.getInt(prefsKey, ChameleonSettings.sniffingMode)); } else if(prefsKey.equals(CWD_PREFERENCE)) { sharedPrefs.getString(prefsKey, ExternalFileIO.CURRENT_WORKING_DIRECTORY); } else if(prefsKey.equals(LAST_TAB_INDEX_PREFERENCE)) { - return String.format(Locale.getDefault(), "%d", sharedPrefs.getInt(prefsKey, LiveLoggerActivity.getSelectedTab())); + return String.format(BuildConfig.DEFAULT_LOCALE, "%d", sharedPrefs.getInt(prefsKey, LiveLoggerActivity.getSelectedTab())); } else if(prefsKey.equals(LAST_TAB_SUBMENU_INDEX_PREFERENCE)) { int submenuIndex = TabFragment.UITAB_DATA[LiveLoggerActivity.getSelectedTab()].lastMenuIndex; - return String.format(Locale.getDefault(), "%d", sharedPrefs.getInt(prefsKey, submenuIndex)); + return String.format(BuildConfig.DEFAULT_LOCALE, "%d", sharedPrefs.getInt(prefsKey, submenuIndex)); } else if(prefsKey.equals(LOGGING_MIN_DATA_BYTES)) { - return String.format(Locale.getDefault(), "%d", sharedPrefs.getInt(prefsKey, 0)); + return String.format(BuildConfig.DEFAULT_LOCALE, "%d", sharedPrefs.getInt(prefsKey, 0)); } else if(prefsKey.equals(LOGGING_CONFIG_CLEAR_LOGS_ON_NEW_DEVICE)) { return sharedPrefs.getBoolean(prefsKey, ChameleonLogUtils.CONFIG_CLEAR_LOGS_NEW_DEVICE_CONNNECT) ? "true" : "false"; @@ -432,7 +432,7 @@ else if(prefsKey.equals(LOGGING_CONFIG_WRITE_LOGDATA_TO_FILE)) { return sharedPrefs.getBoolean(prefsKey, AndroidLog.WRITE_LOGDATA_TO_FILE) ? "true" : "false"; } else if(prefsKey.equals(LOGGING_CONFIG_LOGDATA_LEVEL_THRESHOLD)) { - return String.format(Locale.getDefault(), "%d", sharedPrefs.getInt(prefsKey, AndroidLog.LOGDATA_LEVEL_THRESHOLD.ordinal())); + return String.format(BuildConfig.DEFAULT_LOCALE, "%d", sharedPrefs.getInt(prefsKey, AndroidLog.LOGDATA_LEVEL_THRESHOLD.ordinal())); } else if(prefsKey.equals(SCRIPTING_CONFIG_SAVE_CONSOLE_OUTPUT_FILE)) { return sharedPrefs.getBoolean(prefsKey, ScriptingConfig.SAVE_CONSOLE_OUTPUT_FILE) ? "true" : "false"; @@ -501,7 +501,7 @@ else if(prefsKey.equals(SCRIPTING_CONFIG_LIMIT_SCRIPT_EXEC_TIME)) { return sharedPrefs.getBoolean(prefsKey, ScriptingConfig.DEFAULT_LIMIT_SCRIPT_EXEC_TIME) ? "true" : "false"; } else if(prefsKey.equals(SCRIPTING_CONFIG_LIMIT_SCRIPT_EXEC_TIME_SECONDS)) { - return String.format(Locale.getDefault(), "%d", sharedPrefs.getInt(prefsKey, ScriptingConfig.DEFAULT_LIMIT_SCRIPT_EXEC_TIME_SECONDS)); + return String.format(BuildConfig.DEFAULT_LOCALE, "%d", sharedPrefs.getInt(prefsKey, ScriptingConfig.DEFAULT_LIMIT_SCRIPT_EXEC_TIME_SECONDS)); } return null; } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ApduGUITools.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ApduGUITools.java index f2463dc..5eaf2de 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ApduGUITools.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ApduGUITools.java @@ -132,7 +132,7 @@ public static void searchAPDUDatabase(String searchText) { LinearLayout layoutList = (LinearLayout) ((ScrollView) ApduUtils.tabView.findViewById(R.id.apduSearchResultsScrollView)).getChildAt(0); for(int cmd = 0; cmd < ApduUtils.fullInsList.length; cmd++) { String summaryStr = ApduUtils.fullInsList[cmd].getSummary(); - if(summaryStr.toLowerCase(Locale.getDefault()).contains(searchText)) { + if(summaryStr.toLowerCase(BuildConfig.DEFAULT_LOCALE).contains(searchText)) { LinearLayout searchResult = (LinearLayout) LiveLoggerActivity.defaultInflater.inflate(R.layout.apdu_search_item, null); if(searchResult != null) { String[] cmdDescParts = ApduUtils.fullInsList[cmd].apduCmdDesc.split("[\\(\\)]"); diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/BluetoothSerialInterface.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/BluetoothBLEInterface.java similarity index 52% rename from app/src/main/java/com/maxieds/chameleonminilivedebugger/BluetoothSerialInterface.java rename to app/src/main/java/com/maxieds/chameleonminilivedebugger/BluetoothBLEInterface.java index 5046cc0..aaae963 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/BluetoothSerialInterface.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/BluetoothBLEInterface.java @@ -17,150 +17,81 @@ This program (The Chameleon Mini Live Debugger) is free software written by package com.maxieds.chameleonminilivedebugger; +import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; +import android.os.Build; import android.os.Handler; -import android.util.Log; import android.webkit.WebSettings; import android.webkit.WebView; -import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; +import androidx.core.app.ActivityCompat; import java.io.IOException; -import java.util.HashMap; import java.util.Locale; -import java.util.Map; import java.util.concurrent.Semaphore; -public class BluetoothSerialInterface extends SerialIOReceiver { +public class BluetoothBLEInterface extends SerialIOReceiver { - /** - * TODO: Check XModem functionality with the BT devices - * TODO: On connect, update the device serial HW/MAC - */ + /* TODO: Check XModem functionality with the BT devices */ - private static final String TAG = BluetoothSerialInterface.class.getSimpleName(); - - /* TODO: Is this enum / state tracking code needed ??? */ - public enum ChameleonBluetoothDeviceState { - - BTDEV_STATE_ERROR(0), - BTDEV_STATE_DISABLED_OFF(1), - BTDEV_STATE_DISCONNECTED(2), - BTDEV_STATE_IDLE(3), - BTDEV_STATE_AVAILABLE_INIT(4), - BTDEV_STATE_AVAILABLE_CONNECTING_ABTN(5), - BTDEV_STATE_AVAILABLE_CONNECTING_BLE(6), - BTDEV_STATE_ACTIVE(7), - BTDEV_STATE_HALTING(8); - - public static final int BTDEV_STATE_COUNT = ChameleonBluetoothDeviceState.values().length; - - public static final Map BTDEV_STATE_MAP = new HashMap<>(); - static { - for (BluetoothSerialInterface.ChameleonBluetoothDeviceState btDevState : values()) { - Integer levelOrdering = Integer.valueOf(btDevState.getStateLevelOrdering()); - BTDEV_STATE_MAP.put(levelOrdering, btDevState); - } - } - - private int stateLevel; - ChameleonBluetoothDeviceState(int level) { - stateLevel = level; - } - - public int getStateLevelOrdering() { - return this.stateLevel; - } - - public static ChameleonBluetoothDeviceState getStateFromLevelOrdering(int inputLevel) { - inputLevel = inputLevel % ChameleonBluetoothDeviceState.BTDEV_STATE_COUNT; - if(inputLevel < 0 || inputLevel >= ChameleonBluetoothDeviceState.BTDEV_STATE_COUNT) { - return null; - } - int inputLevelKey = Integer.valueOf(inputLevel); - return BTDEV_STATE_MAP.get(inputLevelKey); - } - - public boolean isBeforeNextStateInSequence(ChameleonBluetoothDeviceState nextState) { - int readyStateLevel = 0; - int haltStateLevel = Math.max(0, ChameleonBluetoothDeviceState.BTDEV_STATE_COUNT - 1); - int curStateLevel = getStateLevelOrdering(); - int nextStateLevel = nextState.getStateLevelOrdering(); - if(nextStateLevel == haltStateLevel && curStateLevel == readyStateLevel) { - return true; - } else if(nextStateLevel >= haltStateLevel) { - return false; - } else if(curStateLevel >= nextStateLevel) { - return false; - } else if(nextStateLevel > curStateLevel) { - return true; - } else { - return false; - } - } - - public boolean isAfterNextStateInSequence(ChameleonBluetoothDeviceState nextState) { - return getStateLevelOrdering() != nextState.getStateLevelOrdering() && !isBeforeNextStateInSequence(nextState); - } - - public boolean isEqualInSequence(ChameleonBluetoothDeviceState nextState) { - return getStateLevelOrdering() != nextState.getStateLevelOrdering(); - } - - } + private static final String TAG = BluetoothBLEInterface.class.getSimpleName(); public static final int ACTVITY_REQUEST_BLUETOOTH_ENABLED_CODE = 0x00B1; public static final int ACTVITY_REQUEST_BLUETOOTH_DISCOVERABLE_CODE = 0x00B1; public String getInterfaceLoggingTag() { - return "SerialBTReaderInterface"; + return TAG; } - private Context notifyContext; private BluetoothDevice activeDevice; - private BluetoothSerialInterface.ChameleonBluetoothDeviceState btDeviceState; private BluetoothGattConnector btGattConnectorBLEDevice; private int baudRate; private boolean serialConfigured; private boolean receiversRegistered; - private final Semaphore serialPortLock = new Semaphore(1, true); + private Semaphore btDevLock = new Semaphore(1, true); + @SuppressLint("MissingPermission") public boolean isBluetoothEnabled(boolean startActivityIfNot) { LiveLoggerActivity mainActivityCtx = LiveLoggerActivity.getLiveLoggerInstance(); - if(!mainActivityCtx.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) { + if (!mainActivityCtx.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) { return false; - } else if(!mainActivityCtx.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + } else if (!mainActivityCtx.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { return false; } BluetoothAdapter btAdapter = null; BluetoothAdapter btAdapterDefault = BluetoothAdapter.getDefaultAdapter(); BluetoothManager btManager = (BluetoothManager) mainActivityCtx.getSystemService(Context.BLUETOOTH_SERVICE); BluetoothAdapter btAdapterFromService = btManager != null ? btManager.getAdapter() : null; - if(btAdapterFromService != null) { + if (btAdapterFromService != null) { btAdapter = btAdapterFromService; - } else if(btAdapterDefault != null) { + } else if (btAdapterDefault != null) { btAdapter = btAdapterDefault; } - if(btAdapter == null) { + if (btAdapter == null) { return false; - } else if(!btAdapter.isEnabled()) { - if(startActivityIfNot) { - Intent turnBTOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); - mainActivityCtx.startActivityForResult(turnBTOn, ACTVITY_REQUEST_BLUETOOTH_ENABLED_CODE); + } else if (!btAdapter.isEnabled()) { + if (startActivityIfNot) { + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + Intent turnBTOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + mainActivityCtx.startActivityForResult(turnBTOn, ACTVITY_REQUEST_BLUETOOTH_ENABLED_CODE); + } } } - if(startActivityIfNot) { + if (startActivityIfNot) { Intent btMakeDiscIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); btMakeDiscIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); - mainActivityCtx.startActivityForResult(btMakeDiscIntent, ACTVITY_REQUEST_BLUETOOTH_DISCOVERABLE_CODE); + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (ActivityCompat.checkSelfPermission(LiveLoggerActivity.getLiveLoggerInstance(), android.Manifest.permission.BLUETOOTH_ADVERTISE) != PackageManager.PERMISSION_GRANTED) { + mainActivityCtx.startActivityForResult(btMakeDiscIntent, ACTVITY_REQUEST_BLUETOOTH_DISCOVERABLE_CODE); + } + } } return false; } @@ -192,7 +123,7 @@ public static void displayAndroidBluetoothTroubleshooting() { wv.setInitialScale(10); adBuilder.setCancelable(true); - adBuilder.setTitle("Bluetooth Troubleshooting/Tips:"); + adBuilder.setTitle("Bluetooth Troubleshooting / Tips:"); adBuilder.setPositiveButton( "Back to Previous", new DialogInterface.OnClickListener() { @@ -209,19 +140,16 @@ public void onClick(DialogInterface dialog, int id) { } public boolean configureSerialConnection(BluetoothDevice btDev) { - if(btDev == null) { + if (btDev == null) { return false; - } - if(!receiversRegistered) { + } else if (!receiversRegistered) { configureSerial(); } - activeDevice = btDev; - AndroidLog.i(TAG, "BTDEV: " + activeDevice.toString()); + activeDevice = btDev; ChameleonIO.REVE_BOARD = false; ChameleonIO.PAUSED = false; ChameleonSettings.chameleonDeviceMAC = btDev.getAddress(); ChameleonSettings.chameleonDeviceSerialNumber = ChameleonSettings.chameleonDeviceMAC; - /* TODO: Update the settings tab with connected device information at this point ?!? */ Handler configDeviceHandler = new Handler(); Runnable configDeviceRunnable = new Runnable() { @@ -230,9 +158,10 @@ public void run() { if(ChameleonSettings.getActiveSerialIOPort() != null && btGattConnectorBLEDevice.isDeviceConnected()) { configDeviceHandler.removeCallbacks(this); ChameleonIO.deviceStatus.updateAllStatusAndPost(false); - ChameleonIO.deviceStatus.updateAllStatusAndPost(false); /* Make sure the device returned the correct data to display */ + ChameleonIO.deviceStatus.updateAllStatusAndPost(false); /* Twice: Make sure the device returned the correct data to display */ ChameleonIO.DeviceStatusSettings.startPostingStats(0); LiveLoggerActivity.getLiveLoggerInstance().setStatusIcon(R.id.statusIconBT, R.drawable.bluetooth16); + UITabUtils.updateConfigTabConnDeviceInfo(true); } else { AndroidLog.i(TAG, "BLE device __NOT__ connected! ... Looping"); @@ -249,90 +178,34 @@ public void run() { return true; } + @SuppressLint("MissingPermission") public String getDeviceName() { - return activeDevice != null ? activeDevice.getName() : ""; + final String unknownBTDevName = ""; + try { + return activeDevice != null ? activeDevice.getName() : unknownBTDevName; + } catch (SecurityException se) { + AndroidLog.printStackTrace(se); + return unknownBTDevName; + } } - public BluetoothSerialInterface(Context appContext) { - notifyContext = appContext; + public BluetoothBLEInterface(Context appContext) { + setListenerContext(appContext); activeDevice = null; - btGattConnectorBLEDevice = new BluetoothGattConnector(notifyContext); + btGattConnectorBLEDevice = new BluetoothGattConnector(appContext); btGattConnectorBLEDevice.setBluetoothSerialInterface(this); - btDeviceState = ChameleonBluetoothDeviceState.BTDEV_STATE_DISCONNECTED; baudRate = ChameleonSettings.serialBaudRate; serialConfigured = false; receiversRegistered = false; } - public void setListenerContext(Context context) { - notifyContext = context; - } - - public boolean notifySerialDataReceived(byte[] serialData) { - AndroidLog.d(TAG, "BTReaderCallback Serial Data: (HEX) " + Utils.bytes2Hex(serialData)); - AndroidLog.d(TAG, "BTReaderCallback Serial Data: (TXT) " + Utils.bytes2Ascii(serialData)); - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_DATA_RECEIVED); - notifyIntent.putExtra("DATA", serialData); - notifyContext.sendBroadcast(notifyIntent); - return true; - } - - public boolean notifyLogDataReceived(byte[] serialData) { - AndroidLog.d(TAG, "BTReaderCallback Log Data: (HEX) " + Utils.bytes2Hex(serialData)); - AndroidLog.d(TAG, "BTReaderCallback Log Data: (TXT) " + Utils.bytes2Ascii(serialData)); - if(serialData.length < ChameleonLogUtils.LOGGING_MIN_DATA_BYTES + 4) { - return false; - } - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_LOGDATA_RECEIVED); - notifyIntent.putExtra("DATA", serialData); - notifyContext.sendBroadcast(notifyIntent); - return true; - } - - public boolean notifyDeviceFound() { - AndroidLog.i(TAG, "notifyDeviceFound"); - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_DEVICE_FOUND); - notifyContext.sendBroadcast(notifyIntent); - return true; - } - - public boolean notifyDeviceConnectionTerminated() { - AndroidLog.i(TAG, "notifyDeviceConnectionTerminated"); - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_DEVICE_CONNECTION_LOST); - notifyContext.sendBroadcast(notifyIntent); - return true; - } - - public boolean notifyStatus(String msgType, String statusMsg) { - AndroidLog.i(TAG, "notifyStatus: " + msgType + ": " + statusMsg); - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_NOTIFY_STATUS); - notifyIntent.putExtra("STATUS-TYPE", msgType); - notifyIntent.putExtra("STATUS-MSG", statusMsg); - notifyContext.sendBroadcast(notifyIntent); - return true; - } - - public boolean notifyBluetoothChameleonDeviceConnected() { - AndroidLog.i(TAG, "notifyBluetoothChameleonDeviceConnected"); - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_NOTIFY_BTDEV_CONNECTED); - notifyContext.sendBroadcast(notifyIntent); - return true; - } - public boolean isWiredUSB() { return false; } public boolean isBluetooth() { return true; } - public int setSerialBaudRate(int brate) { - baudRate = brate; - ChameleonSettings.serialBaudRate = baudRate; - return baudRate; - } - public int setSerialBaudRateHigh() { - return setSerialBaudRate(ChameleonSerialIOInterface.HIGH_SPEED_BAUD_RATE); - } - public int setSerialBaudRateLimited() { - return setSerialBaudRate(ChameleonSerialIOInterface.LIMITED_SPEED_BAUD_RATE); + public int setSerialBaudRate(int bdRate) { + AndroidLog.w(TAG, String.format(BuildConfig.DEFAULT_LOCALE, "Attempt to set serial baud rate to %d on a BT connection")); + return STATUS_NOT_SUPPORTED; } public boolean isDeviceConnected() { @@ -354,14 +227,21 @@ public boolean stopScanningDevices() { return true; } + @SuppressLint("MissingPermission") public String getActiveDeviceInfo() { if(activeDevice == null) { return ": No information available."; } - String devInfo = String.format(Locale.getDefault(), "BT Class: %s\nBond State: %s\nProduct Name: %s\nType: %s\nDevice Address: %s", - activeDevice.getBluetoothClass(), activeDevice.getBondState(), - activeDevice.getName(), activeDevice.getType(), - activeDevice.getAddress());; + String devInfo = ""; + try { + devInfo = String.format(BuildConfig.DEFAULT_LOCALE, "BT Class: %s\nBond State: %s\nProduct Name: %s\nType: %s\nDevice Address: %s", + activeDevice.getBluetoothClass(), activeDevice.getBondState(), + activeDevice.getName(), activeDevice.getType(), + activeDevice.getAddress()); + } catch (SecurityException se) { + AndroidLog.printStackTrace(se); + devInfo = ""; + } return devInfo; } @@ -396,6 +276,9 @@ public int shutdownSerial() { if(ChameleonSettings.SERIALIO_IFACE_ACTIVE_INDEX == ChameleonSettings.BTIO_IFACE_INDEX) { ChameleonSettings.SERIALIO_IFACE_ACTIVE_INDEX = -1; } + btDevLock.release(); + LiveLoggerActivity.getLiveLoggerInstance().clearStatusIcon(R.id.statusIconBT); + UITabUtils.updateConfigTabConnDeviceInfo(true); notifyDeviceConnectionTerminated(); return STATUS_TRUE; } @@ -406,40 +289,38 @@ public int shutdownSerial() { public boolean acquireSerialPort() { try { - serialPortLock.acquire(); + btDevLock.acquire(); return true; } catch(Exception inte) { AndroidLog.printStackTrace(inte); - serialPortLock.release(); + btDevLock.release(); return false; } } public boolean acquireSerialPortNoInterrupt() { try { - serialPortLock.acquireUninterruptibly(); + btDevLock.acquireUninterruptibly(); return true; } catch(Exception inte) { AndroidLog.printStackTrace(inte); - serialPortLock.release(); + btDevLock.release(); return false; } } public boolean tryAcquireSerialPort(int timeout) { - boolean status = false; try { - status = serialPortLock.tryAcquire(timeout, java.util.concurrent.TimeUnit.MILLISECONDS); - return status; + return btDevLock.tryAcquire(timeout, java.util.concurrent.TimeUnit.MILLISECONDS); } catch(Exception ie) { AndroidLog.printStackTrace(ie); - serialPortLock.release(); + btDevLock.release(); return false; } } public boolean releaseSerialPortLock() { - serialPortLock.release(); + btDevLock.release(); return true; } @@ -447,24 +328,19 @@ public int sendDataBuffer(byte[] dataWriteBuffer) { AndroidLog.i(TAG, "write: " + Utils.bytes2Hex(dataWriteBuffer)); if(dataWriteBuffer == null || dataWriteBuffer.length == 0) { return STATUS_FALSE; - } - else if(!serialConfigured()) { + } else if(!serialConfigured()) { return STATUS_FALSE; } try { - btGattConnectorBLEDevice.write(dataWriteBuffer); + if (btGattConnectorBLEDevice.write(dataWriteBuffer) != STATUS_OK) { + return STATUS_FALSE; + } else if (btGattConnectorBLEDevice.read() != STATUS_OK) { + return STATUS_FALSE; + } } catch(IOException ioe) { AndroidLog.printStackTrace(ioe); } return STATUS_TRUE; } - public BluetoothSerialInterface.ChameleonBluetoothDeviceState getState() { - return btDeviceState; - } - - public BluetoothSerialInterface.ChameleonBluetoothDeviceState getBLEGattState() { - return btGattConnectorBLEDevice.getState(); - } - } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/BluetoothGattConnector.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/BluetoothGattConnector.java index d2a0ca7..e7594e0 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/BluetoothGattConnector.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/BluetoothGattConnector.java @@ -35,74 +35,87 @@ This program (The Chameleon Mini Live Debugger) is free software written by import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.util.Log; +import android.os.ParcelUuid; import androidx.annotation.NonNull; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.UUID; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; public class BluetoothGattConnector extends BluetoothGattCallback { private static final String TAG = BluetoothGattConnector.class.getSimpleName(); /** - * OBSERVATIONS/TROUBLESHOOTING NOTES: - * The proprietary Proxgrind/RRG application does something unusual the - * first time it tries to connect to the Chameleon over BT when the - * Chameleon device is reconnected to power via USB after the battery has - * completely lost charge: - * > The user is instructed to press and hold button 'A' for at least - * 15 seconds while this initial connection is made. - * > The step is skipped upon attempts at BT reconnection so long as the - * device has not lost power (disconnected from wired USB, or a - * dead integrated rechargable battery inside the Tiny series devices) - * > Not easy to find out whether a secret PIN is exchanged during the initial - * button press period because the BT connection is relinquished by the - * RRG brand application every time the app is minimized. - * [The only way to see an active PIN string for a connected BT device on - * Android OS is to open the system Settings app and navigate to - * 'Connected devices -> ChameleonDeviceName -> Settings (icon)' - * and then inspect the live settings that are active for the device.] + * OBSERVATIONS / TROUBLESHOOTING NOTES: + * The proprietary Proxgrind / RRG application does something unusual the + * first time it tries to connect to the Chameleon over BT when the + * Chameleon device is reconnected to power via USB after the battery has + * completely lost charge: + * > The user is instructed to press and hold button 'A' for at least + * 15 seconds while this initial connection is made. + * > The step is skipped upon attempts at BT reconnection so long as the + * device has not lost power (disconnected from wired USB, or a + * dead integrated rechargeable battery inside the Tiny series devices) + * > Not easy to find out whether a secret PIN is exchanged during the initial + * button press period because the BT connection is relinquished by the + * RRG brand application every time the app is minimized. + * [The only way to see an active PIN string for a connected BT device on + * Android OS is to open the system Settings app and navigate to + * 'Connected devices -> ChameleonDeviceName -> Settings (icon)' + * and then inspect the live settings that are active for the device.] */ /** - * TODO: Make sure that the BLE UUIDs are the same for both of the Proxgrind Tiny and Tiny Professional devices - * TODO: More BLE documentation at https://punchthrough.com/android-ble-guide/ + * NOTE: More BLE documentation at https://punchthrough.com/android-ble-guide/ + */ + + /* TODO: Make sure that the BLE UUIDs are the same for both of the + * Proxgrind RevG Tiny and TinyPro devices */ public static final String CHAMELEON_REVG_NAME = "BLE-Chameleon"; public static final String CHAMELEON_REVG_NAME_ALTERNATE = "Chameleon"; - public static final String CHAMELEON_REVG_SERVICE_UUID = "51510001-7969-6473-6f40-6b6f6c6c6957"; - public static final String CHAMELEON_REVG_SEND_CHAR_UUID = "51510002-7969-6473-6f40-6b6f6c6c6957"; - public static final String CHAMELEON_REVG_RECV_CHAR_UUID = "51510003-7969-6473-6f40-6b6f6c6c6957"; + public static final String CHAMELEON_REVG_SERVICE_UUID_STRING = "51510001-7969-6473-6f40-6b6f6c6c6957"; + public static final String CHAMELEON_REVG_SEND_CHAR_UUID_STRING = "51510002-7969-6473-6f40-6b6f6c6c6957"; + public static final String CHAMELEON_REVG_RECV_CHAR_UUID_STRING = "51510003-7969-6473-6f40-6b6f6c6c6957"; public static final String CHAMELEON_REVG_TINY_NAME = "ChameleonTiny"; - public static final String CHAMELEON_REVG_TINY_SERVICE_UUID = "51510001-7969-6473-6f40-6b6f6c6c6957"; - public static final String CHAMELEON_REVG_TINY_SEND_CHAR_UUID = "51510002-7969-6473-6f40-6b6f6c6c6957"; - public static final String CHAMELEON_REVG_TINY_RECV_CHAR_UUID = "51510003-7969-6473-6f40-6b6f6c6c6957"; - public static final String CHAMELEON_REVG_CTRL_CHAR_UUID = "52520003-7969-6473-6f40-6b6f6c6c6957"; - public static final String CHAMELEON_REVG_RECV_DESC_UUID = "00002902-0000-1000-8000-00805f9b34fb"; + public static final String CHAMELEON_REVG_TINY_SERVICE_UUID_STRING = "51510001-7969-6473-6f40-6b6f6c6c6957"; + public static final String CHAMELEON_REVG_TINY_SEND_CHAR_UUID_STRING = "51510002-7969-6473-6f40-6b6f6c6c6957"; + public static final String CHAMELEON_REVG_TINY_RECV_CHAR_UUID_STRING = "51510003-7969-6473-6f40-6b6f6c6c6957"; + public static final String CHAMELEON_REVG_CTRL_CHAR_UUID_STRING = "52520003-7969-6473-6f40-6b6f6c6c6957"; + public static final String CHAMELEON_REVG_RECV_DESC_UUID_STRING = "00002902-0000-1000-8000-00805f9b34fb"; + + private static final ParcelUuid CHAMELEON_REVG_SERVICE_UUID = ParcelUuid.fromString(CHAMELEON_REVG_SERVICE_UUID_STRING); + private static final ParcelUuid CHAMELEON_REVG_SEND_CHAR_UUID = ParcelUuid.fromString(CHAMELEON_REVG_SEND_CHAR_UUID_STRING); + private static final ParcelUuid CHAMELEON_REVG_RECV_CHAR_UUID = ParcelUuid.fromString(CHAMELEON_REVG_RECV_CHAR_UUID_STRING); + private static final ParcelUuid CHAMELEON_REVG_TINY_SERVICE_UUID = ParcelUuid.fromString(CHAMELEON_REVG_TINY_SERVICE_UUID_STRING); + private static final ParcelUuid CHAMELEON_REVG_TINY_SEND_CHAR_UUID = ParcelUuid.fromString(CHAMELEON_REVG_TINY_SEND_CHAR_UUID_STRING); + private static final ParcelUuid CHAMELEON_REVG_TINY_RECV_CHAR_UUID = ParcelUuid.fromString(CHAMELEON_REVG_TINY_RECV_CHAR_UUID_STRING); + private static final ParcelUuid CHAMELEON_REVG_CTRL_CHAR_UUID = ParcelUuid.fromString(CHAMELEON_REVG_CTRL_CHAR_UUID_STRING); + private static final ParcelUuid CHAMELEON_REVG_RECV_DESC_UUID = ParcelUuid.fromString(CHAMELEON_REVG_RECV_DESC_UUID_STRING); private static final String BLUETOOTH_SYSTEM_SERVICE = Context.BLUETOOTH_SERVICE; private static final String BLUETOOTH_BOND_RECEIVER_ACTION = BluetoothDevice.ACTION_BOND_STATE_CHANGED; public static final byte[] BLUETOOTH_GATT_ENABLE_NOTIFY_PROP = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE; public static final int BLUETOOTH_GATT_CONNECT_PRIORITY_HIGH = BluetoothGatt.CONNECTION_PRIORITY_HIGH; - public static final int BLUETOOTH_GATT_CONNECT_PRIORITY_BALANCED = BluetoothGatt.CONNECTION_PRIORITY_BALANCED; - public static final int BLUETOOTH_GATT_CONNECT_PRIORITY_LOW_POWER = BluetoothGatt.CONNECTION_PRIORITY_LOW_POWER; - public static final int BLUETOOTH_GATT_WRITE_DESC_TIMEOUT = 2250; public static final int BLUETOOTH_LOCAL_MTU_THRESHOLD = 244; + public static final int BLUETOOTH_BLE_GATT_RSP_WRITE = 0x13; + public static final int BLUETOOTH_BLE_GATT_RSP_EXEC_WRITE = 0x19; + public static final int BLUETOOTH_BLE_GATT_ERROR = 0x85; + private Context btSerialContext; - private String chameleonDeviceBLEService; - private String chameleonDeviceBLESendChar; - private String chameleonDeviceBLERecvChar; + private ParcelUuid chameleonDeviceBLEService; + private ParcelUuid chameleonDeviceBLECtrlChar; + private ParcelUuid chameleonDeviceBLESendChar; + private ParcelUuid chameleonDeviceBLERecvChar; private BluetoothDevice btDevice; private BluetoothAdapter btAdapter; private BluetoothLeScanner bleScanner; @@ -110,18 +123,23 @@ public class BluetoothGattConnector extends BluetoothGattCallback { private BluetoothGattCallback btGattCallback; private BroadcastReceiver btBondReceiver; private boolean btPermsObtained; - private boolean btBondRecvRegistered; private boolean btNotifyUARTService; - private BluetoothSerialInterface btSerialIface; + private boolean btBondRecvRegistered; + private BluetoothBLEInterface btSerialIface; private boolean isConnected; - private BluetoothSerialInterface.ChameleonBluetoothDeviceState btDeviceState; public static byte[] btDevicePinDataBytes = new byte[0]; + private static final long BLE_READ_WRITE_OPERATION_TRYLOCK_TIMEOUT = ChameleonIO.LOCK_TIMEOUT; + + private Semaphore bleReadLock = new Semaphore(1, true); + private Semaphore bleWriteLock = new Semaphore(1, true); + public BluetoothGattConnector(@NonNull Context localContext) { btSerialContext = localContext; chameleonDeviceBLEService = CHAMELEON_REVG_SERVICE_UUID; chameleonDeviceBLESendChar = CHAMELEON_REVG_SEND_CHAR_UUID; - chameleonDeviceBLESendChar = CHAMELEON_REVG_RECV_CHAR_UUID; + chameleonDeviceBLERecvChar = CHAMELEON_REVG_RECV_CHAR_UUID; + chameleonDeviceBLECtrlChar = CHAMELEON_REVG_CTRL_CHAR_UUID; btDevice = null; btBondReceiver = null; btPermsObtained = false; @@ -131,13 +149,12 @@ public BluetoothGattConnector(@NonNull Context localContext) { btAdapter = configureBluetoothAdapter(); btGatt = null; btGattCallback = configureBluetoothGattCallback(); - btSerialIface = (BluetoothSerialInterface) ChameleonSettings.serialIOPorts[ChameleonSettings.BTIO_IFACE_INDEX]; + btSerialIface = (BluetoothBLEInterface) ChameleonSettings.serialIOPorts[ChameleonSettings.BTIO_IFACE_INDEX]; isConnected = false; - btDeviceState = BluetoothSerialInterface.ChameleonBluetoothDeviceState.BTDEV_STATE_DISCONNECTED; BluetoothGattConnector.btDevicePinDataBytes = getStoredBluetoothDevicePinData(); } - public void setBluetoothSerialInterface(BluetoothSerialInterface btLocalSerialIface) { + public void setBluetoothSerialInterface(BluetoothBLEInterface btLocalSerialIface) { btSerialIface = btLocalSerialIface; } @@ -151,12 +168,9 @@ public void onReceive(Context context, Intent intent) { return; } BluetoothDevice btIntentDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - if (btIntentDevice == null) { - return; - } - else { + if (btIntentDevice != null) { AndroidLog.i(TAG, "btBondReceiver: calling notifyBluetoothSerialInterfaceDeviceConnected"); - notifyBluetoothSerialInterfaceDeviceConnected(btIntentDevice); + notifyBluetoothBLEDeviceConnected(btIntentDevice); } } }; @@ -180,14 +194,24 @@ private BluetoothGattCallback configureBluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { - if(status == 19) { - /* Status code 19 is caused by loss of binding information ??? */ + if (status != BluetoothGatt.GATT_SUCCESS) { + AndroidLog.w(TAG, String.format(BuildConfig.DEFAULT_LOCALE, "onConnectionStateChange: error/status code %d = %04x", status, status)); + } + if(status == BLUETOOTH_BLE_GATT_ERROR) { + return; + } else if (status == BLUETOOTH_BLE_GATT_RSP_WRITE) { + return; + } else if (status == BLUETOOTH_BLE_GATT_RSP_EXEC_WRITE) { return; } if(newState == BluetoothProfile.STATE_CONNECTED) { requestConnectionPriority(BLUETOOTH_GATT_CONNECT_PRIORITY_HIGH); btGatt = gatt; - btGatt.discoverServices(); + try { + btGatt.discoverServices(); + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + } } if(newState == BluetoothGatt.STATE_DISCONNECTED) { disconnectDevice(); @@ -196,33 +220,53 @@ public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { + if (status != BluetoothGatt.GATT_SUCCESS) { + AndroidLog.w(TAG, String.format(BuildConfig.DEFAULT_LOCALE, "onServicesDiscovered: error/status code %d = %04x", status, status)); + } + if (status == BLUETOOTH_BLE_GATT_ERROR) { + return; + } List services = gatt.getServices(); AndroidLog.i(TAG,"onServicesDiscovered" + services.toString()); - gatt.readCharacteristic(services.get(1).getCharacteristics().get(0)); + /*try { + gatt.readCharacteristic(services.get(1).getCharacteristics().get(0)); + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + }*/ if(status == BluetoothGatt.GATT_SUCCESS) { - configureNotifyOnSerialBluetoothService(gatt, chameleonDeviceBLERecvChar); + configureNotifyOnSerialBluetoothService(gatt, chameleonDeviceBLERecvChar.toString()); } } @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { + bleWriteLock.release(); + if (status == BLUETOOTH_BLE_GATT_ERROR) { + return; + } UUID activeLocalCharUUID = descriptor.getCharacteristic().getUuid(); - if(!activeLocalCharUUID.equals(UUID.fromString(CHAMELEON_REVG_CTRL_CHAR_UUID))) { - configureNotifyOnSerialBluetoothService(gatt, chameleonDeviceBLERecvChar); + if(!activeLocalCharUUID.equals(CHAMELEON_REVG_CTRL_CHAR_UUID)) { + configureNotifyOnSerialBluetoothService(gatt, chameleonDeviceBLERecvChar.toString()); } - AndroidLog.i(TAG, "onDescriptorWrite: [UUID] " + activeLocalCharUUID.toString()); + AndroidLog.i(TAG, "onDescriptorWrite: [UUID] " + activeLocalCharUUID); } @Override public void onCharacteristicChanged(BluetoothGatt gatt, @NonNull BluetoothGattCharacteristic characteristic) { - gatt.readCharacteristic(characteristic); - AndroidLog.d(TAG, "read characteristic: " + characteristic.getValue().toString()); + try{ + gatt.readCharacteristic(characteristic); + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + } byte[] charData = characteristic.getValue(); if (charData == null) { + AndroidLog.d(TAG, "read characteristic: "); return; + } else { + AndroidLog.d(TAG, "read characteristic: " + String.valueOf(charData)); } + bleReadLock.release(); try { - /* Unpack bytes ?!? */ notifyBluetoothSerialInterfaceDataRead(charData); } catch (Exception dinvEx) { AndroidLog.printStackTrace(dinvEx); @@ -231,13 +275,31 @@ public void onCharacteristicChanged(BluetoothGatt gatt, @NonNull BluetoothGattCh @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { - if (status == BluetoothGatt.GATT_SUCCESS) { + bleReadLock.release(); + if (status == BLUETOOTH_BLE_GATT_ERROR) { + return; + } else if (status == BluetoothGatt.GATT_SUCCESS) { byte[] charData = characteristic.getValue(); notifyBluetoothSerialInterfaceDataRead(charData); } AndroidLog.i(TAG,"onCharacteristicRead" + characteristic.toString()); - AndroidLog.d(TAG, "onCharRead status: " + status); - gatt.disconnect(); + byte[] charData = characteristic.getValue(); + if (charData == null) { + AndroidLog.d(TAG, "read characteristic: "); + return; + } else { + AndroidLog.d(TAG, "read characteristic: " +String.valueOf(charData)); + } + try { + notifyBluetoothSerialInterfaceDataRead(charData); + } catch (Exception dinvEx) { + AndroidLog.printStackTrace(dinvEx); + } + /*try{ + gatt.disconnect(); + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + }*/ } }; @@ -258,17 +320,25 @@ public boolean disconnectDevice() { if(isDeviceConnected()) { btDevice = null; if(btGatt != null) { - btGatt.disconnect(); - btGatt.close(); + try { + btGatt.abortReliableWrite(); + btGatt.disconnect(); + btGatt.close(); + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + } btGatt = null; } btBondRecvRegistered = false; isConnected = false; + bleReadLock.release(); + bleWriteLock.release(); return true; } return false; } + /* TODO: This is where we need to connect the device / gatt and stop the ongoing scan */ private ScanCallback bleScanCallback = new ScanCallback() { @Override @@ -276,7 +346,26 @@ public void onScanResult(int callbackType, ScanResult scanResultData) { LiveLoggerActivity.getLiveLoggerInstance().runOnUiThread(new Runnable() { @Override public void run() { - AndroidLog.i(TAG, "BLE device with name " + scanResultData.getDevice().getName() + "scanned"); + String bleDeviceName = ""; + try { + bleDeviceName = scanResultData.getScanRecord().getDeviceName(); + //bleDeviceName = scanResultData.getDevice().getAddress(); + //scanResultData.isConnectable() + //scanResultData.getDevice().connectGatt() + //scanResultData.getRssi() // in dBm + //scanResultData.getTxPower() // in dBm + /*scanResultData.getScanRecord().toString(); + scanResultData.getScanRecord().getDeviceName(); + List svcUUIDList = scanResultData.getScanRecord().getServiceUuids(); + SparseArray saDeviceManuData = scanResultData.getScanRecord().getManufacturerSpecificData(); + */ + } catch(SecurityException se) { + bleDeviceName = ""; + AndroidLog.printStackTrace(se); + } catch(NullPointerException npe) { + AndroidLog.printStackTrace(npe); + } + AndroidLog.i(TAG, "BLE device with name " + bleDeviceName + "scanned"); } }); } @@ -294,16 +383,39 @@ public boolean startConnectingDevices() { } if(btPermsObtained) { registerBluetoothBondReceiver(); - btAdapter.startDiscovery(); + try { + btAdapter.startDiscovery(); + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + } if (bleScanner == null) { bleScanner = btAdapter.getBluetoothLeScanner(); } if (bleScanner != null) { ScanSettings bleScanSettings = new ScanSettings.Builder() - .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER) + .setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED) + .setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH) + .build(); + ScanFilter chameleonRevGDeviceFilter = new ScanFilter.Builder() + .setDeviceName(CHAMELEON_REVG_NAME) + .build(); + //.setServiceUuid() + ScanFilter chameleonRevGTinyProDeviceFilter = new ScanFilter.Builder() + .setDeviceName(CHAMELEON_REVG_NAME_ALTERNATE) + .build(); + ScanFilter chameleonRevGTinyDeviceFilter = new ScanFilter.Builder() + .setDeviceName(CHAMELEON_REVG_TINY_NAME) .build(); List bleScanFilters = new ArrayList(); - bleScanner.startScan(bleScanFilters, bleScanSettings, bleScanCallback); + bleScanFilters.add(chameleonRevGDeviceFilter); + bleScanFilters.add(chameleonRevGTinyProDeviceFilter); + bleScanFilters.add(chameleonRevGTinyDeviceFilter); + try { + bleScanner.startScan(bleScanFilters, bleScanSettings, bleScanCallback); + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + } } return true; } @@ -315,9 +427,15 @@ public boolean stopConnectingDevices() { btPermsObtained = btSerialIface.isBluetoothEnabled(false); } if(btPermsObtained && btAdapter != null) { - btAdapter.cancelDiscovery(); - if(bleScanner != null) { - bleScanner.stopScan(bleScanCallback); + try { + btAdapter.cancelDiscovery(); + if(bleScanner != null) { + bleScanner.stopScan(bleScanCallback); + bleScanner.flushPendingScanResults(bleScanCallback); + } + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + return false; } return true; } else { @@ -347,6 +465,10 @@ public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { @Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + if (status != BluetoothGatt.GATT_SUCCESS) { + AndroidLog.w(TAG, String.format(BuildConfig.DEFAULT_LOCALE, "onCharacteristicRead (%s): error/status code %d = %04x", characteristic.getUuid().toString(), status, status)); + return; + } btGattCallback.onCharacteristicWrite(gatt, characteristic, status); } @@ -357,18 +479,28 @@ public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteris @Override public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + if (status != BluetoothGatt.GATT_SUCCESS) { + AndroidLog.w(TAG, String.format(BuildConfig.DEFAULT_LOCALE, "onCharacteristicRead (%s): error/status code %d = %04x", characteristic.getUuid().toString(), status, status)); + return; + } btGattCallback.onCharacteristicRead(gatt, characteristic, status); } - public void notifyBluetoothSerialInterfaceDeviceConnected(@NonNull BluetoothDevice btLocalDevice) { + public void notifyBluetoothBLEDeviceConnected(@NonNull BluetoothDevice btLocalDevice) { if(isDeviceConnected() || btNotifyUARTService || btAdapter == null) { return; } btDevice = btLocalDevice; stopConnectingDevices(); - btDevice.connectGatt(btSerialContext, false, this); - btDevice.createBond(); - String btDeviceName = btDevice.getName(); + String btDeviceName = ""; + try { + btDevice.connectGatt(btSerialContext, false, this); + btDevice.createBond(); + btDeviceName = btDevice.getName(); + } catch(SecurityException se) { + btDeviceName = ""; + AndroidLog.printStackTrace(se); + } AndroidLog.i(TAG, "BT Device Name: " + btDeviceName); if(btDeviceName != null && (btDeviceName.equals(CHAMELEON_REVG_NAME) || btDeviceName.equals(CHAMELEON_REVG_NAME_ALTERNATE))) { chameleonDeviceBLEService = CHAMELEON_REVG_SERVICE_UUID; @@ -388,9 +520,6 @@ public void notifyBluetoothSerialInterfaceDeviceConnected(@NonNull BluetoothDevi } public void notifyBluetoothSerialInterfaceDataRead(byte[] serialDataRead) { - if(serialDataRead == null) { - return; - } if(btSerialIface != null) { btSerialIface.onReceivedData(serialDataRead); } @@ -398,7 +527,7 @@ public void notifyBluetoothSerialInterfaceDataRead(byte[] serialDataRead) { private void configureNotifyOnSerialBluetoothService(BluetoothGatt btLocalGatt, String gattUUID) { AndroidLog.i(TAG, "configureNotifyOnSerialBluetoothService"); - BluetoothGattService btgService = btLocalGatt.getService(UUID.fromString(chameleonDeviceBLEService)); + BluetoothGattService btgService = btLocalGatt.getService(chameleonDeviceBLEService.getUuid()); if (btgService == null) { return; } @@ -406,10 +535,14 @@ private void configureNotifyOnSerialBluetoothService(BluetoothGatt btLocalGatt, if (btgChar == null) { return; } - btLocalGatt.setCharacteristicNotification(btgChar, true); - BluetoothGattDescriptor descriptor = btgChar.getDescriptor(UUID.fromString(CHAMELEON_REVG_RECV_DESC_UUID)); - descriptor.setValue(BLUETOOTH_GATT_ENABLE_NOTIFY_PROP); - btLocalGatt.writeDescriptor(descriptor); + try { + btLocalGatt.setCharacteristicNotification(btgChar, true); + BluetoothGattDescriptor descriptor = btgChar.getDescriptor(CHAMELEON_REVG_RECV_DESC_UUID.getUuid()); + descriptor.setValue(BLUETOOTH_GATT_ENABLE_NOTIFY_PROP); + btLocalGatt.writeDescriptor(descriptor); + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + } } @@ -417,30 +550,82 @@ public boolean requestConnectionPriority(int connectPrioritySetting) { if(btGatt == null) { return false; } - return btGatt.requestConnectionPriority(connectPrioritySetting); + try { + return btGatt.requestConnectionPriority(connectPrioritySetting); + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + return false; + } } public int write(byte[] dataBuf) throws IOException { AndroidLog.i(TAG, "write: " + Utils.bytes2Hex(dataBuf)); if (dataBuf.length > BLUETOOTH_LOCAL_MTU_THRESHOLD) { - return -1; + return ChameleonSerialIOInterface.STATUS_ERROR; } if(btGatt == null) { - AndroidLog.i(TAG, "write: btGatt == null!"); disconnectDevice(); - return -1; + return ChameleonSerialIOInterface.STATUS_ERROR; } - BluetoothGattService txDataService = btGatt.getService(UUID.fromString(chameleonDeviceBLEService)); + BluetoothGattService txDataService = btGatt.getService(chameleonDeviceBLEService.getUuid()); if(txDataService == null) { - return -1; + disconnectDevice(); + return ChameleonSerialIOInterface.STATUS_ERROR; } - BluetoothGattCharacteristic btGattChar = txDataService.getCharacteristic(UUID.fromString(chameleonDeviceBLESendChar)); + BluetoothGattCharacteristic btGattChar = txDataService.getCharacteristic(chameleonDeviceBLESendChar.getUuid()); if(btGattChar == null) { - return -1; + disconnectDevice(); + return ChameleonSerialIOInterface.STATUS_ERROR; } btGattChar.setValue(dataBuf); - btGatt.writeCharacteristic(btGattChar); - return 0; + try { + if (bleWriteLock.tryAcquire(BLE_READ_WRITE_OPERATION_TRYLOCK_TIMEOUT, TimeUnit.MILLISECONDS)) { + btGatt.writeCharacteristic(btGattChar); + btGatt.executeReliableWrite(); + } else { + AndroidLog.w(TAG, "Cannot acquire BT BLE read lock for operation"); + return ChameleonSerialIOInterface.STATUS_RESOURCE_UNAVAILABLE; + } + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + return ChameleonSerialIOInterface.STATUS_ERROR; + } catch(InterruptedException ie) { + AndroidLog.printStackTrace(ie); + return ChameleonSerialIOInterface.STATUS_RESOURCE_UNAVAILABLE; + } + return ChameleonSerialIOInterface.STATUS_OK; + } + + public int read() throws IOException { + if(btGatt == null) { + disconnectDevice(); + return ChameleonSerialIOInterface.STATUS_ERROR; + } + BluetoothGattService rxDataService = btGatt.getService(chameleonDeviceBLEService.getUuid()); + if(rxDataService == null) { + disconnectDevice(); + return ChameleonSerialIOInterface.STATUS_ERROR; + } + BluetoothGattCharacteristic btGattChar = rxDataService.getCharacteristic(chameleonDeviceBLERecvChar.getUuid()); + if(btGattChar == null) { + disconnectDevice(); + return ChameleonSerialIOInterface.STATUS_ERROR; + } + try { + if (bleReadLock.tryAcquire(BLE_READ_WRITE_OPERATION_TRYLOCK_TIMEOUT, TimeUnit.MILLISECONDS)) { + btGatt.readCharacteristic(btGattChar); + } else { + AndroidLog.w(TAG, "Cannot acquire BT BLE read lock for operation"); + return ChameleonSerialIOInterface.STATUS_RESOURCE_UNAVAILABLE; + } + } catch(SecurityException se) { + AndroidLog.printStackTrace(se); + return ChameleonSerialIOInterface.STATUS_ERROR; + } catch(InterruptedException ie) { + AndroidLog.printStackTrace(ie); + return ChameleonSerialIOInterface.STATUS_RESOURCE_UNAVAILABLE; + } + return ChameleonSerialIOInterface.STATUS_OK; } public byte[] getStoredBluetoothDevicePinData() { @@ -458,8 +643,4 @@ public void setStoredBluetoothDevicePinData(@NonNull String btPinData) { BluetoothGattConnector.btDevicePinDataBytes = btPinData.getBytes(StandardCharsets.UTF_8); } - public BluetoothSerialInterface.ChameleonBluetoothDeviceState getState() { - return btDeviceState; - } - } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonConfigSlot.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonConfigSlot.java index a61d671..f18ce11 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonConfigSlot.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonConfigSlot.java @@ -88,7 +88,7 @@ public ChameleonConfigSlot(int slotNumber, boolean readDeviceParams) { } public void resetLayoutParameters(int slotNumber) { - slotNickname = String.format(Locale.getDefault(), "Slot %02d", slotNumber); + slotNickname = String.format(BuildConfig.DEFAULT_LOCALE, "Slot %02d", slotNumber); slotIndex = slotNumber; uidHexBytes = ""; uidHexDisplayStr = ""; @@ -161,7 +161,7 @@ else if(nextSlot < 1 || activeSlot < 1 || return false; } try { - ChameleonIO.getSettingFromDevice(String.format(Locale.getDefault(), "SETTING=%d", nextSlot)); + ChameleonIO.getSettingFromDevice(String.format(BuildConfig.DEFAULT_LOCALE, "SETTING=%d", nextSlot)); readParametersFromChameleonSlot(); } catch(Exception exe) { AndroidLog.printStackTrace(exe); @@ -195,7 +195,7 @@ public boolean updateLayoutParameters(boolean readNewTagConfigs) { EditText slotNicknameDisplay = slotConfigLayout.findViewById(R.id.slotNicknameText); slotNicknameDisplay.setText(slotNickname); TextView slotNumberLabel = slotConfigLayout.findViewById(R.id.slotOnOffNumberText); - slotNumberLabel.setText(String.format(Locale.getDefault(), "SLOT %02d", slotIndex)); + slotNumberLabel.setText(String.format(BuildConfig.DEFAULT_LOCALE, "SLOT %02d", slotIndex)); Spinner tagConfigModeSpinner = slotConfigLayout.findViewById(R.id.tagConfigModeSpinner); if(tagConfigModeSpinner == null) { return false; @@ -213,7 +213,7 @@ else if(readNewTagConfigs) { uidHexDisplayStr = Utils.formatUIDString(uidHexBytes, " "); uidBytes.setText(uidHexDisplayStr); TextView memSizeText = (TextView) slotConfigLayout.findViewById(R.id.memorySizeText); - memSizeText.setText(String.format(Locale.getDefault(), "%dB | %dK", tagMemorySize, tagMemorySize / 1024)); + memSizeText.setText(String.format(BuildConfig.DEFAULT_LOCALE, "%dB | %dK", tagMemorySize, tagMemorySize / 1024)); Switch lockSwitch = (Switch) slotConfigLayout.findViewById(R.id.readonlyOnOffSwitch); lockSwitch.setChecked(isLocked); Switch fieldModeSwitch = (Switch) slotConfigLayout.findViewById(R.id.fieldOnOffSwitch); @@ -257,7 +257,7 @@ else if(i == lastSelectedPosition) { } lastSelectedPosition = i; String nextConfigMode = localSpinnerList[i]; - String setConfigCmd = String.format(Locale.getDefault(), "CONFIG=%s", nextConfigMode); + String setConfigCmd = String.format(BuildConfig.DEFAULT_LOCALE, "CONFIG=%s", nextConfigMode); ChameleonIO.getSettingFromDevice(setConfigCmd); readParametersFromChameleonSlot(); updateLayoutParameters(false); @@ -276,7 +276,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { return; } else { - String lockCmd = String.format(Locale.getDefault(), "READONLY=%s", isChecked ? "1" : "0"); + String lockCmd = String.format(BuildConfig.DEFAULT_LOCALE, "READONLY=%s", isChecked ? "1" : "0"); ChameleonIO.getSettingFromDevice(lockCmd); } } @@ -288,7 +288,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { return; } else { - String uidModeCmd = String.format(Locale.getDefault(), "FIELD=%s", isChecked ? "1" : "0"); + String uidModeCmd = String.format(BuildConfig.DEFAULT_LOCALE, "FIELD=%s", isChecked ? "1" : "0"); ChameleonIO.getSettingFromDevice(uidModeCmd); } } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonIO.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonIO.java index 818e12e..d154d8e 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonIO.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonIO.java @@ -19,8 +19,6 @@ This program (The Chameleon Mini Live Debugger) is free software written by import android.os.Handler; import android.os.SystemClock; -import android.util.Log; -import android.view.View; import android.widget.SeekBar; import android.widget.TextView; @@ -31,8 +29,6 @@ This program (The Chameleon Mini Live Debugger) is free software written by import static com.maxieds.chameleonminilivedebugger.ChameleonIO.SerialRespCode.FALSE; import static com.maxieds.chameleonminilivedebugger.ChameleonIO.SerialRespCode.OK; -import static com.maxieds.chameleonminilivedebugger.TabFragment.TAB_TOOLS; -import static com.maxieds.chameleonminilivedebugger.TabFragment.TAB_TOOLS_MITEM_SLOTS; import static java.lang.Math.round; /** @@ -105,7 +101,7 @@ else if(REVE_BOARD) { CHAMELEON_MINI_BOARD_TYPE = CHAMELEON_TYPE_REVE; } else if(deviceActiveSerialIOPort.isBluetooth()) { - String deviceName = ((BluetoothSerialInterface) deviceActiveSerialIOPort).getDeviceName(); + String deviceName = ((BluetoothBLEInterface) deviceActiveSerialIOPort).getDeviceName(); if(deviceName.equals(BluetoothGattConnector.CHAMELEON_REVG_NAME)) { CHAMELEON_MINI_BOARD_TYPE = CHAMELEON_TYPE_PROXGRIND_REVG; } @@ -140,7 +136,7 @@ else if (firmwareVersion.contains("RevG")) { } String chameleonDeviceType = getDeviceDescription(CHAMELEON_MINI_BOARD_TYPE); CHAMELEON_MINI_BOARD_TYPE_DESC = chameleonDeviceType; - String statusMsg = String.format(Locale.getDefault(), "New Chameleon discovered over %s: %s.", deviceConnType, chameleonDeviceType); + String statusMsg = String.format(BuildConfig.DEFAULT_LOCALE, "New Chameleon discovered over %s: %s.", deviceConnType, chameleonDeviceType); Utils.displayToastMessageLong(statusMsg); return CHAMELEON_MINI_BOARD_TYPE; } @@ -344,6 +340,7 @@ public void run() { public static void stopPostingStats() { statsUpdateHandler.removeCallbacksAndMessages(statsUpdateRunnable); + setToolbarStatsToDefault(); postingStatsInProgress = false; } @@ -368,11 +365,11 @@ public void run() { try { ((TextView) LiveLoggerActivity.getContentView(R.id.deviceConfigText)).setText(CONFIG); ((TextView) LiveLoggerActivity.getContentView(R.id.deviceConfigUID)).setText(UID); - String subStats1 = String.format(Locale.getDefault(), "REV%s|MEM-%dK|LOG-%s-%dK", ChameleonIO.REVE_BOARD ? "E" : "G", round(MEMSIZE / 1024), LOGMODE, round(LOGSIZE / 1024)); + String subStats1 = String.format(BuildConfig.DEFAULT_LOCALE, "REV%s|MEM-%dK|LOG-%s-%dK", ChameleonIO.REVE_BOARD ? "E" : "G", round(MEMSIZE / 1024), LOGMODE, round(LOGSIZE / 1024)); ((TextView) LiveLoggerActivity.getContentView(R.id.deviceStats1)).setText(subStats1); - String subStats2 = String.format(Locale.getDefault(), "SLOT-%d|%s|FLD-%s|CHRG-%s", DIP_SETTING, READONLY ? "RO" : "RW", FIELD ? "1" : "0", CHARGING ? "1" : "0"); + String subStats2 = String.format(BuildConfig.DEFAULT_LOCALE, "SLOT-%d|%s|FLD-%s|CHRG-%s", DIP_SETTING, READONLY ? "RO" : "RW", FIELD ? "1" : "0", CHARGING ? "1" : "0"); ((TextView) LiveLoggerActivity.getContentView(R.id.deviceStats2)).setText(subStats2); - String subStats3 = String.format(Locale.getDefault(), "THRS-%dmv|TMT-%s", THRESHOLD, TIMEOUT.replace(" ", "")); + String subStats3 = String.format(BuildConfig.DEFAULT_LOCALE, "THRS-%dmv|TMT-%s", THRESHOLD, TIMEOUT.replace(" ", "")); ((TextView) LiveLoggerActivity.getContentView(R.id.deviceStats3)).setText(subStats3); LiveLoggerActivity.setSignalStrengthIndicator(THRESHOLD); } catch (Exception ex) { @@ -472,21 +469,21 @@ public void run() { String formattedUID = Utils.formatUIDString(UID, ":"); ((TextView) LiveLoggerActivity.getContentView(R.id.deviceConfigUID)).setText(formattedUID); } - String subStats1 = String.format(Locale.getDefault(), "REV%s|MEM-%dK|LOG-%s-%dK", ChameleonIO.REVE_BOARD ? "E" : "G", round(MEMSIZE / 1024), LOGMODE, round(LOGSIZE / 1024)); + String subStats1 = String.format(BuildConfig.DEFAULT_LOCALE, "REV%s|MEM-%dK|LOG-%s-%dK", ChameleonIO.REVE_BOARD ? "E" : "G", round(MEMSIZE / 1024), LOGMODE, round(LOGSIZE / 1024)); ((TextView) LiveLoggerActivity.getContentView(R.id.deviceStats1)).setText(subStats1); - String subStats2 = String.format(Locale.getDefault(), "SLOT-%d|%s|FLD-%s|CHRG-%s", DIP_SETTING, READONLY ? "RO" : "RW", FIELD ? "1" : "0", CHARGING ? "1" : "0"); + String subStats2 = String.format(BuildConfig.DEFAULT_LOCALE, "SLOT-%d|%s|FLD-%s|CHRG-%s", DIP_SETTING, READONLY ? "RO" : "RW", FIELD ? "1" : "0", CHARGING ? "1" : "0"); ((TextView) LiveLoggerActivity.getContentView(R.id.deviceStats2)).setText(subStats2); - String subStats3 = String.format(Locale.getDefault(), "THRS-%dmv|TMT-%s", THRESHOLD, TIMEOUT.replace(" ", "")); + String subStats3 = String.format(BuildConfig.DEFAULT_LOCALE, "THRS-%dmv|TMT-%s", THRESHOLD, TIMEOUT.replace(" ", "")); ((TextView) LiveLoggerActivity.getContentView(R.id.deviceStats3)).setText(subStats3); SeekBar thresholdSeekbar = (SeekBar) LiveLoggerActivity.getContentView(R.id.thresholdSeekbar); if (thresholdSeekbar != null) { thresholdSeekbar.setProgress(THRESHOLD); - ((TextView) LiveLoggerActivity.getContentView(R.id.thresholdSeekbarValueText)).setText(String.format(Locale.getDefault(), "% 5d mV", THRESHOLD)); + ((TextView) LiveLoggerActivity.getContentView(R.id.thresholdSeekbarValueText)).setText(String.format(BuildConfig.DEFAULT_LOCALE, "% 5d mV", THRESHOLD)); } SeekBar timeoutSeekbar = (SeekBar) LiveLoggerActivity.getContentView(R.id.cmdTimeoutSeekbar); if (thresholdSeekbar != null) { thresholdSeekbar.setProgress(THRESHOLD); - ((TextView) LiveLoggerActivity.getContentView(R.id.cmdTimeoutSeekbarValueText)).setText(String.format(Locale.getDefault(), "% 4s (x128) ms", TIMEOUT)); + ((TextView) LiveLoggerActivity.getContentView(R.id.cmdTimeoutSeekbarValueText)).setText(String.format(BuildConfig.DEFAULT_LOCALE, "% 4s (x128) ms", TIMEOUT)); } } catch (Exception ex) { AndroidLog.printStackTrace(ex); diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonSerialIOInterface.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonSerialIOInterface.java index e5cfbf0..f6e335d 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonSerialIOInterface.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonSerialIOInterface.java @@ -21,9 +21,6 @@ This program (The Chameleon Mini Live Debugger) is free software written by public interface ChameleonSerialIOInterface { - void setListenerContext(Context context); - - String SERIALIO_DEVICE_FOUND = "ChameleonSerialIOInterface.SERIALIO_DEVICE_FOUND"; String SERIALIO_DEVICE_CONNECTION_LOST = "ChameleonSerialIOInterface.SERIALIO_DEVICE_CONNECTION_LOST"; String SERIALIO_DATA_RECEIVED = "ChameleonSerialIOInterface.SERIALIO_DATA_RECEIVED"; String SERIALIO_LOGDATA_RECEIVED = "ChameleonSerialIOInterface.SERIALIO_LOGDATA_RECEIVED"; @@ -31,15 +28,18 @@ public interface ChameleonSerialIOInterface { String SERIALIO_NOTIFY_BTDEV_CONNECTED = "ChameleonSerialIOInterface.SERIALIO_NOTIFY_BTDEV_CONNECTED"; int STATUS_ERROR = -1; + int STATUS_NOT_SUPPORTED = -2; + int STATUS_RESOURCE_UNAVAILABLE = -3; int STATUS_OK = 0; int STATUS_TRUE = 1; int STATUS_FALSE = 0; String getInterfaceLoggingTag(); + void setListenerContext(Context context); + boolean notifySerialDataReceived(byte[] serialData); boolean notifyLogDataReceived(byte[] serialData); - boolean notifyDeviceFound(); boolean notifyDeviceConnectionTerminated(); boolean notifyStatus(String msgType, String statusMsg); @@ -75,9 +75,11 @@ public interface ChameleonSerialIOInterface { int setSerialBaudRateHigh(); int setSerialBaudRateLimited(); + String getDeviceName(); + String getActiveDeviceInfo(); + boolean startScanningDevices(); boolean stopScanningDevices(); - String getActiveDeviceInfo(); int configureSerial(); int shutdownSerial(); diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonSettings.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonSettings.java index 218369e..cd58ccb 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonSettings.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ChameleonSettings.java @@ -17,8 +17,6 @@ This program (The Chameleon Mini Live Debugger) is free software written by package com.maxieds.chameleonminilivedebugger; -import android.util.Log; - public class ChameleonSettings { private static final String TAG = ChameleonSettings.class.getSimpleName(); @@ -44,7 +42,7 @@ public class ChameleonSettings { public static synchronized void initSerialIOPortObjects() { serialIOPorts = new SerialIOReceiver[2]; serialIOPorts[USBIO_IFACE_INDEX] = new SerialUSBInterface(LiveLoggerActivity.getLiveLoggerInstance()); - serialIOPorts[BTIO_IFACE_INDEX] = new BluetoothSerialInterface(LiveLoggerActivity.getLiveLoggerInstance()); + serialIOPorts[BTIO_IFACE_INDEX] = new BluetoothBLEInterface(LiveLoggerActivity.getLiveLoggerInstance()); SERIALIO_IFACE_ACTIVE_INDEX = -1; } @@ -67,7 +65,7 @@ public static void initializeSerialIOConnections() { AndroidLog.i(TAG, "Started scanning for SerialUSB devices ... "); serialIOPorts[si].startScanningDevices(); } - else if(si == BTIO_IFACE_INDEX && allowBluetooth && ((BluetoothSerialInterface) serialIOPorts[si]).isBluetoothEnabled()) { + else if(si == BTIO_IFACE_INDEX && allowBluetooth && ((BluetoothBLEInterface) serialIOPorts[si]).isBluetoothEnabled()) { AndroidLog.i(TAG, "Started scanning for SerialBT devices ... "); serialIOPorts[si].startScanningDevices(); } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/CrashReportActivity.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/CrashReportActivity.java index 1b5bb71..191ab3d 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/CrashReportActivity.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/CrashReportActivity.java @@ -186,10 +186,10 @@ else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { private String getEncodedNewGitHubIssueURL() { String newIssueURL = "https://github.com/maxieds/ChameleonMiniLiveDebugger/issues/new?"; String[][] issueContentsData = new String[][] { - { "CMLD Version", String.format(Locale.getDefault(), "v%s (%d:%d)", + { "CMLD Version", String.format(BuildConfig.DEFAULT_LOCALE, "v%s (%d:%d)", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE, BuildConfig.VERSION_CODE - 8080) }, - { "CMLD GitHub Commit", String.format(Locale.getDefault(), "%s @ %s", + { "CMLD GitHub Commit", String.format(BuildConfig.DEFAULT_LOCALE, "%s @ %s", BuildConfig.GIT_COMMIT_HASH, BuildConfig.GIT_COMMIT_DATE) }, { "CMLD Build Date", BuildConfig.BUILD_TIMESTAMP }, { "Chameleon Type", chameleonDeviceType }, @@ -203,8 +203,8 @@ private String getEncodedNewGitHubIssueURL() { { "Android Product", Build.PRODUCT }, { "Android Model", Build.MODEL }, { "Android Hardware", Build.HARDWARE}, - { "Android SDK", String.format(Locale.getDefault(), "%d", Build.VERSION.SDK_INT) }, - { "Android OS Release", String.format(Locale.getDefault(), "%s %s (%s / %s)", + { "Android SDK", String.format(BuildConfig.DEFAULT_LOCALE, "%d", Build.VERSION.SDK_INT) }, + { "Android OS Release", String.format(BuildConfig.DEFAULT_LOCALE, "%s %s (%s / %s)", Build.VERSION.BASE_OS, Build.VERSION.RELEASE, Build.VERSION.CODENAME, Build.VERSION.INCREMENTAL) }, { "Android Board", Build.BOARD }, @@ -228,10 +228,10 @@ private String getEncodedNewGitHubIssueURL() { issueBodyText += "the application? Did you click a button or switch tabs? Any extra details about how the error "; issueBodyText += "happened are useful to fixing the issue in future releases.*\n\n"; int invokingMsgLastItemPos = invokingExcptMsg.lastIndexOf(':'); - String issueTitle = String.format(Locale.getDefault(), "Crash Report (CMLD %s): %s [Android %s, SDK %d]", + String issueTitle = String.format(BuildConfig.DEFAULT_LOCALE, "Crash Report (CMLD %s): %s [Android %s, SDK %d]", BuildConfig.VERSION_NAME, invokingExcptMsg.substring(invokingMsgLastItemPos + 1), Build.VERSION.RELEASE, Build.VERSION.SDK_INT); - newIssueURL += String.format(Locale.getDefault(), "title=%s&body=%s&assignee=maxieds", + newIssueURL += String.format(BuildConfig.DEFAULT_LOCALE, "title=%s&body=%s&assignee=maxieds", Utils.encodeAsciiToURL(issueTitle), Utils.encodeAsciiToURL(issueBodyText)); return newIssueURL; } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ExportTools.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ExportTools.java index 312efdc..7691452 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ExportTools.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ExportTools.java @@ -494,11 +494,11 @@ public static boolean writeHTMLLogFile(File fd) throws Exception { FileOutputStream fout = new FileOutputStream(fd); String htmlHeader = "Chameleon Mini Live Debugger -- Logging Output\n\n"; fout.write(htmlHeader.getBytes(StandardCharsets.US_ASCII)); - String defaultBgColor = String.format(Locale.getDefault(), "#%06X", (0xFFFFFF & ThemesConfiguration.getThemeColorVariant(R.attr.colorPrimaryDarkLog))); + String defaultBgColor = String.format(BuildConfig.DEFAULT_LOCALE, "#%06X", (0xFFFFFF & ThemesConfiguration.getThemeColorVariant(R.attr.colorPrimaryDarkLog))); for (int vi = 0; vi < MainActivityLogUtils.logDataFeed.getChildCount(); vi++) { View logEntryView = MainActivityLogUtils.logDataFeed.getChildAt(vi); if (MainActivityLogUtils.logDataEntries.get(vi) instanceof LogEntryUI) { - String bgColor = String.format(Locale.getDefault(), "#%06X", (0xFFFFFF & logEntryView.getDrawingCacheBackgroundColor())); + String bgColor = String.format(BuildConfig.DEFAULT_LOCALE, "#%06X", (0xFFFFFF & logEntryView.getDrawingCacheBackgroundColor())); if(bgColor.equals(defaultBgColor)) bgColor = "#ffffff"; String lineData = "" + ((LogEntryUI) MainActivityLogUtils.logDataEntries.get(vi)).toString() + "
\n"; diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ExternalFileIO.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ExternalFileIO.java index 9a7f71b..d38fb59 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ExternalFileIO.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ExternalFileIO.java @@ -150,7 +150,7 @@ public static void handleActivityResult(ChameleonMiniLiveDebuggerActivity activi String selectedChooserPath = ""; try { List selectedFilePathsList = FileChooserBuilder.handleActivityResult(activity, chooserRequestCodeAction, resultCode, data); - selectedChooserPath = String.format(Locale.getDefault(), AndroidFileChooser.getFileNotifySelectExceptionFormat(), selectedFilePathsList.get(0)); + selectedChooserPath = String.format(BuildConfig.DEFAULT_LOCALE, AndroidFileChooser.getFileNotifySelectExceptionFormat(), selectedFilePathsList.get(0)); } catch(Exception ex) { AndroidLog.printStackTrace(ex); } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/LiveLoggerActivity.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/LiveLoggerActivity.java index a98120e..ab9997f 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/LiveLoggerActivity.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/LiveLoggerActivity.java @@ -346,19 +346,35 @@ else if(!isTaskRoot()) { configureTabViewPager(); if(completeRestart) { - String[] permissions = { - "android.permission.READ_EXTERNAL_STORAGE", - "android.permission.WRITE_EXTERNAL_STORAGE", - "android.permission.INTERNET", - "android.permission.USB_PERMISSION", - "android.permission.BLUETOOTH", - "android.permission.BLUETOOTH_CONNECT", - "android.permission.BLUETOOTH_ADMIN", - "android.permission.BLUETOOTH_SCAN", - "android.permission.ACCESS_COARSE_LOCATION", - "android.permission.ACCESS_FINE_LOCATION", - "android.permission.VIBRATE", - }; + String[] permissions; + if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + permissions = new String[]{ + "android.permission.READ_EXTERNAL_STORAGE", + "android.permission.WRITE_EXTERNAL_STORAGE", + "android.permission.INTERNET", + "android.permission.USB_PERMISSION", + "android.permission.ACCESS_COARSE_LOCATION", + "android.permission.ACCESS_FINE_LOCATION", + "android.permission.VIBRATE", + "android.permission.BLUETOOTH", + "android.permission.BLUETOOTH_ADMIN", + }; + } else { + permissions = new String[] { + "android.permission.READ_EXTERNAL_STORAGE", + "android.permission.WRITE_EXTERNAL_STORAGE", + "android.permission.INTERNET", + "android.permission.USB_PERMISSION", + "android.permission.ACCESS_COARSE_LOCATION", + "android.permission.ACCESS_FINE_LOCATION", + "android.permission.VIBRATE", + "android.permission.BLUETOOTH", + "android.permission.BLUETOOTH_ADMIN", + "android.permission.BLUETOOTH_SCAN", + "android.permission.BLUETOOTH_CONNECT", + "android.permission.BLUETOOTH_ADVERTISE", + }; + } if (android.os.Build.VERSION.SDK_INT >= 23) { for(String permissionName : permissions) { requestPermissions(new String[] { permissionName }, 0); @@ -393,7 +409,7 @@ else if(!isTaskRoot()) { clearStatusIcon(R.id.statusCodecRXDataEvent); clearStatusIcon(R.id.statusScriptingIsExec); - if(BuildConfig.FLAVOR.equals("paid")) { + if(BuildConfig.PAID_APP_VERSION) { String userGreeting = getString(R.string.appInitialUserGreetingMsgPaid); MainActivityLogUtils.appendNewLog(LogEntryMetadataRecord.createDefaultEventRecord("WELCOME", userGreeting)); String disclaimerStmt = getString(R.string.appPaidFlavorDisclaimerEULA); @@ -571,7 +587,7 @@ else if(intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED) || ChameleonSettings.initializeSerialIOConnections(); } else if(intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) { - BluetoothGattConnector btGattConnect = ((BluetoothSerialInterface) ChameleonSettings.serialIOPorts[ChameleonSettings.BTIO_IFACE_INDEX]).getBluetoothGattConnector(); + BluetoothGattConnector btGattConnect = ((BluetoothBLEInterface) ChameleonSettings.serialIOPorts[ChameleonSettings.BTIO_IFACE_INDEX]).getBluetoothGattConnector(); if(btGattConnect == null) { return; } @@ -579,7 +595,7 @@ else if(intent.getAction().equals(BluetoothDevice.ACTION_FOUND)) { if(btLocalDevice == null) { return; } - btGattConnect.notifyBluetoothSerialInterfaceDeviceConnected(btLocalDevice); + btGattConnect.notifyBluetoothBLEDeviceConnected(btLocalDevice); } else if(intent.getAction().equals(BluetoothDevice.ACTION_ACL_CONNECTED) || intent.getAction().equals(ChameleonSerialIOInterface.SERIALIO_NOTIFY_BTDEV_CONNECTED)) { @@ -592,7 +608,7 @@ else if(intent.getAction().equals(BluetoothDevice.ACTION_ACL_CONNECTED) || Runnable configDeviceRunnable = new Runnable() { public void run() { if(ChameleonSettings.getActiveSerialIOPort() != null && - ((BluetoothSerialInterface) ChameleonSettings.getActiveSerialIOPort()).isDeviceConnected()) { + ((BluetoothBLEInterface) ChameleonSettings.getActiveSerialIOPort()).isDeviceConnected()) { ChameleonIO.detectChameleonType(); ChameleonPeripherals.actionButtonRestorePeripheralDefaults(null); TabFragment.UITAB_DATA[TabFragment.TAB_TOOLS].changeMenuItemDisplay(TAB_TOOLS_MITEM_SLOTS, true); @@ -630,7 +646,7 @@ else if(intent.getAction().equals(BluetoothDevice.ACTION_ACL_DISCONNECTED) || else if(intent.getAction().equals(ChameleonSerialIOInterface.SERIALIO_DATA_RECEIVED)) { byte[] serialByteData = intent.getByteArrayExtra("DATA"); int logCodeByteCount = ChameleonLogUtils.ResponseIsLiveLoggingBytes(serialByteData); - String dataMsg = String.format(Locale.getDefault(), "Unexpected serial I/O data received (data as log below)"); + String dataMsg = String.format(BuildConfig.DEFAULT_LOCALE, "Unexpected serial I/O data received (data as log below)"); MainActivityLogUtils.appendNewLog(LogEntryMetadataRecord.createDefaultEventRecord("ERROR", dataMsg)); MainActivityLogUtils.appendNewLog(LogEntryUI.newInstance(serialByteData, "")); } @@ -1034,7 +1050,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } else { toastStatusMsg = "All CMLD app permissions requested. Enable all to ensure the app runs correctly."; } - } else if (resultCode == BluetoothSerialInterface.ACTVITY_REQUEST_BLUETOOTH_ENABLED_CODE) { + } else if (resultCode == BluetoothBLEInterface.ACTVITY_REQUEST_BLUETOOTH_ENABLED_CODE) { if(resultCode == Activity.RESULT_CANCELED) { /* Bluetooth not enabled: */ finish(); @@ -1042,7 +1058,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } else { toastStatusMsg = "Bluetooth permissions enabled."; } - } else if (resultCode == BluetoothSerialInterface.ACTVITY_REQUEST_BLUETOOTH_DISCOVERABLE_CODE) { + } else if (resultCode == BluetoothBLEInterface.ACTVITY_REQUEST_BLUETOOTH_DISCOVERABLE_CODE) { if(resultCode == Activity.RESULT_CANCELED) { /* Bluetooth discovery not enabled: */ finish(); @@ -1216,11 +1232,11 @@ public void actionButtonDESFireTerminalCommand(@NonNull View view) { } int cmdReqNumBytes = Integer.parseInt(cmdTagComps[1]); if (piccSetBytes.length() != 2 * cmdReqNumBytes) { - String toastErrorMsg = String.format(Locale.getDefault(), "Invalid number of bytes. The command requires %d bytes.", cmdReqNumBytes); + String toastErrorMsg = String.format(BuildConfig.DEFAULT_LOCALE, "Invalid number of bytes. The command requires %d bytes.", cmdReqNumBytes); Utils.displayToastMessageShort(toastErrorMsg); return; } - String chamCmd = String.format(Locale.getDefault(), cmdTagComps[0], piccSetBytes); + String chamCmd = String.format(BuildConfig.DEFAULT_LOCALE, cmdTagComps[0], piccSetBytes); ChameleonIO.executeChameleonMiniCommand(chamCmd, ChameleonIO.TIMEOUT); } } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/LogEntryMetadataRecord.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/LogEntryMetadataRecord.java index 4f9457e..253b8cd 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/LogEntryMetadataRecord.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/LogEntryMetadataRecord.java @@ -188,18 +188,18 @@ public static LogEntryMetadataRecord createDefaultEventRecord(String eventID, St if(eventID.equals("LOCATION")) { String[] locCoords = Utils.getGPSLocationCoordinates(); String locationDetails = ""; - locationDetails += String.format(Locale.getDefault(), "Coordinates: (%s lat, %s long)\n", locCoords[0], locCoords[1]); + locationDetails += String.format(BuildConfig.DEFAULT_LOCALE, "Coordinates: (%s lat, %s long)\n", locCoords[0], locCoords[1]); try { - Geocoder gc = new Geocoder(LiveLoggerActivity.getLiveLoggerInstance(), Locale.getDefault()); + Geocoder gc = new Geocoder(LiveLoggerActivity.getLiveLoggerInstance(), BuildConfig.DEFAULT_LOCALE); List
gcAddrs = gc.getFromLocation(Double.parseDouble(locCoords[0]), Double.parseDouble(locCoords[0]), 1); if (gcAddrs != null && gcAddrs.size() > 0) { - locationDetails += String.format(Locale.getDefault(), "Address: %s, %s, %s %s\n", + locationDetails += String.format(BuildConfig.DEFAULT_LOCALE, "Address: %s, %s, %s %s\n", gcAddrs.get(0).getAddressLine(0), gcAddrs.get(0).getLocality(), gcAddrs.get(0).getAdminArea(), gcAddrs.get(0).getPostalCode(), gcAddrs.get(0).getCountryName()); String knownLocID = gcAddrs.get(0).getFeatureName(); if(knownLocID != null) { - locationDetails += String.format(Locale.getDefault(), "Known ID: %s", knownLocID); + locationDetails += String.format(BuildConfig.DEFAULT_LOCALE, "Known ID: %s", knownLocID); } } } catch (Exception e) { diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/LogEntryUI.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/LogEntryUI.java index b569cbf..fbc3f31 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/LogEntryUI.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/LogEntryUI.java @@ -58,7 +58,7 @@ public class LogEntryUI extends LogEntryBase { private CheckBox entrySelect; private ImageView inoutDirIndicator, apduParseStatus; private TextView tvLabel, tvNumBytes, tvNumMillis, tvLogType, tvEntropy; - private TextView tvDataHexBytes, tvDataAscii, tvApdu, tvDuplicateCount; + private TextView tvDataHexBytes, tvDataAscii, tvDataUint32Values, tvApdu, tvDuplicateCount; /** * Metadata associated with the log entry. @@ -163,6 +163,11 @@ public View cloneLayoutContainer() { TextView tvDataAsciiClone = (TextView) mainEntryContainerClone.findViewById(R.id.text_logdata_ascii); tvDataAsciiClone.setText(tvDataAscii.getText()); TextView tvApduClone = (TextView) mainEntryContainerClone.findViewById(R.id.text_apdu); + TextView tvDataUint32ValuesClone = (TextView) mainEntryContainerClone.findViewById(R.id.text_logdata_uint32_values); + tvDataUint32ValuesClone.setText(tvDataUint32Values.getText()); + if (tvDataUint32Values.getVisibility() == LinearLayout.INVISIBLE) { + tvDataUint32ValuesClone.setVisibility(LinearLayout.INVISIBLE); + } tvApduClone.setText(tvApdu.getText()); if (tvApduClone.getText().toString().equals("APDU: NONE RECOGNIZED")) { tvApduClone.setVisibility(TextView.GONE); @@ -191,7 +196,7 @@ public void configureLayout(LinearLayout mainContainerRef) { apduParseStatus = (ImageView) mainContainerRef.findViewById(R.id.apduParseStatusImg); tvLabel = (TextView) mainContainerRef.findViewById(R.id.text_label); recordID = ++MainActivityLogUtils.RECORDID; - tvLabel.setText(logLabel + String.format(Locale.getDefault(), "%06d", MainActivityLogUtils.RECORDID)); + tvLabel.setText(logLabel + String.format(BuildConfig.DEFAULT_LOCALE, "%06d", MainActivityLogUtils.RECORDID)); tvNumBytes = (TextView) mainContainerRef.findViewById(R.id.text_data_num_bytes); tvNumBytes.setText(String.valueOf(numBytes) + "B"); tvNumMillis = (TextView) mainContainerRef.findViewById(R.id.text_offset_millis); @@ -199,11 +204,33 @@ public void configureLayout(LinearLayout mainContainerRef) { tvLogType = (TextView) mainContainerRef.findViewById(R.id.text_log_type); tvLogType.setText(ChameleonLogUtils.LogCode.lookupByLogCode(logType).getShortCodeName(logType)); tvEntropy = (TextView) mainContainerRef.findViewById(R.id.text_entropy_compression_ratio); - tvEntropy.setText(String.format(Locale.getDefault(), "CPR/ENT: %1.4g", Utils.computeByteArrayEntropy(entryData))); + tvEntropy.setText(String.format(BuildConfig.DEFAULT_LOCALE, "CPR/ENT: %1.4g", Utils.computeByteArrayEntropy(entryData))); tvDataHexBytes = (TextView) mainContainerRef.findViewById(R.id.text_logdata_hex); tvDataHexBytes.setText(Utils.bytes2Hex(entryData)); tvDataAscii = (TextView) mainContainerRef.findViewById(R.id.text_logdata_ascii); tvDataAscii.setText(Utils.bytes2Ascii(entryData)); + TextView tvDataUint32ValuesClone = (TextView) mainContainerRef.findViewById(R.id.text_logdata_uint32_values); + if (entryData.length > 0 && entryData.length <= 4) { + final int base10MaxDigitsToPrint = 6; + + long uint32LE = Utils.bytesToUint32LittleEndian(entryData); + boolean displayDecimalValuesLE = ((int) Math.ceil(Math.log10(uint32LE))) >= base10MaxDigitsToPrint; + String uint32LEDesc = String.format(BuildConfig.DEFAULT_LOCALE, "0x%08X", uint32LE); + if (displayDecimalValuesLE) { + uint32LEDesc += String.format(BuildConfig.DEFAULT_LOCALE, ", %d", uint32LE); + } + uint32LEDesc += String.format(BuildConfig.DEFAULT_LOCALE, " (Little Endian); "); + long uint32BE = Utils.bytesToUint32BigEndian(entryData); + boolean displayDecimalValuesBE = ((int) Math.ceil(Math.log10(uint32BE))) >= base10MaxDigitsToPrint; + String uint32BEDesc = String.format(BuildConfig.DEFAULT_LOCALE, "0x%08X", uint32BE); + if (displayDecimalValuesBE) { + uint32BEDesc += String.format(BuildConfig.DEFAULT_LOCALE, ", %d", uint32BE); + } + uint32BEDesc += String.format(BuildConfig.DEFAULT_LOCALE, " (Big Endian); "); + tvDataUint32Values.setText(uint32LEDesc + uint32BEDesc); + } else { + tvDataUint32Values.setVisibility(LinearLayout.INVISIBLE); + } tvApdu = (TextView) mainContainerRef.findViewById(R.id.text_apdu); tvApdu.setText(ApduUtils.classifyApdu(entryData)); tvDuplicateCount = (TextView) mainEntryContainer.findViewById(R.id.text_duplicate_count); @@ -297,10 +324,10 @@ public boolean appendDuplicate(short offsetTimeMillis) { boolean drawCountInHex = Math.log10(numDuplicates) > 5.0 ? true : false; String duplicateNumberText = ""; if(drawCountInHex) { - duplicateNumberText = String.format(Locale.getDefault(), "0x%04x", numDuplicates); + duplicateNumberText = String.format(BuildConfig.DEFAULT_LOCALE, "0x%04x", numDuplicates); } else { - duplicateNumberText = String.format(Locale.getDefault(), "%06d", numDuplicates); + duplicateNumberText = String.format(BuildConfig.DEFAULT_LOCALE, "%06d", numDuplicates); } duplicateNumberText += " -- IDENTICAL LOGS"; tvDuplicateCount.setVisibility(View.VISIBLE); @@ -337,7 +364,7 @@ public String writeXMLFragment(int indentLevel) { @Override public String toString() { ChameleonLogUtils.LogCode logCode = ChameleonLogUtils.LogCode.lookupByLogCode(logType); - String recordFmt = String.format(Locale.getDefault(), "%06d -- %-32s [%-3s bytes] (%s%-6s ms) [%s] {%s}", recordID, logCode.name(), + String recordFmt = String.format(BuildConfig.DEFAULT_LOCALE, "%06d -- %-32s [%-3s bytes] (%s%-6s ms) [%s] {%s}", recordID, logCode.name(), String.valueOf(entryData.length), diffTimeMillis >= 0 ? "+" : "~", String.valueOf(abs(diffTimeMillis)), Utils.bytes2Hex(entryData), tvApdu.getText().toString()); return recordFmt; diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/MainActivityLogUtils.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/MainActivityLogUtils.java index d117609..aaa44bf 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/MainActivityLogUtils.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/MainActivityLogUtils.java @@ -361,7 +361,7 @@ else if (selectedBytes && !Utils.stringIsHexadecimal(searchString)) { } else if (selectedBytes) { searchString = searchString.replace("[\n\t\r]+", "").replaceAll("..(?!$)", "$0 "); } - searchString = searchString.toLowerCase(Locale.getDefault()); + searchString = searchString.toLowerCase(BuildConfig.DEFAULT_LOCALE); searchStatus = ((CheckBox) llActivity.findViewById(R.id.entrySearchIncludeStatus)).isChecked(); searchAPDU = ((CheckBox) llActivity.findViewById(R.id.entrySearchAPDU)).isChecked(); searchLogPayload = ((CheckBox) llActivity.findViewById(R.id.entrySearchRawLogData)).isChecked(); @@ -378,7 +378,7 @@ else if (selectedBytes && !Utils.stringIsHexadecimal(searchString)) { continue; } if (nextLogEntry instanceof LogEntryMetadataRecord) { - if (searchStatus && nextLogEntry.toString().toLowerCase(Locale.getDefault()).contains(searchString)) { + if (searchStatus && nextLogEntry.toString().toLowerCase(BuildConfig.DEFAULT_LOCALE).contains(searchString)) { searchResultsContainer.addView(nextLogEntry.cloneLayoutContainer()); matchCount++; } @@ -386,9 +386,9 @@ else if (selectedBytes && !Utils.stringIsHexadecimal(searchString)) { } LogEntryUI nextLogEntryUI = (LogEntryUI) nextLogEntry; AndroidLog.i(TAG, nextLogEntryUI.getPayloadDataString(selectedBytes)); - if (searchAPDU && nextLogEntryUI.getAPDUString().toLowerCase(Locale.getDefault()).contains(searchString) || - searchLogHeaders && nextLogEntryUI.getLogCodeName().toLowerCase(Locale.getDefault()).contains(searchString) || - searchLogPayload && nextLogEntryUI.getPayloadDataString(selectedBytes).toLowerCase(Locale.getDefault()).contains(searchString)) { + if (searchAPDU && nextLogEntryUI.getAPDUString().toLowerCase(BuildConfig.DEFAULT_LOCALE).contains(searchString) || + searchLogHeaders && nextLogEntryUI.getLogCodeName().toLowerCase(BuildConfig.DEFAULT_LOCALE).contains(searchString) || + searchLogPayload && nextLogEntryUI.getPayloadDataString(selectedBytes).toLowerCase(BuildConfig.DEFAULT_LOCALE).contains(searchString)) { LinearLayout searchResult = (LinearLayout) nextLogEntryUI.cloneLayoutContainer(); if(searchResult != null) { searchResult.setVisibility(LinearLayout.VISIBLE); @@ -404,7 +404,7 @@ else if (selectedBytes && !Utils.stringIsHexadecimal(searchString)) { } /* Report stats on the search time and display the findings: */ double diffSeconds = (double) (System.currentTimeMillis() - startTime) / 1000.0; - String resultStr = String.format(Locale.getDefault(), "Explored #%d logs in %4g seconds for a total of #%d matching records.", + String resultStr = String.format(BuildConfig.DEFAULT_LOCALE, "Explored #%d logs in %4g seconds for a total of #%d matching records.", logDataEntries.size(), diffSeconds, matchCount); searchResultsContainer.addView(LogEntryMetadataRecord.createDefaultEventRecord("SEARCH", resultStr).getLayoutContainer()); } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/MainActivityNavActions.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/MainActivityNavActions.java index be84481..8470719 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/MainActivityNavActions.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/MainActivityNavActions.java @@ -44,7 +44,7 @@ public static AlertDialog getAboutTheAppDialog() { rawAboutStr = rawAboutStr.replace("%%GIT_COMMIT_DATE%%", String.valueOf(BuildConfig.GIT_COMMIT_DATE)); int aboutLinkColor = LiveLoggerActivity.getLiveLoggerInstance().getTheme().obtainStyledAttributes(new int[] {R.attr.colorAboutLinkColor}).getColor(0, LiveLoggerActivity.getLiveLoggerInstance().getResources().getColor(R.color.colorBigVeryBadError)); - rawAboutStr = rawAboutStr.replace("%%ABOUTLINKCOLOR%%", String.format(Locale.getDefault(), "#%06X", 0xFFFFFF & aboutLinkColor)); + rawAboutStr = rawAboutStr.replace("%%ABOUTLINKCOLOR%%", String.format(BuildConfig.DEFAULT_LOCALE, "#%06X", 0xFFFFFF & aboutLinkColor)); WebView wv = new WebView(LiveLoggerActivity.getLiveLoggerInstance()); wv.getSettings().setJavaScriptEnabled(false); diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ChameleonScripting.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ChameleonScripting.java index 4bd8eb2..4d74c4c 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ChameleonScripting.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ChameleonScripting.java @@ -18,7 +18,6 @@ This program (The Chameleon Mini Live Debugger) is free software written by package com.maxieds.chameleonminilivedebugger.ScriptingAPI; import android.os.Handler; -import android.util.Log; import android.widget.LinearLayout; import com.maxieds.chameleonminilivedebugger.AndroidLog; @@ -30,6 +29,7 @@ This program (The Chameleon Mini Live Debugger) is free software written by import com.maxieds.chameleonminilivedebugger.SerialIOReceiver; import com.maxieds.chameleonminilivedebugger.TabFragment; import com.maxieds.chameleonminilivedebugger.Utils; +import com.maxieds.chameleonminilivedebugger.BuildConfig; import org.antlr.v4.runtime.ANTLRInputStream; import org.antlr.v4.runtime.CommonTokenStream; @@ -121,19 +121,19 @@ public void restoreState(boolean pop) { ChameleonSerialIOInterface serialIOPort = ChameleonSettings.getActiveSerialIOPort(); if(serialIOPort != null) { if (!ChameleonIO.REVE_BOARD) { - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "CONFIG=%s", CONFIG)); - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "UID=%s", UID)); - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "LOGMODE=%s", LOGMODE)); - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "SETTING=%s", SETTING)); - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "READONLY=%s", READONLY)); - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "FIELD=%s", FIELD)); - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "THRESHOLD=%s", THRESHOLD)); - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "TIMEOUT=%s", TIMEOUT)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "CONFIG=%s", CONFIG)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "UID=%s", UID)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "LOGMODE=%s", LOGMODE)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "SETTING=%s", SETTING)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "READONLY=%s", READONLY)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "FIELD=%s", FIELD)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "THRESHOLD=%s", THRESHOLD)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "TIMEOUT=%s", TIMEOUT)); } else { - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "config=%s", CONFIG)); - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "uid=%s", UID)); - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "setting=%s", SETTING)); - ChameleonIOHandler.executeChameleonCommandForResult(String.format(Locale.getDefault(), "readonly=%s", READONLY)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "config=%s", CONFIG)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "uid=%s", UID)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "setting=%s", SETTING)); + ChameleonIOHandler.executeChameleonCommandForResult(String.format(BuildConfig.DEFAULT_LOCALE, "readonly=%s", READONLY)); } } if(serialIOPort != null && pop && !SAVED_DEVICE_STATES.empty()) { @@ -275,13 +275,13 @@ private boolean runScriptPreambleActions() { if(loadedScriptHasSyntaxErrors()) { List syntaxErrorsList = getSyntaxErrors(); for(ChameleonScriptErrorListener.SyntaxError syntaxError : syntaxErrorsList) { - String syntaxErrorNotifyMsg = String.format(Locale.getDefault(), "%s\n%s", + String syntaxErrorNotifyMsg = String.format(BuildConfig.DEFAULT_LOCALE, "%s\n%s", syntaxError.getException().getClass().getSimpleName(), syntaxError.getMessage()); String[] syntaxErrorDetailsList = new String[] { - String.format(Locale.getDefault(), "@LINE-NO: %d", syntaxError.getLine()), - String.format(Locale.getDefault(), "@CHAR-POS: %d", syntaxError.getCharPositionInLine()), - String.format(Locale.getDefault(), "@SYMBOL: '%s'", syntaxError.getOffendingSymbol().toString()), - String.format(Locale.getDefault(), "@TOKEN: %s", syntaxError.getException().getOffendingToken().getText()) + String.format(BuildConfig.DEFAULT_LOCALE, "@LINE-NO: %d", syntaxError.getLine()), + String.format(BuildConfig.DEFAULT_LOCALE, "@CHAR-POS: %d", syntaxError.getCharPositionInLine()), + String.format(BuildConfig.DEFAULT_LOCALE, "@SYMBOL: '%s'", syntaxError.getOffendingSymbol().toString()), + String.format(BuildConfig.DEFAULT_LOCALE, "@TOKEN: %s", syntaxError.getException().getOffendingToken().getText()) }; ScriptingGUIConsole.appendConsoleOutputRecordErrorWarning(syntaxErrorNotifyMsg, syntaxErrorDetailsList, syntaxError.getLine()); AndroidLog.w(TAG, "SYNTAX ERROR: " + syntaxErrorNotifyMsg + "\n" + String.join("\n > ", syntaxErrorDetailsList)); @@ -342,13 +342,13 @@ public void run() { scriptVisitor.visit(scriptParser.file_contents()); //scriptVisitor.visit(scriptParseTree); - writeLogFile(String.format(Locale.getDefault(), "TEXT PARSE TREE for file \"%s\":\n\n%s\n", scriptFilePath, scriptParseTree.toStringTree())); + writeLogFile(String.format(BuildConfig.DEFAULT_LOCALE, "TEXT PARSE TREE for file \"%s\":\n\n%s\n", scriptFilePath, scriptParseTree.toStringTree())); runningTime = System.currentTimeMillis() - lastStartTime; setTimeLimitHandler.removeCallbacks(enforceTimeLimitRunnable); scriptState = ScriptRuntimeState.FINISHED; ScriptingUtils.signalStateChangeByVibration(scriptState); - String scriptRuntimeSummaryMsg = String.format(Locale.getDefault(), "The script finished running normally in %g min (%g sec).", + String scriptRuntimeSummaryMsg = String.format(BuildConfig.DEFAULT_LOCALE, "The script finished running normally in %g min (%g sec).", runningTime / 60000.0, runningTime / 1000.0); scriptRuntimeSummaryMsg += "It generated the following output:\n\n"; scriptRuntimeSummaryMsg += getConsoleOutput(); @@ -377,7 +377,7 @@ public void run() { String ewarnMsg = "Unexpected exception caught."; try { RuntimeException rtEx = (RuntimeException) paramExcpt; - ewarnMsg = String.format(Locale.getDefault(), "%s: \n%s", rtEx.getClass().getSimpleName(), rtEx.getMessage()); + ewarnMsg = String.format(BuildConfig.DEFAULT_LOCALE, "%s: \n%s", rtEx.getClass().getSimpleName(), rtEx.getMessage()); ScriptingGUIConsole.appendConsoleOutputRecordErrorWarning(ewarnMsg, null, getExecutingLineOfCode()); } catch(Exception ex) { AndroidLog.printStackTrace(ex); @@ -451,7 +451,7 @@ public boolean variableNameExists(String varName) { public ScriptingTypes.ScriptVariable lookupVariableByName(String varName) throws ScriptingExceptions.ChameleonScriptingException { ScriptingTypes.ScriptVariable svar = scriptVariablesHashMap.get(varName); - AndroidLog.i(TAG, String.format(Locale.getDefault(), "LOOKED UP (%s) -> VARBYNAME = %s", varName, svar.getName())); + AndroidLog.i(TAG, String.format(BuildConfig.DEFAULT_LOCALE, "LOOKED UP (%s) -> VARBYNAME = %s", varName, svar.getName())); return svar; } @@ -469,7 +469,7 @@ public boolean writeLogFile(String logLine) { return false; } try { - loggingFileStream.write(String.format(Locale.getDefault(), ">> [%s] %s\n", Utils.getTimestamp(), logLine).getBytes()); + loggingFileStream.write(String.format(BuildConfig.DEFAULT_LOCALE, ">> [%s] %s\n", Utils.getTimestamp(), logLine).getBytes()); AndroidLog.i(TAG, "LOG FILE LINE>> " + logLine); } catch(IOException ioe) { AndroidLog.printStackTrace(ioe); @@ -524,7 +524,7 @@ public static boolean runScriptFromStart() { String scriptPath = ScriptingFileIO.expandStoragePath(ScriptingConfig.LAST_SCRIPT_LOADED_PATH); AndroidLog.i(TAG, "Attempting to run script from file path: " + scriptPath); if(ScriptingFileIO.getStoragePathFromRelative(scriptPath, false, false) == null) { - Utils.displayToastMessageShort(String.format(Locale.getDefault(), "Invalid script file path \"%s\".", scriptPath)); + Utils.displayToastMessageShort(String.format(BuildConfig.DEFAULT_LOCALE, "Invalid script file path \"%s\".", scriptPath)); return false; } if(activeChameleonScript != null && !activeChameleonScript.scriptRunnerThread.isInterrupted()) { diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingBreakPoint.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingBreakPoint.java index e6bddb2..c962021 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingBreakPoint.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingBreakPoint.java @@ -135,9 +135,9 @@ public void onClick(View btnView) { return; } if(isLabelType) { - tvBpValue.setText(String.format(Locale.getDefault(), "@%s", getLabel())); + tvBpValue.setText(String.format(BuildConfig.DEFAULT_LOCALE, "@%s", getLabel())); } else { - tvBpValue.setText(String.format(Locale.getDefault(), "L%d (0x%02X)", getLineNumber(), getLineNumber())); + tvBpValue.setText(String.format(BuildConfig.DEFAULT_LOCALE, "L%d (0x%02X)", getLineNumber(), getLineNumber())); } } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingExceptions.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingExceptions.java index c16adec..6860ce7 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingExceptions.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingExceptions.java @@ -17,13 +17,10 @@ This program (The Chameleon Mini Live Debugger) is free software written by package com.maxieds.chameleonminilivedebugger.ScriptingAPI; -import android.util.Log; - import androidx.annotation.NonNull; import com.maxieds.chameleonminilivedebugger.AndroidLog; - -import java.util.Locale; +import com.maxieds.chameleonminilivedebugger.BuildConfig; public class ScriptingExceptions { @@ -64,7 +61,7 @@ public ChameleonScriptingException(@NonNull ExceptionType exType) { } public ChameleonScriptingException(@NonNull ExceptionType exType, String msg) { - super(String.format(Locale.getDefault(), "%s => %s", exType.name(), msg)); + super(String.format(BuildConfig.DEFAULT_LOCALE, "%s => %s", exType.name(), msg)); } public int getInvokingLineNumber() { diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingFunctions.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingFunctions.java index dddbcd4..a1ff28b 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingFunctions.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingFunctions.java @@ -152,7 +152,7 @@ public static ScriptVariable Exit(List argList) throws Chameleon if(argList.size() != 1) { throw new ChameleonScriptingException(ExceptionType.InvalidArgumentException, "Invalid number of parameters."); } - String scriptExitMsg = String.format(Locale.getDefault(), "Script exited with CODE = %d.", argList.get(0).getValueAsInt()); + String scriptExitMsg = String.format(BuildConfig.DEFAULT_LOCALE, "Script exited with CODE = %d.", argList.get(0).getValueAsInt()); ChameleonScripting.getRunningInstance().killRunningScript(scriptExitMsg); return ScriptingTypes.ScriptVariable.newInstance(); } @@ -206,7 +206,7 @@ public static ScriptVariable Sprintf(List argList) throws Chamel } if(fmtSearchPos == rawStringPart.length()) { ScriptingGUIConsole.appendConsoleOutputRecordErrorWarning( - String.format(Locale.getDefault(), "String format error '%s' is invalid!", rawStringPart), + String.format(BuildConfig.DEFAULT_LOCALE, "String format error '%s' is invalid!", rawStringPart), null, ChameleonScripting.getRunningInstance().getExecutingLineOfCode() ); @@ -216,19 +216,19 @@ public static ScriptVariable Sprintf(List argList) throws Chamel char fmtSpec = rawStringPart.charAt(fmtSearchPos); try { if(fmtSpec == 's' || fmtSpec == 'S' || fmtSpec == 'c') { - consoleOutput.append(String.format(Locale.getDefault(), rawStringPart, argList.get(varIndex).getValueAsString())); + consoleOutput.append(String.format(BuildConfig.DEFAULT_LOCALE, rawStringPart, argList.get(varIndex).getValueAsString())); } else if(!argList.get(varIndex).isIntegerType()) { rawStringPart = "%s" + rawStringPart.substring(fmtSearchPos + 1); - consoleOutput.append(String.format(Locale.getDefault(), rawStringPart, argList.get(varIndex).getValueAsString())); + consoleOutput.append(String.format(BuildConfig.DEFAULT_LOCALE, rawStringPart, argList.get(varIndex).getValueAsString())); } else { - consoleOutput.append(String.format(Locale.getDefault(), rawStringPart, argList.get(varIndex).getValueAsInt())); + consoleOutput.append(String.format(BuildConfig.DEFAULT_LOCALE, rawStringPart, argList.get(varIndex).getValueAsInt())); } } catch(Exception strFmtEx) { AndroidLog.printStackTrace(strFmtEx); ScriptingGUIConsole.appendConsoleOutputRecordErrorWarning( - String.format(Locale.getDefault(), "String format error '%s' is invalid!", rawStringPart), + String.format(BuildConfig.DEFAULT_LOCALE, "String format error '%s' is invalid!", rawStringPart), null, ChameleonScripting.getRunningInstance().getExecutingLineOfCode() ); @@ -377,7 +377,7 @@ public static ScriptVariable ArrayToString(List argList) throws AndroidLog.i(TAG,"ArrayToString -> Array Length = " + arrLength); for(int ai = 0; ai < arrLength; ai++) { String nextSpace = (ai + 1 == arrLength) ? " " : ", "; - arrReprStr += String.format(Locale.getDefault(), "%s%s", arrVar.getValueAt(ai).getValueAsString(), nextSpace); + arrReprStr += String.format(BuildConfig.DEFAULT_LOCALE, "%s%s", arrVar.getValueAt(ai).getValueAsString(), nextSpace); } arrReprStr += "}"; AndroidLog.i(TAG, "ArrayToString -> \"" + arrReprStr + "\""); @@ -409,9 +409,9 @@ else if(ChameleonSettings.SERIALIO_IFACE_ACTIVE_INDEX == ChameleonSettings.BTIO_ case "CMLD.versionName": return BuildConfig.VERSION_NAME; case "CMLD.versionCode": - return String.format(Locale.getDefault(), "%d", BuildConfig.VERSION_CODE); + return String.format(BuildConfig.DEFAULT_LOCALE, "%d", BuildConfig.VERSION_CODE); case "CMLD.versionCodeNormalized": - return String.format(Locale.getDefault(), "%d", BuildConfig.VERSION_CODE - 8080); + return String.format(BuildConfig.DEFAULT_LOCALE, "%d", BuildConfig.VERSION_CODE - 8080); case "$env0": return ScriptingConfig.ENV0_VALUE; case "$env1": @@ -427,10 +427,10 @@ else if(ChameleonSettings.SERIALIO_IFACE_ACTIVE_INDEX == ChameleonSettings.BTIO_ } private static void printFunctionArgumentList(String funcName, List svList) { - AndroidLog.i(TAG, String.format(Locale.getDefault(), "FUNCTION %s(...) called with ##% 2d ARGS", funcName, svList.size())); + AndroidLog.i(TAG, String.format(BuildConfig.DEFAULT_LOCALE, "FUNCTION %s(...) called with ##% 2d ARGS", funcName, svList.size())); int varIndex = 0; for(ScriptVariable svar : svList) { - AndroidLog.i(TAG, String.format(Locale.getDefault(), " &&&& [VARIDX=% 2d] '%s' (quoted)", varIndex, svList.get(varIndex++).getValueAsString())); + AndroidLog.i(TAG, String.format(BuildConfig.DEFAULT_LOCALE, " &&&& [VARIDX=% 2d] '%s' (quoted)", varIndex, svList.get(varIndex++).getValueAsString())); } } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingGUIConsole.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingGUIConsole.java index c82093d..8a6cb09 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingGUIConsole.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingGUIConsole.java @@ -37,8 +37,7 @@ This program (The Chameleon Mini Live Debugger) is free software written by import com.maxieds.chameleonminilivedebugger.R; import com.maxieds.chameleonminilivedebugger.TabFragment; import com.maxieds.chameleonminilivedebugger.Utils; - -import java.util.Locale; +import com.maxieds.chameleonminilivedebugger.BuildConfig; public class ScriptingGUIConsole { @@ -96,7 +95,7 @@ public ConsoleOutputRecord setRecordLineOfCode(int nextLoc) { if (nextLoc <= 0) { tvRecLoc.setText("Line ---- "); } else { - tvRecLoc.setText(String.format(Locale.getDefault(), "Line % 3d ", nextLoc)); + tvRecLoc.setText(String.format(BuildConfig.DEFAULT_LOCALE, "Line % 3d ", nextLoc)); } } return this; @@ -122,8 +121,8 @@ public ConsoleOutputRecord setRecordTypeMarker(String typeMarkerText) { if (typeMarkerText.length() > RECORD_TYPE_MARKER_CHAR_WIDTH) { typeMarkerText = typeMarkerText.substring(0, RECORD_TYPE_MARKER_CHAR_WIDTH - 1); } else { - String fmtString = String.format(Locale.getDefault(), "%%%ds", RECORD_TYPE_MARKER_CHAR_WIDTH); - typeMarkerText = String.format(Locale.getDefault(), fmtString, typeMarkerText); + String fmtString = String.format(BuildConfig.DEFAULT_LOCALE, "%%%ds", RECORD_TYPE_MARKER_CHAR_WIDTH); + typeMarkerText = String.format(BuildConfig.DEFAULT_LOCALE, fmtString, typeMarkerText); } tvRecTypeMarker.setText(typeMarkerText); } @@ -231,17 +230,17 @@ public static ConsoleOutputRecord newRecordInstance(ScriptingConsoleRecordType s default: String msgPrefixData = "Script Variable Data:"; String[] msgDataComponents = new String[] { - String.format(Locale.getDefault(), "AS BOOL: %s", scrVarData.getValueAsBoolean() ? "TRUE" : "FALSE"), - String.format(Locale.getDefault(), "AS INT32: %04x (% 6d)", scrVarData.getValueAsInt(), scrVarData.getValueAsInt()), - String.format(Locale.getDefault(), "AS ASCII: %s", scrVarData.getValueAsString()), - String.format(Locale.getDefault(), "AS HEXSTR: %s", Utils.bytes2Ascii(scrVarData.getValueAsString().getBytes())) + String.format(BuildConfig.DEFAULT_LOCALE, "AS BOOL: %s", scrVarData.getValueAsBoolean() ? "TRUE" : "FALSE"), + String.format(BuildConfig.DEFAULT_LOCALE, "AS INT32: %04x (% 6d)", scrVarData.getValueAsInt(), scrVarData.getValueAsInt()), + String.format(BuildConfig.DEFAULT_LOCALE, "AS ASCII: %s", scrVarData.getValueAsString()), + String.format(BuildConfig.DEFAULT_LOCALE, "AS HEXSTR: %s", Utils.bytes2Ascii(scrVarData.getValueAsString().getBytes())) }; return newInfoMessageInstance(msgPrefixData, msgDataComponents, lineOfCode); } } public static ConsoleOutputRecord newInfoMessageInstance(String msgDataPrefix, String msgData[], int lineOfCode) { - ConsoleOutputRecord newInfoMsgRecord = new ConsoleOutputRecord(String.format(Locale.getDefault(), "Information")); + ConsoleOutputRecord newInfoMsgRecord = new ConsoleOutputRecord(String.format(BuildConfig.DEFAULT_LOCALE, "Information")); newInfoMsgRecord.setMainContentLayout(R.layout.scripting_console_record_textinfomsg); newInfoMsgRecord.setRecordIcon(R.drawable.scripting_output_icon_info16); newInfoMsgRecord.setRecordLineOfCode(lineOfCode); @@ -252,7 +251,7 @@ public static ConsoleOutputRecord newInfoMessageInstance(String msgDataPrefix, S } public static ConsoleOutputRecord newErrorWarningMessageInstance(String msgDataPrefix, String msgData[], int lineOfCode) { - ConsoleOutputRecord newEWarnMsgRecord = new ConsoleOutputRecord(String.format(Locale.getDefault(), "Error -- Warning")); + ConsoleOutputRecord newEWarnMsgRecord = new ConsoleOutputRecord(String.format(BuildConfig.DEFAULT_LOCALE, "Error -- Warning")); newEWarnMsgRecord.setMainContentLayout(R.layout.scripting_console_record_textinfomsg); newEWarnMsgRecord.setRecordIcon(R.drawable.scripting_output_icon_error16); newEWarnMsgRecord.setRecordLineOfCode(lineOfCode); @@ -263,7 +262,7 @@ public static ConsoleOutputRecord newErrorWarningMessageInstance(String msgDataP } public static ConsoleOutputRecord newBreakpointRecordInstance(String bpLabel, int lineOfCode) { - ConsoleOutputRecord newBkptMsgRecord = new ConsoleOutputRecord(String.format(Locale.getDefault(), "Breakpoint '%s'", bpLabel)); + ConsoleOutputRecord newBkptMsgRecord = new ConsoleOutputRecord(String.format(BuildConfig.DEFAULT_LOCALE, "Breakpoint '%s'", bpLabel)); newBkptMsgRecord.setMainContentLayout(R.layout.scripting_console_record_textinfomsg); newBkptMsgRecord.setRecordIcon(R.drawable.scripting_output_icon_bkpt16); newBkptMsgRecord.setRecordLineOfCode(lineOfCode); @@ -275,25 +274,25 @@ public static ConsoleOutputRecord newBreakpointRecordInstance(String bpLabel, in public static ConsoleOutputRecord newChameleonCommandResponseRecordInstance(ScriptingTypes.ScriptVariable scHashedArrayVar, int lineOfCode) { try { - ConsoleOutputRecord newCmdRespMsgRecord = new ConsoleOutputRecord(String.format(Locale.getDefault(), "Command Response")); + ConsoleOutputRecord newCmdRespMsgRecord = new ConsoleOutputRecord(String.format(BuildConfig.DEFAULT_LOCALE, "Command Response")); newCmdRespMsgRecord.setMainContentLayout(R.layout.scripting_console_record_cmdresp); newCmdRespMsgRecord.setRecordIcon(R.drawable.scripting_output_icon_cmdresp16_v1); newCmdRespMsgRecord.setRecordLineOfCode(lineOfCode); newCmdRespMsgRecord.setRecordTimestamp(); newCmdRespMsgRecord.setRecordTypeMarker(ScriptingConsoleRecordType.SCRECORD_CHAMCMDRESP); TextView tvCmdName = (TextView) newCmdRespMsgRecord.getMainLayoutView().findViewById(R.id.localCmdResponseRecordChamCmdNameText); - tvCmdName.setText(String.format(Locale.getDefault(), "%s", scHashedArrayVar.getValueAt("cmdName").getValueAsString()).toUpperCase(Locale.getDefault())); + tvCmdName.setText(String.format(BuildConfig.DEFAULT_LOCALE, "%s", scHashedArrayVar.getValueAt("cmdName").getValueAsString()).toUpperCase(BuildConfig.DEFAULT_LOCALE)); TextView tvCmdResp = (TextView) newCmdRespMsgRecord.getMainLayoutView().findViewById(R.id.localCmdResponseRecordChamCmdRespAndCodeText); - tvCmdResp.setText(String.format(Locale.getDefault(), "%s (%s)", + tvCmdResp.setText(String.format(BuildConfig.DEFAULT_LOCALE, "%s (%s)", scHashedArrayVar.getValueAt("respText").getValueAsString(), scHashedArrayVar.getValueAt("respCode").getValueAsString())); TextView tvCmdDataAscii = (TextView) newCmdRespMsgRecord.getMainLayoutView().findViewById(R.id.localCmdResponseRecordChamCmdReturnDataAsciiText); - tvCmdDataAscii.setText(String.format(Locale.getDefault(), "%s", scHashedArrayVar.getValueAt("data").getValueAsString())); + tvCmdDataAscii.setText(String.format(BuildConfig.DEFAULT_LOCALE, "%s", scHashedArrayVar.getValueAt("data").getValueAsString())); TextView tvCmdDataHex = (TextView) newCmdRespMsgRecord.getMainLayoutView().findViewById(R.id.localCmdResponseRecordChamCmdReturnDataHexText); - tvCmdDataHex.setText(String.format(Locale.getDefault(), "%s", Utils.bytes2Ascii(scHashedArrayVar.getValueAt("data").getValueAsString().getBytes()))); + tvCmdDataHex.setText(String.format(BuildConfig.DEFAULT_LOCALE, "%s", Utils.bytes2Ascii(scHashedArrayVar.getValueAt("data").getValueAsString().getBytes()))); TextView tvCmdDataIsError = (TextView) newCmdRespMsgRecord.getMainLayoutView().findViewById(R.id.localCmdResponseRecordChamCmdIsErrorText); - tvCmdDataIsError.setText(String.format(Locale.getDefault(), "%s", scHashedArrayVar.getValueAt("isError").getValueAsBoolean() ? "True" : "False")); + tvCmdDataIsError.setText(String.format(BuildConfig.DEFAULT_LOCALE, "%s", scHashedArrayVar.getValueAt("isError").getValueAsBoolean() ? "True" : "False")); TextView tvCmdDataIsTmt = (TextView) newCmdRespMsgRecord.getMainLayoutView().findViewById(R.id.localCmdResponseRecordChamCmdIsTimeoutText); - tvCmdDataIsTmt.setText(String.format(Locale.getDefault(), "%s", scHashedArrayVar.getValueAt("isTimeout").getValueAsBoolean() ? "True" : "False")); + tvCmdDataIsTmt.setText(String.format(BuildConfig.DEFAULT_LOCALE, "%s", scHashedArrayVar.getValueAt("isTimeout").getValueAsBoolean() ? "True" : "False")); return newCmdRespMsgRecord; } catch(NullPointerException npe) { AndroidLog.printStackTrace(npe); diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingGUIMain.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingGUIMain.java index 41d0163..c86fd2f 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingGUIMain.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingGUIMain.java @@ -32,9 +32,9 @@ This program (The Chameleon Mini Live Debugger) is free software written by import com.maxieds.chameleonminilivedebugger.BuildConfig; import com.maxieds.chameleonminilivedebugger.R; import com.maxieds.chameleonminilivedebugger.Utils; +import com.maxieds.chameleonminilivedebugger.BuildConfig; import java.io.File; -import java.util.Locale; public class ScriptingGUIMain { @@ -87,7 +87,7 @@ public void onClick(View cbView) { CheckBox cbLimitExecTime = cfgBaseLayout.findViewById(R.id.scriptingLoadImportTabLimitExecTimeCbox); cbLimitExecTime.setChecked(ScriptingConfig.DEFAULT_LIMIT_SCRIPT_EXEC_TIME); EditText limitExecTimeSecsText = cfgBaseLayout.findViewById(R.id.scriptingRuntimeLimitExecSecondsText); - limitExecTimeSecsText.setText(String.format(Locale.getDefault(), "%d", ScriptingConfig.DEFAULT_LIMIT_SCRIPT_EXEC_TIME_SECONDS)); + limitExecTimeSecsText.setText(String.format(BuildConfig.DEFAULT_LOCALE, "%d", ScriptingConfig.DEFAULT_LIMIT_SCRIPT_EXEC_TIME_SECONDS)); /* Setup breakpoints GUI displays: */ ScriptingBreakPoint.breakpointsGUIDisplayContainer = (LinearLayout) cfgBaseLayout.findViewById(R.id.scriptingMainTabBreakpointsListView); ImageButton addBPLineBtn = cfgBaseLayout.findViewById(R.id.scriptingBPAddLineAppendBtn); diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingTypes.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingTypes.java index 09397d4..0be72c8 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingTypes.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ScriptingAPI/ScriptingTypes.java @@ -28,7 +28,6 @@ This program (The Chameleon Mini Live Debugger) is free software written by import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.Locale; public class ScriptingTypes { @@ -253,7 +252,7 @@ public String getValueAsString() throws ScriptingExceptions.ChameleonScriptingEx case VariableTypeBoolean: return varValueAsBoolean ? "true" : "false"; case VariableTypeInteger: - return String.format(Locale.getDefault(), "%d", varValueAsInt); + return String.format(BuildConfig.DEFAULT_LOCALE, "%d", varValueAsInt); case VariableTypeArrayMap: String[] arrayListStrDescList = new String[arrayList.size()]; for(int arrListIdx = 0; arrListIdx < arrayList.size(); arrListIdx++) { @@ -265,7 +264,7 @@ public String getValueAsString() throws ScriptingExceptions.ChameleonScriptingEx hashMapStrDescList[hmCount] = hashMap.get(hashKey).getValueAsString(); ++hmCount; } - String arrValueDesc = String.format(Locale.getDefault(), "[ "); + String arrValueDesc = String.format(BuildConfig.DEFAULT_LOCALE, "[ "); if(arrayListStrDescList.length > 0) { arrValueDesc += String.join(", ", arrayListStrDescList); if(hashMapStrDescList.length > 0) { diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/SerialIOReceiver.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/SerialIOReceiver.java index 521c14d..2aa6fda 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/SerialIOReceiver.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/SerialIOReceiver.java @@ -18,6 +18,7 @@ This program (The Chameleon Mini Live Debugger) is free software written by package com.maxieds.chameleonminilivedebugger; import android.content.Context; +import android.content.Intent; import android.util.Log; import org.apache.commons.lang3.ArrayUtils; @@ -34,30 +35,12 @@ public class SerialIOReceiver implements ChameleonSerialIOInterface, ChameleonSe private static final String TAG = SerialIOReceiver.class.getSimpleName(); - public void setListenerContext(Context context) {} + private Context notifyContext; - public String getInterfaceLoggingTag() { - return "AbstractSerialReceiver"; - } - - public boolean notifySerialDataReceived(byte[] serialData) { - return false; - } - - public boolean notifyLogDataReceived(byte[] serialData) { - return false; - } + public void setListenerContext(Context context) { notifyContext = context; } - public boolean notifyDeviceFound() { - return false; - } - - public boolean notifyDeviceConnectionTerminated() { - return false; - } - - public boolean notifyStatus(String msgType, String statusMsg) { - return false; + public String getInterfaceLoggingTag() { + return TAG; } public boolean isWiredUSB() { @@ -73,11 +56,11 @@ public int setSerialBaudRate(int baudRate) { } public int setSerialBaudRateHigh() { - return STATUS_ERROR; + return setSerialBaudRate(ChameleonSerialIOInterface.HIGH_SPEED_BAUD_RATE); } public int setSerialBaudRateLimited() { - return STATUS_ERROR; + return setSerialBaudRate(ChameleonSerialIOInterface.LIMITED_SPEED_BAUD_RATE); } public boolean startScanningDevices() { @@ -88,6 +71,8 @@ public boolean stopScanningDevices() { return false; } + public String getDeviceName() { return AndroidSettingsStorage.getStringValueByKey(AndroidSettingsStorage.DEFAULT_CMLDAPP_PROFILE, AndroidSettingsStorage.PROFILE_NAME_PREFERENCE); } + public String getActiveDeviceInfo() { return null; } @@ -134,6 +119,41 @@ public static void resetRedirectInterface() { redirectSerialDataInterface = null; } + public boolean notifySerialDataReceived(byte[] serialData) { + Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_DATA_RECEIVED); + notifyIntent.putExtra("DATA", serialData); + notifyContext.sendBroadcast(notifyIntent); + AndroidLog.i(TAG, "SERIALIO_DATA_RECEIVED: (HEX) " + Utils.bytes2Hex(serialData)); + AndroidLog.i(TAG, "SERIALIO_DATA_RECEIVED: (TXT) " + Utils.bytes2Ascii(serialData)); + return true; + } + + public boolean notifyLogDataReceived(byte[] serialData) { + if(serialData.length < ChameleonLogUtils.LOGGING_MIN_DATA_BYTES + 4) { + return false; + } + Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_LOGDATA_RECEIVED); + notifyIntent.putExtra("DATA", serialData); + notifyContext.sendBroadcast(notifyIntent); + AndroidLog.i(TAG, "SERIALIO_LOGDATA_RECEIVED: (HEX) " + Utils.bytes2Hex(serialData)); + AndroidLog.i(TAG, "SERIALIO_LOGDATA_RECEIVED: (TXT) " + Utils.bytes2Ascii(serialData)); + return true; + } + + public boolean notifyDeviceConnectionTerminated() { + Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_DEVICE_CONNECTION_LOST); + notifyContext.sendBroadcast(notifyIntent); + return true; + } + + public boolean notifyStatus(String msgType, String statusMsg) { + Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_NOTIFY_STATUS); + notifyIntent.putExtra("STATUS-TYPE", msgType); + notifyIntent.putExtra("STATUS-MSG", statusMsg); + notifyContext.sendBroadcast(notifyIntent); + return true; + } + public void onReceivedData(byte[] liveLogData) { if(redirectSerialDataInterface != null) { @@ -151,7 +171,7 @@ public void onReceivedData(byte[] liveLogData) { } int loggingRespSize = ChameleonLogUtils.ResponseIsLiveLoggingBytes(liveLogData); if (loggingRespSize > 0) { - AndroidLog.i(TAG, "Received new LogEntry @ " + String.format(Locale.getDefault(), "0x%02x", liveLogData[0])); + AndroidLog.i(TAG, "Received new LogEntry @ " + String.format(BuildConfig.DEFAULT_LOCALE, "0x%02x", liveLogData[0])); if(ChameleonLogUtils.LOGMODE_ENABLE_PRINTING_LIVE_LOGS) { notifyLogDataReceived(liveLogData); } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/SerialUSBInterface.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/SerialUSBInterface.java index b11b053..4c6666b 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/SerialUSBInterface.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/SerialUSBInterface.java @@ -26,7 +26,6 @@ This program (The Chameleon Mini Live Debugger) is free software written by import android.hardware.usb.UsbManager; import android.os.Handler; import android.os.Parcelable; -import android.util.Log; import androidx.localbroadcastmanager.content.LocalBroadcastManager; @@ -45,77 +44,31 @@ public class SerialUSBInterface extends SerialIOReceiver { public static final int USB_DATA_BITS = 8; public String getInterfaceLoggingTag() { - return "SerialUSBReaderInterface"; + return TAG; } - private Context notifyContext; private UsbSerialDevice serialPort; private UsbDevice activeDevice; private UsbSerialInterface.UsbReadCallback serialReaderCallback; private int baudRate; private boolean serialConfigured; private boolean receiversRegistered; - private final Semaphore serialPortLock = new Semaphore(1, true); + private Semaphore serialPortLock = new Semaphore(1, true); - public SerialUSBInterface(Context context) { - notifyContext = context; + public SerialUSBInterface(Context appContext) { + setListenerContext(appContext); serialPort = null; baudRate = ChameleonSettings.serialBaudRate; serialConfigured = false; receiversRegistered = false; } - public void setListenerContext(Context context) { - notifyContext = context; - } - - public boolean notifySerialDataReceived(byte[] serialData) { - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_DATA_RECEIVED); - notifyIntent.putExtra("DATA", serialData); - notifyContext.sendBroadcast(notifyIntent); - AndroidLog.i(TAG, "SERIALIO_DATA_RECEIVED: (HEX) " + Utils.bytes2Hex(serialData)); - AndroidLog.i(TAG, "SERIALIO_DATA_RECEIVED: (TXT) " + Utils.bytes2Ascii(serialData)); - return true; - } - - public boolean notifyLogDataReceived(byte[] serialData) { - if(serialData.length < ChameleonLogUtils.LOGGING_MIN_DATA_BYTES + 4) { - return false; - } - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_LOGDATA_RECEIVED); - notifyIntent.putExtra("DATA", serialData); - notifyContext.sendBroadcast(notifyIntent); - AndroidLog.i(TAG, "SERIALIO_LOGDATA_RECEIVED: (HEX) " + Utils.bytes2Hex(serialData)); - AndroidLog.i(TAG, "SERIALIO_LOGDATA_RECEIVED: (TXT) " + Utils.bytes2Ascii(serialData)); - return true; - } - - public boolean notifyDeviceFound() { - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_DEVICE_FOUND); - notifyContext.sendBroadcast(notifyIntent); - return true; - } - - public boolean notifyDeviceConnectionTerminated() { - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_DEVICE_CONNECTION_LOST); - notifyContext.sendBroadcast(notifyIntent); - return true; - } - - public boolean notifyStatus(String msgType, String statusMsg) { - Intent notifyIntent = new Intent(ChameleonSerialIOInterface.SERIALIO_NOTIFY_STATUS); - notifyIntent.putExtra("STATUS-TYPE", msgType); - notifyIntent.putExtra("STATUS-MSG", statusMsg); - notifyContext.sendBroadcast(notifyIntent); - return true; - } - public boolean isWiredUSB() { return true; } public boolean isBluetooth() { return false; } - public int setSerialBaudRate(int brate) { - baudRate = brate; + public int setSerialBaudRate(int bdRate) { + baudRate = bdRate; ChameleonSettings.serialBaudRate = baudRate; if(serialPort != null) { serialPort.setBaudRate(baudRate); @@ -123,15 +76,9 @@ public int setSerialBaudRate(int brate) { } return STATUS_OK; } - public int setSerialBaudRateHigh() { - return setSerialBaudRate(ChameleonSerialIOInterface.HIGH_SPEED_BAUD_RATE); - } - public int setSerialBuadRateLimited() { - return setSerialBaudRate(ChameleonSerialIOInterface.LIMITED_SPEED_BAUD_RATE); - } - private Handler scanDeviceHandler = new Handler(); - private Runnable scanDeviceRunnable = new Runnable() { + private final Handler scanDeviceHandler = new Handler(); + private final Runnable scanDeviceRunnable = new Runnable() { public void run() { if (ChameleonSettings.getActiveSerialIOPort() != null || configureSerial() != 0) { scanDeviceHandler.removeCallbacksAndMessages(this); @@ -157,7 +104,7 @@ public String getActiveDeviceInfo() { if(activeDevice == null) { return ""; } - String devInfo = String.format(Locale.getDefault(), "Manufacturer: %s\nProduct Name: %s\nVersion: %s\nDevice Serial: %s\nUSB Dev: %s", + String devInfo = String.format(BuildConfig.DEFAULT_LOCALE, "Manufacturer: %s\nProduct Name: %s\nVersion: %s\nDevice Serial: %s\nUSB Dev: %s", activeDevice.getManufacturerName(), activeDevice.getProductName(), activeDevice.getVersion(), activeDevice.getSerialNumber(), activeDevice.getDeviceName()); @@ -168,7 +115,7 @@ public int configureSerial() { if(serialConfigured()) { return STATUS_TRUE; } - UsbManager usbManager = (UsbManager) notifyContext.getSystemService(Context.USB_SERVICE); + UsbManager usbManager = (UsbManager) LiveLoggerActivity.getLiveLoggerInstance().getSystemService(Context.USB_SERVICE); UsbDevice device = null; UsbDeviceConnection connection = null; HashMap usbDevices = usbManager.getDeviceList(); @@ -219,13 +166,14 @@ else if(deviceVID == ChameleonIO.CMUSB_REVE_VENDORID && devicePID == ChameleonIO return STATUS_ERROR; } activeDevice = device; - ChameleonSettings.chameleonDeviceSerialNumber = String.format(Locale.getDefault(), "%s-%s-%s", + ChameleonSettings.chameleonDeviceSerialNumber = String.format(BuildConfig.DEFAULT_LOCALE, "%s-%s-%s", activeDevice.getProductName(), activeDevice.getVersion(), activeDevice.getSerialNumber()); ChameleonIO.PAUSED = false; serialConfigured = true; receiversRegistered = true; ChameleonSettings.SERIALIO_IFACE_ACTIVE_INDEX = ChameleonSettings.USBIO_IFACE_INDEX; LiveLoggerActivity.getLiveLoggerInstance().setStatusIcon(R.id.statusIconUSB, R.drawable.usbconnected16); + UITabUtils.updateConfigTabConnDeviceInfo(false); notifyStatus("USB STATUS: ", "Chameleon: " + getActiveDeviceInfo()); return STATUS_TRUE; } @@ -253,6 +201,9 @@ public int shutdownSerial() { if(ChameleonSettings.SERIALIO_IFACE_ACTIVE_INDEX == ChameleonSettings.USBIO_IFACE_INDEX) { ChameleonSettings.SERIALIO_IFACE_ACTIVE_INDEX = -1; } + serialPortLock.release(); + LiveLoggerActivity.getLiveLoggerInstance().clearStatusIcon(R.id.statusIconUSB); + UITabUtils.updateConfigTabConnDeviceInfo(true); notifyDeviceConnectionTerminated(); return STATUS_TRUE; } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/TabFragment.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/TabFragment.java index 655d64c..5e4ba27 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/TabFragment.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/TabFragment.java @@ -72,8 +72,6 @@ public class TabFragment extends Fragment { public static final int TAB_TOOLS_MITEM_APDU = 2; public static final int TAB_EXPORT_MITEM_COLUMNS = TAB_MENU_ITEM_DEFAULT_COLUMNS; - public static final int TAB_EXPORT_MITEM_UPLOAD_DOWNLOAD = 0; - public static final int TAB_EXPORT_MITEM_CLONE = 1; public static final int TAB_SCRIPTING_MITEM_COLUMNS = 2; public static final int TAB_SCRIPTING_MITEM_LOAD_IMPORT = 0; @@ -136,7 +134,7 @@ else if(tabInflatedView == null) { deselectMenuItem(lastMenuIndex); lastMenuIndex = midx; GridLayout menuItemsNav = (GridLayout) tabInflatedView.findViewById(R.id.tabMenuItemsNav); - String indexRefTag = String.format(Locale.getDefault(), "%d:%d", tabIndex, midx); + String indexRefTag = String.format(BuildConfig.DEFAULT_LOCALE, "%d:%d", tabIndex, midx); Button menuItem = (Button) menuItemsNav.findViewWithTag(indexRefTag); if(menuItem == null) { return false; @@ -172,7 +170,7 @@ else if(tabInflatedView == null) { } try { GridLayout menuItemsNav = (GridLayout) tabInflatedView.findViewById(R.id.tabMenuItemsNav); - String indexRefTag = String.format(Locale.getDefault(), "%d:%d", tabIndex, midx); + String indexRefTag = String.format(BuildConfig.DEFAULT_LOCALE, "%d:%d", tabIndex, midx); Button menuItem = (Button) menuItemsNav.findViewWithTag(indexRefTag); menuItem.setBackgroundColor(tabInflatedView.getContext().getResources().getColor(android.R.color.transparent)); menuItem.setTextColor(Utils.getColorFromTheme(R.attr.colorPrimaryDark)); @@ -213,7 +211,7 @@ public View createTabView() { menuItemClick.setPadding(20, 8, 20, 8); menuItemClick.setMaxHeight(100); menuItemClick.setMinWidth(menuItemsNav.getMeasuredWidth() / tabNumColumns); - String indexRefTag = String.format(Locale.getDefault(), "%d:%d", tabIndex, totalItems); + String indexRefTag = String.format(BuildConfig.DEFAULT_LOCALE, "%d:%d", tabIndex, totalItems); menuItemClick.setTag(indexRefTag); menuItemClick.setOnClickListener(new View.OnClickListener() { @Override diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ThemesConfiguration.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ThemesConfiguration.java index 021a878..9231c6d 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/ThemesConfiguration.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/ThemesConfiguration.java @@ -71,7 +71,7 @@ public void run() { public static int setLocalTheme(String themeDesc, boolean applyTheme, ChameleonMiniLiveDebuggerActivity activity) { int themeID; if(activity == null) { - if(BuildConfig.FLAVOR.equals("paid")) { + if(BuildConfig.PAID_APP_VERSION) { themeID = R.style.AppThemeGreenPaid; } else { themeID = R.style.AppThemeGreen; @@ -111,7 +111,7 @@ public static int setLocalTheme(String themeDesc, boolean applyTheme, ChameleonM break; case "Standard Green (Default)": case "Standard Green": - if(BuildConfig.FLAVOR.equals("paid")) { + if(BuildConfig.PAID_APP_VERSION) { themeID = R.style.AppThemeGreenPaid; } else { themeID = R.style.AppThemeGreen; diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/UIDCommands.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/UIDCommands.java index f7a9616..4751f44 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/UIDCommands.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/UIDCommands.java @@ -76,7 +76,7 @@ public static void modifyUID(String uidAction) { ChameleonIO.deviceStatus.LASTUID = ChameleonIO.deviceStatus.UID; byte[] uid = UIDCommands.processUIDCommand(uidAction); String uidCmd = ChameleonIO.REVE_BOARD ? "uid" : "UID"; - String cmdStatus = ChameleonIO.getSettingFromDevice(String.format(Locale.getDefault(), "%s=%s", uidCmd, Utils.bytes2Hex(uid).replace(" ", "").toUpperCase())); + String cmdStatus = ChameleonIO.getSettingFromDevice(String.format(BuildConfig.DEFAULT_LOCALE, "%s=%s", uidCmd, Utils.bytes2Hex(uid).replace(" ", "").toUpperCase())); ChameleonIO.deviceStatus.startPostingStats(250); MainActivityLogUtils.appendNewLog(LogEntryMetadataRecord.createDefaultEventRecord("UID", "Next device UID set to " + Utils.bytes2Hex(uid).replace(" ", ":").toUpperCase())); } diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/UITabUtils.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/UITabUtils.java index 705304f..37e4b09 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/UITabUtils.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/UITabUtils.java @@ -65,6 +65,7 @@ This program (The Chameleon Mini Live Debugger) is free software written by import static com.maxieds.chameleonminilivedebugger.TabFragment.TAB_TOOLS_MITEM_PERIPHERALS; import static com.maxieds.chameleonminilivedebugger.TabFragment.TAB_TOOLS_MITEM_SLOTS; import static com.maxieds.chameleonminilivedebugger.TabFragment.TAB_TOOLS_MITEM_TAGCONFIG; +import static com.maxieds.chameleonminilivedebugger.TabFragment.UITAB_DATA; public class UITabUtils { @@ -160,7 +161,7 @@ public void onScrollStateChange(NumberPicker numberPicker, int scrollState) { if(scrollState == SCROLL_STATE_IDLE) { int previousSlotNumber = ChameleonIO.DeviceStatusSettings.DIP_SETTING; String settingCmd = ChameleonIO.REVE_BOARD ? "setting=" : "SETTING="; - ChameleonIO.getSettingFromDevice(String.format(Locale.getDefault(), "%s%d", settingCmd, numberPicker.getValue())); + ChameleonIO.getSettingFromDevice(String.format(BuildConfig.DEFAULT_LOCALE, "%s%d", settingCmd, numberPicker.getValue())); int activeSlotNumber = numberPicker.getValue(); int numSlotsUpperBound = ChameleonConfigSlot.CHAMELEON_DEVICE_CONFIG_SLOT_COUNT; if(previousSlotNumber != activeSlotNumber && @@ -255,7 +256,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { thresholdSeekbar.incrementProgressBy(25); TextView thresholdSeekbarValueText = (TextView) tabMainLayoutView.findViewById(R.id.thresholdSeekbarValueText); if (thresholdSeekbarValueText != null) { - thresholdSeekbarValueText.setText(String.format(Locale.getDefault(), "% 5d mV", threshold)); + thresholdSeekbarValueText.setText(String.format(BuildConfig.DEFAULT_LOCALE, "% 5d mV", threshold)); } final View seekbarView = tabMainLayoutView; thresholdSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @@ -264,7 +265,7 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { @Override public void onProgressChanged(@NonNull SeekBar seekBar, int progress, boolean fromUser) { if (labelText != null) { - labelText.setText(String.format(Locale.getDefault(), "% 5d mV", progress)); + labelText.setText(String.format(BuildConfig.DEFAULT_LOCALE, "% 5d mV", progress)); } } @@ -296,7 +297,7 @@ public void onStopTrackingTouch(@NonNull SeekBar seekBar) { timeoutSeekbar.incrementProgressBy(2); TextView cmdTimeoutSeekbarValueText = (TextView) tabMainLayoutView.findViewById(R.id.cmdTimeoutSeekbarValueText); if(cmdTimeoutSeekbarValueText != null) { - cmdTimeoutSeekbarValueText.setText(String.format(Locale.getDefault(), "% 4d (x128) ms", timeout)); + cmdTimeoutSeekbarValueText.setText(String.format(BuildConfig.DEFAULT_LOCALE, "% 4d (x128) ms", timeout)); } final View tmtSeekbarView = tabMainLayoutView; timeoutSeekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @@ -305,7 +306,7 @@ public void onStopTrackingTouch(@NonNull SeekBar seekBar) { @Override public void onProgressChanged(@NonNull SeekBar seekBar, int progress, boolean fromUser) { if(labelText != null) { - labelText.setText(String.format(Locale.getDefault(), "% 4d (x128) ms", progress)); + labelText.setText(String.format(BuildConfig.DEFAULT_LOCALE, "% 4d (x128) ms", progress)); } } @@ -374,6 +375,41 @@ else if(menuItemIdx == TAB_SCRIPTING_MITEM_REGISTER_VIEW) {} return true; } + public static boolean updateConfigTabConnDeviceInfo(View parentLayoutView, boolean resetConnection) { + if (parentLayoutView == null) { + return false; + } + EditText deviceNameText = parentLayoutView.findViewById(R.id.slotNicknameText); + TextView chamTypeText = parentLayoutView.findViewById(R.id.chameleonTypeText); + TextView hardwareIDText = parentLayoutView.findViewById(R.id.hardwareSerialIDText); + TextView connStatusText = parentLayoutView.findViewById(R.id.connectionStatusText); + if(chamTypeText != null && hardwareIDText != null && connStatusText != null) { + boolean isChameleonDevConn = ChameleonSettings.getActiveSerialIOPort() != null && !resetConnection; + if (isChameleonDevConn) { + deviceNameText.setText(ChameleonSettings.getActiveSerialIOPort().getDeviceName()); + chamTypeText.setText(ChameleonIO.getDeviceDescription(ChameleonIO.CHAMELEON_MINI_BOARD_TYPE)); + hardwareIDText.setText(ChameleonSettings.chameleonDeviceSerialNumber); + connStatusText.setText(ChameleonSettings.getActiveSerialIOPort().isWiredUSB() ? "USB connection" : "BT connection"); + } else { + deviceNameText.setText(ChameleonSettings.chameleonDeviceNickname); + chamTypeText.setText("None"); + hardwareIDText.setText("None"); + connStatusText.setText("Not connected"); + } + return true; + } else { + return false; + } + } + + public static boolean updateConfigTabConnDeviceInfo(boolean resetConnection) { + if (UITAB_DATA == null || UITAB_DATA.length >= TAB_CONFIG || UITAB_DATA[TAB_CONFIG] == null) { + return false; + } else { + return updateConfigTabConnDeviceInfo(UITAB_DATA[TAB_CONFIG].tabInflatedView, resetConnection); + } + } + public static boolean initializeConfigTab(int menuItemIdx, View tabMainLayoutView) { if(tabMainLayoutView == null) { return false; @@ -440,7 +476,7 @@ public void onClick(View cbView) { ChameleonSettings.stopSerialIOConnectionDiscovery(); ChameleonSettings.initializeSerialIOConnections(); } - BluetoothSerialInterface btSerialInterface = (BluetoothSerialInterface) ChameleonSettings.serialIOPorts[ChameleonSettings.BTIO_IFACE_INDEX]; + BluetoothBLEInterface btSerialInterface = (BluetoothBLEInterface) ChameleonSettings.serialIOPorts[ChameleonSettings.BTIO_IFACE_INDEX]; haveSufficientBTPerms = haveSufficientBTPerms && btSerialInterface != null && btSerialInterface.isBluetoothEnabled(false); if(!cb.isChecked() && !haveSufficientBTPerms) { String btPermsRequiredResStr = llInst.getResources().getString(R.string.btPermsRequiredMsg); @@ -510,7 +546,7 @@ public void onNothingSelected(AdapterView adapterView) { } else if(menuItemIdx == TAB_CONFIG_MITEM_CONNECT) { TextView btStatusText = tabMainLayoutView.findViewById(R.id.androidBluetoothStatusText); - String btStatus = ((BluetoothSerialInterface) ChameleonSettings.serialIOPorts[ChameleonSettings.BTIO_IFACE_INDEX]).isBluetoothEnabled() ? "Enabled" : "Disabled"; + String btStatus = ((BluetoothBLEInterface) ChameleonSettings.serialIOPorts[ChameleonSettings.BTIO_IFACE_INDEX]).isBluetoothEnabled() ? "Enabled" : "Disabled"; btStatusText.setText(btStatus); Button btSettingsBtn = tabMainLayoutView.findViewById(R.id.androidBTSettingsButton); if(btSettingsBtn == null) { @@ -519,7 +555,7 @@ else if(menuItemIdx == TAB_CONFIG_MITEM_CONNECT) { btSettingsBtn.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View btn) { - BluetoothSerialInterface.displayAndroidBluetoothSettings(); + BluetoothBLEInterface.displayAndroidBluetoothSettings(); } }); Button btTroubleshootingBtn = tabMainLayoutView.findViewById(R.id.androidBTTroubleshootingButton); @@ -529,7 +565,7 @@ public void onClick(View btn) { btTroubleshootingBtn.setOnClickListener(new Button.OnClickListener() { @Override public void onClick(View btn) { - BluetoothSerialInterface.displayAndroidBluetoothTroubleshooting(); + BluetoothBLEInterface.displayAndroidBluetoothTroubleshooting(); } }); boolean isChameleonDevConn = ChameleonSettings.getActiveSerialIOPort() != null; @@ -550,22 +586,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) { } else { errorOnInit = true; } - TextView chamTypeText = tabMainLayoutView.findViewById(R.id.chameleonTypeText); - TextView hardwareIDText = tabMainLayoutView.findViewById(R.id.hardwareSerialIDText); - TextView connStatusText = tabMainLayoutView.findViewById(R.id.connectionStatusText); - if(chamTypeText != null && hardwareIDText != null && connStatusText != null) { - if (isChameleonDevConn) { - deviceNameText.setText(AndroidSettingsStorage.getStringValueByKey(ChameleonSettings.chameleonDeviceSerialNumber, AndroidSettingsStorage.PROFILE_NAME_PREFERENCE)); - chamTypeText.setText(ChameleonIO.getDeviceDescription(ChameleonIO.CHAMELEON_MINI_BOARD_TYPE)); - hardwareIDText.setText(ChameleonSettings.chameleonDeviceSerialNumber); - connStatusText.setText(ChameleonSettings.getActiveSerialIOPort().isWiredUSB() ? "USB connection" : "BT connection"); - } else { - deviceNameText.setText(ChameleonSettings.chameleonDeviceNickname); - chamTypeText.setText("None"); - hardwareIDText.setText("None"); - connStatusText.setText("Not connected"); - } - } else { + if (!updateConfigTabConnDeviceInfo(tabMainLayoutView, false)) { errorOnInit = true; } Button chamConnectBtn = tabMainLayoutView.findViewById(R.id.connectToDeviceButton); @@ -610,7 +631,7 @@ else if(menuItemIdx == TAB_CONFIG_MITEM_LOGGING) { try { UITabUtils.connectPeripheralSpinnerAdapterLogMode(tabMainLayoutView, R.id.LogModeSpinner, R.array.LogModeOptions, ChameleonPeripherals.spinnerLogModeAdapter); - String loggingMinDataFieldValue = String.format(Locale.getDefault(), "%d", ChameleonLogUtils.LOGGING_MIN_DATA_BYTES); + String loggingMinDataFieldValue = String.format(BuildConfig.DEFAULT_LOCALE, "%d", ChameleonLogUtils.LOGGING_MIN_DATA_BYTES); EditText loggingLogDataMinBytesField = (EditText) tabMainLayoutView.findViewById(R.id.loggingLogDataMinBytesField); if(loggingLogDataMinBytesField != null) { loggingLogDataMinBytesField.setText(loggingMinDataFieldValue); diff --git a/app/src/main/java/com/maxieds/chameleonminilivedebugger/Utils.java b/app/src/main/java/com/maxieds/chameleonminilivedebugger/Utils.java index fa6666f..418d10e 100755 --- a/app/src/main/java/com/maxieds/chameleonminilivedebugger/Utils.java +++ b/app/src/main/java/com/maxieds/chameleonminilivedebugger/Utils.java @@ -35,6 +35,8 @@ This program (The Chameleon Mini Live Debugger) is free software written by import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; +import org.apache.commons.lang3.ArrayUtils; + import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -48,6 +50,8 @@ This program (The Chameleon Mini Live Debugger) is free software written by import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Random; @@ -152,9 +156,9 @@ public static String bytes2Hex(byte[] bytes) { else if (bytes.length == 0) return ""; StringBuilder hstr = new StringBuilder(); - hstr.append(String.format(Locale.getDefault(), "%02x", bytes[0])); + hstr.append(String.format(BuildConfig.DEFAULT_LOCALE, "%02x", bytes[0])); for (int b = 1; b < bytes.length; b++) - hstr.append(" " + String.format(Locale.getDefault(), "%02x", bytes[b])); + hstr.append(" " + String.format(BuildConfig.DEFAULT_LOCALE, "%02x", bytes[b])); return hstr.toString(); } @@ -172,6 +176,36 @@ public static int bytes2Integer32(byte[] bytesArray) { return rint; } + private static long integer32ToUnsignedInteger32(int int32Value) { + return (long) (int32Value & 0xffffffffL); + } + + private static byte[] bytesToBigEndian(@NonNull byte[] byteBuf, int zeroPadResultOnLeftBy, int zeroPadResultOnRightBy) { + zeroPadResultOnLeftBy = (int) Math.max(0, zeroPadResultOnLeftBy); + zeroPadResultOnRightBy = (int) Math.max(0, zeroPadResultOnRightBy); + int beBufSize = byteBuf.length + zeroPadResultOnLeftBy + zeroPadResultOnRightBy; + byte[] beDataBuf = new byte[beBufSize]; + Arrays.fill(beDataBuf, (byte) 0x00); + ArrayUtils.reverse(byteBuf); + System.arraycopy(byteBuf, 0, beBufSize, zeroPadResultOnLeftBy, byteBuf.length); + return beDataBuf; + } + + public static long bytesToUint32LittleEndian(@NonNull byte[] byteBuf) { + if (byteBuf == null || byteBuf.length == 0 || byteBuf.length > 4) { + return 0xff00000000L; + } + byte[] leByteBuf = bytesToBigEndian(byteBuf, 4 - byteBuf.length, 0); + return integer32ToUnsignedInteger32(bytes2Integer32(leByteBuf)); + } + + public static long bytesToUint32BigEndian(@NonNull byte[] byteBuf) { + if (byteBuf == null || byteBuf.length == 0 || byteBuf.length > 4) { + return 0xff00000000L; + } + return integer32ToUnsignedInteger32(bytes2Integer32(byteBuf)); + } + /** * Reverses the order of the bytes in the array. * @param bytes @@ -309,7 +343,7 @@ public static double computeByteArrayEntropy(byte[] inputBytes) { cmprByteCount += cmpr.deflate(new byte[1024]); } double entropyRatio = (double) cmprByteCount / inputBytes.length; - AndroidLog.i(TAG, String.format(Locale.getDefault(), "Compressed #%d bytes to #%d bytes ... Entropy ratio = %1.4g", inputBytes.length, cmprByteCount, entropyRatio)); + AndroidLog.i(TAG, String.format(BuildConfig.DEFAULT_LOCALE, "Compressed #%d bytes to #%d bytes ... Entropy ratio = %1.4g", inputBytes.length, cmprByteCount, entropyRatio)); return entropyRatio; } @@ -406,8 +440,8 @@ public static String[] getGPSLocationCoordinates() { } Location bestLocProvider = (gpsProviderLocTime - netProviderLocTime > 0) ? locGPSProvider : locGPSProvider; String[] gpsAttrsArray = new String[]{ - String.format(Locale.getDefault(), "%g", bestLocProvider.getLatitude()), - String.format(Locale.getDefault(), "%g", bestLocProvider.getLongitude()) + String.format(BuildConfig.DEFAULT_LOCALE, "%g", bestLocProvider.getLatitude()), + String.format(BuildConfig.DEFAULT_LOCALE, "%g", bestLocProvider.getLongitude()) }; return gpsAttrsArray; } catch(SecurityException secExcpt) { @@ -422,7 +456,7 @@ public static String[] getGPSLocationCoordinates() { public static String getGPSLocationString() { String[] gpsCoords = Utils.getGPSLocationCoordinates(); - String gpsLocStr = String.format(Locale.getDefault(), " -- Location at %s LONG, %s LAT -- ", + String gpsLocStr = String.format(BuildConfig.DEFAULT_LOCALE, " -- Location at %s LONG, %s LAT -- ", gpsCoords[Utils.GPS_LONGITUDE_CINDEX], gpsCoords[Utils.GPS_LATITUDE_CINDEX]); return gpsLocStr; } diff --git a/app/src/main/res/layout/config_tab_connect.xml b/app/src/main/res/layout/config_tab_connect.xml index f058c09..aff1812 100755 --- a/app/src/main/res/layout/config_tab_connect.xml +++ b/app/src/main/res/layout/config_tab_connect.xml @@ -282,6 +282,7 @@ https://github.com/maxieds/ChameleonMiniLiveDebugger