Merge "Force update APs when enabling wifi in WifiSettings." into oc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8535b2f..2d8e06a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3077,6 +3077,16 @@
             android:permission="android.permission.DUMP"
             android:enabled="@bool/config_has_help" />
 
+        <activity android:name=".applications.defaultapps.AutofillPickerActivity"
+                android:taskAffinity=""
+                android:noHistory="true">
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.REQUEST_SET_AUTOFILL_SERVICE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="package" />
+            </intent-filter>
+        </activity>
+
         <!-- This is the longest AndroidManifest.xml ever. -->
     </application>
 </manifest>
diff --git a/res/layout/app_details.xml b/res/layout/app_details.xml
index b05c0dc..c3ffe1a 100644
--- a/res/layout/app_details.xml
+++ b/res/layout/app_details.xml
@@ -112,9 +112,4 @@
 
     </RelativeLayout>
 
-    <!-- Drop shadow -->
-    <View android:layout_width="match_parent"
-          android:layout_height="5dp"
-          android:background="@drawable/action_bar_dropshadow"/>
-
 </LinearLayout>
\ No newline at end of file
diff --git a/res/layout/battery_header.xml b/res/layout/battery_header.xml
index 04ef74d..97cc016 100644
--- a/res/layout/battery_header.xml
+++ b/res/layout/battery_header.xml
@@ -46,8 +46,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_marginTop="12dp"
-            android:textAppearance="@android:style/TextAppearance.Material.Small"
-            android:text="@string/estimated_time_left"/>
+            android:textAppearance="@android:style/TextAppearance.Material.Small"/>
 
     </LinearLayout>
 
diff --git a/res/layout/connection_detail_pref.xml b/res/layout/connection_detail_pref.xml
index 15f1c77..182f2cb 100644
--- a/res/layout/connection_detail_pref.xml
+++ b/res/layout/connection_detail_pref.xml
@@ -43,6 +43,7 @@
         android:id="@android:id/title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:singleLine="false"
         android:paddingLeft="20dp"
         android:textAppearance="@android:style/TextAppearance.Material.Medium"
         android:textColor="@android:color/white"/>
diff --git a/res/layout/search_breadcrumb_view.xml b/res/layout/search_breadcrumb_view.xml
index a78b745..08a2651 100644
--- a/res/layout/search_breadcrumb_view.xml
+++ b/res/layout/search_breadcrumb_view.xml
@@ -20,7 +20,7 @@
     android:id="@+id/breadcrumb"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    android:paddingTop="8dp"
+    android:paddingTop="5dp"
     android:textAppearance="?android:attr/textAppearanceListItemSecondary"
     android:textColor="?android:attr/textColorSecondary"
-    android:ellipsize="marquee"/>
\ No newline at end of file
+    android:ellipsize="marquee"/>
diff --git a/res/layout/search_inline_switch_item.xml b/res/layout/search_inline_switch_item.xml
index 75943c4..526f9fd 100644
--- a/res/layout/search_inline_switch_item.xml
+++ b/res/layout/search_inline_switch_item.xml
@@ -46,9 +46,8 @@
             android:id="@android:id/summary"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
-            android:textColor="?android:attr/textColorSecondary"
-            android:maxLines="10"/>
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"/>
 
         <include layout="@layout/search_breadcrumb_view"/>
     </LinearLayout>
diff --git a/res/layout/search_intent_item.xml b/res/layout/search_intent_item.xml
index 31f7f26..98e2a9b 100644
--- a/res/layout/search_intent_item.xml
+++ b/res/layout/search_intent_item.xml
@@ -46,9 +46,8 @@
             android:id="@android:id/summary"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            android:singleLine="true"
             android:textAppearance="?android:attr/textAppearanceListItemSecondary"
-            android:textColor="?android:attr/textColorSecondary"
-            android:maxLines="3"
             android:ellipsize="marquee"/>
 
         <include layout="@layout/search_breadcrumb_view"/>
diff --git a/src/com/android/settings/ApnEditor.java b/src/com/android/settings/ApnEditor.java
index f97811c..f668957 100644
--- a/src/com/android/settings/ApnEditor.java
+++ b/src/com/android/settings/ApnEditor.java
@@ -788,9 +788,14 @@
      * Check the key fields' validity and save if valid.
      * @param force save even if the fields are not valid, if the app is
      *        being suspended
