Merge "Fix summary loader lifecycle" into nyc-dev
diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java
index 1a3c850..a992897 100644
--- a/src/com/android/settings/SettingsPreferenceFragment.java
+++ b/src/com/android/settings/SettingsPreferenceFragment.java
@@ -399,6 +399,10 @@
         }
     }
 
+    protected int getCachedCount() {
+        return mPreferenceCache.size();
+    }
+
     private void highlightPreference(String key) {
         final int position = canUseListViewForHighLighting(key);
         if (position >= 0) {
diff --git a/src/com/android/settings/applications/AppStatePowerBridge.java b/src/com/android/settings/applications/AppStatePowerBridge.java
index e25b9c9..16de600 100644
--- a/src/com/android/settings/applications/AppStatePowerBridge.java
+++ b/src/com/android/settings/applications/AppStatePowerBridge.java
@@ -56,7 +56,7 @@
     }
 
     public static final AppFilter FILTER_POWER_WHITELISTED = new CompoundFilter(
-            ApplicationsState.FILTER_PERSONAL_WITHOUT_DISABLED_UNTIL_USED, new AppFilter() {
+            ApplicationsState.FILTER_WITHOUT_DISABLED_UNTIL_USED, new AppFilter() {
         @Override
         public void init() {
         }
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 9de3f7a..7936cb9 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 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.*;
@@ -138,7 +139,7 @@
     // This is the string labels for the filter modes above, the order must be kept in sync.
     public static final int[] FILTER_LABELS = new int[]{
             R.string.high_power_filter_on, // High power whitelist, on
-            R.string.filter_all_apps,      // All apps label, but personal filter (for high power);
+            R.string.filter_all_apps,      // Without disabled until used
             R.string.filter_all_apps,      // All apps
             R.string.filter_enabled_apps,  // Enabled
             R.string.filter_apps_disabled, // Disabled
@@ -159,8 +160,8 @@
     public static final AppFilter[] FILTERS = new AppFilter[]{
             new CompoundFilter(AppStatePowerBridge.FILTER_POWER_WHITELISTED,
                     ApplicationsState.FILTER_ALL_ENABLED),     // High power whitelist, on
-            new CompoundFilter(ApplicationsState.FILTER_PERSONAL_WITHOUT_DISABLED_UNTIL_USED,
-                    ApplicationsState.FILTER_ALL_ENABLED),     // All apps label, but personal filter
+            new CompoundFilter(ApplicationsState.FILTER_WITHOUT_DISABLED_UNTIL_USED,
+                    ApplicationsState.FILTER_ALL_ENABLED),     // Without disabled until used
             ApplicationsState.FILTER_EVERYTHING,  // All apps
             ApplicationsState.FILTER_ALL_ENABLED, // Enabled
             ApplicationsState.FILTER_DISABLED,    // Disabled
@@ -901,9 +902,46 @@
                 // Don't have new list yet, but can continue using the old one.
                 return;
             }
+            if (mFilterMode == FILTER_APPS_POWER_WHITELIST ||
+                mFilterMode == FILTER_APPS_POWER_WHITELIST_ALL) {
+                entries = removeDuplicateIgnoringUser(entries);
+            }
             onRebuildComplete(entries);
         }
 
+
+        static private boolean packageNameEquals(PackageItemInfo info1, PackageItemInfo info2) {
+            if (info1 == null || info2 == null) {
+                return false;
+            }
+            if (info1.packageName == null || info2.packageName == null) {
+                return false;
+            }
+            return info1.packageName.equals(info2.packageName);
+        }
+
+        private ArrayList<ApplicationsState.AppEntry> removeDuplicateIgnoringUser(
+                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);
+
+            // assume appinfo of same package but different users are grouped together
+            PackageItemInfo lastInfo = null;
+            for (int i = 0; i < size; i++) {
+                AppEntry appEntry = entries.get(i);
+                PackageItemInfo info = appEntry.info;
+                if (!packageNameEquals(lastInfo, appEntry.info)) {
+                    returnEntries.add(appEntry);
+                }
+                lastInfo = info;
+            }
+            returnEntries.trimToSize();
+            return returnEntries;
+        }
+
         @Override
         public void onRebuildComplete(ArrayList<AppEntry> entries) {
             mBaseEntries = entries;
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 79ce204..78f9833 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -368,7 +368,8 @@
                 }
                 addedSome = true;
                 mAppListGroup.addPreference(pref);
-                if (mAppListGroup.getPreferenceCount() > (MAX_ITEMS_TO_LIST + 1)) {
+                if (mAppListGroup.getPreferenceCount() - getCachedCount()
+                        > (MAX_ITEMS_TO_LIST + 1)) {
                     break;
                 }
             }
@@ -391,8 +392,10 @@
             stats.add(new BatterySipper(type, null, use));
             use += 5;
         }
-        stats.add(new BatterySipper(DrainType.APP,
-                new FakeUid(Process.FIRST_APPLICATION_UID), use));
+        for (int i = 0; i < 100; i++) {
+            stats.add(new BatterySipper(DrainType.APP,
+                    new FakeUid(Process.FIRST_APPLICATION_UID + i), use));
+        }
         stats.add(new BatterySipper(DrainType.APP,
                 new FakeUid(0), use));
 
diff --git a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
index fb0a4d5..61e3b9d 100644
--- a/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
+++ b/src/com/android/settings/inputmethod/InputMethodAndLanguageSettings.java
@@ -262,7 +262,6 @@
             final TextServicesManager tsm = (TextServicesManager) getSystemService(
                     Context.TEXT_SERVICES_MANAGER_SERVICE);
             if (!tsm.isSpellCheckerEnabled()) {
-                spellChecker.setEnabled(false);
                 spellChecker.setSummary(R.string.switch_off_text);
             } else {
                 final SpellCheckerInfo sci = tsm.getCurrentSpellChecker();
diff --git a/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment2.java b/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment2.java
index 6916242..c0d67bb 100644
--- a/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment2.java
+++ b/src/com/android/settings/inputmethod/KeyboardLayoutPickerFragment2.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.inputmethod;
 
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
@@ -45,6 +46,7 @@
     private int mInputDeviceId = -1;
     private InputManager mIm;
     private InputMethodInfo mImi;
+    @Nullable
     private InputMethodSubtype mSubtype;
     private KeyboardLayout[] mKeyboardLayouts;
     private Map<Preference, KeyboardLayout> mPreferenceMap = new HashMap<>();
@@ -82,7 +84,7 @@
         mImi = activity.getIntent().getParcelableExtra(EXTRA_INPUT_METHOD_INFO);
         mSubtype = activity.getIntent().getParcelableExtra(EXTRA_INPUT_METHOD_SUBTYPE);
 
-        if (mInputDeviceIdentifier == null || mImi == null || mSubtype == null) {
+        if (mInputDeviceIdentifier == null || mImi == null) {
             activity.finish();
         }
 
diff --git a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
index cf8db7a..07bcf6a 100644
--- a/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
+++ b/src/com/android/settings/inputmethod/PhysicalKeyboardFragment.java
@@ -147,7 +147,7 @@
                 Preference pref = new Preference(getPrefContext(), null);
                 final InputMethodInfo imi = info.mImi;
                 final InputMethodSubtype imSubtype = info.mImSubtype;
-                if (imi != null && imSubtype != null) {
+                if (imi != null) {
                     pref.setTitle(getDisplayName(getContext(), imi, imSubtype));
                     KeyboardLayout layout = info.mLayout;
                     if (layout != null) {
@@ -214,9 +214,9 @@
     }
 
     private void showKeyboardLayoutScreen(
-            InputDeviceIdentifier inputDeviceIdentifier,
-            InputMethodInfo imi,
-            InputMethodSubtype imSubtype) {
+            @NonNull InputDeviceIdentifier inputDeviceIdentifier,
+            @NonNull InputMethodInfo imi,
+            @Nullable InputMethodSubtype imSubtype) {
         final Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setClass(getActivity(), Settings.KeyboardLayoutPickerActivity.class);
         intent.putExtra(KeyboardLayoutPickerFragment2.EXTRA_INPUT_DEVICE_IDENTIFIER,
@@ -272,12 +272,15 @@
     };
 
     @NonNull
-    static String getDisplayName(
+    static CharSequence getDisplayName(
             @NonNull Context context, @NonNull InputMethodInfo imi,
-            @NonNull InputMethodSubtype imSubtype) {
+            @Nullable InputMethodSubtype imSubtype) {
+        final CharSequence imeName = imi.loadLabel(context.getPackageManager());
+        if (imSubtype == null) {
+            return imeName;
+        }
         final CharSequence imSubtypeName = imSubtype.getDisplayName(
                 context, imi.getPackageName(), imi.getServiceInfo().applicationInfo);
-        final CharSequence imeName = imi.loadLabel(context.getPackageManager());
         return String.format(
                 context.getString(R.string.physical_device_title), imSubtypeName, imeName);
     }
@@ -330,8 +333,21 @@
             final InputManager im = getContext().getSystemService(InputManager.class);
             if (imm != null && im != null) {
                 for (InputMethodInfo imi : imm.getEnabledInputMethodList()) {
-                    for (InputMethodSubtype subtype : imm.getEnabledInputMethodSubtypeList(
-                            imi, true /* allowsImplicitlySelectedSubtypes */)) {
+                    final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(
+                            imi, true /* allowsImplicitlySelectedSubtypes */);
+                    if (subtypes.isEmpty()) {
+                        // Here we use null to indicate that this IME has no subtype.
+                        final InputMethodSubtype nullSubtype = null;
+                        final KeyboardLayout layout = im.getKeyboardLayoutForInputDevice(
+                                deviceInfo.mDeviceIdentifier, imi, nullSubtype);
+                        keyboardInfoList.add(new Keyboards.KeyboardInfo(imi, nullSubtype, layout));
+                        continue;
+                    }
+
+                    // If the IME supports subtypes, we pick up "keyboard" subtypes only.
+                    final int N = subtypes.size();
+                    for (int i = 0; i < N; ++i) {
+                        final InputMethodSubtype subtype = subtypes.get(i);
                         if (!IM_SUBTYPE_MODE_KEYBOARD.equalsIgnoreCase(subtype.getMode())) {
                             continue;
                         }
@@ -421,14 +437,14 @@
         public static final class KeyboardInfo {
             @NonNull
             public final InputMethodInfo mImi;
-            @NonNull
+            @Nullable
             public final InputMethodSubtype mImSubtype;
             @NonNull
             public final KeyboardLayout mLayout;
 
             public KeyboardInfo(
                     @NonNull final InputMethodInfo imi,
-                    @NonNull final InputMethodSubtype imSubtype,
+                    @Nullable final InputMethodSubtype imSubtype,
                     @NonNull final KeyboardLayout layout) {
                 mImi = imi;
                 mImSubtype = imSubtype;