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

The goal is to fix a bunch of fragment-related bugs caused by various
things trying to do fragment transactions after onPause()...  which
currently throws an exception, since this is after the activity's state
has been saved so the new fragment state can be lost.

The basic change is relatively simple -- we now consider processes
hosting paused or stopping activities to be unkillable, and the client
code now does the onSaveInstanceState() as part of stopping the
activity.

For compatibility, if an app's targetSdkVersion is < HONEYCOMB, the
client side will still call onSaveInstanceState() prior to onPause()
and just hold on to that state until it needs to report it in once
being stopped.

Also included here is a change to generate thumbnails by taking
screenshots.  The code for generating thumbnails by re-rendering
the view hierarchy is thus removed.

Change-Id: Iac1191646bd3cadbfe65779297795f22edf7e74a
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index b4ea036..aa4cd66 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -46,6 +46,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -237,6 +239,9 @@
     
     long mInitialStartTime = 0;
     
+    int mThumbnailWidth = -1;
+    int mThumbnailHeight = -1;
+
     static final int PAUSE_TIMEOUT_MSG = 9;
     static final int IDLE_TIMEOUT_MSG = 10;
     static final int IDLE_NOW_MSG = 11;
@@ -256,7 +261,7 @@
                     // We don't at this point know if the activity is fullscreen,
                     // so we need to be conservative and assume it isn't.
                     Slog.w(TAG, "Activity pause timeout for " + token);
-                    activityPaused(token, null, true);
+                    activityPaused(token, true);
                 } break;
                 case IDLE_TIMEOUT_MSG: {
                     if (mService.mDidDexOpt) {
@@ -564,8 +569,6 @@
             // As part of the process of launching, ActivityThread also performs
             // a resume.
             r.state = ActivityState.RESUMED;
-            r.icicle = null;
-            r.haveState = false;
             r.stopped = false;
             mResumedActivity = r;
             r.task.touchActiveTime();
@@ -580,6 +583,9 @@
             r.stopped = true;
         }
 
+        r.icicle = null;
+        r.haveState = false;
+
         // Launch the new version setup screen if needed.  We do this -after-
         // launching the initial activity (that is, home), so that it can have
         // a chance to initialize itself while in the background, making the
@@ -644,6 +650,23 @@
         }
     }
     
+    public final Bitmap screenshotActivities() {
+        Resources res = mService.mContext.getResources();
+        int w = mThumbnailWidth;
+        int h = mThumbnailHeight;
+        if (w < 0) {
+            mThumbnailWidth = w =
+                res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
+            mThumbnailHeight = h =
+                res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);
+        }
+
+        if (w > 0) {
+            return mService.mWindowManager.screenshotApplications(w, h);
+        }
+        return null;
+    }
+
     private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
         if (mPausingActivity != null) {
             RuntimeException e = new RuntimeException();
@@ -663,6 +686,7 @@
         mLastPausedActivity = prev;
         prev.state = ActivityState.PAUSING;
         prev.task.touchActiveTime();
+        prev.thumbnail = screenshotActivities();
 
         mService.updateCpuStats();
         
@@ -726,10 +750,9 @@
         }
     }
     
-    final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
+    final void activityPaused(IBinder token, boolean timeout) {
         if (DEBUG_PAUSE) Slog.v(
-            TAG, "Activity paused: token=" + token + ", icicle=" + icicle
-            + ", timeout=" + timeout);
+            TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
 
         ActivityRecord r = null;
 
@@ -737,10 +760,6 @@
             int index = indexOfTokenLocked(token);
             if (index >= 0) {
                 r = (ActivityRecord)mHistory.get(index);
-                if (!timeout) {
-                    r.icicle = icicle;
-                    r.haveState = true;
-                }
                 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
                 if (mPausingActivity == r) {
                     r.state = ActivityState.PAUSED;