-     * @return true if the data was saved
+     * @return true if there's no error
      */
     private boolean validateAndSave(boolean force) {
+        // nothing to do if it's a read only APN
+        if (mReadOnlyApn) {
+            return true;
+        }
+
         String name = checkNotSet(mName.getText());
         String apn = checkNotSet(mApn.getText());
         String mcc = checkNotSet(mMcc.getText());
diff --git a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
index a2e9fe9..2c97e1a 100644
--- a/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
+++ b/src/com/android/settings/ConfirmDeviceCredentialBaseFragment.java
@@ -68,8 +68,6 @@
             PACKAGE + ".ConfirmCredentials.showWhenLocked";
 
     private FingerprintUiHelper mFingerprintHelper;
-    protected boolean mIsStrongAuthRequired;
-    private boolean mAllowFpAuthentication;
     protected boolean mReturnCredentials = false;
     protected Button mCancelButton;
     protected ImageView mFingerprintIcon;
@@ -83,8 +81,6 @@
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mAllowFpAuthentication = getActivity().getIntent().getBooleanExtra(
-                ALLOW_FP_AUTHENTICATION, false);
         mReturnCredentials = getActivity().getIntent().getBooleanExtra(
                 ChooseLockSettingsHelper.EXTRA_KEY_RETURN_CREDENTIALS, false);
         // Only take this argument into account if it belongs to the current profile.
@@ -133,23 +129,26 @@
     // credential. Otherwise, fingerprint can't unlock fbe/keystore through
     // verifyTiedProfileChallenge. In such case, we also wanna show the user message that
     // fingerprint is disabled due to device restart.
-    private boolean isFingerprintDisallowedByStrongAuth() {
+    protected boolean isFingerprintDisallowedByStrongAuth() {
         return !(mLockPatternUtils.isFingerprintAllowedForUser(mEffectiveUserId)
                 && mUserManager.isUserUnlocked(mUserId));
     }
 
+    private boolean isFingerprintAllowed() {
+        return !mReturnCredentials
+                && getActivity().getIntent().getBooleanExtra(ALLOW_FP_AUTHENTICATION, false)
+                && !isFingerprintDisallowedByStrongAuth()
+                && !isFingerprintDisabledByAdmin();
+    }
+
     @Override
     public void onResume() {
         super.onResume();
-        mIsStrongAuthRequired = isFingerprintDisallowedByStrongAuth();
-        mAllowFpAuthentication = getActivity().getIntent().getBooleanExtra(
-                        ALLOW_FP_AUTHENTICATION, false)
-                && !isFingerprintDisabledByAdmin() && !mReturnCredentials && !mIsStrongAuthRequired;
         refreshLockScreen();
     }
 
     protected void refreshLockScreen() {
-        if (mAllowFpAuthentication) {
+        if (isFingerprintAllowed()) {
             mFingerprintHelper.startListening();
         } else {
             if (mFingerprintHelper.isListening()) {
diff --git a/src/com/android/settings/ConfirmLockPassword.java b/src/com/android/settings/ConfirmLockPassword.java
index 5c86dcd..9a285f2 100644
--- a/src/com/android/settings/ConfirmLockPassword.java
+++ b/src/com/android/settings/ConfirmLockPassword.java
@@ -191,9 +191,10 @@
         }
 
         private int getDefaultDetails() {
+            boolean isStrongAuthRequired = isFingerprintDisallowedByStrongAuth();
             boolean isProfile = UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId);
             // Map boolean flags to an index by isStrongAuth << 2 + isProfile << 1 + isAlpha.
-            int index = ((mIsStrongAuthRequired ? 1 : 0) << 2) + ((isProfile ? 1 : 0) << 1)
+            int index = ((isStrongAuthRequired ? 1 : 0) << 2) + ((isProfile ? 1 : 0) << 1)
                     + (mIsAlpha ? 1 : 0);
             return DETAIL_TEXTS[index];
         }
@@ -443,6 +444,7 @@
                 checkForPendingIntent();
             } else {
                 if (timeoutMs > 0) {
+                    refreshLockScreen();
                     long deadline = mLockPatternUtils.setLockoutAttemptDeadline(
                             effectiveUserId, timeoutMs);
                     handleAttemptLockout(deadline);
diff --git a/src/com/android/settings/ConfirmLockPattern.java b/src/com/android/settings/ConfirmLockPattern.java
index 4b65163..56d92f1 100644
--- a/src/com/android/settings/ConfirmLockPattern.java
+++ b/src/com/android/settings/ConfirmLockPattern.java
@@ -236,12 +236,13 @@
         }
 
         private int getDefaultDetails() {
+            boolean isStrongAuthRequired = isFingerprintDisallowedByStrongAuth();
             if (UserManager.get(getActivity()).isManagedProfile(mEffectiveUserId)) {
-                return mIsStrongAuthRequired
+                return isStrongAuthRequired
                         ? R.string.lockpassword_strong_auth_required_reason_restart_work_pattern
                         : R.string.lockpassword_confirm_your_pattern_generic_profile;
             } else {
-                return mIsStrongAuthRequired
+                return isStrongAuthRequired
                         ? R.string.lockpassword_strong_auth_required_reason_restart_device_pattern
                         : R.string.lockpassword_confirm_your_pattern_generic;
             }
diff --git a/src/com/android/settings/SecuritySettings.java b/src/com/android/settings/SecuritySettings.java
index bdf9644..9a149c3 100644
--- a/src/com/android/settings/SecuritySettings.java
+++ b/src/com/android/settings/SecuritySettings.java
@@ -16,6 +16,9 @@
 
 package com.android.settings;
 
+import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
+import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -33,6 +36,7 @@
 import android.os.PersistableBundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageManager;
 import android.provider.SearchIndexableResource;
 import android.provider.Settings;
 import android.service.trust.TrustAgentService;
@@ -47,7 +51,6 @@
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.Log;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -72,17 +75,10 @@
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedPreference;
 import com.android.settingslib.drawer.CategoryKey;
-import com.android.settingslib.drawer.DashboardCategory;
-import com.android.settingslib.drawer.Tile;
-import com.android.settingslib.drawer.TileUtils;
 
 import java.util.ArrayList;
-import java.util.concurrent.Executors;
 import java.util.List;
 
-import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
 /**
  * Gesture lock pattern settings.
  */
@@ -622,6 +618,18 @@
     public boolean onPreferenceTreeClick(Preference preference) {
         final String key = preference.getKey();
         if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
+            // TODO(b/35930129): Remove once existing password can be passed into vold directly.
+            // Currently we need this logic to ensure that the QUIET_MODE is off for any work
+            // profile with unified challenge on FBE-enabled devices. Otherwise, vold would not be
+            // able to complete the operation due to the lack of (old) encryption key.
+            if (mProfileChallengeUserId != UserHandle.USER_NULL
+                    && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId)
+                    && StorageManager.isFileEncryptedNativeOnly()) {
+                if (Utils.startQuietModeDialogIfNecessary(this.getActivity(), mUm,
+                        mProfileChallengeUserId)) {
+                    return false;
+                }
+            }
             startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment",
                     R.string.lock_settings_picker_title, SET_OR_CHANGE_LOCK_METHOD_REQUEST, null);
         } else if (KEY_UNLOCK_SET_OR_CHANGE_PROFILE.equals(key)) {
diff --git a/src/com/android/settings/accounts/AccountPreferenceBase.java b/src/com/android/settings/accounts/AccountPreferenceBase.java
index 2ad21d9..7c3b54c 100644
--- a/src/com/android/settings/accounts/AccountPreferenceBase.java
+++ b/src/com/android/settings/accounts/AccountPreferenceBase.java
@@ -17,14 +17,10 @@
 
 package com.android.settings.accounts;
 
-import android.accounts.AuthenticatorDescription;
 import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.SyncStatusObserver;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.content.res.Resources.Theme;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
@@ -32,12 +28,10 @@
 import android.os.UserManager;
 import android.support.v7.preference.PreferenceScreen;
 import android.text.format.DateFormat;
-import android.text.format.DateUtils;
 import android.util.Log;
 
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.Utils;
-import com.android.settings.utils.LocalClassLoaderContextThemeWrapper;
 import com.android.settingslib.accounts.AuthenticatorHelper;
 
 import java.util.ArrayList;
diff --git a/src/com/android/settings/accounts/AccountSyncPreferenceController.java b/src/com/android/settings/accounts/AccountSyncPreferenceController.java
index 57d317b..0b095f7 100644
--- a/src/com/android/settings/accounts/AccountSyncPreferenceController.java
+++ b/src/com/android/settings/accounts/AccountSyncPreferenceController.java
@@ -25,6 +25,7 @@
 import android.support.v7.preference.Preference;
 
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.settings.R;
 import com.android.settings.Utils;
 import com.android.settings.core.PreferenceController;
 
@@ -53,8 +54,9 @@
         final Bundle args = new Bundle();
         args.putParcelable(AccountSyncSettings.ACCOUNT_KEY, mAccount);
         args.putParcelable(EXTRA_USER, mUserHandle);
-        Utils.startWithFragment(mContext, AccountSyncSettings.class.getName(), args, null, 0, -1,
-            mAccount.name, MetricsProto.MetricsEvent.ACCOUNT);
+        Utils.startWithFragment(mContext, AccountSyncSettings.class.getName(), args, null, 0,
+                R.string.account_sync_title, null, MetricsProto.MetricsEvent.ACCOUNT);
+
         return true;
     }
 
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 16621f4..c0d2dd8 100755
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -454,6 +454,10 @@
 
     @Override
     public void onPackageSizeChanged(String packageName) {
+        if (!TextUtils.equals(packageName, mPackageName)) {
+            Log.d(LOG_TAG, "Package change irrelevant, skipping");
+          return;
+        }
         refreshUi();
     }
 
diff --git a/src/com/android/settings/applications/defaultapps/AutofillPickerActivity.java b/src/com/android/settings/applications/defaultapps/AutofillPickerActivity.java
new file mode 100644
index 0000000..a173909
--- /dev/null
+++ b/src/com/android/settings/applications/defaultapps/AutofillPickerActivity.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package com.android.settings.applications.defaultapps;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+
+/**
+ * Standalone activity used to launch {@link DefaultAppPickerFragment} from a
+ * {@link android.provider.Settings#ACTION_REQUEST_SET_AUTOFILL_SERVICE} intent.
+ */
+public class AutofillPickerActivity extends SettingsActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        final Intent intent = getIntent();
+        final String packageName = intent.getData().getSchemeSpecificPart();
+        intent.putExtra(EXTRA_SHOW_FRAGMENT, DefaultAutofillPicker.class.getName());
+        intent.putExtra(EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.autofill_app);
+        intent.putExtra(DefaultAutofillPicker.EXTRA_PACKAGE_NAME, packageName);
+
+        super.onCreate(savedInstanceState);
+    }
+
+    @Override
+    protected boolean isValidFragment(String fragmentName) {
+        return super.isValidFragment(fragmentName)
+                || DefaultAutofillPicker.class.getName().equals(fragmentName);
+    }
+}
diff --git a/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java b/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java
index 8eb1fc6..037cddf 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.applications.defaultapps;
 
+import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -38,6 +39,8 @@
     static final String SETTING = Settings.Secure.AUTOFILL_SERVICE;
     static final Intent AUTOFILL_PROBE = new Intent(AutofillService.SERVICE_INTERFACE);
 
+    static final String EXTRA_PACKAGE_NAME = "package_name";
+
     @Override
     public int getMetricsCategory() {
         return MetricsProto.MetricsEvent.DEFAULT_AUTOFILL_PICKER;
@@ -79,11 +82,24 @@
     @Override
     protected boolean setDefaultKey(String key) {
         Settings.Secure.putString(getContext().getContentResolver(), SETTING, key);
+
+        // Check if activity was launched from Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE
+        // intent, and set proper result if so...
+        final Activity activity = getActivity();
+        if (activity != null) {
+            final String packageName = activity.getIntent().getStringExtra(EXTRA_PACKAGE_NAME);
+            if (packageName != null) {
+                final int result = key != null && key.startsWith(packageName) ? Activity.RESULT_OK
+                        : Activity.RESULT_CANCELED;
+                activity.setResult(result);
+                activity.finish();
+            }
+        }
         return true;
     }
 
     /**
-     * Provides Intent to setting activity for the specified auto-fill service.
+     * Provides Intent to setting activity for the specified autofill service.
      */
     static final class AutofillSettingIntentProvider implements SettingIntentProvider {
 
diff --git a/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java
index c071570..508d6c9 100644
--- a/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java
+++ b/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java
@@ -36,7 +36,7 @@
         implements OnSummaryChangeListener,
         LifecycleObserver, OnResume, OnPause, OnStart, OnStop {
 
-    private static final String KEY_TOGGLE_BLUETOOTH = "toggle_bluetooth";
+    public static final String KEY_TOGGLE_BLUETOOTH = "toggle_bluetooth";
 
     private LocalBluetoothManager mBluetoothManager;
     private MasterSwitchPreference mBtPreference;
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
index b12e849..aeb7efb 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
@@ -16,6 +16,7 @@
 package com.android.settings.connecteddevice;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.provider.SearchIndexableResource;
 
 import com.android.internal.logging.nano.MetricsProto;
@@ -85,5 +86,20 @@
                     sir.xmlResId = R.xml.connected_devices;
                     return Arrays.asList(sir);
                 }
+
+                @Override
+                public List<String> getNonIndexableKeys(Context context) {
+                    PackageManager pm = context.getPackageManager();
+                    final List<String> keys = new ArrayList<String>();
+
+                    if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
+                        keys.add(NfcPreferenceController.KEY_TOGGLE_NFC);
+                        keys.add(NfcPreferenceController.KEY_ANDROID_BEAM_SETTINGS);
+                    }
+                    if (!pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
+                        keys.add(BluetoothMasterSwitchPreferenceController.KEY_TOGGLE_BLUETOOTH);
+                    }
+                    return keys;
+                }
             };
-}
\ No newline at end of file
+}
diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionsChecks.java b/src/com/android/settings/dashboard/suggestions/SuggestionsChecks.java
index 1be2c68..bdd5c60 100644
--- a/src/com/android/settings/dashboard/suggestions/SuggestionsChecks.java
+++ b/src/com/android/settings/dashboard/suggestions/SuggestionsChecks.java
@@ -17,19 +17,13 @@
 package com.android.settings.dashboard.suggestions;
 
 import android.app.AutomaticZenRule;
-import android.app.IWallpaperManager;
-import android.app.IWallpaperManager.Stub;
-import android.app.IWallpaperManagerCallback;
 import android.app.KeyguardManager;
 import android.app.NotificationManager;
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.hardware.fingerprint.FingerprintManager;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
+import android.support.annotation.VisibleForTesting;
 
 import com.android.ims.ImsManager;
 import com.android.settings.Settings.FingerprintEnrollSuggestionActivity;
