Adds showWhenLocked attribute to Activities.

The new attribute allows an Activity such as the alarm to appear
on all users screens.

Bug: 7213805 fixed.
Change-Id: If7866b13d88c04af07debc69e0e875d0adc6050a
diff --git a/api/17.txt b/api/17.txt
index e86de90..d7f7c3c 100644
--- a/api/17.txt
+++ b/api/17.txt
@@ -912,6 +912,7 @@
     field public static final int showAsAction = 16843481; // 0x10102d9
     field public static final int showDefault = 16843258; // 0x10101fa
     field public static final int showDividers = 16843561; // 0x1010329
+    field public static final int showOnLockScreen = 16843721; // 0x10103c9
     field public static final int showSilent = 16843259; // 0x10101fb
     field public static final int showWeekNumber = 16843582; // 0x101033e
     field public static final int shownWeekCount = 16843585; // 0x1010341
diff --git a/api/current.txt b/api/current.txt
index e86de90..d7f7c3c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -912,6 +912,7 @@
     field public static final int showAsAction = 16843481; // 0x10102d9
     field public static final int showDefault = 16843258; // 0x10101fa
     field public static final int showDividers = 16843561; // 0x1010329
+    field public static final int showOnLockScreen = 16843721; // 0x10103c9
     field public static final int showSilent = 16843259; // 0x10101fb
     field public static final int showWeekNumber = 16843582; // 0x101033e
     field public static final int shownWeekCount = 16843585; // 0x1010341
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index b884b98..e2ca1dd 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -155,6 +155,12 @@
      */
     public static final int FLAG_HARDWARE_ACCELERATED = 0x0200;
     /**
+     * Value for {@link #flags}: true when the application can be displayed over the lockscreen
+     * and consequently over all users' windows.
+     * @hide
+     */
+    public static final int FLAG_SHOW_ON_LOCK_SCREEN = 0x0400;
+    /**
      * @hide
      * Bit in {@link #flags} corresponding to an immersive activity
      * that wishes not to be interrupted by notifications.
@@ -170,7 +176,7 @@
      * "toast" window).
      * {@see android.app.Notification#FLAG_HIGH_PRIORITY}
      */
-    public static final int FLAG_IMMERSIVE = 0x0400;
+    public static final int FLAG_IMMERSIVE = 0x0800;
     /**
      * @hide Bit in {@link #flags}: If set, this component will only be seen
      * by the primary user.  Only works with broadcast receivers.  Set from the
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c2b75f4..3e8c2a8 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2160,11 +2160,17 @@
         }
 
         if (sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestActivity_showOnLockScreen,
+                false)) {
+            a.info.flags |= ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN;
+        }
+
+        if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestActivity_immersive,
                 false)) {
             a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
         }
-        
+
         if (!receiver) {
             if (sa.getBoolean(
                     com.android.internal.R.styleable.AndroidManifestActivity_hardwareAccelerated,
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index a64cbf7..97202b4 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -74,7 +74,7 @@
     void addWindowToken(IBinder token, int type);
     void removeWindowToken(IBinder token);
     void addAppToken(int addPos, IApplicationToken token,
-            int groupId, int requestedOrientation, boolean fullscreen);
+            int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked);
     void setAppGroupId(IBinder token, int groupId);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index eb3f72e..4c97414 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -219,12 +219,14 @@
          * Window type: an application window that serves as the "base" window
          * of the overall application; all other application windows will
          * appear on top of it.
+         * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_BASE_APPLICATION   = 1;
         
         /**
          * Window type: a normal application window.  The {@link #token} must be
          * an Activity token identifying who the window belongs to.
+         * In multiuser systems shows only on the owning user's window.
          */
         public static final int TYPE_APPLICATION        = 2;
     
@@ -233,6 +235,7 @@
          * application is starting.  Not for use by applications themselves;
          * this is used by the system to display something until the
          * application can show its own windows.
+         * In multiuser systems shows on all users' windows.
          */
         public static final int TYPE_APPLICATION_STARTING = 3;
     
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 58b6572..d899e9d 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -444,6 +444,10 @@
          recently launched activities. -->
     <attr name="excludeFromRecents" format="boolean" />
 
