Merge "Fix Recents in RTL/landscape mode" into jb-mr2-dev
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index da398ef..22ce841 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1094,7 +1094,7 @@
     private boolean deletePackage(String pkg, int unInstallFlags) {
         PackageDeleteObserver obs = new PackageDeleteObserver();
         try {
-            mPm.deletePackage(pkg, obs, unInstallFlags);
+            mPm.deletePackageAsUser(pkg, obs, UserHandle.USER_OWNER, unInstallFlags);
 
             synchronized (obs) {
                 while (!obs.finished) {
diff --git a/core/java/android/accounts/AbstractAccountAuthenticator.java b/core/java/android/accounts/AbstractAccountAuthenticator.java
index e9535ab..fa46689 100644
--- a/core/java/android/accounts/AbstractAccountAuthenticator.java
+++ b/core/java/android/accounts/AbstractAccountAuthenticator.java
@@ -275,6 +275,38 @@
                 handleException(response, "getAccountRemovalAllowed", account.toString(), e);
             }
         }
+
+        public void getAccountCredentialsForCloning(IAccountAuthenticatorResponse response,
+                Account account) throws RemoteException {
+            checkBinderPermission();
+            try {
+                final Bundle result =
+                        AbstractAccountAuthenticator.this.getAccountCredentialsForCloning(
+                                new AccountAuthenticatorResponse(response), account);
+                if (result != null) {
+                    response.onResult(result);
+                }
+            } catch (Exception e) {
+                handleException(response, "getAccountCredentialsForCloning", account.toString(), e);
+            }
+        }
+
+        public void addAccountFromCredentials(IAccountAuthenticatorResponse response,
+                Account account,
+                Bundle accountCredentials) throws RemoteException {
+            checkBinderPermission();
+            try {
+                final Bundle result =
+                        AbstractAccountAuthenticator.this.addAccountFromCredentials(
+                                new AccountAuthenticatorResponse(response), account,
+                                accountCredentials);
+                if (result != null) {
+                    response.onResult(result);
+                }
+            } catch (Exception e) {
+                handleException(response, "addAccountFromCredentials", account.toString(), e);
+            }
+        }
     }
 
     private void handleException(IAccountAuthenticatorResponse response, String method,
@@ -471,4 +503,54 @@
         result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
         return result;
     }
+
+    /**
+     * @hide
+     * Returns a Bundle that contains whatever is required to clone the account on a different
+     * user. The Bundle is passed to the authenticator instance in the target user via
+     * {@link #addAccountFromCredentials(AccountAuthenticatorResponse, Account, Bundle)}.
+     * The default implementation returns null, indicating that cloning is not supported.
+     * @param response to send the result back to the AccountManager, will never be null
+     * @param account the account to clone, will never be null
+     * @return a Bundle result or null if the result is to be returned via the response.
+     * @throws NetworkErrorException
+     * @see {@link #addAccountFromCredentials(AccountAuthenticatorResponse, Account, Bundle)}
+     */
+    public Bundle getAccountCredentialsForCloning(final AccountAuthenticatorResponse response,
+            final Account account) throws NetworkErrorException {
+        new Thread(new Runnable() {
+            public void run() {
+                Bundle result = new Bundle();
+                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+                response.onResult(result);
+            }
+        }).start();
+        return null;
+    }
+
+    /**
+     * @hide
+     * Creates an account based on credentials provided by the authenticator instance of another
+     * user on the device, who has chosen to share the account with this user.
+     * @param response to send the result back to the AccountManager, will never be null
+     * @param account the account to clone, will never be null
+     * @param accountCredentials the Bundle containing the required credentials to create the
+     * account. Contents of the Bundle are only meaningful to the authenticator. This Bundle is
+     * provided by {@link #getAccountCredentialsForCloning(AccountAuthenticatorResponse, Account)}.
+     * @return a Bundle result or null if the result is to be returned via the response.
+     * @throws NetworkErrorException
+     * @see {@link #getAccountCredentialsForCloning(AccountAuthenticatorResponse, Account)}
+     */
+    public Bundle addAccountFromCredentials(final AccountAuthenticatorResponse response,
+            Account account,
+            Bundle accountCredentials) throws NetworkErrorException {
+        new Thread(new Runnable() {
+            public void run() {
+                Bundle result = new Bundle();
+                result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, false);
+                response.onResult(result);
+            }
+        }).start();
+        return null;
+    }
 }
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 6d9bb1d..6aac723 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -1123,6 +1123,57 @@
     }
 
     /**
+     * Adds a shared account from the primary user to a secondary user. Adding the shared account
+     * doesn't take effect immediately. When the target user starts up, any pending shared accounts
+     * are attempted to be copied to the target user from the primary via calls to the
+     * authenticator.
+     * @param account the account to share
+     * @param user the target user
+     * @return
+     * @hide
+     */
+    public boolean addSharedAccount(final Account account, UserHandle user) {
+        try {
+            boolean val = mService.addSharedAccountAsUser(account, user.getIdentifier());
+            return val;
+        } catch (RemoteException re) {
+            // won't ever happen
+            throw new RuntimeException(re);
+        }
+    }
+
+    /**
+     * @hide
+     * Removes the shared account.
+     * @param account the account to remove
+     * @param user the user to remove the account from
+     * @return
+     */
+    public boolean removeSharedAccount(final Account account, UserHandle user) {
+        try {
+            boolean val = mService.removeSharedAccountAsUser(account, user.getIdentifier());
+            return val;
+        } catch (RemoteException re) {
+            // won't ever happen
+            throw new RuntimeException(re);
+        }
+    }
+
+    /**
+     * @hide
+     * @param user
+     * @return
+     */
+    public Account[] getSharedAccounts(UserHandle user) {
+        try {
+            return mService.getSharedAccountsAsUser(user.getIdentifier());
+        } catch (RemoteException re) {
+            // won't ever happen
+            throw new RuntimeException(re);
+        }
+    }
+
+    /**
      * Confirms that the user knows the password for an account to make extra
      * sure they are the owner of the account.  The user-entered password can
      * be supplied directly, otherwise the authenticator for this account type
diff --git a/core/java/android/accounts/IAccountAuthenticator.aidl b/core/java/android/accounts/IAccountAuthenticator.aidl
index 8860710..58612da 100644
--- a/core/java/android/accounts/IAccountAuthenticator.aidl
+++ b/core/java/android/accounts/IAccountAuthenticator.aidl
@@ -70,4 +70,17 @@
      * Gets whether or not the account is allowed to be removed.
      */
     void getAccountRemovalAllowed(in IAccountAuthenticatorResponse response, in Account account);