@@ -49,10 +43,14 @@
  */
 public class SuggestionsChecks {
 
+    private static final String TAG = "SuggestionsChecks";
     private final Context mContext;
 
+    private final WallpaperManagerWrapper mWallpaperManager;
+
     public SuggestionsChecks(Context context) {
         mContext = context.getApplicationContext();
+        mWallpaperManager = new WallpaperManagerWrapper(mContext);
     }
 
     public boolean isSuggestionComplete(Tile suggestion) {
@@ -76,7 +74,7 @@
         }
 
         SuggestionFeatureProvider provider =
-            FeatureFactory.getFactory(mContext).getSuggestionFeatureProvider(mContext);
+                FeatureFactory.getFactory(mContext).getSuggestionFeatureProvider(mContext);
         if (provider != null && provider.isPresent(className)) {
             return provider.isSuggestionCompleted(mContext);
         }
@@ -114,16 +112,9 @@
         return false;
     }
 
-    private boolean hasWallpaperSet() {
-        IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
-        IWallpaperManager service = Stub.asInterface(b);
-        try {
-            return !service.isSetWallpaperAllowed(mContext.getOpPackageName()) ||
-                    service.getWallpaper(mCallback, WallpaperManager.FLAG_SYSTEM,
-                            new Bundle(), mContext.getUserId()) != null;
-        } catch (RemoteException e) {
-        }
-        return false;
+    @VisibleForTesting
+    boolean hasWallpaperSet() {
+        return mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM) > 0;
     }
 
     private boolean isFingerprintEnabled() {
@@ -133,11 +124,4 @@
                 mContext.getUserId());
         return (dpmFlags & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) == 0;
     }
-
-    private final IWallpaperManagerCallback mCallback = new IWallpaperManagerCallback.Stub() {
-        @Override
-        public void onWallpaperChanged() throws RemoteException {
-             // Don't care.
-        }
-    };
 }
diff --git a/src/com/android/settings/dashboard/suggestions/WallpaperManagerWrapper.java b/src/com/android/settings/dashboard/suggestions/WallpaperManagerWrapper.java
new file mode 100644
index 0000000..9efe4fe
--- /dev/null
+++ b/src/com/android/settings/dashboard/suggestions/WallpaperManagerWrapper.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.dashboard.suggestions;
+
+import android.app.WallpaperManager;
+import android.content.Context;
+
+public class WallpaperManagerWrapper {
+
+    private final WallpaperManager mWallpaperManager;
+
+    public WallpaperManagerWrapper(Context context) {
+        mWallpaperManager = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
+    }
+
+    public int getWallpaperId(int which) {
+        return mWallpaperManager.getWallpaperId(which);
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
index ca0348c..c6337ce 100644
--- a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
@@ -98,7 +98,9 @@
             mVolume = mStorageManager.findVolumeByUuid(fsUuid);
         } else {
             final String volId = getArguments().getString(VolumeInfo.EXTRA_VOLUME_ID);
-            mVolume = mStorageManager.findVolumeById(volId);
+            if (volId != null) {
+                mVolume = mStorageManager.findVolumeById(volId);
+            }
         }
 
         if (!isVolumeValid()) {
@@ -129,6 +131,12 @@
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
+
+        // If the volume isn't valid, we are not scaffolded to set up a view.
+        if (!isVolumeValid()) {
+            return;
+        }
+
         final Resources resources = getResources();
         final int padding = resources.getDimensionPixelSize(
                 R.dimen.unmount_button_padding);
diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
index 31ca148..377ec1e 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
@@ -214,6 +214,15 @@
         mAppPreference = (StorageItemPreference) screen.findPreference(OTHER_APPS_KEY);
         mSystemPreference = (StorageItemPreference) screen.findPreference(SYSTEM_KEY);
         mFilePreference = (StorageItemPreference) screen.findPreference(FILES_KEY);
+
+        final VolumeInfo sharedVolume = mSvp.findEmulatedForPrivate(mVolume);
+        // If we don't have a shared volume for our internal storage (or the shared volume isn't
+        // mounted as readable for whatever reason), we should hide the File preference.
+        final boolean hideFilePreference =
+                (sharedVolume == null) || !sharedVolume.isMountedReadable();
+        if (hideFilePreference) {
+            screen.removePreference(mFilePreference);
+        }
     }
 
     public void onLoadFinished(StorageAsyncLoader.AppsStorageResult data) {
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index eede37a..0cbfd54 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -41,6 +41,7 @@
 import com.android.settings.applications.AppHeaderController;
 import com.android.settings.applications.LayoutPreference;
 import com.android.settings.core.PreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.enterprise.DevicePolicyManagerWrapper;
 import com.android.settings.enterprise.DevicePolicyManagerWrapperImpl;
 import com.android.settings.overlay.FeatureFactory;
@@ -56,7 +57,7 @@
  * 2. Battery related controls for app(i.e uninstall, force stop)
  *
  */
-public class AdvancedPowerUsageDetail extends PowerUsageBase implements
+public class AdvancedPowerUsageDetail extends DashboardFragment implements
         ButtonActionDialogFragment.AppButtonsDialogListener {
 
     public static final String TAG = "AdvancedPowerUsageDetail";
diff --git a/src/com/android/settings/fuelgauge/BatteryStatsHelperLoader.java b/src/com/android/settings/fuelgauge/BatteryStatsHelperLoader.java
new file mode 100644
index 0000000..b99519b
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/BatteryStatsHelperLoader.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge;
+
+import android.content.Context;
+import android.os.BatteryStats;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
+
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.utils.AsyncLoader;
+
+/**
+ * Loader to get new {@link BatteryStatsHelper} in the background
+ */
+public class BatteryStatsHelperLoader extends AsyncLoader<BatteryStatsHelper> {
+    @VisibleForTesting
+    UserManager mUserManager;
+    private Bundle mBundle;
+
+    public BatteryStatsHelperLoader(Context context, Bundle bundle) {
+        super(context);
+        mBundle = bundle;
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+    }
+
+    @Override
+    public BatteryStatsHelper loadInBackground() {
+        final BatteryStatsHelper statsHelper = new BatteryStatsHelper(getContext(), true);
+
+        initBatteryStatsHelper(statsHelper);
+        return statsHelper;
+    }
+
+    @Override
+    protected void onDiscardResult(BatteryStatsHelper result) {
+
+    }
+
+    @VisibleForTesting
+    void initBatteryStatsHelper(BatteryStatsHelper statsHelper) {
+        statsHelper.create(mBundle);
+        statsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, mUserManager.getUserProfiles());
+    }
+}
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index c8af4a0..dad7b59 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -102,7 +102,6 @@
         final long rawRealTimeUs = convertMsToUs(SystemClock.elapsedRealtime());
         final int foregroundTypes[] = {BatteryStats.Uid.PROCESS_STATE_TOP,
                 BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE,
-                BatteryStats.Uid.PROCESS_STATE_TOP_SLEEPING,
                 BatteryStats.Uid.PROCESS_STATE_FOREGROUND};
         Log.v(TAG, "package: " + mPackageManager.getNameForUid(uid.getUid()));
 
@@ -129,9 +128,8 @@
             final BatterySipper sipper = sippers.get(i);
             if (shouldHideSipper(sipper)) {
                 sippers.remove(i);
-                if (sipper.drainType != BatterySipper.DrainType.OVERCOUNTED
-                        && sipper.drainType != BatterySipper.DrainType.UNACCOUNTED) {
-                    // Don't add it if it is overcounted or unaccounted
+                if (sipper.drainType != BatterySipper.DrainType.OVERCOUNTED) {
+                    // Don't add it if it is overcounted
                     totalPowerMah += sipper.totalPowerMah;
                 }
             }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
index 28dfe1d..4ebff34 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java
@@ -69,8 +69,7 @@
             UsageType.UNACCOUNTED,
             UsageType.OVERCOUNTED};
 
-    @VisibleForTesting
-    BatteryUtils mBatteryUtils;
+    private BatteryUtils mBatteryUtils;
     private BatteryHistoryPreference mHistPref;
     private PreferenceGroup mUsageListGroup;
     private PowerUsageFeatureProvider mPowerUsageFeatureProvider;
@@ -126,7 +125,6 @@
     @Override
     public void onResume() {
         super.onResume();
-        refreshStats();
     }
 
     @Override
@@ -165,8 +163,11 @@
     }
 
     @Override
-    protected void refreshStats() {
-        super.refreshStats();
+    protected void refreshUi() {
+        final Context context = getContext();
+        if (context == null) {
+            return;
+        }
 
         updatePreference(mHistPref);
 
@@ -256,8 +257,10 @@
         final List<PowerUsageData> batteryDataList = new ArrayList<>(batteryDataMap.values());
         final int dischargeAmount = statusHelper.getStats().getDischargeAmount(STATUS_TYPE);
         final double totalPower = statusHelper.getTotalPower();
+        final double hiddenPower = calculateHiddenPower(batteryDataList);
         for (final PowerUsageData usageData : batteryDataList) {
-            usageData.percentage = (usageData.totalPowerMah / totalPower) * dischargeAmount;
+            usageData.percentage = mBatteryUtils.calculateBatteryPercent(usageData.totalPowerMah,
+                    totalPower, hiddenPower, dischargeAmount);
             updateUsageDataSummary(usageData, totalPower, dischargeAmount);
         }
 
@@ -268,6 +271,17 @@
     }
 
     @VisibleForTesting
+    double calculateHiddenPower(List<PowerUsageData> batteryDataList) {
+        for (final PowerUsageData usageData : batteryDataList) {
+            if (usageData.usageType == UsageType.UNACCOUNTED) {
+                return usageData.totalPowerMah;
+            }
+        }
+
+        return 0;
+    }
+
+    @VisibleForTesting
     void updateUsageDataSummary(PowerUsageData usageData, double totalPower, int dischargeAmount) {
         if (shouldHideSummary(usageData)) {
             return;
@@ -320,6 +334,10 @@
     void setUserManager(UserManager userManager) {
         mUserManager = userManager;
     }
+    @VisibleForTesting
+    void setBatteryUtils(BatteryUtils batteryUtils) {
+        mBatteryUtils = batteryUtils;
+    }
 
     /**
      * Class that contains data used in {@link PowerGaugePreference}.
diff --git a/src/com/android/settings/fuelgauge/PowerUsageBase.java b/src/com/android/settings/fuelgauge/PowerUsageBase.java
index 1d9a228..aee55d6 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageBase.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageBase.java
@@ -16,28 +16,23 @@
 package com.android.settings.fuelgauge;
 
 import android.app.Activity;
-import android.content.BroadcastReceiver;
+import android.app.LoaderManager;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.BatteryStats;
+import android.content.Loader;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
 import android.os.UserManager;
 import android.support.annotation.VisibleForTesting;
 import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
 
 import com.android.internal.os.BatteryStatsHelper;
-import com.android.settings.R;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.utils.AsyncLoader;
 
 /**
  * Common base class for things that need to show the battery usage graph.
  */
-public abstract class PowerUsageBase extends DashboardFragment {
+public abstract class PowerUsageBase extends DashboardFragment
+        implements LoaderManager.LoaderCallbacks<BatteryStatsHelper> {
 
     // +1 to allow ordering for PowerUsageSummary.
     @VisibleForTesting
@@ -62,27 +57,23 @@
 
         mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
         mBatteryBroadcastReceiver.setBatteryChangedListener(() -> {
-            if (!mHandler.hasMessages(MSG_REFRESH_STATS)) {
-                mHandler.sendEmptyMessageDelayed(MSG_REFRESH_STATS, 500);
-            }
+            getLoaderManager().restartLoader(0, null, this);
         });
+
+        getLoaderManager().initLoader(0, icicle, this);
     }
 
     @Override
     public void onStart() {
         super.onStart();
-        mStatsHelper.clearStats();
     }
 
     @Override
     public void onResume() {
         super.onResume();
+
         BatteryStatsHelper.dropFile(getActivity(), BatteryHistoryDetail.BATTERY_HISTORY_FILE);
         mBatteryBroadcastReceiver.register();
-        if (mHandler.hasMessages(MSG_REFRESH_STATS)) {
-            mHandler.removeMessages(MSG_REFRESH_STATS);
-            mStatsHelper.clearStats();
-        }
     }
 
     @Override
@@ -94,7 +85,6 @@
     @Override
     public void onStop() {
         super.onStop();
-        mHandler.removeMessages(MSG_REFRESH_STATS);
     }
 
     @Override
@@ -105,26 +95,27 @@
         }
     }
 
-    protected void refreshStats() {
-        mStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, mUm.getUserProfiles());
-    }
+    protected abstract void refreshUi();
 
     protected void updatePreference(BatteryHistoryPreference historyPref) {
         historyPref.setStats(mStatsHelper);
     }
 
-    static final int MSG_REFRESH_STATS = 100;
+    @Override
+    public Loader<BatteryStatsHelper> onCreateLoader(int id,
+            Bundle args) {
+        return new BatteryStatsHelperLoader(getContext(), args);
+    }
 
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_REFRESH_STATS:
-                    mStatsHelper.clearStats();
-                    refreshStats();
-                    break;
-            }
-        }
-    };
+    @Override
+    public void onLoadFinished(Loader<BatteryStatsHelper> loader,
+            BatteryStatsHelper statsHelper) {
+        mStatsHelper = statsHelper;
+        refreshUi();
+    }
 
