Prevent windows in pinned stack from gaining window focus.

Windows in the pinned stack shouldn't receive input keys, so we prevent
they from gaining window focus so the focus/input keys goes to the stack
below the pinned stack.

Also, cleaned up some code.

Bug: 25580816
Change-Id: Iea1f944d167310233c3dbaea140a4ada568bb815
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 99470c8..d21b327 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2713,57 +2713,60 @@
     }
 
     final void setFocusedActivityLocked(ActivityRecord r, String reason) {
-        if (r != null && mFocusedActivity != r) {
-            if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
-            ActivityRecord last = mFocusedActivity;
-            mFocusedActivity = r;
-            if (r.task.taskType != ActivityRecord.HOME_ACTIVITY_TYPE
-                    && r.task.taskType != ActivityRecord.RECENTS_ACTIVITY_TYPE) {
-                if (mCurAppTimeTracker != r.appTimeTracker) {
-                    // We are switching app tracking.  Complete the current one.
-                    if (mCurAppTimeTracker != null) {
-                        mCurAppTimeTracker.stop();
-                        mHandler.obtainMessage(REPORT_TIME_TRACKER_MSG,
-                                mCurAppTimeTracker).sendToTarget();
-                        mStackSupervisor.clearOtherAppTimeTrackers(r.appTimeTracker);
-                        mCurAppTimeTracker = null;
-                    }
-                    if (r.appTimeTracker != null) {
-                        mCurAppTimeTracker = r.appTimeTracker;
-                        startTimeTrackingFocusedActivityLocked();
-                    }
-                } else {
+        if (r == null || mFocusedActivity == r) {
+            return;
+        }
+
+        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
+        final ActivityRecord last = mFocusedActivity;
+        mFocusedActivity = r;
+        if (r.task.isApplicationTask()) {
+            if (mCurAppTimeTracker != r.appTimeTracker) {
+                // We are switching app tracking.  Complete the current one.
+                if (mCurAppTimeTracker != null) {
+                    mCurAppTimeTracker.stop();
+                    mHandler.obtainMessage(
+                            REPORT_TIME_TRACKER_MSG, mCurAppTimeTracker).sendToTarget();
+                    mStackSupervisor.clearOtherAppTimeTrackers(r.appTimeTracker);
+                    mCurAppTimeTracker = null;
+                }
+                if (r.appTimeTracker != null) {
+                    mCurAppTimeTracker = r.appTimeTracker;
                     startTimeTrackingFocusedActivityLocked();
                 }
             } else {
-                r.appTimeTracker = null;
+                startTimeTrackingFocusedActivityLocked();
             }
-            if (r.task != null && r.task.voiceInteractor != null) {
-                startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
-            } else {
-                finishRunningVoiceLocked();
-                if (last != null && last.task.voiceSession != null) {
-                    // We had been in a voice interaction session, but now focused has
-                    // move to something different.  Just finish the session, we can't
-                    // return to it and retain the proper state and synchronization with
-                    // the voice interaction service.
-                    finishVoiceTask(last.task.voiceSession);
-                }
-            }
-            if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
-                mWindowManager.setFocusedApp(r.appToken, true);
-            }
-            applyUpdateLockStateLocked(r);
-            if (mFocusedActivity.userId != mLastFocusedUserId) {
-                mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
-                mHandler.sendMessage(mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG,
-                        mFocusedActivity.userId, 0));
-                mLastFocusedUserId = mFocusedActivity.userId;
+        } else {
+            r.appTimeTracker = null;
+        }
+        if (r.task.voiceInteractor != null) {
+            startRunningVoiceLocked(r.task.voiceSession, r.info.applicationInfo.uid);
+        } else {
+            finishRunningVoiceLocked();
+            if (last != null && last.task.voiceSession != null) {
+                // We had been in a voice interaction session, but now focused has
+                // move to something different.  Just finish the session, we can't
+                // return to it and retain the proper state and synchronization with
+                // the voice interaction service.
+                finishVoiceTask(last.task.voiceSession);
             }
         }
-        EventLog.writeEvent(EventLogTags.AM_FOCUSED_ACTIVITY,
+        if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
+            mWindowManager.setFocusedApp(r.appToken, true);
+        }
+        applyUpdateLockStateLocked(r);
+        if (mFocusedActivity.userId != mLastFocusedUserId) {
+            mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
+            mHandler.obtainMessage(
+                    FOREGROUND_PROFILE_CHANGED_MSG, mFocusedActivity.userId, 0).sendToTarget();
+            mLastFocusedUserId = mFocusedActivity.userId;
+        }
+
+        EventLogTags.writeAmFocusedActivity(
                 mFocusedActivity == null ? -1 : mFocusedActivity.userId,
-                mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName);
+                mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName,
+                reason);
     }
 
     final void clearFocusedActivity(ActivityRecord r) {
@@ -2779,7 +2782,7 @@
                 }
             }
             mFocusedActivity = null;
-            EventLog.writeEvent(EventLogTags.AM_FOCUSED_ACTIVITY, -1, "NULL");
+            EventLogTags.writeAmFocusedActivity(-1, "NULL", "clearFocusedActivity");
         }
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index da2c8c5c..02a372a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -54,7 +54,6 @@
 import android.app.ResultInfo;
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
@@ -73,7 +72,6 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.service.voice.IVoiceInteractionSession;
 import android.util.EventLog;
 import android.util.Slog;
