Bug 1173147 - Show prompt for GeckoAppShell.openUriExternal. r=sebastian

--HG--
extra : commitid : KRygkmIjsVz
extra : rebase_source : 1cdc9062847fcd133d06650cf15fa91bd5f3b314
This commit is contained in:
Michael Comella 2015-09-18 17:21:07 -07:00
Родитель e64ae0a462
Коммит 4a83ff024d
7 изменённых файлов: 69 добавлений и 22 удалений

Просмотреть файл

@ -8,7 +8,10 @@ import org.mozilla.gecko.util.ActivityResultHandler;
import org.mozilla.gecko.util.ActivityResultHandlerMap;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class ActivityHandlerHelper {
private static final String LOGTAG = "GeckoActivityHandlerHelper";
@ -22,6 +25,26 @@ public class ActivityHandlerHelper {
startIntentForActivity(GeckoAppShell.getGeckoInterface().getActivity(), intent, activityResultHandler);
}
/**
* Starts the Activity, catching & logging if the Activity fails to start.
*
* We catch to prevent callers from passing in invalid Intents and crashing the browser.
*
* @return true if the Activity is successfully started, false otherwise.
*/
public static boolean startIntentAndCatch(final String logtag, final Context context, final Intent intent) {
try {
context.startActivity(intent);
return true;
} catch (final ActivityNotFoundException e) {
Log.w(logtag, "Activity not found.", e);
return false;
} catch (final SecurityException e) {
Log.w(logtag, "Forbidden to launch activity.", e);
return false;
}
}
public static void startIntentForActivity(Activity activity, Intent intent, ActivityResultHandler activityResultHandler) {
activity.startActivityForResult(intent, mActivityResultHandlerMap.put(activityResultHandler));
}

Просмотреть файл

@ -1542,7 +1542,7 @@ public class BrowserApp extends GeckoApp
}
GeckoAppShell.openUriExternal(url, "text/plain", "", "",
Intent.ACTION_SEND, tab.getDisplayTitle());
Intent.ACTION_SEND, tab.getDisplayTitle(), false);
// Context: Sharing via chrome list (no explicit session is active)
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);
@ -1783,7 +1783,7 @@ public class BrowserApp extends GeckoApp
} else if ("Reader:Share".equals(event)) {
final String title = message.getString("title");
final String url = message.getString("url");
GeckoAppShell.openUriExternal(url, "text/plain", "", "", Intent.ACTION_SEND, title);
GeckoAppShell.openUriExternal(url, "text/plain", "", "", Intent.ACTION_SEND, title, false);
} else if ("Sanitize:ClearHistory".equals(event)) {
handleClearHistory(message.optBoolean("clearSearchHistory", false));
callback.sendSuccess(true);

Просмотреть файл

@ -639,7 +639,7 @@ public abstract class GeckoApp
final String url = ReaderModeUtils.stripAboutReaderUrl(tab.getURL());
text += "\n\n" + url;
}
GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, title);
GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, title, false);
// Context: Sharing via chrome list (no explicit session is active)
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);

Просмотреть файл