+    <!-- Specify that an Activity should be shown over the lock screen and,
+         in a multiuser environment, across all users' windows -->
+    <attr name="showOnLockScreen" format="boolean" />
+
     <!-- Specify the authorities under which this content provider can be
          found.  Multiple authorities may be supplied by separating them
          with a semicolon.  Authority names should use a Java-style naming
@@ -1376,6 +1380,7 @@
         <attr name="alwaysRetainTaskState" />
         <attr name="stateNotNeeded" />
         <attr name="excludeFromRecents" />
+        <attr name="showOnLockScreen" />
         <!-- Specify whether the activity is enabled or not (that is, can be instantiated by the system).
              It can also be specified for an application as a whole, in which case a value of "false"
              will override any component specific values (a value of "true" will not override the
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ffc09de..d7a480b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2018,10 +2018,12 @@
   <public type="attr" name="permissionGroupFlags" id="0x010103c5" />
   <public type="attr" name="labelFor" id="0x010103c6" />
   <public type="attr" name="permissionFlags" id="0x010103c7" />
-  <public type="attr" name="checkedTextViewStyle" />
-  <public type="style" name="Widget.Holo.CheckedTextView" />
-  <public type="style" name="Widget.Holo.Light.CheckedTextView" />
-  <public type="style" name="Widget.DeviceDefault.CheckedTextView" />
-  <public type="style" name="Widget.DeviceDefault.Light.CheckedTextView" />
+  <public type="attr" name="checkedTextViewStyle" id="0x010103c8" />
+  <public type="attr" name="showOnLockScreen" id="0x010103c9" />
+
+  <public type="style" name="Widget.Holo.CheckedTextView" id="0x010301d9" />
+  <public type="style" name="Widget.Holo.Light.CheckedTextView" id="0x010301da" />
+  <public type="style" name="Widget.DeviceDefault.CheckedTextView" id="0x010301db" />
+  <public type="style" name="Widget.DeviceDefault.Light.CheckedTextView" id="0x010301dc" />
 
 </resources>
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 3ef6767..dcdde76 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7453,6 +7453,7 @@
         lp.format = v.getBackground().getOpacity();
         lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
         ((WindowManager)mContext.getSystemService(
                 Context.WINDOW_SERVICE)).addView(v, lp);
     }
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index a6dc867..4bcb339 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -420,12 +420,17 @@
         mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
         mLaunchingActivity.setReferenceCounted(false);
     }
