Merge "New generic background restrictions."
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 2db1d15..9ee6228 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -48,6 +48,8 @@
     UserInfo getProfileParent(int userHandle);
     boolean isSameProfileGroup(int userId, int otherUserId);
     UserInfo getUserInfo(int userHandle);
+    String getUserAccount(int userId);
+    void setUserAccount(int userId, String accountName);
     long getUserCreationTime(int userHandle);
     boolean isRestricted();
     boolean canHaveRestrictedProfile(int userId);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c8abcef..1346a39 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -15,8 +15,10 @@
  */
 package android.os;
 
+import android.Manifest;
 import android.accounts.AccountManager;
 import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -1121,6 +1123,39 @@
     }
 
     /**
+     * @return the user's account name, null if not found.
+     * @hide
+     */
+    @RequiresPermission( allOf = {
+            Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+            Manifest.permission.MANAGE_USERS
+    })
+    public @Nullable String getUserAccount(int userHandle) {
+        try {
+            return mService.getUserAccount(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not get user account", re);
+            return null;
+        }
+    }
+
+    /**
+     * Set account name for the given user.
+     * @hide
+     */
+    @RequiresPermission( allOf = {
+            Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+            Manifest.permission.MANAGE_USERS
+    })
+    public void setUserAccount(int userHandle, @Nullable String accountName) {
+        try {
+            mService.setUserAccount(userHandle, accountName);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not set user account", re);
+        }
+    }
+
+    /**
      * Returns information for Primary user.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      *
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 1b97b65..0e66374 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -344,7 +344,7 @@
     <family>
         <font weight="400" style="normal">NanumGothic.ttf</font>
     </family>
-    <family>
+    <family lang="und-Qaae">
         <font weight="400" style="normal">NotoColorEmoji.ttf</font>
     </family>
     <family>
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4497e4d..0b59c16 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Activity;
@@ -58,6 +59,7 @@
 import android.system.OsConstants;
 import android.util.AtomicFile;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -90,6 +92,7 @@
 import java.util.List;
 
 import libcore.io.IoUtils;
+import libcore.util.Objects;
 
 /**
  * Service for {@link UserManager}.
@@ -107,6 +110,7 @@
     private static final boolean DBG_WITH_STACKTRACE = false; // DO NOT SUBMIT WITH TRUE
 
     private static final String TAG_NAME = "name";
+    private static final String TAG_ACCOUNT = "account";
     private static final String ATTR_FLAGS = "flags";
     private static final String ATTR_ICON_PATH = "icon";
     private static final String ATTR_ID = "id";
@@ -178,6 +182,14 @@
     private final SparseArray<UserInfo> mUsers = new SparseArray<>();
 
     /**
+     * This collection contains each user's account name if the user chose to set one up
+     * during the initial user creation process.  Keeping this information separate from mUsers
+     * to avoid accidentally leak it.
+     */
+    @GuardedBy("mUsersLock")
+    private final SparseArray<String> mUserAccounts = new SparseArray<>();
+
+    /**
      * User restrictions set via UserManager.  This doesn't include restrictions set by
      * device owner / profile owners.
      *
@@ -336,6 +348,33 @@
     }
 
     @Override
+    public String getUserAccount(int userId) {
+        checkManageUserAndAcrossUsersFullPermission("get user account");
+        synchronized (mUsersLock) {
+            return mUserAccounts.get(userId);
+        }
+    }
+
+    @Override
+    public void setUserAccount(int userId, String accountName) {
+        checkManageUserAndAcrossUsersFullPermission("set user account");
+        UserInfo userToUpdate = null;
+        synchronized (mPackagesLock) {
+            synchronized (mUsersLock) {
+                String currentAccount = mUserAccounts.get(userId);
+                if (!Objects.equal(currentAccount, accountName)) {
+                    mUserAccounts.put(userId, accountName);
+                    userToUpdate = mUsers.get(userId);
+                }
+            }
+
+            if (userToUpdate != null) {
+                writeUserLP(userToUpdate);
+            }
+        }
+    }
+
+    @Override
     public UserInfo getPrimaryUser() {
         checkManageUsersPermission("query users");
         synchronized (mUsersLock) {
@@ -1052,6 +1091,30 @@
 
     /**
      * Enforces that only the system UID or root's UID or apps that have the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} and
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL INTERACT_ACROSS_USERS_FULL}
+     * permissions can make certain calls to the UserManager.
+     *
+     * @param message used as message if SecurityException is thrown
+     * @throws SecurityException if the caller does not have enough privilege.
+     */
+    private static final void checkManageUserAndAcrossUsersFullPermission(String message) {
+        final int uid = Binder.getCallingUid();
+        if (uid != Process.SYSTEM_UID && uid != 0
+                && ActivityManager.checkComponentPermission(
+                Manifest.permission.MANAGE_USERS,
+                uid, -1, true) != PackageManager.PERMISSION_GRANTED
+                && ActivityManager.checkComponentPermission(
+                Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+                uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException(
+                    "You need MANAGE_USERS and INTERACT_ACROSS_USERS_FULL permission to: "
+                            + message);
+        }
+    }
+
+    /**
+     * Enforces that only the system UID or root's UID or apps that have the
      * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}
      * permission can make certain calls to the UserManager.
      *
@@ -1068,13 +1131,6 @@
         }
     }
 
-    private static void checkSystemOrRoot(String message) {
-        final int uid = Binder.getCallingUid();
-        if (uid != Process.SYSTEM_UID && uid != 0) {
-            throw new SecurityException("Only system may call: " + message);
-        }
-    }
-
     private void writeBitmapLP(UserInfo info, Bitmap bitmap) {
         try {
             File dir = new File(mUsersDir, Integer.toString(info.id));
@@ -1156,11 +1212,14 @@
                     final String name = parser.getName();
                     if (name.equals(TAG_USER)) {
                         String id = parser.getAttributeValue(null, ATTR_ID);
-                        UserInfo user = readUserLP(Integer.parseInt(id));
+                        Pair<UserInfo, String> userPair = readUserLP(Integer.parseInt(id));
 
-                        if (user != null) {
+                        if (userPair != null) {
+                            UserInfo user = userPair.first;
+                            String account = userPair.second;
                             synchronized (mUsersLock) {
                                 mUsers.put(user.id, user);
+                                mUserAccounts.put(user.id, account);
                                 if (mNextSerialNumber < 0 || mNextSerialNumber <= user.id) {
                                     mNextSerialNumber = user.id + 1;
                                 }
@@ -1360,6 +1419,17 @@
                         mDevicePolicyLocalUserRestrictions.get(userInfo.id),
                         TAG_DEVICE_POLICY_RESTRICTIONS);
             }
+            // Update the account field if it is set.
+            String account;
+            synchronized (mUsersLock) {
+                account = mUserAccounts.get(userInfo.id);
+            }
+            if (account != null) {
+                serializer.startTag(null, TAG_ACCOUNT);
+                serializer.text(account);
+                serializer.endTag(null, TAG_ACCOUNT);
+            }
+
             serializer.endTag(null, TAG_USER);
 
             serializer.endDocument();
@@ -1432,10 +1502,11 @@
         }
     }
 
-    private UserInfo readUserLP(int id) {
+    private Pair<UserInfo, String> readUserLP(int id) {
         int flags = 0;
         int serialNumber = id;
         String name = null;
+        String account = null;
         String iconPath = null;
         long creationTime = 0L;
         long lastLoggedInTime = 0L;
@@ -1504,6 +1575,11 @@
                         UserRestrictionsUtils.readRestrictions(parser, baseRestrictions);
                     } else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) {
                         UserRestrictionsUtils.readRestrictions(parser, localRestrictions);
+                    } else if (TAG_ACCOUNT.equals(tag)) {
+                        type = parser.next();
+                        if (type == XmlPullParser.TEXT) {
+                            account = parser.getText();
+                        }
                     }
                 }
             }
@@ -1520,7 +1596,7 @@
                 mBaseUserRestrictions.put(id, baseRestrictions);
                 mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
             }
-            return userInfo;
+            return new Pair<>(userInfo, account);
 
         } catch (IOException ioe) {
         } catch (XmlPullParserException pe) {
@@ -1947,6 +2023,7 @@
         // Remove this user from the list
         synchronized (mUsersLock) {
             mUsers.remove(userHandle);
+            mUserAccounts.delete(userHandle);
             mIsUserManaged.delete(userHandle);
         }
         synchronized (mRestrictionsLock) {
@@ -2507,6 +2584,11 @@
                                 pw, "      ", mCachedEffectiveUserRestrictions.get(user.id));
                     }
                     pw.println();
+                    String accountName = mUserAccounts.get(userId);
+                    if (accountName != null) {
+                        pw.print("    Account name: " + accountName);
+                        pw.println();
+                    }
                 }
             }
             pw.println("  Device policy global restrictions:");
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 9e70138..48a11c5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -16,9 +16,12 @@
 
 package com.android.server.pm;
 
+import android.content.pm.UserInfo;
 import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Parcelable;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.test.AndroidTestCase;
 import android.util.AtomicFile;
 
@@ -29,6 +32,7 @@
 public class UserManagerServiceTest extends AndroidTestCase {
     private static String[] STRING_ARRAY = new String[] {"<tag", "<![CDATA["};
     private File restrictionsFile;
+    private int tempUserId = UserHandle.USER_NULL;
 
     @Override
     protected void setUp() throws Exception {
@@ -40,6 +44,9 @@
     @Override
     protected void tearDown() throws Exception {
         restrictionsFile.delete();
+        if (tempUserId != UserHandle.USER_NULL) {
+            UserManager.get(mContext).removeUser(tempUserId);
+        }
         super.tearDown();
     }
 
@@ -55,6 +62,16 @@
         assertBundle(bundle);
     }
 
+    public void testAddUserWithAccount() {
+        UserManager um = UserManager.get(mContext);
+        UserInfo user = um.createUser("Test User", 0);
+        assertNotNull(user);
+        tempUserId = user.id;
+        String accountName = "Test Account";
+        um.setUserAccount(tempUserId, accountName);
+        assertEquals(accountName, um.getUserAccount(tempUserId));
+    }
+
     private Bundle createBundle() {
         Bundle result = new Bundle();
         // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index b5b4e5f..9eb1665 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -247,6 +247,14 @@
             "android.telecom.extra.CONNECTION_SERVICE";
 
     /**
+     * Optional extra for communicating the call technology used by a
+     * {@link com.android.internal.telephony.Connection} to Telecom
+     * @hide
+     */
+    public static final String EXTRA_CALL_TECHNOLOGY_TYPE =
+            "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
+
+    /**
      * An optional {@link android.content.Intent#ACTION_CALL} intent extra denoting the
      * package name of the app specifying an alternative gateway for the call.
      * The value is a string.