+
+    /**
+     * Returns a Bundle containing the required credentials to copy the account across users.
+     */
+    void getAccountCredentialsForCloning(in IAccountAuthenticatorResponse response,
+            in Account account);
+
+    /**
+     * Uses the Bundle containing credentials from another instance of the authenticator to create
+     * a copy of the account on this user.
+     */
+    void addAccountFromCredentials(in IAccountAuthenticatorResponse response, in Account account,
+            in Bundle accountCredentials);
 }
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index dbb4924..47b257d 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -58,4 +58,9 @@
         in Bundle options, boolean expectActivityLaunch, int userId);
     void getAuthTokenLabel(in IAccountManagerResponse response, String accountType,
         String authTokenType);
+
+    /* Shared accounts */
+    boolean addSharedAccountAsUser(in Account account, int userId);
+    Account[] getSharedAccountsAsUser(int userId);
+    boolean removeSharedAccountAsUser(in Account account, int userId);
 }
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f09c2fe..6d55dd5 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -50,6 +50,7 @@
 import android.net.Uri;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.Display;
 
@@ -1064,7 +1065,7 @@
     public int installExistingPackage(String packageName)
             throws NameNotFoundException {
         try {
-            int res = mPM.installExistingPackage(packageName);
+            int res = mPM.installExistingPackageAsUser(packageName, UserHandle.myUserId());
             if (res == INSTALL_FAILED_INVALID_URI) {
                 throw new NameNotFoundException("Package " + packageName + " doesn't exist");
             }
@@ -1126,7 +1127,7 @@
     @Override
     public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
         try {
-            mPM.deletePackage(packageName, observer, flags);
+            mPM.deletePackageAsUser(packageName, observer, UserHandle.myUserId(), flags);
         } catch (RemoteException e) {
             // Should never happen!
         }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a368451..a32a201 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -194,20 +194,22 @@
     void setInstallerPackageName(in String targetPackage, in String installerPackageName);
 
     /**
-     * Delete a package.
+     * Delete a package for a specific user.
      *
      * @param packageName The fully qualified name of the package to delete.
      * @param observer a callback to use to notify when the package deletion in finished.
+     * @param userId the id of the user for whom to delete the package
      * @param flags - possible values: {@link #DONT_DELETE_DATA}
      */
-    void deletePackage(in String packageName, IPackageDeleteObserver observer, int flags);
+    void deletePackageAsUser(in String packageName, IPackageDeleteObserver observer,
+            int userId, int flags);
 
     String getInstallerPackageName(in String packageName);
 
     void addPackageToPreferred(String packageName);
-    
+
     void removePackageFromPreferred(String packageName);
-    
+
     List<PackageInfo> getPreferredPackages(int flags);
 
     void resetPreferredActivities(int userId);
@@ -381,7 +383,7 @@
             in VerificationParams verificationParams,
             in ContainerEncryptionParams encryptionParams);
 
-    int installExistingPackage(String packageName);
+    int installExistingPackageAsUser(String packageName, int userId);
 
     void verifyPendingInstall(int id, int verificationCode);
     void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay);
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 593f826..4c87830 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -97,6 +97,10 @@
         return (flags & FLAG_GUEST) == FLAG_GUEST;
     }
 