+    @Override
+    public void onLoaderReset(Loader<BatteryStatsHelper> loader) {
+
+    }
 }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index 1bc67af..bcf830b 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -18,6 +18,8 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.graphics.drawable.Drawable;
 import android.os.BatteryStats;
 import android.os.Build;
@@ -142,7 +144,6 @@
     @Override
     public void onResume() {
         super.onResume();
-        refreshStats();
     }
 
     @Override
@@ -236,7 +237,7 @@
                 } else {
                     mStatsType = BatteryStats.STATS_SINCE_CHARGED;
                 }
-                refreshStats();
+                refreshUi();
                 return true;
             case MENU_HIGH_POWER_APPS:
                 Bundle args = new Bundle();
@@ -259,7 +260,7 @@
                 item.setTitle(mShowAllApps ? R.string.hide_extra_apps : R.string.show_all_apps);
                 metricsFeatureProvider.action(context,
                         MetricsEvent.ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE, mShowAllApps);
-                refreshStats();
+                refreshUi();
                 return true;
             default:
                 return super.onOptionsItemSelected(item);
@@ -396,15 +397,11 @@
         return results;
     }
 
-    protected void refreshStats() {
-        super.refreshStats();
-
-        BatteryInfo.getBatteryInfo(getContext(), new BatteryInfo.Callback() {
-            @Override
-            public void onBatteryInfoLoaded(BatteryInfo info) {
-                updateHeaderPreference(info);
-            }
-        });
+    protected void refreshUi() {
+        final Context context = getContext();
+        if (context == null) {
+            return;
+        }
 
         cacheRemoveAllPrefs(mAppListGroup);
         mAppListGroup.setOrderingAsAdded(false);
@@ -413,7 +410,13 @@
         final PowerProfile powerProfile = mStatsHelper.getPowerProfile();
         final BatteryStats stats = mStatsHelper.getStats();
         final double averagePower = powerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
-        final Context context = getContext();
+
+        final long elapsedRealtimeUs = SystemClock.elapsedRealtime() * 1000;
+        Intent batteryBroadcast = context.registerReceiver(null,
+                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+        BatteryInfo batteryInfo = BatteryInfo.getBatteryInfo(context, batteryBroadcast,
+                mStatsHelper.getStats(), elapsedRealtimeUs, false);
+        updateHeaderPreference(batteryInfo);
 
         final TypedValue value = new TypedValue();
         context.getTheme().resolveAttribute(android.R.attr.colorControlNormal, value, true);
diff --git a/src/com/android/settings/nfc/NfcPreferenceController.java b/src/com/android/settings/nfc/NfcPreferenceController.java
index 11e3e09..7164b5b 100644
--- a/src/com/android/settings/nfc/NfcPreferenceController.java
+++ b/src/com/android/settings/nfc/NfcPreferenceController.java
@@ -39,8 +39,8 @@
 public class NfcPreferenceController extends PreferenceController
         implements LifecycleObserver, OnResume, OnPause {
 
-    private static final String KEY_TOGGLE_NFC = "toggle_nfc";
-    private static final String KEY_ANDROID_BEAM_SETTINGS = "android_beam_settings";
+    public static final String KEY_TOGGLE_NFC = "toggle_nfc";
+    public static final String KEY_ANDROID_BEAM_SETTINGS = "android_beam_settings";
 
     private NfcEnabler mNfcEnabler;
     private NfcAdapter mNfcAdapter;
diff --git a/src/com/android/settings/notification/AppNotificationSettings.java b/src/com/android/settings/notification/AppNotificationSettings.java
index bcf9c3f..db5cf2f 100644
--- a/src/com/android/settings/notification/AppNotificationSettings.java
+++ b/src/com/android/settings/notification/AppNotificationSettings.java
@@ -19,6 +19,7 @@
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 
 import android.app.Activity;
 import android.app.NotificationChannel;
@@ -251,12 +252,14 @@
 
     private void setupImportanceToggle() {
         mImportanceToggle.setDisabledByAdmin(mSuspendedAppsAdmin);
-        mImportanceToggle.setChecked(mChannel.getImportance() >= IMPORTANCE_DEFAULT);
+        mImportanceToggle.setChecked(mChannel.getImportance() >= IMPORTANCE_DEFAULT
+                || mChannel.getImportance() == IMPORTANCE_UNSPECIFIED);
         mImportanceToggle.setOnPreferenceChangeListener(
                 new Preference.OnPreferenceChangeListener() {
             @Override
             public boolean onPreferenceChange(Preference preference, Object newValue) {
-                final int importance = ((Boolean) newValue ? IMPORTANCE_DEFAULT : IMPORTANCE_LOW);
+                final int importance =
+                        ((Boolean) newValue ? IMPORTANCE_UNSPECIFIED : IMPORTANCE_LOW);
                 mChannel.setImportance(importance);
                 mChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
                 mBackend.updateChannel(mPkg, mUid, mChannel);
diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java
index aee9dc2..b591d85 100644
--- a/src/com/android/settings/notification/ConfigureNotificationSettings.java
+++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java
@@ -17,21 +17,24 @@
 package com.android.settings.notification;
 
 import android.content.Context;
+import android.provider.SearchIndexableResource;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.core.PreferenceController;
+import com.android.settings.core.lifecycle.Lifecycle;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.gestures.SwipeToNotificationPreferenceController;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 public class ConfigureNotificationSettings extends DashboardFragment {
     private static final String TAG = "ConfigNotiSettings";
 
-    private LockScreenNotificationPreferenceController mLockScreenNotificationController;
-
     @Override
     public int getMetricsCategory() {
         return MetricsEvent.CONFIGURE_NOTIFICATION;
@@ -49,15 +52,42 @@
 
     @Override
     protected List<PreferenceController> getPreferenceControllers(Context context) {
+        return buildPreferenceControllers(context, getLifecycle());
+    }
+
+    private static List<PreferenceController> buildPreferenceControllers(Context context,
+            Lifecycle lifecycle) {
         final List<PreferenceController> controllers = new ArrayList<>();
         final PulseNotificationPreferenceController pulseController =
                 new PulseNotificationPreferenceController(context);
-        mLockScreenNotificationController = new LockScreenNotificationPreferenceController(context);
-        getLifecycle().addObserver(pulseController);
-        getLifecycle().addObserver(mLockScreenNotificationController);
-        controllers.add(new SwipeToNotificationPreferenceController(context, getLifecycle()));
+        final LockScreenNotificationPreferenceController lockScreenNotificationController =
+                new LockScreenNotificationPreferenceController(context);
+        if (lifecycle != null) {
+            lifecycle.addObserver(pulseController);
+            lifecycle.addObserver(lockScreenNotificationController);
+        }
+        controllers.add(new SwipeToNotificationPreferenceController(context, lifecycle));
         controllers.add(pulseController);
-        controllers.add(mLockScreenNotificationController);
+        controllers.add(lockScreenNotificationController);
         return controllers;
     }
+
+    /**
+     * For Search.
+     */
+    public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+            new BaseSearchIndexProvider() {
+                @Override
+                public List<SearchIndexableResource> getXmlResourcesToIndex(
+                        Context context, boolean enabled) {
+                    final SearchIndexableResource sir = new SearchIndexableResource(context);
+                    sir.xmlResId = R.xml.configure_notification_settings;
+                    return Arrays.asList(sir);
+                }
+
+                @Override
+                public List<PreferenceController> getPreferenceControllers(Context context) {
+                    return buildPreferenceControllers(context, null);
+                }
+            };
 }
diff --git a/src/com/android/settings/search/BaseSearchIndexProvider.java b/src/com/android/settings/search/BaseSearchIndexProvider.java
index 54f66ea..bda9319 100644
--- a/src/com/android/settings/search/BaseSearchIndexProvider.java
+++ b/src/com/android/settings/search/BaseSearchIndexProvider.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.XmlResourceParser;
 import android.provider.SearchIndexableResource;
+import android.support.annotation.CallSuper;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -57,6 +58,7 @@
     }
 
     @Override
+    @CallSuper
     public List<String> getNonIndexableKeys(Context context) {
         if (!isPageSearchEnabled(context)) {
             // Entire page should be suppressed, mark all keys from this page as non-indexable.
diff --git a/src/com/android/settings/search2/DatabaseIndexingManager.java b/src/com/android/settings/search2/DatabaseIndexingManager.java
index 533884d..ccc5283 100644
--- a/src/com/android/settings/search2/DatabaseIndexingManager.java
+++ b/src/com/android/settings/search2/DatabaseIndexingManager.java
@@ -515,7 +515,7 @@
             if (count > 0) {
                 while (cursor.moveToNext()) {
                     final int providerRank = cursor.getInt(COLUMN_INDEX_XML_RES_RANK);
-
+                    // TODO remove provider rank
                     final int xmlResId = cursor.getInt(COLUMN_INDEX_XML_RES_RESID);
 
                     final String className = cursor.getString(COLUMN_INDEX_XML_RES_CLASS_NAME);
@@ -560,7 +560,7 @@
             if (count > 0) {
                 while (cursor.moveToNext()) {
                     final int providerRank = cursor.getInt(COLUMN_INDEX_RAW_RANK);
-
+                    // TODO Remove rank
                     final String title = cursor.getString(COLUMN_INDEX_RAW_TITLE);
                     final String summaryOn = cursor.getString(COLUMN_INDEX_RAW_SUMMARY_ON);
                     final String summaryOff = cursor.getString(COLUMN_INDEX_RAW_SUMMARY_OFF);
@@ -749,7 +749,6 @@
                     .setEntries(null)
                     .setClassName(fragmentName)
                     .setScreenTitle(screenTitle)
-                    .setIconResId(iconResId)
                     .setRank(rank)
                     .setIntentAction(intentAction)
                     .setIntentTargetPackage(intentTargetPackage)
diff --git a/src/com/android/settings/search2/SearchFragment.java b/src/com/android/settings/search2/SearchFragment.java
index 8e1e1b4..c5db08d 100644
--- a/src/com/android/settings/search2/SearchFragment.java
+++ b/src/com/android/settings/search2/SearchFragment.java
@@ -168,6 +168,17 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        if (TextUtils.isEmpty(mQuery)) {
+            return;
+        }
+        final String query = mQuery;
+        mQuery = "";
+        onQueryTextChange(query);
+    }
+
+    @Override
     public void onStop() {
         super.onStop();
         final Activity activity = getActivity();
@@ -206,7 +217,6 @@
         mResultClickCount = 0;
         mNeverEnteredQuery = false;
         mQuery = query;
-        mSearchAdapter.clearResults();
 
         if (isEmptyQuery) {
             final LoaderManager loaderManager = getLoaderManager();
@@ -252,7 +262,13 @@
             return;
         }
         final int resultCount = mSearchAdapter.displaySearchResults();
-        mNoResultsView.setVisibility(resultCount == 0 ? View.VISIBLE : View.GONE);
+
+        if (resultCount == 0) {
+            mNoResultsView.setVisibility(View.VISIBLE);
+        } else {
+            mNoResultsView.setVisibility(View.GONE);
+            mResultsRecyclerView.scrollToPosition(0);
+        }
         mSearchFeatureProvider.showFeedbackButton(this, getView());
     }
 
diff --git a/src/com/android/settings/search2/SearchResult.java b/src/com/android/settings/search2/SearchResult.java
index 6b27d89..ecc41b6 100644
--- a/src/com/android/settings/search2/SearchResult.java
+++ b/src/com/android/settings/search2/SearchResult.java
@@ -93,7 +93,7 @@
         icon = builder.mIcon;
         payload = builder.mResultPayload;
         viewType = payload.getType();
-        stableId = Objects.hash(title, summary, breadcrumbs, rank, icon, payload, viewType);
+        stableId = Objects.hash(title, summary, breadcrumbs, rank, viewType);
     }
 
     @Override
@@ -104,6 +104,22 @@
         return this.rank - searchResult.rank;
     }
 
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof SearchResult)) {
+            return false;
+        }
+        return this.stableId == ((SearchResult) obj).stableId;
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) stableId;
+    }
+
     public static class Builder {
         protected CharSequence mTitle;
         protected CharSequence mSummary;
@@ -127,19 +143,19 @@
             return this;
         }
 
-        public Builder  addRank(int rank) {
+        public Builder addRank(int rank) {
             if (rank >= 0 && rank <= 9) {
                 mRank = rank;
             }
             return this;
         }
 
-        public Builder  addIcon(Drawable icon) {
+        public Builder addIcon(Drawable icon) {
             mIcon = icon;
             return this;
         }
 
-        public Builder  addPayload(ResultPayload payload) {
+        public Builder addPayload(ResultPayload payload) {
             mResultPayload = payload;
             return this;
         }
diff --git a/src/com/android/settings/search2/SearchResultDiffCallback.java b/src/com/android/settings/search2/SearchResultDiffCallback.java
new file mode 100644
index 0000000..9bd1bde
--- /dev/null
+++ b/src/com/android/settings/search2/SearchResultDiffCallback.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.settings.search2;
+
+import android.support.v7.util.DiffUtil;
+
+import java.util.List;
+
+/**
+ * Callback for DiffUtil to elegantly update search data when the query changes.
+ */
+public class SearchResultDiffCallback extends DiffUtil.Callback {
+
+    private List<SearchResult> mOldList;
+    private List<SearchResult> mNewList;
+
+    public SearchResultDiffCallback(List<SearchResult> oldList, List<SearchResult> newList) {
+        mOldList = oldList;
+        mNewList = newList;
+    }
+
+    @Override
+    public int getOldListSize() {
+        return mOldList.size();
+    }
+
+    @Override
+    public int getNewListSize() {
+        return mNewList.size();
+    }
+
+    @Override
+    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
+        return mOldList.get(oldItemPosition).equals(mNewList.get(newItemPosition));
+    }
+
+    @Override
+    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
+        return mOldList.get(oldItemPosition).equals(mNewList.get(newItemPosition));
+    }
+}
diff --git a/src/com/android/settings/search2/SearchResultsAdapter.java b/src/com/android/settings/search2/SearchResultsAdapter.java
index 6ff68b1..60f2f7c 100644
--- a/src/com/android/settings/search2/SearchResultsAdapter.java
+++ b/src/com/android/settings/search2/SearchResultsAdapter.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.support.annotation.MainThread;
 import android.support.annotation.VisibleForTesting;
+import android.support.v7.util.DiffUtil;
 import android.support.v7.widget.RecyclerView;
 import android.util.ArrayMap;
 import android.view.LayoutInflater;
@@ -37,8 +38,9 @@
 
 public class SearchResultsAdapter extends RecyclerView.Adapter<SearchViewHolder> {
 
-    private final List<SearchResult> mSearchResults;
     private final SearchFragment mFragment;
+
+    private List<SearchResult> mSearchResults;
     private Map<String, List<? extends SearchResult>> mResultsMap;
 
     public SearchResultsAdapter(SearchFragment fragment) {
@@ -128,7 +130,7 @@
                 .get(InstalledAppResultLoader.class.getName());
         final int dbSize = (databaseResults != null) ? databaseResults.size() : 0;
         final int appSize = (installedAppResults != null) ? installedAppResults.size() : 0;
-        final List<SearchResult> results = new ArrayList<>(dbSize + appSize);
+        final List<SearchResult> newResults = new ArrayList<>(dbSize + appSize);
 
         int dbIndex = 0;
         int appIndex = 0;
@@ -136,23 +138,25 @@
 
         while (rank <= BOTTOM_RANK) {
             while ((dbIndex < dbSize) && (databaseResults.get(dbIndex).rank == rank)) {
-                results.add(databaseResults.get(dbIndex++));
+                newResults.add(databaseResults.get(dbIndex++));
             }
             while ((appIndex < appSize) && (installedAppResults.get(appIndex).rank == rank)) {
-                results.add(installedAppResults.get(appIndex++));
+                newResults.add(installedAppResults.get(appIndex++));
             }
             rank++;
         }
 
         while (dbIndex < dbSize) {
-            results.add(databaseResults.get(dbIndex++));
+            newResults.add(databaseResults.get(dbIndex++));
         }
         while (appIndex < appSize) {
-            results.add(installedAppResults.get(appIndex++));
+            newResults.add(installedAppResults.get(appIndex++));
         }
 
-        mSearchResults.addAll(results);
-        notifyDataSetChanged();
+        final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(
+                new SearchResultDiffCallback(mSearchResults, newResults), false /* detectMoves */);
+        mSearchResults = newResults;
+        diffResult.dispatchUpdatesTo(this);
 
         return mSearchResults.size();
     }
diff --git a/src/com/android/settings/search2/SearchViewHolder.java b/src/com/android/settings/search2/SearchViewHolder.java
index 123a602..fef9367 100644
--- a/src/com/android/settings/search2/SearchViewHolder.java
+++ b/src/com/android/settings/search2/SearchViewHolder.java
@@ -66,9 +66,11 @@
             iconView.setImageDrawable(appResult.info.loadIcon(pm));
         } else if (result.icon != null) {
             iconView.setImageDrawable(result.icon);
+            // TODO set color of icon
         } else {
             iconView.setBackgroundResource(R.drawable.empty_icon);
         }
+
         bindBreadcrumbView(result);
     }
 
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index 240b8eb..f5462b0 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -1,7 +1,5 @@
-com.android.settings.notification.ConfigureNotificationSettings
 com.android.settings.language.LanguageAndRegionSettings
 com.android.settings.notification.ZenModePrioritySettings
-com.android.settings.inputmethod.InputAndGestureSettings
 com.android.settings.accounts.AccountDetailDashboardFragment
 com.android.settings.fuelgauge.PowerUsageDetail
 com.android.settings.fuelgauge.AdvancedPowerUsageDetail
diff --git a/tests/robotests/src/com/android/settings/accounts/AccountSyncPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/AccountSyncPreferenceControllerTest.java
index 26c640d..c159a24 100644
--- a/tests/robotests/src/com/android/settings/accounts/AccountSyncPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/AccountSyncPreferenceControllerTest.java
@@ -15,11 +15,16 @@
  */
 package com.android.settings.accounts;
 
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+
 import android.accounts.Account;
 import android.content.Context;
+import android.content.Intent;
 import android.os.UserHandle;
 import android.support.v7.preference.Preference;
 
+import com.android.settings.R;
 import com.android.settings.SettingsActivity;
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
@@ -29,9 +34,6 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
 
-import static org.mockito.Mockito.mock;
-import static com.google.common.truth.Truth.assertThat;
-
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class AccountSyncPreferenceControllerTest {
@@ -42,13 +44,18 @@
         final Context context = application.getApplicationContext();
         final Preference preference = new Preference(context);
         preference.setKey("account_sync");
-        AccountSyncPreferenceController controller = new AccountSyncPreferenceController(context);
-        controller.init(new Account("acct1", "type1"), mock(UserHandle.class));
 
+        final AccountSyncPreferenceController controller =
+                new AccountSyncPreferenceController(context);
+        controller.init(new Account("acct1", "type1"), mock(UserHandle.class));
         controller.handlePreferenceTreeClick(preference);
 
-        assertThat(application.getNextStartedActivity().getStringExtra(
-            SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo(AccountSyncSettings.class.getName());
+        final Intent nextActivity = application.getNextStartedActivity();
+
+        assertThat(nextActivity.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
+                .isEqualTo(AccountSyncSettings.class.getName());
+        assertThat(nextActivity.getIntExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, 0))
+                .isEqualTo(R.string.account_sync_title);
     }
 
 }
diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java
index 9c91ccf..6cf4a59 100644
--- a/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java
+++ b/tests/robotests/src/com/android/settings/applications/InstalledAppDetailsTest.java
@@ -18,7 +18,6 @@
 
 
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
@@ -69,6 +68,9 @@
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public final class InstalledAppDetailsTest {
+
+    private static final String PACKAGE_NAME = "test_package_name";
+
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Context mContext;
     @Mock
@@ -182,6 +184,24 @@
     }
 
     @Test
+    public void packageSizeChange_isOtherPackage_shouldNotRefreshUi() {
+        ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
+        mAppDetail.onPackageSizeChanged("Not_" + PACKAGE_NAME);
+
+        verify(mAppDetail, never()).refreshUi();
+    }
+
+    @Test
+    public void packageSizeChange_isOwnPackage_shouldRefreshUi() {
+        doReturn(Boolean.TRUE).when(mAppDetail).refreshUi();
+        ReflectionHelpers.setField(mAppDetail, "mPackageName", PACKAGE_NAME);
+
+        mAppDetail.onPackageSizeChanged(PACKAGE_NAME);
+
+        verify(mAppDetail).refreshUi();
+    }
+
+    @Test
     public void launchPowerUsageDetailFragment_shouldNotCrash() {
         mAppDetail.mBatteryPreference = mBatteryPreference;
         mAppDetail.mSipper = mBatterySipper;
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
index fc4b75f..a4b5c97 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragmentTest.java
@@ -15,8 +15,12 @@
  */
 package com.android.settings.connecteddevice;
 
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.provider.SearchIndexableResource;
 
+import com.android.settings.bluetooth.BluetoothMasterSwitchPreferenceController;
+import com.android.settings.nfc.NfcPreferenceController;
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
 import com.android.settingslib.drawer.CategoryKey;
@@ -24,22 +28,33 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowApplication;
 
 import java.util.List;
 
 import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class ConnectedDeviceDashboardFragmentTest {
+    @Mock
+    Context mContext;
+
+    @Mock
+    private PackageManager mManager;
 
     private ConnectedDeviceDashboardFragment mFragment;
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
         mFragment = new ConnectedDeviceDashboardFragment();
+        when(mContext.getPackageManager()).thenReturn(mManager);
     }
 
     @Test
@@ -50,11 +65,47 @@
     @Test
     public void testSearchIndexProvider_shouldIndexResource() {
         final List<SearchIndexableResource> indexRes =
-                ConnectedDeviceDashboardFragment.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(
-                        ShadowApplication.getInstance().getApplicationContext(),
-                        true /* enabled */);
+                mFragment.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex(mContext, true /* enabled */);
 
         assertThat(indexRes).isNotNull();
         assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId());
     }
+
+    @Test
+    public void testSearchIndexProvider_NoNfc_KeyAdded() {
+        when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(false);
+        final List<String> keys = mFragment.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+        assertThat(keys).isNotNull();
+        assertThat(keys).contains(NfcPreferenceController.KEY_TOGGLE_NFC);
+        assertThat(keys).contains(NfcPreferenceController.KEY_ANDROID_BEAM_SETTINGS);
+    }
+
+    @Test
+    public void testSearchIndexProvider_NFC_KeyNotAdded() {
+        when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true);
+        final List<String> keys = mFragment.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+        assertThat(keys).isNotNull();
+        assertThat(keys).doesNotContain(NfcPreferenceController.KEY_TOGGLE_NFC);
+        assertThat(keys).doesNotContain(NfcPreferenceController.KEY_ANDROID_BEAM_SETTINGS);
+    }
+
+    @Test
+    public void testSearchIndexProvider_NoBluetooth_KeyAdded() {
+        when(mManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(false);
+        final List<String> keys = mFragment.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+        assertThat(keys).isNotNull();
+        assertThat(keys).contains(BluetoothMasterSwitchPreferenceController.KEY_TOGGLE_BLUETOOTH);
+    }
+
+    @Test
+    public void testSearchIndexProvider_Bluetooth_KeyNotAdded() {
+        when(mManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)).thenReturn(true);
+        final List<String> keys = mFragment.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext);
+
+        assertThat(keys).isNotNull();
+        assertThat(keys).doesNotContain(BluetoothMasterSwitchPreferenceController.KEY_TOGGLE_BLUETOOTH);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionsChecksTest.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionsChecksTest.java
index 72231b2..accca2a 100644
--- a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionsChecksTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionsChecksTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 Google Inc.
+ * Copyright (C) 2017 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,12 +17,12 @@
 package com.android.settings.dashboard.suggestions;
 
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.when;
 
+import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -41,6 +41,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
+
 
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
@@ -54,7 +56,8 @@
     private FingerprintManager mFingerprintManager;
     @Mock
     private DevicePolicyManager mDevicePolicyManager;
-
+    @Mock
+    private WallpaperManagerWrapper mWallpaperManager;
     private SuggestionsChecks mSuggestionsChecks;
 
     @Before
@@ -118,4 +121,24 @@
                 Settings.FingerprintEnrollSuggestionActivity.class));
         return tile;
     }
+
+    @Test
+    public void hasWallpaperSet_no_shouldReturnFalse() {
+        ReflectionHelpers.setField(mSuggestionsChecks, "mWallpaperManager", mWallpaperManager);
+        when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM))
+                .thenReturn(0);
+
+        assertThat(mSuggestionsChecks.hasWallpaperSet())
+                .isFalse();
+    }
+
+    @Test
+    public void hasWallpaperSet_yes_shouldReturnTrue() {
+        ReflectionHelpers.setField(mSuggestionsChecks, "mWallpaperManager", mWallpaperManager);
+        when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM))
+                .thenReturn(100);
+
+        assertThat(mSuggestionsChecks.hasWallpaperSet())
+                .isTrue();
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
index 47d910d..efe44ef 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -84,7 +84,7 @@
         FakeFeatureFactory.setupForTest(mContext);
         mFakeFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
         mMetricsFeatureProvider = mFakeFeatureFactory.getMetricsFeatureProvider();
-        mVolume = new VolumeInfo("id", 0, null, "id");
+        mVolume = spy(new VolumeInfo("id", 0, null, "id"));
         // Note: null is passed as the Lifecycle because we are handling it outside of the normal
         //       Settings fragment lifecycle for test purposes.
         mController = new StorageItemPreferenceController(mContext, mFragment, mVolume, mSvp);
@@ -305,4 +305,90 @@
         verify(system, times(2)).setIcon(any(Drawable.class));
         verify(files, times(2)).setIcon(any(Drawable.class));
     }
