Merge "Cleanup Controllers/Fragments"
diff --git a/res/drawable/line.xml b/res/drawable/line.xml
new file mode 100644
index 0000000..786ed1c
--- /dev/null
+++ b/res/drawable/line.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 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.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+
+    <solid android:color="@android:color/transparent" />
+
+    <padding
+        android:top="10dp"
+        android:left="10dp"
+        android:right="10dp"
+        android:bottom="10dp"/>
+</shape>
\ No newline at end of file
diff --git a/res/drawable/line_drawable.xml b/res/drawable/line_drawable.xml
new file mode 100644
index 0000000..a524c61
--- /dev/null
+++ b/res/drawable/line_drawable.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 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.
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_pressed="true"
+        android:drawable="@drawable/line" />
+
+    <item
+        android:drawable="@drawable/line" />
+</selector>
\ No newline at end of file
diff --git a/res/drawable/thumb.xml b/res/drawable/thumb.xml
new file mode 100644
index 0000000..42fbd8c
--- /dev/null
+++ b/res/drawable/thumb.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 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.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+
+    <corners
+        android:topLeftRadius="8dp"
+        android:topRightRadius="8dp"
+        android:bottomLeftRadius="8dp"
+        android:bottomRightRadius="8dp"/>
+
+    <padding
+        android:paddingLeft="8dp"
+        android:paddingRight="8dp" />
+
+    <solid android:color="?android:attr/colorControlNormal" />
+
+</shape>
\ No newline at end of file
diff --git a/res/drawable/thumb_drawable.xml b/res/drawable/thumb_drawable.xml
new file mode 100644
index 0000000..b99536d
--- /dev/null
+++ b/res/drawable/thumb_drawable.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2017 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.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item
+        android:state_pressed="true"
+        android:drawable="@drawable/thumb"/>
+
+    <item
+        android:drawable="@drawable/thumb"/>
+</selector>
\ No newline at end of file
diff --git a/res/layout/manage_applications_apps.xml b/res/layout/manage_applications_apps.xml
index e4ec871..d362528 100644
--- a/res/layout/manage_applications_apps.xml
+++ b/res/layout/manage_applications_apps.xml
@@ -14,44 +14,53 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical">
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
 
     <FrameLayout
-              android:layout_width="match_parent"
-              android:layout_height="0dp"
-              android:layout_weight="1">
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
 
-        <LinearLayout android:id="@+id/list_container"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:orientation="vertical"
-                android:visibility="gone">
+        <LinearLayout
+            android:id="@+id/list_container"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical"
+            android:visibility="gone">
 
             <FrameLayout
                 android:id="@+id/pinned_header"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content" />
 
-            <FrameLayout android:layout_width="match_parent"
-                    android:layout_height="0px"
-                    android:layout_weight="1">
+            <FrameLayout
+                android:layout_width="match_parent"
+                android:layout_height="0px"
+                android:layout_weight="1">
 
-                <ListView android:id="@android:id/list"
-                    android:drawSelectorOnTop="false"
+                <android.support.v7.widget.RecyclerView
+                    android:id="@+id/apps_list"
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
-                    android:clipToPadding="false"
-                    android:scrollbarStyle="@integer/preference_scrollbar_style" />
+                    settings:fastScrollEnabled="true"
+                    settings:fastScrollHorizontalThumbDrawable="@drawable/thumb_drawable"
+                    settings:fastScrollHorizontalTrackDrawable="@drawable/line_drawable"
+                    settings:fastScrollVerticalThumbDrawable="@drawable/thumb_drawable"
+                    settings:fastScrollVerticalTrackDrawable="@drawable/line_drawable"/>
 
-                <TextView android:id="@android:id/empty"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        android:gravity="center"
-                        android:text="@string/no_applications"
-                        android:textAppearance="?android:attr/textAppearanceLarge" />
+                <TextView
+                    android:id="@android:id/empty"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:gravity="center"
+                    android:text="@string/no_applications"
+                    android:textAppearance="?android:attr/textAppearanceLarge"
+                    android:visibility="invisible" />
 
             </FrameLayout>
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 819c491..9687bf2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6703,7 +6703,7 @@
     <!-- Do not disturb: Subtitle for DND behavior indicating no sound will get past DND due to user and/or API-invoked Total Silence mode. [CHAR LIMIT=40] -->
     <string name="zen_mode_behavior_total_silence">No sound (Total Silence)</string>
 
-    <!-- Do not disturb: Used before specifying which sounds can bypass DND (ie: No sound except alarms and reminders). [CHAR LIMIT=30] -->
+    <!-- Do not disturb: Used before specifying which sounds can bypass DND (ie: No sound except alarms and reminders). [CHAR LIMIT=40] -->
     <string name="zen_mode_behavior_no_sound_except">No sound except <xliff:g id="categories" example="alarms, media and system feedback">%1$s</xliff:g></string>
 
     <!-- Do not disturb: Specifies sounds that can bypass DND in user and/or API-invoked Alarms Only mode.  [CHAR LIMIT=100] -->
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index 287498f..822a60d 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -277,9 +277,9 @@
             root.removeAll();
         }
         if (ProgressiveDisclosureMixin.isV2Enabled()) {
-            addPreferencesFromResource(R.xml.security_settings);
-        } else {
             addPreferencesFromResource(R.xml.security_settings_advanced_button);
+        } else {
+            addPreferencesFromResource(R.xml.security_settings);
         }
         root = getPreferenceScreen();
 
diff --git a/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java b/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java
index 07f4c37..f66a5e2 100644
--- a/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java
+++ b/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java
@@ -23,6 +23,7 @@
 import android.app.DialogFragment;
 import android.app.Fragment;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.DialogInterface;
 import android.os.Binder;
 import android.os.Bundle;
