Call ensureActivitiesVisibleLocked from supervisor.

- Don't call ActivityStack.ensureActivitiesVisibleLocked directly.
Instead call ActivityStackSupervisor.ensureActivitiesVisibleLocked.

- Add detecting monochrome screenshots to black screenshots.

- minor refactors.

Change-Id: I050b1cd40cacaab451f1460a77a82125a8077ff2
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 0e2b4a4..c34b4ec 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4597,7 +4597,7 @@
         synchronized(this) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
             if (stack != null) {
-                stack.activityResumedLocked(token);
+                ActivityRecord.activityResumedLocked(token);
             }
         }
         Binder.restoreCallingIdentity(origId);
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 88bcdab..51b9984 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -54,6 +54,9 @@
  * An entry in the history stack, representing an activity.
  */
 final class ActivityRecord {
+    static final String TAG = ActivityManagerService.TAG;
+    static final boolean DEBUG_SAVED_STATE = ActivityStackSupervisor.DEBUG_SAVED_STATE;
+
     final ActivityManagerService service; // owner
     final IApplicationToken.Stub appToken; // window manager token
     final ActivityInfo info; // all about me
@@ -295,10 +298,7 @@
 
         @Override public boolean keyDispatchingTimedOut() {
             ActivityRecord activity = weakActivity.get();
-            if (activity != null) {
-                return activity.keyDispatchingTimedOut();
-            }
-            return false;
+            return activity != null && activity.keyDispatchingTimedOut();
         }
 
         @Override public long getKeyDispatchingTimeout() {
@@ -417,10 +417,10 @@
             if (intent != null && (aInfo.flags & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0) {
                 intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
             }
-            
+
             packageName = aInfo.applicationInfo.packageName;
             launchMode = aInfo.launchMode;
-            
+
             AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
                     realTheme, com.android.internal.R.styleable.Window);
             fullscreen = ent != null && !ent.array.getBoolean(
@@ -429,30 +429,24 @@
                     com.android.internal.R.styleable.Window_windowIsTranslucent, false);
             noDisplay = ent != null && ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowNoDisplay, false);
-            
-            if (!_componentSpecified || _launchedFromUid == Process.myUid()
-                    || _launchedFromUid == 0) {
-                // If we know the system has determined the component, then
-                // we can consider this to be a home activity...
-                if (Intent.ACTION_MAIN.equals(_intent.getAction()) &&
-                        _intent.hasCategory(Intent.CATEGORY_HOME) &&
-                        _intent.getCategories().size() == 1 &&
-                        _intent.getData() == null &&
-                        _intent.getType() == null &&
-                        (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
-                        !ResolverActivity.class.getName().equals(realActivity.getClassName())) {
+
+            // If we know the system has determined the component, then
+            // we can consider this to be a home activity...
+            // Note the last check is so we don't count the resolver
+            // activity as being home...  really, we don't care about
+            // doing anything special with something that comes from
+            // the core framework package.
+            isHomeActivity =
+                    (!_componentSpecified || _launchedFromUid == Process.myUid()
+                            || _launchedFromUid == 0) &&
+                    Intent.ACTION_MAIN.equals(_intent.getAction()) &&
+                    _intent.hasCategory(Intent.CATEGORY_HOME) &&
+                    _intent.getCategories().size() == 1 &&
+                    _intent.getData() == null &&
+                    _intent.getType() == null &&
+                    (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
+                    !ResolverActivity.class.getName().equals(realActivity.getClassName());
                     // This sure looks like a home activity!
-                    // Note the last check is so we don't count the resolver
-                    // activity as being home...  really, we don't care about
-                    // doing anything special with something that comes from
-                    // the core framework package.
-                    isHomeActivity = true;
-                } else {
-                    isHomeActivity = false;
-                }
-            } else {
-                isHomeActivity = false;
-            }
 
             immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
         } else {
@@ -580,7 +574,7 @@
         }
         newIntents.add(intent);
     }
-    
+
     /**
      * Deliver a new Intent to an existing activity, so that its onNewIntent()
      * method will be called at the proper time.
@@ -714,9 +708,6 @@
     }
 
     void updateThumbnail(Bitmap newThumbnail, CharSequence description) {
-        if ((intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
-            // This is a logical break in the task; it repre
-        }
         if (thumbHolder != null) {
             if (newThumbnail != null) {
                 if (ActivityManagerService.DEBUG_THUMBNAILS) Slog.i(ActivityManagerService.TAG,
@@ -764,20 +755,20 @@
         // so it is best to leave as-is.
         return app != null && !app.crashing && !app.notResponding;
     }
-    
+
     public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
         if (mayFreezeScreenLocked(app)) {
             service.mWindowManager.startAppFreezingScreen(appToken, configChanges);
         }
     }
-    
+
     public void stopFreezingScreenLocked(boolean force) {
         if (force || frozenBeforeDestroy) {
             frozenBeforeDestroy = false;
             service.mWindowManager.stopAppFreezingScreen(appToken, force);
         }
     }
-    
+
     public void windowsDrawn() {
         synchronized(service) {
             if (launchTime != 0) {
@@ -817,7 +808,6 @@
 
     public void windowsVisible() {
         synchronized(service) {
-            final ActivityStack stack = task.stack;
             mStackSupervisor.reportActivityVisibleLocked(this);
             if (ActivityManagerService.DEBUG_SWITCH) Log.v(
                     ActivityManagerService.TAG, "windowsVisible(): " + this);
@@ -858,7 +848,7 @@
                 ActivityManagerService.TAG, "windowsGone(): " + this);
         nowVisible = false;
     }
-    
+
     private ActivityRecord getWaitingHistoryRecordLocked() {
         // First find the real culprit...  if we are waiting
         // for another app to start, then we have paused dispatching
@@ -876,7 +866,7 @@
                 r = this;
             }
         }
-        
+
         return r;
     }
 
@@ -889,7 +879,7 @@
         }
         return service.inputDispatchingTimedOut(anrApp, r, this, false);
     }
-    
+
     /** Returns the key dispatching timeout for this application token. */
     public long getKeyDispatchingTimeout() {
         synchronized(service) {
@@ -903,7 +893,7 @@
      * currently pausing, or is resumed.
      */
     public boolean isInterestingToUserLocked() {
-        return visible || nowVisible || state == ActivityState.PAUSING || 
+        return visible || nowVisible || state == ActivityState.PAUSING ||
                 state == ActivityState.RESUMED;
     }
 
@@ -926,6 +916,13 @@
         }
     }
 
+    static void activityResumedLocked(IBinder token) {
+        final ActivityRecord r = ActivityRecord.forToken(token);
+        if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
+        r.icicle = null;
+        r.haveState = false;
+    }
+
     static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
         final ActivityRecord r = ActivityRecord.forToken(token);
         if (r == null) {
@@ -947,7 +944,7 @@
         return null;
     }
 
-    static final ActivityStack getStackLocked(IBinder token) {
+    static ActivityStack getStackLocked(IBinder token) {
         final ActivityRecord r = ActivityRecord.isInStackLocked(token);
         if (r != null) {
             return r.task.stack;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 5162319..4787a1e 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -291,8 +291,7 @@
                             mService.logAppTooSlow(r.app, r.pauseTime,
                                     "pausing " + r);
                         }
-
-                        activityPausedLocked(r != null ? r.appToken : null, true);
+                        activityPausedLocked(r.appToken, true);
                     }
                 } break;
                 case LAUNCH_TICK_MSG: {
@@ -581,7 +580,7 @@
      * matters on the home stack. All other stacks are single user.
      * @return whether there are any activities for the specified user.
      */
-    final boolean switchUserLocked(int userId, UserStartedState uss) {
+    final boolean switchUserLocked(int userId) {
         if (VALIDATE_TOKENS) {
             validateAppTokensLocked();
         }
@@ -592,10 +591,9 @@
 
         // Move userId's tasks to the top.
         boolean haveActivities = false;
-        TaskRecord task = null;
         int index = mTaskHistory.size();
         for (int i = 0; i < index; ++i) {
-            task = mTaskHistory.get(i);
+            TaskRecord task = mTaskHistory.get(i);
             if (task.userId == userId) {
                 haveActivities = true;
                 mTaskHistory.remove(i);
@@ -840,13 +838,6 @@
         }
     }
 
-    final void activityResumedLocked(IBinder token) {
-        final ActivityRecord r = ActivityRecord.forToken(token);
-        if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; dropping state of: " + r);
-        r.icicle = null;
-        r.haveState = false;
-    }
-
     final void activityPausedLocked(IBinder token, boolean timeout) {
         if (DEBUG_PAUSE) Slog.v(
             TAG, "Activity paused: token=" + token + ", timeout=" + timeout);
@@ -1065,8 +1056,7 @@
         boolean showHomeBehindStack = false;
         boolean behindFullscreen = !mStackSupervisor.isFrontStack(this) &&
                 !(forceHomeShown && isHomeStack());
-        int taskNdx;
-        for (taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 final ActivityRecord r = activities.get(activityNdx);
@@ -2214,7 +2204,7 @@
 
             // If this activity is fullscreen, set up to hide those under it.
             if (DEBUG_VISBILITY) Slog.v(TAG, "Idle activity for " + res);
-            ensureActivitiesVisibleLocked(null, 0);
+            mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
         }
 
         return res;
@@ -3428,7 +3418,7 @@
                 // activities are running, taking care of restarting this
                 // process.
                 if (hasVisibleActivities) {
-                    ensureActivitiesVisibleLocked(null, 0);
+                    mStackSupervisor.ensureActivitiesVisibleLocked(null, 0);
                 }
             }
         }
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 60b7061..69e9f76 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -52,6 +52,7 @@
 import android.content.res.Configuration;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -84,6 +85,7 @@
     static final boolean DEBUG_APP = DEBUG || false;
     static final boolean DEBUG_SAVED_STATE = DEBUG || false;
     static final boolean DEBUG_STATES = DEBUG || false;
+    static final boolean DEBUG_IDLE = DEBUG || false;
 
     public static final int HOME_STACK_ID = 0;
 
@@ -347,11 +349,12 @@
                               + hr.intent.getComponent().flattenToShortString(), e);
                         throw e;
                     }
-                } else {
-                    stack.ensureActivitiesVisibleLocked(hr, null, processName, 0, false);
                 }
             }
         }