+
+    @Test
+    public void displayPreference_dontHideFilePreferenceWhenEmulatedInternalStorageUsed() {
+        StorageItemPreference audio = new StorageItemPreference(mContext);
+        StorageItemPreference image = new StorageItemPreference(mContext);
+        StorageItemPreference games = new StorageItemPreference(mContext);
+        StorageItemPreference apps = new StorageItemPreference(mContext);
+        StorageItemPreference system = new StorageItemPreference(mContext);
+        StorageItemPreference files = new StorageItemPreference(mContext);
+        PreferenceScreen screen = mock(PreferenceScreen.class);
+        when(screen.findPreference(eq(StorageItemPreferenceController.AUDIO_KEY)))
+                .thenReturn(audio);
+        when(screen.findPreference(eq(StorageItemPreferenceController.PHOTO_KEY)))
+                .thenReturn(image);
+        when(screen.findPreference(eq(StorageItemPreferenceController.GAME_KEY))).thenReturn(games);
+        when(screen.findPreference(eq(StorageItemPreferenceController.OTHER_APPS_KEY)))
+                .thenReturn(apps);
+        when(screen.findPreference(eq(StorageItemPreferenceController.SYSTEM_KEY)))
+                .thenReturn(system);
+        when(screen.findPreference(eq(StorageItemPreferenceController.FILES_KEY)))
+                .thenReturn(files);
+
+        when(mSvp.findEmulatedForPrivate(any(VolumeInfo.class))).thenReturn(mVolume);
+        when(mVolume.isMountedReadable()).thenReturn(true);
+
+        mController.displayPreference(screen);
+
+        verify(screen, times(0)).removePreference(files);
+    }
+
+    @Test
+    public void displayPreference_hideFilePreferenceWhenEmulatedStorageUnreadable() {
+        StorageItemPreference audio = new StorageItemPreference(mContext);
+        StorageItemPreference image = new StorageItemPreference(mContext);
+        StorageItemPreference games = new StorageItemPreference(mContext);
+        StorageItemPreference apps = new StorageItemPreference(mContext);
+        StorageItemPreference system = new StorageItemPreference(mContext);
+        StorageItemPreference files = new StorageItemPreference(mContext);
+        PreferenceScreen screen = mock(PreferenceScreen.class);
+        when(screen.findPreference(eq(StorageItemPreferenceController.AUDIO_KEY)))
+                .thenReturn(audio);
+        when(screen.findPreference(eq(StorageItemPreferenceController.PHOTO_KEY)))
+                .thenReturn(image);
+        when(screen.findPreference(eq(StorageItemPreferenceController.GAME_KEY))).thenReturn(games);
+        when(screen.findPreference(eq(StorageItemPreferenceController.OTHER_APPS_KEY)))
+                .thenReturn(apps);
+        when(screen.findPreference(eq(StorageItemPreferenceController.SYSTEM_KEY)))
+                .thenReturn(system);
+        when(screen.findPreference(eq(StorageItemPreferenceController.FILES_KEY)))
+                .thenReturn(files);
+
+        when(mSvp.findEmulatedForPrivate(any(VolumeInfo.class))).thenReturn(mVolume);
+        when(mVolume.isMountedReadable()).thenReturn(false);
+
+        mController.displayPreference(screen);
+
+        verify(screen).removePreference(files);
+    }
+
+    @Test
+    public void displayPreference_hideFilePreferenceWhenNoEmulatedInternalStorage() {
+        StorageItemPreference audio = new StorageItemPreference(mContext);
+        StorageItemPreference image = new StorageItemPreference(mContext);
+        StorageItemPreference games = new StorageItemPreference(mContext);
+        StorageItemPreference apps = new StorageItemPreference(mContext);
+        StorageItemPreference system = new StorageItemPreference(mContext);
+        StorageItemPreference files = new StorageItemPreference(mContext);
+        PreferenceScreen screen = mock(PreferenceScreen.class);
+        when(screen.findPreference(eq(StorageItemPreferenceController.AUDIO_KEY)))
+                .thenReturn(audio);
+        when(screen.findPreference(eq(StorageItemPreferenceController.PHOTO_KEY)))
+                .thenReturn(image);
+        when(screen.findPreference(eq(StorageItemPreferenceController.GAME_KEY))).thenReturn(games);
+        when(screen.findPreference(eq(StorageItemPreferenceController.OTHER_APPS_KEY)))
+                .thenReturn(apps);
+        when(screen.findPreference(eq(StorageItemPreferenceController.SYSTEM_KEY)))
+                .thenReturn(system);
+        when(screen.findPreference(eq(StorageItemPreferenceController.FILES_KEY)))
+                .thenReturn(files);
+
+        when(mSvp.findEmulatedForPrivate(any(VolumeInfo.class))).thenReturn(null);
+
+        mController.displayPreference(screen);
+
+        verify(screen).removePreference(files);
+    }
 }
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryStatsHelperLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryStatsHelperLoaderTest.java
new file mode 100644
index 0000000..d19a4b2
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryStatsHelperLoaderTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.fuelgauge;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.os.BatteryStats;
+import android.os.Bundle;
+import android.os.UserManager;
+
+import com.android.internal.os.BatteryStatsHelper;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BatteryStatsHelperLoaderTest {
+    @Mock
+    private BatteryStatsHelper mBatteryStatsHelper;
+    @Mock
+    private Bundle mBundle;
+    @Mock
+    private Context mContext;
+    @Mock
+    private UserManager mUserManager;
+    private BatteryStatsHelperLoader mLoader;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mLoader = new BatteryStatsHelperLoader(mContext, mBundle);
+        mLoader.mUserManager = mUserManager;
+    }
+
+    @Test
+    public void testInitBatteryStatsHelper_init() {
+        mLoader.initBatteryStatsHelper(mBatteryStatsHelper);
+
+        verify(mBatteryStatsHelper).create(mBundle);
+        verify(mBatteryStatsHelper).refreshStats(BatteryStats.STATS_SINCE_CHARGED,
+                mUserManager.getUserProfiles());
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
index 52cfe4c..f9cc771 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
@@ -64,12 +64,13 @@
     private static final long TIME_STATE_BACKGROUND = 6000 * UNIT;
 
     private static final int UID = 123;
-    private static final long TIME_EXPECTED_FOREGROUND = 9000;
+    private static final long TIME_EXPECTED_FOREGROUND = 6500;
     private static final long TIME_EXPECTED_BACKGROUND = 6000;
-    private static final long TIME_EXPECTED_ALL = 15000;
+    private static final long TIME_EXPECTED_ALL = 12500;
     private static final double BATTERY_SCREEN_USAGE = 300;
     private static final double BATTERY_SYSTEM_USAGE = 600;
     private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
+    private static final double BATTERY_UNACCOUNTED_USAGE = 700;
     private static final double TOTAL_BATTERY_USAGE = 1000;
     private static final double HIDDEN_USAGE = 200;
     private static final int DISCHARGE_AMOUNT = 80;
@@ -85,6 +86,8 @@
     @Mock
     private BatterySipper mOvercountedBatterySipper;
     @Mock
+    private BatterySipper mUnaccountedBatterySipper;
+    @Mock
     private BatterySipper mSystemBatterySipper;
     @Mock
     private BatterySipper mCellBatterySipper;
@@ -126,6 +129,9 @@
         mOvercountedBatterySipper.drainType = BatterySipper.DrainType.OVERCOUNTED;
         mOvercountedBatterySipper.totalPowerMah = BATTERY_OVERACCOUNTED_USAGE;
 
+        mUnaccountedBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
+        mUnaccountedBatterySipper.totalPowerMah = BATTERY_UNACCOUNTED_USAGE;
+
         mBatteryUtils = BatteryUtils.getInstance(RuntimeEnvironment.application);
         mBatteryUtils.mPowerUsageFeatureProvider = mProvider;
 
@@ -171,12 +177,14 @@
         sippers.add(mScreenBatterySipper);
         sippers.add(mSystemBatterySipper);
         sippers.add(mOvercountedBatterySipper);
+        sippers.add(mUnaccountedBatterySipper);
         when(mProvider.isTypeSystem(mSystemBatterySipper))
                 .thenReturn(true);
 
         final double totalUsage = mBatteryUtils.removeHiddenBatterySippers(sippers);
         assertThat(sippers).containsExactly(mNormalBatterySipper);
-        assertThat(totalUsage).isWithin(PRECISION).of(BATTERY_SCREEN_USAGE + BATTERY_SYSTEM_USAGE);
+        assertThat(totalUsage).isWithin(PRECISION).of(
+                BATTERY_SCREEN_USAGE + BATTERY_SYSTEM_USAGE + BATTERY_UNACCOUNTED_USAGE);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java
index 7a1284a..d46baa1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java
@@ -111,7 +111,7 @@
         mPowerUsageAdvanced.setPackageManager(mPackageManager);
         mPowerUsageAdvanced.setPowerUsageFeatureProvider(mPowerUsageFeatureProvider);
         mPowerUsageAdvanced.setUserManager(mUserManager);
-        mPowerUsageAdvanced.mBatteryUtils = spy(new BatteryUtils(mShadowContext));
+        mPowerUsageAdvanced.setBatteryUtils(BatteryUtils.getInstance(mShadowContext));
 
         mPowerUsageData = new PowerUsageData(UsageType.APP);
         mMaxBatterySipper.totalPowerMah = TYPE_BLUETOOTH_USAGE;
@@ -299,4 +299,16 @@
         assertThat(mPowerUsageAdvanced.shouldShowBatterySipper(mNormalBatterySipper)).isTrue();
     }
 
