From 71375f31493849359318bfe4ba5340dde33d1fb2 Mon Sep 17 00:00:00 2001 From: Martin Williams Date: Wed, 15 May 2024 11:26:27 +0100 Subject: [PATCH] Flash first flow --- app/build.gradle | 1 + .../main/java/com/samsung/microbit/MBApp.java | 64 +- .../java/com/samsung/microbit/MBAppState.java | 166 +++++ .../microbit/core/bluetooth/BLEManager.java | 6 +- .../core/bluetooth/BluetoothUtils.java | 210 ++++-- .../microbit/data/model/ConnectedDevice.java | 8 + .../samsung/microbit/service/BLEService.java | 5 +- .../samsung/microbit/service/IPCService.java | 6 +- .../microbit/service/ServiceConnector.java | 4 +- .../microbit/ui/activity/MakeCodeWebView.java | 9 +- .../microbit/ui/activity/PairingActivity.java | 124 ++-- .../microbit/ui/activity/ProjectActivity.java | 672 ++++++++++++------ .../microbit/ui/view/PatternDrawable.java | 120 ++++ .../microbit/utils/BLEConnectionHandler.java | 7 +- .../main/res/layout-land/activity_main.xml | 24 +- .../res/layout-land/view_projects_pattern.xml | 159 +++++ .../layout-land/view_projects_searching.xml | 129 ++++ .../main/res/layout-port/activity_main.xml | 24 +- .../res/layout-sw600dp-port/activity_main.xml | 24 +- app/src/main/res/layout/activity_projects.xml | 44 +- app/src/main/res/layout/projects_app_bar.xml | 4 +- .../main/res/layout/view_projects_pattern.xml | 131 ++++ .../res/layout/view_projects_projects.xml | 47 ++ .../res/layout/view_projects_searching.xml | 105 +++ app/src/main/res/values/strings.xml | 36 +- pfLibrary | 2 +- 26 files changed, 1656 insertions(+), 475 deletions(-) create mode 100644 app/src/main/java/com/samsung/microbit/MBAppState.java create mode 100644 app/src/main/java/com/samsung/microbit/ui/view/PatternDrawable.java create mode 100644 app/src/main/res/layout-land/view_projects_pattern.xml create mode 100644 app/src/main/res/layout-land/view_projects_searching.xml create mode 100644 app/src/main/res/layout/view_projects_pattern.xml create mode 100644 app/src/main/res/layout/view_projects_projects.xml create mode 100644 app/src/main/res/layout/view_projects_searching.xml diff --git a/app/build.gradle b/app/build.gradle index 810ea93d..de9db653 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,6 +33,7 @@ android { } dependencies { + implementation 'androidx.lifecycle:lifecycle-process:2.7.0' testImplementation 'junit:junit:4.12' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.11.0' diff --git a/app/src/main/java/com/samsung/microbit/MBApp.java b/app/src/main/java/com/samsung/microbit/MBApp.java index b69bcd69..bce2b9c3 100644 --- a/app/src/main/java/com/samsung/microbit/MBApp.java +++ b/app/src/main/java/com/samsung/microbit/MBApp.java @@ -1,15 +1,31 @@ package com.samsung.microbit; +import static com.samsung.microbit.BuildConfig.DEBUG; + import android.app.Application; import android.graphics.Typeface; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.ProcessLifecycleOwner; + +import com.samsung.microbit.MBAppState; + /** * Represents a custom class of the app. * Provides some resources that use along app modules, * such as app context, font styles and etc. */ -public class MBApp extends Application { +public class MBApp extends Application implements DefaultLifecycleObserver { + private static final String TAG = MBApp.class.getSimpleName(); + + public void logi(String message) { + if ( DEBUG) { + Log.i(TAG, "### " + Thread.currentThread().getId() + " # " + message); + } + } private static MBApp app = null; @@ -19,12 +35,15 @@ public class MBApp extends Application { private boolean justPaired; + private MBAppState appState = new MBAppState(); + @Override public void onCreate() { super.onCreate(); app = this; + ProcessLifecycleOwner.get().getLifecycle().addObserver(this); initTypefaces(); - + appState.prefsLoad(); Log.d("MBApp", "App Created"); } @@ -61,4 +80,43 @@ public static MBApp getApp() { return app; } -} \ No newline at end of file + public static MBAppState getAppState() { + return app.appState; + } + + @Override + public void onCreate(@NonNull LifecycleOwner owner) { + logi("onCreate"); + MBApp.getAppState().eventPairForeground(); + } + + @Override + public void onStart(@NonNull LifecycleOwner owner) { + logi("onStart"); + MBApp.getAppState().eventPairForeground(); + } + + @Override + public void onResume(@NonNull LifecycleOwner owner) { + logi("onResume"); + MBApp.getAppState().eventPairForeground(); + } + + @Override + public void onPause(@NonNull LifecycleOwner owner) { + logi("onPause"); + MBApp.getAppState().eventPairBackground(); + } + + @Override + public void onStop(@NonNull LifecycleOwner owner) { + logi("onStop"); + MBApp.getAppState().eventPairBackground(); + } + + @Override + public void onDestroy(@NonNull LifecycleOwner owner) { + logi("onDestroy"); + MBApp.getAppState().eventPairBackground(); + } +} diff --git a/app/src/main/java/com/samsung/microbit/MBAppState.java b/app/src/main/java/com/samsung/microbit/MBAppState.java new file mode 100644 index 00000000..88e93ca9 --- /dev/null +++ b/app/src/main/java/com/samsung/microbit/MBAppState.java @@ -0,0 +1,166 @@ +package com.samsung.microbit; + +import static com.samsung.microbit.BuildConfig.DEBUG; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + +import com.samsung.microbit.MBApp; +import com.samsung.microbit.core.bluetooth.BluetoothUtils; +import com.samsung.microbit.data.constants.Constants; +import com.samsung.microbit.data.model.ConnectedDevice; + +public class MBAppState { + private static final String TAG = MBAppState.class.getSimpleName(); + + public void logi(String message) { + if ( DEBUG) { + Log.i(TAG, "### " + Thread.currentThread().getId() + " # " + message); + } + } + + public enum PairState { + PairStateNone, + PairStateError, + PairStateLaunch, + PairStateSession, + PairStateChecked + } + + public boolean pairStateLaunch; + public boolean pairStateSession; + public boolean pairStateError; + public boolean pairStateMakeCode; + public boolean pairStateResetTriple; + + public MBAppState() { + pairStateLaunch = true; + pairStateSession = true; + pairStateError = false; + pairStateMakeCode = false; + pairStateResetTriple = true; + } + + public PairState pairState() { + PairState ps = PairState.PairStateChecked; + + if ( !BluetoothUtils.getCurrentMicrobitIsValid( MBApp.getApp())) + ps = PairState.PairStateNone; + else if ( pairStateError) + ps = PairState.PairStateError; + else if ( pairStateLaunch) + ps = PairState.PairStateLaunch; + else if ( pairStateSession) + ps = PairState.PairStateSession; + else + ps = PairState.PairStateChecked; + + logi( "pairState " + ps); + return ps; + } + + public void eventPairSuccess() { + logi( "eventPairSuccess"); + pairStateLaunch = false; + pairStateSession = false; + pairStateError = false; + prefsSave(); + } + + public void eventPairChecked() { + logi( "eventPairChecked"); + pairStateLaunch = false; + pairStateSession = false; + } + + public void eventPairDifferent() { + logi( "eventPairDifferent"); + pairStateSession = true; + } + + public void eventPairBackground() { + logi( "eventPairBackground"); + if ( !pairStateMakeCode) + pairStateSession = true; + } + + public void eventPairForeground() { + logi( "eventPairForeground"); + if ( !pairStateMakeCode) + pairStateSession = true; + } + + public void eventPairError() { + logi( "eventPairError"); + pairStateError = true; + prefsSave(); + } + + public void eventPairMakeCodeBegin() { + logi( "eventPairMakeCodeBegin"); + pairStateSession = true; + pairStateMakeCode = true; + } + + public void eventPairMakeCodeEnd() { + logi( "eventPairMakeCodeEnd"); + pairStateMakeCode = false; + } + + public void eventPairSendError() { + logi( "eventPairSendError"); + pairStateError = true; + prefsSave(); + } + + public void eventPairResetTriple( boolean yes) + { + logi( "eventPairResetTriple " + yes); + pairStateResetTriple = yes; + prefsSave(); + } + + public void eventPairResetMethodCheck( ConnectedDevice device) + { + logi( "eventPairResetMethodCheck"); + if ( device != null && device.mPattern != null) + { + if ( device.mhardwareVersion == 1) // MICROBIT_V1 + { + eventPairResetTriple( false); + return; + } + } + eventPairResetTriple( true); + } + + public static final String PREFERENCES_pairStateError = "Preferences.pairStateError"; + public static final String PREFERENCES_pairStateResetTriple = "Preferences.pairStateResetTriple"; + + public void prefsLoad() + { + Context ctx = MBApp.getApp(); + SharedPreferences prefs = ctx.getSharedPreferences(Constants.PREFERENCES, Context.MODE_MULTI_PROCESS); + if ( prefs == null) { + logi( "prefsLoad failed"); + return; + } + pairStateError = prefs.getBoolean( PREFERENCES_pairStateError, pairStateError); + pairStateResetTriple = prefs.getBoolean( PREFERENCES_pairStateResetTriple, pairStateResetTriple); + } + + public void prefsSave() + { + Context ctx = MBApp.getApp(); + SharedPreferences prefs = ctx.getSharedPreferences(Constants.PREFERENCES, Context.MODE_MULTI_PROCESS); + SharedPreferences.Editor prefsEdit = prefs == null ? null: prefs.edit(); + if ( prefsEdit == null) { + logi( "prefsSave failed"); + return; + } + prefsEdit.putBoolean( PREFERENCES_pairStateError, pairStateError); + prefsEdit.putBoolean( PREFERENCES_pairStateResetTriple, pairStateResetTriple); + prefsEdit.apply(); + } +} diff --git a/app/src/main/java/com/samsung/microbit/core/bluetooth/BLEManager.java b/app/src/main/java/com/samsung/microbit/core/bluetooth/BLEManager.java index d0f3b5dc..c44603d9 100644 --- a/app/src/main/java/com/samsung/microbit/core/bluetooth/BLEManager.java +++ b/app/src/main/java/com/samsung/microbit/core/bluetooth/BLEManager.java @@ -776,15 +776,13 @@ public void onServicesDiscovered(BluetoothGatt gatt, int status) { } if(status == BluetoothGatt.GATT_SUCCESS) { - ConnectedDevice cD = BluetoothUtils.getPairedMicrobit(MBApp.getApp()); if(gatt.getService(UUID.fromString("0000fe59-0000-1000-8000-00805f9b34fb")) != null ) { Log.v(TAG, "Hardware Type: V2"); - cD.mhardwareVersion = 2; + BluetoothUtils.setCurrentMicrobitHardwareVersion(MBApp.getApp(), 2); } else { Log.v(TAG, "Hardware Type: V1"); - cD.mhardwareVersion = 1; + BluetoothUtils.setCurrentMicrobitHardwareVersion(MBApp.getApp(), 1); } - BluetoothUtils.setPairedMicroBit(MBApp.getApp(), cD); bleState |= state; } else { bleState &= (~state); diff --git a/app/src/main/java/com/samsung/microbit/core/bluetooth/BluetoothUtils.java b/app/src/main/java/com/samsung/microbit/core/bluetooth/BluetoothUtils.java index c4caca8a..6dcd20db 100644 --- a/app/src/main/java/com/samsung/microbit/core/bluetooth/BluetoothUtils.java +++ b/app/src/main/java/com/samsung/microbit/core/bluetooth/BluetoothUtils.java @@ -9,7 +9,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.Build; -import android.provider.Settings; import android.util.Log; import com.google.gson.Gson; @@ -26,11 +25,12 @@ public class BluetoothUtils { private static final String TAG = BluetoothUtils.class.getSimpleName(); - public static final String PREFERENCES_KEY = "Microbit_PairedDevices"; - public static final String PREFERENCES_PAIREDDEV_KEY = "PairedDeviceDevice"; + private static final String PREFERENCES_KEY = "Microbit_PairedDevices"; + private static final String PREFERENCES_PAIREDDEV_KEY = "PairedDeviceDevice"; - // sConnectedDevice used only as a buffer - actual value stored in prefs - private static ConnectedDevice sConnectedDevice = new ConnectedDevice(); + // sConnectedDevice used only as a cache - actual value stored in prefs + // Use getCurrentMicrobit() to read, so as to read prefs if necessary + private static ConnectedDevice sConnectedDevice = null; private static void logi(String message) { if(DEBUG) { @@ -38,13 +38,12 @@ private static void logi(String message) { } } - public static SharedPreferences getPreferences(Context ctx) { - + private static SharedPreferences getPreferences(Context ctx) { logi("getPreferences() :: ctx.getApplicationContext() = " + ctx.getApplicationContext()); return ctx.getApplicationContext().getSharedPreferences(PREFERENCES_KEY, Context.MODE_MULTI_PROCESS); } - public static ConnectedDevice deviceFromPrefs(Context ctx) { + private static ConnectedDevice deviceFromPrefs(Context ctx) { SharedPreferences prefs = getPreferences( ctx); ConnectedDevice fromPrefs = null; @@ -57,7 +56,7 @@ public static ConnectedDevice deviceFromPrefs(Context ctx) { return fromPrefs; } - public static void deviceToPrefs(Context ctx, ConnectedDevice toPrefs) { + private static void deviceToPrefs(Context ctx, ConnectedDevice toPrefs) { SharedPreferences prefs = ctx.getApplicationContext().getSharedPreferences(PREFERENCES_KEY, Context.MODE_MULTI_PROCESS); SharedPreferences.Editor editor = prefs.edit(); @@ -84,7 +83,7 @@ private static boolean havePermissionsFlashing( Context ctx) { return yes; } - public static String parse(final BluetoothGattCharacteristic characteristic) { + public static String parseCharacteristic(final BluetoothGattCharacteristic characteristic) { final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); final byte[] data = characteristic.getValue(); if(data == null) @@ -104,90 +103,143 @@ public static String parse(final BluetoothGattCharacteristic characteristic) { return new String(out); } - public static boolean inZenMode(Context paramContext) { - /* - /** - * Defines global zen mode. ZEN_MODE_OFF, ZEN_MODE_IMPORTANT_INTERRUPTIONS, - - public static final String ZEN_MODE = "zen_mode"; - public static final int ZEN_MODE_OFF = 0; - public static final int ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1; - public static final int ZEN_MODE_NO_INTERRUPTIONS = 2; - public static final int ZEN_MODE_ALARMS = 3; - */ - int zenMode = Settings.Global.getInt(paramContext.getContentResolver(), "zen_mode", 0); - Log.i("MicroBit", "zen_mode : " + zenMode); - return (zenMode != 0); - } - - public static void updateFirmwareMicrobit(Context ctx, String firmware) { - ConnectedDevice fromPrefs = deviceFromPrefs(ctx); - if( fromPrefs != null) { - Log.v("BluetoothUtils", "Updating the microbit firmware version"); - fromPrefs.mfirmware_version = firmware; - deviceToPrefs(ctx, fromPrefs); - } + public static void setCurrentMicrobitFirmware(Context ctx, String firmware) { + Log.v("BluetoothUtils", "Updating the microbit firmware version"); + getCurrentMicrobit( ctx); + sConnectedDevice.mfirmware_version = firmware; + saveCurrentMicrobit( ctx); } - public static void updateConnectionStartTime(Context ctx, long time) { - ConnectedDevice fromPrefs = deviceFromPrefs(ctx); - if( fromPrefs != null) { - Log.e("BluetoothUtils", "Updating the microbit connection time"); - fromPrefs.mlast_connection_time = time; - deviceToPrefs(ctx, fromPrefs); - } + public static void setCurrentMicrobitConnectionStartTime(Context ctx, long time) { + Log.e("BluetoothUtils", "Updating the microbit connection time"); + getCurrentMicrobit( ctx); + sConnectedDevice.mlast_connection_time = time; + saveCurrentMicrobit( ctx); } - public static ConnectedDevice getPairedMicrobit(Context ctx) { - SharedPreferences pairedDevicePref = ctx.getApplicationContext().getSharedPreferences(PREFERENCES_KEY, - Context.MODE_MULTI_PROCESS); + public static void setCurrentMicrobitHardwareVersion(Context ctx, int version) { + Log.e("BluetoothUtils", "setCurrentMicrobitHardwareVersion " +version); + getCurrentMicrobit( ctx); + sConnectedDevice.mhardwareVersion = version; + saveCurrentMicrobit( ctx); + } - if(sConnectedDevice == null) { - sConnectedDevice = new ConnectedDevice(); + public static void setCurrentMicrobitStatus(Context ctx, boolean status) { + Log.e("BluetoothUtils", "setCurrentMicrobitStatus " + status); + getCurrentMicrobit( ctx); + sConnectedDevice.mStatus = status; + saveCurrentMicrobit( ctx); + } + + /** + * Check if we can access system paired devices list + * Do we have permission and is Bluetooth on? + */ + public static boolean canCheckPairedList(Context ctx) { + if ( havePermissionsFlashing( ctx)) { + MBApp mbApp = MBApp.getApp(); + BluetoothManager manager = (BluetoothManager) mbApp.getSystemService(Context.BLUETOOTH_SERVICE); + BluetoothAdapter adapter = manager.getAdapter(); + return adapter.isEnabled(); } + return false; + } - ConnectedDevice fromPrefs = deviceFromPrefs(ctx); - if( fromPrefs == null) { - sConnectedDevice.mPattern = null; - sConnectedDevice.mName = null; - } else { - boolean pairedMicrobitInSystemList = false; - sConnectedDevice = fromPrefs; - //Check if the microbit is still paired with our mobile - BluetoothAdapter mBluetoothAdapter = ((BluetoothManager) MBApp.getApp().getSystemService(Context - .BLUETOOTH_SERVICE)).getAdapter(); - if(mBluetoothAdapter.isEnabled() && havePermissionsFlashing( ctx)) { - @SuppressLint("MissingPermission") Set pairedDevices = mBluetoothAdapter.getBondedDevices(); - for(BluetoothDevice bt : pairedDevices) { - if(bt.getAddress().equals(sConnectedDevice.mAddress)) { - pairedMicrobitInSystemList = true; - break; - } + /** + * Check if address is in system paired devices list + * if address is null return false + * if we cannot check return false + */ + public static boolean addressIsDefinitelyInPairedList(Context ctx, final String address) { + if ( address == null) { + return false; + } + if ( canCheckPairedList( ctx)) { + MBApp mbApp = MBApp.getApp(); + BluetoothManager manager = (BluetoothManager) mbApp.getSystemService(Context.BLUETOOTH_SERVICE); + BluetoothAdapter adapter = manager.getAdapter(); + @SuppressLint("MissingPermission") + Set pairedDevices = adapter.getBondedDevices(); + for(BluetoothDevice bt : pairedDevices) { + if(bt.getAddress().equals( address)) { + return true; } - } else { - //Do not change the list until the Bluetooth is back ON again - pairedMicrobitInSystemList = true; } + } + return false; + } - if(!pairedMicrobitInSystemList) { - Log.e("BluetoothUtils", "The last paired microbit is no longer in the system list. Hence removing it"); - //Return a NULL device & update preferences - sConnectedDevice.mPattern = null; - sConnectedDevice.mName = null; - sConnectedDevice.mStatus = false; - sConnectedDevice.mAddress = null; - sConnectedDevice.mPairingCode = 0; - sConnectedDevice.mfirmware_version = null; - sConnectedDevice.mlast_connection_time = 0; - - setPairedMicroBit(ctx, null); + /** + * Check if address is not in system paired devices list + * if address is null return true + * if we cannot check return false + */ + public static boolean addressIsDefinitelyNotInPairedList(Context ctx, final String address) { + if ( address == null) { + return true; + } + if ( canCheckPairedList( ctx)) { + MBApp mbApp = MBApp.getApp(); + BluetoothManager manager = (BluetoothManager) mbApp.getSystemService(Context.BLUETOOTH_SERVICE); + BluetoothAdapter adapter = manager.getAdapter(); + @SuppressLint("MissingPermission") + Set pairedDevices = adapter.getBondedDevices(); + for(BluetoothDevice bt : pairedDevices) { + if(bt.getAddress().equals( address)) { + return false; + } } + return true; + } + return false; + } + + private static void saveCurrentMicrobit(Context ctx) { + deviceToPrefs( ctx, sConnectedDevice); + } + + private static ConnectedDevice loadCurrentMicrobit(Context ctx) { + sConnectedDevice = deviceFromPrefs(ctx); + if ( sConnectedDevice == null) { + sConnectedDevice = new ConnectedDevice(); } return sConnectedDevice; } - public static void setPairedMicroBit(Context ctx, ConnectedDevice newDevice) { - deviceToPrefs( ctx, newDevice); + public static void setCurrentMicroBit(Context ctx, ConnectedDevice newDevice) { + sConnectedDevice = newDevice; + saveCurrentMicrobit( ctx); + } + + public static ConnectedDevice getCurrentMicrobit(Context ctx) { + if ( sConnectedDevice == null) { + sConnectedDevice = loadCurrentMicrobit( ctx); + } + return sConnectedDevice; + } + + public static boolean getCurrentMicrobitIsValid(Context ctx) { + getCurrentMicrobit( ctx); + return sConnectedDevice != null + && sConnectedDevice.mPattern != null + && sConnectedDevice.mName != null + && sConnectedDevice.mAddress != null; + } + + public static boolean getCurrentMicrobitIsDefinitelyInPairedList(Context ctx) { + getCurrentMicrobit(ctx); + return addressIsDefinitelyInPairedList( ctx, sConnectedDevice.mAddress); + } + + public static boolean getCurrentMicrobitIsDefinitelyNotInPairedList(Context ctx) { + getCurrentMicrobit(ctx); + return addressIsDefinitelyNotInPairedList( ctx, sConnectedDevice.mAddress); } +// public static ConnectedDevice getPairedMicrobit(Context ctx) { +// if ( getCurrentMicrobitIsDefinitelyNotInPairedList( ctx)) { +// setCurrentMicroBit( ctx, new ConnectedDevice()); +// } +// return sConnectedDevice; +// } } diff --git a/app/src/main/java/com/samsung/microbit/data/model/ConnectedDevice.java b/app/src/main/java/com/samsung/microbit/data/model/ConnectedDevice.java index df7c9eec..10b335f5 100644 --- a/app/src/main/java/com/samsung/microbit/data/model/ConnectedDevice.java +++ b/app/src/main/java/com/samsung/microbit/data/model/ConnectedDevice.java @@ -17,6 +17,14 @@ public class ConnectedDevice { public int mhardwareVersion; public ConnectedDevice() { + mPattern = null; + mName = null; + mStatus = false; + mAddress = null; + mPairingCode = 0; + mfirmware_version = null; + mlast_connection_time = 0; + mhardwareVersion = 0; } public ConnectedDevice(String name, String pattern, diff --git a/app/src/main/java/com/samsung/microbit/service/BLEService.java b/app/src/main/java/com/samsung/microbit/service/BLEService.java index d05450eb..92e68eb7 100644 --- a/app/src/main/java/com/samsung/microbit/service/BLEService.java +++ b/app/src/main/java/com/samsung/microbit/service/BLEService.java @@ -681,7 +681,7 @@ private int writeCharacteristic(BluetoothGattCharacteristic characteristic) { rc = bleManager.writeCharacteristic(characteristic); rc = interpretCode(rc); - logi("Data written to " + characteristic.getUuid() + " value : (0x)" + BluetoothUtils.parse + logi("Data written to " + characteristic.getUuid() + " value : (0x)" + BluetoothUtils.parseCharacteristic (characteristic) + " Return Value = 0x" + Integer.toHexString(rc)); } return rc; @@ -773,8 +773,7 @@ public void handleConnectionEvent(int event, boolean gattForceClosed) { private String searchDeviceAddress() { logi("getDeviceAddress()"); - ConnectedDevice currentDevice = BluetoothUtils.getPairedMicrobit(this); - String deviceAddress = currentDevice.mAddress; + String deviceAddress = BluetoothUtils.getCurrentMicrobit(this).mAddress; if(deviceAddress == null) { setNotification(false, ERROR_UNKNOWN_3); } diff --git a/app/src/main/java/com/samsung/microbit/service/IPCService.java b/app/src/main/java/com/samsung/microbit/service/IPCService.java index d87b9027..c467dd40 100644 --- a/app/src/main/java/com/samsung/microbit/service/IPCService.java +++ b/app/src/main/java/com/samsung/microbit/service/IPCService.java @@ -158,10 +158,8 @@ private void handleMessage(Message message) { if (message.arg1 == EventCategories.IPC_BLE_NOTIFICATION_GATT_CONNECTED || message.arg1 == EventCategories.IPC_BLE_NOTIFICATION_GATT_DISCONNECTED) { - - ConnectedDevice cd = BluetoothUtils.getPairedMicrobit(appContext); - cd.mStatus = (message.arg1 == EventCategories.IPC_BLE_NOTIFICATION_GATT_CONNECTED); - BluetoothUtils.setPairedMicroBit(appContext, cd); + BluetoothUtils.setCurrentMicrobitStatus( appContext, + message.arg1 == EventCategories.IPC_BLE_NOTIFICATION_GATT_CONNECTED); } Bundle messageData = message.getData(); diff --git a/app/src/main/java/com/samsung/microbit/service/ServiceConnector.java b/app/src/main/java/com/samsung/microbit/service/ServiceConnector.java index 867d7e71..ae05a375 100644 --- a/app/src/main/java/com/samsung/microbit/service/ServiceConnector.java +++ b/app/src/main/java/com/samsung/microbit/service/ServiceConnector.java @@ -92,9 +92,7 @@ public void onServiceConnected(ComponentName className, IBinder service) { mServiceMessengers.put(className.getClassName(), mServiceMessenger); if(++countBoundServices == COUNT_SERVICES_FOR_BINDING) { - ConnectedDevice connectedDevice = BluetoothUtils.getPairedMicrobit(mCtx); - - if(connectedDevice.mStatus) { + if( BluetoothUtils.getCurrentMicrobit(mCtx).mStatus) { Intent intent = new Intent(mCtx, IPCService.class); intent.putExtra(IPCConstants.INTENT_TYPE, EventCategories.IPC_BLE_CONNECT); mCtx.startService(intent); diff --git a/app/src/main/java/com/samsung/microbit/ui/activity/MakeCodeWebView.java b/app/src/main/java/com/samsung/microbit/ui/activity/MakeCodeWebView.java index 56963e61..fe19035e 100644 --- a/app/src/main/java/com/samsung/microbit/ui/activity/MakeCodeWebView.java +++ b/app/src/main/java/com/samsung/microbit/ui/activity/MakeCodeWebView.java @@ -21,6 +21,7 @@ import android.widget.Toast; import com.samsung.microbit.BuildConfig; +import com.samsung.microbit.MBApp; import com.samsung.microbit.R; import com.samsung.microbit.utils.FileUtils; import com.samsung.microbit.utils.ProjectsHelper; @@ -94,7 +95,10 @@ protected void onCreate(Bundle savedInstanceState) { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { Log.v(TAG, "url: " + url); - if (url.contains("https://microbit.org/")) activityHandle.finish(); + if (url.contains("https://microbit.org/")) { + MBApp.getAppState().eventPairMakeCodeEnd(); + activityHandle.finish(); + } return false; } @@ -244,6 +248,7 @@ else if ( !hexName.isEmpty()) { } webView.loadUrl(makecodeUrl); + MBApp.getAppState().eventPairMakeCodeBegin(); } // onCreate private void saveData( String name, String mimetype, byte[] data) { @@ -301,6 +306,7 @@ public void onBackPressed() { public void onClick(final View v) { if(v.getId() == R.id.backBtn) { + MBApp.getAppState().eventPairMakeCodeEnd(); finish(); } } @@ -456,6 +462,7 @@ class JavaScriptInterface { @JavascriptInterface public void clickBrand() { try { + MBApp.getAppState().eventPairMakeCodeEnd(); MakeCodeWebView.activityHandle.finish(); } catch(Exception e) { Log.v(TAG, e.toString()); diff --git a/app/src/main/java/com/samsung/microbit/ui/activity/PairingActivity.java b/app/src/main/java/com/samsung/microbit/ui/activity/PairingActivity.java index 70a43d34..573e48f5 100644 --- a/app/src/main/java/com/samsung/microbit/ui/activity/PairingActivity.java +++ b/app/src/main/java/com/samsung/microbit/ui/activity/PairingActivity.java @@ -138,6 +138,7 @@ private enum PAIRING_STATE { public final static String ACTION_RESET_TO_BLE = "com.samsung.microbit.ACTION_RESET_TO_BLE"; public final static String ACTION_PAIR_BEFORE_FLASH = "com.samsung.microbit.ACTION_PAIR_BEFORE_FLASH"; + public final static String ACTION_PAIR_BEFORE_FLASH_ALREADY_RESET = "com.samsung.microbit.ACTION_PAIR_BEFORE_FLASH_ALREADY_RESET"; private String inAction = ""; @@ -162,6 +163,10 @@ private void handleIncomingIntent(Intent intent) { pairBeforeFlashStart(); return; } + if ( inAction.equals(ACTION_PAIR_BEFORE_FLASH_ALREADY_RESET)) { + pairBeforeFlashAlreadyResetStart(); + return; + } } private void resetToBLEStart() { @@ -185,12 +190,27 @@ private void pairBeforeFlashFinish( int resultCode) { finish(); } + private void pairBeforeFlashAlreadyResetStart() { + displayScreen(PAIRING_STATE.PAIRING_STATE_TRIPLE); + checkBluetoothPermissions(); + } + + private void pairBeforeFlashAlreadyResetFinish( int resultCode) { + inAction = ""; + setResult( resultCode); + finish(); + } + public void onFinish( int resultCode) { logi("onFinish " + resultCode); if ( inAction.equals(ACTION_PAIR_BEFORE_FLASH)) { pairBeforeFlashFinish( resultCode); return; } + if ( inAction.equals(ACTION_PAIR_BEFORE_FLASH_ALREADY_RESET)) { + pairBeforeFlashAlreadyResetFinish( resultCode); + return; + } displayScreen(PAIRING_STATE.PAIRING_STATE_CONNECT_BUTTON); } @@ -282,6 +302,18 @@ private void proceedAfterBlePermissionGranted() { return; } + startPairingUI(); + } + + /** + * Starts the pairing user interface + * assuming permissions granted, and Bluetooth is on, and Location on if required + */ + private void startPairingUI() { + if ( inAction.equals(ACTION_PAIR_BEFORE_FLASH_ALREADY_RESET)) { + displayScreen(PAIRING_STATE.PAIRING_STATE_STEP_2); + return; + } displayScreen(PAIRING_STATE.PAIRING_STATE_TRIPLE); } @@ -479,6 +511,10 @@ public void onClick(View v) { pairBeforeFlashFinish( RESULT_CANCELED); return; } + if ( inAction.equals(ACTION_PAIR_BEFORE_FLASH_ALREADY_RESET)) { + pairBeforeFlashAlreadyResetFinish( RESULT_CANCELED); + return; + } displayScreen(PAIRING_STATE.PAIRING_STATE_STEP_2); } }; @@ -1051,13 +1087,14 @@ public String getStatusString(boolean status) { private void updatePairedDeviceCard() { logi("updatePairedDeviceCard"); - ConnectedDevice connectedDevice = BluetoothUtils.getPairedMicrobit(this); - if(connectedDevice.mName == null) { - // No device is Paired + String name = BluetoothUtils.getCurrentMicrobit(this).mName; + if( name == null) { + // Not valid deviceConnectionStatusTextView.setText("-"); } else { - deviceConnectionStatusTextView.setText(connectedDevice.mName); - } + deviceConnectionStatusTextView.setText( name); + + } logi("updatePairedDeviceCard End"); } @@ -1197,41 +1234,6 @@ public void popupLocationNeeded() { failedPermissionHandler, failedPermissionHandler); } - /** - * Enables or disables connection with a currently paired micro:bit board. - */ -// private void toggleConnection() { -// ConnectedDevice currentDevice = BluetoothUtils.getPairedMicrobit(this); -// Log.v(TAG, "currentDevice.toString()"); -// -// if(currentDevice.mAddress != null) { -// boolean currentState = currentDevice.mStatus; -// -// if(!currentState) { -// setActivityState(PairingActivityState.STATE_CONNECTING); -// requestPermissions.clear(); -// PopUp.show(getString(R.string.init_connection), -// "", -// R.drawable.message_face, R.drawable.blue_btn, -// PopUp.GIFF_ANIMATION_NONE, -// PopUp.TYPE_SPINNER, -// null, null); -// -// ServiceUtils.sendConnectDisconnectMessage(true); -// } else { -// setActivityState(PairingActivityState.STATE_DISCONNECTING); -// PopUp.show(getString(R.string.disconnecting), -// "", -// R.drawable.message_face, R.drawable.blue_btn, -// PopUp.GIFF_ANIMATION_NONE, -// PopUp.TYPE_SPINNER, -// null, null); -// -// ServiceUtils.sendConnectDisconnectMessage(false); -// } -// } -// } - @Override public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { @@ -1424,7 +1426,7 @@ public void onClick(View v) { PopUp.hide(); //Unpair the device for secure BLE unPairDevice(); - BluetoothUtils.setPairedMicroBit(MBApp.getApp(), null); + BluetoothUtils.setCurrentMicroBit(MBApp.getApp(), null); updatePairedDeviceCard(); } },//override click listener for ok button @@ -1435,8 +1437,7 @@ public void onClick(View v) { * Finds all bonded devices and tries to unbond it. */ private void unPairDevice() { - ConnectedDevice connectedDevice = BluetoothUtils.getPairedMicrobit(this); - String addressToDelete = connectedDevice.mAddress; + String addressToDelete = BluetoothUtils.getCurrentMicrobit(this).mAddress; // Get the paired devices and put them in a Set BluetoothAdapter mBluetoothAdapter = ((BluetoothManager) getSystemService(BLUETOOTH_SERVICE)).getAdapter(); Set pairedDevices = mBluetoothAdapter.getBondedDevices(); @@ -1465,6 +1466,10 @@ private void handleResetAll() { pairBeforeFlashFinish( RESULT_CANCELED); return; } + if ( inAction.equals(ACTION_PAIR_BEFORE_FLASH_ALREADY_RESET)) { + pairBeforeFlashAlreadyResetFinish( RESULT_CANCELED); + return; + } if(pairingState == PAIRING_STATE.PAIRING_STATE_CONNECT_BUTTON) { finish(); } else { @@ -1506,6 +1511,7 @@ private void popupPairingTimeout() { */ private void popupPairingFailed() { logi("popupPairingFailed() :: Start"); + MBApp.getAppState().eventPairError(); PopUp.show(getString(R.string.pairing_failed_message), //message getString(R.string.pairing_failed_title), //title R.drawable.error_face, //image icon res id @@ -1516,7 +1522,7 @@ private void popupPairingFailed() { @Override public void onClick(View v) { PopUp.hide(); - displayScreen(PAIRING_STATE.PAIRING_STATE_TRIPLE); + startPairingUI(); } },//override click listener for ok button new View.OnClickListener() { @@ -1543,8 +1549,28 @@ private void handlePairingSuccessful() { null, System.currentTimeMillis(), getBLEPair().resultHardwareVersion); - BluetoothUtils.setPairedMicroBit(MBApp.getApp(), newDev); + BluetoothUtils.setCurrentMicroBit(MBApp.getApp(), newDev); + MBApp.getAppState().eventPairSuccess(); updatePairedDeviceCard(); + + Log.e(TAG, "Set just paired to true"); + if(justPaired) { + justPaired = false; + MBApp.getApp().setJustPaired(true); + } else { + MBApp.getApp().setJustPaired(false); + } + + // If flashing, leave micro:bit in Bluetooth mode + if ( inAction.equals(ACTION_PAIR_BEFORE_FLASH)) { + onFinish( RESULT_OK); + return; + } + if ( inAction.equals(ACTION_PAIR_BEFORE_FLASH_ALREADY_RESET)) { + onFinish( RESULT_OK); + return; + } + // Pop up to show pairing successful PopUp.show(getString(R.string.pairing_successful_tip_message), // message getString(R.string.pairing_success_message_1), //title @@ -1554,14 +1580,6 @@ private void handlePairingSuccessful() { PopUp.TYPE_ALERT, //type of popup. successfulPairingHandler, successfulPairingHandler); - - Log.e(TAG, "Set just paired to true"); - if(justPaired) { - justPaired = false; - MBApp.getApp().setJustPaired(true); - } else { - MBApp.getApp().setJustPaired(false); - } } @Override diff --git a/app/src/main/java/com/samsung/microbit/ui/activity/ProjectActivity.java b/app/src/main/java/com/samsung/microbit/ui/activity/ProjectActivity.java index 4f81f09a..c411caef 100644 --- a/app/src/main/java/com/samsung/microbit/ui/activity/ProjectActivity.java +++ b/app/src/main/java/com/samsung/microbit/ui/activity/ProjectActivity.java @@ -11,29 +11,25 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.content.res.AssetFileDescriptor; import android.content.res.Configuration; -import android.database.Cursor; +import android.graphics.Typeface; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.os.Handler; -import android.provider.DocumentsContract; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.Window; -import android.webkit.ValueCallback; -import android.webkit.WebChromeClient; +import android.widget.Button; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; -import androidx.annotation.RequiresApi; import androidx.appcompat.widget.PopupMenu; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; @@ -43,43 +39,33 @@ import com.samsung.microbit.MBApp; import com.samsung.microbit.R; import com.samsung.microbit.core.bluetooth.BluetoothUtils; -import com.samsung.microbit.data.constants.Constants; import com.samsung.microbit.data.constants.EventCategories; import com.samsung.microbit.data.constants.IPCConstants; import com.samsung.microbit.data.constants.PermissionCodes; import com.samsung.microbit.data.constants.RequestCodes; import com.samsung.microbit.data.model.ConnectedDevice; import com.samsung.microbit.data.model.Project; +import com.samsung.microbit.data.model.ui.BaseActivityState; import com.samsung.microbit.data.model.ui.FlashActivityState; -import com.samsung.microbit.data.model.ui.PairingActivityState; import com.samsung.microbit.service.BLEService; import com.samsung.microbit.service.DfuService; import com.samsung.microbit.service.PartialFlashingService; import com.samsung.microbit.ui.BluetoothChecker; import com.samsung.microbit.ui.PopUp; import com.samsung.microbit.ui.adapter.ProjectAdapter; +import com.samsung.microbit.ui.view.PatternDrawable; import com.samsung.microbit.utils.BLEConnectionHandler; import com.samsung.microbit.utils.FileUtils; -import com.samsung.microbit.utils.IOUtils; import com.samsung.microbit.utils.ProjectsHelper; import com.samsung.microbit.utils.ServiceUtils; import com.samsung.microbit.utils.Utils; import com.samsung.microbit.utils.irmHexUtils; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.FilenameFilter; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; -import java.net.URI; -import java.net.URLDecoder; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; @@ -107,9 +93,7 @@ import static com.samsung.microbit.ui.activity.PopUpActivity.INTENT_GIFF_ANIMATION_CODE; import static com.samsung.microbit.utils.FileUtils.getFileSize; -import org.microbit.android.partialflashing.HexUtils; - -// import com.samsung.microbit.core.GoogleAnalyticsManager; +import org.microbit.android.partialflashing.PartialFlashingBaseService; /** * Represents the Flash screen that contains a list of project samples @@ -156,20 +140,54 @@ public class ProjectActivity extends Activity implements View.OnClickListener, B private boolean minimumPermissionsGranted; - private boolean inMakeCodeActionFlash = false; + enum Purpose { + PurposeIdle, + PurposeSend, + PurposeMakeCode + } + + private Purpose mPurpose = Purpose.PurposeIdle; + private int applicationSize; - private int prepareToFlashResult; + private int prepareToFlashResult; private int MICROBIT_V1 = 1; private int MICROBIT_V2 = 2; - BLEService bleService; - private static final int REQUEST_CODE_EXPORT = 1; private static final int REQUEST_CODE_IMPORT = 2; private static final int REQUEST_CODE_RESET_TO_BLE = 3; private static final int REQUEST_CODE_PAIR_BEFORE_FLASH = 4; + private static final int REQUEST_CODE_PAIR_BEFORE_FLASH_ALREADY_RESET = 5; + + private enum Screen { + ScreenMain, + ScreenPattern, + ScreenSearch + } + + private Screen mScreen = Screen.ScreenMain; + + private void displayScreen( Screen newState) { + logi("displayScreen"); + mScreen = newState; + initViews(); + setupFontStyle(); + } + + private void displayShowSearchingDifferent( boolean show) { + Button searchingDifferent = (Button) findViewById(R.id.viewProjectsSearchingDifferent); + searchingDifferent.setVisibility( show ? View.VISIBLE : View.INVISIBLE); + } + + boolean activityStateIsFlashing() { + return mActivityState == FlashActivityState.FLASH_STATE_FIND_DEVICE + || mActivityState == FlashActivityState.FLASH_STATE_VERIFY_DEVICE + || mActivityState == FlashActivityState.FLASH_STATE_WAIT_DEVICE_REBOOT + || mActivityState == FlashActivityState.FLASH_STATE_INIT_DEVICE + || mActivityState == FlashActivityState.FLASH_STATE_PROGRESS; + } private void goToPairingFromAppBarDeviceName() { Intent intent = new Intent(this, PairingActivity.class); @@ -182,6 +200,12 @@ private void goToPairingToPairBeforeFlash() { startActivityForResult( i, REQUEST_CODE_PAIR_BEFORE_FLASH); } + private void goToPairingToPairBeforeFlashAlreadyReset() { + Intent i = new Intent(this, PairingActivity.class); + i.setAction( PairingActivity.ACTION_PAIR_BEFORE_FLASH_ALREADY_RESET); + startActivityForResult( i, REQUEST_CODE_PAIR_BEFORE_FLASH_ALREADY_RESET); + } + private void goToPairingResetToBLE() { Intent i = new Intent(this, PairingActivity.class); i.setAction( PairingActivity.ACTION_RESET_TO_BLE); @@ -192,14 +216,30 @@ protected void onActivityResultPairing(int requestCode, int resultCode, Intent d switch ( requestCode) { case REQUEST_CODE_RESET_TO_BLE: if (resultCode == RESULT_OK) { - startFlashing(); + switch ( MBApp.getAppState().pairState()) + { + case PairStateNone: + case PairStateError: + onFlashComplete(); // won't happen + break; + case PairStateLaunch: + case PairStateSession: + displayScreen( Screen.ScreenPattern); + break; + case PairStateChecked: + default: + startFlashing(); + break; + } } else { onFlashComplete(); } break; case REQUEST_CODE_PAIR_BEFORE_FLASH: + case REQUEST_CODE_PAIR_BEFORE_FLASH_ALREADY_RESET: if (resultCode == RESULT_OK) { - flashingChecks(); + // micro:bit should still be in Bluetooth mode + flashingChecks( true); } else { onFlashComplete(); } @@ -208,8 +248,9 @@ protected void onActivityResultPairing(int requestCode, int resultCode, Intent d } private void goToMakeCode( String hex, String name) { - if ( inMakeCodeActionFlash) { - inMakeCodeActionFlash = false; + if ( mPurpose == Purpose.PurposeMakeCode) { + mPurpose = Purpose.PurposeIdle; + displayScreen( Screen.ScreenMain); setResult( Activity.RESULT_OK); finish(); } else { @@ -225,8 +266,47 @@ private void goToMakeCode( String hex, String name) { } private void onFlashComplete() { - if ( inMakeCodeActionFlash) { - goToMakeCode( null, null); + switch ( mPurpose) { + default: + case PurposeIdle: + case PurposeSend: + mPurpose = Purpose.PurposeIdle; + setActivityState(FlashActivityState.STATE_IDLE); + displayScreen( Screen.ScreenMain); + break; + case PurposeMakeCode: + goToMakeCode( null, null); + break; + } + } + + void restartPurpose() { + switch ( mPurpose) { + default: + case PurposeIdle: + setActivityState(FlashActivityState.STATE_IDLE); + displayScreen( Screen.ScreenMain); + break; + case PurposeSend: + case PurposeMakeCode: + setActivityState(FlashActivityState.STATE_ENABLE_BT_INTERNAL_FLASH_REQUEST); + startBluetoothForFlashing(); + break; + } + } + + void onPatternIsDifferent() { + switch ( mPurpose) { + default: + case PurposeIdle: + setActivityState(FlashActivityState.STATE_IDLE); + displayScreen( Screen.ScreenMain); + break; + case PurposeSend: + case PurposeMakeCode: + setActivityState(FlashActivityState.STATE_ENABLE_BT_INTERNAL_FLASH_REQUEST); + goToPairingToPairBeforeFlashAlreadyReset(); + break; } } @@ -447,15 +527,46 @@ public void onConfigurationChanged(Configuration newConfig) { * Setup font style by setting an appropriate typeface to needed views. */ private void setupFontStyle() { + + MBApp application = MBApp.getApp(); + Typeface defaultTypeface = application.getTypeface(); + Typeface boldTypeface = application.getTypefaceBold(); + Typeface robotoTypeface = application.getRobotoTypeface(); + // Title font TextView flashProjectsTitle = (TextView) findViewById(R.id.flash_projects_title_txt); - flashProjectsTitle.setTypeface(MBApp.getApp().getTypeface()); + flashProjectsTitle.setTypeface(defaultTypeface); // Create projects TextView createProjectText = (TextView) findViewById(R.id.custom_button_text); - createProjectText.setTypeface(MBApp.getApp().getRobotoTypeface()); + createProjectText.setTypeface(robotoTypeface); + + mEmptyText.setTypeface(defaultTypeface); + + // Pattern + TextView patternHeader = (TextView) findViewById(R.id.viewProjectsPatternHeader); + Button patternDifferent = (Button) findViewById(R.id.viewProjectsPatternDifferent); + Button patternCancel = (Button) findViewById(R.id.viewProjectsPatternCancel); + Button patternOK = (Button) findViewById(R.id.viewProjectsPatternOK); + + patternHeader.setTypeface(boldTypeface); + patternDifferent.setTypeface(robotoTypeface); + patternCancel.setTypeface(robotoTypeface); + patternOK.setTypeface(robotoTypeface); + + patternDifferent.setOnClickListener(this); + patternCancel.setOnClickListener(this); + patternOK.setOnClickListener(this); + + // Searching + TextView searchingHeader = (TextView) findViewById(R.id.viewProjectsSearchingHeader); + Button searchingDifferent = (Button) findViewById(R.id.viewProjectsSearchingDifferent); + searchingDifferent.setVisibility( View.VISIBLE); - mEmptyText.setTypeface(MBApp.getApp().getTypeface()); + searchingHeader.setTypeface(boldTypeface); + searchingDifferent.setTypeface(robotoTypeface); + + searchingDifferent.setOnClickListener(this); } private void initViews() { @@ -465,8 +576,58 @@ private void initViews() { if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { mProjectListViewRight = (ListView) findViewById(R.id.projectListViewRight); } - } + LinearLayout layoutProjects = (LinearLayout) findViewById(R.id.viewProjectsProjects); + LinearLayout layoutPattern = (LinearLayout) findViewById(R.id.viewProjectsPattern); + LinearLayout layoutSearch = (LinearLayout) findViewById(R.id.viewProjectsSearching); + + switch ( mScreen) { + case ScreenMain: + layoutProjects.setVisibility( View.VISIBLE); + layoutPattern.setVisibility( View.GONE); + layoutSearch.setVisibility( View.GONE); + break; + case ScreenPattern: { + PatternDrawable patternDrawable = new PatternDrawable(); + ImageView patternGrid = (ImageView) findViewById(R.id.viewProjectsPatternGrid); + TextView patternHeader = (TextView) findViewById(R.id.viewProjectsPatternHeader); + patternGrid.setImageDrawable( patternDrawable); + String deviceName = " "; + if (havePermissionsFlashing()) { + String pattern = BluetoothUtils.getCurrentMicrobit(this).mPattern; + if ( pattern != null) { + deviceName = pattern; + } + } + String header = getResources().getString(R.string.compare_your_pattern_with_NAME, deviceName); + patternHeader.setText( header); + patternDrawable.setDeviceName( deviceName); + layoutProjects.setVisibility(View.GONE); + layoutPattern.setVisibility(View.VISIBLE); + layoutSearch.setVisibility(View.GONE); + break; + } + case ScreenSearch: + PatternDrawable searchDrawable = new PatternDrawable(); + ImageView searchGrid = (ImageView) findViewById(R.id.viewProjectsSearchingGrid); + TextView searchHeader = (TextView) findViewById(R.id.viewProjectsSearchingHeader); + searchGrid.setImageDrawable( searchDrawable); + String deviceName = " "; + if (havePermissionsFlashing()) { + String pattern = BluetoothUtils.getCurrentMicrobit(this).mPattern; + if ( pattern != null) { + deviceName = pattern; + } + } + String header = getResources().getString(R.string.searching_for_microbit_NAME, deviceName); + searchHeader.setText( header); + searchDrawable.setDeviceName( deviceName); + layoutProjects.setVisibility( View.GONE); + layoutPattern.setVisibility( View.GONE); + layoutSearch.setVisibility( View.VISIBLE); + break; + } + } private void releaseViews() { mProjectListView = null; @@ -520,13 +681,19 @@ protected void onNewIntent(Intent intent) { } private void handleIncomingIntent(Intent intent) { + if ( mPurpose != Purpose.PurposeIdle) { + showPopupBusy(); + return; + } + String action = intent.getAction(); if (action != null && action.equals(MakeCodeWebView.ACTION_FLASH)) { makeCodeActionFlash(intent); return; } - inMakeCodeActionFlash = false; + mPurpose = Purpose.PurposeIdle; + displayScreen( Screen.ScreenMain); Uri uri = null; if (action != null && action.equals(Intent.ACTION_SEND) && intent.hasExtra(Intent.EXTRA_STREAM)) { @@ -540,9 +707,8 @@ private void handleIncomingIntent(Intent intent) { } private void makeCodeActionFlash(Intent intent) { - setActivityState(FlashActivityState.STATE_ENABLE_BT_EXTERNAL_FLASH_REQUEST); - - inMakeCodeActionFlash = true; + mPurpose = Purpose.PurposeMakeCode; + setActivityState(FlashActivityState.STATE_ENABLE_BT_INTERNAL_FLASH_REQUEST); mProgramToSend = null; String fullPathOfFile = intent.getStringExtra("path"); @@ -626,6 +792,16 @@ public void onClick(View v) { } }; + private void showPopupBusy() { + // Another download session is in progress.xml + PopUp.show(getString(R.string.multple_flashing_session_msg), + "", + R.drawable.flash_face, R.drawable.blue_btn, + PopUp.GIFF_ANIMATION_FLASH, + TYPE_ALERT, + popupOkHandler, popupOkHandler); + } + /** * Shows a pop-up window "More permission needed" with message that * that files cannot be accessed and displayed. @@ -735,34 +911,25 @@ private void setConnectedDeviceText() { // ImageView connectedIndicatorIcon = (ImageView) findViewById(R.id.connectedIndicatorIcon); //Override the connection Icon in case of active flashing - if(mActivityState == FlashActivityState.FLASH_STATE_FIND_DEVICE - || mActivityState == FlashActivityState.FLASH_STATE_VERIFY_DEVICE - || mActivityState == FlashActivityState.FLASH_STATE_WAIT_DEVICE_REBOOT - || mActivityState == FlashActivityState.FLASH_STATE_INIT_DEVICE - || mActivityState == FlashActivityState.FLASH_STATE_PROGRESS - ) { + if ( activityStateIsFlashing()) { // connectedIndicatorIcon.setImageResource(R.drawable.device_status_connected); connectedIndicatorText.setText(getString(R.string.connected_to)); - return; } - ConnectedDevice device = BluetoothUtils.getPairedMicrobit(this); - if(!device.mStatus) { + + boolean status = BluetoothUtils.getCurrentMicrobit(this).mStatus; + String name = BluetoothUtils.getCurrentMicrobit(this).mName; + if ( name == null) { + name = ""; + } + if(!status) { // connectedIndicatorIcon.setImageResource(R.drawable.device_status_disconnected); connectedIndicatorText.setText(getString(R.string.not_connected)); - if(device.mName != null) { - deviceName.setText(device.mName); - } else { - deviceName.setText(""); - } + deviceName.setText(name); } else { // connectedIndicatorIcon.setImageResource(R.drawable.device_status_connected); connectedIndicatorText.setText(getString(R.string.connected_to)); - if(device.mName != null) { - deviceName.setText(device.mName); - } else { - deviceName.setText(""); - } + deviceName.setText(name); } } @@ -886,26 +1053,16 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { return; case REQUEST_CODE_RESET_TO_BLE: case REQUEST_CODE_PAIR_BEFORE_FLASH: + case REQUEST_CODE_PAIR_BEFORE_FLASH_ALREADY_RESET: onActivityResultPairing( requestCode, resultCode, data); return; } - boolean flash = mActivityState == FlashActivityState.STATE_ENABLE_BT_INTERNAL_FLASH_REQUEST || - mActivityState == FlashActivityState.STATE_ENABLE_BT_EXTERNAL_FLASH_REQUEST; - boolean connect = mActivityState == FlashActivityState.STATE_ENABLE_BT_FOR_CONNECT; - if (requestCode == RequestCodes.REQUEST_ENABLE_BT) { if (resultCode == Activity.RESULT_OK) { - if (flash) { - proceedAfterBlePermissionGrantedAndBleEnabled(); - } -// else if (connect) { -// setActivityState(FlashActivityState.STATE_IDLE); -// toggleConnection(); -// } + proceedAfterBlePermissionGrantedAndBleEnabled(); } else if (resultCode == Activity.RESULT_CANCELED) { - setActivityState(FlashActivityState.STATE_IDLE); PopUp.show(getString(R.string.bluetooth_off_cannot_continue), //message "", R.drawable.error_face, R.drawable.red_btn, @@ -960,13 +1117,20 @@ private void proceedAfterBlePermissionGrantedAndBleEnabled() { * Checks for requisite state of a micro:bit board. If all is good then * initiates flashing. */ - ConnectedDevice currentMicrobit = BluetoothUtils.getPairedMicrobit(this); - if ( currentMicrobit.mPattern == null) { - goToPairingToPairBeforeFlash(); - return; + switch ( MBApp.getAppState().pairState()) + { + case PairStateNone: + case PairStateError: + //showPopupQuestionFlashToDevice( true); + goToPairingToPairBeforeFlash(); + break; + case PairStateLaunch: + case PairStateSession: + case PairStateChecked: + default: + flashingChecks( false); + break; } - - flashingChecks(); } /** @@ -1047,44 +1211,19 @@ public void onClick(View v) { } }); } - - /** - * Allows to enable or disable connection to a micro:bit board. - */ -// private void toggleConnection() { -// ConnectedDevice connectedDevice = BluetoothUtils.getPairedMicrobit(this); -// if(connectedDevice.mPattern != null) { -// if(connectedDevice.mStatus) { -// setActivityState(FlashActivityState.STATE_DISCONNECTING); -// PopUp.show(getString(R.string.disconnecting), -// "", -// R.drawable.flash_face, R.drawable.blue_btn, -// PopUp.GIFF_ANIMATION_NONE, -// PopUp.TYPE_SPINNER, -// null, null); -// ServiceUtils.sendConnectDisconnectMessage(false); -// } else { -// mRequestPermissions.clear(); -// setActivityState(FlashActivityState.STATE_CONNECTING); -// PopUp.show(getString(R.string.init_connection), -// "", -// R.drawable.flash_face, R.drawable.blue_btn, -// PopUp.GIFF_ANIMATION_NONE, -// PopUp.TYPE_SPINNER, -// null, null); -// -// ServiceUtils.sendConnectDisconnectMessage(true); -// } -// } -// } - + /** * Sends a project to flash on a micro:bit board. If bluetooth is off then turn it on. * * @param project Project to flash. */ public void sendProject(final Project project) { + if ( mPurpose != Purpose.PurposeIdle) { + showPopupBusy(); + return; + } mProgramToSend = project; + mPurpose = Purpose.PurposeSend; setActivityState(FlashActivityState.STATE_ENABLE_BT_INTERNAL_FLASH_REQUEST); startBluetoothForFlashing(); } @@ -1103,7 +1242,7 @@ public void onClick(final View v) { switch(v.getId()) { case R.id.createProject: scriptsPopup(); - break; + break; case R.id.backBtn: Intent intentHomeActivity = new Intent(this, HomeActivity.class); @@ -1111,26 +1250,42 @@ public void onClick(final View v) { startActivity(intentHomeActivity); finish(); break; -// -// case R.id.connectedIndicatorIcon: -// if(!BluetoothChecker.getInstance().isBluetoothON()) { -// setActivityState(FlashActivityState.STATE_ENABLE_BT_FOR_CONNECT); -// startBluetooth(); -// } else { -// toggleConnection(); -// } -// break; + case R.id.deviceName: goToPairingFromAppBarDeviceName(); break; + case R.id.viewProjectsPatternDifferent: + MBApp.getAppState().eventPairDifferent(); + onPatternIsDifferent(); + break; + + case R.id.viewProjectsPatternOK: + MBApp.getAppState().eventPairChecked(); + startFlashing(); + break; + + case R.id.viewProjectsPatternCancel: + onFlashComplete(); + break; + + case R.id.viewProjectsSearchingDifferent: + MBApp.getAppState().eventPairDifferent(); + displayShowSearchingDifferent( false); + if( service != null) { + Intent intent = new Intent(PartialFlashingBaseService.BROADCAST_ACTION); + intent.putExtra(PartialFlashingBaseService.EXTRA_ACTION, PartialFlashingBaseService.ACTION_ABORT); + LocalBroadcastManager.getInstance( MBApp.getApp()).sendBroadcast(intent); + } else { + onPatternIsDifferent(); + } + break; } } - private void flashingChecks() { - ConnectedDevice currentMicrobit = BluetoothUtils.getPairedMicrobit(MBApp.getApp()); - - if(currentMicrobit.mhardwareVersion != MICROBIT_V1 && currentMicrobit.mhardwareVersion != MICROBIT_V2 ) { + private void flashingChecks( boolean assumeAlreadyInBluetoothMode) { + int hardwareVersion = BluetoothUtils.getCurrentMicrobit(MBApp.getApp()).mhardwareVersion; + if( hardwareVersion != MICROBIT_V1 && hardwareVersion != MICROBIT_V2 ) { PopUp.show(getString(R.string.dfu_what_hardware_title), getString(R.string.dfu_what_hardware), R.drawable.error_face, R.drawable.red_btn, @@ -1139,17 +1294,13 @@ private void flashingChecks() { new View.OnClickListener() { @Override public void onClick(View v) { - ConnectedDevice temp = BluetoothUtils.getPairedMicrobit(MBApp.getApp()); - temp.mhardwareVersion = MICROBIT_V2; - BluetoothUtils.setPairedMicroBit(MBApp.getApp(), temp); + BluetoothUtils.setCurrentMicrobitHardwareVersion(MBApp.getApp(), MICROBIT_V2); PopUp.hide(); } },new View.OnClickListener() { @Override public void onClick(View v) { - ConnectedDevice temp = BluetoothUtils.getPairedMicrobit(MBApp.getApp()); - temp.mhardwareVersion = MICROBIT_V1; - BluetoothUtils.setPairedMicroBit(MBApp.getApp(), temp); + BluetoothUtils.setCurrentMicrobitHardwareVersion(MBApp.getApp(), MICROBIT_V1); PopUp.hide(); } } @@ -1167,46 +1318,44 @@ public void onClick(View v) { // return; // } - if(mActivityState == FlashActivityState.FLASH_STATE_FIND_DEVICE - || mActivityState == FlashActivityState.FLASH_STATE_VERIFY_DEVICE - || mActivityState == FlashActivityState.FLASH_STATE_WAIT_DEVICE_REBOOT - || mActivityState == FlashActivityState.FLASH_STATE_INIT_DEVICE - || mActivityState == FlashActivityState.FLASH_STATE_PROGRESS - - ) { - // Another download session is in progress.xml - PopUp.show(getString(R.string.multple_flashing_session_msg), - "", - R.drawable.flash_face, R.drawable.blue_btn, - PopUp.GIFF_ANIMATION_FLASH, - TYPE_ALERT, - popupClickFlashComplete, popupClickFlashComplete); + if ( activityStateIsFlashing()) { + showPopupBusy(); return; } - if(mActivityState == FlashActivityState.STATE_ENABLE_BT_INTERNAL_FLASH_REQUEST || - mActivityState == FlashActivityState.STATE_ENABLE_BT_EXTERNAL_FLASH_REQUEST) { - //Check final device from user and start flashing - PopUp.show(getString(R.string.flash_start_message, currentMicrobit.mName), //message - getString(R.string.flashing_title), //title - R.drawable.flash_face, R.drawable.blue_btn, //image icon res id - PopUp.GIFF_ANIMATION_NONE, - PopUp.TYPE_CHOICE, //type of popup. - new View.OnClickListener() { - @Override - public void onClick(View v) { - ConnectedDevice currentMicrobit = BluetoothUtils.getPairedMicrobit(MBApp.getApp()); - PopUp.hide(); - goToPairingResetToBLE(); - } - }, - popupClickFlashComplete); - } else { + if ( assumeAlreadyInBluetoothMode) { startFlashing(); + } else { + //showPopupQuestionFlashToDevice( false); + goToPairingResetToBLE(); } } + private void showPopupQuestionFlashToDevice( boolean goToPairing) { + String name = BluetoothUtils.getCurrentMicrobit(MBApp.getApp()).mName; + String message = getString(R.string.flash_start_message_pair); + if ( name != null) { + message = getString(R.string.flash_start_message, name); + } + PopUp.show( message, + getString(R.string.flashing_title), //title + R.drawable.flash_face, R.drawable.blue_btn, //image icon res id + PopUp.GIFF_ANIMATION_NONE, + PopUp.TYPE_CHOICE, //type of popup. + new View.OnClickListener() { + @Override + public void onClick(View v) { + PopUp.hide(); + if ( goToPairing) { + goToPairingToPairBeforeFlash(); + } else { + goToPairingResetToBLE(); + } + } + }, + popupClickFlashComplete); + } /** * Prepares for flashing process. @@ -1220,12 +1369,7 @@ protected void startFlashing() { setActivityState(FlashActivityState.FLASH_STATE_FIND_DEVICE); registerCallbacksForFlashing(); - PopUp.show(getString(R.string.dfu_status_starting_msg), - "", - R.drawable.flash_face, R.drawable.blue_btn, - PopUp.GIFF_ANIMATION_FLASH, - TYPE_SPINNER_NOT_CANCELABLE, - null, null); + displayScreen( Screen.ScreenSearch); new Thread( new Runnable() { @Override @@ -1234,16 +1378,23 @@ public void run() { runOnUiThread(new Runnable() { @Override public void run() { +// PopUp.show(getString(R.string.dfu_status_starting_msg), +// "", +// R.drawable.flash_face, R.drawable.blue_btn, +// PopUp.GIFF_ANIMATION_FLASH, +// TYPE_SPINNER_NOT_CANCELABLE, +// null, null); + switch (prepareToFlashResult) { case 0: startPartialFlash(); break; case 1: - PopUp.hide(); +// PopUp.hide(); popupHexNotCompatible(); break; case 2: - PopUp.hide(); +// PopUp.hide(); popupFailedToCreateFiles(); break; } @@ -1298,10 +1449,7 @@ protected int prepareToFlash() { m_MicroBitFirmware = "0.0"; m_HexFileSizeStats = getFileSize(mProgramToSend.filePath); - ConnectedDevice currentMicrobit = BluetoothUtils.getPairedMicrobit(this); - - MBApp application = MBApp.getApp(); - int hardwareType = currentMicrobit.mhardwareVersion; + int hardwareType = BluetoothUtils.getCurrentMicrobit(this).mhardwareVersion; // Create tmp hex for V1 or V2 // String[] oldret = universalHexToDFUOld(mProgramToSend.filePath, hardwareType); @@ -1340,9 +1488,14 @@ protected int prepareToFlash() { return 0; } - public void startDFUFlash() { + private void startDFUFlash() { logi("startDFUFlash"); PopUp.hide(); + + if ( !BluetoothUtils.getCurrentMicrobitIsValid(this)) { + return; // Invalid address causes crash + } + PopUp.show(getString(R.string.dfu_status_starting_msg), "", R.drawable.flash_face, R.drawable.blue_btn, @@ -1350,14 +1503,12 @@ public void startDFUFlash() { TYPE_SPINNER_NOT_CANCELABLE, null, null); - MBApp application = MBApp.getApp(); - ConnectedDevice currentMicrobit = BluetoothUtils.getPairedMicrobit(this); - int hardwareType = currentMicrobit.mhardwareVersion; + ConnectedDevice currentMicrobit = BluetoothUtils.getCurrentMicrobit(this); // Start DFU Service Log.v(TAG, "Start Full DFU"); Log.v(TAG, "DFU bin: " + getCachePathAppBin()); - if(hardwareType == MICROBIT_V2) { + if( currentMicrobit.mhardwareVersion == MICROBIT_V2) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { DfuServiceInitiator.createDfuNotificationChannel(this); } @@ -1390,19 +1541,33 @@ public void startDFUFlash() { protected void startPartialFlash() { logi("startPartialFlash"); + switch ( MBApp.getAppState().pairState()) + { + case PairStateNone: + case PairStateError: + case PairStateLaunch: + case PairStateSession: + goToPairingToPairBeforeFlashAlreadyReset(); + return; + case PairStateChecked: + default: + break; + } + MBApp application = MBApp.getApp(); - ConnectedDevice currentMicrobit = BluetoothUtils.getPairedMicrobit(this); - int hardwareType = currentMicrobit.mhardwareVersion; // Attempt a partial flash Log.v(TAG, "Send Partial Flashing Intent"); if(service != null) { application.stopService(service); } + + ConnectedDevice currentMicrobit = BluetoothUtils.getCurrentMicrobit(this); + service = new Intent(application, PartialFlashingService.class); service.putExtra("deviceAddress", currentMicrobit.mAddress); service.putExtra("filepath", getCachePathAppHex()); // a path or URI must be provided. - service.putExtra("hardwareType", hardwareType); // a path or URI must be provided. + service.putExtra("hardwareType", currentMicrobit.mhardwareVersion); service.putExtra("pf", true); // Enable partial flashing application.startService(service); logi("startPartialFlash End"); @@ -1786,6 +1951,8 @@ private void pfRegister() { pfFilter.addAction(PartialFlashingService.BROADCAST_PF_FAILED); pfFilter.addAction(PartialFlashingService.BROADCAST_PF_ATTEMPT_DFU); pfFilter.addAction(PartialFlashingService.BROADCAST_COMPLETE); + pfFilter.addAction(PartialFlashingService.BROADCAST_PF_ABORTED); + pfFilter.addAction(PartialFlashingService.BROADCAST_ERROR); LocalBroadcastManager.getInstance(MBApp.getApp()).registerReceiver(pfResultReceiver, pfFilter); pfRegistered = true; @@ -1895,6 +2062,7 @@ public void onReceive(Context context, Intent intent) { flashSuccess.putExtra(INTENT_EXTRA_TYPE, TYPE_ALERT); localBroadcastManager.sendBroadcast( flashSuccess ); } else if(intent.getAction().equals(PartialFlashingService.BROADCAST_START)) { + displayShowSearchingDifferent( false); // Display progress // Add click handler because BROADCAST_COMPLETE (above) makes this "Flash Complete" PopUp.show("", @@ -1906,20 +2074,61 @@ public void onReceive(Context context, Intent intent) { popupClickFlashComplete, popupClickFlashComplete); } else if(intent.getAction().equals(PartialFlashingService.BROADCAST_PF_ATTEMPT_DFU)) { Log.v(TAG, "Use Nordic DFU"); + displayShowSearchingDifferent( false); startDFUFlash(); } else if(intent.getAction().equals(PartialFlashingService.BROADCAST_PF_FAILED)) { - Log.v(TAG, "Partial flashing failed"); + MBApp.getAppState().eventPairSendError(); // If Partial Flashing Fails - DON'T ATTEMPT FULL DFU automatically // Set flag to avoid partial flash next time - PopUp.show(getString(R.string.could_not_connect), //message - getString(R.string.could_not_connect_title), + PopUp.show(getString(R.string.connection_lost) + "\n\n" + getString(R.string.retry), //message + getString(R.string.flashing_failed_title), R.drawable.error_face, R.drawable.red_btn, - PopUp.GIFF_ANIMATION_PAIRING, - TYPE_ALERT, //type of popup. - popupClickFlashComplete, popupClickFlashComplete); - } + PopUp.GIFF_ANIMATION_ERROR, + PopUp.TYPE_CHOICE, + new View.OnClickListener() { + @Override + public void onClick(View v) { + PopUp.hide(); + restartPurpose(); + } + }, popupClickFlashComplete); + } else if(intent.getAction().equals(PartialFlashingService.BROADCAST_ERROR)) { + MBApp.getAppState().eventPairSendError(); + final int errorCode = intent.getIntExtra(PartialFlashingService.EXTRA_DATA, 0); + String error_message = getString(R.string.connection_failed); + + switch (errorCode) { + case PartialFlashingService.ERROR_CONNECT: + error_message = getString(R.string.connection_failed); + break; + case PartialFlashingService.ERROR_RECONNECT: + error_message = getString(R.string.reconnection_failed); + break; + case PartialFlashingService.ERROR_DFU_MODE: + error_message = getString(R.string.reset_to_dfu_mode_failed); + break; + } + + logi("PFResultReceiver.onReceive() :: " + error_message + " code " + errorCode); + PopUp.show( error_message + "\n\n" + getString(R.string.retry), + getString(R.string.flashing_failed_title), + R.drawable.message_face, R.drawable.red_btn, + PopUp.GIFF_ANIMATION_ERROR, + PopUp.TYPE_CHOICE, + new View.OnClickListener() { + @Override + public void onClick(View v) { + PopUp.hide(); + restartPurpose(); + } + }, popupClickFlashComplete); + } else if(intent.getAction().equals(PartialFlashingService.BROADCAST_PF_ABORTED)) { + Log.v(TAG, "Partial flashing aborted"); + // Currently, only button viewProjectsSearchingDifferent triggers abort + onPatternIsDifferent(); + } } } @@ -1979,8 +2188,6 @@ public void onClick(View v) { break; case DfuService.PROGRESS_COMPLETED: if (!isCompleted) { - setActivityState(FlashActivityState.STATE_IDLE); - MBApp application = MBApp.getApp(); dfuUnregister(); @@ -2101,8 +2308,7 @@ public void onClick(View v) { break; */ case DfuService.PROGRESS_ABORTED: - setActivityState(FlashActivityState.STATE_IDLE); - + MBApp.getAppState().eventPairSendError(); MBApp application = MBApp.getApp(); dfuUnregister(); @@ -2175,25 +2381,35 @@ public void onClick(View v) { } } } else if(intent.getAction().equals(DfuService.BROADCAST_ERROR)) { - int errorCode = intent.getIntExtra(DfuService.EXTRA_DATA, 0); - -// // REMOVE tryToConnectAgain -// if(errorCode == DfuService.ERROR_FILE_INVALID) { -// notAValidFlashHexFile = true; -// } - - String error_message = GattError.parse(errorCode); - - if(errorCode == DfuService.ERROR_FILE_INVALID) { - error_message += getString(R.string.reset_microbit_because_of_hex_file_wrong); + MBApp.getAppState().eventPairSendError(); + final int errorCode = intent.getIntExtra(DfuBaseService.EXTRA_DATA, 0); + final int errorType = intent.getIntExtra(DfuBaseService.EXTRA_ERROR_TYPE, 0); + String error_message = ""; + + switch (errorType) { + case DfuBaseService.ERROR_TYPE_COMMUNICATION_STATE: + if ( errorCode == 0x0085) { + error_message = getString(R.string.not_found); + } else { + error_message = GattError.parseConnectionError(errorCode); + } + error_message = getString(R.string.connection_error_CODE, error_message); + break; + case DfuBaseService.ERROR_TYPE_DFU_REMOTE: + error_message = GattError.parseDfuRemoteError( errorCode); + error_message = getString(R.string.dfu_error_CODE, error_message); + break; + default: + if ( errorCode == 0) { + error_message = getString(R.string.not_found); + } else { + error_message = GattError.parse(errorCode); + } + error_message = getString(R.string.communication_error_CODE, error_message); + break; } - logi("DFUResultReceiver.onReceive() :: Flashing ERROR!! Code - [" + intent.getIntExtra(DfuService.EXTRA_DATA, 0) - + "] Error Type - [" + intent.getIntExtra(DfuService.EXTRA_ERROR_TYPE, 0) + "]"); - - setActivityState(FlashActivityState.STATE_IDLE); - - MBApp application = MBApp.getApp(); + logi("DFUResultReceiver.onReceive() :: " + error_message + " type " + + errorType + " code " + errorCode); dfuUnregister(); // removeReconnectionRunnable(); // REMOVE tryToConnectAgain @@ -2205,28 +2421,18 @@ public void onClick(View v) { m_BinSizeStats, m_MicroBitFirmware); */ - //Check for GATT ERROR - prompt user to enter bluetooth mode - if(errorCode == 0x0085) { - PopUp.show(getString(R.string.connect_tip_text), - "Remember to enter bluetooth mode", - R.drawable.message_face, R.drawable.red_btn, - PopUp.GIFF_ANIMATION_PAIRING, - PopUp.TYPE_CHOICE, - new View.OnClickListener() { - @Override - public void onClick(View v) { - PopUp.hide(); - flashingChecks(); - } - }, popupClickFlashComplete); - } else { - PopUp.show(error_message + "\n\n" + getString(R.string.connect_tip_text), //message - getString(R.string.flashing_failed_title), //title - R.drawable.error_face, R.drawable.red_btn, - PopUp.GIFF_ANIMATION_ERROR, - TYPE_ALERT, //type of popup. - popupClickFlashComplete, popupClickFlashComplete); - } + PopUp.show( error_message + "\n\n" + getString(R.string.retry), + getString(R.string.flashing_failed_title), + R.drawable.message_face, R.drawable.red_btn, + PopUp.GIFF_ANIMATION_ERROR, + PopUp.TYPE_CHOICE, + new View.OnClickListener() { + @Override + public void onClick(View v) { + PopUp.hide(); + restartPurpose(); + } + }, popupClickFlashComplete); } else if(intent.getAction().equals(DfuService.BROADCAST_LOG)) { //Only used for Stats at the moment String data; @@ -2267,11 +2473,11 @@ public boolean onCreateOptionsMenu(Menu menu) { private void scriptsPopup() { PopupMenu popupMenu = new PopupMenu( this, findViewById(R.id.createProject)); int itemID = Menu.FIRST; - popupMenu.getMenu().add( 0, itemID, 0, "Create Code"); + popupMenu.getMenu().add( 0, itemID, 0, R.string.create_code); itemID++; - popupMenu.getMenu().add( 0, itemID, 1, "Import"); + popupMenu.getMenu().add( 0, itemID, 1, R.string.menu_import); itemID++; - popupMenu.getMenu().add( 0, itemID, 2, "Export"); + popupMenu.getMenu().add( 0, itemID, 2, R.string.menu_export); itemID++; popupMenu.setOnMenuItemClickListener( new PopupMenu.OnMenuItemClickListener() { diff --git a/app/src/main/java/com/samsung/microbit/ui/view/PatternDrawable.java b/app/src/main/java/com/samsung/microbit/ui/view/PatternDrawable.java new file mode 100644 index 00000000..341059c0 --- /dev/null +++ b/app/src/main/java/com/samsung/microbit/ui/view/PatternDrawable.java @@ -0,0 +1,120 @@ +package com.samsung.microbit.ui.view; + +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; + +public class PatternDrawable extends Drawable { + private final Paint paintOffLine; + private final Paint paintOffFill; + private final Paint paintOnLine; + private final Paint paintOnFill; + public int [] mPattern = new int [5]; + + public void setDeviceName( String name) { + for ( int col = 0; col < 5; col++) { + mPattern[col] = -1; + if ( col < name.length()) { + String s = ( col % 2) != 0 ? "AEIOU" : "TPGVZ"; + String c = name.substring(col, col + 1); + int idx = s.indexOf( c); + if ( idx < 5) { + mPattern[col] = 5 - idx; + } + } + + } + } + + public PatternDrawable() { + // Set up color and text size + paintOffLine = new Paint(); + paintOffFill = new Paint(); + paintOnLine = new Paint(); + paintOnFill = new Paint(); + + paintOffLine.setARGB(255, 85, 85, 85); + paintOffFill.setARGB(255, 217, 217, 217); + paintOnLine.setARGB(255, 0xfc, 0xee, 0x21); + paintOnFill.setARGB(255, 255, 0, 0); + + paintOffFill.setStyle(Paint.Style.FILL); + paintOnFill.setStyle(Paint.Style.FILL); + + paintOffLine.setStyle(Paint.Style.STROKE); + paintOnLine.setStyle(Paint.Style.STROKE); + + paintOffLine.setStrokeWidth(10); + paintOnLine.setStrokeWidth(10); + } + + @Override + public void setAlpha(int alpha) { + // This method is required + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + // This method is required + } + + @Override + public int getOpacity() { + // Must be PixelFormat.UNKNOWN, TRANSLUCENT, TRANSPARENT, or OPAQUE + return PixelFormat.OPAQUE; + } + + @Override + public void draw(Canvas canvas) { + // Get the drawable's bounds + int width = getBounds().width(); + int height = getBounds().height(); + + int x0 = 0; + int y0 = 0; + if ( width > height) { + x0 = ( width - height) / 2; + width = height; + } else { + y0 = ( height - width) / 2; + height = width; + } + + int w = width / 20; + int h = height / 20; + if ( w < 1) w = 1; + if ( h < 1) w = 1; + int w2 = w * 2; + int h2 = h * 2; + int w4 = w * 4; + int h4 = h * 4; + int w0 = ( width - 5 * w4) / 2; + int h0 = ( height - 5 * h4) / 2; + + int linewidth = w2 < h2 ? w2 / 10 : h2 / 10; + if ( linewidth < 1) linewidth = 1; + + paintOffLine.setStrokeWidth(linewidth); + paintOnLine.setStrokeWidth(linewidth); + + for ( int col = 0; col < 5; col++) + { + for ( int row = 0; row < 5; row++) + { + int left = x0 + w0 + col * w4 + w; + int top = y0 + h0 + row * h4 + h; + RectF rect = new RectF(left, top, left + w2, top + h2); + if ( row >= 5 - mPattern[col]) { + canvas.drawRect( rect, paintOnFill); + canvas.drawRect( rect, paintOnLine); + } else { + canvas.drawRect( rect, paintOffFill); + canvas.drawRect( rect, paintOffLine); + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/samsung/microbit/utils/BLEConnectionHandler.java b/app/src/main/java/com/samsung/microbit/utils/BLEConnectionHandler.java index cade4238..6a869cc0 100644 --- a/app/src/main/java/com/samsung/microbit/utils/BLEConnectionHandler.java +++ b/app/src/main/java/com/samsung/microbit/utils/BLEConnectionHandler.java @@ -36,7 +36,7 @@ public void onReceive(Context context, Intent intent) { bleConnectionManager.preUpdateUi(); //setConnectedDeviceText(); if(firmware != null && !firmware.isEmpty()) { - BluetoothUtils.updateFirmwareMicrobit(context, firmware); + BluetoothUtils.setCurrentMicrobitFirmware(context, firmware); return; } @@ -51,10 +51,9 @@ public void onReceive(Context context, Intent intent) { bleConnectionManager.addPermissionRequest(getNotification); return; } - ConnectedDevice device = BluetoothUtils.getPairedMicrobit(context); if(mActivityState == BaseActivityState.STATE_CONNECTING) { if(error == 0) { - BluetoothUtils.updateConnectionStartTime(context, System.currentTimeMillis()); + BluetoothUtils.setCurrentMicrobitConnectionStartTime(context, System.currentTimeMillis()); //Check if more permissions were needed and request in the Application if(!bleConnectionManager.arePermissionsGranted()) { bleConnectionManager.setActivityState(BaseActivityState.STATE_IDLE); @@ -67,7 +66,7 @@ public void onReceive(Context context, Intent intent) { } if(error == 0 && mActivityState == BaseActivityState.STATE_DISCONNECTING) { long now = System.currentTimeMillis(); - long connectionTime = (now - device.mlast_connection_time) / 1000; //Time in seconds + long connectionTime = (now - BluetoothUtils.getCurrentMicrobit(context).mlast_connection_time) / 1000; //Time in seconds } bleConnectionManager.setActivityState(BaseActivityState.STATE_IDLE); diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml index f505e16e..7d35cb7a 100644 --- a/app/src/main/res/layout-land/activity_main.xml +++ b/app/src/main/res/layout-land/activity_main.xml @@ -25,7 +25,7 @@ android:layout_margin="@dimen/main_activity_gif_image_margin" android:contentDescription="@string/desc_homescreen_logo_img" android:foregroundGravity="center" - android:nextFocusDown="@+id/connect_device_btn" + android:nextFocusDown="@+id/create_code_btn" android:scrollbars="none" /> @@ -37,14 +37,14 @@ android:layout_marginBottom="@dimen/buttons_layout_margin" android:layout_marginEnd="@dimen/buttons_layout_margin" android:layout_marginStart="@dimen/buttons_layout_margin"> - +