Skip to content

Commit

Permalink
Protect external activities (#78)
Browse files Browse the repository at this point in the history
* Protect against external activity failure
* change popups to toasts
* modify debug code
* ignore resolveActivity
  • Loading branch information
martinwork authored Sep 25, 2024
1 parent cf250cb commit d1a49f7
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 55 deletions.
6 changes: 6 additions & 0 deletions app/src/main/java/com/samsung/microbit/ui/FetchPopups.java
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
92 changes: 92 additions & 0 deletions app/src/main/java/com/samsung/microbit/ui/UIUtils.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}

/**
Expand Down Expand Up @@ -938,16 +945,7 @@ public void onPageFinished(WebView view, String url) {
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> 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

Expand Down Expand Up @@ -981,6 +979,21 @@ public void onDownloadBase64( String base64, String mimetype) {
}
}

private boolean showFileChooser(WebView webView, ValueCallback<Uri[]> 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() {"
Expand Down Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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]
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -135,15 +136,7 @@ public void onPageFinished (WebView view, String url) {
webView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> 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
Expand Down Expand Up @@ -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) {
Expand All @@ -268,6 +261,23 @@ else if ( !hexName.isEmpty()) {
} // onCreate


private boolean showFileChooser(WebView webView, ValueCallback<Uri[]> 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);
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand Down
Loading

0 comments on commit d1a49f7

Please sign in to comment.