+    public boolean isRestricted() {
+        return (flags & FLAG_RESTRICTED) == FLAG_RESTRICTED;
+    }
+
     public UserInfo() {
     }
 
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 79dadd7..f359146 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -73,10 +73,6 @@
         ta.recycle();
     }
 
-    public void setOverlayMode(boolean mode) {
-        mOverlayMode = mode;
-    }
-
     public void setActionBar(ActionBarImpl impl, boolean overlayMode) {
         mActionBar = impl;
         mOverlayMode = overlayMode;
@@ -177,7 +173,9 @@
 
         // The top and bottom action bars are always within the content area.
         boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true);
-        changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
+        if (mActionBarBottom != null) {
+            changed |= applyInsets(mActionBarBottom, insets, true, false, true, true);
+        }
 
         mBaseInnerInsets.set(insets);
         computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets);
@@ -219,6 +217,8 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        pullChildren();
+
         int maxHeight = 0;
         int maxWidth = 0;
         int childState = 0;
@@ -234,13 +234,16 @@
                 mActionBarTop.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
         childState = combineMeasuredStates(childState, mActionBarTop.getMeasuredState());
 
-        measureChildWithMargins(mActionBarBottom, widthMeasureSpec, 0, heightMeasureSpec, 0);
-        lp = (LayoutParams) mActionBarBottom.getLayoutParams();
-        maxWidth = Math.max(maxWidth,
-                mActionBarBottom.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
-        maxHeight = Math.max(maxHeight,
-                mActionBarBottom.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
-        childState = combineMeasuredStates(childState, mActionBarBottom.getMeasuredState());
+        // xlarge screen layout doesn't have bottom action bar.
+        if (mActionBarBottom != null) {
+            measureChildWithMargins(mActionBarBottom, widthMeasureSpec, 0, heightMeasureSpec, 0);
+            lp = (LayoutParams) mActionBarBottom.getLayoutParams();
+            maxWidth = Math.max(maxWidth,
+                    mActionBarBottom.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
+            maxHeight = Math.max(maxHeight,
+                    mActionBarBottom.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
+            childState = combineMeasuredStates(childState, mActionBarBottom.getMeasuredState());
+        }
 
         final int vis = getWindowSystemUiVisibility();
         final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0;
@@ -264,10 +267,12 @@
 
         if (mActionView.isSplitActionBar()) {
             // If action bar is split, adjust bottom insets for it.
-            if (stable) {
-                bottomInset = mActionBarHeight;
-            } else {
-                bottomInset = mActionBarBottom.getMeasuredHeight();
+            if (mActionBarBottom != null) {
+                if (stable) {
+                    bottomInset = mActionBarHeight;
+                } else {
+                    bottomInset = mActionBarBottom.getMeasuredHeight();
+                }
             }
         }
 
diff --git a/core/res/res/layout-xlarge/screen_action_bar.xml b/core/res/res/layout-xlarge/screen_action_bar.xml
index 0b6122d..4f286780 100644
--- a/core/res/res/layout-xlarge/screen_action_bar.xml
+++ b/core/res/res/layout-xlarge/screen_action_bar.xml
@@ -15,33 +15,43 @@
 -->
 
 <!--
-This is an optimized layout for a screen with the Action Bar enabled.
+This is an optimized layout for a screen with
+the Action Bar enabled overlaying application content.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:fitsSystemWindows="true"
+<com.android.internal.widget.ActionBarOverlayLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/action_bar_overlay_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
     android:splitMotionEvents="false">
-    <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        style="?android:attr/actionBarStyle">
-        <com.android.internal.widget.ActionBarView
-            android:id="@+id/action_bar"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            style="?android:attr/actionBarStyle" />
-        <com.android.internal.widget.ActionBarContextView
-            android:id="@+id/action_context_bar"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:visibility="gone"
-            style="?android:attr/actionModeStyle" />
-    </com.android.internal.widget.ActionBarContainer>
     <FrameLayout android:id="@android:id/content"
         android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1"
-        android:foregroundGravity="fill_horizontal|top"
-        android:foreground="?android:attr/windowContentOverlay" />
-</LinearLayout>
+        android:layout_height="match_parent" />
+    <LinearLayout android:id="@+id/top_action_bar"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content">
+        <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            style="?android:attr/actionBarStyle"
+            android:gravity="top">
+            <com.android.internal.widget.ActionBarView
+                android:id="@+id/action_bar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                style="?android:attr/actionBarStyle" />
+            <com.android.internal.widget.ActionBarContextView
+                android:id="@+id/action_context_bar"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:visibility="gone"
+                style="?android:attr/actionModeStyle" />
+        </com.android.internal.widget.ActionBarContainer>
+        <ImageView android:src="?android:attr/windowContentOverlay"
+                   android:scaleType="fitXY"
+                   android:layout_width="match_parent"
+                   android:layout_height="wrap_content" />
+    </LinearLayout>
+</com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/layout-xlarge/screen_action_bar_overlay.xml b/core/res/res/layout-xlarge/screen_action_bar_overlay.xml
deleted file mode 100644
index a95635e..0000000
--- a/core/res/res/layout-xlarge/screen_action_bar_overlay.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!--
-This is an optimized layout for a screen with
-the Action Bar enabled overlaying application content.
--->
-
-<com.android.internal.widget.ActionBarOverlayLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/action_bar_overlay_layout"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:splitMotionEvents="false">
-    <FrameLayout android:id="@android:id/content"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-    <LinearLayout android:id="@+id/top_action_bar"
-                  android:layout_width="match_parent"
-                  android:layout_height="wrap_content"
-                  android:layout_gravity="top">
-        <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:layout_alignParentTop="true"
-            style="?android:attr/actionBarStyle"
-            android:gravity="top">
-            <com.android.internal.widget.ActionBarView
-                android:id="@+id/action_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                style="?android:attr/actionBarStyle" />
-            <com.android.internal.widget.ActionBarContextView
-                android:id="@+id/action_context_bar"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:visibility="gone"
-                style="?android:attr/actionModeStyle" />
-        </com.android.internal.widget.ActionBarContainer>
-        <ImageView android:src="?android:attr/windowContentOverlay"
-                   android:scaleType="fitXY"
-                   android:layout_width="match_parent"
-                   android:layout_height="wrap_content" />
-    </LinearLayout>
-</com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c87cb27..140ff70 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1363,7 +1363,6 @@
   <java-symbol type="layout" name="keyguard_account_view" />
   <java-symbol type="layout" name="recent_apps_dialog" />
   <java-symbol type="layout" name="screen_action_bar" />
-  <java-symbol type="layout" name="screen_action_bar_overlay" />
   <java-symbol type="layout" name="screen_custom_title" />
   <java-symbol type="layout" name="screen_progress" />
   <java-symbol type="layout" name="screen_simple" />
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 8e1773a..f824a8e 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -156,6 +156,12 @@
 
     private void updateAlphaFromOffset(View animView, boolean dismissable) {
         if (FADE_OUT_DURING_SWIPE && dismissable) {
+            float alpha = getAlphaForOffset(animView);
+            if (alpha != 0f && alpha != 1f) {
+                animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+            } else {
+                animView.setLayerType(View.LAYER_TYPE_NONE, null);
+            }
             animView.setAlpha(getAlphaForOffset(animView));
         }
         invalidateGlobalRegion(animView);
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index 2a62c17..49295f5 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -21,7 +21,6 @@
 import android.accounts.AccountAndUser;
 import android.accounts.AccountAuthenticatorResponse;
 import android.accounts.AccountManager;
-import android.accounts.AccountManagerResponse;
 import android.accounts.AuthenticatorDescription;
 import android.accounts.GrantCredentialsPermissionActivity;
 import android.accounts.IAccountAuthenticator;
@@ -70,6 +69,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Sets;
@@ -103,7 +103,7 @@
 
     private static final int TIMEOUT_DELAY_MS = 1000 * 60;
     private static final String DATABASE_NAME = "accounts.db";
-    private static final int DATABASE_VERSION = 4;
+    private static final int DATABASE_VERSION = 5;
 
     private final Context mContext;
 
@@ -146,6 +146,8 @@
     private static final String META_KEY = "key";
     private static final String META_VALUE = "value";
 
+    private static final String TABLE_SHARED_ACCOUNTS = "shared_accounts";
+
     private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
             new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
     private static final Intent ACCOUNTS_CHANGED_INTENT;
@@ -249,12 +251,18 @@
 
         IntentFilter userFilter = new IntentFilter();
         userFilter.addAction(Intent.ACTION_USER_REMOVED);
-        mContext.registerReceiver(new BroadcastReceiver() {
+        userFilter.addAction(Intent.ACTION_USER_STARTED);
+        mContext.registerReceiverAsUser(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                onUserRemoved(intent);
+                String action = intent.getAction();
+                if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                    onUserRemoved(intent);
+                } else if (Intent.ACTION_USER_STARTED.equals(action)) {
+                    onUserStarted(intent);
+                }
             }
-        }, userFilter);
+        }, UserHandle.ALL, userFilter, null, null);
     }
 
     public void systemReady() {
@@ -430,6 +438,21 @@
         }
     }
 
+    private void onUserStarted(Intent intent) {
+        int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+        if (userId < 1) return;
+
+        // Check if there's a shared account that needs to be created as an account
+        Account[] sharedAccounts = getSharedAccountsAsUser(userId);
+        if (sharedAccounts == null || sharedAccounts.length == 0) return;
+        Account[] accounts = getAccountsAsUser(null, userId);
+        for (Account sa : sharedAccounts) {
+            if (ArrayUtils.contains(accounts, sa)) continue;
+            // Account doesn't exist. Copy it now.
+            copyAccountToUser(sa, UserHandle.USER_OWNER, userId);
+        }
+    }
+
     @Override
     public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
         Slog.d(TAG, "onServiceChanged() for userId " + userId);
@@ -535,14 +558,120 @@
         // fails if the account already exists
         long identityToken = clearCallingIdentity();
         try {
-            return addAccountInternal(accounts, account, password, extras);
+            return addAccountInternal(accounts, account, password, extras, false);
         } finally {
             restoreCallingIdentity(identityToken);
         }
     }
 
