Bug 1356517 - Add deep links to handle events. r=Grisha
authorNevin Chen <cnevinchen@gmail.com>
Tue, 25 Apr 2017 18:01:34 +0800
changeset 356019 340b02a5a42cba525c0433a823bf4b09b3f21623
parent 356018 9233d2abdfc241478a6971be5fa44530eb18eb01
child 356020 525326d5ddb15a849d0f8cd29594e88cbda34b0e
push id31754
push userkwierso@gmail.com
push dateWed, 03 May 2017 00:28:51 +0000
treeherdermozilla-central@5eaf2d70eded [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGrisha
bugs1356517
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1356517 - Add deep links to handle events. r=Grisha MozReview-Commit-ID: 4OQTrbEdVtQ
mobile/android/base/AndroidManifest.xml.in
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java
mobile/android/base/java/org/mozilla/gecko/deeplink/DeepLinkContract.java
mobile/android/base/moz.build
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -93,16 +93,17 @@
             <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" />
+                <data android:scheme="firefox" />
             </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" />
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -207,17 +207,17 @@ public class BrowserApp extends GeckoApp
     // TODO: Replace with kinto endpoint.
     private static final String SWITCHBOARD_SERVER = "https://firefox.settings.services.mozilla.com/v1/buckets/fennec/collections/experiments/records";
 
     private static final String STATE_ABOUT_HOME_TOP_PADDING = "abouthome_top_padding";
 
     private static final String BROWSER_SEARCH_TAG = "browser_search";
 
     // Request ID for startActivityForResult.
-    private static final int ACTIVITY_REQUEST_PREFERENCES = 1001;
+    public static final int ACTIVITY_REQUEST_PREFERENCES = 1001;
     private static final int ACTIVITY_REQUEST_TAB_QUEUE = 2001;
     public static final int ACTIVITY_REQUEST_FIRST_READERVIEW_BOOKMARK = 3001;
     public static final int ACTIVITY_RESULT_FIRST_READERVIEW_BOOKMARKS_GOTO_BOOKMARKS = 3002;
     public static final int ACTIVITY_RESULT_FIRST_READERVIEW_BOOKMARKS_IGNORE = 3003;
     public static final int ACTIVITY_REQUEST_TRIPLE_READERVIEW = 4001;
     public static final int ACTIVITY_RESULT_TRIPLE_READERVIEW_ADD_BOOKMARK = 4002;
     public static final int ACTIVITY_RESULT_TRIPLE_READERVIEW_IGNORE = 4003;
 
--- a/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java
@@ -1,45 +1,68 @@
 /* -*- 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.Context;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import android.support.customtabs.CustomTabsIntent;
+import android.util.Log;
 
+import org.mozilla.gecko.home.HomeConfig;
 import org.mozilla.gecko.webapps.WebAppActivity;
 import org.mozilla.gecko.webapps.WebAppIndexer;
 import org.mozilla.gecko.customtabs.CustomTabsActivity;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.mozglue.SafeIntent;
 import org.mozilla.gecko.preferences.GeckoPreferences;
 import org.mozilla.gecko.tabqueue.TabQueueHelper;
 import org.mozilla.gecko.tabqueue.TabQueueService;
 
+import static org.mozilla.gecko.BrowserApp.ACTIVITY_REQUEST_PREFERENCES;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.DEEP_LINK_SCHEME;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_BOOKMARK_LIST;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_DEFAULT_BROWSER;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_HISTORY_LIST;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_PREFERENCES;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_PREFERENCES_ACCESSIBILITY;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_PREFERENCES_NOTIFICATIONS;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_PREFERENCES_PRIAVACY;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_PREFERENCES_SEARCH;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_SAVE_AS_PDF;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_SIGN_UP;
+import static org.mozilla.gecko.deeplink.DeepLinkContract.SUMO_DEFAULT_BROWSER;
+
 /**
  * Activity that receives incoming Intents and dispatches them to the appropriate activities (e.g. browser, custom tabs, web app).
  */
 public class LauncherActivity extends Activity {
+
+    private static final String TAG = LauncherActivity.class.getSimpleName();
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         GeckoAppShell.ensureCrashHandling();
 
         final SafeIntent safeIntent = new SafeIntent(getIntent());
 
+        // Is this deep link?
+        if (isDeepLink(safeIntent)) {
+            dispatchDeepLink(safeIntent);
+
         // Is this web app?
-        if (isWebAppIntent(safeIntent)) {
+        } else if (isWebAppIntent(safeIntent)) {
             dispatchWebAppIntent();
 
         // If it's not a view intent, it won't be a custom tabs intent either. Just launch!
         } else if (!isViewIntentWithURL(safeIntent)) {
             dispatchNormalIntent();
 
         // Is this a custom tabs intent, and are custom tabs enabled?
         } else if (AppConstants.MOZ_ANDROID_CUSTOM_TABS && isCustomTabsIntent(safeIntent)
@@ -76,16 +99,26 @@ public class LauncherActivity extends Ac
         Intent intent = new Intent(getIntent());
         intent.setClassName(getApplicationContext(), AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
 
         filterFlags(intent);
 
         startActivity(intent);
     }
 
+    private void dispatchUrlIntent(@NonNull String url) {
+        Intent intent = new Intent(getIntent());
+        intent.setData(Uri.parse(url));
+        intent.setClassName(getApplicationContext(), AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
+
+        filterFlags(intent);
+
+        startActivity(intent);
+    }
+
     private void dispatchCustomTabsIntent() {
         Intent intent = new Intent(getIntent());
         intent.setClassName(getApplicationContext(), CustomTabsActivity.class.getName());
 
         filterFlags(intent);
 
         startActivity(intent);
     }
@@ -122,9 +155,75 @@ public class LauncherActivity extends Ac
 
     private static boolean isWebAppIntent(@NonNull final SafeIntent safeIntent) {
         return GeckoApp.ACTION_WEBAPP.equals(safeIntent.getAction());
     }
 
     private boolean isCustomTabsEnabled() {
         return GeckoSharedPrefs.forApp(this).getBoolean(GeckoPreferences.PREFS_CUSTOM_TABS, false);
     }
+
+    private boolean isDeepLink(SafeIntent intent) {
+        if (intent == null || intent.getData() == null || intent.getData().getScheme() == null
+                || intent.getAction() == null) {
+            return false;
+        }
+        boolean schemeMatched = intent.getData().getScheme().equalsIgnoreCase(DEEP_LINK_SCHEME);
+        boolean actionMatched = intent.getAction().equals(Intent.ACTION_VIEW);
+        return schemeMatched && actionMatched;
+    }
+
+    private void dispatchDeepLink(SafeIntent intent) {
+        if (intent == null || intent.getData() == null || intent.getData().getHost() == null) {
+            return;
+        }
+        final String host = intent.getData().getHost();
+
+        switch (host) {
+            case LINK_DEFAULT_BROWSER:
+                GeckoSharedPrefs.forApp(this).edit().putBoolean(GeckoPreferences.PREFS_DEFAULT_BROWSER, true).apply();
+
+                if (AppConstants.Versions.feature24Plus) {
+                    // We are special casing the link to set the default browser here: On old Android versions we
+                    // link to a SUMO page but on new Android versions we can link to the default app settings where
+                    // the user can actually set a default browser (Bug 1312686).
+                    final Intent changeDefaultApps = new Intent("android.settings.MANAGE_DEFAULT_APPS_SETTINGS");
+                    startActivity(changeDefaultApps);
+                } else {
+                    dispatchUrlIntent(SUMO_DEFAULT_BROWSER);
+                }
+                break;
+            case LINK_SAVE_AS_PDF:
+                EventDispatcher.getInstance().dispatch("SaveAs:PDF", null);
+                break;
+            case LINK_BOOKMARK_LIST:
+                String bookmarks = AboutPages.getURLForBuiltinPanelType(HomeConfig.PanelType.BOOKMARKS);
+                dispatchUrlIntent(bookmarks);
+                break;
+            case LINK_HISTORY_LIST:
+                String history = AboutPages.getURLForBuiltinPanelType(HomeConfig.PanelType.COMBINED_HISTORY);
+                dispatchUrlIntent(history);
+                break;
+            case LINK_SIGN_UP:
+                dispatchUrlIntent(AboutPages.ACCOUNTS + "?action=signup");
+                break;
+            case LINK_PREFERENCES:
+                Intent settingsIntent = new Intent(this, GeckoPreferences.class);
+
+                // We want to know when the Settings activity returns, because
+                // we might need to redisplay based on a locale change.
+                startActivityForResult(settingsIntent, ACTIVITY_REQUEST_PREFERENCES);
+                break;
+            case LINK_PREFERENCES_PRIAVACY:
+            case LINK_PREFERENCES_SEARCH:
+            case LINK_PREFERENCES_NOTIFICATIONS:
+            case LINK_PREFERENCES_ACCESSIBILITY:
+                settingsIntent = new Intent(this, GeckoPreferences.class);
+                GeckoPreferences.setResourceToOpen(settingsIntent, host);
+                startActivityForResult(settingsIntent, ACTIVITY_REQUEST_PREFERENCES);
+                break;
+            default:
+                Log.w(TAG, "unrecognized deep links");
+        }
+
+    }
+
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/deeplink/DeepLinkContract.java
@@ -0,0 +1,26 @@
+/* -*- 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.deeplink;
+
+// This class defines the contract when using deep links
+public class DeepLinkContract {
+
+    // Sumo page for setting Fennec as default browser
+    public static final String SUMO_DEFAULT_BROWSER = "https://support.mozilla.org/kb/make-firefox-default-browser-android?utm_source=inproduct&amp;utm_medium=settings&amp;utm_campaign=mobileandroid";
+    public static final String DEEP_LINK_SCHEME = "firefox";
+
+    public static final String LINK_DEFAULT_BROWSER = "default_browser";
+    public static final String LINK_SAVE_AS_PDF = "save_as_pdf";
+    public static final String LINK_BOOKMARK_LIST = "bookmark_list";
+    public static final String LINK_HISTORY_LIST = "history_list";
+    public static final String LINK_SIGN_UP = "sign_up";
+    public static final String LINK_PREFERENCES = "preferences";
+    public static final String LINK_PREFERENCES_PRIAVACY = "preferences_privacy";
+    public static final String LINK_PREFERENCES_SEARCH = "preferences_search";
+    public static final String LINK_PREFERENCES_NOTIFICATIONS = "preferences_notifications";
+    public static final String LINK_PREFERENCES_ACCESSIBILITY = "preferences_accessibility";
+
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -520,16 +520,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'db/SQLiteBridgeContentProvider.java',
     'db/SuggestedSites.java',
     'db/Table.java',
     'db/TabsAccessor.java',
     'db/TabsProvider.java',
     'db/UrlAnnotations.java',
     'db/URLImageDataTable.java',
     'db/URLMetadata.java',
+    'deeplink/DeepLinkContract.java',
     'delegates/BookmarkStateChangeDelegate.java',
     'delegates/BrowserAppDelegate.java',
     'delegates/BrowserAppDelegateWithReference.java',
     'delegates/OfflineTabStatusDelegate.java',
     'delegates/ScreenshotDelegate.java',
     'delegates/TabsTrayVisibilityAwareDelegate.java',
     'DevToolsAuthHelper.java',
     'distribution/Distribution.java',