Introduce persistent forms of Activity lifecycle calls.
When an Activity is created with R.attr.persistable true different
forms of activity lifecycle methods including PersistableBundle will
be used.
Fixes bug 13736007.
Change-Id: I7e92917b300b76964257cfcc26c24e76aa19bd16
diff --git a/api/current.txt b/api/current.txt
index d9add0b..34ece93 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3256,6 +3256,7 @@
method public boolean onContextItemSelected(android.view.MenuItem);
method public void onContextMenuClosed(android.view.Menu);
method protected void onCreate(android.os.Bundle);
+ method protected void onCreate(android.os.Bundle, android.os.PersistableBundle);
method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo);
method public java.lang.CharSequence onCreateDescription();
method protected deprecated android.app.Dialog onCreateDialog(int);
@@ -3286,6 +3287,7 @@
method public void onPanelClosed(int, android.view.Menu);
method protected void onPause();
method protected void onPostCreate(android.os.Bundle);
+ method protected void onPostCreate(android.os.Bundle, android.os.PersistableBundle);
method protected void onPostResume();
method protected deprecated void onPrepareDialog(int, android.app.Dialog);
method protected deprecated void onPrepareDialog(int, android.app.Dialog, android.os.Bundle);
@@ -3295,9 +3297,11 @@
method public void onProvideAssistData(android.os.Bundle);
method protected void onRestart();
method protected void onRestoreInstanceState(android.os.Bundle);
+ method protected void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle);
method protected void onResume();
method public deprecated java.lang.Object onRetainNonConfigurationInstance();
method protected void onSaveInstanceState(android.os.Bundle);
+ method protected void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle);
method public boolean onSearchRequested();
method protected void onStart();
method protected void onStop();
@@ -4191,14 +4195,18 @@
method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean);
method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean);
method public void callActivityOnCreate(android.app.Activity, android.os.Bundle);
+ method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnDestroy(android.app.Activity);
method public void callActivityOnNewIntent(android.app.Activity, android.content.Intent);
method public void callActivityOnPause(android.app.Activity);
method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle);
+ method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnRestart(android.app.Activity);
method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle);
+ method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnResume(android.app.Activity);
method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle);
+ method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle);
method public void callActivityOnStart(android.app.Activity);
method public void callActivityOnStop(android.app.Activity);
method public void callActivityOnUserLeaving(android.app.Activity);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index af3a92c..2a9dcfe 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
package android.app;
import android.annotation.NonNull;
+import android.os.PersistableBundle;
import android.transition.Scene;
import android.transition.TransitionManager;
import android.util.ArrayMap;
@@ -921,6 +922,30 @@
}
/**
+ * Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with
+ * the attribute {@link android.R.attr#persistable} set true.
+ *
+ * @param savedInstanceState if the activity is being re-initialized after
+ * previously being shut down then this Bundle contains the data it most
+ * recently supplied in {@link #onSaveInstanceState}.
+ * <b><i>Note: Otherwise it is null.</i></b>
+ * @param persistentState if the activity is being re-initialized after
+ * previously being shut down or powered off then this Bundle contains the data it most
+ * recently supplied to outPersistentState in {@link #onSaveInstanceState}.
+ * <b><i>Note: Otherwise it is null.</i></b>
+ *
+ * @see #onCreate(android.os.Bundle)
+ * @see #onStart
+ * @see #onSaveInstanceState
+ * @see #onRestoreInstanceState
+ * @see #onPostCreate
+ */
+ protected void onCreate(@Nullable Bundle savedInstanceState,
+ @Nullable PersistableBundle persistentState) {
+ onCreate(savedInstanceState);
+ }
+
+ /**
* The hook for {@link ActivityThread} to restore the state of this activity.
*
* Calls {@link #onSaveInstanceState(android.os.Bundle)} and
@@ -934,6 +959,23 @@
}
/**
+ * The hook for {@link ActivityThread} to restore the state of this activity.
+ *
+ * Calls {@link #onSaveInstanceState(android.os.Bundle)} and
+ * {@link #restoreManagedDialogs(android.os.Bundle)}.
+ *
+ * @param savedInstanceState contains the saved state
+ * @param persistentState contains the persistable saved state
+ */
+ final void performRestoreInstanceState(Bundle savedInstanceState,
+ PersistableBundle persistentState) {
+ onRestoreInstanceState(savedInstanceState, persistentState);
+ if (savedInstanceState != null) {
+ restoreManagedDialogs(savedInstanceState);
+ }
+ }
+
+ /**
* This method is called after {@link #onStart} when the activity is
* being re-initialized from a previously saved state, given here in
* <var>savedInstanceState</var>. Most implementations will simply use {@link #onCreate}
@@ -961,7 +1003,34 @@
}
}
}
-
+
+ /**
+ * This is the same as {@link #onRestoreInstanceState(Bundle)} but is called for activities
+ * created with the attribute {@link android.R.attr#persistable}. The {@link
+ * android.os.PersistableBundle} passed came from the restored PersistableBundle first
+ * saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
+ *
+ * <p>This method is called between {@link #onStart} and
+ * {@link #onPostCreate}.
+ *
+ * <p>If this method is called {@link #onRestoreInstanceState(Bundle)} will not be called.
+ *
+ * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
+ * @param persistentState the data most recently supplied in {@link #onSaveInstanceState}.
+ *
+ * @see #onRestoreInstanceState(Bundle)
+ * @see #onCreate
+ * @see #onPostCreate
+ * @see #onResume
+ * @see #onSaveInstanceState
+ */
+ protected void onRestoreInstanceState(Bundle savedInstanceState,
+ PersistableBundle persistentState) {
+ if (savedInstanceState != null) {
+ onRestoreInstanceState(savedInstanceState);
+ }
+ }
+
/**
* Restore the state of any saved managed dialogs.
*
@@ -1038,6 +1107,21 @@
}
/**
+ * This is the same as {@link #onPostCreate(Bundle)} but is called for activities
+ * created with the attribute {@link android.R.attr#persistable}.
+ *
+ * @param savedInstanceState The data most recently supplied in {@link #onSaveInstanceState}
+ * @param persistentState The data caming from the PersistableBundle first
+ * saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}.
+ *
+ * @see #onCreate
+ */
+ protected void onPostCreate(@Nullable Bundle savedInstanceState,
+ @Nullable PersistableBundle persistentState) {
+ onPostCreate(savedInstanceState);
+ }
+
+ /**
* Called after {@link #onCreate} — or after {@link #onRestart} when
* the activity had been stopped, but is now again being displayed to the
* user. It will be followed by {@link #onResume}.
@@ -1193,6 +1277,22 @@
}
/**
+ * The hook for {@link ActivityThread} to save the state of this activity.
+ *
+ * Calls {@link #onSaveInstanceState(android.os.Bundle)}
+ * and {@link #saveManagedDialogs(android.os.Bundle)}.
+ *
+ * @param outState The bundle to save the state to.
+ * @param outPersistentState The bundle to save persistent state to.
+ */
+ final void performSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
+ onSaveInstanceState(outState, outPersistentState);
+ saveManagedDialogs(outState);
+ if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState +
+ ", " + outPersistentState);
+ }
+
+ /**
* Called to retrieve per-instance state from an activity before being killed
* so that the state can be restored in {@link #onCreate} or
* {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method
@@ -1247,6 +1347,25 @@
}
/**
+ * This is the same as {@link #onSaveInstanceState} but is called for activities
+ * created with the attribute {@link android.R.attr#persistable}. The {@link
+ * android.os.PersistableBundle} passed in will be saved and presented in
+ * {@link #onCreate(Bundle, PersistableBundle)} the first time that this activity
+ * is restarted following the next device reboot.
+ *
+ * @param outState Bundle in which to place your saved state.
+ * @param outPersistentState State which will be saved across reboots.
+ *
+ * @see #onSaveInstanceState(Bundle)
+ * @see #onCreate
+ * @see #onRestoreInstanceState(Bundle, PersistableBundle)
+ * @see #onPause
+ */
+ protected void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
+ onSaveInstanceState(outState);
+ }
+
+ /**
* Save the state of any managed dialogs.
*
* @param outState place to store the saved state.
@@ -5487,13 +5606,22 @@
return mParent != null ? mParent.getActivityToken() : mToken;
}
- final void performCreate(Bundle icicle) {
- onCreate(icicle);
+ final void performCreateCommon() {
mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
}
+ final void performCreate(Bundle icicle) {
+ onCreate(icicle);
+ performCreateCommon();
+ }
+
+ final void performCreate(Bundle icicle, PersistableBundle persistentState) {
+ onCreate(icicle, persistentState);
+ performCreateCommon();
+ }
+
final void performStart() {
mFragments.noteStateNotSaved();
mCalled = false;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 57da21e..ec2868af 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -40,6 +40,7 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
@@ -454,7 +455,8 @@
case ACTIVITY_PAUSED_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
- activityPaused(token);
+ PersistableBundle persistentState = data.readPersistableBundle();
+ activityPaused(token, persistentState);
reply.writeNoException();
return true;
}
@@ -463,10 +465,9 @@
data.enforceInterface(IActivityManager.descriptor);
IBinder token = data.readStrongBinder();
Bundle map = data.readBundle();
- Bitmap thumbnail = data.readInt() != 0
- ? Bitmap.CREATOR.createFromParcel(data) : null;
+ PersistableBundle persistentState = data.readPersistableBundle();
CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
- activityStopped(token, map, thumbnail, description);
+ activityStopped(token, map, persistentState, description);
reply.writeNoException();
return true;
}
@@ -2583,31 +2584,27 @@
data.recycle();
reply.recycle();
}
- public void activityPaused(IBinder token) throws RemoteException
+ public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
+ data.writePersistableBundle(persistentState);
mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
public void activityStopped(IBinder token, Bundle state,
- Bitmap thumbnail, CharSequence description) throws RemoteException
+ PersistableBundle persistentState, CharSequence description) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
data.writeBundle(state);
- if (thumbnail != null) {
- data.writeInt(1);
- thumbnail.writeToParcel(data, 0);
- } else {
- data.writeInt(0);
- }
+ data.writePersistableBundle(persistentState);
TextUtils.writeToParcel(description, data, 0);
mRemote.transact(ACTIVITY_STOPPED_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 3b2ff7f..63594bf 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -56,11 +56,11 @@
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -69,8 +69,6 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
-import android.transition.Scene;
-import android.transition.TransitionManager;
import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
@@ -268,6 +266,7 @@
Intent intent;
IVoiceInteractor voiceInteractor;
Bundle state;
+ PersistableBundle persistentState;
Activity activity;
Window window;
Activity parent;
@@ -317,6 +316,10 @@
return false;
}
+ public boolean isPersistable() {
+ return (activityInfo.flags & ActivityInfo.FLAG_PERSISTABLE) != 0;
+ }
+
public String toString() {
ComponentName componentName = intent != null ? intent.getComponent() : null;
return "ActivityRecord{"
@@ -605,8 +608,8 @@
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
- IVoiceInteractor voiceInteractor,
- int procState, Bundle state, List<ResultInfo> pendingResults,
+ IVoiceInteractor voiceInteractor, int procState, Bundle state,
+ PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle resumeArgs) {
@@ -622,6 +625,7 @@
r.activityInfo = info;
r.compatInfo = compatInfo;
r.state = state;
+ r.persistentState = persistentState;
r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents;
@@ -2205,7 +2209,11 @@
}
activity.mCalled = false;
- mInstrumentation.callActivityOnCreate(activity, r.state);
+ if (r.isPersistable()) {
+ mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
+ } else {
+ mInstrumentation.callActivityOnCreate(activity, r.state);
+ }
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
@@ -2218,13 +2226,23 @@
r.stopped = false;
}
if (!r.activity.mFinished) {
- if (r.state != null) {
+ if (r.isPersistable()) {
+ if (r.state != null || r.persistentState != null) {
+ mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
+ r.persistentState);
+ }
+ } else if (r.state != null) {
mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
}
}
if (!r.activity.mFinished) {
activity.mCalled = false;
- mInstrumentation.callActivityOnPostCreate(activity, r.state);
+ if (r.isPersistable()) {
+ mInstrumentation.callActivityOnPostCreate(activity, r.state,
+ r.persistentState);
+ } else {
+ mInstrumentation.callActivityOnPostCreate(activity, r.state);
+ }
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
@@ -2842,6 +2860,7 @@
r.paused = false;
r.stopped = false;
r.state = null;
+ r.persistentState = null;
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
throw new RuntimeException(
@@ -3069,7 +3088,7 @@
// Tell the activity manager we have paused.
try {
- ActivityManagerNative.getDefault().activityPaused(token);
+ ActivityManagerNative.getDefault().activityPaused(token, r.persistentState);
} catch (RemoteException ex) {
}
}
@@ -3099,17 +3118,13 @@
+ r.intent.getComponent().toShortString());
Slog.e(TAG, e.getMessage(), e);
}
- Bundle state = null;
if (finished) {
r.activity.mFinished = true;
}
try {
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) {
- state = new Bundle();
- state.setAllowFds(false);
- mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
- r.state = state;
+ callCallActivityOnSaveInstanceState(r);
}
// Now we are idle.
r.activity.mCalled = false;
@@ -3145,7 +3160,7 @@
listeners.get(i).onPaused(r.activity);
}
- return state;
+ return !r.activity.mFinished && saveState ? r.state : null;
}
final void performStopActivity(IBinder token, boolean saveState) {
@@ -3156,7 +3171,7 @@
private static class StopInfo implements Runnable {
ActivityClientRecord activity;
Bundle state;
- Bitmap thumbnail;
+ PersistableBundle persistentState;
CharSequence description;
@Override public void run() {
@@ -3164,7 +3179,7 @@
try {
if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity);
ActivityManagerNative.getDefault().activityStopped(
- activity.token, state, thumbnail, description);
+ activity.token, state, persistentState, description);
} catch (RemoteException ex) {
}
}
@@ -3203,7 +3218,6 @@
private void performStopActivityInner(ActivityClientRecord r,
StopInfo info, boolean keepShown, boolean saveState) {
if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
- Bundle state = null;
if (r != null) {
if (!keepShown && r.stopped) {
if (r.activity.mFinished) {
@@ -3223,7 +3237,6 @@
// First create a thumbnail for the activity...
// For now, don't create the thumbnail here; we are
// doing that by doing a screen snapshot.
- info.thumbnail = null; //createThumbnailBitmap(r);
info.description = r.activity.onCreateDescription();
} catch (Exception e) {
if (!mInstrumentation.onException(r.activity, e)) {
@@ -3238,12 +3251,7 @@
// Next have the activity save its current state and managed dialogs...
if (!r.activity.mFinished && saveState) {
if (r.state == null) {
- state = new Bundle();
- state.setAllowFds(false);
- mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
- r.state = state;
- } else {
- state = r.state;
+ callCallActivityOnSaveInstanceState(r);
}
}
@@ -3319,6 +3327,7 @@
// manager to proceed and allow us to go fully into the background.
info.activity = r;
info.state = r.state;
+ info.persistentState = r.persistentState;
mH.post(info);
}
@@ -3775,9 +3784,7 @@
performPauseActivity(r.token, false, r.isPreHoneycomb());
}
if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
- r.state = new Bundle();
- r.state.setAllowFds(false);
- mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
+ callCallActivityOnSaveInstanceState(r);
}
handleDestroyActivity(r.token, false, configChanges, true);
@@ -3807,6 +3814,18 @@
handleLaunchActivity(r, currentIntent);
}
+ private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
+ r.state = new Bundle();
+ r.state.setAllowFds(false);
+ if (r.isPersistable()) {
+ r.persistentState = new PersistableBundle();
+ mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
+ r.persistentState);
+ } else {
+ mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
+ }
+ }
+
ArrayList<ComponentCallbacks2> collectComponentCallbacks(
boolean allActivities, Configuration newConfig) {
ArrayList<ComponentCallbacks2> callbacks
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 7f2fb59..e7902a9 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -29,6 +29,7 @@
import android.os.Bundle;
import android.os.Debug;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.Parcel;
@@ -141,6 +142,7 @@
data.readStrongBinder());
int procState = data.readInt();
Bundle state = data.readBundle();
+ PersistableBundle persistentState = data.readPersistableBundle();
List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
boolean notResumed = data.readInt() != 0;
@@ -151,9 +153,9 @@
boolean autoStopProfiler = data.readInt() != 0;
Bundle resumeArgs = data.readBundle();
scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo,
- voiceInteractor, procState, state,
- ri, pi, notResumed, isForward, profileName, profileFd, autoStopProfiler,
- resumeArgs);
+ voiceInteractor, procState, state, persistentState,
+ ri, pi, notResumed, isForward, profileName, profileFd,
+ autoStopProfiler, resumeArgs);
return true;
}
@@ -731,8 +733,8 @@
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
- IVoiceInteractor voiceInteractor,
- int procState, Bundle state, List<ResultInfo> pendingResults,
+ IVoiceInteractor voiceInteractor, int procState, Bundle state,
+ PersistableBundle persistentState, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle resumeArgs)
@@ -748,6 +750,7 @@
data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null);
data.writeInt(procState);
data.writeBundle(state);
+ data.writePersistableBundle(persistentState);
data.writeTypedList(pendingResults);
data.writeTypedList(pendingNewIntents);
data.writeInt(notResumed ? 1 : 0);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2e9cdf3b7..074b427 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -45,6 +45,7 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.StrictMode;
import android.service.voice.IVoiceInteractionSession;
@@ -104,9 +105,9 @@
public void activityResumed(IBinder token) throws RemoteException;
public void activityIdle(IBinder token, Configuration config,
boolean stopProfiling) throws RemoteException;
- public void activityPaused(IBinder token) throws RemoteException;
+ public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException;
public void activityStopped(IBinder token, Bundle state,
- Bitmap thumbnail, CharSequence description) throws RemoteException;
+ PersistableBundle persistentState, CharSequence description) throws RemoteException;
public void activitySlept(IBinder token) throws RemoteException;
public void activityDestroyed(IBinder token) throws RemoteException;
public String getCallingPackage(IBinder token) throws RemoteException;
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index fefba8a..a832034 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -28,6 +28,7 @@
import android.os.Bundle;
import android.os.Debug;
import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.IInterface;
@@ -58,8 +59,8 @@
void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
IVoiceInteractor voiceInteractor, int procState, Bundle state,
- List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed,
- boolean isForward,
+ PersistableBundle persistentState, List<ResultInfo> pendingResults,
+ List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle resumeArgs)
throws RemoteException;
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e58ccb8..bb3e002 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -30,6 +30,7 @@
import android.os.Looper;
import android.os.MessageQueue;
import android.os.PerformanceCollector;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -1061,15 +1062,7 @@
return (Activity)cl.loadClass(className).newInstance();
}
- /**
- * Perform calling of an activity's {@link Activity#onCreate}
- * method. The default implementation simply calls through to that method.
- *
- * @param activity The activity being created.
- * @param icicle The previously frozen state (or null) to pass through to
- * onCreate().
- */
- public void callActivityOnCreate(Activity activity, Bundle icicle) {
+ private void prePerformCreate(Activity activity) {
if (mWaitingActivities != null) {
synchronized (mSync) {
final int N = mWaitingActivities.size();
@@ -1083,9 +1076,9 @@
}
}
}
-
- activity.performCreate(icicle);
-
+ }
+
+ private void postPerformCreate(Activity activity) {
if (mActivityMonitors != null) {
synchronized (mSync) {
final int N = mActivityMonitors.size();
@@ -1096,6 +1089,33 @@
}
}
}
+
+ /**
+ * Perform calling of an activity's {@link Activity#onCreate}
+ * method. The default implementation simply calls through to that method.
+ *
+ * @param activity The activity being created.
+ * @param icicle The previously frozen state (or null) to pass through to onCreate().
+ */
+ public void callActivityOnCreate(Activity activity, Bundle icicle) {
+ prePerformCreate(activity);
+ activity.performCreate(icicle);
+ postPerformCreate(activity);
+ }
+
+ /**
+ * Perform calling of an activity's {@link Activity#onCreate}
+ * method. The default implementation simply calls through to that method.
+ * @param activity The activity being created.
+ * @param icicle The previously frozen state (or null) to pass through to
+ * @param persistentState The previously persisted state (or null)
+ */
+ public void callActivityOnCreate(Activity activity, Bundle icicle,
+ PersistableBundle persistentState) {
+ prePerformCreate(activity);
+ activity.performCreate(icicle, persistentState);
+ postPerformCreate(activity);
+ }
public void callActivityOnDestroy(Activity activity) {
// TODO: the following block causes intermittent hangs when using startActivity
@@ -1130,7 +1150,7 @@
/**
* Perform calling of an activity's {@link Activity#onRestoreInstanceState}
* method. The default implementation simply calls through to that method.
- *
+ *
* @param activity The activity being restored.
* @param savedInstanceState The previously saved state being restored.
*/
@@ -1139,9 +1159,22 @@
}
/**
+ * Perform calling of an activity's {@link Activity#onRestoreInstanceState}
+ * method. The default implementation simply calls through to that method.
+ *
+ * @param activity The activity being restored.
+ * @param savedInstanceState The previously saved state being restored.
+ * @param persistentState The previously persisted state (or null)
+ */
+ public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState,
+ PersistableBundle persistentState) {
+ activity.performRestoreInstanceState(savedInstanceState, persistentState);
+ }
+
+ /**
* Perform calling of an activity's {@link Activity#onPostCreate} method.
* The default implementation simply calls through to that method.
- *
+ *
* @param activity The activity being created.
* @param icicle The previously frozen state (or null) to pass through to
* onPostCreate().
@@ -1151,6 +1184,19 @@
}
/**
+ * Perform calling of an activity's {@link Activity#onPostCreate} method.
+ * The default implementation simply calls through to that method.
+ *
+ * @param activity The activity being created.
+ * @param icicle The previously frozen state (or null) to pass through to
+ * onPostCreate().
+ */
+ public void callActivityOnPostCreate(Activity activity, Bundle icicle,
+ PersistableBundle persistentState) {
+ activity.onPostCreate(icicle, persistentState);
+ }
+
+ /**
* Perform calling of an activity's {@link Activity#onNewIntent}
* method. The default implementation simply calls through to that method.
*
@@ -1215,7 +1261,7 @@
/**
* Perform calling of an activity's {@link Activity#onSaveInstanceState}
* method. The default implementation simply calls through to that method.
- *
+ *
* @param activity The activity being saved.
* @param outState The bundle to pass to the call.
*/
@@ -1224,6 +1270,18 @@
}
/**
+ * Perform calling of an activity's {@link Activity#onSaveInstanceState}
+ * method. The default implementation simply calls through to that method.
+ * @param activity The activity being saved.
+ * @param outState The bundle to pass to the call.
+ * @param outPersistentState The persistent bundle to pass to the call.
+ */
+ public void callActivityOnSaveInstanceState(Activity activity, Bundle outState,
+ PersistableBundle outPersistentState) {
+ activity.performSaveInstanceState(outState, outPersistentState);
+ }
+
+ /**
* Perform calling of an activity's {@link Activity#onPause} method. The
* default implementation simply calls through to that method.
*
@@ -1428,7 +1486,7 @@
}
/**
- * Like {@link #execStartActivity},
+ * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
* but accepts an array of activities to be started. Note that active
* {@link ActivityMonitor} objects only match against the first activity in
* the array.
@@ -1442,7 +1500,7 @@
}
/**
- * Like {@link #execStartActivity},
+ * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
* but accepts an array of activities to be started. Note that active
* {@link ActivityMonitor} objects only match against the first activity in
* the array.
@@ -1545,7 +1603,8 @@
}
/**
- * Like {@link #execStartActivity}, but for starting as a particular user.
+ * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)},
+ * but for starting as a particular user.
*
* @param who The Context from which the activity is being started.
* @param contextThread The main thread of the Context from which the activity
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cbb8377..51d23c1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -35,6 +35,7 @@
import android.appwidget.AppWidgetManager;
import android.graphics.Rect;
import android.os.BatteryStats;
+import android.os.PersistableBundle;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
@@ -5422,22 +5423,21 @@
}
@Override
- public final void activityPaused(IBinder token) {
+ public final void activityPaused(IBinder token, PersistableBundle persistentState) {
final long origId = Binder.clearCallingIdentity();
synchronized(this) {
ActivityStack stack = ActivityRecord.getStackLocked(token);
if (stack != null) {
- stack.activityPausedLocked(token, false);
+ stack.activityPausedLocked(token, false, persistentState);
}
}
Binder.restoreCallingIdentity(origId);
}
@Override
- public final void activityStopped(IBinder token, Bundle icicle, Bitmap thumbnail,
- CharSequence description) {
- if (localLOGV) Slog.v(
- TAG, "Activity stopped: token=" + token);
+ public final void activityStopped(IBinder token, Bundle icicle,
+ PersistableBundle persistentState, CharSequence description) {
+ if (localLOGV) Slog.v(TAG, "Activity stopped: token=" + token);
// Refuse possible leaked file descriptors
if (icicle != null && icicle.hasFileDescriptors()) {
@@ -5449,7 +5449,7 @@
synchronized (this) {
ActivityRecord r = ActivityRecord.isInStackLocked(token);
if (r != null) {
- r.task.stack.activityStoppedLocked(r, icicle, thumbnail, description);
+ r.task.stack.activityStoppedLocked(r, icicle, persistentState, description);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 7c3f288..ed7ed35 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import android.os.PersistableBundle;
import android.os.Trace;
import com.android.internal.R.styleable;
import com.android.internal.app.ResolverActivity;
@@ -118,6 +119,7 @@
ProcessRecord app; // if non-null, hosting application
ActivityState state; // current state we are in
Bundle icicle; // last saved activity state
+ PersistableBundle persistentState; // last persistently saved activity state
boolean frontOfTask; // is this the root activity of its task?
boolean launchFailed; // set if a launched failed, to abort on 2nd try
boolean haveState; // have we gotten the last activity state?
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index ee39b67..48d16e0 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -70,6 +70,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.Trace;
@@ -278,7 +279,7 @@
if (r.app != null) {
mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r);
}
- activityPausedLocked(r.appToken, true);
+ activityPausedLocked(r.appToken, true, r.persistentState);
}
} break;
case LAUNCH_TICK_MSG: {
@@ -862,13 +863,15 @@
}
}
- final void activityPausedLocked(IBinder token, boolean timeout) {
+ final void activityPausedLocked(IBinder token, boolean timeout,
+ PersistableBundle persistentState) {
if (DEBUG_PAUSE) Slog.v(
TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
final ActivityRecord r = isInStackLocked(token);
if (r != null) {
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
+ r.persistentState = persistentState;
if (mPausingActivity == r) {
if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
+ (timeout ? " (due to timeout)" : " (pause complete)"));
@@ -883,13 +886,14 @@
}
}
- final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
- CharSequence description) {
+ final void activityStoppedLocked(ActivityRecord r, Bundle icicle,
+ PersistableBundle persistentState, CharSequence description) {
if (r.state != ActivityState.STOPPING) {
Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r);
mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
return;
}
+ r.persistentState = persistentState;
if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle);
if (icicle != null) {
// If icicle is null, this is happening due to a timeout, so we
@@ -897,7 +901,7 @@
r.icicle = icicle;
r.haveState = true;
r.launchCount = 0;
- r.updateThumbnail(thumbnail, description);
+ r.updateThumbnail(null, description);
}
if (!r.stopped) {
if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 2e979d2..72651f3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1023,10 +1023,10 @@
r.clearOptionsLocked();
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
- new Configuration(mService.mConfiguration), r.compat,
- r.task.voiceInteractor, app.repProcState, r.icicle, results, newIntents,
- !andResume, mService.isNextTransitionForward(), profileFile, profileFd,
- profileAutoStop, options);
+ new Configuration(mService.mConfiguration), r.compat, r.task.voiceInteractor,
+ app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume,
+ mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop,
+ options);
if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
// This may be a heavy-weight process! Note that the package