+    private boolean copyAccountToUser(final Account account, int userFrom, int userTo) {
+        final UserAccounts fromAccounts = getUserAccounts(userFrom);
+        final UserAccounts toAccounts = getUserAccounts(userTo);
+        if (fromAccounts == null || toAccounts == null) {
+            return false;
+        }
+
+        long identityToken = clearCallingIdentity();
+        try {
+            new Session(fromAccounts, null, account.type, false,
+                    false /* stripAuthTokenFromResult */) {
+                protected String toDebugString(long now) {
+                    return super.toDebugString(now) + ", getAccountCredentialsForClone"
+                            + ", " + account.type;
+                }
+
+                public void run() throws RemoteException {
+                    mAuthenticator.getAccountCredentialsForCloning(this, account);
+                }
+
+                public void onResult(Bundle result) {
+                    if (result != null) {
+                        if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
+                            // Create a Session for the target user and pass in the bundle
+                            Slog.i(TAG, "getAccountCredentialsForCloning returned success, "
+                                    + "sending result to target user");
+                            completeCloningAccount(result, account, toAccounts);
+                        } else {
+                            Slog.e(TAG, "getAccountCredentialsForCloning returned failure");
+                            clonePassword(fromAccounts, toAccounts, account);
+                        }
+                        return;
+                    } else {
+                        Slog.e(TAG, "getAccountCredentialsForCloning returned null");
+                        clonePassword(fromAccounts, toAccounts, account);
+                        super.onResult(result);
+                    }
+                }
+            }.bind();
+        } finally {
+            restoreCallingIdentity(identityToken);
+        }
+        return true;
+    }
+
+    // TODO: Remove fallback - move to authenticator
+    private void clonePassword(UserAccounts fromAccounts, UserAccounts toAccounts,
+            Account account) {
+        long id = clearCallingIdentity();
+        try {
+            String password = readPasswordInternal(fromAccounts, account);
+            String extraFlags = readUserDataInternal(fromAccounts, account, "flags");
+            String extraServices = readUserDataInternal(fromAccounts, account, "services");
+            Bundle extras = new Bundle();
+            extras.putString("flags", extraFlags);
+            extras.putString("services", extraServices);
+            addAccountInternal(toAccounts, account, password, extras, true);
+        } finally {
+            restoreCallingIdentity(id);
+        }
+    }
+
+    void completeCloningAccount(final Bundle result, final Account account,
+            final UserAccounts targetUser) {
+        long id = clearCallingIdentity();
+        try {
+            new Session(targetUser, null, account.type, false,
+                    false /* stripAuthTokenFromResult */) {
+                protected String toDebugString(long now) {
+                    return super.toDebugString(now) + ", getAccountCredentialsForClone"
+                            + ", " + account.type;
+                }
+
+                public void run() throws RemoteException {
+                    mAuthenticator.addAccountFromCredentials(this, account, result);
+                }
+
+                public void onResult(Bundle result) {
+                    if (result != null) {
+                        if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
+                            // TODO: Anything?
+                            Slog.i(TAG, "addAccount returned success");
+                        } else {
+                            // TODO: Show error notification
+                            // TODO: Should we remove the shadow account to avoid retries?
+                            Slog.e(TAG, "addAccountFromCredentials returned failure");
+                        }
+                        return;
+                    } else {
+                        Slog.e(TAG, "addAccountFromCredentials returned null");
+                        super.onResult(result);
+                    }
+                }
+
+                public void onError(int errorCode, String errorMessage) {
+                    super.onError(errorCode,  errorMessage);
+                    // TODO: Show error notification to user
+                    // TODO: Should we remove the shadow account so that it doesn't keep trying?
+                }
+
+            }.bind();
+        } finally {
+            restoreCallingIdentity(id);
+        }
+    }
+
     private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