+    @Test
+    public void testCalculateHiddenPower_returnCorrectPower() {
+        List<PowerUsageData> powerUsageDataList = new ArrayList<>();
+        final double unaccountedPower = 100;
+        final double normalPower = 150;
+        powerUsageDataList.add(new PowerUsageData(UsageType.UNACCOUNTED, unaccountedPower));
+        powerUsageDataList.add(new PowerUsageData(UsageType.APP, normalPower));
+        powerUsageDataList.add(new PowerUsageData(UsageType.CELL, normalPower));
+
+        assertThat(mPowerUsageAdvanced.calculateHiddenPower(powerUsageDataList)).isWithin(
+                PRECISION).of(unaccountedPower);
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index 5cb60d2..3556d09 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -486,7 +486,7 @@
         }
 
         @Override
-        protected void refreshStats() {
+        protected void refreshUi() {
             // Leave it empty for toggle apps menu test
         }
     }
diff --git a/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java b/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java
index 647d68c..645dfe5 100644
--- a/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java
+++ b/tests/robotests/src/com/android/settings/search/SearchResultsAdapterTest.java
@@ -63,6 +63,8 @@
     private Context mContext;
     private String mLoaderClassName;
 
+    private String[] TITLES = {"alpha", "bravo", "charlie", "appAlpha", "appBravo", "appCharlie"};
+
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
@@ -72,13 +74,13 @@
     }
 
     @Test