@@ -54,7 +55,8 @@
 
     @Override
     protected List<? extends DefaultAppInfo> getCandidates() {
-        final AccessibilityManager accessibilityManager = getContext()
+        final Context context = getContext();
+        final AccessibilityManager accessibilityManager = context
                 .getSystemService(AccessibilityManager.class);
         final List<AccessibilityServiceInfo> installedServices =
                 accessibilityManager.getInstalledAccessibilityServiceList();
@@ -63,7 +65,7 @@
         List<DefaultAppInfo> candidates = new ArrayList<>(numInstalledServices);
         for (int i = 0; i < numInstalledServices; i++) {
             AccessibilityServiceInfo installedServiceInfo = installedServices.get(i);
-            candidates.add(new DefaultAppInfo(mPm,
+            candidates.add(new DefaultAppInfo(context, mPm,
                     UserHandle.myUserId(),
                     installedServiceInfo.getComponentName(),
                     (String) installedServiceInfo.loadSummary(mPm.getPackageManager()),
diff --git a/src/com/android/settings/applications/assist/DefaultAssistPicker.java b/src/com/android/settings/applications/assist/DefaultAssistPicker.java
index 51cb677..07bc809 100644
--- a/src/com/android/settings/applications/assist/DefaultAssistPicker.java
+++ b/src/com/android/settings/applications/assist/DefaultAssistPicker.java
@@ -79,7 +79,7 @@
                 continue;
             }
             packages.add(packageName);
-            candidates.add(new DefaultAppInfo(mPm, mUserId, info.component));
+            candidates.add(new DefaultAppInfo(getContext(), mPm, mUserId, info.component));
         }
         return candidates;
     }
@@ -88,7 +88,7 @@
     protected String getDefaultKey() {
         final ComponentName cn = getCurrentAssist();
         if (cn != null) {
-            return new DefaultAppInfo(mPm, mUserId, cn).getKey();
+            return new DefaultAppInfo(getContext(), mPm, mUserId, cn).getKey();
         }
         return null;
     }
diff --git a/src/com/android/settings/applications/assist/DefaultAssistPreferenceController.java b/src/com/android/settings/applications/assist/DefaultAssistPreferenceController.java
index 7520155..cba08c8 100644
--- a/src/com/android/settings/applications/assist/DefaultAssistPreferenceController.java
+++ b/src/com/android/settings/applications/assist/DefaultAssistPreferenceController.java
@@ -87,7 +87,7 @@
         if (cn == null) {
             return null;
         }
-        return new DefaultAppInfo(mPackageManager, mUserId, cn);
+        return new DefaultAppInfo(mContext, mPackageManager, mUserId, cn);
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/applications/assist/DefaultVoiceInputPicker.java b/src/com/android/settings/applications/assist/DefaultVoiceInputPicker.java
index c1fc528..5adda23 100644
--- a/src/com/android/settings/applications/assist/DefaultVoiceInputPicker.java
+++ b/src/com/android/settings/applications/assist/DefaultVoiceInputPicker.java
@@ -57,17 +57,18 @@
     @Override
     protected List<VoiceInputDefaultAppInfo> getCandidates() {
         final List<VoiceInputDefaultAppInfo> candidates = new ArrayList<>();
+        final Context context = getContext();
         boolean hasEnabled = true;
         for (VoiceInputHelper.InteractionInfo info : mHelper.mAvailableInteractionInfos) {
             final boolean enabled = TextUtils.equals(info.key, mAssistRestrict);
             hasEnabled |= enabled;
-            candidates.add(new VoiceInputDefaultAppInfo(mPm, mUserId, info, enabled));
+            candidates.add(new VoiceInputDefaultAppInfo(context, mPm, mUserId, info, enabled));
         }
 
         final boolean assistIsService = !hasEnabled;
         for (VoiceInputHelper.RecognizerInfo info : mHelper.mAvailableRecognizerInfos) {
             final boolean enabled = !assistIsService;
-            candidates.add(new VoiceInputDefaultAppInfo(mPm, mUserId, info, enabled));
+            candidates.add(new VoiceInputDefaultAppInfo(context, mPm, mUserId, info, enabled));
         }
         return candidates;
     }
@@ -132,9 +133,9 @@
 
         public VoiceInputHelper.BaseInfo mInfo;
 
-        public VoiceInputDefaultAppInfo(PackageManagerWrapper pm, int userId,
+        public VoiceInputDefaultAppInfo(Context context, PackageManagerWrapper pm, int userId,
                 VoiceInputHelper.BaseInfo info, boolean enabled) {
-            super(pm, userId, info.componentName, null /* summary */, enabled);
+            super(context, pm, userId, info.componentName, null /* summary */, enabled);
             mInfo = info;
         }
 
diff --git a/src/com/android/settings/applications/assist/DefaultVoiceInputPreferenceController.java b/src/com/android/settings/applications/assist/DefaultVoiceInputPreferenceController.java
index 3443a44..c305ccf 100644
--- a/src/com/android/settings/applications/assist/DefaultVoiceInputPreferenceController.java
+++ b/src/com/android/settings/applications/assist/DefaultVoiceInputPreferenceController.java
@@ -104,15 +104,15 @@
         }
         for (VoiceInputHelper.InteractionInfo info : mHelper.mAvailableInteractionInfos) {
             if (TextUtils.equals(defaultKey, info.key)) {
-                return new DefaultVoiceInputPicker.VoiceInputDefaultAppInfo(mPackageManager,
-                        mUserId, info, true /* enabled */);
+                return new DefaultVoiceInputPicker.VoiceInputDefaultAppInfo(mContext,
+                        mPackageManager, mUserId, info, true /* enabled */);
             }
         }
 
         for (VoiceInputHelper.RecognizerInfo info : mHelper.mAvailableRecognizerInfos) {
             if (TextUtils.equals(defaultKey, info.key)) {
-                return new DefaultVoiceInputPicker.VoiceInputDefaultAppInfo(mPackageManager,
-                        mUserId, info, true /* enabled */);
+                return new DefaultVoiceInputPicker.VoiceInputDefaultAppInfo(mContext,
+                        mPackageManager, mUserId, info, true /* enabled */);
             }
         }
         return null;
diff --git a/src/com/android/settings/applications/defaultapps/DefaultAppInfo.java b/src/com/android/settings/applications/defaultapps/DefaultAppInfo.java
index ec44af4..71b5ec4 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultAppInfo.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultAppInfo.java
@@ -18,6 +18,7 @@
 
 import android.app.AppGlobals;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageItemInfo;
@@ -25,6 +26,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.util.IconDrawableFactory;
 
 import com.android.settings.widget.RadioButtonPickerFragment;
 import com.android.settingslib.wrapper.PackageManagerWrapper;
@@ -39,18 +41,20 @@
     public final PackageItemInfo packageItemInfo;
     public final String summary;
     protected final PackageManagerWrapper mPm;
+    private final Context mContext;
 
-    public DefaultAppInfo(PackageManagerWrapper pm, int uid, ComponentName cn) {
-        this(pm, uid, cn, null /* summary */);
+    public DefaultAppInfo(Context context, PackageManagerWrapper pm, int uid, ComponentName cn) {
+        this(context, pm, uid, cn, null /* summary */, true /* enabled */);
     }
 
-    public DefaultAppInfo(PackageManagerWrapper pm, int uid, ComponentName cn, String summary) {
-        this(pm, uid, cn, summary, true /* enabled */);
+    public DefaultAppInfo(Context context, PackageManagerWrapper pm, PackageItemInfo info) {
+        this(context, pm, info, null /* summary */, true /* enabled */);
     }
 
-    public DefaultAppInfo(PackageManagerWrapper pm, int uid, ComponentName cn, String summary,
-            boolean enabled) {
+    public DefaultAppInfo(Context context, PackageManagerWrapper pm, int uid, ComponentName cn,
+            String summary, boolean enabled) {
         super(enabled);
+        mContext = context;
         mPm = pm;
         packageItemInfo = null;
         userId = uid;
@@ -58,9 +62,10 @@
         this.summary = summary;
     }
 
-    public DefaultAppInfo(PackageManagerWrapper pm, PackageItemInfo info, String summary,
-            boolean enabled) {
+    public DefaultAppInfo(Context context, PackageManagerWrapper pm, PackageItemInfo info,
+            String summary, boolean enabled) {
         super(enabled);
+        mContext = context;
         mPm = pm;
         userId = UserHandle.myUserId();
         packageItemInfo = info;
@@ -68,10 +73,6 @@
         this.summary = summary;
     }
 
-    public DefaultAppInfo(PackageManagerWrapper pm, PackageItemInfo info) {
-        this(pm, info, null /* summary */, true /* enabled */);
-    }
-
     @Override
     public CharSequence loadLabel() {
         if (componentName != null) {
@@ -97,22 +98,29 @@
 
     @Override
     public Drawable loadIcon() {
+        final IconDrawableFactory factory = IconDrawableFactory.newInstance(mContext);
         if (componentName != null) {
             try {
                 final ComponentInfo componentInfo = getComponentInfo();
+                final ApplicationInfo appInfo = mPm.getApplicationInfoAsUser(
+                        componentName.getPackageName(), 0, userId);
                 if (componentInfo != null) {
-                    return componentInfo.loadIcon(mPm.getPackageManager());
+                    return factory.getBadgedIcon(componentInfo, appInfo, userId);
                 } else {
-                    final ApplicationInfo appInfo = mPm.getApplicationInfoAsUser(
-                            componentName.getPackageName(), 0, userId);
-                    return appInfo.loadIcon(mPm.getPackageManager());
+                    return factory.getBadgedIcon(appInfo);
                 }
             } catch (PackageManager.NameNotFoundException e) {
                 return null;
             }
         }
         if (packageItemInfo != null) {
-            return packageItemInfo.loadIcon(mPm.getPackageManager());
+            try {
+                final ApplicationInfo appInfo = mPm.getApplicationInfoAsUser(
+                        packageItemInfo.packageName, 0, userId);
+                return factory.getBadgedIcon(packageItemInfo, appInfo, userId);
+            } catch (PackageManager.NameNotFoundException e) {
+                return null;
+            }
         } else {
             return null;
         }
diff --git a/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java b/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java
index 34d1338..cc85f77 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java
@@ -187,10 +187,11 @@
         final List<DefaultAppInfo> candidates = new ArrayList<>();
         final List<ResolveInfo> resolveInfos = mPm.getPackageManager()
                 .queryIntentServices(AUTOFILL_PROBE, PackageManager.GET_META_DATA);
+        final Context context = getContext();
         for (ResolveInfo info : resolveInfos) {
             final String permission = info.serviceInfo.permission;
             if (Manifest.permission.BIND_AUTOFILL_SERVICE.equals(permission)) {
-                candidates.add(new DefaultAppInfo(mPm, mUserId, new ComponentName(
+                candidates.add(new DefaultAppInfo(context, mPm, mUserId, new ComponentName(
                         info.serviceInfo.packageName, info.serviceInfo.name)));
             }
         }
diff --git a/src/com/android/settings/applications/defaultapps/DefaultAutofillPreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultAutofillPreferenceController.java
index 30aaf64..508cc63 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultAutofillPreferenceController.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultAutofillPreferenceController.java
@@ -62,7 +62,7 @@
         final String flattenComponent = Settings.Secure.getString(mContext.getContentResolver(),
                 DefaultAutofillPicker.SETTING);
         if (!TextUtils.isEmpty(flattenComponent)) {
-            DefaultAppInfo appInfo = new DefaultAppInfo(mPackageManager,
+            DefaultAppInfo appInfo = new DefaultAppInfo(mContext, mPackageManager,
                     mUserId, ComponentName.unflattenFromString(flattenComponent));
             return appInfo;
         }
diff --git a/src/com/android/settings/applications/defaultapps/DefaultBrowserPicker.java b/src/com/android/settings/applications/defaultapps/DefaultBrowserPicker.java
index e965052..fb9c3bf 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultBrowserPicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultBrowserPicker.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.applications.defaultapps;
 
+import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 
@@ -47,7 +48,7 @@
     @Override
     protected List<DefaultAppInfo> getCandidates() {
         final List<DefaultAppInfo> candidates = new ArrayList<>();
-
+        final Context context = getContext();
         // Resolve that intent and check that the handleAllWebDataURI boolean is set
         final List<ResolveInfo> list = mPm.queryIntentActivitiesAsUser(
                 DefaultBrowserPreferenceController.BROWSE_PROBE, PackageManager.MATCH_ALL, mUserId);
@@ -59,7 +60,7 @@
                 continue;
             }
             try {
-                candidates.add(new DefaultAppInfo(mPm,
+                candidates.add(new DefaultAppInfo(context, mPm,
                         mPm.getApplicationInfoAsUser(info.activityInfo.packageName, 0, mUserId)));
             } catch (PackageManager.NameNotFoundException e) {
                 // Skip unknown packages.
diff --git a/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceController.java
index a0bf0ca..916f9422 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceController.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultBrowserPreferenceController.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
@@ -25,6 +26,7 @@
 import android.net.Uri;
 import android.support.v7.preference.Preference;
 import android.text.TextUtils;
+import android.util.IconDrawableFactory;
 import android.util.Log;
 
 import java.util.List;
@@ -67,7 +69,7 @@
         try {
             final String packageName = mPackageManager.getDefaultBrowserPackageNameAsUser(mUserId);
             Log.d(TAG, "Get default browser package: " + packageName);
-            return new DefaultAppInfo(mPackageManager,
+            return new DefaultAppInfo(mContext, mPackageManager,
                     mPackageManager.getPackageManager().getApplicationInfo(packageName, 0));
         } catch (PackageManager.NameNotFoundException e) {
             return null;
@@ -124,8 +126,19 @@
             final ResolveInfo info = list.get(0);
             final ComponentInfo cn = info.getComponentInfo();
             final String packageName = cn == null ? null : cn.packageName;
+            if (TextUtils.isEmpty(packageName)) {
+                return null;
+            }
+            final ApplicationInfo appInfo;
+            try {
+                appInfo = mPackageManager.getPackageManager().getApplicationInfo(packageName, 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.w(TAG, "Error getting app info for " + packageName);
+                return null;
+            }
             Log.d(TAG, "Getting icon for the only browser app: " + packageName);
-            return info.loadIcon(mPackageManager.getPackageManager());
+            final IconDrawableFactory iconFactory = IconDrawableFactory.newInstance(mContext);
+            return iconFactory.getBadgedIcon(cn, appInfo, mUserId);
         }
         return null;
     }
diff --git a/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java b/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java
index 1d707df..8f8c64e 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultEmergencyPicker.java
@@ -17,6 +17,7 @@
 package com.android.settings.applications.defaultapps;
 
 import android.content.ContentResolver;
+import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -44,12 +45,13 @@
         final List<ResolveInfo> infos = mPm.getPackageManager().queryIntentActivities(
                 DefaultEmergencyPreferenceController.QUERY_INTENT, 0);
         PackageInfo bestMatch = null;
+        final Context context = getContext();
         for (ResolveInfo info : infos) {
             try {
                 final PackageInfo packageInfo =
                         mPm.getPackageManager().getPackageInfo(info.activityInfo.packageName, 0);
                 final ApplicationInfo appInfo = packageInfo.applicationInfo;
-                candidates.add(new DefaultAppInfo(mPm, appInfo));
+                candidates.add(new DefaultAppInfo(context, mPm, appInfo));
                 // Get earliest installed system app.
                 if (isSystemApp(appInfo) && (bestMatch == null ||
                         bestMatch.firstInstallTime > packageInfo.firstInstallTime)) {
diff --git a/src/com/android/settings/applications/defaultapps/DefaultHomePicker.java b/src/com/android/settings/applications/defaultapps/DefaultHomePicker.java
index dca7ad1..75f5292 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultHomePicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultHomePicker.java
@@ -53,6 +53,7 @@
         final boolean mustSupportManagedProfile = hasManagedProfile();
         final List<DefaultAppInfo> candidates = new ArrayList<>();
         final List<ResolveInfo> homeActivities = new ArrayList<>();
+        final Context context = getContext();
         mPm.getHomeActivities(homeActivities);
 
         for (ResolveInfo resolveInfo : homeActivities) {
@@ -71,7 +72,7 @@
                 summary = null;
             }
             final DefaultAppInfo candidate =
-                    new DefaultAppInfo(mPm, mUserId, activityName, summary, enabled);
+                    new DefaultAppInfo(context, mPm, mUserId, activityName, summary, enabled);
             candidates.add(candidate);
         }
         return candidates;
diff --git a/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java
index 1b229e8..bd8b5d1 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultHomePreferenceController.java
@@ -61,11 +61,12 @@
         final ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
         final ComponentName currentDefaultHome = mPackageManager.getHomeActivities(homeActivities);
         if (currentDefaultHome != null) {
-            return new DefaultAppInfo(mPackageManager, mUserId, currentDefaultHome);
+            return new DefaultAppInfo(mContext, mPackageManager, mUserId, currentDefaultHome);
         }
         final ActivityInfo onlyAppInfo = getOnlyAppInfo();
         if (onlyAppInfo != null) {
-            return new DefaultAppInfo(mPackageManager, mUserId, onlyAppInfo.getComponentName());
+            return new DefaultAppInfo(mContext, mPackageManager, mUserId,
+                    onlyAppInfo.getComponentName());
         }
         return null;
     }
diff --git a/src/com/android/settings/applications/defaultapps/DefaultPhonePicker.java b/src/com/android/settings/applications/defaultapps/DefaultPhonePicker.java
index fc643c8..9f6cc4d 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultPhonePicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultPhonePicker.java
@@ -48,9 +48,10 @@
         final List<DefaultAppInfo> candidates = new ArrayList<>();
         final List<String> dialerPackages =
                 DefaultDialerManager.getInstalledDialerApplications(getContext(), mUserId);
+        final Context context = getContext();
         for (String packageName : dialerPackages) {
             try {
-                candidates.add(new DefaultAppInfo(mPm,
+                candidates.add(new DefaultAppInfo(context, mPm,
                         mPm.getApplicationInfoAsUser(packageName, 0, mUserId)));
             } catch (PackageManager.NameNotFoundException e) {
                 // Skip unknown packages.
diff --git a/src/com/android/settings/applications/defaultapps/DefaultPhonePreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultPhonePreferenceController.java
index 712badb..92c9386 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultPhonePreferenceController.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultPhonePreferenceController.java
@@ -57,7 +57,7 @@
     @Override
     protected DefaultAppInfo getDefaultAppInfo() {
         try {
-            return new DefaultAppInfo(mPackageManager,
+            return new DefaultAppInfo(mContext, mPackageManager,
                     mPackageManager.getPackageManager().getApplicationInfo(
                             DefaultDialerManager.getDefaultDialerApplication(mContext, mUserId),
                             0));
diff --git a/src/com/android/settings/applications/defaultapps/DefaultSmsPicker.java b/src/com/android/settings/applications/defaultapps/DefaultSmsPicker.java
index 966cd43..57159b3 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultSmsPicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultSmsPicker.java
@@ -41,13 +41,14 @@
 
     @Override
     protected List<DefaultAppInfo> getCandidates() {
+        final Context context = getContext();
         final Collection<SmsApplication.SmsApplicationData> smsApplications =
-                SmsApplication.getApplicationCollection(getContext());
+                SmsApplication.getApplicationCollection(context);
         final List<DefaultAppInfo> candidates = new ArrayList<>(smsApplications.size());
 
         for (SmsApplication.SmsApplicationData smsApplicationData : smsApplications) {
             try {
-                candidates.add(new DefaultAppInfo(mPm,
+                candidates.add(new DefaultAppInfo(context, mPm,
                         mPm.getApplicationInfoAsUser(smsApplicationData.mPackageName, 0, mUserId)));
             } catch (PackageManager.NameNotFoundException e) {
                 // Skip unknown packages.
diff --git a/src/com/android/settings/applications/defaultapps/DefaultSmsPreferenceController.java b/src/com/android/settings/applications/defaultapps/DefaultSmsPreferenceController.java
index 63075b9..c3b7ac4 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultSmsPreferenceController.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultSmsPreferenceController.java
@@ -47,7 +47,7 @@
     protected DefaultAppInfo getDefaultAppInfo() {
         final ComponentName app = SmsApplication.getDefaultSmsApplication(mContext, true);
         if (app != null) {
-            return new DefaultAppInfo(mPackageManager, mUserId, app);
+            return new DefaultAppInfo(mContext, mPackageManager, mUserId, app);
         }
         return null;
     }
diff --git a/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
new file mode 100644
index 0000000..9ac2167
--- /dev/null
+++ b/src/com/android/settings/applications/manageapplications/ApplicationViewHolder.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.settings.applications.manageapplications;
+
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.StringRes;
+import android.support.annotation.VisibleForTesting;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+public class ApplicationViewHolder extends RecyclerView.ViewHolder {
+
+    private final TextView mAppName;
+    private final ImageView mAppIcon;
+
+    @VisibleForTesting
+    final TextView mSummary;
+    @VisibleForTesting
+    final TextView mDisabled;
+
+    ApplicationViewHolder(View itemView) {
+        super(itemView);
+        mAppName = itemView.findViewById(android.R.id.title);
+        mAppIcon = itemView.findViewById(android.R.id.icon);
+        mSummary = itemView.findViewById(R.id.widget_text1);
+        mDisabled = itemView.findViewById(R.id.widget_text2);
+    }
+
+    static View newView(LayoutInflater inflater, ViewGroup parent) {
+        final View root = LayoutInflater.from(parent.getContext())
+                .inflate(R.layout.preference_app, parent, false);
+        inflater.inflate(R.layout.widget_text_views,
+                root.findViewById(android.R.id.widget_frame));
+        return root;
+    }
+
+    void setSummary(CharSequence summary) {
+        mSummary.setText(summary);
+    }
+
+    void setSummary(@StringRes int summary) {
+        mSummary.setText(summary);
+    }
+
+    void setEnabled(boolean isEnabled) {
+        itemView.setEnabled(isEnabled);
+    }
+
+    void setTitle(CharSequence title) {
+        if (title == null) {
+            return;
+        }
+        mAppName.setText(title);
+    }
+
+    void setIcon(Drawable icon) {
+        if (icon == null) {
+            return;
+        }
+        mAppIcon.setImageDrawable(icon);
+    }
+
+    void updateDisableView(ApplicationInfo info) {
+        if ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
+            mDisabled.setVisibility(View.VISIBLE);
+            mDisabled.setText(R.string.not_installed);
+        } else if (!info.enabled || info.enabledSetting
+                == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+            mDisabled.setVisibility(View.VISIBLE);
+            mDisabled.setText(R.string.disabled);
+        } else {
+            mDisabled.setVisibility(View.GONE);
+        }
+    }
+
+    void updateSizeText(AppEntry entry, CharSequence invalidSizeStr, int whichSize) {
+        if (ManageApplications.DEBUG) {
+            Log.d(ManageApplications.TAG, "updateSizeText of "
+                    + entry.label + " " + entry + ": " + entry.sizeStr);
+        }
+        if (entry.sizeStr != null) {
+            switch (whichSize) {
+                case ManageApplications.SIZE_INTERNAL:
+                    setSummary(entry.internalSizeStr);
+                    break;
+                case ManageApplications.SIZE_EXTERNAL:
+                    setSummary(entry.externalSizeStr);
+                    break;
+                default:
+                    setSummary(entry.sizeStr);
+                    break;
+            }
+        } else if (entry.size == ApplicationsState.SIZE_INVALID) {
+            setSummary(invalidSizeStr);
+        }
+    }
+}
diff --git a/src/com/android/settings/applications/manageapplications/FileViewHolderController.java b/src/com/android/settings/applications/manageapplications/FileViewHolderController.java
index 03e2e55..4e6bf26 100644
--- a/src/com/android/settings/applications/manageapplications/FileViewHolderController.java
+++ b/src/com/android/settings/applications/manageapplications/FileViewHolderController.java
@@ -35,12 +35,14 @@
 
     /**
      * Initializes the view within an AppViewHolder.
+     *
      * @param holder The holder to use to initialize.
      */
-    void setupView(AppViewHolder holder);
+    void setupView(ApplicationViewHolder holder);
 
     /**
      * Handles the behavior when the view is clicked.
+     *
      * @param fragment Fragment where the click originated.
      */
     void onClick(Fragment fragment);
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 932b2dd..3caa8ab 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -40,16 +40,14 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageItemInfo;
-import android.content.pm.PackageManager;
-import android.icu.text.AlphabeticIndex;
 import android.os.Bundle;
 import android.os.Environment;
-import android.os.Handler;
-import android.os.LocaleList;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.preference.PreferenceFrameLayout;
 import android.support.annotation.VisibleForTesting;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
@@ -59,19 +57,11 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.AbsListView;
 import android.widget.AdapterView;
-import android.widget.AdapterView.OnItemClickListener;
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.ArrayAdapter;
-import android.widget.BaseAdapter;
-import android.widget.Filter;
-import android.widget.Filterable;
 import android.widget.FrameLayout;
-import android.widget.ListView;
-import android.widget.SectionIndexer;
 import android.widget.Spinner;
-import android.widget.TextView;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
@@ -86,7 +76,6 @@
 import com.android.settings.Settings.UsageAccessSettingsActivity;
 import com.android.settings.Settings.WriteSettingsActivity;
 import com.android.settings.SettingsActivity;
-import com.android.settings.Utils;
 import com.android.settings.applications.AppInfoBase;
 import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
 import com.android.settings.applications.AppStateBaseBridge;
@@ -122,13 +111,13 @@
 import com.android.settingslib.applications.ApplicationsState.CompoundFilter;
 import com.android.settingslib.applications.ApplicationsState.VolumeFilter;
 import com.android.settingslib.applications.StorageStatsSource;
+import com.android.settingslib.utils.ThreadUtils;
 import com.android.settingslib.wrapper.PackageManagerWrapper;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Locale;
 import java.util.Set;
 
 /**
@@ -138,7 +127,7 @@
  * intent.
  */
 public class ManageApplications extends InstrumentedPreferenceFragment
-        implements OnItemClickListener, OnItemSelectedListener {
+        implements View.OnClickListener, OnItemSelectedListener {
 
     static final String TAG = "ManageApplications";
     static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -185,23 +174,17 @@
     private ApplicationsState mApplicationsState;
 
     public int mListType;
-    public AppFilterItem mFilter;
-
-    public ApplicationsAdapter mApplications;
+    private AppFilterItem mFilter;
+    private ApplicationsAdapter mApplications;
 
     private View mLoadingContainer;
 
     private View mListContainer;
-
-    // ListView used to display list
-    private ListView mListView;
+    private RecyclerView mRecyclerView;
 
     // Size resource used for packages whose size computation failed for some reason
     CharSequence mInvalidSizeStr;
 
-    // layout inflater object used to inflate views
-    private LayoutInflater mInflater;
-
     private String mCurrentPkgName;
     private int mCurrentUid;
 
@@ -234,6 +217,7 @@
     private int mStorageType;
     private boolean mIsWorkOnly;
     private int mWorkUserId;
+    private View mEmptyView;
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
@@ -304,25 +288,14 @@
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
-        // initialize the inflater
-        mInflater = inflater;
-
         mRootView = inflater.inflate(R.layout.manage_applications_apps, null);
         mLoadingContainer = mRootView.findViewById(R.id.loading_container);
         mListContainer = mRootView.findViewById(R.id.list_container);
         if (mListContainer != null) {
             // Create adapter and list view here
-            View emptyView = mListContainer.findViewById(com.android.internal.R.id.empty);
-            ListView lv = mListContainer.findViewById(android.R.id.list);
-            if (emptyView != null) {
-                lv.setEmptyView(emptyView);
-            }
-            lv.setOnItemClickListener(this);
-            lv.setSaveEnabled(true);
-            lv.setItemsCanFocus(true);
-            lv.setTextFilterEnabled(true);
-            mListView = lv;
-            mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter);
+            mEmptyView = mListContainer.findViewById(android.R.id.empty);
+            mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter,
+                    savedInstanceState);
             if (savedInstanceState != null) {
                 mApplications.mHasReceivedLoadEntries =
                         savedInstanceState.getBoolean(EXTRA_HAS_ENTRIES, false);
@@ -347,11 +320,10 @@
                                 mVolumeUuid,
                                 UserHandle.of(userId)));
             }
-            mListView.setAdapter(mApplications);
-            mListView.setRecyclerListener(mApplications);
-            mListView.setFastScrollEnabled(isFastScrollEnabled());
-
-            Utils.prepareCustomPreferencesList(container, mRootView, mListView, false);
+            mRecyclerView = mListContainer.findViewById(R.id.apps_list);
+            mRecyclerView.setLayoutManager(new LinearLayoutManager(
+                    getContext(), RecyclerView.VERTICAL, false /* reverseLayout */));
+            mRecyclerView.setAdapter(mApplications);
         }
 
         // We have to do this now because PreferenceFrameLayout looks at it
@@ -492,6 +464,9 @@
         outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
         outState.putBoolean(EXTRA_HAS_ENTRIES, mApplications.mHasReceivedLoadEntries);
         outState.putBoolean(EXTRA_HAS_BRIDGE, mApplications.mHasReceivedBridgeCallback);
+        if (mApplications != null) {
+            mApplications.onSaveInstanceState(outState);
+        }
     }
 
     @Override
@@ -633,7 +608,6 @@
             case R.id.sort_order_alpha:
             case R.id.sort_order_size:
                 mSortOrder = menuId;
-                mListView.setFastScrollEnabled(isFastScrollEnabled());
                 if (mApplications != null) {
                     mApplications.rebuild(mSortOrder);
                 }
@@ -667,11 +641,16 @@
     }
 
     @Override
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+    public void onClick(View view) {
         if (mApplications == null) {
             return;
         }
+        final int position = mRecyclerView.getChildAdapterPosition(view);
 
+        if (position == RecyclerView.NO_POSITION) {
+            Log.w(TAG, "Cannot find position for child, skipping onClick handling");
+            return;
+        }
         if (mApplications.getApplicationCount() > position) {
             ApplicationsState.AppEntry entry = mApplications.getAppEntry(position);
             mCurrentPkgName = entry.info.packageName;
@@ -757,7 +736,9 @@
                     mFilterOptions.size() > 1 ? View.VISIBLE : View.GONE);
             notifyDataSetChanged();
             if (mFilterOptions.size() == 1) {
-                if (DEBUG) Log.d(TAG, "Auto selecting filter " + filter);
+                if (DEBUG) {
+                    Log.d(TAG, "Auto selecting filter " + filter);
+                }
                 mManageApplications.mFilterSpinner.setSelection(0);
                 mManageApplications.onItemSelected(null, null, 0, 0);
             }
@@ -777,7 +758,9 @@
             notifyDataSetChanged();
             if (mManageApplications.mFilter == filter) {
                 if (mFilterOptions.size() > 0) {
-                    if (DEBUG) Log.d(TAG, "Auto selecting filter " + mFilterOptions.get(0));
+                    if (DEBUG) {
+                        Log.d(TAG, "Auto selecting filter " + mFilterOptions.get(0));
+                    }
                     mManageApplications.mFilterSpinner.setSelection(0);
                     mManageApplications.onItemSelected(null, null, 0, 0);
                 }
@@ -795,38 +778,25 @@
         }
     }
 
-    /*
-     * Custom adapter implementation for the ListView
-     * This adapter maintains a map for each displayed application and its properties
-     * An index value on each AppInfo object indicates the correct position or index
-     * in the list. If the list gets updated dynamically when the user is viewing the list of
-     * applications, we need to return the correct index of position. This is done by mapping
-     * the getId methods via the package name into the internal maps and indices.
-     * The order of applications in the list is mirrored in mAppLocalList
-     */
-    static class ApplicationsAdapter extends BaseAdapter implements Filterable,
-            ApplicationsState.Callbacks, AppStateBaseBridge.Callback,
-            AbsListView.RecyclerListener, SectionIndexer {
+    static class ApplicationsAdapter extends RecyclerView.Adapter<ApplicationViewHolder>
+            implements ApplicationsState.Callbacks, AppStateBaseBridge.Callback {
 
-        private static final SectionInfo[] EMPTY_SECTIONS = new SectionInfo[0];
+        private static final String STATE_LAST_SCROLL_INDEX = "state_last_scroll_index";
+        private static final int VIEW_TYPE_APP = 0;
+        private static final int VIEW_TYPE_EXTRA_VIEW = 1;
 
         private final ApplicationsState mState;
         private final ApplicationsState.Session mSession;
         private final ManageApplications mManageApplications;
         private final Context mContext;
-        private final ArrayList<View> mActive = new ArrayList<>();
         private final AppStateBaseBridge mExtraInfoBridge;
-        private final Handler mBgHandler;
-        private final Handler mFgHandler;
         private final LoadingViewController mLoadingViewController;
 
         private AppFilterItem mAppFilter;
-        private ArrayList<ApplicationsState.AppEntry> mBaseEntries;
         private ArrayList<ApplicationsState.AppEntry> mEntries;
         private boolean mResumed;
         private int mLastSortMode = -1;
         private int mWhichSize = SIZE_TOTAL;
-        CharSequence mCurFilterPrefix;
         private AppFilter mCompositeFilter;
         private boolean mHasReceivedLoadEntries;
         private boolean mHasReceivedBridgeCallback;
@@ -836,39 +806,11 @@
         // fragment is paused. We need this special handling because app entries are added gradually
         // when we rebuild the list after the user made some changes, like uninstalling an app.
         private int mLastIndex = -1;
-        private int mLastTop;
-
-        private AlphabeticIndex.ImmutableIndex<Locale> mIndex;
-        private SectionInfo[] mSections = EMPTY_SECTIONS;
-        private int[] mPositionToSectionIndex;
-
-        private Filter mFilter = new Filter() {
-            @Override
-            protected FilterResults performFiltering(CharSequence constraint) {
-                ArrayList<ApplicationsState.AppEntry> entries
-                        = applyPrefixFilter(constraint, mBaseEntries);
-                FilterResults fr = new FilterResults();
-                fr.values = entries;
-                fr.count = entries.size();
-                return fr;
-            }
-
-            @Override
-            @SuppressWarnings("unchecked")
-            protected void publishResults(CharSequence constraint, FilterResults results) {
-                mCurFilterPrefix = constraint;
-                mEntries = (ArrayList<ApplicationsState.AppEntry>) results.values;
-                rebuildSections();
-                notifyDataSetChanged();
-            }
-        };
-
 
         public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications,
-                AppFilterItem appFilter) {
+                AppFilterItem appFilter, Bundle savedInstanceState) {
+            setHasStableIds(true);
             mState = state;
-            mFgHandler = new Handler();
-            mBgHandler = new Handler(mState.getBackgroundLooper());
             mSession = state.newSession(this);
             mManageApplications = manageApplications;
             mLoadingViewController = new LoadingViewController(
@@ -893,6 +835,9 @@
             } else {
                 mExtraInfoBridge = null;
             }
+            if (savedInstanceState != null) {
+                mLastIndex = savedInstanceState.getInt(STATE_LAST_SCROLL_INDEX);
+            }
         }
 
         public void setCompositeFilter(AppFilter compositeFilter) {
@@ -907,9 +852,11 @@
 
         public void setExtraViewController(FileViewHolderController extraViewController) {
             mExtraViewController = extraViewController;
-            mBgHandler.post(() -> {
+            // Start to query extra view's stats on background, and once done post result to main
+            // thread.
+            ThreadUtils.postOnBackgroundThread(() -> {
                 mExtraViewController.queryStats();
-                mFgHandler.post(() -> {
+                ThreadUtils.postOnMainThread(() -> {
                     onExtraViewCompleted();
                 });
             });
@@ -938,11 +885,13 @@
                     mExtraInfoBridge.pause();
                 }
             }
+        }
+
+        public void onSaveInstanceState(Bundle outState) {
             // Record the current scroll position before pausing.
-            mLastIndex = mManageApplications.mListView.getFirstVisiblePosition();
-            View v = mManageApplications.mListView.getChildAt(0);
-            mLastTop =
-                    (v == null) ? 0 : (v.getTop() - mManageApplications.mListView.getPaddingTop());
+            final LinearLayoutManager layoutManager =
+                    (LinearLayoutManager) mManageApplications.mRecyclerView.getLayoutManager();
+            outState.putInt(STATE_LAST_SCROLL_INDEX, layoutManager.findFirstVisibleItemPosition());
         }
 
         public void release() {
@@ -960,6 +909,21 @@
             rebuild();
         }
 
+        @Override
+        public ApplicationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            final View view = ApplicationViewHolder.newView(
+                    LayoutInflater.from(parent.getContext()), parent);
+            return new ApplicationViewHolder(view);
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            boolean isLastItem = (getItemCount() - 1) == position;
+            return hasExtraView() && isLastItem
+                    ? VIEW_TYPE_EXTRA_VIEW
+                    : VIEW_TYPE_APP;
+        }
+
         public void rebuild() {
             if (!mHasReceivedLoadEntries
                     || (mExtraInfoBridge != null && !mHasReceivedBridgeCallback)) {
@@ -1008,11 +972,11 @@
 
             filterObj = new CompoundFilter(filterObj, ApplicationsState.FILTER_NOT_HIDE);
             AppFilter finalFilterObj = filterObj;
-            mBgHandler.post(() -> {
+            ThreadUtils.postOnBackgroundThread(() -> {
                 final ArrayList<AppEntry> entries = mSession.rebuild(finalFilterObj,
                         comparatorObj, false);
                 if (entries != null) {
-                    mFgHandler.post(() -> onRebuildComplete(entries));
+                    ThreadUtils.postOnMainThread(() -> onRebuildComplete(entries));
                 }
             });
         }
@@ -1031,8 +995,7 @@
                 ArrayList<ApplicationsState.AppEntry> entries) {
             int size = entries.size();
             // returnList will not have more entries than entries
-            ArrayList<ApplicationsState.AppEntry> returnEntries = new
-                    ArrayList<ApplicationsState.AppEntry>(size);
+            ArrayList<ApplicationsState.AppEntry> returnEntries = new ArrayList<>(size);
 
             // assume appinfo of same package but different users are grouped together
             PackageItemInfo lastInfo = null;
@@ -1055,21 +1018,19 @@
                     filterType == FILTER_APPS_POWER_WHITELIST_ALL) {
                 entries = removeDuplicateIgnoringUser(entries);
             }
-            mBaseEntries = entries;
-            if (mBaseEntries != null) {
-                mEntries = applyPrefixFilter(mCurFilterPrefix, mBaseEntries);
-                rebuildSections();
-            } else {
-                mEntries = null;
-                mSections = EMPTY_SECTIONS;
-                mPositionToSectionIndex = null;
-            }
-
+            mEntries = entries;
             notifyDataSetChanged();
+            if (getItemCount() == 0) {
+                mManageApplications.mRecyclerView.setVisibility(View.GONE);
+                mManageApplications.mEmptyView.setVisibility(View.VISIBLE);
+            } else {
+                mManageApplications.mEmptyView.setVisibility(View.GONE);
+                mManageApplications.mRecyclerView.setVisibility(View.VISIBLE);
+            }
             // Restore the last scroll position if the number of entries added so far is bigger than
             // it.
-            if (mLastIndex != -1 && getCount() > mLastIndex) {
-                mManageApplications.mListView.setSelectionFromTop(mLastIndex, mLastTop);
+            if (mLastIndex != -1 && getItemCount() > mLastIndex) {
+                mManageApplications.mRecyclerView.getLayoutManager().scrollToPosition(mLastIndex);
                 mLastIndex = -1;
             }
 
@@ -1086,45 +1047,6 @@
             mManageApplications.setHasInstant(mState.haveInstantApps());
         }
 
-        private void rebuildSections() {
-            if (mEntries != null && mManageApplications.mListView.isFastScrollEnabled()) {
-                // Rebuild sections
-                if (mIndex == null) {
-                    LocaleList locales = mContext.getResources().getConfiguration().getLocales();
-                    if (locales.size() == 0) {
-                        locales = new LocaleList(Locale.ENGLISH);
-                    }
-                    AlphabeticIndex<Locale> index = new AlphabeticIndex(locales.get(0));
-                    int localeCount = locales.size();
-                    for (int i = 1; i < localeCount; i++) {
-                        index.addLabels(locales.get(i));
-                    }
-                    // Ensure we always have some base English locale buckets
-                    index.addLabels(Locale.ENGLISH);
-                    mIndex = index.buildImmutableIndex();
-                }
-
-                ArrayList<SectionInfo> sections = new ArrayList<>();
-                int lastSecId = -1;
-                int totalEntries = mEntries.size();
-                mPositionToSectionIndex = new int[totalEntries];
-
-                for (int pos = 0; pos < totalEntries; pos++) {
-                    String label = mEntries.get(pos).label;
-                    int secId = mIndex.getBucketIndex(TextUtils.isEmpty(label) ? "" : label);
-                    if (secId != lastSecId) {
-                        lastSecId = secId;
-                        sections.add(new SectionInfo(mIndex.getBucket(secId).getLabel(), pos));
-                    }
-                    mPositionToSectionIndex[pos] = sections.size() - 1;
-                }
-                mSections = sections.toArray(EMPTY_SECTIONS);
-            } else {
-                mSections = EMPTY_SECTIONS;
-                mPositionToSectionIndex = null;
-            }
-        }
-
         @VisibleForTesting
         void updateLoading() {
             final boolean appLoaded = mHasReceivedLoadEntries && mSession.getAllApps().size() != 0;
@@ -1135,26 +1057,6 @@
             }
         }
 
-        ArrayList<ApplicationsState.AppEntry> applyPrefixFilter(CharSequence prefix,
-                ArrayList<ApplicationsState.AppEntry> origEntries) {
-            if (prefix == null || prefix.length() == 0) {
-                return origEntries;
-            } else {
-                String prefixStr = ApplicationsState.normalize(prefix.toString());
-                final String spacePrefixStr = " " + prefixStr;
-                ArrayList<ApplicationsState.AppEntry> newEntries
-                        = new ArrayList<ApplicationsState.AppEntry>();
-                for (int i = 0; i < origEntries.size(); i++) {
-                    ApplicationsState.AppEntry entry = origEntries.get(i);
-                    String nlabel = entry.getNormalizedLabel();
-                    if (nlabel.startsWith(prefixStr) || nlabel.indexOf(spacePrefixStr) != -1) {
-                        newEntries.add(entry);
-                    }
-                }
-                return newEntries;
-            }
-        }
-
         @Override
         public void onExtraInfoUpdated() {
             mHasReceivedBridgeCallback = true;
@@ -1186,29 +1088,27 @@
 
         @Override
         public void onPackageSizeChanged(String packageName) {
-            for (int i = 0; i < mActive.size(); i++) {
-                AppViewHolder holder = (AppViewHolder) mActive.get(i).getTag();
-                if (holder == null || holder.entry == null) {
+            if (mEntries == null) {
+                return;
+            }
+            final int size = mEntries.size();
+            for (int i = 0; i < size; i++) {
+                final AppEntry entry = mEntries.get(i);
+                final ApplicationInfo info = entry.info;
+                if (info == null && !TextUtils.equals(packageName, info.packageName)) {
                     continue;
                 }
-                ApplicationInfo info = holder.entry.info;
-                if (info == null) {
-                    continue;
-                }
-                if (holder.entry.info.packageName.equals(packageName)) {
-                    synchronized (holder.entry) {
-                        updateSummary(holder);
-                    }
-                    if (holder.entry.info.packageName.equals(mManageApplications.mCurrentPkgName)
-                            && mLastSortMode == R.id.sort_order_size) {
-                        // We got the size information for the last app the
-                        // user viewed, and are sorting by size...  they may
-                        // have cleared data, so we immediately want to resort
-                        // the list with the new size to reflect it to the user.
-                        rebuild();
-                    }
+                if (TextUtils.equals(mManageApplications.mCurrentPkgName, info.packageName)) {
+                    // We got the size information for the last app the
+                    // user viewed, and are sorting by size...  they may
+                    // have cleared data, so we immediately want to resort
+                    // the list with the new size to reflect it to the user.
+                    rebuild();
                     return;
+                } else {
+                    notifyItemChanged(i);
                 }
+
             }
         }
 
@@ -1227,46 +1127,30 @@
         }
 
         public void onExtraViewCompleted() {
-            int size = mActive.size();
-            // If we have no elements, don't do anything.
-            if (size < 1) {
+            if (!hasExtraView()) {
                 return;
             }
-            AppViewHolder holder = (AppViewHolder) mActive.get(size - 1).getTag();
-
-            // HACK: The extra view has no AppEntry -- and should be the only element without one.
-            // Thus, if the last active element has no AppEntry, it is the extra view.
-            if (holder == null || holder.entry != null) {
-                return;
-            }
-
-            mExtraViewController.setupView(holder);
+            // Update last item - this is assumed to be the extra view.
+            notifyItemChanged(getItemCount() - 1);
         }
 
-        public int getCount() {
+        @Override
+        public int getItemCount() {
             if (mEntries == null) {
                 return 0;
             }
-            int extraViewAddition =
-                    (mExtraViewController != null && mExtraViewController.shouldShow()) ? 1 : 0;
-            return mEntries.size() + extraViewAddition;
+            return mEntries.size() + (hasExtraView() ? 1 : 0);
         }
 
         public int getApplicationCount() {
             return mEntries != null ? mEntries.size() : 0;
         }
 
-        public Object getItem(int position) {
-            if (position == mEntries.size()) {
-                return mExtraViewController;
-            }
+        public AppEntry getAppEntry(int position) {
             return mEntries.get(position);
         }
 
-        public ApplicationsState.AppEntry getAppEntry(int position) {
-            return mEntries.get(position);
-        }
-
+        @Override
         public long getItemId(int position) {
             if (position == mEntries.size()) {
                 return -1;
@@ -1274,142 +1158,76 @@
             return mEntries.get(position).id;
         }
 
-        @Override
-        public boolean areAllItemsEnabled() {
-            return false;
-        }
-
-        @Override
         public boolean isEnabled(int position) {
-            if (position == mEntries.size() && mExtraViewController != null &&
-                    mExtraViewController.shouldShow()) {
-                return true;
-            }
-
-            if (mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {
+            if (getItemViewType(position) == VIEW_TYPE_EXTRA_VIEW
+                    || mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {
                 return true;
             }
             ApplicationsState.AppEntry entry = mEntries.get(position);
             return !PowerWhitelistBackend.getInstance().isSysWhitelisted(entry.info.packageName);
         }
 
-        public View getView(int position, View convertView, ViewGroup parent) {
-            // A ViewHolder keeps references to children views to avoid unnecessary calls
-            // to findViewById() on each row.
-            AppViewHolder holder = AppViewHolder.createOrRecycle(mManageApplications.mInflater,
-                    convertView);
-            convertView = holder.rootView;
-
-            // Handle the extra view if it is the last entry.
+        @Override
+        public void onBindViewHolder(ApplicationViewHolder holder, int position) {
             if (mEntries != null && mExtraViewController != null && position == mEntries.size()) {
+                // set up view for extra view controller
                 mExtraViewController.setupView(holder);
-                convertView.setEnabled(true);
             } else {
                 // Bind the data efficiently with the holder
                 ApplicationsState.AppEntry entry = mEntries.get(position);
                 synchronized (entry) {
-                    holder.entry = entry;
-                    if (entry.label != null) {
-                        holder.appName.setText(entry.label);
-                    }
+                    holder.setTitle(entry.label);
                     mState.ensureIcon(entry);
-                    if (entry.icon != null) {
-                        holder.appIcon.setImageDrawable(entry.icon);
-                    }
-                    updateSummary(holder);
-                    updateDisableView(holder.disabled, entry.info);
+                    holder.setIcon(entry.icon);
+                    updateSummary(holder, entry);
+                    holder.updateDisableView(entry.info);
                 }
-                convertView.setEnabled(isEnabled(position));
+                holder.setEnabled(isEnabled(position));
             }
-
-            mActive.remove(convertView);
-            mActive.add(convertView);
-            return convertView;
+            holder.itemView.setOnClickListener(mManageApplications);
         }
 
-        @VisibleForTesting
-        void updateDisableView(TextView view, ApplicationInfo info) {
-            if ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
-                view.setVisibility(View.VISIBLE);
-                view.setText(R.string.not_installed);
-            } else if (!info.enabled || info.enabledSetting
-                    == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
-                view.setVisibility(View.VISIBLE);
-                view.setText(R.string.disabled);
-            } else {
-                view.setVisibility(View.GONE);
-            }
-        }
-
-        private void updateSummary(AppViewHolder holder) {
+        private void updateSummary(ApplicationViewHolder holder, AppEntry entry) {
             switch (mManageApplications.mListType) {
                 case LIST_TYPE_NOTIFICATION:
-                    if (holder.entry.extraInfo != null) {
-                        holder.summary.setText(InstalledAppDetails.getNotificationSummary(
-                                (AppRow) holder.entry.extraInfo, mContext));
+                    if (entry.extraInfo != null) {
+                        holder.setSummary(InstalledAppDetails.getNotificationSummary(
+                                (AppRow) entry.extraInfo, mContext));
                     } else {
-                        holder.summary.setText(null);
+                        holder.setSummary(null);
                     }
                     break;
-
                 case LIST_TYPE_USAGE_ACCESS:
-                    if (holder.entry.extraInfo != null) {
-                        holder.summary.setText((new UsageState((PermissionState) holder.entry
-                                .extraInfo)).isPermissible()
-                                ? R.string.app_permission_summary_allowed
-                                : R.string.app_permission_summary_not_allowed);
+                    if (entry.extraInfo != null) {
+                        holder.setSummary(
+                                (new UsageState((PermissionState) entry.extraInfo)).isPermissible()
+                                        ? R.string.app_permission_summary_allowed
+                                        : R.string.app_permission_summary_not_allowed);
                     } else {
-                        holder.summary.setText(null);
+                        holder.setSummary(null);
                     }
                     break;
-
                 case LIST_TYPE_HIGH_POWER:
-                    holder.summary.setText(HighPowerDetail.getSummary(mContext, holder.entry));
+                    holder.setSummary(HighPowerDetail.getSummary(mContext, entry));
                     break;
-
                 case LIST_TYPE_OVERLAY:
-                    holder.summary.setText(DrawOverlayDetails.getSummary(mContext, holder.entry));
+                    holder.setSummary(DrawOverlayDetails.getSummary(mContext, entry));
                     break;
-
                 case LIST_TYPE_WRITE_SETTINGS:
-                    holder.summary.setText(WriteSettingsDetails.getSummary(mContext,
-                            holder.entry));
+                    holder.setSummary(WriteSettingsDetails.getSummary(mContext, entry));
                     break;
-
                 case LIST_TYPE_MANAGE_SOURCES:
-                    holder.summary.setText(ExternalSourcesDetails.getPreferenceSummary(mContext,
-                            holder.entry));
+                    holder.setSummary(ExternalSourcesDetails.getPreferenceSummary(mContext, entry));
                     break;
-
                 default:
-                    holder.updateSizeText(mManageApplications.mInvalidSizeStr, mWhichSize);
+                    holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
                     break;
             }
         }
 
-        @Override
-        public Filter getFilter() {
-            return mFilter;
-        }
-
-        @Override
-        public void onMovedToScrapHeap(View view) {
-            mActive.remove(view);
-        }
-
-        @Override
-        public Object[] getSections() {
-            return mSections;
-        }
-
-        @Override
-        public int getPositionForSection(int sectionIndex) {
-            return mSections[sectionIndex].position;
-        }
-
-        @Override
-        public int getSectionForPosition(int position) {
-            return mPositionToSectionIndex[position];
+        private boolean hasExtraView() {
+            return mExtraViewController != null
+                    && mExtraViewController.shouldShow();
         }
     }
 
@@ -1439,21 +1257,6 @@
         }
     }
 
-    private static class SectionInfo {
-        final String label;
-        final int position;
-
-        public SectionInfo(String label, int position) {
-            this.label = label;
-            this.position = position;
-        }
-
-        @Override
-        public String toString() {
-            return label;
-        }
-    }
-
     public static final SummaryLoader.SummaryProviderFactory SUMMARY_PROVIDER_FACTORY
             = new SummaryLoader.SummaryProviderFactory() {
         @Override
diff --git a/src/com/android/settings/applications/manageapplications/MusicViewHolderController.java b/src/com/android/settings/applications/manageapplications/MusicViewHolderController.java
index 1e44047..2a2ac3b 100644
--- a/src/com/android/settings/applications/manageapplications/MusicViewHolderController.java
+++ b/src/com/android/settings/applications/manageapplications/MusicViewHolderController.java
@@ -72,11 +72,11 @@
     }
 
     @Override
-    public void setupView(AppViewHolder holder) {
-        holder.appIcon.setImageDrawable(
+    public void setupView(ApplicationViewHolder holder) {
+        holder.setIcon(
                 new InsetDrawable(mContext.getDrawable(R.drawable.ic_headset_24dp), INSET_SIZE));
-        holder.appName.setText(mContext.getText(R.string.audio_files_title));
-        holder.summary.setText(Formatter.formatFileSize(mContext, mMusicSize));
+        holder.setTitle(mContext.getText(R.string.audio_files_title));
+        holder.setSummary(Formatter.formatFileSize(mContext, mMusicSize));
     }
 
     @Override
diff --git a/src/com/android/settings/applications/manageapplications/PhotosViewHolderController.java b/src/com/android/settings/applications/manageapplications/PhotosViewHolderController.java
index 2d77f26..fafa875 100644
--- a/src/com/android/settings/applications/manageapplications/PhotosViewHolderController.java
+++ b/src/com/android/settings/applications/manageapplications/PhotosViewHolderController.java
@@ -71,11 +71,11 @@
     }
 
     @Override
-    public void setupView(AppViewHolder holder) {
-        holder.appIcon.setImageDrawable(
+    public void setupView(ApplicationViewHolder holder) {
+        holder.setIcon(
                 new InsetDrawable(mContext.getDrawable(R.drawable.ic_photo_library), INSET_SIZE));
-        holder.appName.setText(mContext.getText(R.string.storage_detail_images));
-        holder.summary.setText(Formatter.formatFileSize(mContext, mFilesSize));
+        holder.setTitle(mContext.getText(R.string.storage_detail_images));
+        holder.setSummary(Formatter.formatFileSize(mContext, mFilesSize));
     }
 
     @Override
diff --git a/src/com/android/settings/datetime/TimeFormatPreferenceController.java b/src/com/android/settings/datetime/TimeFormatPreferenceController.java
index c594b26..302c624 100644
--- a/src/com/android/settings/datetime/TimeFormatPreferenceController.java
+++ b/src/com/android/settings/datetime/TimeFormatPreferenceController.java
@@ -103,6 +103,7 @@
 
     static void timeUpdated(Context context, Boolean is24Hour) {
         Intent timeChanged = new Intent(Intent.ACTION_TIME_CHANGED);
+        timeChanged.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
         int timeFormatPreference;
         if (is24Hour == null) {
             timeFormatPreference = Intent.EXTRA_TIME_PREF_VALUE_USE_LOCALE_DEFAULT;
diff --git a/src/com/android/settings/development/AppPicker.java b/src/com/android/settings/development/AppPicker.java
index d038b8f..433f31a 100644
--- a/src/com/android/settings/development/AppPicker.java
+++ b/src/com/android/settings/development/AppPicker.java
@@ -32,7 +32,6 @@
 import android.widget.ListView;
 
 import com.android.settings.R;
-import com.android.settings.applications.manageapplications.AppViewHolder;
 
 import java.text.Collator;
 import java.util.ArrayList;
diff --git a/src/com/android/settings/applications/manageapplications/AppViewHolder.java b/src/com/android/settings/development/AppViewHolder.java
similarity index 71%
rename from src/com/android/settings/applications/manageapplications/AppViewHolder.java
rename to src/com/android/settings/development/AppViewHolder.java
index 7b9d766..7a90bcf 100644
--- a/src/com/android/settings/applications/manageapplications/AppViewHolder.java
+++ b/src/com/android/settings/development/AppViewHolder.java
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-package com.android.settings.applications.manageapplications;
+package com.android.settings.development;
 
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -57,24 +56,4 @@
             return (AppViewHolder)convertView.getTag();
         }
     }
-
-    void updateSizeText(CharSequence invalidSizeStr, int whichSize) {
-        if (ManageApplications.DEBUG) Log.i(ManageApplications.TAG, "updateSizeText of "
-                + entry.label + " " + entry + ": " + entry.sizeStr);
-        if (entry.sizeStr != null) {
-            switch (whichSize) {
-                case ManageApplications.SIZE_INTERNAL:
-                    summary.setText(entry.internalSizeStr);
-                    break;
-                case ManageApplications.SIZE_EXTERNAL:
-                    summary.setText(entry.externalSizeStr);
-                    break;
-                default:
-                    summary.setText(entry.sizeStr);
-                    break;
-            }
-        } else if (entry.size == ApplicationsState.SIZE_INVALID) {
-            summary.setText(invalidSizeStr);
-        }
-    }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/development/WebViewAppPreferenceControllerV2.java b/src/com/android/settings/development/WebViewAppPreferenceControllerV2.java
index 87ddb81..d061281 100644
--- a/src/com/android/settings/development/WebViewAppPreferenceControllerV2.java
+++ b/src/com/android/settings/development/WebViewAppPreferenceControllerV2.java
@@ -85,7 +85,7 @@
     @VisibleForTesting
     DefaultAppInfo getDefaultAppInfo() {
         final PackageInfo currentPackage = mWebViewUpdateServiceWrapper.getCurrentWebViewPackage();
-        return new DefaultAppInfo(mPackageManager,
+        return new DefaultAppInfo(mContext, mPackageManager,
                 currentPackage == null ? null : currentPackage.applicationInfo);
     }
 
diff --git a/src/com/android/settings/display/AppGridView.java b/src/com/android/settings/display/AppGridView.java
index 2d52ef2..4b814d0 100644
--- a/src/com/android/settings/display/AppGridView.java
+++ b/src/com/android/settings/display/AppGridView.java
@@ -16,20 +16,23 @@
 
 package com.android.settings.display;
 
-import com.android.settings.R;
-
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.support.annotation.VisibleForTesting;
 import android.util.AttributeSet;
+import android.util.IconDrawableFactory;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ArrayAdapter;
 import android.widget.GridView;
 import android.widget.ImageView;
 
+import com.android.settings.R;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -63,7 +66,8 @@
     /**
      * Loads application labels and icons.
      */
-    private static class AppsAdapter extends ArrayAdapter<ActivityEntry> {
+    @VisibleForTesting
+    public static class AppsAdapter extends ArrayAdapter<ActivityEntry> {
         private final PackageManager mPackageManager;
         private final int mIconResId;
 
@@ -80,9 +84,8 @@
         public View getView(int position, View convertView, ViewGroup parent) {
             final View view = super.getView(position, convertView, parent);
             final ActivityEntry entry = getItem(position);
-            final ImageView iconView = (ImageView) view.findViewById(mIconResId);
-            final Drawable icon = entry.info.loadIcon(mPackageManager);
-            iconView.setImageDrawable(icon);
+            final ImageView iconView = view.findViewById(mIconResId);
+            iconView.setImageDrawable(entry.getIcon());
             return view;
         }
 
@@ -108,10 +111,11 @@
             final PackageManager pm = mPackageManager;
             final ArrayList<ActivityEntry> results = new ArrayList<>();
             final List<ResolveInfo> infos = pm.queryIntentActivities(mainIntent, 0);
+            final IconDrawableFactory iconFactory = IconDrawableFactory.newInstance(getContext());
             for (ResolveInfo info : infos) {
                 final CharSequence label = info.loadLabel(pm);
                 if (label != null) {
-                    results.add(new ActivityEntry(info, label.toString()));
+                    results.add(new ActivityEntry(info, label.toString(), iconFactory));
                 }
             }
 
@@ -124,13 +128,19 @@
     /**
      * Class used for caching the activity label and icon.
      */
-    private static class ActivityEntry implements Comparable<ActivityEntry> {
+    @VisibleForTesting
+    public static class ActivityEntry implements Comparable<ActivityEntry> {
+
         public final ResolveInfo info;
         public final String label;
+        private final IconDrawableFactory mIconFactory;
+        private final int mUserId;
 
-        public ActivityEntry(ResolveInfo info, String label) {
+        public ActivityEntry(ResolveInfo info, String label, IconDrawableFactory iconFactory) {
             this.info = info;
             this.label = label;
+            mIconFactory = iconFactory;
+            mUserId = UserHandle.myUserId();
         }
 
         @Override
@@ -142,5 +152,10 @@
         public String toString() {
             return label;
         }
+
+        public Drawable getIcon() {
+            return mIconFactory.getBadgedIcon(
+                    info.activityInfo, info.activityInfo.applicationInfo, mUserId);
+        }
     }
 }
diff --git a/src/com/android/settings/enterprise/ApplicationListPreferenceController.java b/src/com/android/settings/enterprise/ApplicationListPreferenceController.java
index eee9b33..dce6f57 100644
--- a/src/com/android/settings/enterprise/ApplicationListPreferenceController.java
+++ b/src/com/android/settings/enterprise/ApplicationListPreferenceController.java
@@ -20,6 +20,7 @@
 import android.content.pm.PackageManager;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
+import android.util.IconDrawableFactory;
 
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
@@ -63,13 +64,14 @@
         if (screen == null) {
             return;
         }
+        final IconDrawableFactory iconDrawableFactory = IconDrawableFactory.newInstance(mContext);
         final Context prefContext = mParent.getPreferenceManager().getContext();
         for (int position = 0; position < result.size(); position++) {
             final UserAppInfo item = result.get(position);
             final Preference preference = new Preference(prefContext);
             preference.setLayoutResource(R.layout.preference_app);
             preference.setTitle(item.appInfo.loadLabel(mPm));
-            preference.setIcon(item.appInfo.loadIcon(mPm));
+            preference.setIcon(iconDrawableFactory.getBadgedIcon(item.appInfo));
             preference.setOrder(position);
             preference.setSelectable(false);
             screen.addPreference(preference);
diff --git a/src/com/android/settings/search/AccessibilityServiceResultLoader.java b/src/com/android/settings/search/AccessibilityServiceResultLoader.java
index 7ffbcfc..64cceb7 100644
--- a/src/com/android/settings/search/AccessibilityServiceResultLoader.java
+++ b/src/com/android/settings/search/AccessibilityServiceResultLoader.java
@@ -26,8 +26,10 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
 import android.support.annotation.VisibleForTesting;
 import android.support.v4.content.ContextCompat;
+import android.util.IconDrawableFactory;
 import android.view.accessibility.AccessibilityManager;
 
 import com.android.settings.R;
@@ -44,17 +46,22 @@
 
     private static final int NAME_NO_MATCH = -1;
 
+    private final Context mContext;
+
     private List<String> mBreadcrumb;
     private SiteMapManager mSiteMapManager;
     @VisibleForTesting
     final String mQuery;
     private final AccessibilityManager mAccessibilityManager;
     private final PackageManager mPackageManager;
+    private final int mUserId;
 
 
     public AccessibilityServiceResultLoader(Context context, String query,
             SiteMapManager mapManager) {
         super(context);
+        mContext = context;
+        mUserId = UserHandle.myUserId();
         mSiteMapManager = mapManager;
         mPackageManager = context.getPackageManager();
         mAccessibilityManager =
@@ -68,6 +75,7 @@
         final Context context = getContext();
         final List<AccessibilityServiceInfo> services = mAccessibilityManager
                 .getInstalledAccessibilityServiceList();
+        final IconDrawableFactory iconFactory = IconDrawableFactory.newInstance(mContext);
         final String screenTitle = context.getString(R.string.accessibility_settings);
         for (AccessibilityServiceInfo service : services) {
             if (service == null) {
@@ -87,7 +95,10 @@
             if (resolveInfo.getIconResource() == 0) {
                 icon = ContextCompat.getDrawable(context, R.mipmap.ic_accessibility_generic);
             } else {
-                icon = resolveInfo.loadIcon(mPackageManager);
+                icon = iconFactory.getBadgedIcon(
+                        resolveInfo.serviceInfo,
+                        resolveInfo.serviceInfo.applicationInfo,
+                        mUserId);
             }
             final String componentName = new ComponentName(serviceInfo.packageName,
                     serviceInfo.name).flattenToString();
diff --git a/src/com/android/settings/webview/WebViewAppPicker.java b/src/com/android/settings/webview/WebViewAppPicker.java
index 362ca1f..536cd8b 100644
--- a/src/com/android/settings/webview/WebViewAppPicker.java
+++ b/src/com/android/settings/webview/WebViewAppPicker.java
@@ -60,12 +60,13 @@
     @Override
     protected List<DefaultAppInfo> getCandidates() {
         final List<DefaultAppInfo> packageInfoList = new ArrayList<DefaultAppInfo>();
-        List<ApplicationInfo> pkgs =
-                getWebViewUpdateServiceWrapper().getValidWebViewApplicationInfos(getContext());
+        final Context context = getContext();
+        final WebViewUpdateServiceWrapper webViewUpdateService = getWebViewUpdateServiceWrapper();
+        final List<ApplicationInfo> pkgs =
+                webViewUpdateService.getValidWebViewApplicationInfos(context);
         for (ApplicationInfo ai : pkgs) {
-            packageInfoList.add(createDefaultAppInfo(mPm, ai,
-                    getDisabledReason(getWebViewUpdateServiceWrapper(),
-                            getContext(), ai.packageName)));
+            packageInfoList.add(createDefaultAppInfo(context, mPm, ai,
+                    getDisabledReason(webViewUpdateService, context, ai.packageName)));
         }
         return packageInfoList;
     }
@@ -112,9 +113,9 @@
     }
 
     private static class WebViewAppInfo extends DefaultAppInfo {
-        public WebViewAppInfo(PackageManagerWrapper pm, PackageItemInfo packageItemInfo,
-                String summary, boolean enabled) {
-            super(pm, packageItemInfo, summary, enabled);
+        public WebViewAppInfo(Context context, PackageManagerWrapper pm,
+                PackageItemInfo packageItemInfo, String summary, boolean enabled) {
+            super(context, pm, packageItemInfo, summary, enabled);
         }
 
         @Override
@@ -131,9 +132,9 @@
 
 
     @VisibleForTesting
-    DefaultAppInfo createDefaultAppInfo(PackageManagerWrapper pm, PackageItemInfo packageItemInfo,
-            String disabledReason) {
-        return new WebViewAppInfo(pm, packageItemInfo, disabledReason,
+    DefaultAppInfo createDefaultAppInfo(Context context, PackageManagerWrapper pm,
+            PackageItemInfo packageItemInfo, String disabledReason) {
+        return new WebViewAppInfo(context, pm, packageItemInfo, disabledReason,
                 TextUtils.isEmpty(disabledReason) /* enabled */);
     }
 
diff --git a/src/com/android/settings/webview/WebViewAppPreferenceController.java b/src/com/android/settings/webview/WebViewAppPreferenceController.java
index 96db801..9410af7 100644
--- a/src/com/android/settings/webview/WebViewAppPreferenceController.java
+++ b/src/com/android/settings/webview/WebViewAppPreferenceController.java
@@ -46,7 +46,7 @@
     @Override
     public DefaultAppInfo getDefaultAppInfo() {
         PackageInfo currentPackage = mWebViewUpdateServiceWrapper.getCurrentWebViewPackage();
-        return new DefaultAppInfo(mPackageManager,
+        return new DefaultAppInfo(mContext, mPackageManager,
                 currentPackage == null ? null : currentPackage.applicationInfo);
     }
 
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppInfoTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppInfoTest.java
index 0ae9615..d4cd6da 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppInfoTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppInfoTest.java
@@ -21,11 +21,13 @@
 import static org.mockito.Mockito.when;
 
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
 
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settingslib.wrapper.PackageManagerWrapper;
 
 import org.junit.Before;
@@ -33,6 +35,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 
 @RunWith(SettingsRobolectricTestRunner.class)
@@ -48,31 +51,33 @@
     @Mock
     private PackageManagerWrapper mPackageManagerWrapper;
 
+    private Context mContext;
     private DefaultAppInfo mInfo;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
         when(mPackageManagerWrapper.getPackageManager()).thenReturn(mPackageManager);
     }
 
     @Test
     public void initInfoWithActivityInfo_shouldLoadInfo() {
         mPackageItemInfo.packageName = "test";
-        mInfo = new DefaultAppInfo(mPackageManagerWrapper, mPackageItemInfo);
+        mInfo = new DefaultAppInfo(mContext, mPackageManagerWrapper, mPackageItemInfo);
         mInfo.loadLabel();
-        mInfo.loadIcon();
+        Drawable icon = mInfo.loadIcon();
 
         assertThat(mInfo.getKey()).isEqualTo(mPackageItemInfo.packageName);
+        assertThat(icon).isNotNull();
         verify(mPackageItemInfo).loadLabel(mPackageManager);
-        verify(mPackageItemInfo).loadIcon(mPackageManager);
     }
 
     @Test
     public void initInfoWithComponent_shouldLoadInfo() {
         when(mComponentName.getPackageName()).thenReturn("com.android.settings");
 
-        mInfo = new DefaultAppInfo(mPackageManagerWrapper, 0 /* uid */, mComponentName);
+        mInfo = new DefaultAppInfo(mContext, mPackageManagerWrapper, 0 /* uid */, mComponentName);
         mInfo.getKey();
 
         verify(mComponentName).flattenToString();
diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java
new file mode 100644
index 0000000..cf2403b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ApplicationViewHolderTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.settings.applications.manageapplications;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.settings.R;
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settingslib.applications.ApplicationsState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class ApplicationViewHolderTest {
+
+    private Context mContext;
+    private View mView;
+    private ApplicationViewHolder mHolder;
+
+    @Before
+    public void seUp() {
+        mContext = RuntimeEnvironment.application;
+        mView = ApplicationViewHolder.newView(LayoutInflater.from(mContext),
+                new FrameLayout(mContext));
+        mHolder = new ApplicationViewHolder(mView);
+    }
+
+    @Test
+    public void updateDisableView_appDisabledUntilUsed_shouldSetDisabled() {
+        final ApplicationInfo info = new ApplicationInfo();
+        info.flags = ApplicationInfo.FLAG_INSTALLED;
+        info.enabled = true;
+        info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+        mHolder.updateDisableView(info);
+
+        assertThat(mHolder.mDisabled.getText()).isEqualTo(mContext.getText(R.string.disabled));
+    }
+
+    @Test
+    public void setSummaries() {
+        mHolder.setSummary("hello");
+        assertThat(mHolder.mSummary.getText()).isEqualTo("hello");
+
+        mHolder.setSummary(R.string.disabled);
+        assertThat(mHolder.mSummary.getText()).isEqualTo(mContext.getText(R.string.disabled));
+    }
+
+    @Test
+    public void updateSize() {
+        final String invalidStr = "invalid";
+        final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class);
+        entry.internalSizeStr = "internal";
+        entry.externalSizeStr = "external";
+        entry.sizeStr = entry.internalSizeStr;
+
+        mHolder.updateSizeText(entry, invalidStr, ManageApplications.SIZE_INTERNAL);
+        assertThat(mHolder.mSummary.getText()).isEqualTo(entry.internalSizeStr);
+
+        mHolder.updateSizeText(entry, invalidStr, ManageApplications.SIZE_EXTERNAL);
+        assertThat(mHolder.mSummary.getText()).isEqualTo(entry.externalSizeStr);
+
+        entry.sizeStr = null;
+        entry.size = ApplicationsState.SIZE_INVALID;
+        mHolder.updateSizeText(entry, invalidStr, ManageApplications.SIZE_EXTERNAL);
+        assertThat(mHolder.mSummary.getText()).isEqualTo(invalidStr);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
index 9afaf1f..9eb36ef 100644
--- a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
@@ -31,19 +31,16 @@
 
 import android.app.Activity;
 import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.os.Handler;
+import android.os.Bundle;
 import android.os.Looper;
+import android.support.v7.widget.RecyclerView;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.TextView;
 
 import com.android.settings.R;
-import com.android.settings.Settings;
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.testutils.shadow.SettingsShadowResources;
@@ -103,30 +100,6 @@
     }
 
     @Test
-    public void launchFragment() {
-        SettingsRobolectricTestRunner.startSettingsFragment(
-                mFragment, Settings.ManageApplicationsActivity.class);
-    }
-
-    @Test
-    public void updateDisableView_appDisabledUntilUsed_shouldSetDisabled() {
-        final TextView view = mock(TextView.class);
-        final ApplicationInfo info = new ApplicationInfo();
-        info.flags = ApplicationInfo.FLAG_INSTALLED;
-        info.enabled = true;
-        info.enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
-        ManageApplications fragment = mock(ManageApplications.class);
-        when(fragment.getActivity()).thenReturn(mock(Activity.class));
-        final ManageApplications.ApplicationsAdapter adapter =
-                new ManageApplications.ApplicationsAdapter(mState, fragment,
-                        AppFilterRegistry.getInstance().get(FILTER_APPS_ALL));
-
-        adapter.updateDisableView(view, info);
-
-        verify(view).setText(R.string.disabled);
-    }
-
-    @Test
     public void updateMenu_mainListType_showAppReset() {
         setUpOptionMenus();
         ReflectionHelpers.setField(mFragment, "mListType", ManageApplications.LIST_TYPE_MAIN);
@@ -170,14 +143,12 @@
         ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class));
         ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class));
         when(fragment.getActivity()).thenReturn(mock(Activity.class));
-        final Handler handler = mock(Handler.class);
         final ManageApplications.ApplicationsAdapter adapter =
-            spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
-                    AppFilterRegistry.getInstance().get(FILTER_APPS_ALL)));
+                spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
+                        AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
         final LoadingViewController loadingViewController =
                 mock(LoadingViewController.class);
         ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
-        ReflectionHelpers.setField(adapter, "mFgHandler", handler);
 
         // app loading completed
         ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", true);
@@ -196,15 +167,12 @@
         ReflectionHelpers.setField(fragment, "mLoadingContainer", mock(View.class));
         ReflectionHelpers.setField(fragment, "mListContainer", mock(View.class));
         when(fragment.getActivity()).thenReturn(mock(Activity.class));
-
-        final Handler handler = mock(Handler.class);
         final ManageApplications.ApplicationsAdapter adapter =
-            spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
-                    AppFilterRegistry.getInstance().get(FILTER_APPS_ALL)));
+                spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
+                        AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
         final LoadingViewController loadingViewController =
                 mock(LoadingViewController.class);
         ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
-        ReflectionHelpers.setField(adapter, "mFgHandler", handler);
 
         // app loading not yet completed
         ReflectionHelpers.setField(adapter, "mHasReceivedLoadEntries", false);
@@ -218,6 +186,10 @@
     public void onRebuildComplete_shouldHideLoadingView() {
         final Context context = RuntimeEnvironment.application;
         final ManageApplications fragment = mock(ManageApplications.class);
+        final RecyclerView recyclerView = mock(RecyclerView.class);
+        final View emptyView = mock(View.class);
+        ReflectionHelpers.setField(fragment, "mRecyclerView", recyclerView);
+        ReflectionHelpers.setField(fragment, "mEmptyView", emptyView);
         final View loadingContainer = mock(View.class);
         when(loadingContainer.getContext()).thenReturn(context);
         final View listContainer = mock(View.class);
@@ -226,14 +198,12 @@
         ReflectionHelpers.setField(fragment, "mLoadingContainer", loadingContainer);
         ReflectionHelpers.setField(fragment, "mListContainer", listContainer);
         when(fragment.getActivity()).thenReturn(mock(Activity.class));
-        final Handler handler = mock(Handler.class);
         final ManageApplications.ApplicationsAdapter adapter =
-            spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
-                    AppFilterRegistry.getInstance().get(FILTER_APPS_ALL)));
+                spy(new ManageApplications.ApplicationsAdapter(mState, fragment,
+                        AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
         final LoadingViewController loadingViewController =
                 mock(LoadingViewController.class);
         ReflectionHelpers.setField(adapter, "mLoadingViewController", loadingViewController);
-        ReflectionHelpers.setField(adapter, "mFgHandler", handler);
         ReflectionHelpers.setField(adapter, "mAppFilter",
                 AppFilterRegistry.getInstance().get(FILTER_APPS_ALL));
 
diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/MusicViewHolderControllerTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/MusicViewHolderControllerTest.java
index 46a059a..28ac9d9 100644
--- a/tests/robotests/src/com/android/settings/applications/manageapplications/MusicViewHolderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/manageapplications/MusicViewHolderControllerTest.java
@@ -28,11 +28,12 @@
 import android.os.storage.VolumeInfo;
 import android.provider.DocumentsContract;
 import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
 
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settingslib.applications.StorageStatsSource;
-import com.android.settingslib.deviceinfo.StorageVolumeProvider;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -51,14 +52,13 @@
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Fragment mFragment;
     @Mock
-    private StorageVolumeProvider mSvp;
-    @Mock
     private StorageStatsSource mSource;
 
     private Context mContext;
     private MusicViewHolderController mController;
     private VolumeInfo mVolume;
-    private AppViewHolder mHolder;
+    private View mView;
+    private ApplicationViewHolder mHolder;
 
     @Before
     public void setUp() throws Exception {
@@ -69,25 +69,26 @@
                 new UserHandle(0));
 
         LayoutInflater inflater = LayoutInflater.from(mContext);
-        mHolder = AppViewHolder.createOrRecycle(inflater, null);
+        mView = ApplicationViewHolder.newView(inflater, new FrameLayout(mContext));
+        mHolder = new ApplicationViewHolder(mView);
     }
 
     @Test
     public void storageShouldBeZeroBytesIfQueriedBeforeStorageQueryFinishes() {
         mController.setupView(mHolder);
 
-        assertThat(mHolder.summary.getText().toString()).isEqualTo("0.00 B");
+        assertThat(mHolder.mSummary.getText().toString()).isEqualTo("0.00 B");
     }
 
     @Test
     public void storageShouldRepresentStorageStatsQuery() throws Exception {
-        when(mSource.getExternalStorageStats(nullable(String.class), nullable(UserHandle.class))).thenReturn(
-                new StorageStatsSource.ExternalStorageStats(1, 1, 0, 0, 0));
+        when(mSource.getExternalStorageStats(nullable(String.class), nullable(UserHandle.class)))
+                .thenReturn(new StorageStatsSource.ExternalStorageStats(1, 1, 0, 0, 0));
 
         mController.queryStats();
         mController.setupView(mHolder);
 
-        assertThat(mHolder.summary.getText().toString()).isEqualTo("1.00 B");
+        assertThat(mHolder.mSummary.getText().toString()).isEqualTo("1.00 B");
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/applications/manageapplications/PhotosViewHolderControllerTest.java b/tests/robotests/src/com/android/settings/applications/manageapplications/PhotosViewHolderControllerTest.java
index a051ac3..2a26e31 100644
--- a/tests/robotests/src/com/android/settings/applications/manageapplications/PhotosViewHolderControllerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/manageapplications/PhotosViewHolderControllerTest.java
@@ -27,11 +27,12 @@
 import android.os.UserHandle;
 import android.os.storage.VolumeInfo;
 import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
 
 import com.android.settings.TestConfig;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settingslib.applications.StorageStatsSource;
-import com.android.settingslib.deviceinfo.StorageVolumeProvider;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -48,14 +49,14 @@
 public class PhotosViewHolderControllerTest {
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Fragment mFragment;
-
-    @Mock private StorageVolumeProvider mSvp;
     @Mock private StorageStatsSource mSource;
 
     private Context mContext;
     private PhotosViewHolderController mController;
     private VolumeInfo mVolume;
-    private AppViewHolder mHolder;
+    private View mView;
+    private ApplicationViewHolder mHolder;
+
 
     @Before
     public void setUp() throws Exception {
@@ -66,15 +67,16 @@
                 new PhotosViewHolderController(
                         mContext, mSource, mVolume.fsUuid, new UserHandle(0));
 
-        LayoutInflater inflater = LayoutInflater.from(mContext);
-        mHolder = AppViewHolder.createOrRecycle(inflater, null);
+        final LayoutInflater inflater = LayoutInflater.from(mContext);
+        mView = ApplicationViewHolder.newView(inflater, new FrameLayout(mContext));
+        mHolder = new ApplicationViewHolder(mView);
     }
 
     @Test
     public void storageShouldBeZeroBytesIfQueriedBeforeStorageQueryFinishes() {
         mController.setupView(mHolder);
 
-        assertThat(mHolder.summary.getText().toString()).isEqualTo("0.00 B");
+        assertThat(mHolder.mSummary.getText().toString()).isEqualTo("0.00 B");
     }
 
     @Test
@@ -85,7 +87,7 @@
         mController.queryStats();
         mController.setupView(mHolder);
 
-        assertThat(mHolder.summary.getText().toString()).isEqualTo("11.00 B");
+        assertThat(mHolder.mSummary.getText().toString()).isEqualTo("11.00 B");
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/datetime/TimeChangeListenerMixinTest.java b/tests/robotests/src/com/android/settings/datetime/TimeChangeListenerMixinTest.java
index 843c753..ada59f4 100644
--- a/tests/robotests/src/com/android/settings/datetime/TimeChangeListenerMixinTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/TimeChangeListenerMixinTest.java
@@ -66,7 +66,8 @@
     public void onResume_shouldRegisterIntentFilter() {
         mMixin.onResume();
         mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_TICK));
-        mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_CHANGED));
+        mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_CHANGED)
+                .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND));
         mContext.sendBroadcast(new Intent(Intent.ACTION_TIMEZONE_CHANGED));
 
         verify(mCallback, times(3)).updateTimeAndDateDisplay(mContext);
@@ -77,7 +78,8 @@
         mMixin.onResume();
         mMixin.onPause();
         mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_TICK));
-        mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_CHANGED));
+        mContext.sendBroadcast(new Intent(Intent.ACTION_TIME_CHANGED)
+                .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND));
         mContext.sendBroadcast(new Intent(Intent.ACTION_TIMEZONE_CHANGED));
 
         verify(mCallback, never()).updateTimeAndDateDisplay(mContext);
diff --git a/tests/robotests/src/com/android/settings/display/AppGridViewTest.java b/tests/robotests/src/com/android/settings/display/AppGridViewTest.java
new file mode 100644
index 0000000..d0a92c9
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/display/AppGridViewTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.settings.display;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.util.IconDrawableFactory;
+
+import com.android.settings.TestConfig;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AppGridViewTest {
+
+    @Mock
+    private ResolveInfo mInfo;
+    @Mock
+    private ActivityInfo mActivityInfo;
+    private Context mContext;
+    private IconDrawableFactory mIconFactory;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mInfo.activityInfo = mActivityInfo;
+        mContext = RuntimeEnvironment.application;
+        mIconFactory = IconDrawableFactory.newInstance(mContext);
+    }
+
+    @Test
+    public void appEntry_shouldLoadIcon() {
+
+        final AppGridView.ActivityEntry activityEntry = new AppGridView.ActivityEntry(
+                mInfo, "label", mIconFactory);
+
+        assertThat(activityEntry.label).isEqualTo("label");
+        assertThat(activityEntry.getIcon()).isNotNull();
+    }
+
+    @Test
+    public void appEntry_compare_shouldCompareIgnoreCase() {
+        final AppGridView.ActivityEntry entry1 = new AppGridView.ActivityEntry(
+                mInfo, "label", mIconFactory);
+        final AppGridView.ActivityEntry entry2 = new AppGridView.ActivityEntry(
+                mInfo, "LABEL", mIconFactory);
+        final AppGridView.ActivityEntry entry3 = new AppGridView.ActivityEntry(
+                mInfo, "label2", mIconFactory);
+
+        assertThat(entry1.compareTo(entry2)).isEqualTo(0);
+        assertThat(entry1.compareTo(entry3)).isNotEqualTo(0);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
index 73d001a..470b69c 100644
--- a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
+++ b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java
@@ -16,38 +16,6 @@
 
 package com.android.settings.webview;
 
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageItemInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
-import android.os.UserManager;
-
-import com.android.settings.testutils.SettingsRobolectricTestRunner;
-import com.android.settings.TestConfig;
-import com.android.settings.applications.defaultapps.DefaultAppInfo;
-import com.android.settings.core.instrumentation.MetricsFeatureProvider;
-import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.widget.RadioButtonPreference;
-import com.android.settings.wrapper.UserPackageWrapper;
-import com.android.settingslib.wrapper.PackageManagerWrapper;
-
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Answers;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import org.robolectric.util.ReflectionHelpers;
-
-import java.util.Arrays;
-
 import static android.provider.Settings.ACTION_WEBVIEW_SETTINGS;
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.Matchers.any;
@@ -62,22 +30,47 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+
+import com.android.settings.TestConfig;
+import com.android.settings.applications.defaultapps.DefaultAppInfo;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.widget.RadioButtonPreference;
+import com.android.settings.wrapper.UserPackageWrapper;
+import com.android.settingslib.wrapper.PackageManagerWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.Arrays;
+
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class WebViewAppPickerTest {
     private Context mContext = RuntimeEnvironment.application;
 
-    private static UserInfo sFirstUser;
-    private static UserInfo sSecondUser;
+    private UserInfo mFirstUser;
+    private UserInfo mSecondUser;
 
     private final static String DEFAULT_PACKAGE_NAME = "DEFAULT_PACKAGE_NAME";
 
-    @BeforeClass
-    public static void beforeClass() {
-        sFirstUser = new UserInfo(0, "FIRST_USER", 0);
-        sSecondUser = new UserInfo(0, "SECOND_USER", 0);
-    }
-
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Activity mActivity;
     @Mock
@@ -99,7 +92,8 @@
         MockitoAnnotations.initMocks(this);
         FakeFeatureFactory.setupForTest(mActivity);
         when(mActivity.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
-
+        mFirstUser = new UserInfo(0, "FIRST_USER", 0);
+        mSecondUser = new UserInfo(0, "SECOND_USER", 0);
         mPicker = new WebViewAppPicker();
         mPicker = spy(mPicker);
         doNothing().when(mPicker).updateCandidates();
@@ -174,7 +168,7 @@
     @Test
     public void testDisabledPackageShownAsDisabled() {
         String disabledReason = "disabled";
-        DefaultAppInfo webviewAppInfo = mPicker.createDefaultAppInfo(mPackageManager,
+        DefaultAppInfo webviewAppInfo = mPicker.createDefaultAppInfo(mActivity, mPackageManager,
                 createApplicationInfo(DEFAULT_PACKAGE_NAME), disabledReason);
 
         RadioButtonPreference mockPreference = mock(RadioButtonPreference.class);
@@ -189,7 +183,7 @@
     @Test
     public void testEnabledPackageShownAsEnabled() {
         String disabledReason = "";
-        DefaultAppInfo webviewAppInfo = mPicker.createDefaultAppInfo(mPackageManager,
+        DefaultAppInfo webviewAppInfo = mPicker.createDefaultAppInfo(mActivity, mPackageManager,
                 createApplicationInfo(DEFAULT_PACKAGE_NAME), disabledReason);
 
         RadioButtonPreference mockPreference = mock(RadioButtonPreference.class);
@@ -204,7 +198,7 @@
     @Test
     public void testDisabledPackageShowsDisabledReasonSummary() {
         String disabledReason = "disabled";
-        DefaultAppInfo webviewAppInfo = mPicker.createDefaultAppInfo(mPackageManager,
+        DefaultAppInfo webviewAppInfo = mPicker.createDefaultAppInfo(mActivity, mPackageManager,
                 createApplicationInfo(DEFAULT_PACKAGE_NAME), disabledReason);
 
         RadioButtonPreference mockPreference = mock(RadioButtonPreference.class);
@@ -220,7 +214,7 @@
     @Test
     public void testEnabledPackageShowsEmptySummary() {
         String disabledReason = null;
-        DefaultAppInfo webviewAppInfo = mPicker.createDefaultAppInfo(mPackageManager,
+        DefaultAppInfo webviewAppInfo = mPicker.createDefaultAppInfo(mActivity, mPackageManager,
                 createApplicationInfo(DEFAULT_PACKAGE_NAME), disabledReason);
 
         RadioButtonPreference mockPreference = mock(RadioButtonPreference.class);
@@ -268,14 +262,14 @@
         UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class);
         when(packageForFirstUser.isEnabledPackage()).thenReturn(false);
         when(packageForFirstUser.isInstalledPackage()).thenReturn(true);
-        when(packageForFirstUser.getUserInfo()).thenReturn(sFirstUser);
+        when(packageForFirstUser.getUserInfo()).thenReturn(mFirstUser);
 
         WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class);
         when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME)))
                 .thenReturn(Arrays.asList(packageForFirstUser));
 
         final String EXPECTED_DISABLED_REASON = String.format(
-                "(disabled for user %s)", sFirstUser.name);
+                "(disabled for user %s)", mFirstUser.name);
         assertThat(mPicker.getDisabledReason(wvusWrapper, mContext,
                 DEFAULT_PACKAGE_NAME)).isEqualTo(EXPECTED_DISABLED_REASON);
     }
@@ -285,14 +279,14 @@
         UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class);
         when(packageForFirstUser.isEnabledPackage()).thenReturn(true);
         when(packageForFirstUser.isInstalledPackage()).thenReturn(false);
-        when(packageForFirstUser.getUserInfo()).thenReturn(sFirstUser);
+        when(packageForFirstUser.getUserInfo()).thenReturn(mFirstUser);
 
         WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class);
         when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME)))
                 .thenReturn(Arrays.asList(packageForFirstUser));
 
         final String EXPECTED_DISABLED_REASON = String.format(
-                "(uninstalled for user %s)", sFirstUser.name);
+                "(uninstalled for user %s)", mFirstUser.name);
         assertThat(mPicker.getDisabledReason(wvusWrapper, mContext,
                 DEFAULT_PACKAGE_NAME)).isEqualTo(EXPECTED_DISABLED_REASON);
     }
@@ -302,19 +296,19 @@
         UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class);
         when(packageForFirstUser.isEnabledPackage()).thenReturn(false);
         when(packageForFirstUser.isInstalledPackage()).thenReturn(true);
-        when(packageForFirstUser.getUserInfo()).thenReturn(sFirstUser);
+        when(packageForFirstUser.getUserInfo()).thenReturn(mFirstUser);
 
         UserPackageWrapper packageForSecondUser = mock(UserPackageWrapper.class);
         when(packageForSecondUser.isEnabledPackage()).thenReturn(true);
         when(packageForSecondUser.isInstalledPackage()).thenReturn(false);
-        when(packageForSecondUser.getUserInfo()).thenReturn(sSecondUser);
+        when(packageForSecondUser.getUserInfo()).thenReturn(mSecondUser);
 
         WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class);
         when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME)))
                 .thenReturn(Arrays.asList(packageForFirstUser, packageForSecondUser));
 
         final String EXPECTED_DISABLED_REASON = String.format(
-                "(disabled for user %s)", sFirstUser.name);
+                "(disabled for user %s)", mFirstUser.name);
         assertThat(mPicker.getDisabledReason(
                 wvusWrapper, mContext, DEFAULT_PACKAGE_NAME)).isEqualTo(EXPECTED_DISABLED_REASON);
     }
@@ -328,19 +322,19 @@
         UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class);
         when(packageForFirstUser.isEnabledPackage()).thenReturn(false);
         when(packageForFirstUser.isInstalledPackage()).thenReturn(false);
-        when(packageForFirstUser.getUserInfo()).thenReturn(sFirstUser);
+        when(packageForFirstUser.getUserInfo()).thenReturn(mFirstUser);
 
         UserPackageWrapper packageForSecondUser = mock(UserPackageWrapper.class);
         when(packageForSecondUser.isEnabledPackage()).thenReturn(true);
         when(packageForSecondUser.isInstalledPackage()).thenReturn(true);
-        when(packageForSecondUser.getUserInfo()).thenReturn(sSecondUser);
+        when(packageForSecondUser.getUserInfo()).thenReturn(mSecondUser);
 
         WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class);
         when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME)))
                 .thenReturn(Arrays.asList(packageForFirstUser, packageForSecondUser));
 
         final String EXPECTED_DISABLED_REASON = String.format(
-                "(uninstalled for user %s)", sFirstUser.name);
+                "(uninstalled for user %s)", mFirstUser.name);
         assertThat(mPicker.getDisabledReason(wvusWrapper, mContext,
                 DEFAULT_PACKAGE_NAME)).isEqualTo(EXPECTED_DISABLED_REASON);
     }
@@ -354,7 +348,7 @@
         PackageItemInfo mockPackageItemInfo = mock(PackageItemInfo.class);
         mockPackageItemInfo.packageName = DEFAULT_PACKAGE_NAME;
         when(mockPackageItemInfo.loadLabel(any())).thenReturn("myPackage");
-        DefaultAppInfo webviewAppInfo = mPicker.createDefaultAppInfo(mPackageManager,
+        DefaultAppInfo webviewAppInfo = mPicker.createDefaultAppInfo(mActivity, mPackageManager,
                 mockPackageItemInfo, "" /* disabledReason */);
 
         PackageInfo packageInfo = new PackageInfo();