Bug 1352997 - Part 6 - Switch over web apps and implement additional startup logic for them. r?sebastian draft
authorJan Henning <jh+bugzilla@buttercookie.de>
Tue, 04 Apr 2017 21:50:33 +0200
changeset 559324 7267adcbaa1c04110fc2b0436b933472c7b57200
parent 559323 3c7fa0d6ee3e738e38fad38f22eae75a630dadfb
child 623360 0b5cfb3f0a1c55c51eb073b1343f084479d67e70
push id53055
push usermozilla@buttercookie.de
push dateSun, 09 Apr 2017 20:38:11 +0000
reviewerssebastian
bugs1352997
milestone55.0a1
Bug 1352997 - Part 6 - Switch over web apps and implement additional startup logic for them. r?sebastian Web Apps are single task activities, but Android's task switcher will only ever return the intent that originally created the activity and will never ever update its stored intent for subsequent launches via onNewIntent, so we have to do this ourselves. Additionally, web apps have some additional logic when being launched via a new intent that checks whether the currently loaded page matches the scope of the web app intent and then resets it if necessary. We now hook up this logic to the new SingleTabActivity wiring. MozReview-Commit-ID: 9bo4gXbfPNg
mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
--- a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
@@ -10,64 +10,67 @@ import java.io.IOException;
 
 import android.app.ActivityManager;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.v7.widget.Toolbar;
 import android.support.v7.app.ActionBar;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.view.Window;
 import android.view.WindowManager;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
 import org.json.JSONObject;
 import org.json.JSONException;
 
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.SingleTabActivity;
 import org.mozilla.gecko.icons.decoders.FaviconDecoder;
 import org.mozilla.gecko.mozglue.SafeIntent;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.util.ColorUtil;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.FileUtils;
 import org.mozilla.gecko.util.GeckoBundle;
 
 import static org.mozilla.gecko.Tabs.TabEvents;
 
-public class WebAppActivity extends GeckoApp {
+public class WebAppActivity extends SingleTabActivity {
     private static final String LOGTAG = "WebAppActivity";
 
     public static final String MANIFEST_PATH = "MANIFEST_PATH";
+    private static final String SAVED_INTENT = "savedIntent";
 
     private TextView mUrlView;
-    private String mManifestPath;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
-        Intent savedIntent = getIntent();
-        super.onCreate(savedInstanceState);
-        // GeckoApp's default behaviour is to reset the intent if we've got any
-        // savedInstanceState, which we don't want here.
-        setIntent(savedIntent);
+        if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0 &&
+        savedInstanceState != null) {
+            // Even though we're a single task activity, Android's task switcher has the
+            // annoying habit of never updating its stored intent after our initial creation,
+            // even if we've been subsequently started with a new intent.
 
-        if (savedInstanceState != null) {
-            mManifestPath = savedInstanceState.getString(WebAppActivity.MANIFEST_PATH, null);
-        } else {
-            mManifestPath = getIntent().getStringExtra(WebAppActivity.MANIFEST_PATH);
+            // This below is needed if we should ever decide to store a custom class as intent extra.
+            savedInstanceState.setClassLoader(getClass().getClassLoader());
+
+            Intent lastLaunchIntent = savedInstanceState.getParcelable(SAVED_INTENT);
+            setIntent(lastLaunchIntent);
         }
-        loadManifest(mManifestPath);
+
+        super.onCreate(savedInstanceState);
 
         final Toolbar toolbar = (Toolbar) findViewById(R.id.actionbar);
         setSupportActionBar(toolbar);
 
         final ProgressBar progressBar = (ProgressBar) findViewById(R.id.page_progress);
         progressBar.setVisibility(View.GONE);
 
         final ActionBar actionBar = getSupportActionBar();
@@ -118,17 +121,17 @@ public class WebAppActivity extends Geck
             mUrlView.setText(tab.getURL());
         }
     }
 
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
-        outState.putString(WebAppActivity.MANIFEST_PATH, mManifestPath);
+        outState.putParcelable(SAVED_INTENT, getIntent());
     }
 
     @Override
     public void onDestroy() {
         super.onDestroy();
         EventDispatcher.getInstance().unregisterUiThreadListener(this,
               "Website:AppEntered",
               "Website:AppLeft",
@@ -137,51 +140,48 @@ public class WebAppActivity extends Geck
     }
 
     @Override
     protected int getNewTabFlags() {
         return Tabs.LOADURL_WEBAPP | super.getNewTabFlags();
     }
 
     @Override
-    protected void onDone() {
-        finish();
+    protected void onTabOpenFromIntent(Tab tab) {
+        super.onTabOpenFromIntent(tab);
+        loadManifest(tab.getManifestPath());
     }
 
     /**
-     * In case this activity is reused (the user has opened > 10 current web apps)
-     * we check that app launched is still within the same host as the
-     * shortcut has set, if not we reload the homescreens url
+     * In case this activity and its tab are reused (the user has opened
+     *  > 10 current web apps), we check that app launched is still within
+     * the same host as the intent has set.
+     * If it isn't, we reload the intent URL.
      */
     @Override
-    protected void onNewIntent(Intent externalIntent) {
-        super.onNewIntent(externalIntent);
-
-        final SafeIntent intent = new SafeIntent(externalIntent);
+    protected void onTabSelectFromIntent(Tab tab) {
+        super.onTabSelectFromIntent(tab);
 
-        if (hasGeckoTab(intent)) {
-            loadManifest(intent.getStringExtra(WebAppActivity.MANIFEST_PATH));
-        } else {
-            restoreLastSelectedTab();
+        SafeIntent intent = new SafeIntent(getIntent());
 
-            final String launchUrl = intent.getDataString();
-            final String currentUrl = Tabs.getInstance().getSelectedTab().getURL();
-            final boolean isSameDomain = Uri.parse(currentUrl).getHost()
-                    .equals(Uri.parse(launchUrl).getHost());
+        final String launchUrl = intent.getDataString();
+        final String currentUrl = tab.getURL();
+        final boolean isSameDomain = Uri.parse(currentUrl).getHost()
+                .equals(Uri.parse(launchUrl).getHost());
 
-            if (!isSameDomain) {
-                mManifestPath = externalIntent.getStringExtra(WebAppActivity.MANIFEST_PATH);
-                loadManifest(mManifestPath);
-                Tabs.getInstance().loadUrl(launchUrl);
-            }
+        if (!isSameDomain) {
+            String manifestPath = intent.getStringExtra(MANIFEST_PATH);
+            tab.setManifestUrl(manifestPath);
+            loadManifest(manifestPath);
+            Tabs.getInstance().loadUrl(launchUrl);
         }
     }
 
     private void loadManifest(String manifestPath) {
-        if (manifestPath == null) {
+        if (TextUtils.isEmpty(manifestPath)) {
             Log.e(LOGTAG, "Missing manifest");
             return;
         }
         // The customisations defined in the manifest only work on Android API 21+
         if (AppConstants.Versions.preLollipop) {
             return;
         }