-    public void testNoResultsAdded_EmptyListReturned() {
+    public void testNoResultsAdded_emptyListReturned() {
         List<SearchResult> updatedResults = mAdapter.getSearchResults();
         assertThat(updatedResults).isEmpty();
     }
 
     @Test
-    public void testSingleSourceMerge_ExactCopyReturned() {
+    public void testSingleSourceMerge_exactCopyReturned() {
         ArrayList<SearchResult> intentResults = getIntentSampleResults();
         mAdapter.addSearchResults(intentResults, mLoaderClassName);
         mAdapter.displaySearchResults();
@@ -88,7 +90,7 @@
     }
 
     @Test
-    public void testCreateViewHolder_ReturnsIntentResult() {
+    public void testCreateViewHolder_returnsIntentResult() {
         ViewGroup group = new FrameLayout(mContext);
         SearchViewHolder view = mAdapter.onCreateViewHolder(group,
                 ResultPayload.PayloadType.INTENT);
@@ -96,7 +98,7 @@
     }
 
     @Test
-    public void testCreateViewHolder_ReturnsInlineSwitchResult() {
+    public void testCreateViewHolder_returnsInlineSwitchResult() {
         ViewGroup group = new FrameLayout(mContext);
         SearchViewHolder view = mAdapter.onCreateViewHolder(group,
                 ResultPayload.PayloadType.INLINE_SWITCH);
@@ -104,21 +106,54 @@
     }
 
     @Test
-    public void testEndToEndSearch_ProperResultsMerged() {
-        mAdapter.addSearchResults(getDummyAppResults(),
+    public void testEndToEndSearch_properResultsMerged_correctOrder() {
+        mAdapter.addSearchResults(getDummyAppResults(), InstalledAppResultLoader.class.getName());
+        mAdapter.addSearchResults(getDummyDbResults(), DatabaseResultLoader.class.getName());
+        mAdapter.displaySearchResults();
+
+        List<SearchResult> results = mAdapter.getSearchResults();
+        List<SearchResult> sortedDummyResults  = getSortedDummyResults();
+
+        assertThat(results).containsExactlyElementsIn(sortedDummyResults).inOrder();
+    }
+
+    @Test
+    public void testEndToEndSearch_addResults_resultsAddedInOrder() {
+        List<AppSearchResult> appResults = getDummyAppResults();
+        List<SearchResult> dbResults = getDummyDbResults();
+        // Add two individual items
+        mAdapter.addSearchResults(appResults.subList(0,1),
                 InstalledAppResultLoader.class.getName());
-        mAdapter.addSearchResults(getDummyDbResults(),
-                DatabaseResultLoader.class.getName());
+        mAdapter.addSearchResults(dbResults.subList(0,1), DatabaseResultLoader.class.getName());
+        mAdapter.displaySearchResults();
+        // Add super-set of items
+        mAdapter.addSearchResults(appResults, InstalledAppResultLoader.class.getName());
+        mAdapter.addSearchResults(dbResults, DatabaseResultLoader.class.getName());
+        mAdapter.displaySearchResults();
+
+        List<SearchResult> results = mAdapter.getSearchResults();
+        List<SearchResult> sortedDummyResults  = getSortedDummyResults();
+        assertThat(results).containsExactlyElementsIn(sortedDummyResults).inOrder();
+    }
+
+    @Test
+    public void testEndToEndSearch_removeResults_resultsAdded() {
+        List<AppSearchResult> appResults = getDummyAppResults();
+        List<SearchResult> dbResults = getDummyDbResults();
+        // Add list of items
+        mAdapter.addSearchResults(appResults, InstalledAppResultLoader.class.getName());
+        mAdapter.addSearchResults(dbResults, DatabaseResultLoader.class.getName());
+        mAdapter.displaySearchResults();
+        // Add subset of items
+        mAdapter.addSearchResults(appResults.subList(0,1),
+                InstalledAppResultLoader.class.getName());
+        mAdapter.addSearchResults(dbResults.subList(0,1), DatabaseResultLoader.class.getName());
         int count = mAdapter.displaySearchResults();
 
         List<SearchResult> results = mAdapter.getSearchResults();
-        assertThat(results.get(0).title).isEqualTo("alpha");
-        assertThat(results.get(1).title).isEqualTo("appAlpha");
-        assertThat(results.get(2).title).isEqualTo("appBravo");
-        assertThat(results.get(3).title).isEqualTo("bravo");
-        assertThat(results.get(4).title).isEqualTo("appCharlie");
-        assertThat(results.get(5).title).isEqualTo("Charlie");
-        assertThat(count).isEqualTo(6);
+        assertThat(results.get(0).title).isEqualTo(TITLES[0]);
+        assertThat(results.get(1).title).isEqualTo(TITLES[3]);
+        assertThat(count).isEqualTo(2);
     }
 
     private List<SearchResult> getDummyDbResults() {
@@ -127,15 +162,15 @@
         SearchResult.Builder builder = new SearchResult.Builder();
         builder.addPayload(payload);
 
-        builder.addTitle("alpha")
+        builder.addTitle(TITLES[0])
                 .addRank(1);
         results.add(builder.build());
 
-        builder.addTitle("bravo")
+        builder.addTitle(TITLES[1])
                 .addRank(3);
         results.add(builder.build());
 
-        builder.addTitle("Charlie")
+        builder.addTitle(TITLES[2])
                 .addRank(6);
         results.add(builder.build());
 
@@ -148,21 +183,35 @@
         AppSearchResult.Builder builder = new AppSearchResult.Builder();
         builder.addPayload(payload);
 
-        builder.addTitle("appAlpha")
+        builder.addTitle(TITLES[3])
                 .addRank(1);
         results.add(builder.build());
 
-        builder.addTitle("appBravo")
+        builder.addTitle(TITLES[4])
                 .addRank(2);
         results.add(builder.build());
 
-        builder.addTitle("appCharlie")
+        builder.addTitle(TITLES[5])
                 .addRank(4);
         results.add(builder.build());
 
         return results;
     }
 
+    private List<SearchResult> getSortedDummyResults() {
+        List<AppSearchResult> appResults = getDummyAppResults();
+        List<SearchResult> dbResults = getDummyDbResults();
+        List<SearchResult> sortedResults = new ArrayList<>(appResults.size() + dbResults.size());
+        sortedResults.add(dbResults.get(0)); // alpha
+        sortedResults.add(appResults.get(0)); // appAlpha
+        sortedResults.add(appResults.get(1)); // appBravo
+        sortedResults.add(dbResults.get(1)); // bravo
+        sortedResults.add(appResults.get(2)); // appCharlie
+        sortedResults.add(dbResults.get(2)); // Charlie
+
+        return sortedResults;
+    }
+
     private ArrayList<SearchResult> getIntentSampleResults() {
         ArrayList<SearchResult> sampleResults = new ArrayList<>();
         ArrayList<String> breadcrumbs = new ArrayList<>();
diff --git a/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java b/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java
index aa4e4f9..047d867 100644
--- a/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java
+++ b/tests/robotests/src/com/android/settings/search2/DatabaseIndexingManagerTest.java
@@ -303,7 +303,7 @@
         // Class Name
         assertThat(cursor.getString(11)).isEqualTo(className);
         // Icon
-        assertThat(cursor.getInt(12)).isEqualTo(iconResId);
+        assertThat(cursor.getInt(12)).isEqualTo(0);
         // Intent Action
         assertThat(cursor.getString(13)).isEqualTo(action);
         // Target Package
diff --git a/tests/unit/src/com/android/settings/deviceinfo/PublicVolumeSettingsTest.java b/tests/unit/src/com/android/settings/deviceinfo/PublicVolumeSettingsTest.java
new file mode 100644
index 0000000..4903b86
--- /dev/null
+++ b/tests/unit/src/com/android/settings/deviceinfo/PublicVolumeSettingsTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.settings.deviceinfo;
+
+import android.content.Intent;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.settings.Settings;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class PublicVolumeSettingsTest {
+    @Rule
+    public ActivityTestRule<Settings.PublicVolumeSettingsActivity> mActivityRule =
+            new ActivityTestRule<>(Settings.PublicVolumeSettingsActivity.class, true, true);
+
+    @Test
+    public void test_invalidSetupDoesNotCrashSettings() {
+        Intent intent = new Intent();
+        intent.setAction(android.provider.Settings.ACTION_INTERNAL_STORAGE_SETTINGS);
+        intent.setClassName(InstrumentationRegistry.getTargetContext().getPackageName(),
+                Settings.PublicVolumeSettingsActivity.class.getName());
+        mActivityRule.launchActivity(intent);
+
+        // Should exit gracefully without crashing.
+    }
+}