Merge "Update Data Usage Settings for Enterprise" into lmp-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8b32440..7a3953b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4810,6 +4810,10 @@
     <string name="data_usage_data_limit">Set data limit</string>
     <!-- Title for option to pick visible time range from a list available usage periods. [CHAR LIMIT=25] -->
     <string name="data_usage_cycle">Data usage cycle</string>
+    <!-- Title for application data usage separator in data usage list. [CHAR LIMIT=25] -->
+    <string name="data_usage_app_items_header_text">App usage</string>
+    <!-- Title for managed user in data usage list. [CHAR LIMIT=25] -->
+    <string name="data_usage_managed_user_text">Work profile</string>
     <!-- Title for menu option to enable mobile data when roaming. [CHAR LIMIT=26] -->
     <string name="data_usage_menu_roaming">Data roaming</string>
     <!-- Title for menu option to restrict background data usage. [CHAR LIMIT=26] -->
diff --git a/src/com/android/settings/DataUsageSummary.java b/src/com/android/settings/DataUsageSummary.java
index f8f285f..ac9344c 100644
--- a/src/com/android/settings/DataUsageSummary.java
+++ b/src/com/android/settings/DataUsageSummary.java
@@ -87,6 +87,7 @@
 import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.preference.Preference;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -419,7 +420,8 @@
         mEmpty = (TextView) mHeader.findViewById(android.R.id.empty);
         mStupidPadding = mHeader.findViewById(R.id.stupid_padding);
 
-        mAdapter = new DataUsageAdapter(mUidDetailProvider, mInsetSide);
+        final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mAdapter = new DataUsageAdapter(um, mUidDetailProvider, mInsetSide);
         mListView.setOnItemClickListener(mListListener);
         mListView.setAdapter(mAdapter);
 