-    
+
+    private boolean okToShow(ActivityRecord r) {
+        return r.userId == mCurrentUser
+                || (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0;
+    }
+
     final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
-            if (!r.finishing && r != notTop && r.userId == mCurrentUser) {
+            if (!r.finishing && r != notTop && okToShow(r)) {
                 return r;
             }
             i--;
@@ -437,7 +442,7 @@
         int i = mHistory.size()-1;
         while (i >= 0) {
             ActivityRecord r = mHistory.get(i);
-            if (!r.finishing && !r.delayedResume && r != notTop && r.userId == mCurrentUser) {
+            if (!r.finishing && !r.delayedResume && r != notTop && okToShow(r)) {
                 return r;
             }
             i--;
@@ -460,7 +465,7 @@
             ActivityRecord r = mHistory.get(i);
             // Note: the taskId check depends on real taskId fields being non-zero
             if (!r.finishing && (token != r.appToken) && (taskId != r.task.taskId)
-                    && r.userId == mCurrentUser) {
+                    && okToShow(r)) {
                 return r;
             }
             i--;
@@ -1806,7 +1811,8 @@
                         mHistory.add(addPos, r);
                         r.putInHistory();
                         mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
-                                r.info.screenOrientation, r.fullscreen);
+                                r.info.screenOrientation, r.fullscreen,
+                                (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
                         if (VALIDATE_TOKENS) {
                             validateAppTokensLocked();
                         }
@@ -1870,7 +1876,8 @@
             }
             r.updateOptionsLocked(options);
             mService.mWindowManager.addAppToken(
-                    addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen);
+                    addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
+                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
             boolean doShow = true;
             if (newTask) {
                 // Even though this activity is starting fresh, we still need
@@ -1908,7 +1915,8 @@
             // If this is the first activity, don't do any fancy animations,
             // because there is nothing for it to animate on top of.
             mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
-                    r.info.screenOrientation, r.fullscreen);
+                    r.info.screenOrientation, r.fullscreen,
+                    (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
             ActivityOptions.abort(options);
         }
         if (VALIDATE_TOKENS) {
@@ -2616,7 +2624,6 @@
             Bundle options) {
         final Intent intent = r.intent;
         final int callingUid = r.launchedFromUid;
-        final int userId = r.userId;
 
         int launchFlags = intent.getFlags();
         
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 13b072c..7efffe5 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -50,6 +50,7 @@
     int groupId = -1;
     boolean appFullscreen;
     int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+    boolean showWhenLocked;
 
     // The input dispatching timeout for this application token in nanoseconds.
     long inputDispatchingTimeoutNanos;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 1b1d85b..e670028 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -3703,7 +3703,7 @@
 
     @Override
     public void addAppToken(int addPos, IApplicationToken token,
-            int groupId, int requestedOrientation, boolean fullscreen) {
+            int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3733,6 +3733,7 @@
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
             atoken.groupId = groupId;
             atoken.appFullscreen = fullscreen;
+            atoken.showWhenLocked = showWhenLocked;
             atoken.requestedOrientation = requestedOrientation;
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
                     + " at " + addPos);
@@ -5411,7 +5412,7 @@
                 final WindowList windows = iterator.next().getWindowList();
                 for (int i = 0; i < windows.size(); i++) {
                     final WindowState win = windows.get(i);
-                    if (win.isOtherUsersAppWindow()) {
+                    if (win.isHiddenFromUserLocked()) {
                         Slog.w(TAG, "current user violation " + newUserId + " hiding "
                                 + win + ", attrs=" + win.mAttrs.type + ", belonging to "
                                 + win.mOwnerUid);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 6e388f2..dee66a6 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -940,7 +940,7 @@
     }
 
     boolean showLw(boolean doAnimation, boolean requestAnim) {
-        if (isOtherUsersAppWindow()) {
+        if (isHiddenFromUserLocked()) {
             Slog.w(TAG, "current user violation " + mService.mCurrentUserId + " trying to display "
                     + this + ", type " + mAttrs.type + ", belonging to " + mOwnerUid);
             return false;
@@ -1030,7 +1030,18 @@
         mShowToOwnerOnly = showToOwnerOnly;
     }
 
-    boolean isOtherUsersAppWindow() {
+    boolean isHiddenFromUserLocked() {
+        // Save some cycles by not calling getDisplayInfo unless it is an application
+        // window intended for all users.
+        if (mAttrs.type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
+                && mAppToken != null && mAppToken.showWhenLocked) {
+            final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
+            if (isFullscreen(displayInfo.appWidth, displayInfo.appHeight)) {
+                // Is a fullscreen window, like the clock alarm. Show to everyone.
+                return false;
+            }
+        }
+
         return mShowToOwnerOnly && UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId;
     }
 
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 817a234..d63fb5a 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -1334,7 +1334,7 @@
 
     // This must be called while inside a transaction.
     boolean performShowLocked() {
-        if (mWin.isOtherUsersAppWindow()) {
+        if (mWin.isHiddenFromUserLocked()) {
             Slog.w(TAG, "current user violation " + mService.mCurrentUserId + " trying to display "
                     + this + ", type " + mWin.mAttrs.type + ", belonging to " + mWin.mOwnerUid);
             return false;
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 1f6279c..746ac06 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
         }
         
         try {
-            mWm.addAppToken(0, null, 0, 0, false);
+            mWm.addAppToken(0, null, 0, 0, false, false);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
index b8d21f3..ddb0665 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowManager.java
@@ -78,7 +78,8 @@
     }
 
     @Override
-    public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4)
+    public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4,
+                            boolean arg5)
             throws RemoteException {
         // TODO Auto-generated method stub