diff options
author | digit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-07 16:59:34 +0000 |
---|---|---|
committer | digit@chromium.org <digit@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-07 16:59:34 +0000 |
commit | f1bdf1c72a39f47c133f7a45ff441849ec8b496b (patch) | |
tree | db89f58152e350dd2afc52b127f7773e39c6b0f3 | |
parent | cbf03ba141434e753c517370696d93b43d8582d5 (diff) | |
download | chromium_src-f1bdf1c72a39f47c133f7a45ff441849ec8b496b.zip chromium_src-f1bdf1c72a39f47c133f7a45ff441849ec8b496b.tar.gz chromium_src-f1bdf1c72a39f47c133f7a45ff441849ec8b496b.tar.bz2 |
android: Improve ActivityStatus and add ChromiumActivity.
The ActivityStatus class used to track activity state changes is too basic
for some usage scenarios.
This patch does the following:
- Augment ActivityStatus with a new StateListener type that can be
registered to listen to all activity state changes.
Also add getActivity(), getState(), registerStateListener()
and unregisterStateListener() as static method.
- Add a new ChromiumActivity class that all Chromium main activities
should sub-class, to ensure that the ActivityStatus state is updated
appropriately.
- Modify all main activities in the Chromium code base to extend
from ChromiumActivity instead of Activity.
BUG=none
Review URL: https://chromiumcodereview.appspot.com/11419287
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@171789 0039d316-1c4b-4281-b951-d872f2087c98
8 files changed, 191 insertions, 43 deletions
diff --git a/base/android/java/src/org/chromium/base/ActivityStatus.java b/base/android/java/src/org/chromium/base/ActivityStatus.java index 765d841..b80c149 100644 --- a/base/android/java/src/org/chromium/base/ActivityStatus.java +++ b/base/android/java/src/org/chromium/base/ActivityStatus.java @@ -4,6 +4,7 @@ package org.chromium.base; +import android.app.Activity; import android.os.Looper; import java.util.ArrayList; @@ -12,55 +13,137 @@ import java.util.ArrayList; * Provides information about the parent activity's status. */ public class ActivityStatus { + + // Constants matching activity states reported to StateListener.onStateChange + public static final int CREATED = 1; + public static final int STARTED = 2; + public static final int RESUMED = 3; + public static final int PAUSED = 4; + public static final int STOPPED = 5; + public static final int DESTROYED = 6; + + // Current main activity, or null if none. + 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; + + // Current activity instance, or null. + private static ActivityStatus sInstance; + + // List of pause/resume listeners. + private final ArrayList<Listener> mListeners; + + // List of state listeners. + private final ArrayList<StateListener> mStateListeners; + + protected ActivityStatus() { + mListeners = new ArrayList<Listener>(); + mStateListeners = new ArrayList<StateListener>(); + } + + /** + * Must be called by the main activity when it changes state. + * @param activity Current activity. + * @param newState New state value. + */ + public static void onStateChange(Activity activity, int newState) { + if (newState == CREATED) { + sActivity = activity; + } + sActivityState = newState; + getInstance().changeState(newState); + + if (newState == DESTROYED) { + sActivity = null; + } + } + + private void changeState(int newState) { + for (StateListener listener : mStateListeners) { + listener.onActivityStateChange(newState); + } + if (newState == PAUSED || newState == RESUMED) { + boolean paused = (newState == PAUSED); + for (Listener listener : mListeners) { + listener.onActivityStatusChanged(paused); + } + } + } + + // This interface can only be used to listen to PAUSED and RESUMED + // events. Deprecated, new code should use StateListener instead. + // TODO(digit): Remove once all users have switched to StateListener. + @Deprecated public interface Listener { /** - * Called when the activity's status changes. + * Called when the activity is paused or resumed only. * @param isPaused true if the activity is paused, false if not. */ public void onActivityStatusChanged(boolean isPaused); } - private boolean mIsPaused = false; - private ArrayList<Listener> mListeners = new ArrayList<Listener>(); - private static ActivityStatus sActivityStatus; - - private ActivityStatus() { + // Use this interface to listen to all state changes. + public interface StateListener { + /** + * Called when the activity's state changes. + * @param newState New activity state. + */ + public void onActivityStateChange(int newState); } + /** + * Returns the current ActivityStatus instance. + */ public static ActivityStatus getInstance() { // Can only be called on the UI thread. assert Looper.myLooper() == Looper.getMainLooper(); - if (sActivityStatus == null) { - sActivityStatus = new ActivityStatus(); + if (sInstance == null) { + sInstance = new ActivityStatus(); } - return sActivityStatus; + return sInstance; } /** * Indicates that the parent activity was paused. */ public void onPause() { - mIsPaused = true; - informAllListeners(); + changeState(PAUSED); } /** * Indicates that the parent activity was resumed. */ public void onResume() { - mIsPaused = false; - informAllListeners(); + changeState(RESUMED); } /** * Indicates that the parent activity is currently paused. */ public boolean isPaused() { - return mIsPaused; + return sActivityState == PAUSED; + } + + /** + * Returns the current main application activity. + */ + public static Activity getActivity() { + return sActivity; + } + + /** + * Returns the current main application activity's state. + */ + public static int getState() { + // To simplify unit testing, don't check sActivity for null. + return sActivityState; } /** - * Registers the given listener to receive activity status updates. + * Registers the given pause/resume listener to receive activity + * status updates. Use registerStateListener() instead. * @param listener Listener to receive status updates. */ public void registerListener(Listener listener) { @@ -68,16 +151,29 @@ public class ActivityStatus { } /** - * Unregisters the given listener from receiving activity status updates. + * Unregisters the given pause/resume listener from receiving activity + * status updates. Use unregisterStateListener() instead. * @param listener Listener that doesn't want to receive status updates. */ public void unregisterListener(Listener listener) { mListeners.remove(listener); } - private void informAllListeners() { - for (Listener listener : mListeners) { - listener.onActivityStatusChanged(mIsPaused); - } + /** + * Registers the given listener to receive activity state changes. + * @param listener Listener to receive state changes. + */ + public static void registerStateListener(StateListener listener) { + ActivityStatus status = getInstance(); + status.mStateListeners.add(listener); + } + + /** + * Unregisters the given listener from receiving activity state changes. + * @param listener Listener that doesn't want to receive state changes. + */ + public static void unregisterStateListener(StateListener listener) { + ActivityStatus status = getInstance(); + status.mStateListeners.remove(listener); } } diff --git a/base/android/java/src/org/chromium/base/ChromiumActivity.java b/base/android/java/src/org/chromium/base/ChromiumActivity.java new file mode 100644 index 0000000..f857e12 --- /dev/null +++ b/base/android/java/src/org/chromium/base/ChromiumActivity.java @@ -0,0 +1,50 @@ +// 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.STARTED); + } + + @Override + protected void onPause() { + ActivityStatus.onStateChange(this, ActivityStatus.STARTED); + super.onPause(); + } + + @Override + protected void onStop() { + ActivityStatus.onStateChange(this, ActivityStatus.STARTED); + super.onStop(); + } + + @Override + protected void onDestroy() { + ActivityStatus.onStateChange(this, ActivityStatus.DESTROYED); + super.onDestroy(); + } +} 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 68f9f04..e754bb8 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 @@ -11,6 +11,7 @@ import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; +import org.chromium.base.ChromiumActivity; import org.chromium.chrome.browser.DevToolsServer; import org.chromium.chrome.browser.TabBase; import org.chromium.content.app.LibraryLoader; @@ -22,7 +23,7 @@ import org.chromium.ui.gfx.ActivityNativeWindow; /** * The {@link Activity} component of a basic test shell to test Chrome features. */ -public class ChromiumTestShellActivity extends Activity { +public class ChromiumTestShellActivity extends ChromiumActivity { private static final String TAG = ChromiumTestShellActivity.class.getCanonicalName(); private static final String COMMAND_LINE_FILE = "/data/local/tmp/chromium-testshell-command-line"; 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 75be3dd..6efcb95 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 @@ -37,7 +37,7 @@ class LocationProvider { * ensures that the start/stop calls into this class are done in the UI thread. */ private static class LocationProviderImpl - implements LocationListener, ActivityStatus.Listener { + implements LocationListener, ActivityStatus.StateListener { private Context mContext; private LocationManager mLocationManager; @@ -49,11 +49,11 @@ class LocationProvider { mContext = context; } - public void onActivityStatusChanged(boolean isPaused) { - if (isPaused) { + public void onActivityStateChange(int state) { + if (state == ActivityStatus.PAUSED) { mShouldRunAfterActivityResume = mIsRunning; unregisterFromLocationUpdates(); - } else { + } else if (state == ActivityStatus.RESUMED) { assert !mIsRunning; if (mShouldRunAfterActivityResume) { registerForLocationUpdates(); @@ -68,7 +68,7 @@ class LocationProvider { private void start(boolean gpsEnabled) { if (!mIsRunning && !mShouldRunAfterActivityResume) { // Currently idle so start listening to activity status changes. - ActivityStatus.getInstance().registerListener(this); + ActivityStatus.registerStateListener(this); } mIsGpsEnabled = gpsEnabled; if (ActivityStatus.getInstance().isPaused()) { @@ -84,7 +84,7 @@ class LocationProvider { */ private void stop() { unregisterFromLocationUpdates(); - ActivityStatus.getInstance().unregisterListener(this); + ActivityStatus.unregisterStateListener(this); mShouldRunAfterActivityResume = false; } 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 0fa6c06..5dde1f2 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 @@ -60,9 +60,9 @@ public class LocationProviderTest extends InstrumentationTestCase { public void testStartPauseResumeStop() throws Exception { mLocationProvider.start(false); assertTrue("Should be running", mLocationProvider.isRunning()); - ActivityStatus.getInstance().onPause(); + ActivityStatus.onStateChange(null, ActivityStatus.PAUSED); assertFalse("Should have paused", mLocationProvider.isRunning()); - ActivityStatus.getInstance().onResume(); + ActivityStatus.onStateChange(null, ActivityStatus.RESUMED); assertTrue("Should have resumed", mLocationProvider.isRunning()); mLocationProvider.stop(); assertFalse("Should have stopped", mLocationProvider.isRunning()); @@ -76,10 +76,10 @@ public class LocationProviderTest extends InstrumentationTestCase { @UiThreadTest @Feature({"Location"}) public void testPauseStartResumeStop() throws Exception { - ActivityStatus.getInstance().onPause(); + ActivityStatus.onStateChange(null, ActivityStatus.PAUSED); mLocationProvider.start(false); assertFalse("Should not be running", mLocationProvider.isRunning()); - ActivityStatus.getInstance().onResume(); + ActivityStatus.onStateChange(null, ActivityStatus.RESUMED); assertTrue("Should have resumed", mLocationProvider.isRunning()); mLocationProvider.stop(); assertFalse("Should have stopped", mLocationProvider.isRunning()); @@ -94,11 +94,11 @@ public class LocationProviderTest extends InstrumentationTestCase { public void testStartPauseUpgradeResumeStop() throws Exception { mLocationProvider.start(false); assertTrue("Should be running", mLocationProvider.isRunning()); - ActivityStatus.getInstance().onPause(); + ActivityStatus.onStateChange(null, ActivityStatus.PAUSED); assertFalse("Should have paused", mLocationProvider.isRunning()); mLocationProvider.start(true); assertFalse("Should be paused", mLocationProvider.isRunning()); - ActivityStatus.getInstance().onResume(); + ActivityStatus.onStateChange(null, ActivityStatus.RESUMED); assertTrue("Should have resumed", mLocationProvider.isRunning()); mLocationProvider.stop(); assertFalse("Should have stopped", mLocationProvider.isRunning()); diff --git a/content/shell/android/java/src/org/chromium/content_shell/ContentShellActivity.java b/content/shell/android/java/src/org/chromium/content_shell/ContentShellActivity.java index 22456af..bddb70f 100644 --- a/content/shell/android/java/src/org/chromium/content_shell/ContentShellActivity.java +++ b/content/shell/android/java/src/org/chromium/content_shell/ContentShellActivity.java @@ -11,6 +11,7 @@ import android.text.TextUtils; import android.util.Log; import android.view.KeyEvent; +import org.chromium.base.ChromiumActivity; import org.chromium.content.app.LibraryLoader; import org.chromium.content.browser.ActivityContentVideoViewDelegate; import org.chromium.content.browser.ContentVideoView; @@ -22,7 +23,7 @@ import org.chromium.ui.gfx.ActivityNativeWindow; /** * Activity for managing the Content Shell. */ -public class ContentShellActivity extends Activity { +public class ContentShellActivity extends ChromiumActivity { public static final String COMMAND_LINE_FILE = "/data/local/tmp/content-shell-command-line"; private static final String TAG = ContentShellActivity.class.getName(); diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java index c5fd033..90aa753 100644 --- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java +++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java @@ -21,7 +21,7 @@ import org.chromium.base.ActivityStatus; * ACCESS_NETWORK_STATE permission. */ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver - implements ActivityStatus.Listener { + implements ActivityStatus.StateListener { /** Queries the ConnectivityManager for information about the current connection. */ static class ConnectivityManagerDelegate { @@ -73,11 +73,10 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver mConnectivityManagerDelegate = new ConnectivityManagerDelegate(context); mConnectionType = currentConnectionType(context); - ActivityStatus status = ActivityStatus.getInstance(); - if (!status.isPaused()) { + if (ActivityStatus.getState() != ActivityStatus.PAUSED) { registerReceiver(); } - status.registerListener(this); + ActivityStatus.registerStateListener(this); } /** @@ -168,12 +167,12 @@ public class NetworkChangeNotifierAutoDetect extends BroadcastReceiver } } - // AcitivityStatus.Listener + // ActivityStatus.StateListener @Override - public void onActivityStatusChanged(boolean isPaused) { - if (isPaused) { + public void onActivityStateChange(int state) { + if (state == ActivityStatus.PAUSED) { unregisterReceiver(); - } else { + } else if (state == ActivityStatus.RESUMED) { registerReceiver(); } } 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 77022506..fef3dce 100644 --- a/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java +++ b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java @@ -11,6 +11,7 @@ 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.SystemMonitor; @@ -19,7 +20,7 @@ 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 Activity { +public class ChromeNativeTestActivity extends ChromiumActivity { private final String TAG = "ChromeNativeTestActivity"; private final String EXTRA_RUN_IN_SUB_THREAD = "RunInSubThread"; // We post a delayed task to run tests so that we do not block onCreate(). |