Merge "Fix issue #7649590: Background windows sometimes not being hidden for secondary users" into jb-mr1.1-dev
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 0fe2a8e3..2b6cbcf 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -74,7 +74,7 @@
     void setEventDispatching(boolean enabled);
     void addWindowToken(IBinder token, int type);
     void removeWindowToken(IBinder token);
-    void addAppToken(int addPos, IApplicationToken token,
+    void addAppToken(int addPos, int userId, IApplicationToken token,
             int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked);
     void setAppGroupId(IBinder token, int groupId);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
diff --git a/services/java/com/android/server/AttributeCache.java b/services/java/com/android/server/AttributeCache.java
index 81378dc..81613c6 100644
--- a/services/java/com/android/server/AttributeCache.java
+++ b/services/java/com/android/server/AttributeCache.java
@@ -23,6 +23,7 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.os.UserHandle;
 import android.util.SparseArray;
 
 import java.util.HashMap;
@@ -34,52 +35,54 @@
  */
 public final class AttributeCache {
     private static AttributeCache sInstance = null;
-    
+
     private final Context mContext;
-    private final WeakHashMap<String, Package> mPackages =
-            new WeakHashMap<String, Package>();
+    private final SparseArray<WeakHashMap<String, Package>> mPackages =
+            new SparseArray<WeakHashMap<String, Package>>();
     private final Configuration mConfiguration = new Configuration();
-    
+
     public final static class Package {
         public final Context context;
         private final SparseArray<HashMap<int[], Entry>> mMap
                 = new SparseArray<HashMap<int[], Entry>>();
-        
+
         public Package(Context c) {
             context = c;
         }
     }
-    
+
     public final static class Entry {
         public final Context context;
         public final TypedArray array;
-        
+
         public Entry(Context c, TypedArray ta) {
             context = c;
             array = ta;
         }
     }
-    
+
     public static void init(Context context) {
         if (sInstance == null) {
             sInstance = new AttributeCache(context);
         }
     }
-    
+
     public static AttributeCache instance() {
         return sInstance;
     }
-    
+
     public AttributeCache(Context context) {
         mContext = context;
     }
-    
+
     public void removePackage(String packageName) {
         synchronized (this) {
-            mPackages.remove(packageName);
+            for (int i=0; i<mPackages.size(); i++) {
+                mPackages.valueAt(i).remove(packageName);
+            }
         }
     }
-    
+
     public void updateConfiguration(Configuration config) {
         synchronized (this) {
             int changes = mConfiguration.updateFrom(config);
@@ -93,10 +96,21 @@
             }
         }
     }
-    
-    public Entry get(String packageName, int resId, int[] styleable) {
+
+    public void removeUser(int userId) {
         synchronized (this) {
-            Package pkg = mPackages.get(packageName);
+            mPackages.remove(userId);
+        }
+    }
+
+    public Entry get(int userId, String packageName, int resId, int[] styleable) {
+        synchronized (this) {
+            WeakHashMap<String, Package> packages = mPackages.get(userId);
+            if (packages == null) {
+                packages = new WeakHashMap<String, Package>();
+                mPackages.put(userId, packages);
+            }
+            Package pkg = packages.get(packageName);
             HashMap<int[], Entry> map = null;
             Entry ent = null;
             if (pkg != null) {
@@ -110,7 +124,8 @@
             } else {
                 Context context;
                 try {
-                    context = mContext.createPackageContext(packageName, 0);
+                    context = mContext.createPackageContextAsUser(packageName, 0,
+                            new UserHandle(userId));
                     if (context == null) {
                         return null;
                     }
@@ -118,7 +133,7 @@
                     return null;
                 }
                 pkg = new Package(context);
-                mPackages.put(packageName, pkg);
+                packages.put(packageName, pkg);
             }
             
             if (map == null) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d15b854..409480f 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -14551,6 +14551,10 @@
                 // Clean up all state and processes associated with the user.
                 // Kill all the processes for the user.
                 forceStopUserLocked(userId);
+                AttributeCache ac = AttributeCache.instance();
+                if (ac != null) {
+                    ac.removeUser(userId);
+                }
             }
         }
 
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 749dc66..de0f9ca 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -407,7 +407,7 @@
             packageName = aInfo.applicationInfo.packageName;
             launchMode = aInfo.launchMode;
             
-            AttributeCache.Entry ent = AttributeCache.instance().get(packageName,
+            AttributeCache.Entry ent = AttributeCache.instance().get(userId, packageName,
                     realTheme, com.android.internal.R.styleable.Window);
             fullscreen = ent != null && !ent.array.getBoolean(
                     com.android.internal.R.styleable.Window_windowIsFloating, false)
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 4546dc3..27dd732 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1810,8 +1810,8 @@
                         }
                         mHistory.add(addPos, r);
                         r.putInHistory();
-                        mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId,
-                                r.info.screenOrientation, r.fullscreen,
+                        mService.mWindowManager.addAppToken(addPos, r.userId, r.appToken,
+                                r.task.taskId, r.info.screenOrientation, r.fullscreen,
                                 (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
                         if (VALIDATE_TOKENS) {
                             validateAppTokensLocked();
@@ -1875,8 +1875,8 @@
                 mNoAnimActivities.remove(r);
             }
             r.updateOptionsLocked(options);
-            mService.mWindowManager.addAppToken(
-                    addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen,
+            mService.mWindowManager.addAppToken(addPos, r.userId, 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) {
@@ -1914,8 +1914,8 @@
         } else {
             // 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,
+            mService.mWindowManager.addAppToken(addPos, r.userId, r.appToken,
+                    r.task.taskId, r.info.screenOrientation, r.fullscreen,
                     (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0);
             ActivityOptions.abort(options);
         }
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 7efffe5..2802ad7 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -37,6 +37,8 @@
  * really activity) that is displaying windows.
  */
 class AppWindowToken extends WindowToken {
+    // The user who owns this app window token.
+    final int userId;
     // Non-null only for application tokens.
     final IApplicationToken appToken;
 
@@ -98,9 +100,10 @@
     // Input application handle used by the input dispatcher.
     final InputApplicationHandle mInputApplicationHandle;
 
-    AppWindowToken(WindowManagerService _service, IApplicationToken _token) {
+    AppWindowToken(WindowManagerService _service, int _userId, IApplicationToken _token) {
         super(_service, _token.asBinder(),
                 WindowManager.LayoutParams.TYPE_APPLICATION, true);
+        userId = _userId;
         appWindowToken = this;
         appToken = _token;
         mInputApplicationHandle = new InputApplicationHandle(this);
@@ -225,7 +228,8 @@
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
         if (appToken != null) {
-            pw.print(prefix); pw.println("app=true");
+            pw.print(prefix); pw.print("app=true");
+                    pw.print(" userId="); pw.println(userId);
         }
         if (allAppWindows.size() > 0) {
             pw.print(prefix); pw.print("allAppWindows="); pw.println(allAppWindows);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 9ba83d0..003f4db 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -3200,7 +3200,7 @@
         return info;
     }
 
-    private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
+    private AttributeCache.Entry getCachedAnimations(int userId, WindowManager.LayoutParams lp) {
         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
                 + (lp != null ? lp.packageName : null)
                 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
@@ -3215,13 +3215,13 @@
             }
             if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
                     + packageName);
-            return AttributeCache.instance().get(packageName, resId,
+            return AttributeCache.instance().get(userId, packageName, resId,
                     com.android.internal.R.styleable.WindowAnimation);
         }
         return null;
     }
 
-    private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
+    private AttributeCache.Entry getCachedAnimations(int userId, String packageName, int resId) {
         if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
                 + packageName + " resId=0x" + Integer.toHexString(resId));
         if (packageName != null) {
@@ -3230,17 +3230,17 @@
             }
             if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
                     + packageName);
-            return AttributeCache.instance().get(packageName, resId,
+            return AttributeCache.instance().get(userId, packageName, resId,
                     com.android.internal.R.styleable.WindowAnimation);
         }
         return null;
     }
 
-    Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
+    Animation loadAnimation(int userId, WindowManager.LayoutParams lp, int animAttr) {
         int anim = 0;
         Context context = mContext;
         if (animAttr >= 0) {
-            AttributeCache.Entry ent = getCachedAnimations(lp);
+            AttributeCache.Entry ent = getCachedAnimations(userId, lp);
             if (ent != null) {
                 context = ent.context;
                 anim = ent.array.getResourceId(animAttr, 0);
@@ -3252,11 +3252,11 @@
         return null;
     }
 
-    private Animation loadAnimation(String packageName, int resId) {
+    private Animation loadAnimation(int userId, String packageName, int resId) {
         int anim = 0;
         Context context = mContext;
         if (resId >= 0) {
-            AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
+            AttributeCache.Entry ent = getCachedAnimations(userId, packageName, resId);
             if (ent != null) {
                 context = ent.context;
                 anim = resId;
@@ -3484,7 +3484,7 @@
             Animation a;
             boolean initialized = false;
             if (mNextAppTransitionType == ActivityOptions.ANIM_CUSTOM) {
-                a = loadAnimation(mNextAppTransitionPackage, enter ?
+                a = loadAnimation(atoken.userId, mNextAppTransitionPackage, enter ?
                         mNextAppTransitionEnter : mNextAppTransitionExit);
                 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                         "applyAnimation: atoken=" + atoken
@@ -3565,7 +3565,7 @@
                                 : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
                         break;
                 }
-                a = animAttr != 0 ? loadAnimation(lp, animAttr) : null;
+                a = animAttr != 0 ? loadAnimation(atoken.userId, lp, animAttr) : null;
                 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                         "applyAnimation: atoken=" + atoken
                         + " anim=" + a
@@ -3752,7 +3752,7 @@
     }
 
     @Override
-    public void addAppToken(int addPos, IApplicationToken token,
+    public void addAppToken(int addPos, int userId, IApplicationToken token,
             int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
@@ -3779,7 +3779,7 @@
                 Slog.w(TAG, "Attempted to add existing app token: " + token);
                 return;
             }
-            atoken = new AppWindowToken(this, token);
+            atoken = new AppWindowToken(this, userId, token);
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
             atoken.groupId = groupId;
             atoken.appFullscreen = fullscreen;
@@ -4396,8 +4396,8 @@
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Checking theme of starting window: 0x"
                     + Integer.toHexString(theme));
             if (theme != 0) {
-                AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
-                        com.android.internal.R.styleable.Window);
+                AttributeCache.Entry ent = AttributeCache.instance().get(wtoken.userId,
+                        pkg, theme, com.android.internal.R.styleable.Window);
                 if (ent == null) {
                     // Whoops!  App doesn't exist.  Um.  Okay.  We'll just
                     // pretend like we didn't see that.
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index d7fcc67..10784fe 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -14,6 +14,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.os.Debug;
+import android.os.UserHandle;
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.Surface;
@@ -1533,7 +1534,8 @@
                         break;
                 }
                 if (attr >= 0) {
-                    a = mService.loadAnimation(mWin.mAttrs, attr);
+                    a = mService.loadAnimation(UserHandle.getUserId(mWin.mOwnerUid),
+                            mWin.mAttrs, attr);
                 }
             }
             if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
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 746ac06..596f722 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, false);
+            mWm.addAppToken(0, 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/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 3e625f9..091c6e5 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -87,7 +87,7 @@
     // ---- unused implementation of IWindowManager ----
 
     @Override
-    public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, boolean arg4,
+    public void addAppToken(int arg0, int arg1p5, IApplicationToken arg1, int arg2, int arg3, boolean arg4,
                             boolean arg5)
             throws RemoteException {
         // TODO Auto-generated method stub