Bug 1351739 - Part 1 - Track the currently active activity. r?sebastian draft
authorJan Henning <jh+bugzilla@buttercookie.de>
Sun, 02 Apr 2017 11:22:12 +0200
changeset 559299 ad3144e298c7801dd4b04605798ff7a8b08d94bd
parent 559298 044ee92d0ced47f8e4055667b23afbb62d6df3a6
child 559300 a984289df68676d6c2c3694e24d02d1be530c68f
push id53051
push usermozilla@buttercookie.de
push dateSun, 09 Apr 2017 17:35:56 +0000
reviewerssebastian
bugs1351739
milestone55.0a1
Bug 1351739 - Part 1 - Track the currently active activity. r?sebastian Required because later on, we'll need to know if we're in the correct activity for a tab or need to switch activities. As a follow-up, we can later also hook up our current manual activity tracking from GeckoApplication to this (we most probably won't be able to get rid of the GeckoActivityStatus shenanigans, though). MozReview-Commit-ID: 5lZrAMsB9Gy
mobile/android/base/java/org/mozilla/gecko/GeckoActivity.java
mobile/android/base/java/org/mozilla/gecko/GeckoActivityMonitor.java
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
mobile/android/base/moz.build
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoActivity.java
@@ -37,16 +37,21 @@ public abstract class GeckoActivity exte
 
         if (getApplication() instanceof GeckoApplication) {
             ((GeckoApplication) getApplication()).onActivityResume(this);
             mGeckoActivityOpened = false;
         }
     }
 
     @Override
+    protected void onNewIntent(Intent externalIntent) {
+        GeckoActivityMonitor.getInstance().onActivityNewIntent(this);
+    }
+
+    @Override
     public void onCreate(android.os.Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         if (AppConstants.MOZ_ANDROID_ANR_REPORTER) {
             ANRReporter.register(getApplicationContext());
         }
     }
 
     @Override
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoActivityMonitor.java
@@ -0,0 +1,89 @@
+/* -*- 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.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.Application;
+import android.os.Bundle;
+
+public class GeckoActivityMonitor implements Application.ActivityLifecycleCallbacks {
+    private static final String LOGTAG = "GeckoActivityMonitor";
+
+    @SuppressLint("StaticFieldLeak")
+    // We only hold a reference to the currently running activity - when this activity pauses,
+    // the reference is released or else overwritten by the next activity.
+    private static final GeckoActivityMonitor instance = new GeckoActivityMonitor();
+
+    private Activity currentActivity;
+
+    public static GeckoActivityMonitor getInstance() {
+        return instance;
+    }
+
+    private GeckoActivityMonitor() { }
+
+    public Activity getCurrentActivity() {
+        return currentActivity;
+    }
+
+    @Override
+    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+        currentActivity = activity;
+    }
+
+    // onNewIntent happens inbetween a pause/resume cycle, which means that we wouldn't have
+    // a current activity to report if we were using only the official ActivityLifecycleCallbacks.
+    // For code that wants to know the current activity even at this point we therefore have to
+    // handle this ourselves.
+    public void onActivityNewIntent(Activity activity) {
+        currentActivity = activity;
+    }
+
+    @Override
+    public void onActivityStarted(Activity activity) {
+        currentActivity = activity;
+    }
+
+    @Override
+    public void onActivityResumed(Activity activity) {
+        currentActivity = activity;
+    }
+
+    /**
+     * Intended to be used if the current activity is required to be up-to-date for code that
+     * executes in onCreate/onstart/... before calling the corresponding superclass method.
+     */
+    public void setCurrentActivity(Activity activity) {
+        currentActivity = activity;
+    }
+
+    @Override
+    public void onActivityPaused(Activity activity) {
+        releaseIfCurrentActivity(activity);
+    }
+
+    @Override
+    public void onActivityStopped(Activity activity) {
+        releaseIfCurrentActivity(activity);
+    }
+
+    @Override
+    public void onActivitySaveInstanceState(Activity activity, Bundle outState) { }
+
+    @Override
+    public void onActivityDestroyed(Activity activity) {
+        releaseIfCurrentActivity(activity);
+    }
+
+    private void releaseIfCurrentActivity(Activity activity) {
+        // If the next activity has already started by the time the previous activity is being
+        // stopped/destroyed, we no longer need to clear the previous activity.
+        if (currentActivity == activity) {
+            currentActivity = null;
+        }
+    }
+}
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -2132,16 +2132,18 @@ public abstract class GeckoApp
                         halfSize + sHeight),
                 null);
 
         return bitmap;
     }
 
     @Override
     protected void onNewIntent(Intent externalIntent) {
+        super.onNewIntent(externalIntent);
+
         final SafeIntent intent = new SafeIntent(externalIntent);
 
         final boolean isFirstTab = !mWasFirstTabShownAfterActivityUnhidden;
         mWasFirstTabShownAfterActivityUnhidden = true; // Reset since we'll be loading a tab.
 
         // if we were previously OOM killed, we can end up here when launching
         // from external shortcuts, so set this as the intent for initialization
         if (!mInitialized) {
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
@@ -160,16 +160,18 @@ public class GeckoApplication extends Ap
             // Not much to be done here: it was weak before, so it's weak now.  Not worth aborting.
             Log.e(LOG_TAG, "Got exception applying PRNGFixes! Cryptographic data produced on this device may be weak. Ignoring.", e);
         }
 
         mIsInitialResume = true;
 
         mRefWatcher = LeakCanary.install(this);
 
+        registerActivityLifecycleCallbacks(GeckoActivityMonitor.getInstance());
+
         final Context context = getApplicationContext();
         GeckoAppShell.setApplicationContext(context);
         HardwareUtils.init(context);
         FilePicker.init(context);
         DownloadsIntegration.init();
         HomePanelsManager.getInstance().init(context);
 
         GlobalPageMetadata.getInstance().init();
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -465,16 +465,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'firstrun/FirstrunPager.java',
     'firstrun/FirstrunPagerConfig.java',
     'firstrun/FirstrunPanel.java',
     'firstrun/RestrictedWelcomePanel.java',
     'firstrun/SyncPanel.java',
     'firstrun/TabQueuePanel.java',
     'FormAssistPopup.java',
     'GeckoActivity.java',
+    'GeckoActivityMonitor.java',
     'GeckoActivityStatus.java',
     'GeckoApp.java',
     'GeckoApplication.java',
     'GeckoFontScaleListener.java',
     'GeckoJavaSampler.java',
     'GeckoMessageReceiver.java',
     'GeckoProfilesProvider.java',
     'GeckoService.java',