Bug 1276696 - Introduce new LauncherActivity that will handle all incoming Intents. r?mcomella
We will need to dispatch Intent objects to different destinations (Browser, Custom Tab and eventually
progressive web apps).
The logic of TabQueueDispatcher is folded into this new activity.
MozReview-Commit-ID: 3P4eIvtAKEW
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -39,16 +39,20 @@
<meta-data android:name="com.sec.android.support.multiwindow" android:value="true"/>
#ifdef MOZ_NATIVE_DEVICES
<!-- This resources comes from Google Play Services. Required for casting support. -->
<meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
#endif
+ <!-- This activity handles all incoming Intents and dispatches them to other activities. -->
+ <activity android:name="org.mozilla.gecko.LauncherActivity"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
<!-- Fennec is shipped as the Android package named
org.mozilla.{fennec,firefox,firefox_beta}. The internal Java
package hierarchy inside the Android package used to have an
org.mozilla.{fennec,firefox,firefox_beta} subtree *and* an
org.mozilla.gecko subtree; it now only has org.mozilla.gecko. -->
<activity android:name="@MOZ_ANDROID_BROWSER_INTENT_CLASS@"
android:label="@string/moz_app_displayname"
android:taskAffinity="@ANDROID_PACKAGE_NAME@.BROWSER"
@@ -59,29 +63,50 @@
android:exported="true"
android:theme="@style/Gecko.App" />
<!-- Bug 1256615 / Bug 1268455: We published an .App alias and we need to maintain it
forever. If we don't, home screen shortcuts will disappear because the intent
filter details change. -->
<activity-alias android:name=".App"
android:label="@MOZ_APP_DISPLAYNAME@"
- android:targetActivity="@MOZ_ANDROID_BROWSER_INTENT_CLASS@">
+ android:targetActivity="org.mozilla.gecko.LauncherActivity">
<!-- android:priority ranges between -1000 and 1000. We never want
another activity to usurp the MAIN action, so we ratchet our
priority up. -->
<intent-filter android:priority="999">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER"/>
<category android:name="android.intent.category.APP_BROWSER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <data android:scheme="http" />
+ <data android:scheme="https" />
+ <data android:scheme="about" />
+ <data android:scheme="javascript" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.BROWSABLE" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="file" />
+ <data android:scheme="http" />
+ <data android:scheme="https" />
+ <data android:mimeType="text/html"/>
+ <data android:mimeType="text/plain"/>
+ <data android:mimeType="application/xhtml+xml"/>
+ </intent-filter>
+
<meta-data android:name="com.sec.minimode.icon.portrait.normal"
android:resource="@drawable/icon"/>
<meta-data android:name="com.sec.minimode.icon.landscape.normal"
android:resource="@drawable/icon" />
<intent-filter>
<action android:name="org.mozilla.gecko.ACTION_ALERT_CALLBACK" />
@@ -166,44 +191,16 @@
before the rest of the plumbing is in place -->
<service android:name="org.mozilla.gecko.tabqueue.TabQueueService" />
<activity android:name="org.mozilla.gecko.tabqueue.TabQueuePrompt"
android:launchMode="singleTop"
android:theme="@style/OverlayActivity" />
- <activity android:name="org.mozilla.gecko.tabqueue.TabQueueDispatcher"
- android:label="@MOZ_APP_DISPLAYNAME@"
- android:launchMode="singleTask"
- android:excludeFromRecents="true"
- android:taskAffinity="@ANDROID_PACKAGE_NAME@.TABQUEUE"
- android:theme="@style/TabQueueActivity">
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:scheme="about" />
- <data android:scheme="javascript" />
- </intent-filter>
- <intent-filter>
- <action android:name="android.intent.action.VIEW" />
- <category android:name="android.intent.category.BROWSABLE" />
- <category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="file" />
- <data android:scheme="http" />
- <data android:scheme="https" />
- <data android:mimeType="text/html"/>
- <data android:mimeType="text/plain"/>
- <data android:mimeType="application/xhtml+xml"/>
- </intent-filter>
- </activity>
-
<receiver android:name="org.mozilla.gecko.restrictions.RestrictionProvider">
<intent-filter>
<action android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
</intent-filter>
</receiver>
<!-- Masquerade as the Resolver so that we can be opened from the Marketplace. -->
<activity-alias
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java
@@ -0,0 +1,71 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.tabqueue.TabQueueHelper;
+import org.mozilla.gecko.tabqueue.TabQueueService;
+
+/**
+ * Activity that receives incoming Intents and dispatches them to the appropriate activities (e.g. browser, custom tabs, web app).
+ */
+public class LauncherActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ GeckoAppShell.ensureCrashHandling();
+
+ if (isViewIntent()) {
+ dispatchViewIntent();
+ } else {
+ dispatchNormalIntent();
+ }
+
+ finish();
+ }
+
+ /**
+ * Dispatch a VIEW action intent; either to the browser or to the tab queue service.
+ */
+ private void dispatchViewIntent() {
+ if (TabQueueHelper.TAB_QUEUE_ENABLED
+ && TabQueueHelper.isTabQueueEnabled(this)
+ && !getIntent().getBooleanExtra(BrowserContract.SKIP_TAB_QUEUE_FLAG, false)) {
+ dispatchTabQueueIntent();
+ } else {
+ dispatchNormalIntent();
+ }
+ }
+
+ /**
+ * Launch tab queue service to display overlay.
+ */
+ private void dispatchTabQueueIntent() {
+ Intent intent = new Intent(getIntent());
+ intent.setClass(getApplicationContext(), TabQueueService.class);
+ startService(intent);
+ }
+
+ /**
+ * Launch the browser activity.
+ */
+ private void dispatchNormalIntent() {
+ Intent intent = new Intent(getIntent());
+ intent.setClassName(getApplicationContext(), AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
+ startActivity(intent);
+ }
+
+ private boolean isViewIntent() {
+ final String action = getIntent().getAction();
+ return Intent.ACTION_VIEW.equals(action);
+ }
+}
deleted file mode 100644
--- a/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabQueueDispatcher.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.gecko.tabqueue;
-
-import org.mozilla.gecko.AppConstants;
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.Locales;
-import org.mozilla.gecko.Telemetry;
-import org.mozilla.gecko.TelemetryContract;
-import org.mozilla.gecko.db.BrowserContract;
-
-import android.content.Intent;
-import android.os.Bundle;
-import android.text.TextUtils;
-import android.util.Log;
-import org.mozilla.gecko.mozglue.SafeIntent;
-
-/**
- * This class takes over external url loads (Intent.VIEW) from the BrowserApp class. It determines if
- * the tab queue functionality is enabled and forwards the intent to the TabQueueService to process if it is.
- *
- * If the tab queue functionality is not enabled then it forwards the intent to BrowserApp to handle as normal.
- */
-public class TabQueueDispatcher extends Locales.LocaleAwareActivity {
- private static final String LOGTAG = "Gecko" + TabQueueDispatcher.class.getSimpleName();
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- GeckoAppShell.ensureCrashHandling();
-
- // The EXCLUDE_FROM_RECENTS flag is sticky
- // (see http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.0_r1/com/android/server/am/ActivityRecord.java/#468)
- // So let's remove this whilst keeping all other flags the same, otherwise BrowserApp will vanish from Recents!
- Intent intent = getIntent();
- int flags = intent.getFlags() & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
- intent.setFlags(flags);
-
- SafeIntent safeIntent = new SafeIntent(intent);
-
- // For the moment lets exit early and start fennec as normal if we're not in nightly with
- // the tab queue build flag.
- if (!TabQueueHelper.TAB_QUEUE_ENABLED) {
- loadNormally(safeIntent.getUnsafe());
- return;
- }
-
- // Skip the Tab Queue if instructed.
- boolean shouldSkipTabQueue = safeIntent.getBooleanExtra(BrowserContract.SKIP_TAB_QUEUE_FLAG, false);
- if (shouldSkipTabQueue) {
- loadNormally(safeIntent.getUnsafe());
- return;
- }
-
- // The URL is usually hiding somewhere in the extra text. Extract it.
- final String dataString = safeIntent.getDataString();
- if (TextUtils.isEmpty(dataString)) {
- abortDueToNoURL(dataString);
- return;
- }
-
- boolean shouldShowOpenInBackgroundToast = TabQueueHelper.isTabQueueEnabled(this);
-
- if (shouldShowOpenInBackgroundToast) {
- showToast(safeIntent.getUnsafe());
- } else {
- loadNormally(safeIntent.getUnsafe());
- }
- }
-
- private void showToast(Intent intent) {
- intent.setClass(getApplicationContext(), TabQueueService.class);
- startService(intent);
- finish();
- }
-
- /**
- * Start fennec with the supplied intent.
- */
- private void loadNormally(Intent intent) {
- intent.setClassName(getApplicationContext(), AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
- startActivity(intent);
- Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "");
- finish();
- }
-
- /**
- * Abort as we were started with no URL.
- * @param dataString
- */
- private void abortDueToNoURL(String dataString) {
- // TODO: Lets decide what to do here in bug 1134148
- Log.w(LOGTAG, "Unable to process tab queue insertion. No URL found! - passed data string: " + dataString);
- finish();
- }
-}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -447,16 +447,17 @@ gbjar.sources += ['java/org/mozilla/geck
'home/TopSitesPanel.java',
'home/TopSitesThumbnailView.java',
'home/TwoLinePageRow.java',
'InputConnectionListener.java',
'InputMethods.java',
'IntentHelper.java',
'javaaddons/JavaAddonManager.java',
'javaaddons/JavaAddonManagerV1.java',
+ 'LauncherActivity.java',
'lwt/LightweightTheme.java',
'lwt/LightweightThemeDrawable.java',
'mdns/MulticastDNSManager.java',
'media/AudioFocusAgent.java',
'media/MediaControlService.java',
'MediaCastingBar.java',
'MemoryMonitor.java',
'menu/GeckoMenu.java',
@@ -556,17 +557,16 @@ gbjar.sources += ['java/org/mozilla/geck
'SnackbarHelper.java',
'sqlite/ByteBufferInputStream.java',
'sqlite/MatrixBlobCursor.java',
'sqlite/SQLiteBridge.java',
'sqlite/SQLiteBridgeException.java',
'SuggestClient.java',
'SurfaceBits.java',
'Tab.java',
- 'tabqueue/TabQueueDispatcher.java',
'tabqueue/TabQueueHelper.java',
'tabqueue/TabQueuePrompt.java',
'tabqueue/TabQueueService.java',
'tabqueue/TabReceivedService.java',
'Tabs.java',
'tabs/PrivateTabsPanel.java',
'tabs/TabCurve.java',
'tabs/TabHistoryController.java',