@@ -1497,7 +1499,7 @@
 
         @Override
         public int compareTo(AppItem another) {
-            int comparison = Integer.compare(another.category, category);
+            int comparison = Integer.compare(category, another.category);
             if (comparison == 0) {
                 comparison = Long.compare(another.total, total);
             }
@@ -1523,13 +1525,15 @@
     public static class DataUsageAdapter extends BaseAdapter {
         private final UidDetailProvider mProvider;
         private final int mInsetSide;
+        private final UserManager mUm;
 
         private ArrayList<AppItem> mItems = Lists.newArrayList();
         private long mLargest;
 
-        public DataUsageAdapter(UidDetailProvider provider, int insetSide) {
+        public DataUsageAdapter(final UserManager userManager, UidDetailProvider provider, int insetSide) {
             mProvider = checkNotNull(provider);
             mInsetSide = insetSide;
+            mUm = userManager;
         }
 
         /**
@@ -1540,8 +1544,8 @@
             mLargest = 0;
 
             final int currentUserId = ActivityManager.getCurrentUser();
+            final List<UserHandle> profiles = mUm.getUserProfiles();
             final SparseArray<AppItem> knownItems = new SparseArray<AppItem>();
-            boolean hasApps = false;
 
             NetworkStats.Entry entry = null;
             final int size = stats != null ? stats.size() : 0;
@@ -1550,35 +1554,43 @@
 
                 // Decide how to collapse items together
                 final int uid = entry.uid;
+
                 final int collapseKey;
+                final int category;
+                final int userId = UserHandle.getUserId(uid);
                 if (UserHandle.isApp(uid)) {
-                    if (UserHandle.getUserId(uid) == currentUserId) {
+                    if (profiles.contains(new UserHandle(userId))) {
+                        if (userId != currentUserId) {
+                            // Add to a managed user item.
+                            final int managedKey = UidDetailProvider.buildKeyForUser(userId);
+                            accumulate(managedKey, knownItems, entry,
+                                    AppItem.CATEGORY_USER);
+                        }
+                        // Add to app item.
                         collapseKey = uid;
+                        category = AppItem.CATEGORY_APP;
                     } else {
-                        collapseKey = UidDetailProvider.buildKeyForUser(UserHandle.getUserId(uid));
+                        // Add to other user item.
+                        collapseKey = UidDetailProvider.buildKeyForUser(userId);
+                        category = AppItem.CATEGORY_USER;
                     }
                 } else if (uid == UID_REMOVED || uid == UID_TETHERING) {
                     collapseKey = uid;
+                    category = AppItem.CATEGORY_APP;
                 } else {
                     collapseKey = android.os.Process.SYSTEM_UID;
+                    category = AppItem.CATEGORY_APP;
                 }
-
-                AppItem item = knownItems.get(collapseKey);
-                if (item == null) {
-                    item = new AppItem(collapseKey);
-                    mItems.add(item);
-                    knownItems.put(item.key, item);
-                }
-                item.addUid(uid);
-                item.total += entry.rxBytes + entry.txBytes;
-                if (item.total > mLargest) {
-                    mLargest = item.total;
-                }
+                accumulate(collapseKey, knownItems, entry, category);
             }
 
-            for (int uid : restrictedUids) {
-                // Only splice in restricted state for current user
-                if (UserHandle.getUserId(uid) != currentUserId) continue;
+            final int restrictedUidsMax = restrictedUids.length;
+            for (int i = 0; i < restrictedUidsMax; ++i) {
+                final int uid = restrictedUids[i];
+                // Only splice in restricted state for current user or managed users
+                if (!profiles.contains(new UserHandle(UserHandle.getUserId(uid)))) {
+                    continue;
+                }
 
                 AppItem item = knownItems.get(uid);
                 if (item == null) {
@@ -1590,8 +1602,7 @@
                 item.restricted = true;
             }
 
-            hasApps = !mItems.isEmpty();
-            if (hasApps) {
+            if (!mItems.isEmpty()) {
                 final AppItem title = new AppItem();
                 title.category = AppItem.CATEGORY_APP_TITLE;
                 mItems.add(title);
@@ -1601,6 +1612,33 @@
             notifyDataSetChanged();
         }
 
+        /**
+         * Accumulate data usage of a network stats entry for the item mapped by the collapse key.
+         * Creates the item if needed.
+         *
+         * @param collapseKey the collapse key used to map the item.
+         * @param knownItems collection of known (already existing) items.
+         * @param entry the network stats entry to extract data usage from.
+         * @param itemCategory the item is categorized on the list view by this category. Must be
+         *            either AppItem.APP_ITEM_CATEGORY or AppItem.MANAGED_USER_ITEM_CATEGORY
+         */
+        private void accumulate(int collapseKey, final SparseArray<AppItem> knownItems,
+                NetworkStats.Entry entry, int itemCategory) {
+            final int uid = entry.uid;
+            AppItem item = knownItems.get(collapseKey);
+            if (item == null) {
+                item = new AppItem(collapseKey);
+                item.category = itemCategory;
+                mItems.add(item);
+                knownItems.put(item.key, item);
+            }
+            item.addUid(uid);
+            item.total += entry.rxBytes + entry.txBytes;
+            if (mLargest < item.total) {
+                mLargest = item.total;
+            }
+        }
+
         @Override
         public int getCount() {
             return mItems.size();
@@ -1616,11 +1654,17 @@
             return mItems.get(position).key;
         }
 
+        /**
+         * See {@link #getItemViewType} for the view types.
+         */
         @Override
         public int getViewTypeCount() {
             return 2;
         }
 
+        /**
+         * Returns 1 for separator items and 0 for anything else.
+         */
         @Override
         public int getItemViewType(int position) {
             final AppItem item = mItems.get(position);
@@ -1638,6 +1682,9 @@
 
         @Override
         public boolean isEnabled(int position) {
+            if (position > mItems.size()) {
+                throw new ArrayIndexOutOfBoundsException();
+            }
             return getItemViewType(position) == 0;
         }
 
diff --git a/src/com/android/settings/net/UidDetailProvider.java b/src/com/android/settings/net/UidDetailProvider.java
index 69e6b5a..e8416ca 100644
--- a/src/com/android/settings/net/UidDetailProvider.java
+++ b/src/com/android/settings/net/UidDetailProvider.java
@@ -27,6 +27,7 @@
 import android.net.ConnectivityManager;
 import android.net.TrafficStats;
 import android.os.UserManager;
+import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.SparseArray;
 
@@ -41,8 +42,18 @@
     private final Context mContext;
     private final SparseArray<UidDetail> mUidDetailCache;
 
+    public static final int OTHER_USER_RANGE_START = -2000;
+
     public static int buildKeyForUser(int userHandle) {
-        return -(2000 + userHandle);
+        return OTHER_USER_RANGE_START - userHandle;
+    }
+
+    public static boolean isKeyForUser(int key) {
+        return key <= OTHER_USER_RANGE_START;
+    }
+
+    public static int getUserIdForKey(int key) {
+        return OTHER_USER_RANGE_START - key;
     }
 
     public UidDetailProvider(Context context) {
@@ -113,14 +124,22 @@
                 return detail;
         }
 
+        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
         // Handle keys that are actually user handles
-        if (uid <= -2000) {
-            final int userHandle = (-uid) - 2000;
-            final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+        if (isKeyForUser(uid)) {
+            final int userHandle = getUserIdForKey(uid);
             final UserInfo info = um.getUserInfo(userHandle);
             if (info != null) {
-                detail.label = res.getString(R.string.running_process_item_user_label, info.name);
-                detail.icon = Utils.getUserIcon(mContext, um, info);
+                if (info.isManagedProfile()) {
+                    detail.label = res.getString(R.string.data_usage_managed_user_text);
+                    detail.icon = Resources.getSystem().getDrawable(
+                            com.android.internal.R.drawable.ic_afw_icon);
+                } else {
+                    detail.label = res.getString(R.string.running_process_item_user_label,
+                            info.name);
+                    detail.icon = Utils.getUserIcon(mContext, um, info);
+                }
                 return detail;
             }
         }
@@ -132,7 +151,8 @@
             if (length == 1) {
                 final ApplicationInfo info = pm.getApplicationInfo(packageNames[0], 0);
                 detail.label = info.loadLabel(pm).toString();
-                detail.icon = info.loadIcon(pm);
+                detail.icon = um.getBadgedDrawableForUser(info.loadIcon(pm),
+                        new UserHandle(UserHandle.getUserId(uid)));
             } else if (length > 1) {
                 detail.detailLabels = new CharSequence[length];
                 for (int i = 0; i < length; i++) {
@@ -144,7 +164,8 @@
                     if (packageInfo.sharedUserLabel != 0) {
                         detail.label = pm.getText(packageName, packageInfo.sharedUserLabel,
                                 packageInfo.applicationInfo).toString();
-                        detail.icon = appInfo.loadIcon(pm);
+                        detail.icon = um.getBadgedDrawableForUser(appInfo.loadIcon(pm),
+                                new UserHandle(UserHandle.getUserId(uid)));
                     }
                 }
             }