Merge "Add BatteryInfo logging to settings" into oc-dr1-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e89016d..32e3548 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4662,23 +4662,30 @@
     <!-- Title for force stop dialog [CHAR LIMIT=30] -->
     <string name="dialog_stop_title">Stop app?</string>
     <!-- Message body for force stop dialog [CHAR LIMIT=NONE] -->
-    <string name="dialog_stop_message" product="default">Your phone can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> is keeping your phone awake.\n\nTo try to fix this issue, you can force stop the app.\n\nIf this keeps happening, you may need to uninstall the app to improve battery performance.</string>
+    <string name="dialog_stop_message" product="default">Your phone can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> is keeping your phone awake.\n\nTo try to fix this issue, you can stop the app.\n\nIf this keeps happening, you may need to uninstall the app to improve battery performance.</string>
     <!-- Message body for force stop dialog [CHAR LIMIT=NONE] -->
-    <string name="dialog_stop_message" product="tablet">Your tablet can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> is keeping your tablet awake.\n\nTo try to fix this issue, you can force stop the app.\n\nIf this keeps happening, you may need to uninstall the app to improve battery performance.</string>
+    <string name="dialog_stop_message" product="tablet">Your tablet can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> is keeping your tablet awake.\n\nTo try to fix this issue, you can stop the app.\n\nIf this keeps happening, you may need to uninstall the app to improve battery performance.</string>
     <!-- Message body for force stop dialog [CHAR LIMIT=NONE] -->
-    <string name="dialog_stop_message" product="device">Your device can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> is keeping your device awake.\n\nTo try to fix this issue, you can force stop the app.\n\nIf this keeps happening, you may need to uninstall the app to improve battery performance.</string>
+    <string name="dialog_stop_message" product="device">Your device can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> is keeping your device awake.\n\nTo try to fix this issue, you can stop the app.\n\nIf this keeps happening, you may need to uninstall the app to improve battery performance.</string>
+
+    <!-- Message body for force stop dialog [CHAR LIMIT=NONE] -->
+    <string name="dialog_stop_message_wakeup_alarm" product="default">Your phone can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps waking up your phone.\n\nTo try to fix this issue, you can stop <xliff:g id="app">%1$s</xliff:g>.\n\nIf this keeps happening, you may need to uninstall the app to improve battery performance.</string>
+    <!-- Message body for force stop dialog [CHAR LIMIT=NONE] -->
+    <string name="dialog_stop_message_wakeup_alarm" product="tablet">Your tablet can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps waking up your tablet.\n\nTo try to fix this issue, you can stop <xliff:g id="app">%1$s</xliff:g>.\n\nIf this keeps happening, you may need to uninstall the app to improve battery performance.</string>
+    <!-- Message body for force stop dialog [CHAR LIMIT=NONE] -->
+    <string name="dialog_stop_message_wakeup_alarm" product="device">Your device can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps waking up your device.\n\nTo try to fix this issue, you can stop <xliff:g id="app">%1$s</xliff:g>.\n\nIf this keeps happening, you may need to uninstall the app to improve battery performance.</string>
 
     <!-- Text for OK button in force stop dialog [CHAR LIMIT=30] -->
     <string name="dialog_stop_ok">Stop app</string>
 
     <!-- Title for background usage dialog [CHAR LIMIT=60] -->
-    <string name="dialog_background_check_title">Turn off background usage?</string>
+    <string name="dialog_background_check_title">Turn off background usage &amp; stop app?</string>
     <!-- Message body for background usage dialog [CHAR LIMIT=NONE] -->
-    <string name="dialog_background_check_message" product="default">Your phone can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps waking up your phone.\n\nTo address this issue, your phone can prevent this app from running in the background.</string>
+    <string name="dialog_background_check_message" product="default">Your phone can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps waking up your phone.\n\nTo try to fix this issue, you can stop <xliff:g id="app">%1$s</xliff:g> and prevent it from running in the background.</string>
     <!-- Message body for background usage dialog [CHAR LIMIT=NONE] -->
-    <string name="dialog_background_check_message" product="tablet">Your tablet can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps waking up your tablet.\n\nTo address this issue, your tablet can prevent this app from running in the background.</string>
+    <string name="dialog_background_check_message" product="tablet">Your tablet can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps waking up your tablet.\n\nTo try to fix this issue, you can stop <xliff:g id="app">%1$s</xliff:g> and prevent it from running in the background.</string>
     <!-- Message body for background usage dialog [CHAR LIMIT=NONE] -->
-    <string name="dialog_background_check_message" product="device">Your device can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps waking up your device.\n\nTo address this issue, your device can prevent this app from running in the background.</string>
+    <string name="dialog_background_check_message" product="device">Your device can\'t manage battery normally because <xliff:g id="app">%1$s</xliff:g> keeps waking up your device.\n\nTo try to fix this issue, you can stop <xliff:g id="app">%1$s</xliff:g> and prevent it from running in the background.</string>
     <!-- Text for OK button in background usage dialog [CHAR LIMIT=30] -->
     <string name="dialog_background_check_ok">Turn off</string>
 