-            Bundle extras) {
+            Bundle extras, boolean restricted) {
         if (account == null) {
             return false;
         }
@@ -768,6 +897,21 @@
             removeAccountFromCacheLocked(accounts, account);
             sendAccountsChangedBroadcast(accounts.userId);
         }
+        if (accounts.userId == UserHandle.USER_OWNER) {
+            // Owner's account was removed, remove from any users that are sharing
+            // this account.
+            long id = Binder.clearCallingIdentity();
+            try {
+                List<UserInfo> users = mUserManager.getUsers(true);
+                for (UserInfo user : users) {
+                    if (!user.isPrimary() && user.isRestricted()) {
+                        removeSharedAccountAsUser(account, user.id);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(id);
+            }
+        }
     }
 
     public void invalidateAuthToken(String accountType, String authToken) {
@@ -1606,6 +1750,65 @@
     }
 
     @Override
+    public boolean addSharedAccountAsUser(Account account, int userId) {
+        userId = handleIncomingUser(userId);
+        SQLiteDatabase db = getUserAccounts(userId).openHelper.getWritableDatabase();
+        ContentValues values = new ContentValues();
+        values.put(ACCOUNTS_NAME, account.name);
+        values.put(ACCOUNTS_TYPE, account.type);
+        db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+                new String[] {account.name, account.type});
+        long accountId = db.insert(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME, values);
+        if (accountId < 0) {
+            Log.w(TAG, "insertAccountIntoDatabase: " + account
+                    + ", skipping the DB insert failed");
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean removeSharedAccountAsUser(Account account, int userId) {
+        userId = handleIncomingUser(userId);
+        UserAccounts accounts = getUserAccounts(userId);
+        SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
+        int r = db.delete(TABLE_SHARED_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
+                new String[] {account.name, account.type});
+        if (r > 0) {
+            removeAccountInternal(accounts, account);
+        }
+        return r > 0;
+    }
+
+    @Override
+    public Account[] getSharedAccountsAsUser(int userId) {
+        userId = handleIncomingUser(userId);
+        UserAccounts accounts = getUserAccounts(userId);
+        ArrayList<Account> accountList = new ArrayList<Account>();
+        Cursor cursor = null;
+        try {
+            cursor = accounts.openHelper.getReadableDatabase()
+                    .query(TABLE_SHARED_ACCOUNTS, new String[]{ACCOUNTS_NAME, ACCOUNTS_TYPE},
+                    null, null, null, null, null);
+            if (cursor != null && cursor.moveToFirst()) {
+                int nameIndex = cursor.getColumnIndex(ACCOUNTS_NAME);
+                int typeIndex = cursor.getColumnIndex(ACCOUNTS_TYPE);
+                do {
+                    accountList.add(new Account(cursor.getString(nameIndex),
+                            cursor.getString(typeIndex)));
+                } while (cursor.moveToNext());
+            }
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
+        }
+        Account[] accountArray = new Account[accountList.size()];
+        accountList.toArray(accountArray);
+        return accountArray;
+    }
+
+    @Override
     public Account[] getAccounts(String type) {
         return getAccountsAsUser(type, UserHandle.getCallingUserId());
     }
@@ -1679,7 +1882,6 @@
         private int mNumRequestContinued = 0;
         private int mNumErrors = 0;
 
-
         IAccountAuthenticator mAuthenticator = null;
 
         private final boolean mStripAuthTokenFromResult;
@@ -1688,7 +1890,7 @@
         public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
                 boolean expectActivityLaunch, boolean stripAuthTokenFromResult) {
             super();
-            if (response == null) throw new IllegalArgumentException("response is null");
+            //if (response == null) throw new IllegalArgumentException("response is null");
             if (accountType == null) throw new IllegalArgumentException("accountType is null");
             mAccounts = accounts;
             mStripAuthTokenFromResult = stripAuthTokenFromResult;
@@ -1699,11 +1901,13 @@
             synchronized (mSessions) {
                 mSessions.put(toString(), this);
             }
-            try {
-                response.asBinder().linkToDeath(this, 0 /* flags */);
-            } catch (RemoteException e) {
-                mResponse = null;
-                binderDied();
+            if (response != null) {
+                try {
+                    response.asBinder().linkToDeath(this, 0 /* flags */);
+                } catch (RemoteException e) {
+                    mResponse = null;
+                    binderDied();
+                }
             }
         }
 
@@ -2011,9 +2215,19 @@
                     + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
                     + META_VALUE + " TEXT)");
 
+            createSharedAccountsTable(db);
+
             createAccountsDeletionTrigger(db);
         }
 
