summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/android/java/src/org/chromium/base/ActivityStatus.java157
-rw-r--r--base/android/java/src/org/chromium/base/ChromiumActivity.java49
-rw-r--r--base/android/java/src/org/chromium/base/ChromiumApplication.java20
-rw-r--r--chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java4
-rw-r--r--chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplication.java6
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/LocationProvider.java6
-rw-r--r--content/public/android/javatests/src/org/chromium/content/browser/LocationProviderTest.java36
-rw-r--r--content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java4
-rw-r--r--content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java6
-rw-r--r--testing/android/AndroidManifest.xml3
-rw-r--r--testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java7
11 files changed, 205 insertions, 93 deletions
diff --git a/base/android/java/src/org/chromium/base/ActivityStatus.java b/base/android/java/src/org/chromium/base/ActivityStatus.java
index 4747234..e449b38 100644
--- a/base/android/java/src/org/chromium/base/ActivityStatus.java
+++ b/base/android/java/src/org/chromium/base/ActivityStatus.java
@@ -5,8 +5,12 @@
package org.chromium.base;
import android.app.Activity;
-import android.os.Handler;
-import android.os.Looper;
+import android.app.Application;
+import android.app.Application.ActivityLifecycleCallbacks;
+import android.os.Bundle;
+
+import java.util.HashMap;
+import java.util.Map;
/**
* Provides information about the current activity's status, and a way
@@ -25,15 +29,14 @@ public class ActivityStatus {
public static final int STOPPED = ActivityState.STOPPED;
public static final int DESTROYED = ActivityState.DESTROYED;
- // Current main activity, or null if none.
+ // Last activity that was shown (or null if none or it was destroyed).
private static Activity sActivity;
- // Current main activity's state. This can be set even if sActivity is null, to simplify unit
- // testing.
- private static int sActivityState;
+ private static final Map<Activity, Integer> sActivityStates
+ = new HashMap<Activity, Integer>();
- private static final ObserverList<StateListener> sStateListeners =
- new ObserverList<StateListener>();
+ private static final ObserverList<StateListener> sStateListeners
+ = new ObserverList<StateListener>();
/**
* Interface to be implemented by listeners.
@@ -49,47 +52,163 @@ public class ActivityStatus {
private ActivityStatus() {}
/**
+ * Initializes the activity status for a specified application.
+ *
+ * @param application The application whose status you wish to monitor.
+ */
+ public static void initialize(Application application) {
+ application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
+ @Override
+ public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
+ onStateChange(activity, CREATED);
+ }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ onStateChange(activity, DESTROYED);
+ }
+
+ @Override
+ public void onActivityPaused(Activity activity) {
+ onStateChange(activity, PAUSED);
+ }
+
+ @Override
+ public void onActivityResumed(Activity activity) {
+ onStateChange(activity, RESUMED);
+ }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
+
+ @Override
+ public void onActivityStarted(Activity activity) {
+ onStateChange(activity, STARTED);
+ }
+
+ @Override
+ public void onActivityStopped(Activity activity) {
+ onStateChange(activity, STOPPED);
+ }
+ });
+ }
+
+ /**
* Must be called by the main activity when it changes state.
+ *
* @param activity Current activity.
* @param newState New state value.
*/
+ // TODO(tedchoc): Make this method private (and remove @Deprecated) once all downstream usages
+ // move to the initialize method.
+ @Deprecated
public static void onStateChange(Activity activity, int newState) {
+ if (activity == null) throw new IllegalArgumentException("null activity is not supported");
+
if (sActivity != activity) {
// ActivityStatus is notified with the CREATED event very late during the main activity
// creation to avoid making startup performance worse than it is by notifying observers
// that could do some expensive work. This can lead to non-CREATED events being fired
// before the CREATED event which is problematic.
// TODO(pliard): fix http://crbug.com/176837.
- sActivity = activity;
+ if (sActivity == null
+ || newState == CREATED || newState == RESUMED || newState == STARTED) {
+ sActivity = activity;
+ }
}
- sActivityState = newState;
- for (StateListener listener : sStateListeners) {
- listener.onActivityStateChange(newState);
+
+ if (newState != DESTROYED) {
+ sActivityStates.put(activity, newState);
+ } else {
+ sActivityStates.remove(activity);
}
- if (newState == DESTROYED) {
- sActivity = null;
+
+ if (sActivity == activity) {
+ for (StateListener listener : sStateListeners) {
+ listener.onActivityStateChange(newState);
+ }
+ if (newState == DESTROYED) {
+ sActivity = null;
+ }
}
}
/**
- * Indicates that the parent activity is currently paused.
+ * Testing method to update the state of the specified activity.
+ */
+ public static void onStateChangeForTesting(Activity activity, int newState) {
+ onStateChange(activity, newState);
+ }
+
+ /**
+ * Indicates that the current activity is paused.
+ *
+ * Use explicit state checking instead.
*/
+ @Deprecated
public static boolean isPaused() {
- return sActivityState == PAUSED;
+ if (sActivity == null) return false;
+ Integer currentStatus = sActivityStates.get(sActivity);
+ return currentStatus != null && currentStatus.intValue() == PAUSED;
}
/**
- * Returns the current main application activity.
+ * @return The current activity.
*/
public static Activity getActivity() {
return sActivity;
}
/**
- * Returns the current main application activity's state.
+ * @return The current activity's state (if no activity is registered, then DESTROYED will
+ * be returned).
*/
public static int getState() {
- return sActivityState;
+ return getStateForActivity(sActivity);
+ }
+
+ /**
+ * Query the state for a given activity. If the activity is not being tracked, this will
+ * return {@link #DESTROYED}.
+ *
+ * <p>
+ * When relying on this method, be familiar with the expected life cycle state
+ * transitions:
+ * <a href="http://developer.android.com/guide/components/activities.html#Lifecycle">
+ * Activity Lifecycle
+ * </a>
+ *
+ * <p>
+ * During activity transitions (activity B launching in front of activity A), A will completely
+ * paused before the creation of activity B begins.
+ *
+ * <p>
+ * A basic flow for activity A starting, followed by activity B being opened and then closed:
+ * <ul>
+ * <li> -- Starting Activity A --
+ * <li> Activity A - CREATED
+ * <li> Activity A - STARTED
+ * <li> Activity A - RESUMED
+ * <li> -- Staring Activity B --
+ * <li> Activity A - PAUSED
+ * <li> Activity B - CREATED
+ * <li> Activity B - STARTED
+ * <li> Activity B - RESUMED
+ * <li> Activity A - STOPPED
+ * <li> -- Closing Activity B, Activity A regaining focus --
+ * <li> Activity B - PAUSED
+ * <li> Activity A - STARTED
+ * <li> Activity A - RESUMED
+ * <li> Activity B - STOPPED
+ * <li> Activity B - DESTROYED
+ * </ul>
+ *
+ * @param activity The activity whose state is to be returned.
+ * @return The state of the specified activity.
+ */
+ public static int getStateForActivity(Activity activity) {
+ Integer currentStatus = sActivityStates.get(activity);
+ return currentStatus != null ? currentStatus.intValue() : DESTROYED;
}
/**
diff --git a/base/android/java/src/org/chromium/base/ChromiumActivity.java b/base/android/java/src/org/chromium/base/ChromiumActivity.java
deleted file mode 100644
index 65f5ce9..0000000
--- a/base/android/java/src/org/chromium/base/ChromiumActivity.java
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.base;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-// All Chromium main activities should extend this class. This allows various sub-systems to
-// properly react to activity state changes.
-public class ChromiumActivity extends Activity {
-
- @Override
- protected void onCreate(Bundle savedInstance) {
- super.onCreate(savedInstance);
- ActivityStatus.onStateChange(this, ActivityStatus.CREATED);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- ActivityStatus.onStateChange(this, ActivityStatus.STARTED);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- ActivityStatus.onStateChange(this, ActivityStatus.RESUMED);
- }
-
- @Override
- protected void onPause() {
- ActivityStatus.onStateChange(this, ActivityStatus.PAUSED);
- super.onPause();
- }
-
- @Override
- protected void onStop() {
- ActivityStatus.onStateChange(this, ActivityStatus.STOPPED);
- super.onStop();
- }
-
- @Override
- protected void onDestroy() {
- ActivityStatus.onStateChange(this, ActivityStatus.DESTROYED);
- super.onDestroy();
- }
-}
diff --git a/base/android/java/src/org/chromium/base/ChromiumApplication.java b/base/android/java/src/org/chromium/base/ChromiumApplication.java
new file mode 100644
index 0000000..7c2b957
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ChromiumApplication.java
@@ -0,0 +1,20 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Application;
+
+/**
+ * Basic application functionality that should be shared among all browser applications.
+ */
+public class ChromiumApplication extends Application {
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ ActivityStatus.initialize(this);
+ }
+
+}
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java
index 8672ba9..f32fe46 100644
--- a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellActivity.java
@@ -4,6 +4,7 @@
package org.chromium.chrome.testshell;
+import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
@@ -14,7 +15,6 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
-import org.chromium.base.ChromiumActivity;
import org.chromium.base.MemoryPressureListener;
import org.chromium.chrome.browser.DevToolsServer;
import org.chromium.chrome.testshell.sync.SyncController;
@@ -31,7 +31,7 @@ import org.chromium.ui.WindowAndroid;
/**
* The {@link android.app.Activity} component of a basic test shell to test Chrome features.
*/
-public class ChromiumTestShellActivity extends ChromiumActivity implements MenuHandler {
+public class ChromiumTestShellActivity extends Activity implements MenuHandler {
private static final String TAG = "ChromiumTestShellActivity";
/**
* Sending an intent with this action will simulate a memory pressure signal
diff --git a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplication.java b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplication.java
index 8f0c1de..d0f0125 100644
--- a/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplication.java
+++ b/chrome/android/testshell/java/src/org/chromium/chrome/testshell/ChromiumTestShellApplication.java
@@ -4,9 +4,9 @@
package org.chromium.chrome.testshell;
-import android.app.Application;
import android.content.Intent;
+import org.chromium.base.ChromiumApplication;
import org.chromium.base.PathUtils;
import org.chromium.chrome.browser.UmaUtils;
import org.chromium.content.browser.ResourceExtractor;
@@ -15,10 +15,10 @@ import org.chromium.content.common.CommandLine;
import java.util.ArrayList;
/**
- * A basic test shell {@link Application}. Handles setting up the native library and
+ * A basic test shell {@link android.app.Application}. Handles setting up the native library and
* loading the right resources.
*/
-public class ChromiumTestShellApplication extends Application {
+public class ChromiumTestShellApplication extends ChromiumApplication {
private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "chromiumtestshell";
private static final String[] CHROME_MANDATORY_PAKS = {
"en-US.pak",
diff --git a/content/public/android/java/src/org/chromium/content/browser/LocationProvider.java b/content/public/android/java/src/org/chromium/content/browser/LocationProvider.java
index 8b8eb29..300bfa5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/LocationProvider.java
+++ b/content/public/android/java/src/org/chromium/content/browser/LocationProvider.java
@@ -73,7 +73,11 @@ class LocationProvider {
ActivityStatus.registerStateListener(this);
}
mIsGpsEnabled = gpsEnabled;
- if (ActivityStatus.isPaused()) {
+
+ int activityState = ActivityStatus.getState();
+ if (activityState == ActivityStatus.PAUSED
+ || activityState == ActivityStatus.STOPPED
+ || activityState == ActivityStatus.DESTROYED) {
mShouldRunAfterActivityResume = true;
} else {
unregisterFromLocationUpdates();
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/LocationProviderTest.java b/content/public/android/javatests/src/org/chromium/content/browser/LocationProviderTest.java
index 5dde1f2..0e417f5 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/LocationProviderTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/LocationProviderTest.java
@@ -4,6 +4,7 @@
package org.chromium.content.browser;
+import android.app.Activity;
import android.test.UiThreadTest;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -15,10 +16,12 @@ import org.chromium.base.test.util.Feature;
* Test suite for LocationProvider.
*/
public class LocationProviderTest extends InstrumentationTestCase {
+ private Activity mActivity;
private LocationProvider mLocationProvider;
@Override
public void setUp() {
+ mActivity = new Activity();
mLocationProvider = LocationProvider.create(getInstrumentation().getTargetContext());
}
@@ -29,6 +32,7 @@ public class LocationProviderTest extends InstrumentationTestCase {
@UiThreadTest
@Feature({"Location"})
public void testStartStop() throws Exception {
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.RESUMED);
mLocationProvider.start(false);
assertTrue("Should be running", mLocationProvider.isRunning());
mLocationProvider.stop();
@@ -42,6 +46,7 @@ public class LocationProviderTest extends InstrumentationTestCase {
@UiThreadTest
@Feature({"Location"})
public void testStartUpgradeStop() throws Exception {
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.RESUMED);
mLocationProvider.start(false);
assertTrue("Should be running", mLocationProvider.isRunning());
mLocationProvider.start(true);
@@ -58,11 +63,12 @@ public class LocationProviderTest extends InstrumentationTestCase {
@UiThreadTest
@Feature({"Location"})
public void testStartPauseResumeStop() throws Exception {
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.RESUMED);
mLocationProvider.start(false);
assertTrue("Should be running", mLocationProvider.isRunning());
- ActivityStatus.onStateChange(null, ActivityStatus.PAUSED);
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.PAUSED);
assertFalse("Should have paused", mLocationProvider.isRunning());
- ActivityStatus.onStateChange(null, ActivityStatus.RESUMED);
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.RESUMED);
assertTrue("Should have resumed", mLocationProvider.isRunning());
mLocationProvider.stop();
assertFalse("Should have stopped", mLocationProvider.isRunning());
@@ -76,10 +82,27 @@ public class LocationProviderTest extends InstrumentationTestCase {
@UiThreadTest
@Feature({"Location"})
public void testPauseStartResumeStop() throws Exception {
- ActivityStatus.onStateChange(null, ActivityStatus.PAUSED);
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.PAUSED);
mLocationProvider.start(false);
assertFalse("Should not be running", mLocationProvider.isRunning());
- ActivityStatus.onStateChange(null, ActivityStatus.RESUMED);
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.RESUMED);
+ assertTrue("Should have resumed", mLocationProvider.isRunning());
+ mLocationProvider.stop();
+ assertFalse("Should have stopped", mLocationProvider.isRunning());
+ }
+
+ /**
+ * Verify that calling start when the activity is stopped doesn't start listening
+ * for location updates until activity resumes.
+ */
+ @SmallTest
+ @UiThreadTest
+ @Feature({"Location"})
+ public void testPauseStopStartResumeStop() throws Exception {
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.STOPPED);
+ mLocationProvider.start(false);
+ assertFalse("Should not be running", mLocationProvider.isRunning());
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.RESUMED);
assertTrue("Should have resumed", mLocationProvider.isRunning());
mLocationProvider.stop();
assertFalse("Should have stopped", mLocationProvider.isRunning());
@@ -92,13 +115,14 @@ public class LocationProviderTest extends InstrumentationTestCase {
@UiThreadTest
@Feature({"Location"})
public void testStartPauseUpgradeResumeStop() throws Exception {
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.RESUMED);
mLocationProvider.start(false);
assertTrue("Should be running", mLocationProvider.isRunning());
- ActivityStatus.onStateChange(null, ActivityStatus.PAUSED);
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.PAUSED);
assertFalse("Should have paused", mLocationProvider.isRunning());
mLocationProvider.start(true);
assertFalse("Should be paused", mLocationProvider.isRunning());
- ActivityStatus.onStateChange(null, ActivityStatus.RESUMED);
+ ActivityStatus.onStateChangeForTesting(mActivity, ActivityStatus.RESUMED);
assertTrue("Should have resumed", mLocationProvider.isRunning());
mLocationProvider.stop();
assertFalse("Should have stopped", mLocationProvider.isRunning());
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
index c98ba12..f6720b6 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellActivity.java
@@ -4,6 +4,7 @@
package org.chromium.content_shell_apk;
+import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -14,7 +15,6 @@ import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
-import org.chromium.base.ChromiumActivity;
import org.chromium.base.MemoryPressureListener;
import org.chromium.content.app.LibraryLoader;
import org.chromium.content.browser.ActivityContentVideoViewClient;
@@ -33,7 +33,7 @@ import org.chromium.ui.WindowAndroid;
/**
* Activity for managing the Content Shell.
*/
-public class ContentShellActivity extends ChromiumActivity {
+public class ContentShellActivity extends Activity {
public static final String COMMAND_LINE_FILE = "/data/local/tmp/content-shell-command-line";
private static final String TAG = "ContentShellActivity";
diff --git a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
index ddbe76f..284f412 100644
--- a/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
+++ b/content/shell/android/shell_apk/src/org/chromium/content_shell_apk/ContentShellApplication.java
@@ -4,17 +4,15 @@
package org.chromium.content_shell_apk;
-import android.app.Application;
-
+import org.chromium.base.ChromiumApplication;
import org.chromium.base.PathUtils;
-import org.chromium.content.app.LibraryLoader;
import org.chromium.content.browser.ResourceExtractor;
/**
* Entry point for the content shell application. Handles initialization of information that needs
* to be shared across the main activity and the child services created.
*/
-public class ContentShellApplication extends Application {
+public class ContentShellApplication extends ChromiumApplication {
private static final String[] MANDATORY_PAK_FILES = new String[] {"content_shell.pak"};
private static final String PRIVATE_DATA_DIRECTORY_SUFFIX = "content_shell";
diff --git a/testing/android/AndroidManifest.xml b/testing/android/AndroidManifest.xml
index 73a0c14..a1afb56 100644
--- a/testing/android/AndroidManifest.xml
+++ b/testing/android/AndroidManifest.xml
@@ -12,7 +12,8 @@ found in the LICENSE file.
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="17" />
- <application android:label="ChromeNativeTests">
+ <application android:label="ChromeNativeTests"
+ android:name="org.chromium.base.ChromiumApplication">
<activity android:name=".ChromeNativeTestActivity"
android:label="ChromeNativeTest"
android:configChanges="orientation|keyboardHidden">
diff --git a/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
index 6486a14..b8e41c83 100644
--- a/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
+++ b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
@@ -7,23 +7,18 @@ package org.chromium.native_test;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
-import android.os.Environment;
import android.os.Handler;
import android.util.Log;
-import org.chromium.base.ChromiumActivity;
import org.chromium.base.PathUtils;
import org.chromium.base.PowerMonitor;
-
// TODO(cjhopman): This should not refer to content. NativeLibraries should be moved to base.
import org.chromium.content.app.NativeLibraries;
-import java.io.File;
-
// Android's NativeActivity is mostly useful for pure-native code.
// Our tests need to go up to our own java classes, which is not possible using
// the native activity class loader.
-public class ChromeNativeTestActivity extends ChromiumActivity {
+public class ChromeNativeTestActivity extends Activity {
private static final String TAG = "ChromeNativeTestActivity";
private static final String EXTRA_RUN_IN_SUB_THREAD = "RunInSubThread";
// We post a delayed task to run tests so that we do not block onCreate().