Merge "Show wifi status label in preference summary." into pi-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d0556d3..604a49f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -393,8 +393,12 @@
     <string name="bluetooth_paired_device_title">Your devices</string>
     <!-- Title for pairing bluetooth device page [CHAR LIMIT=none] -->
     <string name="bluetooth_pairing_page_title">Pair new device</string>
-    <!-- Summary for bluetooth item in connection detail page -->
-    <string name="bluetooth_pref_summary">Allow device to pair and connect to bluetooth devices</string>
+    <!-- Summary for bluetooth item in connection detail page. (tablet)-->
+    <string name="bluetooth_pref_summary" product="tablet">Allow your tablet to communicate with nearby Bluetooth devices</string>
+    <!-- Summary for bluetooth item in connection detail page. (device)-->
+    <string name="bluetooth_pref_summary" product="device">Allow your device to communicate with nearby Bluetooth devices</string>
+    <!-- Summary for bluetooth item in connection detail page. (phone)-->
+    <string name="bluetooth_pref_summary" product="default">Allow your phone to communicate with nearby Bluetooth devices</string>
 
     <!-- Setting Checkbox title for disabling Bluetooth inband ringing in Development Settings -->
     <string name="bluetooth_disable_inband_ringing">Disable in-band ringing</string>
@@ -412,7 +416,7 @@
     <!-- Title for preference to add a device [CHAR LIMIT=none]-->
     <string name="connected_device_add_device_title">Add device</string>
     <!-- Summary for preference to add a device [CHAR LIMIT=none]-->
-    <string name="connected_device_add_device_summary">Bluetooth will turn on to enable pairing</string>
+    <string name="connected_device_add_device_summary">Bluetooth will turn on to pair</string>
     <!-- Title for other connection preferences [CHAR LIMIT=none]-->
     <string name="connected_device_connections_title">Connection preferences</string>
     <!-- Title for Bluetooth preference to open paired but no connection list [CHAR LIMIT=none]-->
@@ -6619,7 +6623,7 @@
     <string name="help_url_bluetooth" translatable="false"></string>
     <!-- Help URL, Data usage [DO NOT TRANSLATE] -->
     <string name="help_url_data_usage" translatable="false"></string>
-    <!-- Help URL, Data saver [DO NOT TRANSLATE] -->
+    <!-- Help URL, Data Saver [DO NOT TRANSLATE] -->
     <string name="help_url_data_saver" translatable="false"></string>
     <!-- Help URL, Unrestricted data access [DO NOT TRANSLATE] -->
     <string name="help_url_unrestricted_data_access" translatable="false"></string>
@@ -7358,7 +7362,7 @@
     <string name="recent_notifications">Recently sent</string>
 
     <!-- Preference title for showing all apps on device [CHAR_LIMIT=50]-->
-    <string name="recent_notifications_see_all_title">See all apps</string>
+    <string name="recent_notifications_see_all_title">See all from last 7 days</string>
 
     <!-- Configure Notifications: Advanced section header [CHAR LIMIT=30] -->
     <string name="advanced_section_header">Advanced</string>
@@ -8843,6 +8847,9 @@
     <!-- Summary of condition that work mode is off [CHAR LIMIT=NONE] -->
     <string name="condition_work_summary">Apps, background sync, and other features related to your work profile are turned off.</string>
 
+    <!-- Action label on device muted card - clicking action will turn on ringtone sound [CHAR LIMIT=50] -->
+    <string name="condition_device_muted_action_turn_on_sound">Turn on sound</string>
+
     <!-- Title of condition that indicates device is muted [CHAR LIMIT=50] -->
     <string name="condition_device_muted_title" product="tablet">Device is muted</string>
 
@@ -9076,7 +9083,7 @@
     <string name="launch_mdp_app_text">View plan</string>
 
     <!-- Name of Data Saver screens [CHAR LIMIT=30] -->
-    <string name="data_saver_title">Data saver</string>
+    <string name="data_saver_title">Data Saver</string>
 
     <!-- Button that leads to list of apps with unrestricted data access [CHAR LIMIT=60] -->
     <string name="unrestricted_data_saver">Unrestricted data</string>
diff --git a/res/xml/date_time_prefs.xml b/res/xml/date_time_prefs.xml
index 3249189..511b39f 100644
--- a/res/xml/date_time_prefs.xml
+++ b/res/xml/date_time_prefs.xml
@@ -30,7 +30,6 @@
             android:summaryOn="@string/date_time_auto_summaryOn"
             android:summaryOff="@string/date_time_auto_summaryOff"
             settings:useAdditionalSummary="true"
-            settings:restrictedSwitchSummary="@string/enabled_by_admin"
             settings:userRestriction="no_config_date_time" />
 
         <com.android.settingslib.RestrictedPreference
diff --git a/res/xml/zen_mode_block_settings.xml b/res/xml/zen_mode_block_settings.xml
index ce33e97..595e2ca 100644
--- a/res/xml/zen_mode_block_settings.xml
+++ b/res/xml/zen_mode_block_settings.xml
@@ -17,7 +17,8 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:key="zen_mode_block_settings_page">
+    android:key="zen_mode_block_settings_page"
+    android:title="@string/zen_mode_behavior_settings_title">
 
     <!-- sound vibration -->
     <CheckBoxPreference
diff --git a/src/com/android/settings/accounts/RemoveAccountPreferenceController.java b/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
index 068847f..98ab504 100644
--- a/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
+++ b/src/com/android/settings/accounts/RemoveAccountPreferenceController.java
@@ -21,11 +21,11 @@
 import android.accounts.AccountManagerFuture;
 import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
-import android.app.admin.DevicePolicyManager;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.Fragment;
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -44,6 +44,8 @@
 import com.android.settings.core.PreferenceControllerMixin;
 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
 import com.android.settings.wrapper.DevicePolicyManagerWrapper;
+import com.android.settingslib.RestrictedLockUtils;
+import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 import com.android.settingslib.core.AbstractPreferenceController;
 
 import java.io.IOException;
@@ -92,12 +94,15 @@
 
     @Override
     public void onClick(View v) {
-        final Intent intent = mDpm.createAdminSupportIntent(UserManager.DISALLOW_MODIFY_ACCOUNTS);
-        if (intent != null) {
-            // DISALLOW_MODIFY_ACCOUNTS is active, show admin support dialog
-            mContext.startActivity(intent);
-            return;
+        if (mUserHandle != null) {
+            final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(mContext,
+                UserManager.DISALLOW_MODIFY_ACCOUNTS, mUserHandle.getIdentifier());
+            if (admin != null) {
+                RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, admin);
+                return;
+            }
         }
+
         ConfirmRemoveAccountDialog.show(mParentFragment, mAccount, mUserHandle);
     }
 
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index d144169..6521056 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.applications.manageapplications;
 
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry
         .FILTER_APPS_ALL;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry
@@ -50,6 +51,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.preference.PreferenceFrameLayout;
+import android.support.annotation.NonNull;
 import android.support.annotation.VisibleForTesting;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -844,11 +846,16 @@
         private boolean mHasReceivedBridgeCallback;
         private FileViewHolderController mExtraViewController;
 
-        // These two variables are used to remember and restore the last scroll position when this
+        // This is to remember and restore the last scroll position when this
         // 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;
 
+        @VisibleForTesting
+        OnScrollListener mOnScrollListener;
+        private RecyclerView mRecyclerView;
+
+
         public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications,
                 AppFilterItem appFilter, Bundle savedInstanceState) {
             setHasStableIds(true);
@@ -886,6 +893,22 @@
             }
         }
 
+        @Override
+        public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
+            super.onAttachedToRecyclerView(recyclerView);
+            mRecyclerView = recyclerView;
+            mOnScrollListener = new OnScrollListener(this);
+            mRecyclerView.addOnScrollListener(mOnScrollListener);
+        }
+
+        @Override
+        public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
+            super.onDetachedFromRecyclerView(recyclerView);
+            mRecyclerView.removeOnScrollListener(mOnScrollListener);
+            mOnScrollListener = null;
+            mRecyclerView = null;
+        }
+
         public void setCompositeFilter(AppFilter compositeFilter) {
             mCompositeFilter = compositeFilter;
             rebuild();
@@ -1180,9 +1203,8 @@
                     rebuild();
                     return;
                 } else {
-                    notifyItemChanged(i);
+                    mOnScrollListener.postNotifyItemChange(i);
                 }
-
             }
         }
 
@@ -1310,13 +1332,39 @@
             return mExtraViewController != null
                     && mExtraViewController.shouldShow();
         }