+        private void createSharedAccountsTable(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE_SHARED_ACCOUNTS + " ( "
+                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
+                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
+                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
+        }
+
         private void createAccountsDeletionTrigger(SQLiteDatabase db) {
             db.execSQL(""
                     + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
@@ -2058,6 +2272,15 @@
                         " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
                 oldVersion++;
             }
+
+            if (oldVersion == 4) {
+                createSharedAccountsTable(db);
+                oldVersion++;
+            }
+
+            if (oldVersion != newVersion) {
+                Log.e(TAG, "failed to upgrade version " + oldVersion + " to version " + newVersion);
+            }
         }
 
         @Override
@@ -2216,6 +2439,16 @@
         throw new SecurityException(msg);
     }
 
+    private int handleIncomingUser(int userId) {
+        try {
+            return ActivityManagerNative.getDefault().handleIncomingUser(
+                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true, true, "", null);
+        } catch (RemoteException re) {
+            // Shouldn't happen, local.
+        }
+        return userId;
+    }
+
     private boolean inSystemImage(int callingUid) {
         final int callingUserId = UserHandle.getUserId(callingUid);
 
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 7fb8902..cfb0f3f 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -5652,7 +5652,7 @@
                 null);
 
         final int uid = Binder.getCallingUid();
-        if (!isUserAllowed(uid, UserManager.ALLOW_INSTALL_APPS)) {
+        if (!isUserAllowed(UserHandle.getUserId(uid), UserManager.ALLOW_INSTALL_APPS)) {
             try {
                 observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED);
             } catch (RemoteException re) {
@@ -5690,13 +5690,17 @@
      * @hide
      */
     @Override
-    public int installExistingPackage(String packageName) {
+    public int installExistingPackageAsUser(String packageName, int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
                 null);
         PackageSetting pkgSetting;
         final int uid = Binder.getCallingUid();
-        final int userId = UserHandle.getUserId(uid);
-        if (!isUserAllowed(uid, UserManager.ALLOW_INSTALL_APPS)) {
+        if (UserHandle.getUserId(uid) != userId) {
+            mContext.enforceCallingPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "installExistingPackage for user " + userId);
+        }
+        if (!isUserAllowed(userId, UserManager.ALLOW_INSTALL_APPS)) {
             return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
         }
 
@@ -5730,14 +5734,11 @@
         return PackageManager.INSTALL_SUCCEEDED;
     }
 
-    private boolean isUserAllowed(int callingUid, String restrictionKey) {
-        if (callingUid != android.os.Process.myUid()) {
-            Bundle restrictions = sUserManager.getUserRestrictions(
-                    UserHandle.getUserId(callingUid));
-            if (!restrictions.getBoolean(UserManager.ALLOW_INSTALL_APPS)) {
-                Log.w(TAG, "User does not have permission to: " + restrictionKey);
-                return false;
-            }
+    private boolean isUserAllowed(int userId, String restrictionKey) {
+        Bundle restrictions = sUserManager.getUserRestrictions(userId);
+        if (!restrictions.getBoolean(UserManager.ALLOW_INSTALL_APPS)) {
+            Log.w(TAG, "User does not have permission to: " + restrictionKey);
+            return false;
         }
         return true;
     }
@@ -8090,14 +8091,19 @@
         return tmpPackageFile;
     }
 
-    public void deletePackage(final String packageName,
-                              final IPackageDeleteObserver observer,
-                              final int flags) {
+    @Override
+    public void deletePackageAsUser(final String packageName,
+                                    final IPackageDeleteObserver observer,
+                                    final int userId, final int flags) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.DELETE_PACKAGES, null);
-        // Queue up an async operation since the package deletion may take a little while.
         final int uid = Binder.getCallingUid();
-        if (!isUserAllowed(uid, UserManager.ALLOW_UNINSTALL_APPS)) {
+        if (UserHandle.getUserId(uid) != userId) {
+            mContext.enforceCallingPermission(
+                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                    "deletePackage for user " + userId);
+        }
+        if (!isUserAllowed(userId, UserManager.ALLOW_UNINSTALL_APPS)) {
             try {
                 observer.packageDeleted(packageName, PackageManager.DELETE_FAILED_USER_RESTRICTED);
             } catch (RemoteException re) {
@@ -8105,10 +8111,11 @@
             return;
         }
 
+        // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
-                final int returnCode = deletePackageX(packageName, uid, flags);
+                final int returnCode = deletePackageX(packageName, userId, flags);
                 if (observer != null) {
                     try {
                         observer.packageDeleted(packageName, returnCode);
@@ -8134,14 +8141,14 @@
      *  persisting settings for later use
      *  sending a broadcast if necessary
      */
-    private int deletePackageX(String packageName, int uid, int flags) {
+    private int deletePackageX(String packageName, int userId, int flags) {
         final PackageRemovedInfo info = new PackageRemovedInfo();
         final boolean res;
 
         IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
         try {
-            if (dpm != null && dpm.packageHasActiveAdmins(packageName, UserHandle.getUserId(uid))) {
+            if (dpm != null && dpm.packageHasActiveAdmins(packageName, userId)) {
                 Slog.w(TAG, "Not removing package " + packageName + ": has active device admin");
                 return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER;
             }
@@ -8153,7 +8160,7 @@
         synchronized (mInstallLock) {
             res = deletePackageLI(packageName,
                     (flags & PackageManager.DELETE_ALL_USERS) != 0
-                            ? UserHandle.ALL : new UserHandle(UserHandle.getUserId(uid)),
+                            ? UserHandle.ALL : new UserHandle(userId),
                     true, flags | REMOVE_CHATTY, info, true);
             systemUpdate = info.isRemovedPackageSystemUpdate;
             if (res && !systemUpdate && mPackages.get(packageName) == null) {
@@ -8376,7 +8383,7 @@
                 Slog.w(TAG, "Package named '" + packageName + "' doesn't exist.");
                 return false;
             }
-            if (!isSystemApp(ps) && user != null
+            if (user != null
                     && user.getIdentifier() != UserHandle.USER_ALL) {
                 // The caller is asking that the package only be deleted for a single
                 // user.  To do this, we just mark its uninstalled state and delete
@@ -8387,17 +8394,27 @@
                         true,  //stopped
                         true,  //notLaunched
                         null, null);
-                if (ps.isAnyInstalled(sUserManager.getUserIds())) {
-                    // Other user still have this package installed, so all
+                if (!isSystemApp(ps)) {
+                    if (ps.isAnyInstalled(sUserManager.getUserIds())) {
+                        // Other user still have this package installed, so all
+                        // we need to do is clear this user's data and save that
+                        // it is uninstalled.
+                        removeUser = user.getIdentifier();
+                        appId = ps.appId;
+                        mSettings.writePackageRestrictionsLPr(removeUser);
+                    } else {
+                        // We need to set it back to 'installed' so the uninstall
+                        // broadcasts will be sent correctly.
+                        ps.setInstalled(true, user.getIdentifier());
+                    }
+                } else {
+                    // This is a system app, so we assume that the
+                    // other users still have this package installed, so all
                     // we need to do is clear this user's data and save that
                     // it is uninstalled.
                     removeUser = user.getIdentifier();
                     appId = ps.appId;
                     mSettings.writePackageRestrictionsLPr(removeUser);
-                } else {
-                    // We need to set it back to 'installed' so the uninstall
-                    // broadcasts will be sent correctly.
-                    ps.setInstalled(true, user.getIdentifier());
                 }
             }
         }
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index c3f4256..1414cbd 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -542,16 +542,16 @@
 
     private void fallbackToSingleUserLocked() {
         // Create the primary user
-        UserInfo primary = new UserInfo(0,
+        UserInfo primary = new UserInfo(UserHandle.USER_OWNER,
                 mContext.getResources().getString(com.android.internal.R.string.owner_name), null,
                 UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED);
         mUsers.put(0, primary);
         mNextSerialNumber = MIN_USER_ID;
-        
+
         Bundle restrictions = new Bundle();
         initRestrictionsToDefaults(restrictions);
-        mUserRestrictions.append(0, restrictions);
-        
+        mUserRestrictions.append(UserHandle.USER_OWNER, restrictions);
+
         updateUserIdsLocked();
 
         writeUserListLocked();
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index a0ed530..506fcec 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -997,6 +997,9 @@
                     Slog.i(TAG, "WIN DEATH: " + win);
                     if (win != null) {
                         mService.removeWindowLocked(mSession, win);
+                    } else if (WindowState.this.mHasSurface) {
+                        Slog.e(TAG, "!!! LEAK !!! Window removed but surface still valid.");
+                        mService.removeWindowLocked(mSession, WindowState.this);
                     }
                 }
             } catch (IllegalArgumentException ex) {
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 4a489d5..e6a1df1 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -1745,6 +1745,8 @@
                     //Ignore more client requests
                     break;
                 case PEER_CONNECTION_USER_ACCEPT:
+                    //Stop discovery to avoid failure due to channel switch
+                    mWifiNative.p2pStopFind();
                     if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) {
                         mWifiNative.startWpsPbc(mGroup.getInterface(), null);
                     } else {