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(). | 