@ -55,13 +55,13 @@ import org.mozilla.gecko.util.NativeJSContainer;
import org.mozilla.gecko.util.NativeJSObject;
import org.mozilla.gecko.util.ProxySelector;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.widget.ExternalIntentDuringPrivateBrowsingPromptFragment;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -106,6 +106,7 @@ import android.os.SystemClock;
import android.os.Vibrator;
import android.provider.Browser;
import android.provider.Settings;
import android.support.v4.app.FragmentActivity;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Base64;
@ -1049,6 +1050,17 @@ public class GeckoAppShell
return true;
}
@WrapForJNI
public static boolean openUriExternal(String targetURI,
String mimeType,
String packageName,
String className,
String action,
String title) {
// Default to showing prompt in private browsing to be safe.
return openUriExternal(targetURI, mimeType, packageName, className, action, title, true);
}
/**
* Given the inputs to <code>getOpenURIIntent</code>, plus an optional
* package name and class name, create and fire an intent to open the
@ -1062,15 +1074,20 @@ public class GeckoAppShell
* @param action an Android action specifier, such as
* <code>Intent.ACTION_SEND</code>.
* @param title the title to use in <code>ACTION_SEND</code> intents.
* @return true if the activity started successfully; false otherwise.
* @param showPromptInPrivateBrowsing whether or not the user should be prompted when opening
* this uri from private browsing. This should be true
* when the user doesn't explicitly choose to open an an
* external app (e.g. just clicked a link).
* @return true if the activity started successfully or the user was prompted to open the
* application; false otherwise.
*/
@WrapForJNI
public static boolean openUriExternal(String targetURI,
String mimeType,
String packageName,
String className,
String action,
String title) {
String title,
final boolean showPromptInPrivateBrowsing) {
final Context context = getContext();
final Intent intent = getOpenURIIntent(context, targetURI,
mimeType, action, title);
@ -1089,15 +1106,16 @@ public class GeckoAppShell
}
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
context.startActivity(intent);
return true;
} catch (ActivityNotFoundException e) {
Log.w(LOGTAG, "Activity not found.", e);
return false;
} catch (SecurityException e) {
Log.w(LOGTAG, "Forbidden to launch activity.", e);
return false;
if (!showPromptInPrivateBrowsing) {
return ActivityHandlerHelper.startIntentAndCatch(LOGTAG, context, intent);
} else {
// Ideally we retrieve the Activity from the calling args, rather than
// statically, but since this method is called from Gecko and I'm
// unfamiliar with that code, this is a simpler solution.
final FragmentActivity fragmentActivity = (FragmentActivity) getGeckoInterface().getActivity();
return ExternalIntentDuringPrivateBrowsingPromptFragment.showDialogOrAndroidChooser(
context, fragmentActivity.getSupportFragmentManager(), intent);
}
}

Просмотреть файл

@ -123,7 +123,7 @@ public final class IntentHelper implements GeckoEventListener,
message.optString("packageName"),
message.optString("className"),
message.optString("action"),
message.optString("title"));
message.optString("title"), false);
}
private void openForResult(final JSONObject message) throws JSONException {

Просмотреть файл

@ -197,7 +197,7 @@ public abstract class HomeFragment extends Fragment {
return false;
} else {
GeckoAppShell.openUriExternal(info.url, SHARE_MIME_TYPE, "", "",
Intent.ACTION_SEND, info.getDisplayTitle());
Intent.ACTION_SEND, info.getDisplayTitle(), false);
// Context: Sharing via chrome homepage contextmenu list (home session should be active)
Telemetry.sendUIEvent(TelemetryContract.Event.SHARE, TelemetryContract.Method.LIST);

Просмотреть файл

@ -4,6 +4,7 @@
package org.mozilla.gecko.widget;
import org.mozilla.gecko.ActivityHandlerHelper;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
@ -55,12 +56,14 @@ public class ExternalIntentDuringPrivateBrowsingPromptFragment extends DialogFra
return builder.create();
}
public static void showDialogOrAndroidChooser(final Context context, final FragmentManager fragmentManager,
/**
* @return true if the Activity is started or a dialog is shown. false if the Activity fails to start.
*/
public static boolean showDialogOrAndroidChooser(final Context context, final FragmentManager fragmentManager,
final Intent intent) {
final Tab selectedTab = Tabs.getInstance().getSelectedTab();
if (selectedTab == null || !selectedTab.isPrivate()) {
context.startActivity(intent);
return;
return ActivityHandlerHelper.startIntentAndCatch(LOGTAG, context, intent);
}
final PackageManager pm = context.getPackageManager();
@ -74,14 +77,17 @@ public class ExternalIntentDuringPrivateBrowsingPromptFragment extends DialogFra
fragment.setArguments(args);
fragment.show(fragmentManager, FRAGMENT_TAG);
// We don't know the results of the user interaction with the fragment so just return true.
return true;
} else if (matchingActivities.size() > 1) {
// Android chooser dialog will be shown, which should make the users
// aware they're entering a new application from private browsing.
context.startActivity(intent);
return ActivityHandlerHelper.startIntentAndCatch(LOGTAG, context, intent);
} else {
// Normally, we show about:neterror when an Intent does not resolve
// but we don't have the references here to do that so log instead.
Log.w(LOGTAG, "showDialogOrAndroidChooser unexpectedly called with Intent that does not resolve");
return false;
}
}
}