+
+        public static class OnScrollListener extends RecyclerView.OnScrollListener {
+            private int mScrollState = SCROLL_STATE_IDLE;
+            private boolean mDelayNotifyDataChange;
+            private ApplicationsAdapter mAdapter;
+
+            public OnScrollListener(ApplicationsAdapter adapter) {
+                mAdapter = adapter;
+            }
+
+            @Override
+            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
+                mScrollState = newState;
+                if (mScrollState == SCROLL_STATE_IDLE && mDelayNotifyDataChange) {
+                    mDelayNotifyDataChange = false;
+                    mAdapter.notifyDataSetChanged();
+                }
+            }
+
+            public void postNotifyItemChange(int index) {
+                if (mScrollState == SCROLL_STATE_IDLE) {
+                    mAdapter.notifyItemChanged(index);
+                } else {
+                    mDelayNotifyDataChange = true;
+                }
+            }
+        }
     }
 
     private static class SummaryProvider implements SummaryLoader.SummaryProvider {
 
         private final Context mContext;
         private final SummaryLoader mLoader;
-        private ApplicationsState.Session mSession;
 
         private SummaryProvider(Context context, SummaryLoader loader) {
             mContext = context;
diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java
index 879a4b8..937e6db 100644
--- a/src/com/android/settings/dashboard/DashboardAdapter.java
+++ b/src/com/android/settings/dashboard/DashboardAdapter.java
@@ -18,7 +18,6 @@
 import android.app.Activity;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.service.settings.suggestions.Suggestion;
 import android.support.annotation.VisibleForTesting;
@@ -262,7 +261,7 @@
 
     @VisibleForTesting
     void onBindConditionHeader(final ConditionHeaderHolder holder, ConditionHeaderData data) {
-        holder.icon.setImageIcon(data.conditionIcons.get(0));
+        holder.icon.setImageDrawable(data.conditionIcons.get(0));
         if (data.conditionCount == 1) {
             holder.title.setText(data.title);
             holder.summary.setText(null);
@@ -338,7 +337,7 @@
         outState.putBoolean(STATE_CONDITION_EXPANDED, mDashboardData.isConditionExpanded());
     }
 
-    private void updateConditionIcons(List<Icon> icons, ViewGroup parent) {
+    private void updateConditionIcons(List<Drawable> icons, ViewGroup parent) {
         if (icons == null || icons.size() < 2) {
             parent.setVisibility(View.INVISIBLE);
             return;
@@ -348,7 +347,7 @@
         for (int i = 1, size = icons.size(); i < size; i++) {
             ImageView icon = (ImageView) inflater.inflate(
                     R.layout.condition_header_icon, parent, false);
-            icon.setImageIcon(icons.get(i));
+            icon.setImageDrawable(icons.get(i));
             parent.addView(icon);
         }
         parent.setVisibility(View.VISIBLE);
diff --git a/src/com/android/settings/dashboard/DashboardData.java b/src/com/android/settings/dashboard/DashboardData.java
index 113caba..b180dd7 100644
--- a/src/com/android/settings/dashboard/DashboardData.java
+++ b/src/com/android/settings/dashboard/DashboardData.java
@@ -16,7 +16,7 @@
 package com.android.settings.dashboard;
 
 import android.annotation.IntDef;
-import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
 import android.service.settings.suggestions.Suggestion;
 import android.support.annotation.VisibleForTesting;
 import android.support.v7.util.DiffUtil;
@@ -432,7 +432,7 @@
      * also be used to check the diff in DiffUtil.Callback
      */
     public static class ConditionHeaderData {
-        public final List<Icon> conditionIcons;
+        public final List<Drawable> conditionIcons;
         public final CharSequence title;
         public final int conditionCount;
 
diff --git a/src/com/android/settings/dashboard/conditional/AirplaneModeCondition.java b/src/com/android/settings/dashboard/conditional/AirplaneModeCondition.java
index c6002bd..448510f 100644
--- a/src/com/android/settings/dashboard/conditional/AirplaneModeCondition.java
+++ b/src/com/android/settings/dashboard/conditional/AirplaneModeCondition.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.net.ConnectivityManager;
 import android.provider.Settings;
@@ -58,8 +59,8 @@
     }
 
     @Override
-    public Icon getIcon() {
-        return Icon.createWithResource(mManager.getContext(), R.drawable.ic_airplane);
+    public Drawable getIcon() {
+        return mManager.getContext().getDrawable(R.drawable.ic_airplane);
     }
 
     @Override
diff --git a/src/com/android/settings/dashboard/conditional/BackgroundDataCondition.java b/src/com/android/settings/dashboard/conditional/BackgroundDataCondition.java
index 34172c2..a7e160f 100644
--- a/src/com/android/settings/dashboard/conditional/BackgroundDataCondition.java
+++ b/src/com/android/settings/dashboard/conditional/BackgroundDataCondition.java
@@ -16,7 +16,7 @@
 package com.android.settings.dashboard.conditional;
 
 import android.content.Intent;
-import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
 import android.net.NetworkPolicyManager;
 import android.util.FeatureFlagUtils;
 
@@ -37,8 +37,8 @@
     }
 
     @Override
-    public Icon getIcon() {
-        return Icon.createWithResource(mManager.getContext(), R.drawable.ic_data_saver);
+    public Drawable getIcon() {
+        return mManager.getContext().getDrawable(R.drawable.ic_data_saver);
     }
 
     @Override
@@ -53,7 +53,7 @@
 
     @Override
     public CharSequence[] getActions() {
-        return new CharSequence[] { mManager.getContext().getString(R.string.condition_turn_off) };
+        return new CharSequence[] {mManager.getContext().getString(R.string.condition_turn_off)};
     }
 
     @Override
diff --git a/src/com/android/settings/dashboard/conditional/BatterySaverCondition.java b/src/com/android/settings/dashboard/conditional/BatterySaverCondition.java
index d113578..f1962ef 100644
--- a/src/com/android/settings/dashboard/conditional/BatterySaverCondition.java
+++ b/src/com/android/settings/dashboard/conditional/BatterySaverCondition.java
@@ -16,12 +16,13 @@
 package com.android.settings.dashboard.conditional;
 
 import android.content.Intent;
-import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
 import android.os.PowerManager;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.fuelgauge.BatterySaverDrawable;
 import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings;
 import com.android.settingslib.fuelgauge.BatterySaverUtils;
 
@@ -37,8 +38,8 @@
     }
 
     @Override
-    public Icon getIcon() {
-        return Icon.createWithResource(mManager.getContext(), R.drawable.ic_settings_battery);
+    public Drawable getIcon() {
+        return new BatterySaverDrawable(mManager.getContext(), 0);
     }
 
     @Override
@@ -53,7 +54,7 @@
 
     @Override
     public CharSequence[] getActions() {
-        return new CharSequence[] { mManager.getContext().getString(R.string.condition_turn_off) };
+        return new CharSequence[] {mManager.getContext().getString(R.string.condition_turn_off)};
     }
 
     @Override
diff --git a/src/com/android/settings/dashboard/conditional/CellularDataCondition.java b/src/com/android/settings/dashboard/conditional/CellularDataCondition.java
index 112248c..bc0cbd5 100644
--- a/src/com/android/settings/dashboard/conditional/CellularDataCondition.java
+++ b/src/com/android/settings/dashboard/conditional/CellularDataCondition.java
@@ -14,9 +14,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
 import android.net.ConnectivityManager;
 import android.telephony.TelephonyManager;
+
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.settings.R;
@@ -58,8 +59,8 @@
     }
 
     @Override
-    public Icon getIcon() {
-        return Icon.createWithResource(mManager.getContext(), R.drawable.ic_cellular_off);
+    public Drawable getIcon() {
+        return mManager.getContext().getDrawable(R.drawable.ic_cellular_off);
     }
 
     @Override
diff --git a/src/com/android/settings/dashboard/conditional/Condition.java b/src/com/android/settings/dashboard/conditional/Condition.java
index d66440e..f2905b9 100644
--- a/src/com/android/settings/dashboard/conditional/Condition.java
+++ b/src/com/android/settings/dashboard/conditional/Condition.java
@@ -19,10 +19,10 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.IntentFilter;
-import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
 import android.os.PersistableBundle;
-
 import android.support.annotation.VisibleForTesting;
+
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.overlay.FeatureFactory;
 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -151,7 +151,7 @@
     public abstract int getMetricsConstant();
 
     // UI.
-    public abstract Icon getIcon();
+    public abstract Drawable getIcon();
     public abstract CharSequence getTitle();
     public abstract CharSequence getSummary();
     public abstract CharSequence[] getActions();
diff --git a/src/com/android/settings/dashboard/conditional/ConditionAdapter.java b/src/com/android/settings/dashboard/conditional/ConditionAdapter.java
index a540b3f..a656cc7 100644
--- a/src/com/android/settings/dashboard/conditional/ConditionAdapter.java
+++ b/src/com/android/settings/dashboard/conditional/ConditionAdapter.java
@@ -50,8 +50,8 @@
             //TODO: get rid of setTag/getTag
             Condition condition = (Condition) v.getTag();
             mMetricsFeatureProvider.action(mContext,
-                MetricsEvent.ACTION_SETTINGS_CONDITION_CLICK,
-                condition.getMetricsConstant());
+                    MetricsEvent.ACTION_SETTINGS_CONDITION_CLICK,
+                    condition.getMetricsConstant());
             condition.onPrimaryClick();
         }
     };
@@ -108,7 +108,7 @@
     @Override
     public void onBindViewHolder(DashboardItemHolder holder, int position) {
         bindViews(mConditions.get(position), holder,
-            position == mConditions.size() - 1, mConditionClickListener);
+                position == mConditions.size() - 1, mConditionClickListener);
     }
 
     @Override
@@ -145,7 +145,7 @@
         View card = view.itemView.findViewById(R.id.content);
         card.setTag(condition);
         card.setOnClickListener(onClickListener);
-        view.icon.setImageIcon(condition.getIcon());
+        view.icon.setImageDrawable(condition.getIcon());
         view.title.setText(condition.getTitle());
 
         CharSequence[] actions = condition.getActions();
diff --git a/src/com/android/settings/dashboard/conditional/DndCondition.java b/src/com/android/settings/dashboard/conditional/DndCondition.java
index 673dccc..3112d48 100644
--- a/src/com/android/settings/dashboard/conditional/DndCondition.java
+++ b/src/com/android/settings/dashboard/conditional/DndCondition.java
@@ -20,7 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
 import android.os.PersistableBundle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
@@ -81,8 +81,8 @@
     }
 
     @Override
-    public Icon getIcon() {
-        return Icon.createWithResource(mManager.getContext(), R.drawable.ic_zen);
+    public Drawable getIcon() {
+        return mManager.getContext().getDrawable(R.drawable.ic_zen);
     }
 
     @Override
diff --git a/src/com/android/settings/dashboard/conditional/HotspotCondition.java b/src/com/android/settings/dashboard/conditional/HotspotCondition.java
index c62b0a4..53e0c07 100644
--- a/src/com/android/settings/dashboard/conditional/HotspotCondition.java
+++ b/src/com/android/settings/dashboard/conditional/HotspotCondition.java
@@ -19,7 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
@@ -64,8 +64,8 @@
     }
 
     @Override
-    public Icon getIcon() {
-        return Icon.createWithResource(mManager.getContext(), R.drawable.ic_hotspot);
+    public Drawable getIcon() {
+        return mManager.getContext().getDrawable(R.drawable.ic_hotspot);
     }
 
     private String getSsid() {
diff --git a/src/com/android/settings/dashboard/conditional/NightDisplayCondition.java b/src/com/android/settings/dashboard/conditional/NightDisplayCondition.java
index 9cb8605..78278b5 100644
--- a/src/com/android/settings/dashboard/conditional/NightDisplayCondition.java
+++ b/src/com/android/settings/dashboard/conditional/NightDisplayCondition.java
@@ -17,7 +17,7 @@
 package com.android.settings.dashboard.conditional;
 
 import android.content.Intent;
-import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
 
 import com.android.internal.app.ColorDisplayController;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -42,8 +42,8 @@
     }
 
     @Override
-    public Icon getIcon() {
-        return Icon.createWithResource(mManager.getContext(), R.drawable.ic_settings_night_display);
+    public Drawable getIcon() {
+        return mManager.getContext().getDrawable(R.drawable.ic_settings_night_display);
     }
 
     @Override
@@ -58,7 +58,7 @@
 
     @Override
     public CharSequence[] getActions() {
-        return new CharSequence[] { mManager.getContext().getString(R.string.condition_turn_off) };
+        return new CharSequence[] {mManager.getContext().getString(R.string.condition_turn_off)};
     }
 
     @Override
diff --git a/src/com/android/settings/dashboard/conditional/WorkModeCondition.java b/src/com/android/settings/dashboard/conditional/WorkModeCondition.java
index cb1b60a..941d5b0 100644
--- a/src/com/android/settings/dashboard/conditional/WorkModeCondition.java
+++ b/src/com/android/settings/dashboard/conditional/WorkModeCondition.java
@@ -19,7 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.UserInfo;
-import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.os.UserManager;
 
@@ -60,9 +60,8 @@
     }
 
     @Override
-    public Icon getIcon() {
-        return Icon.createWithResource(mManager.getContext(),
-                R.drawable.ic_signal_workmode_enable);
+    public Drawable getIcon() {
+        return mManager.getContext().getDrawable(R.drawable.ic_signal_workmode_enable);
     }
 
     @Override
diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java
index 25ab330..ccfcff1 100644
--- a/src/com/android/settings/datausage/DataUsageSummary.java
+++ b/src/com/android/settings/datausage/DataUsageSummary.java
@@ -20,7 +20,6 @@
 import android.content.Intent;
 import android.net.NetworkTemplate;
 import android.os.Bundle;
-import android.os.UserManager;
 import android.provider.SearchIndexableResource;
 import android.support.annotation.VisibleForTesting;
 import android.support.v7.preference.Preference;
@@ -35,21 +34,16 @@
 import android.text.TextUtils;
 import android.text.format.Formatter;
 import android.text.style.RelativeSizeSpan;
-import android.view.Menu;
-import android.view.MenuInflater;
 import android.view.MenuItem;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
-import com.android.settings.SettingsActivity;
 import com.android.settings.Utils;
 import com.android.settings.dashboard.SummaryLoader;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
-import com.android.settings.widget.EntityHeaderController;
 import com.android.settingslib.NetworkPolicyEditor;
 import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.net.DataUsageController;
 
 import java.util.ArrayList;
diff --git a/src/com/android/settings/datetime/timezone/BaseTimeZoneAdapter.java b/src/com/android/settings/datetime/timezone/BaseTimeZoneAdapter.java
index effa948..5a614a3 100644
--- a/src/com/android/settings/datetime/timezone/BaseTimeZoneAdapter.java
+++ b/src/com/android/settings/datetime/timezone/BaseTimeZoneAdapter.java
@@ -18,6 +18,7 @@
 
 import android.icu.text.BreakIterator;
 import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
 import android.support.annotation.WorkerThread;
 import android.support.v7.widget.RecyclerView;
 import android.text.TextUtils;
@@ -42,14 +43,14 @@
         extends RecyclerView.Adapter<BaseTimeZoneAdapter.ItemViewHolder> {
 
     private final List<T> mOriginalItems;
-    private final OnListItemClickListener mOnListItemClickListener;
+    private final OnListItemClickListener<T> mOnListItemClickListener;
     private final Locale mLocale;
     private final boolean mShowItemSummary;
 
     private List<T> mItems;
     private ArrayFilter mFilter;
 
-    public BaseTimeZoneAdapter(List<T> items, OnListItemClickListener
+    public BaseTimeZoneAdapter(List<T> items, OnListItemClickListener<T>
             onListItemClickListener, Locale locale, boolean showItemSummary) {
         mOriginalItems = items;
         mItems = items;
@@ -69,14 +70,8 @@
 
     @Override
     public void onBindViewHolder(@NonNull ItemViewHolder holder, int position) {
-        final AdapterItem item = mItems.get(position);
-        holder.mSummaryFrame.setVisibility(
-                mShowItemSummary ? View.VISIBLE : View.GONE);
-        holder.mTitleView.setText(item.getTitle());
-        holder.mIconTextView.setText(item.getIconText());
-        holder.mSummaryView.setText(item.getSummary());
-        holder.mTimeView.setText(item.getCurrentTime());
-        holder.setPosition(position);
+        holder.setAdapterItem(mItems.get(position));
+        holder.mSummaryFrame.setVisibility(mShowItemSummary ? View.VISIBLE : View.GONE);
     }
 
     @Override
@@ -89,8 +84,7 @@
         return mItems.size();
     }
 
-    public  @NonNull
-    Filter getFilter() {
+    public @NonNull ArrayFilter getFilter() {
         if (mFilter == null) {
             mFilter = new ArrayFilter();
         }
@@ -110,18 +104,18 @@
         String[] getSearchKeys();
     }
 
-    public static class ItemViewHolder extends RecyclerView.ViewHolder
-            implements View.OnClickListener{
+    public static class ItemViewHolder<T extends BaseTimeZoneAdapter.AdapterItem>
+            extends RecyclerView.ViewHolder implements View.OnClickListener {
 
-        final OnListItemClickListener mOnListItemClickListener;
+        final OnListItemClickListener<T> mOnListItemClickListener;
         final View mSummaryFrame;
         final TextView mTitleView;
         final TextView mIconTextView;
         final TextView mSummaryView;
         final TextView mTimeView;
-        private int mPosition;
+        private T mItem;
 
-        public ItemViewHolder(View itemView, OnListItemClickListener onListItemClickListener) {
+        public ItemViewHolder(View itemView, OnListItemClickListener<T> onListItemClickListener) {
             super(itemView);
             itemView.setOnClickListener(this);
             mSummaryFrame = itemView.findViewById(R.id.summary_frame);
@@ -132,13 +126,17 @@
             mOnListItemClickListener = onListItemClickListener;
         }
 
-        public void setPosition(int position) {
-            mPosition = position;
+        public void setAdapterItem(T item) {
+            mItem = item;
+            mTitleView.setText(item.getTitle());
+            mIconTextView.setText(item.getIconText());
+            mSummaryView.setText(item.getSummary());
+            mTimeView.setText(item.getCurrentTime());
         }
 
         @Override
         public void onClick(View v) {
-            mOnListItemClickListener.onListItemClick(mPosition);
+            mOnListItemClickListener.onListItemClick(mItem);
         }
     }
 
@@ -151,7 +149,8 @@
      * require additional pre-processing. Potentially, a trie structure can be used to match
      * prefixes of the search keys.
      */
-    private class ArrayFilter extends Filter {
+    @VisibleForTesting
+    public class ArrayFilter extends Filter {
 
         private BreakIterator mBreakIterator = BreakIterator.getWordInstance(mLocale);
 
@@ -197,8 +196,9 @@
             return results;
         }
 
+        @VisibleForTesting
         @Override
-        protected void publishResults(CharSequence constraint, FilterResults results) {
+        public void publishResults(CharSequence constraint, FilterResults results) {
             mItems = (List<T>) results.values;
             notifyDataSetChanged();
         }
diff --git a/src/com/android/settings/datetime/timezone/BaseTimeZoneInfoPicker.java b/src/com/android/settings/datetime/timezone/BaseTimeZoneInfoPicker.java
index c1a3f8b..d734542 100644
--- a/src/com/android/settings/datetime/timezone/BaseTimeZoneInfoPicker.java
+++ b/src/com/android/settings/datetime/timezone/BaseTimeZoneInfoPicker.java
@@ -31,7 +31,6 @@
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
-import java.util.Objects;
 
 /**
  * Render a list of {@class TimeZoneInfo} into the list view in {@class BaseTimeZonePicker}
@@ -52,8 +51,8 @@
         return mAdapter;
     }
 
-    private void onListItemClick(int position) {
-        final TimeZoneInfo timeZoneInfo = mAdapter.getItem(position).mTimeZoneInfo;
+    private void onListItemClick(TimeZoneInfoItem item) {
+        final TimeZoneInfo timeZoneInfo = item.mTimeZoneInfo;
         getActivity().setResult(Activity.RESULT_OK, prepareResultData(timeZoneInfo));
         getActivity().finish();
     }
@@ -67,7 +66,7 @@
     protected static class ZoneAdapter extends BaseTimeZoneAdapter<TimeZoneInfoItem> {
 
         public ZoneAdapter(Context context, List<TimeZoneInfo> timeZones,
-                OnListItemClickListener onListItemClickListener, Locale locale) {
+                OnListItemClickListener<TimeZoneInfoItem> onListItemClickListener, Locale locale) {
             super(createTimeZoneInfoItems(context, timeZones, locale),
                     onListItemClickListener, locale,  true /* showItemSummary */);
         }
diff --git a/src/com/android/settings/datetime/timezone/BaseTimeZonePicker.java b/src/com/android/settings/datetime/timezone/BaseTimeZonePicker.java
index 032e2d2..5150045 100644
--- a/src/com/android/settings/datetime/timezone/BaseTimeZonePicker.java
+++ b/src/com/android/settings/datetime/timezone/BaseTimeZonePicker.java
@@ -17,6 +17,7 @@
 package com.android.settings.datetime.timezone;
 
 import android.os.Bundle;
+import android.support.annotation.VisibleForTesting;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.view.LayoutInflater;
@@ -161,8 +162,8 @@
         return false;
     }
 
-    public interface OnListItemClickListener {
-        void onListItemClick(int position);
+    public interface OnListItemClickListener<T extends BaseTimeZoneAdapter.AdapterItem> {
+        void onListItemClick(T item);
     }
 
 }
diff --git a/src/com/android/settings/datetime/timezone/RegionSearchPicker.java b/src/com/android/settings/datetime/timezone/RegionSearchPicker.java
index bb87e85..ca4e0bc 100644
--- a/src/com/android/settings/datetime/timezone/RegionSearchPicker.java
+++ b/src/com/android/settings/datetime/timezone/RegionSearchPicker.java
@@ -18,15 +18,16 @@
 
 import android.app.Activity;
 import android.content.Intent;
-import android.graphics.Paint;
 import android.icu.text.Collator;
 import android.icu.text.LocaleDisplayNames;
 import android.os.Bundle;
+import android.support.annotation.VisibleForTesting;
 import android.util.Log;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.datetime.timezone.BaseTimeZoneAdapter.AdapterItem;
 import com.android.settings.datetime.timezone.model.FilteredCountryTimeZones;
 import com.android.settings.datetime.timezone.model.TimeZoneData;
 
@@ -63,8 +64,8 @@
         return mAdapter;
     }
 
-    private void onListItemClick(int position) {
-        final String regionId = mAdapter.getItem(position).getId();
+    private void onListItemClick(RegionItem item) {
+        final String regionId = item.getId();
         final FilteredCountryTimeZones countryTimeZones = mTimeZoneData.lookupCountryTimeZones(
                 regionId);
         final Activity activity = getActivity();
@@ -119,7 +120,8 @@
         return new ArrayList<>(items);
     }
 
-    private static class RegionItem implements BaseTimeZoneAdapter.AdapterItem {
+    @VisibleForTesting
+    static class RegionItem implements AdapterItem {
 
         private final String mId;
         private final String mName;
diff --git a/src/com/android/settings/fingerprint/FingerprintUiHelper.java b/src/com/android/settings/fingerprint/FingerprintUiHelper.java
index 655ce26..4a67ecd 100644
--- a/src/com/android/settings/fingerprint/FingerprintUiHelper.java
+++ b/src/com/android/settings/fingerprint/FingerprintUiHelper.java
@@ -79,6 +79,10 @@
 
     @Override
     public void onAuthenticationError(int errMsgId, CharSequence errString) {
+        if (errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
+            // Only happens if we get preempted by another activity. Ignored.
+            return;
+        }
         showError(errString);
         setFingerprintIconVisibility(false);
     }
diff --git a/src/com/android/settings/fuelgauge/BatteryEntry.java b/src/com/android/settings/fuelgauge/BatteryEntry.java
index 7a18cd0..1733a6e 100644
--- a/src/com/android/settings/fuelgauge/BatteryEntry.java
+++ b/src/com/android/settings/fuelgauge/BatteryEntry.java
@@ -38,6 +38,7 @@
 
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Locale;
 
 /**
  * Wraps the power usage data of a BatterySipper with information about package name
@@ -55,6 +56,8 @@
     static final ArrayList<BatteryEntry> mRequestQueue = new ArrayList<BatteryEntry>();
     static Handler sHandler;
 
+    static Locale sCurrentLocale = null;
+
     static private class NameAndIconLoader extends Thread {
         private boolean mAbort = false;
 
@@ -227,6 +230,13 @@
     }
 
     void getQuickNameIconForUid(final int uid) {
+        // Locale sync to system config in Settings
+        final Locale locale = Locale.getDefault();
+        if (sCurrentLocale != locale) {
+            clearUidCache();
+            sCurrentLocale = locale;
+        }
+
         final String uidString = Integer.toString(uid);
         if (sUidCache.containsKey(uidString)) {
             UidToDetail utd = sUidCache.get(uidString);
diff --git a/src/com/android/settings/fuelgauge/BatterySaverDrawable.java b/src/com/android/settings/fuelgauge/BatterySaverDrawable.java
new file mode 100644
index 0000000..0d3008a
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/BatterySaverDrawable.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 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.fuelgauge;
+
+import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+
+import com.android.settingslib.Utils;
+import com.android.settingslib.graph.BatteryMeterDrawableBase;
+
+/**
+ * Drawable that shows a static battery saver icon - a full battery symbol and a plus sign.
+ */
+public class BatterySaverDrawable extends BatteryMeterDrawableBase {
+
+    private static final int MAX_BATTERY = 100;
+
+    public BatterySaverDrawable(Context context, int frameColor) {
+        super(context, frameColor);
+        // Show as full so it's always uniform color
+        setBatteryLevel(MAX_BATTERY);
+        setPowerSave(true);
+        setCharging(false);
+        setPowerSaveAsColorError(false);
+        final int tintColor = Utils.getColorAttr(context, android.R.attr.colorAccent);
+        setColorFilter(new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN));
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java
index d4e950c..ed2f6b6 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTip.java
@@ -112,7 +112,7 @@
                     metricsFeatureProvider.action(context,
                             MetricsProto.MetricsEvent.ACTION_APP_RESTRICTION_TIP_LIST,
                             appInfo.packageName,
-                            Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, anomalyType));
+                            Pair.create(MetricsProto.MetricsEvent.FIELD_ANOMALY_TYPE, anomalyType));
                 }
 
             }
diff --git a/src/com/android/settings/notification/NotificationAppPreference.java b/src/com/android/settings/notification/NotificationAppPreference.java
index a6bcdd6..e43c52b 100644
--- a/src/com/android/settings/notification/NotificationAppPreference.java
+++ b/src/com/android/settings/notification/NotificationAppPreference.java
@@ -17,35 +17,38 @@
 
 import android.content.Context;
 import android.support.v7.preference.PreferenceViewHolder;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.view.View;
-import android.widget.ProgressBar;
 import android.widget.Switch;
 
 import com.android.settings.R;
+import com.android.settings.widget.MasterSwitchPreference;
 import com.android.settingslib.RestrictedLockUtils;
-import com.android.settingslib.TwoTargetPreference;
 
 /**
  * Shows an app icon, title and summary. Has a second switch touch target.
  */
-public class NotificationAppPreference extends TwoTargetPreference {
+public class NotificationAppPreference extends MasterSwitchPreference {
 
-    private int mProgress;
-    private boolean mProgressVisible;
     private Switch mSwitch;
     private boolean mChecked;
     private boolean mEnableSwitch = true;
 
     public NotificationAppPreference(Context context) {
         super(context);
-        setLayoutResource(R.layout.preference_app);
     }
 
     public NotificationAppPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
-        setLayoutResource(R.layout.preference_app);
+    }
+
+    public NotificationAppPreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
+    public NotificationAppPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
     }
 
     @Override
@@ -53,26 +56,10 @@
         return R.layout.preference_widget_master_switch;
     }
 
-    public void setProgress(int amount) {
-        mProgress = amount;
-        mProgressVisible = true;
-        notifyChanged();
-    }
-
     @Override
     public void onBindViewHolder(PreferenceViewHolder view) {
         super.onBindViewHolder(view);
 
-        view.findViewById(R.id.summary_container)
-                .setVisibility(TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
-        final ProgressBar progress = (ProgressBar) view.findViewById(android.R.id.progress);
-        if (mProgressVisible) {
-            progress.setProgress(mProgress);
-            progress.setVisibility(View.VISIBLE);
-        } else {
-            progress.setVisibility(View.GONE);
-        }
-
         final View widgetView = view.findViewById(android.R.id.widget_frame);
         if (widgetView != null) {
             widgetView.setOnClickListener(new View.OnClickListener() {
diff --git a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java
index 6cc99f7..3867640 100644
--- a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java
+++ b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java
@@ -81,7 +81,6 @@
     private PreferenceCategory mCategory;
     private Preference mSeeAllPref;
     private Preference mDivider;
-    private boolean mHasRecentApps;
 
     static {
         SKIP_SYSTEM_PACKAGES.addAll(Arrays.asList(
@@ -142,20 +141,7 @@
     public void updateState(Preference preference) {
         super.updateState(preference);
         refreshUi(mCategory.getContext());
-        // Show total number of installed apps as See all's summary.
-        new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON,
-                new PackageManagerWrapper(mContext.getPackageManager())) {
-            @Override
-            protected void onCountComplete(int num) {
-                if (mHasRecentApps) {
-                    mSeeAllPref.setTitle(
-                            mContext.getString(R.string.recent_notifications_see_all_title));
-                } else {
-                    mSeeAllPref.setSummary(mContext.getString(R.string.apps_summary, num));
-                }
-            }
-        }.execute();
-
+        mSeeAllPref.setTitle(mContext.getString(R.string.recent_notifications_see_all_title));
     }
 
     @VisibleForTesting
@@ -163,10 +149,8 @@
         reloadData();
         final List<NotifyingApp> recentApps = getDisplayableRecentAppList();
         if (recentApps != null && !recentApps.isEmpty()) {
-            mHasRecentApps = true;
             displayRecentApps(prefContext, recentApps);
         } else {
-            mHasRecentApps = false;
             displayOnlyAllAppsLink();
         }
     }
@@ -228,7 +212,7 @@
             pref.setTitle(appEntry.label);
             pref.setIcon(mIconDrawableFactory.getBadgedIcon(appEntry.info));
             pref.setSummary(StringUtil.formatRelativeTime(mContext,
-                    System.currentTimeMillis() - app.getLastNotified(), false));
+                    System.currentTimeMillis() - app.getLastNotified(), true));
             pref.setOrder(i);
             Bundle args = new Bundle();
             args.putString(AppInfoBase.ARG_PACKAGE_NAME, pkgName);
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index 38fdbce..50cb40a 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -636,13 +636,15 @@
         }
 
         /**
-         * Validates PIN and returns the validation result.
+         * Validates PIN/Password and returns the validation result.
          *
          * @param password the raw password the user typed in
          * @return the validation result.
          */
         private int validatePassword(String password) {
             int errorCode = NO_ERROR;
+            final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
+
 
             if (password.length() < mPasswordMinLength) {
                 if (mPasswordMinLength > mPasswordMinLengthToFulfillAllPolicies) {
@@ -652,8 +654,14 @@
                 errorCode |= TOO_LONG;
             } else {
                 // The length requirements are fulfilled.
-                if (mRequestedQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX) {
+                final int dpmQuality = mLockPatternUtils.getRequestedPasswordQuality(mUserId);
+                if (dpmQuality == PASSWORD_QUALITY_NUMERIC_COMPLEX &&
+                        metrics.numeric == password.length()) {
                     // Check for repeated characters or sequences (e.g. '1234', '0000', '2468')
+                    // if DevicePolicyManager requires a complex numeric password. There can be
+                    // two cases in the UI: 1. User chooses to enroll a PIN, 2. User chooses to
+                    // enroll a password but enters a numeric-only pin. We should carry out the
+                    // sequence check in both cases.
                     final int sequence = PasswordMetrics.maxLengthSequence(password);
                     if (sequence > PasswordMetrics.MAX_ALLOWED_SEQUENCE) {
                         errorCode |= CONTAIN_SEQUENTIAL_DIGITS;
@@ -674,8 +682,6 @@
                 }
             }
 
-            final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password);
-
             // Ensure no non-digits if we are requesting numbers. This shouldn't be possible unless
             // user finds some way to bring up soft keyboard.
             if (mRequestedQuality == PASSWORD_QUALITY_NUMERIC
diff --git a/src/com/android/settings/wifi/CaptivePortalNetworkCallback.java b/src/com/android/settings/wifi/CaptivePortalNetworkCallback.java
new file mode 100644
index 0000000..9bcfba0
--- /dev/null
+++ b/src/com/android/settings/wifi/CaptivePortalNetworkCallback.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 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.wifi;
+
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+
+import com.android.internal.util.Preconditions;
+
+/** Listens for changes to NetworkCapabilities to update the ConnectedAccessPointPreference. */
+final class CaptivePortalNetworkCallback extends NetworkCallback {
+
+    private final ConnectedAccessPointPreference mConnectedApPreference;
+    private final Network mNetwork;
+
+    private boolean mIsCaptivePortal;
+
+    CaptivePortalNetworkCallback(
+            Network network, ConnectedAccessPointPreference connectedApPreference) {
+        mNetwork = Preconditions.checkNotNull(network);
+        mConnectedApPreference = Preconditions.checkNotNull(connectedApPreference);
+    }
+
+    @Override
+    public void onLost(Network network) {
+        if (mNetwork.equals(network)) {
+            mIsCaptivePortal = false;
+        }
+    }
+
+    @Override
+    public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
+        if (mNetwork.equals(network)) {
+            mIsCaptivePortal = WifiUtils.canSignIntoNetwork(networkCapabilities);
+            mConnectedApPreference.setCaptivePortal(mIsCaptivePortal);
+        }
+    }
+
+    /**
+     * Returns true if the supplied network and preference are not null and are the same as the
+     * originally supplied values.
+     */
+    public boolean isSameNetworkAndPreference(
+            Network network, ConnectedAccessPointPreference connectedApPreference) {
+        return mNetwork.equals(network) && mConnectedApPreference == connectedApPreference;
+    }
+
+    /**
+     * Returns true if the most recent update to the NetworkCapabilities indicates a captive portal
+     * network and the Network was not lost in the interim.
+     */
+    public boolean isCaptivePortal() {
+        return mIsCaptivePortal;
+    }
+
+    /** Returns the currently associated network. */
+    public Network getNetwork() {
+        return mNetwork;
+    }
+}
diff --git a/src/com/android/settings/wifi/ConnectedAccessPointPreference.java b/src/com/android/settings/wifi/ConnectedAccessPointPreference.java
index e9e1560..def48e0 100644
--- a/src/com/android/settings/wifi/ConnectedAccessPointPreference.java
+++ b/src/com/android/settings/wifi/ConnectedAccessPointPreference.java
@@ -31,15 +31,12 @@
 public class ConnectedAccessPointPreference extends AccessPointPreference implements
         View.OnClickListener {
 
-    private final CaptivePortalStatus mCaptivePortalStatus;
     private OnGearClickListener mOnGearClickListener;
-    private boolean mCaptivePortalNetwork;
+    private boolean mIsCaptivePortal;
 
     public ConnectedAccessPointPreference(AccessPoint accessPoint, Context context,
-            UserBadgeCache cache, @DrawableRes int iconResId, boolean forSavedNetworks,
-            CaptivePortalStatus captivePortalStatus) {
+            UserBadgeCache cache, @DrawableRes int iconResId, boolean forSavedNetworks) {
         super(accessPoint, context, cache, iconResId, forSavedNetworks);
-        mCaptivePortalStatus = captivePortalStatus;
     }
 
     @Override
@@ -51,9 +48,8 @@
     public void refresh() {
         super.refresh();
 
-        mCaptivePortalNetwork = mCaptivePortalStatus.isCaptivePortalNetwork();
-        setShowDivider(mCaptivePortalNetwork);
-        if (mCaptivePortalNetwork) {
+        setShowDivider(mIsCaptivePortal);
+        if (mIsCaptivePortal) {
             setSummary(R.string.wifi_tap_to_sign_in);
         }
     }
@@ -71,8 +67,8 @@
         gear.setOnClickListener(this);
 
         final View gearNoBg = holder.findViewById(R.id.settings_button_no_background);
-        gearNoBg.setVisibility(mCaptivePortalNetwork ? View.INVISIBLE : View.VISIBLE);
-        gear.setVisibility(mCaptivePortalNetwork ? View.VISIBLE : View.INVISIBLE);
+        gearNoBg.setVisibility(mIsCaptivePortal ? View.INVISIBLE : View.VISIBLE);
+        gear.setVisibility(mIsCaptivePortal ? View.VISIBLE : View.INVISIBLE);
     }
 
     @Override
@@ -84,11 +80,15 @@
         }
     }
 
+    public void setCaptivePortal(boolean isCaptivePortal) {
+        if (mIsCaptivePortal != isCaptivePortal) {
+            mIsCaptivePortal = isCaptivePortal;
+            refresh();
+        }
+    }
+
     public interface OnGearClickListener {
         void onGearClick(ConnectedAccessPointPreference p);
     }
 
-    public interface CaptivePortalStatus {
-        boolean isCaptivePortalNetwork();
-    }
 }
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 7c1b725..0f6a0bb 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.wifi;
 
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
 
 import android.annotation.NonNull;
@@ -27,14 +28,15 @@
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.net.Network;
-import android.net.NetworkCapabilities;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.State;
+import android.net.NetworkRequest;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
 import android.nfc.NfcAdapter;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.PowerManager;
 import android.provider.Settings;
 import android.support.annotation.VisibleForTesting;
@@ -124,6 +126,7 @@
     private WifiManager.ActionListener mConnectListener;
     private WifiManager.ActionListener mSaveListener;
     private WifiManager.ActionListener mForgetListener;
+    private CaptivePortalNetworkCallback mCaptivePortalNetworkCallback;
 
     /**
      * The state of {@link #isUiRestricted()} at {@link #onCreate(Bundle)}}. This is neccesary to
@@ -400,6 +403,7 @@
     public void onStop() {
         getView().removeCallbacks(mUpdateAccessPointsRunnable);
         getView().removeCallbacks(mHideProgressBarRunnable);
+        unregisterCaptivePortalNetworkCallback();
         super.onStop();
     }
 
@@ -786,11 +790,9 @@
 
     @NonNull
     private ConnectedAccessPointPreference createConnectedAccessPointPreference(
-            AccessPoint accessPoint,
-            ConnectedAccessPointPreference.CaptivePortalStatus captivePortalStatus) {
+            AccessPoint accessPoint) {
         return new ConnectedAccessPointPreference(accessPoint, getPrefContext(), mUserBadgeCache,
-                R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */,
-                captivePortalStatus);
+                R.drawable.ic_wifi_signal_0, false /* forSavedNetworks */);
     }
 
     /**
@@ -817,8 +819,9 @@
         }
 
         // Is the previous currently connected SSID different from the new one?
-        AccessPointPreference preference = (AccessPointPreference)
-            (mConnectedAccessPointPreferenceCategory.getPreference(0));
+        ConnectedAccessPointPreference preference =
+                (ConnectedAccessPointPreference)
+                        (mConnectedAccessPointPreferenceCategory.getPreference(0));
         // The AccessPoints need to be the same reference to ensure that updates are reflected
         // in the UI.
         if (preference.getAccessPoint() != connectedAp) {
@@ -829,8 +832,10 @@
 
         // Else same AP is connected, simply refresh the connected access point preference
         // (first and only access point in this category).
-        ((AccessPointPreference) mConnectedAccessPointPreferenceCategory.getPreference(0))
-                .refresh();
+        preference.refresh();
+        // Update any potential changes to the connected network and ensure that the callback is
+        // registered after an onStop lifecycle event.
+        registerCaptivePortalNetworkCallback(getCurrentWifiNetwork(), preference);
         return true;
     }
 
@@ -840,18 +845,19 @@
      */
     private void addConnectedAccessPointPreference(AccessPoint connectedAp) {
         final ConnectedAccessPointPreference pref =
-                createConnectedAccessPointPreference(
-                        connectedAp, this::isConnectedToCaptivePortalNetwork);
+                createConnectedAccessPointPreference(connectedAp);
+        registerCaptivePortalNetworkCallback(getCurrentWifiNetwork(), pref);
 
         // Launch details page or captive portal on click.
         pref.setOnPreferenceClickListener(
                 preference -> {
                     pref.getAccessPoint().saveWifiState(pref.getExtras());
-                    Network network = getConnectedWifiNetwork();
-                    if (isConnectedToCaptivePortalNetwork(network)) {
+                    if (mCaptivePortalNetworkCallback != null
+                            && mCaptivePortalNetworkCallback.isCaptivePortal()) {
                         ConnectivityManagerWrapper connectivityManagerWrapper =
                                 new ConnectivityManagerWrapper(mConnectivityManager);
-                        connectivityManagerWrapper.startCaptivePortalApp(network);
+                        connectivityManagerWrapper.startCaptivePortalApp(
+                                mCaptivePortalNetworkCallback.getNetwork());
                     } else {
                         launchNetworkDetailsFragment(pref);
                     }
@@ -874,6 +880,41 @@
         }
     }
 
+    private void registerCaptivePortalNetworkCallback(
+            Network wifiNetwork, ConnectedAccessPointPreference pref) {
+        if (wifiNetwork == null || pref == null) {
+            Log.w(TAG, "Network or Preference were null when registering callback.");
+            return;
+        }
+
+        if (mCaptivePortalNetworkCallback != null
+                && mCaptivePortalNetworkCallback.isSameNetworkAndPreference(wifiNetwork, pref)) {
+            return;
+        }
+
+        unregisterCaptivePortalNetworkCallback();
+
+        mCaptivePortalNetworkCallback = new CaptivePortalNetworkCallback(wifiNetwork, pref);
+        mConnectivityManager.registerNetworkCallback(
+                new NetworkRequest.Builder()
+                        .clearCapabilities()
+                        .addTransportType(TRANSPORT_WIFI)
+                        .build(),
+                mCaptivePortalNetworkCallback,
+                new Handler(Looper.getMainLooper()));
+    }
+
+    private void unregisterCaptivePortalNetworkCallback() {
+        if (mCaptivePortalNetworkCallback != null) {
+            try {
+                mConnectivityManager.unregisterNetworkCallback(mCaptivePortalNetworkCallback);
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Unregistering CaptivePortalNetworkCallback failed.", e);
+            }
+            mCaptivePortalNetworkCallback = null;
+        }
+    }
+
     private void launchNetworkDetailsFragment(ConnectedAccessPointPreference pref) {
         new SubSettingLauncher(getContext())
                 .setTitle(getContext().getString(R.string.pref_title_network_details))
@@ -883,38 +924,15 @@
                 .launch();
     }
 
-    private boolean isConnectedToCaptivePortalNetwork() {
-        return isConnectedToCaptivePortalNetwork(getConnectedWifiNetwork());
-    }
-
-    private boolean isConnectedToCaptivePortalNetwork(Network network) {
-        if (mConnectivityManager == null || network == null) {
-            return false;
-        }
-        return WifiUtils.canSignIntoNetwork(mConnectivityManager.getNetworkCapabilities(network));
-    }
-
-    private Network getConnectedWifiNetwork() {
-        if (mConnectivityManager != null) {
-            Network networks[] = mConnectivityManager.getAllNetworks();
-            if (networks != null) {
-                for (Network network : networks) {
-                    NetworkCapabilities capabilities =
-                            mConnectivityManager.getNetworkCapabilities(network);
-                    if (capabilities != null
-                            && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
-                        return network;
-                    }
-                }
-            }
-        }
-        return null;
+    private Network getCurrentWifiNetwork() {
+        return mWifiManager != null ? mWifiManager.getCurrentNetwork() : null;
     }
 
     /** Removes all preferences and hide the {@link #mConnectedAccessPointPreferenceCategory}. */
     private void removeConnectedAccessPointPreference() {
         mConnectedAccessPointPreferenceCategory.removeAll();
         mConnectedAccessPointPreferenceCategory.setVisible(false);
+        unregisterCaptivePortalNetworkCallback();
     }
 
     private void setAdditionalSettingsSummaries() {
diff --git a/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
index 6020277..3df7c9d 100644
--- a/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/RemoveAccountPreferenceControllerTest.java
@@ -32,8 +32,8 @@
 import android.app.Activity;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
+import android.content.ComponentName;
 import android.content.Context;
-import android.content.Intent;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.UserHandle;
@@ -48,8 +48,13 @@
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.testutils.shadow.ShadowAccountManager;
 import com.android.settings.testutils.shadow.ShadowContentResolver;
+import com.android.settings.testutils.shadow.ShadowDevicePolicyManager;
+import com.android.settings.testutils.shadow.ShadowUserManager;
 import com.android.settings.wrapper.DevicePolicyManagerWrapper;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -60,6 +65,11 @@
 import org.robolectric.shadows.ShadowApplication;
 
 @RunWith(SettingsRobolectricTestRunner.class)
+@Config(
+    shadows = {
+        ShadowUserManager.class,
+        ShadowDevicePolicyManager.class
+    })
 public class RemoveAccountPreferenceControllerTest {
 
     private static final String KEY_REMOVE_ACCOUNT = "remove_account";
@@ -125,8 +135,21 @@
     @Test
     public void onClick_shouldNotStartConfirmDialogWhenModifyAccountsIsDisallowed() {
         when(mFragment.isAdded()).thenReturn(true);
-        when(mDevicePolicyManager.createAdminSupportIntent(UserManager.DISALLOW_MODIFY_ACCOUNTS))
-            .thenReturn(new Intent());
+
+        final int userId = UserHandle.myUserId();
+        mController.init(new Account("test", "test"), UserHandle.of(userId));
+
+        List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>();
+        enforcingUsers.add(new UserManager.EnforcingUser(userId,
+            UserManager.RESTRICTION_SOURCE_DEVICE_OWNER));
+        ComponentName componentName = new ComponentName("test", "test");
+        // Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null.
+        ShadowUserManager.getShadow().setUserRestrictionSources(
+            UserManager.DISALLOW_MODIFY_ACCOUNTS,
+            UserHandle.of(userId),
+            enforcingUsers);
+        ShadowDevicePolicyManager.getShadow().setDeviceOwnerComponentOnAnyUser(componentName);
+
         mController.onClick(null);
 
         verify(mFragmentTransaction, never()).add(
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 f60c7b0..fb7b59d 100644
--- a/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/manageapplications/ManageApplicationsTest.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.applications.manageapplications;
 
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING;
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
 import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MAIN;
 import static com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NOTIFICATION;
@@ -229,6 +231,40 @@
         verify(loadingViewController).showContent(true /* animate */);
     }
 
+    @Test
+    public void notifyItemChange_recyclerViewIdle_shouldNotify() {
+        final RecyclerView recyclerView = mock(RecyclerView.class);
+        final ManageApplications.ApplicationsAdapter adapter =
+                spy(new ManageApplications.ApplicationsAdapter(mState,
+                        mock(ManageApplications.class),
+                        AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
+
+        adapter.onAttachedToRecyclerView(recyclerView);
+        adapter.mOnScrollListener.onScrollStateChanged(recyclerView, SCROLL_STATE_IDLE);
+        adapter.mOnScrollListener.postNotifyItemChange(0 /* index */);
+
+        verify(adapter).notifyItemChanged(0);
+    }
+
+    @Test
+    public void notifyItemChange_recyclerViewScrolling_shouldNotifyWhenIdle() {
+        final RecyclerView recyclerView = mock(RecyclerView.class);
+        final ManageApplications.ApplicationsAdapter adapter =
+                spy(new ManageApplications.ApplicationsAdapter(mState,
+                        mock(ManageApplications.class),
+                        AppFilterRegistry.getInstance().get(FILTER_APPS_ALL), new Bundle()));
+
+        adapter.onAttachedToRecyclerView(recyclerView);
+        adapter.mOnScrollListener.onScrollStateChanged(recyclerView, SCROLL_STATE_DRAGGING);
+        adapter.mOnScrollListener.postNotifyItemChange(0 /* index */);
+
+        verify(adapter, never()).notifyItemChanged(0);
+        verify(adapter, never()).notifyDataSetChanged();
+
+        adapter.mOnScrollListener.onScrollStateChanged(recyclerView, SCROLL_STATE_IDLE);
+        verify(adapter).notifyDataSetChanged();
+    }
+
     private void setUpOptionMenus() {
         when(mMenu.findItem(anyInt())).thenAnswer(invocation -> {
             final Object[] args = invocation.getArguments();
diff --git a/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java b/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java
index 0333ae0..6d56731 100644
--- a/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java
@@ -27,7 +27,7 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.IntentFilter;
-import android.graphics.drawable.Icon;
+import android.graphics.drawable.Drawable;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -120,7 +120,7 @@
         }
 
         @Override
-        public Icon getIcon() {
+        public Drawable getIcon() {
             return null;
         }
 
diff --git a/tests/robotests/src/com/android/settings/datetime/timezone/RegionSearchPickerTest.java b/tests/robotests/src/com/android/settings/datetime/timezone/RegionSearchPickerTest.java
index b2c7f03..8da9cbf 100644
--- a/tests/robotests/src/com/android/settings/datetime/timezone/RegionSearchPickerTest.java
+++ b/tests/robotests/src/com/android/settings/datetime/timezone/RegionSearchPickerTest.java
@@ -16,7 +16,20 @@
 
 package com.android.settings.datetime.timezone;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.widget.Filter;
+import android.widget.LinearLayout;
+
 import com.android.settings.datetime.timezone.BaseTimeZoneAdapter.AdapterItem;
+import com.android.settings.datetime.timezone.BaseTimeZoneAdapter.ItemViewHolder;
+import com.android.settings.datetime.timezone.RegionSearchPicker.RegionItem;
 import com.android.settings.datetime.timezone.model.TimeZoneData;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 
@@ -24,17 +37,23 @@
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 
-import static com.google.common.truth.Truth.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
 @RunWith(SettingsRobolectricTestRunner.class)
+@Config(shadows = {
+        RegionSearchPickerTest.ShadowBaseTimeZonePicker.class,
+        RegionSearchPickerTest.ShadowFragment.class,
+    }
+)
 public class RegionSearchPickerTest {
 
     @Test
@@ -44,16 +63,90 @@
         CountryZonesFinder finder = mock(CountryZonesFinder.class);
         when(finder.lookupAllCountryIsoCodes()).thenReturn(regionList);
 
-        RegionSearchPicker picker = new RegionSearchPicker() {
-            @Override
-            protected Locale getLocale() {
-                return Locale.US;
-            }
-        };
+        RegionSearchPicker picker = new RegionSearchPicker();
         BaseTimeZoneAdapter adapter = picker.createAdapter(new TimeZoneData(finder));
         assertEquals(1, adapter.getItemCount());
         AdapterItem item = adapter.getItem(0);
         assertEquals("United States", item.getTitle().toString());
         assertThat(Arrays.asList(item.getSearchKeys())).contains("United States");
     }
+
+    // Test RegionSearchPicker does not crash due to the wrong assumption that no view is clicked
+    // before all views are updated and after internal data structure is updated for text filtering.
+    // This test mocks the text filtering event and emit click event immediately
+    // http://b/75322108
+    @Test
+    public void clickItemView_duringRegionSearch_shouldNotCrash() {
+        List regionList = new ArrayList();
+        regionList.add("US");
+        CountryZonesFinder finder = mock(CountryZonesFinder.class);
+        when(finder.lookupAllCountryIsoCodes()).thenReturn(regionList);
+
+        // Prepare the picker and adapter
+        RegionSearchPicker picker = new RegionSearchPicker();
+        BaseTimeZoneAdapter<RegionItem> adapter = picker.createAdapter(new TimeZoneData(finder));
+        // Prepare and bind a new ItemViewHolder with United States
+        ItemViewHolder viewHolder = adapter.onCreateViewHolder(
+                new LinearLayout(RuntimeEnvironment.application), 0);
+        adapter.onBindViewHolder(viewHolder, 0);
+        assertEquals(1, adapter.getItemCount());
+
+        // Pretend to search for a unknown region and no result is found.
+        FilterWrapper filterWrapper = new FilterWrapper(adapter.getFilter());
+        filterWrapper.publishEmptyResult("Unknown region 1");
+
+        // Assert that the adapter should have been updated with no item
+        assertEquals(0, adapter.getItemCount());
+        viewHolder.itemView.performClick(); // This should not crash
+    }
+
+    // FilterResults is a protected inner class. Use FilterWrapper to create an empty FilterResults
+    // instance.
+    private static class FilterWrapper extends Filter {
+
+        private final BaseTimeZoneAdapter.ArrayFilter mFilter;
+
+        private FilterWrapper(BaseTimeZoneAdapter.ArrayFilter filter) {
+            mFilter = filter;
+        }
+
+        @Override
+        protected FilterResults performFiltering(CharSequence charSequence) {
+            return null;
+        }
+
+        private void publishEmptyResult(CharSequence charSequence) {
+            FilterResults filterResults = new FilterResults();
+            filterResults.count = 0;
+            filterResults.values = new ArrayList<>();
+            publishResults(charSequence, filterResults);
+        }
+
+        @Override
+        protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
+            mFilter.publishResults(charSequence, filterResults);
+        }
+    }
+
+    // Robolectric can't start android.app.Fragment with support library v4 resources. Pretend
+    // the fragment has started, and provide the objects in context here.
+    @Implements(BaseTimeZonePicker.class)
+    public static class ShadowBaseTimeZonePicker extends ShadowFragment {
+
+        @Implementation
+        protected Locale getLocale() {
+            return Locale.US;
+        }
+    }
+
+    @Implements(Fragment.class)
+    public static class ShadowFragment {
+
+        private Activity mActivity = Robolectric.setupActivity(Activity.class);
+
+        @Implementation
+        public final Activity getActivity() {
+            return mActivity;
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
index 21b1d29..b6be9ee 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryEntryTest.java
@@ -39,6 +39,8 @@
 import org.mockito.junit.MockitoRule;
 import org.robolectric.RobolectricTestRunner;
 
+import java.util.Locale;
+
 @RunWith(RobolectricTestRunner.class)
 public class BatteryEntryTest {
 
@@ -148,4 +150,17 @@
 
         assertThat(entry.extractPackagesFromSipper(entry.sipper)).isEqualTo(entry.sipper.mPackages);
     }
+
+    @Test
+    public void testUidCache_switchLocale_shouldCleanCache() {
+        BatteryEntry.stopRequestQueue();
+
+        Locale.setDefault(new Locale("en_US"));
+        BatteryEntry.sUidCache.put(Integer.toString(APP_UID), null);
+        assertThat(BatteryEntry.sUidCache).isNotEmpty();
+
+        Locale.setDefault(new Locale("zh_TW"));
+        createBatteryEntryForApp();
+        assertThat(BatteryEntry.sUidCache).isEmpty(); // check if cache is clear
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java
index 7fe617e..c23311b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/RestrictAppTipTest.java
@@ -172,11 +172,11 @@
         verify(mMetricsFeatureProvider).action(mContext,
                 MetricsProto.MetricsEvent.ACTION_APP_RESTRICTION_TIP_LIST,
                 PACKAGE_NAME,
-                Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, ANOMALY_WAKEUP));
+                Pair.create(MetricsProto.MetricsEvent.FIELD_ANOMALY_TYPE, ANOMALY_WAKEUP));
         verify(mMetricsFeatureProvider).action(mContext,
                 MetricsProto.MetricsEvent.ACTION_APP_RESTRICTION_TIP_LIST,
                 PACKAGE_NAME,
-                Pair.create(MetricsProto.MetricsEvent.FIELD_CONTEXT, ANOMALY_WAKELOCK));
+                Pair.create(MetricsProto.MetricsEvent.FIELD_ANOMALY_TYPE, ANOMALY_WAKELOCK));
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/notification/NotificationAppPreferenceTest.java b/tests/robotests/src/com/android/settings/notification/NotificationAppPreferenceTest.java
index 4ac7527..80780ac 100644
--- a/tests/robotests/src/com/android/settings/notification/NotificationAppPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/notification/NotificationAppPreferenceTest.java
@@ -211,28 +211,4 @@
 
         assertThat(toggle.getContentDescription()).isEqualTo(label);
     }
-
-    @Test
-    public void setSummary_showSummaryContainer() {
-        final NotificationAppPreference preference = new NotificationAppPreference(mContext);
-        View rootView = View.inflate(mContext, R.layout.preference_app, null /* parent */);
-        PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(rootView);
-        preference.setSummary("test");
-        preference.onBindViewHolder(holder);
-
-        assertThat(holder.findViewById(R.id.summary_container).getVisibility())
-                .isEqualTo(View.VISIBLE);
-    }
-
-    @Test
-    public void noSummary_hideSummaryContainer() {
-        final NotificationAppPreference preference = new NotificationAppPreference(mContext);
-        View rootView = View.inflate(mContext, R.layout.preference_app, null /* parent */);
-        PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(rootView);
-        preference.setSummary(null);
-        preference.onBindViewHolder(holder);
-
-        assertThat(holder.findViewById(R.id.summary_container).getVisibility())
-                .isEqualTo(View.GONE);
-    }
 }
diff --git a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java
index 13826b2..3447703 100644
--- a/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/RecentNotifyingAppsPreferenceControllerTest.java
@@ -290,7 +290,7 @@
 
         mController.displayPreference(mScreen);
 
-        verify(mCategory).addPreference(argThat(summaryMatches("0 minutes ago")));
+        verify(mCategory).addPreference(argThat(summaryMatches("Just now")));
     }
 
     private static ArgumentMatcher<Preference> summaryMatches(String expected) {
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
index 77daae0..7e2c3cc 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowDevicePolicyManager.java
@@ -5,12 +5,14 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
+import org.robolectric.shadow.api.Shadow;
 
 /**
  * This shadow if using {@link ShadowDevicePolicyManagerWrapper} is not possible.
@@ -19,6 +21,7 @@
 public class ShadowDevicePolicyManager extends org.robolectric.shadows.ShadowDevicePolicyManager {
     private Map<Integer, CharSequence> mSupportMessagesMap = new HashMap<>();
     private boolean mIsAdminActiveAsUser = false;
+    ComponentName mDeviceOwnerComponentName;
 
     public void setShortSupportMessageForUser(ComponentName admin, int userHandle, String message) {
         mSupportMessagesMap.put(Objects.hash(admin, userHandle), message);
@@ -38,4 +41,17 @@
     public void setIsAdminActiveAsUser(boolean active) {
         mIsAdminActiveAsUser = active;
     }
+
+    public static ShadowDevicePolicyManager getShadow() {
+        return (ShadowDevicePolicyManager) Shadow.extract(
+            RuntimeEnvironment.application.getSystemService(DevicePolicyManager.class));
+    }
+
+    public ComponentName getDeviceOwnerComponentOnAnyUser() {
+        return mDeviceOwnerComponentName;
+    }
+
+    public void setDeviceOwnerComponentOnAnyUser(ComponentName admin) {
+        mDeviceOwnerComponentName = admin;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/ConnectedAccessPointPreferenceTest.java b/tests/robotests/src/com/android/settings/wifi/ConnectedAccessPointPreferenceTest.java
index b9b29d2..452fe03 100644
--- a/tests/robotests/src/com/android/settings/wifi/ConnectedAccessPointPreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/ConnectedAccessPointPreferenceTest.java
@@ -17,6 +17,7 @@
 package com.android.settings.wifi;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -32,7 +33,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
-import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 
@@ -45,8 +45,6 @@
     private View mView;
     @Mock
     private ConnectedAccessPointPreference.OnGearClickListener mOnGearClickListener;
-    @Mock
-    private ConnectedAccessPointPreference.CaptivePortalStatus mCaptivePortalStatus;
     private Context mContext;
     private ConnectedAccessPointPreference mConnectedAccessPointPreference;
 
@@ -56,7 +54,7 @@
 
         mContext = RuntimeEnvironment.application;
         mConnectedAccessPointPreference = new ConnectedAccessPointPreference(mAccessPoint, mContext,
-                null, 0 /* iconResId */, false /* forSavedNetworks */, mCaptivePortalStatus);
+                null, 0 /* iconResId */, false /* forSavedNetworks */);
         mConnectedAccessPointPreference.setOnGearClickListener(mOnGearClickListener);
     }
 
@@ -78,15 +76,13 @@
 
     @Test
     public void testCaptivePortalStatus_isCaptivePortal_dividerDrawn() {
-        Mockito.when(mCaptivePortalStatus.isCaptivePortalNetwork()).thenReturn(true);
-        mConnectedAccessPointPreference.refresh();
+        mConnectedAccessPointPreference.setCaptivePortal(true);
         assertThat(mConnectedAccessPointPreference.shouldShowDivider()).isTrue();
     }
 
     @Test
     public void testCaptivePortalStatus_isNotCaptivePortal_dividerNotDrawn() {
-        Mockito.when(mCaptivePortalStatus.isCaptivePortalNetwork()).thenReturn(false);
-        mConnectedAccessPointPreference.refresh();
+        mConnectedAccessPointPreference.setCaptivePortal(false);
         assertThat(mConnectedAccessPointPreference.shouldShowDivider()).isFalse();
     }