diff --git a/res/xml/app_storage_settings.xml b/res/xml/app_storage_settings.xml
index 1c71bfa..b96afbf 100644
--- a/res/xml/app_storage_settings.xml
+++ b/res/xml/app_storage_settings.xml
@@ -41,7 +41,6 @@
 
     <PreferenceCategory
         android:key="storage_category"
-        android:layout="@layout/tall_preference_category"
         android:title="@string/app_info_storage_title"
         settings:allowDividerAbove="false"
         settings:allowDividerBelow="false">
diff --git a/src/com/android/settings/search/SearchFragment.java b/src/com/android/settings/search/SearchFragment.java
index 7fb7257..aec140a 100644
--- a/src/com/android/settings/search/SearchFragment.java
+++ b/src/com/android/settings/search/SearchFragment.java
@@ -183,10 +183,11 @@
         mSearchView.requestFocus();
 
         // Updating internal views inside SearchView was the easiest way to get this too look right.
-        // We null-check here so that tests pass since the robotests can't find the internal views.
-        TextView searchText = mSearchView.findViewById(com.android.internal.R.id.search_src_text);
-        if (searchText != null) {
-            searchText.setTextColor(getContext().getColorStateList(
+        // Instead of grabbing the TextView directly, we grab it as a view and do an instanceof
+        // check. This ensures if we return, say, a LinearLayout in the tests, they won't fail.
+        View searchText = mSearchView.findViewById(com.android.internal.R.id.search_src_text);
+        if (searchText instanceof TextView) {
+            ((TextView) searchText).setTextColor(getContext().getColorStateList(
                     com.android.internal.R.color.text_color_primary));
         }
         View editFrame = mSearchView.findViewById(com.android.internal.R.id.search_edit_frame);
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 5cb27f9..bef2e9a 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -725,6 +725,7 @@
         final boolean voiceCapable = Utils.isVoiceCapable(context);
         final ArrayList<Integer> missingIcons = new ArrayList<>();
         final ArrayList<UserPreference> userPreferences = new ArrayList<>();
+        int guestId = UserPreference.USERID_GUEST_DEFAULTS;
         userPreferences.add(mMePreference);
 
         for (UserInfo user : users) {
@@ -738,6 +739,7 @@
                 pref = mMePreference;
             } else if (user.isGuest()) {
                 // Skip over Guest. We add generic Guest settings after this loop
+                guestId = user.id;
                 continue;
             } else {
                 // With Telephony:
@@ -814,9 +816,23 @@
             userPreferences.add(pref);
             pref.setDisabledByAdmin(
                     mUserCaps.mDisallowAddUser ? mUserCaps.mEnforcedAdmin : null);
-            if (!pref.isDisabledByAdmin()) {
-                pref.setSelectable(false);
-            }
+            int finalGuestId = guestId;
+            pref.setOnPreferenceClickListener(preference -> {
+                int id = finalGuestId;
+                if (id == UserPreference.USERID_GUEST_DEFAULTS) {
+                    UserInfo guest = mUserManager.createGuest(
+                            getContext(), preference.getTitle().toString());
+                    if (guest != null) {
+                        id = guest.id;
+                    }
+                }
+                try {
+                    ActivityManager.getService().switchUser(id);
+                } catch (RemoteException e) {
+                    e.rethrowFromSystemServer();
+                }
+                return true;
+            });
         }
 
         // Sort list of users by serialNum
diff --git a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
index bf67565..ee4acd1 100644
--- a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
+++ b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java
@@ -127,17 +127,25 @@
         final List<AccessPoint> accessPoints =
                 WifiSavedConfigUtils.getAllConfigs(context, mWifiManager);
         Collections.sort(accessPoints, SAVED_NETWORK_COMPARATOR);
-        preferenceScreen.removeAll();
+        cacheRemoveAllPrefs(preferenceScreen);
 
         final int accessPointsSize = accessPoints.size();
-        for (int i = 0; i < accessPointsSize; ++i){
+        for (int i = 0; i < accessPointsSize; ++i) {
+            AccessPoint ap = accessPoints.get(i);
+            String key = AccessPointPreference.generatePreferenceKey(ap);
             LongPressAccessPointPreference preference =
-                    new LongPressAccessPointPreference(accessPoints.get(i), context,
-                            mUserBadgeCache, true, this);
-            preference.setIcon(null);
-            preferenceScreen.addPreference(preference);
+                    (LongPressAccessPointPreference) getCachedPreference(key);
+            if (preference == null) {
+                preference = new LongPressAccessPointPreference(
+                        ap, context, mUserBadgeCache, true, this);
+                preference.setKey(key);
+                preference.setIcon(null);
+                preferenceScreen.addPreference(preference);
+            }
         }
 
+        removeCachedPrefs(preferenceScreen);
+
         if(getPreferenceScreen().getPreferenceCount() < 1) {
             Log.w(TAG, "Saved networks activity loaded, but there are no saved networks!");
         }
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 0333f63..bd35851 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -43,7 +43,6 @@
 import android.support.annotation.VisibleForTesting;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceCategory;
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -749,10 +748,7 @@
             AccessPoint accessPoint = accessPoints.get(index);
             // Ignore access points that are out of range.
             if (accessPoint.isReachable()) {
-                String key = accessPoint.getBssid();
-                if (TextUtils.isEmpty(key)) {
-                    key = accessPoint.getSsidStr();
-                }
+                String key = AccessPointPreference.generatePreferenceKey(accessPoint);
                 hasAvailableAccessPoints = true;
                 LongPressAccessPointPreference pref =
                         (LongPressAccessPointPreference) getCachedPreference(key);
diff --git a/tests/robotests/src/com/android/settings/language/LanguageAndInputSettingsTest.java b/tests/robotests/src/com/android/settings/language/LanguageAndInputSettingsTest.java
index beece64..b4a4638 100644
--- a/tests/robotests/src/com/android/settings/language/LanguageAndInputSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/language/LanguageAndInputSettingsTest.java
@@ -21,6 +21,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.hardware.input.InputManager;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -191,10 +192,14 @@
     @Test
     public void testNonIndexableKeys_existInXmlLayout() {
         final Context context = spy(RuntimeEnvironment.application);
+        final Resources res = spy(RuntimeEnvironment.application.getResources());
         //(InputManager) context.getSystemService(Context.INPUT_SERVICE);
         InputManager manager = mock(InputManager.class);
         when(manager.getInputDeviceIds()).thenReturn(new int[]{});
         doReturn(manager).when(context).getSystemService(Context.INPUT_SERVICE);
+        doReturn(res).when(context).getResources();
+        doReturn(false).when(res)
+            .getBoolean(com.android.internal.R.bool.config_supportSystemNavigationKeys);
         final List<String> niks = LanguageAndInputSettings.SEARCH_INDEX_DATA_PROVIDER
                 .getNonIndexableKeys(context);
         final int xmlId = (new LanguageAndInputSettings()).getPreferenceScreenResId();
diff --git a/tests/unit/src/com/android/settings/wifi/WifiSettingsUiTest.java b/tests/unit/src/com/android/settings/wifi/WifiSettingsUiTest.java
index 640c884..a85d591 100644
--- a/tests/unit/src/com/android/settings/wifi/WifiSettingsUiTest.java
+++ b/tests/unit/src/com/android/settings/wifi/WifiSettingsUiTest.java
@@ -15,6 +15,24 @@
  */
 package com.android.settings.wifi;
 
+import static android.support.test.InstrumentationRegistry.getInstrumentation;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.Visibility.VISIBLE;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.startsWith;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import android.app.Activity;
 import android.app.Fragment;
 import android.content.Context;
@@ -31,6 +49,7 @@
 
 import com.android.settings.Settings.WifiSettingsActivity;
 import com.android.settingslib.wifi.AccessPoint;
+import com.android.settingslib.wifi.TestAccessPointBuilder;
 import com.android.settingslib.wifi.WifiTracker;
 import com.android.settingslib.wifi.WifiTracker.WifiListener;
 import com.android.settingslib.wifi.WifiTrackerFactory;
@@ -46,25 +65,6 @@
 
 import java.util.List;
 
-import static android.support.test.InstrumentationRegistry.getInstrumentation;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.Visibility.VISIBLE;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.startsWith;
-
-import static org.mockito.Mockito.atMost;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
 @RunWith(AndroidJUnit4.class)
 public class WifiSettingsUiTest {
 
@@ -242,4 +242,34 @@
         getInstrumentation().callActivityOnStart(activity);
         verify(mWifiTracker, atMost(1)).forceUpdate();
     }
+
+    @Test
+    public void changingSecurityStateOnApShouldNotCauseMultipleListItems() {
+        setWifiState(WifiManager.WIFI_STATE_ENABLED);
+        TestAccessPointBuilder builder = new TestAccessPointBuilder(mContext)
+                .setSsid(TEST_SSID).setSecurity(AccessPoint.SECURITY_NONE);
+        AccessPoint open = builder.build();
+
+        builder.setSecurity(AccessPoint.SECURITY_EAP);
+        AccessPoint eap = builder.build();
+
+        builder.setSecurity(AccessPoint.SECURITY_WEP);
+        AccessPoint wep = builder.build();
+
+        // Return a different security state each time getAccessPoints is invoked
+        when(mWifiTracker.getAccessPoints())
+                .thenReturn(Lists.newArrayList(open, eap))
+                .thenReturn(Lists.newArrayList(eap))
+                .thenReturn(Lists.newArrayList(wep));
+
+        launchActivity();
+
+        onView(withText(TEST_SSID)).check(matches(isDisplayed()));
+
+        mWifiListener.onAccessPointsChanged();
+        onView(withText(TEST_SSID)).check(matches(isDisplayed()));
+
+        mWifiListener.onAccessPointsChanged();
+        onView(withText(TEST_SSID)).check(matches(isDisplayed()));
+    }
 }