@@ -2827,41 +2825,43 @@
     }
 
     private void adjustFocusedActivityLocked(ActivityRecord r, String reason) {
-        if (mStackSupervisor.isFocusedStack(this) && mService.mFocusedActivity == r) {
-            ActivityRecord next = topRunningActivityLocked();
-            final String myReason = reason + " adjustFocus";
-            if (next != r) {
-                if (next != null && StackId.keepFocusInStackIfPossible(mStackId)) {
-                    // For freeform, docked, and pinned stacks we always keep the focus within the
-                    // stack as long as there is a running activity in the stack that we can adjust
-                    // focus to.
-                    mService.setFocusedActivityLocked(next, myReason);
-                    return;
-                } else {
-                    final TaskRecord task = r.task;
-                    if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
-                        // For non-fullscreen stack, we want to move the focus to the next visible
-                        // stack to prevent the home screen from moving to the top and obscuring
-                        // other visible stacks.
-                        if (!mFullscreen
-                                && adjustFocusToNextVisibleStackLocked(null, myReason)) {
-                            return;
-                        }
-                        // Move the home stack to the top if this stack is fullscreen or there is no
-                        // other visible stack.
-                        if (mStackSupervisor.moveHomeStackTaskToTop(
-                                task.getTaskToReturnTo(), myReason)) {
-                            // Activity focus was already adjusted. Nothing else to do...
-                            return;
-                        }
+        if (!mStackSupervisor.isFocusedStack(this) || mService.mFocusedActivity != r) {
+            return;
+        }
+
+        final ActivityRecord next = topRunningActivityLocked();
+        final String myReason = reason + " adjustFocus";
+        if (next != r) {
+            if (next != null && StackId.keepFocusInStackIfPossible(mStackId)) {
+                // For freeform, docked, and pinned stacks we always keep the focus within the
+                // stack as long as there is a running activity in the stack that we can adjust
+                // focus to.
+                mService.setFocusedActivityLocked(next, myReason);
+                return;
+            } else {
+                final TaskRecord task = r.task;
+                if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
+                    // For non-fullscreen stack, we want to move the focus to the next visible
+                    // stack to prevent the home screen from moving to the top and obscuring
+                    // other visible stacks.
+                    if (!mFullscreen
+                            && adjustFocusToNextVisibleStackLocked(null, myReason)) {
+                        return;
+                    }
+                    // Move the home stack to the top if this stack is fullscreen or there is no
+                    // other visible stack.
+                    if (mStackSupervisor.moveHomeStackTaskToTop(
+                            task.getTaskToReturnTo(), myReason)) {
+                        // Activity focus was already adjusted. Nothing else to do...
+                        return;
                     }
                 }
             }
+        }
 
-            final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
-            if (top != null) {
-                mService.setFocusedActivityLocked(top, myReason);
-            }
+        final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
+        if (top != null) {
+            mService.setFocusedActivityLocked(top, myReason);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 78b5f33..0397553 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -91,7 +91,7 @@
 30042 am_activity_fully_drawn_time (User|1|5),(Token|1|5),(Component Name|3),(time|2|3)
 
 # Activity focused
-30043 am_focused_activity (User|1|5),(Component Name|3)
+30043 am_focused_activity (User|1|5),(Component Name|3),(Reason|3)
 
 # Stack focus
 30044 am_focused_stack (User|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 77a29f3..77b7f2e 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -269,6 +269,10 @@
         return candidate;
     }
 
+    boolean stackCanReceiveKeys() {
+        return (windows.size() > 0) ? windows.get(windows.size() - 1).stackCanReceiveKeys() : false;
+    }
+
     boolean isVisible() {
         final int N = allAppWindows.size();
         for (int i=0; i<N; i++) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 87deaa4..824d1ac 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -699,26 +699,4 @@
         }
         return false;
     }
-
-    /**
-     * Returns true if this stack has a window that is fully visible, doesn't perform an entry
-     * animation and is just positioned where it's supposed to be.
-     */
-    boolean hasWindowWithFinalVisibility() {
-        for (int i = mTasks.size() - 1; i >= 0; i--) {
-            Task task = mTasks.get(i);
-            for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
-                final AppWindowToken token = task.mAppTokens.get(j);
-                if (token.mAppAnimator.animating || token.mWillReplaceWindow) {
-                    continue;
-                }
-                WindowState win = token.findMainWindow();
-                if (win != null && !win.mWinAnimator.mEnterAnimationPending
-                        && !win.mWinAnimator.mEnteringAnimation) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 395962c..36db53f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -9104,8 +9104,9 @@
                         if (wtoken == token) {
                             break;
                         }
-                        if (mFocusedApp == token) {
-                            // Whoops, we are below the focused app...  no focus for you!
+                        if (mFocusedApp == token && token.stackCanReceiveKeys()) {
+                            // Whoops, we are below the focused app whose stack can receive keys...
+                            // No focus for you!!!
                             if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG,
                                     "findFocusedWindow: Reached focused app=" + mFocusedApp);
                             return null;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 29cadf3..cfa2bb3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -56,6 +56,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
+import static android.app.ActivityManager.StackId;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT;
 import static android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME;
@@ -1564,13 +1565,17 @@
         }
     }
 
-    /**
-     * @return true if this window desires key events.
-     */
-    public final boolean canReceiveKeys() {
+    /** @return true if this window desires key events. */
+    boolean canReceiveKeys() {
         return isVisibleOrAdding()
                 && (mViewVisibility == View.VISIBLE)
-                && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0);
+                && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
+                && stackCanReceiveKeys();
+    }
+
+    boolean stackCanReceiveKeys() {
+        final TaskStack stack = getStack();
+        return stack != null && StackId.canReceiveKeys(stack.mStackId);
     }
 
     @Override