Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 514d7d8d authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android (Google) Code Review
Browse files

Merge "Rework activity lifecycle so onSaveInstanceState() is after onPause()."

parents f9dee3b1 0aae2d4e
Loading
Loading
Loading
Loading
+13 −41
Original line number Original line Diff line number Diff line
@@ -297,7 +297,7 @@ import java.util.List;
 *             <p>Followed by either <code>onResume()</code> if the activity
 *             <p>Followed by either <code>onResume()</code> if the activity
 *             returns back to the front, or <code>onStop()</code> if it becomes
 *             returns back to the front, or <code>onStop()</code> if it becomes
 *             invisible to the user.</td>
 *             invisible to the user.</td>
 *         <td align="center"><font color="#800000"><strong>Yes</strong></font></td>
 *         <td align="center"><font color="#800000"><strong>Pre-{@link android.os.Build.VERSION_CODES#HONEYCOMB}</strong></font></td>
 *         <td align="center"><code>onResume()</code> or<br>
 *         <td align="center"><code>onResume()</code> or<br>
 *                 <code>onStop()</code></td>
 *                 <code>onStop()</code></td>
 *     </tr>
 *     </tr>
@@ -347,6 +347,14 @@ import java.util.List;
 * because the later is not part of the lifecycle callbacks, so will not
 * because the later is not part of the lifecycle callbacks, so will not
 * be called in every situation as described in its documentation.</p>
 * be called in every situation as described in its documentation.</p>
 *
 *
 * <p class="note">Be aware that these semantics will change slightly between
 * applications targeting platforms starting with {@link android.os.Build.VERSION_CODES#HONEYCOMB}
 * vs. those targeting prior platforms.  Starting with Honeycomb, an application
 * is not in the killable state until its {@link #onStop} has returned.  This
 * impacts when {@link #onSaveInstanceState(Bundle)} may be called (it may be
 * safely called after {@link #onPause()} and allows and application to safely
 * wait until {@link #onStop()} to save persistent state.</p>
 *
 * <p>For those methods that are not marked as being killable, the activity's
 * <p>For those methods that are not marked as being killable, the activity's
 * process will not be killed by the system starting from the time the method
 * process will not be killed by the system starting from the time the method
 * is called and continuing after it returns.  Thus an activity is in the killable
 * is called and continuing after it returns.  Thus an activity is in the killable
@@ -489,7 +497,7 @@ import java.util.List;
 * paused.  Note this implies
 * paused.  Note this implies
 * that the user pressing BACK from your activity does <em>not</em>
 * that the user pressing BACK from your activity does <em>not</em>
 * mean "cancel" -- it means to leave the activity with its current contents
 * mean "cancel" -- it means to leave the activity with its current contents
 * saved away.  Cancelling edits in an activity must be provided through
 * saved away.  Canceling edits in an activity must be provided through
 * some other mechanism, such as an explicit "revert" or "undo" option.</p>
 * some other mechanism, such as an explicit "revert" or "undo" option.</p>
 *
 *
 * <p>See the {@linkplain android.content.ContentProvider content package} for
 * <p>See the {@linkplain android.content.ContentProvider content package} for
@@ -1255,11 +1263,8 @@ public class Activity extends ContextThemeWrapper
     * can use the given <var>canvas</var>, which is configured to draw into the
     * can use the given <var>canvas</var>, which is configured to draw into the
     * bitmap, for rendering if desired.
     * bitmap, for rendering if desired.
     * 
     * 
     * <p>The default implementation renders the Screen's current view
     * <p>The default implementation returns fails and does not draw a thumbnail;
     * hierarchy into the canvas to generate a thumbnail.
     * this will result in the platform creating its own thumbnail if needed.
     * 
     * <p>If you return false, the bitmap will be filled with a default
     * thumbnail.
     * 
     * 
     * @param outBitmap The bitmap to contain the thumbnail.
     * @param outBitmap The bitmap to contain the thumbnail.
     * @param canvas Can be used to render into the bitmap.
     * @param canvas Can be used to render into the bitmap.
@@ -1272,42 +1277,9 @@ public class Activity extends ContextThemeWrapper
     * @see #onPause
     * @see #onPause
     */
     */
    public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas) {
    public boolean onCreateThumbnail(Bitmap outBitmap, Canvas canvas) {
        if (mDecor == null) {
        return false;
        return false;
    }
    }


        int paddingLeft = 0;
        int paddingRight = 0;
        int paddingTop = 0;
        int paddingBottom = 0;

        // Find System window and use padding so we ignore space reserved for decorations
        // like the status bar and such.
        final FrameLayout top = (FrameLayout) mDecor;
        for (int i = 0; i < top.getChildCount(); i++) {
            View child = top.getChildAt(i);
            if (child.isFitsSystemWindowsFlagSet()) {
                paddingLeft = child.getPaddingLeft();
                paddingRight = child.getPaddingRight();
                paddingTop = child.getPaddingTop();
                paddingBottom = child.getPaddingBottom();
                break;
            }
        }
        
        final int visibleWidth = mDecor.getWidth() - paddingLeft - paddingRight;
        final int visibleHeight = mDecor.getHeight() - paddingTop - paddingBottom;

        canvas.save();
        canvas.scale( (float) outBitmap.getWidth() / visibleWidth,
                (float) outBitmap.getHeight() / visibleHeight);
        canvas.translate(-paddingLeft, -paddingTop);
        mDecor.draw(canvas);
        canvas.restore();

        return true;
    }

    /**
    /**
     * Generate a new description for this activity.  This method is called
     * Generate a new description for this activity.  This method is called
     * before pausing the activity and can, if desired, return some textual
     * before pausing the activity and can, if desired, return some textual
+7 −7
Original line number Original line Diff line number Diff line
@@ -359,8 +359,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
        case ACTIVITY_PAUSED_TRANSACTION: {
        case ACTIVITY_PAUSED_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            data.enforceInterface(IActivityManager.descriptor);
            IBinder token = data.readStrongBinder();
            IBinder token = data.readStrongBinder();
            Bundle map = data.readBundle();
            activityPaused(token);
            activityPaused(token, map);
            reply.writeNoException();
            reply.writeNoException();
            return true;
            return true;
        }
        }
@@ -368,10 +367,11 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
        case ACTIVITY_STOPPED_TRANSACTION: {
        case ACTIVITY_STOPPED_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            data.enforceInterface(IActivityManager.descriptor);
            IBinder token = data.readStrongBinder();
            IBinder token = data.readStrongBinder();
            Bundle map = data.readBundle();
            Bitmap thumbnail = data.readInt() != 0
            Bitmap thumbnail = data.readInt() != 0
                ? Bitmap.CREATOR.createFromParcel(data) : null;
                ? Bitmap.CREATOR.createFromParcel(data) : null;
            CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
            CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data);
            activityStopped(token, thumbnail, description);
            activityStopped(token, map, thumbnail, description);
            reply.writeNoException();
            reply.writeNoException();
            return true;
            return true;
        }
        }
@@ -1688,25 +1688,25 @@ class ActivityManagerProxy implements IActivityManager
        data.recycle();
        data.recycle();
        reply.recycle();
        reply.recycle();
    }
    }
    public void activityPaused(IBinder token, Bundle state) throws RemoteException
    public void activityPaused(IBinder token) throws RemoteException
    {
    {
        Parcel data = Parcel.obtain();
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(token);
        data.writeStrongBinder(token);
        data.writeBundle(state);
        mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
        mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0);
        reply.readException();
        reply.readException();
        data.recycle();
        data.recycle();
        reply.recycle();
        reply.recycle();
    }
    }
    public void activityStopped(IBinder token,
    public void activityStopped(IBinder token, Bundle state,
            Bitmap thumbnail, CharSequence description) throws RemoteException
            Bitmap thumbnail, CharSequence description) throws RemoteException
    {
    {
        Parcel data = Parcel.obtain();
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(token);
        data.writeStrongBinder(token);
        data.writeBundle(state);
        if (thumbnail != null) {
        if (thumbnail != null) {
            data.writeInt(1);
            data.writeInt(1);
            thumbnail.writeToParcel(data, 0);
            thumbnail.writeToParcel(data, 0);
+70 −38
Original line number Original line Diff line number Diff line
@@ -239,6 +239,14 @@ public final class ActivityThread {
            nextIdle = null;
            nextIdle = null;
        }
        }


        public boolean isPreHoneycomb() {
            if (activity != null) {
                return activity.getApplicationInfo().targetSdkVersion
                        < android.os.Build.VERSION_CODES.HONEYCOMB;
            }
            return false;
        }

        public String toString() {
        public String toString() {
            ComponentName componentName = intent.getComponent();
            ComponentName componentName = intent.getComponent();
            return "ActivityRecord{"
            return "ActivityRecord{"
@@ -2299,10 +2307,13 @@ public final class ActivityThread {


    private int mThumbnailWidth = -1;
    private int mThumbnailWidth = -1;
    private int mThumbnailHeight = -1;
    private int mThumbnailHeight = -1;
    private Bitmap mAvailThumbnailBitmap = null;
    private Canvas mThumbnailCanvas = null;


    private final Bitmap createThumbnailBitmap(ActivityClientRecord r) {
    private final Bitmap createThumbnailBitmap(ActivityClientRecord r) {
        Bitmap thumbnail = null;
        Bitmap thumbnail = mAvailThumbnailBitmap;
        try {
        try {
            if (thumbnail == null) {
                int w = mThumbnailWidth;
                int w = mThumbnailWidth;
                int h;
                int h;
                if (w < 0) {
                if (w < 0) {
@@ -2318,21 +2329,21 @@ public final class ActivityThread {


                // On platforms where we don't want thumbnails, set dims to (0,0)
                // On platforms where we don't want thumbnails, set dims to (0,0)
                if ((w > 0) && (h > 0)) {
                if ((w > 0) && (h > 0)) {
                View topView = r.activity.getWindow().getDecorView();

                // Maximize bitmap by capturing in native aspect.
                if (topView.getWidth() >= topView.getHeight()) {
                    thumbnail = Bitmap.createBitmap(w, h, THUMBNAIL_FORMAT);
                    thumbnail = Bitmap.createBitmap(w, h, THUMBNAIL_FORMAT);
                } else {
                    thumbnail.eraseColor(0);
                    thumbnail = Bitmap.createBitmap(h, w, THUMBNAIL_FORMAT);
                }
            }
            }


                thumbnail.eraseColor(0);
            Canvas cv = mThumbnailCanvas;
                Canvas cv = new Canvas(thumbnail);
            if (cv == null) {
                mThumbnailCanvas = cv = new Canvas();
            }

            cv.setBitmap(thumbnail);
            if (!r.activity.onCreateThumbnail(thumbnail, cv)) {
            if (!r.activity.onCreateThumbnail(thumbnail, cv)) {
                mAvailThumbnailBitmap = thumbnail;
                thumbnail = null;
                thumbnail = null;
            }
            }
            }


        } catch (Exception e) {
        } catch (Exception e) {
            if (!mInstrumentation.onException(r.activity, e)) {
            if (!mInstrumentation.onException(r.activity, e)) {
@@ -2357,14 +2368,14 @@ public final class ActivityThread {
            }
            }


            r.activity.mConfigChangeFlags |= configChanges;
            r.activity.mConfigChangeFlags |= configChanges;
            Bundle state = performPauseActivity(token, finished, true);
            performPauseActivity(token, finished, r.isPreHoneycomb());


            // Make sure any pending writes are now committed.
            // Make sure any pending writes are now committed.
            QueuedWork.waitToFinish();
            QueuedWork.waitToFinish();
            
            
            // Tell the activity manager we have paused.
            // Tell the activity manager we have paused.
            try {
            try {
                ActivityManagerNative.getDefault().activityPaused(token, state);
                ActivityManagerNative.getDefault().activityPaused(token);
            } catch (RemoteException ex) {
            } catch (RemoteException ex) {
            }
            }
        }
        }
@@ -2404,6 +2415,8 @@ public final class ActivityThread {
                state = new Bundle();
                state = new Bundle();
                mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
                mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
                r.state = state;
                r.state = state;
            } else {
                r.state = null;
            }
            }
            // Now we are idle.
            // Now we are idle.
            r.activity.mCalled = false;
            r.activity.mCalled = false;
@@ -2430,9 +2443,9 @@ public final class ActivityThread {
        return state;
        return state;
    }
    }


    final void performStopActivity(IBinder token) {
    final void performStopActivity(IBinder token, boolean saveState) {
        ActivityClientRecord r = mActivities.get(token);
        ActivityClientRecord r = mActivities.get(token);
        performStopActivityInner(r, null, false);
        performStopActivityInner(r, null, false, saveState);
    }
    }


    private static class StopInfo {
    private static class StopInfo {
@@ -2447,9 +2460,18 @@ public final class ActivityThread {
        }
        }
    }
    }


    /**
     * Core implementation of stopping an activity.  Note this is a little
     * tricky because the server's meaning of stop is slightly different
     * than our client -- for the server, stop means to save state and give
     * it the result when it is done, but the window may still be visible.
     * For the client, we want to call onStop()/onStart() to indicate when
     * the activity's UI visibillity changes.
     */
    private final void performStopActivityInner(ActivityClientRecord r,
    private final void performStopActivityInner(ActivityClientRecord r,
            StopInfo info, boolean keepShown) {
            StopInfo info, boolean keepShown, boolean saveState) {
        if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
        if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
        Bundle state = null;
        if (r != null) {
        if (r != null) {
            if (!keepShown && r.stopped) {
            if (!keepShown && r.stopped) {
                if (r.activity.mFinished) {
                if (r.activity.mFinished) {
@@ -2479,6 +2501,17 @@ public final class ActivityThread {
                }
                }
            }
            }


            // Next have the activity save its current state and managed dialogs...
            if (!r.activity.mFinished && saveState) {
                if (r.state == null) {
                    state = new Bundle();
                    mInstrumentation.callActivityOnSaveInstanceState(r.activity, state);
                    r.state = state;
                } else {
                    state = r.state;
                }
            }

            if (!keepShown) {
            if (!keepShown) {
                try {
                try {
                    // Now we are idle.
                    // Now we are idle.
@@ -2530,7 +2563,7 @@ public final class ActivityThread {
        r.activity.mConfigChangeFlags |= configChanges;
        r.activity.mConfigChangeFlags |= configChanges;


        StopInfo info = new StopInfo();
        StopInfo info = new StopInfo();
        performStopActivityInner(r, info, show);
        performStopActivityInner(r, info, show, true);


        if (localLOGV) Slog.v(
        if (localLOGV) Slog.v(
            TAG, "Finishing stop of " + r + ": show=" + show
            TAG, "Finishing stop of " + r + ": show=" + show
@@ -2541,7 +2574,7 @@ public final class ActivityThread {
        // Tell activity manager we have been stopped.
        // Tell activity manager we have been stopped.
        try {
        try {
            ActivityManagerNative.getDefault().activityStopped(
            ActivityManagerNative.getDefault().activityStopped(
                r.token, info.thumbnail, info.description);
                r.token, r.state, info.thumbnail, info.description);
        } catch (RemoteException ex) {
        } catch (RemoteException ex) {
        }
        }
    }
    }
@@ -2557,7 +2590,7 @@ public final class ActivityThread {
    private final void handleWindowVisibility(IBinder token, boolean show) {
    private final void handleWindowVisibility(IBinder token, boolean show) {
        ActivityClientRecord r = mActivities.get(token);
        ActivityClientRecord r = mActivities.get(token);
        if (!show && !r.stopped) {
        if (!show && !r.stopped) {
            performStopActivityInner(r, null, show);
            performStopActivityInner(r, null, show, false);
        } else if (show && r.stopped) {
        } else if (show && r.stopped) {
            // If we are getting ready to gc after going to the background, well
            // If we are getting ready to gc after going to the background, well
            // we are back active so skip it.
            // we are back active so skip it.
@@ -2651,9 +2684,6 @@ public final class ActivityThread {
            if (finishing) {
            if (finishing) {
                r.activity.mFinished = true;
                r.activity.mFinished = true;
            }
            }
            if (getNonConfigInstance) {
                r.activity.mChangingConfigurations = true;
            }
            if (!r.paused) {
            if (!r.paused) {
                try {
                try {
                    r.activity.mCalled = false;
                    r.activity.mCalled = false;
@@ -2924,9 +2954,11 @@ public final class ActivityThread {
        r.onlyLocalRequest = tmp.onlyLocalRequest;
        r.onlyLocalRequest = tmp.onlyLocalRequest;
        Intent currentIntent = r.activity.mIntent;
        Intent currentIntent = r.activity.mIntent;


        r.activity.mChangingConfigurations = true;

        Bundle savedState = null;
        Bundle savedState = null;
        if (!r.paused) {
        if (!r.paused) {
            savedState = performPauseActivity(r.token, false, true);
            savedState = performPauseActivity(r.token, false, r.isPreHoneycomb());
        }
        }


        handleDestroyActivity(r.token, false, configChanges, true);
        handleDestroyActivity(r.token, false, configChanges, true);
+3 −3
Original line number Original line Diff line number Diff line
@@ -119,9 +119,9 @@ public interface IActivityManager extends IInterface {
    public void attachApplication(IApplicationThread app) throws RemoteException;
    public void attachApplication(IApplicationThread app) throws RemoteException;
    /* oneway */
    /* oneway */
    public void activityIdle(IBinder token, Configuration config) throws RemoteException;
    public void activityIdle(IBinder token, Configuration config) throws RemoteException;
    public void activityPaused(IBinder token, Bundle state) throws RemoteException;
    public void activityPaused(IBinder token) throws RemoteException;
    /* oneway */
    /* oneway */
    public void activityStopped(IBinder token,
    public void activityStopped(IBinder token, Bundle state,
            Bitmap thumbnail, CharSequence description) throws RemoteException;
            Bitmap thumbnail, CharSequence description) throws RemoteException;
    /* oneway */
    /* oneway */
    public void activityDestroyed(IBinder token) throws RemoteException;
    public void activityDestroyed(IBinder token) throws RemoteException;
+2 −2
Original line number Original line Diff line number Diff line
@@ -176,7 +176,7 @@ public class LocalActivityManager {
                }
                }
                if (desiredState == CREATED) {
                if (desiredState == CREATED) {
                    if (localLOGV) Log.v(TAG, r.id + ": stopping");
                    if (localLOGV) Log.v(TAG, r.id + ": stopping");
                    mActivityThread.performStopActivity(r);
                    mActivityThread.performStopActivity(r, false);
                    r.curState = CREATED;
                    r.curState = CREATED;
                }
                }
                return;
                return;
@@ -191,7 +191,7 @@ public class LocalActivityManager {
                    if (localLOGV) Log.v(TAG, r.id + ": pausing");
                    if (localLOGV) Log.v(TAG, r.id + ": pausing");
                    performPause(r, mFinishing);
                    performPause(r, mFinishing);
                    if (localLOGV) Log.v(TAG, r.id + ": stopping");
                    if (localLOGV) Log.v(TAG, r.id + ": stopping");
                    mActivityThread.performStopActivity(r);
                    mActivityThread.performStopActivity(r, false);
                    r.curState = CREATED;
                    r.curState = CREATED;
                }
                }
                return;
                return;
Loading