diff --git a/app/src/main/java/com/samsung/microbit/ui/FetchPopups.java b/app/src/main/java/com/samsung/microbit/ui/FetchPopups.java index 03b0649..5c1212b 100644 --- a/app/src/main/java/com/samsung/microbit/ui/FetchPopups.java +++ b/app/src/main/java/com/samsung/microbit/ui/FetchPopups.java @@ -59,6 +59,12 @@ public void bluetoothOff() { popupClickActivityCancelled, popupClickActivityCancelled); } + public void bluetoothEnableRestricted() { + UIUtils.safelyStartActivityToast( mClient.fetchPopupsContext(), + mClient.fetchPopupsContext().getString(R.string.unable_to_start_activity_to_enable_bluetooth)); + mClient.fetchPopupsCancelled(); + } + public void bluetoothConnectPermissionError() { PopUp.show(mClient.fetchPopupsContext().getString(R.string.ble_permission_connect_error), mClient.fetchPopupsContext().getString(R.string.permissions_needed_title), diff --git a/app/src/main/java/com/samsung/microbit/ui/UIUtils.java b/app/src/main/java/com/samsung/microbit/ui/UIUtils.java index a85a129..05f9ea0 100644 --- a/app/src/main/java/com/samsung/microbit/ui/UIUtils.java +++ b/app/src/main/java/com/samsung/microbit/ui/UIUtils.java @@ -1,10 +1,16 @@ package com.samsung.microbit.ui; import android.app.Activity; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; import android.graphics.Point; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Bundle; import android.util.Log; import android.util.TypedValue; import android.view.View; @@ -13,6 +19,7 @@ import android.widget.Button; import android.widget.ImageButton; import android.widget.TextView; +import android.widget.Toast; import com.samsung.microbit.R; @@ -271,4 +278,89 @@ public void gifAnimate( @IdRes int id) { view.animate(); } } + + public static void safelyStartActivityToast( Context context, String message, String title) { + Toast.makeText( context, title + ".\n" + message, Toast.LENGTH_LONG).show(); + } + + public static void safelyStartActivityToast( Context context, String title) { + safelyStartActivityToast( context, context.getString(R.string.this_device_may_have_restrictions_in_place), title); + } + + public static void safelyStartActivityToastGeneric( Context context) { + safelyStartActivityToast( context, context.getString(R.string.unable_to_start_activity)); + } + + public static void safelyStartActivityToastOpenLink( Context context) { + safelyStartActivityToast( context, context.getString(R.string.unable_to_open_link)); + } + +// public static boolean safelyStartActivityDebugFail = false; + + // Wrap startActivity and startActivityForResult + // Return non-zero error on fail + // When startActivityForResult fails, the caller likely + // needs to add code similar to the cancel case in onActivityResult + public static int safelyStartActivity( Context context, boolean report, Intent intent, + boolean forResult, int requestCode, Bundle options) { +// if ( safelyStartActivityDebugFail) { +// if (report) { +// safelyStartActivityToastGeneric(context); +// } +// return 4; +// } + + int error = 0; + + try { + if ( forResult) { + if ( !(context instanceof Activity)) { + error = 3; + } else { + ((Activity) context).startActivityForResult(intent, requestCode, options); + } + } else { + context.startActivity(intent); + } + } catch (Exception e) { + Log.i(TAG, "startActivity - exception"); + e.printStackTrace(); + error = 2; + } + + if ( report && error != 0) { + safelyStartActivityToastGeneric( context); + } + return error; + } + + public static int safelyStartActivity(Context context, boolean report, Intent intent, Bundle options) { + return UIUtils.safelyStartActivity( context, report, intent, false, 0, options); + } + + public static int safelyStartActivity(Context context, boolean report, Intent intent) { + return UIUtils.safelyStartActivity( context, report, intent, null); + } + + public static int safelyStartActivityForResult(Activity activity, boolean report, Intent intent, int requestCode, Bundle options) { + return UIUtils.safelyStartActivity( activity, report, intent, true, requestCode, options); + } + + public static int safelyStartActivityForResult(Activity activity, boolean report, Intent intent, int requestCode) { + return UIUtils.safelyStartActivityForResult( activity, report, intent, requestCode, null); + } + + public static int safelyStartActivityViewURI( Context context, boolean report, Uri uri) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData( uri); + int error = UIUtils.safelyStartActivity( context, false, intent); + if ( report && error != 0) { + safelyStartActivityToastOpenLink( context); + } + return error; + } + + public static int safelyStartActivityViewURL( Context context, boolean report, String url) { + return UIUtils.safelyStartActivityViewURI( context, report, Uri.parse( url)); + } } diff --git a/app/src/main/java/com/samsung/microbit/ui/activity/FetchActivity.java b/app/src/main/java/com/samsung/microbit/ui/activity/FetchActivity.java index 26e28b4..9a01d7c 100644 --- a/app/src/main/java/com/samsung/microbit/ui/activity/FetchActivity.java +++ b/app/src/main/java/com/samsung/microbit/ui/activity/FetchActivity.java @@ -360,6 +360,14 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } dataToSave = null; break; + case REQUEST_CODE_CHOOSE_FILE: + if ( resultCode != RESULT_OK) { + mWebFileChooserCallback.onReceiveValue( null); + return; + } + Uri[] uris = WebChromeClient.FileChooserParams.parseResult ( resultCode, data); + mWebFileChooserCallback.onReceiveValue( uris); + break; } } @@ -468,9 +476,7 @@ public void onClick(final View v) { break; case R.id.fetchSelectDuringMore: - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(getString(R.string.fetchDuringFindOutMoreUrl))); - startActivity(intent); + UIUtils.safelyStartActivityViewURL( this, true, getString(R.string.fetchDuringFindOutMoreUrl)); break; } } @@ -675,7 +681,10 @@ private MBAppState.PairState pairState() { @SuppressLint("MissingPermission") private void enableBluetooth() { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); - startActivityForResult(enableBtIntent, RequestCodes.REQUEST_ENABLE_BT); + int error = UIUtils.safelyStartActivityForResult( this, false, enableBtIntent, RequestCodes.REQUEST_ENABLE_BT); + if ( error != 0) { + mPopups.bluetoothEnableRestricted(); + } } private boolean havePermission(String permission) { @@ -869,9 +878,7 @@ private void displayUpdateDeviceName() { private void openURL( String url) { logi( "openURL: " + url); - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse( url)); - startActivity(intent); + UIUtils.safelyStartActivityViewURL( this, true, url); } /** @@ -938,16 +945,7 @@ public void onPageFinished(WebView view, String url) { mWebView.setWebChromeClient(new WebChromeClient() { @Override public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { - mWebFileChooserCallback = filePathCallback; - try { - Intent intent = fileChooserParams.createIntent(); - startActivityForResult(intent, REQUEST_CODE_CHOOSE_FILE); - } catch (Exception e) { - e.printStackTrace(); - return false; - } - return true; - + return showFileChooser( webView, filePathCallback, fileChooserParams); } }); //setWebChromeClient @@ -981,6 +979,21 @@ public void onDownloadBase64( String base64, String mimetype) { } } + private boolean showFileChooser(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { + mWebFileChooserCallback = filePathCallback; + try { + Intent intent = fileChooserParams.createIntent(); + int error = UIUtils.safelyStartActivityForResult( this, true, intent, REQUEST_CODE_CHOOSE_FILE); + if ( error != 0) { + mWebFileChooserCallback.onReceiveValue( null); + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + } + private void onDownloadBlob( String blob) { String js = "javascript:(" + "function f() {" @@ -1032,7 +1045,10 @@ private void saveData( String name, String mimetype, byte[] data) { intent.setType( mimetype); intent.putExtra(Intent.EXTRA_TITLE, name); dataToSave = data; - startActivityForResult( intent, REQUEST_CODE_SAVEDATA); + int error = UIUtils.safelyStartActivityForResult( this, true, intent, REQUEST_CODE_SAVEDATA); + if ( error != 0) { + dataToSave = null; + } } private String displayHtmlGetPath() { diff --git a/app/src/main/java/com/samsung/microbit/ui/activity/HomeActivity.java b/app/src/main/java/com/samsung/microbit/ui/activity/HomeActivity.java index 43e221c..60881ee 100644 --- a/app/src/main/java/com/samsung/microbit/ui/activity/HomeActivity.java +++ b/app/src/main/java/com/samsung/microbit/ui/activity/HomeActivity.java @@ -42,6 +42,7 @@ import com.samsung.microbit.data.model.ConnectedDevice; import com.samsung.microbit.service.IPCService; import com.samsung.microbit.ui.PopUp; +import com.samsung.microbit.ui.UIUtils; import com.samsung.microbit.utils.FileUtils; import com.samsung.microbit.utils.ProjectsHelper; import com.samsung.microbit.utils.Utils; @@ -393,9 +394,7 @@ public void onClick(final View v) { startActivity(i); break; case R.id.discover_btn: - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(getString(R.string.discover_url))); - startActivity(intent); + UIUtils.safelyStartActivityViewURL( this, true, getString(R.string.discover_url)); break; // TODO: HACK - Navigation View items from drawer here instead of [onNavigationItemSelected] @@ -406,9 +405,7 @@ public void onClick(final View v) { } break; case R.id.btn_about: { - Intent aboutIntent = new Intent(Intent.ACTION_VIEW); - aboutIntent.setData(Uri.parse(getString(R.string.about_url))); - startActivity(aboutIntent); + UIUtils.safelyStartActivityViewURL( this, true, getString(R.string.about_url)); // Close drawer drawer.closeDrawer(GravityCompat.START); } @@ -422,19 +419,13 @@ public void onClick(final View v) { } break; case R.id.btn_privacy_cookies: { - - Intent privacyIntent = new Intent(Intent.ACTION_VIEW); - privacyIntent.setData(Uri.parse(getString(R.string.privacy_policy_url))); - startActivity(privacyIntent); + UIUtils.safelyStartActivityViewURL( this, true, getString(R.string.privacy_policy_url)); // Close drawer drawer.closeDrawer(GravityCompat.START); } break; case R.id.btn_terms_conditions: { - - Intent termsIntent = new Intent(Intent.ACTION_VIEW); - termsIntent.setData(Uri.parse(getString(R.string.terms_of_use_url))); - startActivity(termsIntent); + UIUtils.safelyStartActivityViewURL( this, true, getString(R.string.terms_of_use_url)); // Close drawer drawer.closeDrawer(GravityCompat.START); } @@ -449,7 +440,7 @@ public void onClick(final View v) { String body = prepareEmailBody(); feedbackIntent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(body)); Intent mailer = Intent.createChooser(feedbackIntent, null); - startActivity(mailer); + UIUtils.safelyStartActivity( this, true, mailer); // Close drawer if(drawer != null) { drawer.closeDrawer(GravityCompat.START); 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 51023d6..a995861 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 @@ -22,6 +22,7 @@ import com.samsung.microbit.BuildConfig; import com.samsung.microbit.MBApp; import com.samsung.microbit.R; +import com.samsung.microbit.ui.UIUtils; import com.samsung.microbit.utils.FileUtils; import com.samsung.microbit.utils.ProjectsHelper; @@ -135,15 +136,7 @@ public void onPageFinished (WebView view, String url) { webView.setWebChromeClient(new WebChromeClient() { @Override public boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { - onShowFileChooser_filePathCallback = filePathCallback; - try { - Intent intent = fileChooserParams.createIntent(); - startActivityForResult(intent, REQUEST_CODE_CHOOSE_FILE); - } catch (Exception e) { - e.printStackTrace(); - return false; - } - return true; + return showFileChooser( webView, filePathCallback, fileChooserParams); } }); //setWebChromeClient @@ -243,7 +236,7 @@ else if ( !hexName.isEmpty()) { openProjectActivity( hexToWrite); } else { Toast.makeText( MakeCodeWebView.this, - "Saved to FLASH page", Toast.LENGTH_LONG).show(); + "Saved to My Programs page", Toast.LENGTH_LONG).show(); } } } catch ( Exception e) { @@ -268,6 +261,23 @@ else if ( !hexName.isEmpty()) { } // onCreate + private boolean showFileChooser(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams) { + onShowFileChooser_filePathCallback = filePathCallback; + try { + Intent intent = fileChooserParams.createIntent(); + int error = UIUtils.safelyStartActivityForResult( this, true, intent, REQUEST_CODE_CHOOSE_FILE); + if ( error != 0) { + onShowFileChooser_filePathCallback.onReceiveValue( null); + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + return true; + + } + + private boolean overrideUri( final Uri uri) { String url = uri.toString().toLowerCase(); Log.v(TAG, "overrideUri: " + url); @@ -333,9 +343,7 @@ else if ( host.equals( "github.com")) { void openUri( Uri uri) { Log.v(TAG, "openUri: " + uri); - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData( uri); - startActivity(intent); + UIUtils.safelyStartActivityViewURI( this, true, uri); } private void saveData( String name, String mimetype, byte[] data) { @@ -344,7 +352,10 @@ private void saveData( String name, String mimetype, byte[] data) { intent.setType( mimetype); intent.putExtra(Intent.EXTRA_TITLE, name); dataToSave = data; - startActivityForResult( intent, REQUEST_CODE_SAVEDATA); + int error = UIUtils.safelyStartActivityForResult( this, true, intent, REQUEST_CODE_SAVEDATA); + if ( error != 0) { + dataToSave = null; + } } @Override 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 6754ff3..f37bc12 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 @@ -50,6 +50,7 @@ import com.samsung.microbit.service.BLEService; import com.samsung.microbit.ui.BluetoothChecker; import com.samsung.microbit.ui.PopUp; +import com.samsung.microbit.ui.UIUtils; import com.samsung.microbit.ui.adapter.LEDAdapter; import com.samsung.microbit.utils.BLEConnectionHandler; import com.samsung.microbit.utils.Utils; @@ -1200,7 +1201,13 @@ private void displayScreenTripleOrStep1( int resIdGif, int resIdPrompt) */ private void enableBluetooth() { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); - startActivityForResult(enableBtIntent, RequestCodes.REQUEST_ENABLE_BT); + int error = UIUtils.safelyStartActivityForResult( this, false, enableBtIntent, RequestCodes.REQUEST_ENABLE_BT); + if ( error != 0) { + //Change state back to Idle + setActivityState(PairingActivityState.STATE_IDLE); + UIUtils.safelyStartActivityToast( this, getString(R.string.unable_to_start_activity_to_enable_bluetooth)); + onFinish( RESULT_CANCELED); + } } private void enableLocation() { @@ -1212,9 +1219,7 @@ private void enableLocation() { @Override public void onClick(View v) { PopUp.hide(); - //Unpair the device for secure BLE - Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); - startActivityForResult( intent, RequestCodes.REQUEST_ENABLE_LOCATION); + enableLocationOK(); } },//override click listener for ok button new View.OnClickListener() { @@ -1227,6 +1232,15 @@ public void onClick(View v) { }); } + private void enableLocationOK() { + Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); + int error = UIUtils.safelyStartActivityForResult( this, false, intent, RequestCodes.REQUEST_ENABLE_LOCATION); + if ( error != 0) { + setActivityState(PairingActivityState.STATE_IDLE); + popupLocationRestricted(); + } + } + public void popupLocationNeeded() { PopUp.show("Cannot continue without enabling location", //message "", @@ -1236,6 +1250,12 @@ public void popupLocationNeeded() { failedPermissionHandler, failedPermissionHandler); } + public void popupLocationRestricted() { + UIUtils.safelyStartActivityToast( this, + getString(R.string.unable_to_start_activity_to_enable_location_services)); + onFinish( RESULT_CANCELED); + } + @Override public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) { 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 3fce191..2b1dd6d 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 @@ -52,6 +52,7 @@ import com.samsung.microbit.service.PartialFlashingService; import com.samsung.microbit.ui.BluetoothChecker; import com.samsung.microbit.ui.PopUp; +import com.samsung.microbit.ui.UIUtils; import com.samsung.microbit.ui.adapter.ProjectAdapter; import com.samsung.microbit.ui.view.PatternDrawable; import com.samsung.microbit.utils.BLEConnectionHandler; @@ -1084,7 +1085,12 @@ private void proceedAfterBlePermissionGrantedAndBleEnabled() { @SuppressLint("MissingPermission") private void enableBluetooth() { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); - startActivityForResult(enableBtIntent, RequestCodes.REQUEST_ENABLE_BT); + int error = UIUtils.safelyStartActivityForResult( this, false, enableBtIntent, RequestCodes.REQUEST_ENABLE_BT); + if ( error != 0) { + UIUtils.safelyStartActivityToast( this, + getString(R.string.unable_to_start_activity_to_enable_bluetooth)); + onFlashComplete(); + } } private boolean havePermission(String permission) { @@ -2462,7 +2468,9 @@ private void scriptsImport() { intent.addCategory(Intent.CATEGORY_OPENABLE); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); intent.setType("application/octet-stream"); - startActivityForResult( Intent.createChooser(intent, messageTitle), REQUEST_CODE_IMPORT); + int error = UIUtils.safelyStartActivityForResult( this, true, Intent.createChooser(intent, messageTitle), REQUEST_CODE_IMPORT); + if ( error != 0) { + } } protected void onActivityResultScriptsImport(int requestCode, int resultCode, Intent data) { @@ -2482,7 +2490,9 @@ private void scriptsExport() { intent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); intent.setType( mimetype); intent.putExtra(Intent.EXTRA_TITLE, name); - startActivityForResult( Intent.createChooser(intent, messageTitle), REQUEST_CODE_EXPORT); + int error = UIUtils.safelyStartActivityForResult( this, true, Intent.createChooser(intent, messageTitle), REQUEST_CODE_EXPORT); + if ( error != 0) { + } } protected void onActivityResultScriptsExport(int requestCode, int resultCode, Intent data) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5e6708a..c40d535 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -426,5 +426,9 @@ Out of memory Failed to create MY_DATA.HTM Works with micro:bit V2 only + "This device may be restricted." + "Unable to turn on Bluetooth" + "Unable to turn on Location" + "Unable to start external activity" + "Unable to open link" -