+        if (!didSomething) {
+            ensureActivitiesVisibleLocked(null, 0);
+        }
         return didSomething;
     }
 
@@ -1637,6 +1640,8 @@
 
         ActivityRecord r = ActivityRecord.forToken(token);
         if (r != null) {
+            if (DEBUG_IDLE) Slog.d(TAG, "activityIdleInternalLocked: Callers=" +
+                    Debug.getCallers(4));
             mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
             r.finishLaunchTickingLocked();
             res = r.task.stack.activityIdleInternalLocked(token, fromTimeout, config);
@@ -1996,7 +2001,7 @@
         }
 
         mStartingUsers.add(uss);
-        boolean haveActivities = mHomeStack.switchUserLocked(userId, uss);
+        boolean haveActivities = mHomeStack.switchUserLocked(userId);
 
         resumeTopActivitiesLocked();
 
@@ -2211,6 +2216,7 @@
     }
 
     void scheduleIdleTimeoutLocked(ActivityRecord next) {
+        if (DEBUG_IDLE) Slog.d(TAG, "scheduleIdleTimeoutLocked: Callers=" + Debug.getCallers(4));
         Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG, next);
         mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
     }
@@ -2220,6 +2226,7 @@
     }
 
     void removeTimeoutsForActivityLocked(ActivityRecord r) {
+        if (DEBUG_IDLE) Slog.d(TAG, "removeTimeoutsForActivity: Callers=" + Debug.getCallers(4));
         mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
     }
 
@@ -2243,6 +2250,8 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case IDLE_TIMEOUT_MSG: {
+                    if (DEBUG_IDLE) Slog.d(TAG, "handleMessage: IDLE_TIMEOUT_MSG: Callers=" +
+                            Debug.getCallers(4));
                     if (mService.mDidDexOpt) {
                         mService.mDidDexOpt = false;
                         Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index f963f11..948d234 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -5648,14 +5648,16 @@
             int[] buffer = new int[bm.getWidth() * bm.getHeight()];
             bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
             boolean allBlack = true;
+            final int firstColor = buffer[0];
             for (int i = 0; i < buffer.length; i++) {
-                if (buffer[i] != Color.BLACK) {
+                if (buffer[i] != firstColor) {
                     allBlack = false;
                     break;
                 }
             }
             if (allBlack) {
-                Slog.i(TAG, "Screenshot " + appWin + " was all black! mSurfaceLayer=" +
+                Slog.i(TAG, "Screenshot " + appWin + " was monochrome(" +
+                        Integer.toHexString(firstColor) + ")! mSurfaceLayer=" +
                         (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null") +
                         " minLayer=" + minLayer + " maxLayer=" + maxLayer);
             }