Bug 826385 - Reduce pause/resume notifications to gecko; r=mfinkle
authorGeoff Brown <gbrown@mozilla.com>
Tue, 29 Jan 2013 14:59:42 -0700
changeset 130156 6a15e1b67fed52b8d3561f76acf5ac67bcc6d45c
parent 130155 0aea65518be3c19767cdc5df1aee23815775ef25
child 130157 b437c69914066e06ddcd656b2835ad19f0046f90
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs826385
milestone21.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 826385 - Reduce pause/resume notifications to gecko; r=mfinkle
mobile/android/base/GeckoActivity.java.in
mobile/android/base/GeckoApplication.java
mobile/android/base/GeckoPreferences.java
--- a/mobile/android/base/GeckoActivity.java.in
+++ b/mobile/android/base/GeckoActivity.java.in
@@ -1,35 +1,77 @@
 /* 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/. */
 
+#filter substitution
+
 package org.mozilla.gecko;
 
 import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Intent;
 
-public class GeckoActivity extends Activity {
+interface GeckoActivityStatus {
+    public boolean isGeckoActivityOpened();
+    public boolean isFinishing();  // typically from android.app.Activity
+};
+
+public class GeckoActivity extends Activity implements GeckoActivityStatus {
+    // has this activity recently started another Gecko activity?
+    private boolean mGeckoActivityOpened = false;
+
     @Override
     public void onPause() {
         super.onPause();
 
         if (getApplication() instanceof GeckoApplication) {
             ((GeckoApplication) getApplication()).onActivityPause(this);
         }
     }
 
     @Override
     public void onResume() {
         super.onResume();
 
         if (getApplication() instanceof GeckoApplication) {
             ((GeckoApplication) getApplication()).onActivityResume(this);
+            mGeckoActivityOpened = false;
         }
     }
 
+    @Override
+    public void startActivity(Intent intent) {
+        checkIfGeckoActivity(intent);
+        super.startActivity(intent);
+    }
+
+    @Override
+    public void startActivityForResult(Intent intent, int request) {
+        checkIfGeckoActivity(intent);
+        super.startActivityForResult(intent, request);
+    }
+
+    private void checkIfGeckoActivity(Intent intent) {
+        // Whenever we call our own activity, the component and it's package name is set.
+        // If we call an activity from another package, or an open intent (leaving android to resolve)
+        // component has a different package name or it is null.
+        ComponentName component = intent.getComponent();
+        mGeckoActivityOpened = false;
+        if (component != null &&
+            component.getPackageName() != null &&
+            component.getPackageName().equals("@ANDROID_PACKAGE_NAME@")) {
+            mGeckoActivityOpened = true;
+        }
+    }
+
+    public boolean isGeckoActivityOpened() {
+        return mGeckoActivityOpened;
+    }
+
     public boolean isApplicationInBackground() {
         return ((GeckoApplication) getApplication()).isApplicationInBackground();
     }
 
     @Override
     public void onLowMemory() {
         MemoryMonitor.getInstance().onLowMemory();
         super.onLowMemory();
--- a/mobile/android/base/GeckoApplication.java
+++ b/mobile/android/base/GeckoApplication.java
@@ -5,16 +5,17 @@
 package org.mozilla.gecko;
 
 import android.app.Application;
 
 public class GeckoApplication extends Application {
 
     private boolean mInited;
     private boolean mInBackground;
+    private boolean mPausedGecko;
 
     private LightweightTheme mLightweightTheme;
 
     protected void initialize() {
         if (mInited)
             return;
 
         // workaround for http://code.google.com/p/android/issues/detail?id=20915
@@ -27,27 +28,38 @@ public class GeckoApplication extends Ap
         GeckoConnectivityReceiver.getInstance().init(getApplicationContext());
         GeckoBatteryManager.getInstance().init(getApplicationContext());
         GeckoBatteryManager.getInstance().start();
         GeckoNetworkManager.getInstance().init(getApplicationContext());
         MemoryMonitor.getInstance().init(getApplicationContext());
         mInited = true;
     }
 
-    protected void onActivityPause(GeckoActivity activity) {
+    protected void onActivityPause(GeckoActivityStatus activity) {
         mInBackground = true;
 
-        GeckoAppShell.sendEventToGecko(GeckoEvent.createPauseEvent(true));
+        if ((activity.isFinishing() == false) &&
+            (activity.isGeckoActivityOpened() == false)) {
+            // Notify Gecko that we are pausing; the cache service will be
+            // shutdown, closing the disk cache cleanly. If the android
+            // low memory killer subsequently kills us, the disk cache will
+            // be left in a consistent state, avoiding costly cleanup and
+            // re-creation. 
+            GeckoAppShell.sendEventToGecko(GeckoEvent.createPauseEvent(true));
+            mPausedGecko = true;
+        }
         GeckoConnectivityReceiver.getInstance().stop();
         GeckoNetworkManager.getInstance().stop();
     }
 
-    protected void onActivityResume(GeckoActivity activity) {
-        if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning))
+    protected void onActivityResume(GeckoActivityStatus activity) {
+        if (mPausedGecko) {
             GeckoAppShell.sendEventToGecko(GeckoEvent.createResumeEvent(true));
+            mPausedGecko = false;
+        }
         GeckoConnectivityReceiver.getInstance().start();
         GeckoNetworkManager.getInstance().start();
 
         mInBackground = false;
     }
 
     public boolean isApplicationInBackground() {
         return mInBackground;
--- a/mobile/android/base/GeckoPreferences.java
+++ b/mobile/android/base/GeckoPreferences.java
@@ -38,17 +38,17 @@ import android.view.View;
 import android.widget.EditText;
 import android.widget.LinearLayout;
 import android.widget.Toast;
 
 import java.util.ArrayList;
 
 public class GeckoPreferences
     extends PreferenceActivity
-    implements OnPreferenceChangeListener, GeckoEventListener
+    implements OnPreferenceChangeListener, GeckoEventListener, GeckoActivityStatus
 {
     private static final String LOGTAG = "GeckoPreferences";
 
     private ArrayList<String> mPreferencesList;
     private PreferenceScreen mPreferenceScreen;
     private static boolean sIsCharEncodingEnabled = false;
     private static final String NON_PREF_PREFIX = "android.not_a_preference.";
 
@@ -80,16 +80,34 @@ public class GeckoPreferences
     }
 
     @Override
     protected void onDestroy() {
         super.onDestroy();
         unregisterEventListener("Sanitize:Finished");
     }
 
+    @Override
+    public void onPause() {
+        super.onPause();
+
+        if (getApplication() instanceof GeckoApplication) {
+            ((GeckoApplication) getApplication()).onActivityPause(this);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+
+        if (getApplication() instanceof GeckoApplication) {
+            ((GeckoApplication) getApplication()).onActivityResume(this);
+        }
+    }
+
     public void handleMessage(String event, JSONObject message) {
         try {
             if (event.equals("Sanitize:Finished")) {
                 boolean success = message.getBoolean("success");
                 final int stringRes = success ? R.string.private_data_success : R.string.private_data_fail;
                 final Context context = this;
                 GeckoAppShell.getMainHandler().post(new Runnable () {
                     public void run() {
@@ -440,9 +458,13 @@ public class GeckoPreferences
 
     private void registerEventListener(String event) {
         GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
     }
 
     private void unregisterEventListener(String event) {
         GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this);
     }
+
+    public boolean isGeckoActivityOpened() {
+        return false;
+    }
 }