Merge "Notification settings, importance and pre-O apps" into oc-dev
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 730e0ed..8e3fbe2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6515,6 +6515,9 @@
     <!-- Configure Notifications: Work profile section header [CHAR LIMIT=30] -->
     <string name="profile_section_header">Work notifications</string>
 
+    <!-- Configure Notifications: Title for the notification badging option. [CHAR LIMIT=30] -->
+    <string name="notification_badging_title">Allow icon badges</string>
+
     <!-- Configure Notifications: Title for the pulse notification light option. [CHAR LIMIT=30] -->
     <string name="notification_pulse_title">Blink light</string>
 
diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml
index a6ffff4..bed3aa6 100644
--- a/res/xml/configure_notification_settings.xml
+++ b/res/xml/configure_notification_settings.xml
@@ -22,6 +22,11 @@
         android:key="dashboard_tile_placeholder"
         android:order="1"/>
 
+    <!-- Notification badging -->
+    <SwitchPreference
+        android:key="notification_badging"
+        android:title="@string/notification_badging_title"/>
+
     <!-- Pulse notification light -->
     <SwitchPreference
         android:key="notification_pulse"
@@ -31,7 +36,7 @@
     <com.android.settings.notification.RestrictedDropDownPreference
         android:key="lock_screen_notifications"
         android:title="@string/lock_screen_notifications_title"
-        android:summary="%s"/>
+        android:summary="@string/summary_placeholder"/>
 
     <SwitchPreference
         android:key="gesture_swipe_down_fingerprint"
@@ -45,7 +50,7 @@
         <com.android.settings.notification.RestrictedDropDownPreference
             android:key="lock_screen_notifications_profile"
             android:title="@string/lock_screen_notifications_title"
-            android:summary="%s"/>
+            android:summary="@string/summary_placeholder"/>
 
     </PreferenceCategory>
 
diff --git a/res/xml/security_lockscreen_settings.xml b/res/xml/security_lockscreen_settings.xml
index e151b2b..2a4416e 100644
--- a/res/xml/security_lockscreen_settings.xml
+++ b/res/xml/security_lockscreen_settings.xml
@@ -21,7 +21,7 @@
         <com.android.settings.notification.RestrictedDropDownPreference
             android:key="lock_screen_notifications"
             android:title="@string/lock_screen_notifications_title"
-            android:summary="%s"/>
+            android:summary="@string/summary_placeholder"/>
 
         <com.android.settingslib.RestrictedSwitchPreference
             android:key="add_users_when_locked"
diff --git a/res/xml/wifi_configure_settings.xml b/res/xml/wifi_configure_settings.xml
index 14990a5..ac992d7 100644
--- a/res/xml/wifi_configure_settings.xml
+++ b/res/xml/wifi_configure_settings.xml
@@ -31,10 +31,11 @@
         android:title="@string/use_open_wifi_automatically_title"
         android:summary="@string/use_open_wifi_automatically_summary" />
 
-    <Preference
+    <SwitchPreference
             android:key="notify_open_networks"
             android:title="@string/wifi_notify_open_networks"
-            android:icon="@drawable/ic_open_wifi_notifications"/>
+            android:icon="@drawable/ic_open_wifi_notifications"
+            android:summary="@string/wifi_notify_open_networks_summary" />
 
     <SwitchPreference
         android:key="wifi_cellular_data_fallback"
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index f6f980a..0142ea2 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -103,6 +103,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.UserIcons;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.password.FingerprintManagerWrapper;
+import com.android.settings.password.IFingerprintManager;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -1197,6 +1199,15 @@
         }
     }
 
+    public static IFingerprintManager getFingerprintManagerWrapperOrNull(Context context) {
+        FingerprintManager fingerprintManager = getFingerprintManagerOrNull(context);
+        if (fingerprintManager != null) {
+            return new FingerprintManagerWrapper(fingerprintManager);
+        } else {
+            return null;
+        }
+    }
+
     /**
      * Launches an intent which may optionally have a user id defined.
      * @param fragment Fragment to use to launch the activity.
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index caac95f..edf2b75 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -271,6 +271,7 @@
             Settings.PrintSettingsActivity.class.getName(),
             // Home page > Apps & Notifications
             Settings.UserSettingsActivity.class.getName(),
+            Settings.ConfigureNotificationSettingsActivity.class.getName(),
             Settings.ManageApplicationsActivity.class.getName(),
             Settings.PaymentSettingsActivity.class.getName(),
             // Home page > Security & screen lock
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
index 510e953..107838c 100644
--- a/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
@@ -82,9 +82,7 @@
             @Override
             public void onEnrollmentProgressChange(int steps, int remaining) {
                 mNextClicked = true;
-                if (!mSidecar.cancelEnrollment()) {
-                    proceedToEnrolling();
-                }
+                proceedToEnrolling(true /* cancelEnrollment */);
             }
 
             @Override
@@ -95,7 +93,7 @@
             public void onEnrollmentError(int errMsgId, CharSequence errString) {
                 if (mNextClicked && errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
                     mNextClicked = false;
-                    proceedToEnrolling();
+                    proceedToEnrolling(false /* cancelEnrollment */);
                 }
             }
         });
@@ -123,15 +121,23 @@
     @Override
     protected void onNextButtonClick() {
         mNextClicked = true;
-        if (mSidecar == null || (mSidecar != null && !mSidecar.cancelEnrollment())) {
-            proceedToEnrolling();
-        }
+        proceedToEnrolling(true /* cancelEnrollment */);
     }
 
-    private void proceedToEnrolling() {
-        getFragmentManager().beginTransaction().remove(mSidecar).commit();
-        mSidecar = null;
-        startActivityForResult(getEnrollingIntent(), ENROLLING);
+    private void proceedToEnrolling(boolean cancelEnrollment) {
+        if (mSidecar != null) {
+            if (cancelEnrollment) {
+                if (mSidecar.cancelEnrollment()) {
+                    // Enrollment cancel requested. When the cancellation is successful,
+                    // onEnrollmentError will be called with FINGERPRINT_ERROR_CANCELED, calling
+                    // this again.
+                    return;
+                }
+            }
+            getFragmentManager().beginTransaction().remove(mSidecar).commit();
+            mSidecar = null;
+            startActivityForResult(getEnrollingIntent(), ENROLLING);
+        }
     }
 
     @Override
diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollSidecar.java b/src/com/android/settings/fingerprint/FingerprintEnrollSidecar.java
index e0c5d65..7fc7a04 100644
--- a/src/com/android/settings/fingerprint/FingerprintEnrollSidecar.java
+++ b/src/com/android/settings/fingerprint/FingerprintEnrollSidecar.java
@@ -28,12 +28,13 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.ChooseLockSettingsHelper;
 import com.android.settings.Utils;
-import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.core.InstrumentedFragment;
+import com.android.settings.password.IFingerprintManager;
 
 /**
  * Sidecar fragment to handle the state around fingerprint enrollment.
  */
-public class FingerprintEnrollSidecar extends InstrumentedPreferenceFragment {
+public class FingerprintEnrollSidecar extends InstrumentedFragment {
 
     private int mEnrollmentSteps = -1;
     private int mEnrollmentRemaining = 0;
@@ -44,7 +45,7 @@
     private byte[] mToken;
     private boolean mDone;
     private int mUserId;
-    private FingerprintManager mFingerprintManager;
+    private IFingerprintManager mFingerprintManager;
 
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -55,7 +56,7 @@
     @Override
     public void onAttach(Activity activity) {
         super.onAttach(activity);
-        mFingerprintManager = Utils.getFingerprintManagerOrNull(activity);
+        mFingerprintManager = Utils.getFingerprintManagerWrapperOrNull(activity);
         mToken = activity.getIntent().getByteArrayExtra(
                 ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
         mUserId = activity.getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
diff --git a/src/com/android/settings/fuelgauge/BatteryMeterView.java b/src/com/android/settings/fuelgauge/BatteryMeterView.java
index c450b90..969f886 100644
--- a/src/com/android/settings/fuelgauge/BatteryMeterView.java
+++ b/src/com/android/settings/fuelgauge/BatteryMeterView.java
@@ -38,6 +38,8 @@
     @VisibleForTesting
     ColorFilter mAccentColorFilter;
 
+    private int mLevel;
+
     public BatteryMeterView(Context context) {
         this(context, null, 0);
     }
@@ -64,6 +66,7 @@
     }
 
     public void setBatteryLevel(int level) {
+        mLevel = level;
         mDrawable.setBatteryLevel(level);
         if (level < mDrawable.getCriticalLevel()) {
             mDrawable.setBatteryColorFilter(mErrorColorFilter);
@@ -72,6 +75,10 @@
         }
     }
 
+    public int getBatteryLevel() {
+        return mLevel;
+    }
+
     public void setCharging(boolean charging) {
         mDrawable.setCharging(charging);
     }
diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
index bcf830b..0309296 100644
--- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.fuelgauge;
 
+import android.animation.Animator;
+import android.animation.ValueAnimator;
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
@@ -41,6 +43,7 @@
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
+import android.view.animation.AnimationUtils;
 import android.widget.TextView;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -84,6 +87,10 @@
     private static final String KEY_BATTERY_HEADER = "battery_header";
     private static final int MAX_ITEMS_TO_LIST = USE_FAKE_DATA ? 30 : 10;
     private static final int MIN_AVERAGE_POWER_THRESHOLD_MILLI_AMP = 10;
+    private static final int BATTERY_ANIMATION_DURATION_MS_PER_LEVEL = 30;
+
+    @VisibleForTesting
+    static final String ARG_BATTERY_LEVEL = "key_battery_level";
 
     private static final String KEY_SCREEN_USAGE = "screen_usage";
     private static final String KEY_TIME_SINCE_LAST_FULL_CHARGE = "last_full_charge";
@@ -105,6 +112,8 @@
             new FooterPreferenceMixin(this, getLifecycle());
 
     @VisibleForTesting
+    int mBatteryLevel;
+    @VisibleForTesting
     boolean mShowAllApps = false;
     @VisibleForTesting
     PowerGaugePreference mScreenUsagePref;
@@ -124,6 +133,8 @@
         super.onCreate(icicle);
         setAnimationAllowed(true);
 
+        mBatteryLevel = getContext().getResources().getInteger(
+                com.android.internal.R.integer.config_criticalBatteryWarningLevel) + 1;
         mBatteryLayoutPref = (LayoutPreference) findPreference(KEY_BATTERY_HEADER);
         mAppListGroup = (PreferenceGroup) findPreference(KEY_APP_LIST);
         mScreenUsagePref = (PowerGaugePreference) findPreference(KEY_SCREEN_USAGE);
@@ -137,6 +148,14 @@
     }
 
     @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        if (savedInstanceState != null) {
+            mBatteryLevel = savedInstanceState.getInt(ARG_BATTERY_LEVEL);
+        }
+    }
+
+    @Override
     public int getMetricsCategory() {
         return MetricsEvent.FUELGAUGE_POWER_USAGE_SUMMARY;
     }
@@ -144,6 +163,8 @@
     @Override
     public void onResume() {
         super.onResume();
+
+        initHeaderPreference();
     }
 
     @Override
@@ -162,6 +183,12 @@
     }
 
     @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(ARG_BATTERY_LEVEL, mBatteryLevel);
+    }
+
+    @Override
     public boolean onPreferenceTreeClick(Preference preference) {
         if (KEY_BATTERY_HEADER.equals(preference.getKey())) {
             performBatteryHeaderClick();
@@ -569,15 +596,46 @@
                 .findViewById(R.id.battery_header_icon);
         final TextView timeText = (TextView) mBatteryLayoutPref.findViewById(R.id.battery_percent);
         final TextView summary1 = (TextView) mBatteryLayoutPref.findViewById(R.id.summary1);
-        timeText.setText(Utils.formatPercentage(info.batteryLevel));
         if (info.remainingLabel == null ) {
             summary1.setText(info.statusLabel);
         } else {
             summary1.setText(info.remainingLabel);
         }
-
-        batteryView.setBatteryLevel(info.batteryLevel);
         batteryView.setCharging(!info.discharging);
+        startBatteryHeaderAnimationIfNecessary(batteryView, timeText, mBatteryLevel,
+                info.batteryLevel);
+    }
+
+    @VisibleForTesting
+    void initHeaderPreference() {
+        final BatteryMeterView batteryView = (BatteryMeterView) mBatteryLayoutPref
+                .findViewById(R.id.battery_header_icon);
+        final TextView timeText = (TextView) mBatteryLayoutPref.findViewById(R.id.battery_percent);
+
+        batteryView.setBatteryLevel(mBatteryLevel);
+        timeText.setText(Utils.formatPercentage(mBatteryLevel));
+    }
+
+    @VisibleForTesting
+    void startBatteryHeaderAnimationIfNecessary(BatteryMeterView batteryView, TextView timeTextView,
+            int prevLevel, int currentLevel) {
+        mBatteryLevel = currentLevel;
+        final int diff = Math.abs(prevLevel - currentLevel);
+        if (diff != 0) {
+            final ValueAnimator animator = ValueAnimator.ofInt(prevLevel, currentLevel);
+            animator.setDuration(BATTERY_ANIMATION_DURATION_MS_PER_LEVEL * diff);
+            animator.setInterpolator(AnimationUtils.loadInterpolator(getContext(),
+                    android.R.interpolator.fast_out_slow_in));
+            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    final Integer level = (Integer) animation.getAnimatedValue();
+                    batteryView.setBatteryLevel(level);
+                    timeTextView.setText(Utils.formatPercentage(level));
+                }
+            });
+            animator.start();
+        }
     }
 
     @VisibleForTesting
diff --git a/src/com/android/settings/notification/BadgingNotificationPreferenceController.java b/src/com/android/settings/notification/BadgingNotificationPreferenceController.java
new file mode 100644
index 0000000..225ede5
--- /dev/null
+++ b/src/com/android/settings/notification/BadgingNotificationPreferenceController.java
@@ -0,0 +1,126 @@
+/*
+ * 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.notification;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.TwoStatePreference;
+import android.util.Log;
+
+import com.android.settings.core.PreferenceController;
+import com.android.settings.core.lifecycle.LifecycleObserver;
+import com.android.settings.core.lifecycle.events.OnPause;
+import com.android.settings.core.lifecycle.events.OnResume;
+
+import static android.provider.Settings.Secure.NOTIFICATION_BADGING;
+
+public class BadgingNotificationPreferenceController extends PreferenceController implements
+        Preference.OnPreferenceChangeListener, LifecycleObserver, OnResume, OnPause {
+
+    private static final String TAG = "BadgeNotifPrefContr";
+    private static final String KEY_NOTIFICATION_BADGING = "notification_badging";
+    private static final int DEFAULT_VALUE = 1;
+
+    private SettingObserver mSettingObserver;
+
+    public BadgingNotificationPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        Preference preference = screen.findPreference(NOTIFICATION_BADGING);
+        if (preference != null) {
+            mSettingObserver = new SettingObserver(preference);
+        }
+    }
+
+    @Override
+    public void onResume() {
+        if (mSettingObserver != null) {
+            mSettingObserver.register(mContext.getContentResolver(), true /* register */);
+        }
+    }
+
+    @Override
+    public void onPause() {
+        if (mSettingObserver != null) {
+            mSettingObserver.register(mContext.getContentResolver(), false /* register */);
+        }
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_NOTIFICATION_BADGING;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mContext.getResources()
+                .getBoolean(com.android.internal.R.bool.config_notificationBadging);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        final boolean checked = Settings.Secure.getInt(mContext.getContentResolver(),
+                NOTIFICATION_BADGING, DEFAULT_VALUE) == 1;
+        ((TwoStatePreference) preference).setChecked(checked);
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final boolean val = (Boolean) newValue;
+        return Settings.Secure.putInt(mContext.getContentResolver(),
+                NOTIFICATION_BADGING, val ? 1 : 0);
+    }
+
+    class SettingObserver extends ContentObserver {
+
+        private final Uri NOTIFICATION_BADGING_URI =
+                Settings.Secure.getUriFor(NOTIFICATION_BADGING);
+
+        private final Preference mPreference;
+
+        public SettingObserver(Preference preference) {
+            super(new Handler());
+            mPreference = preference;
+        }
+
+        public void register(ContentResolver cr, boolean register) {
+            if (register) {
+                cr.registerContentObserver(NOTIFICATION_BADGING_URI, false, this);
+            } else {
+                cr.unregisterContentObserver(this);
+            }
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            if (NOTIFICATION_BADGING_URI.equals(uri)) {
+                updateState(mPreference);
+            }
+        }
+    }
+}
diff --git a/src/com/android/settings/notification/ConfigureNotificationSettings.java b/src/com/android/settings/notification/ConfigureNotificationSettings.java
index b591d85..a1c5263 100644
--- a/src/com/android/settings/notification/ConfigureNotificationSettings.java
+++ b/src/com/android/settings/notification/ConfigureNotificationSettings.java
@@ -58,6 +58,8 @@
     private static List<PreferenceController> buildPreferenceControllers(Context context,
             Lifecycle lifecycle) {
         final List<PreferenceController> controllers = new ArrayList<>();
+        final BadgingNotificationPreferenceController badgeController =
+                new BadgingNotificationPreferenceController(context);
         final PulseNotificationPreferenceController pulseController =
                 new PulseNotificationPreferenceController(context);
         final LockScreenNotificationPreferenceController lockScreenNotificationController =
@@ -67,6 +69,7 @@
             lifecycle.addObserver(lockScreenNotificationController);
         }
         controllers.add(new SwipeToNotificationPreferenceController(context, lifecycle));
+        controllers.add(badgeController);
         controllers.add(pulseController);
         controllers.add(lockScreenNotificationController);
         return controllers;
diff --git a/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java b/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java
index 547ff80..73469b0 100644
--- a/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java
+++ b/src/com/android/settings/notification/LockScreenNotificationPreferenceController.java
@@ -281,6 +281,7 @@
             return;
         }
         mLockscreenSelectedValue = getSummaryResource();
+        mLockscreen.setSummary("%s");
         mLockscreen.setValue(Integer.toString(mLockscreenSelectedValue));
     }
 
diff --git a/src/com/android/settings/password/FingerprintManagerWrapper.java b/src/com/android/settings/password/FingerprintManagerWrapper.java
index b00f786..51b31af 100644
--- a/src/com/android/settings/password/FingerprintManagerWrapper.java
+++ b/src/com/android/settings/password/FingerprintManagerWrapper.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
+import android.os.CancellationSignal;
 
 import com.android.internal.util.Preconditions;
 
@@ -33,15 +35,33 @@
         mFingerprintManager = fingerprintManager;
     }
 
+    @Override
     public boolean isHardwareDetected() {
         return mFingerprintManager.isHardwareDetected();
     }
 
+    @Override
     public boolean hasEnrolledFingerprints(int userId) {
         return mFingerprintManager.hasEnrolledFingerprints(userId);
     }
 
+    @Override
     public long preEnroll() {
         return mFingerprintManager.preEnroll();
     }
+
+    @Override
+    public void setActiveUser(int userId) {
+        mFingerprintManager.setActiveUser(userId);
+    }
+
+    @Override
+    public void enroll(
+            byte[] token,
+            CancellationSignal cancel,
+            int flags,
+            int userId,
+            EnrollmentCallback callback) {
+        mFingerprintManager.enroll(token, cancel, flags, userId, callback);
+    }
 }
diff --git a/src/com/android/settings/password/IFingerprintManager.java b/src/com/android/settings/password/IFingerprintManager.java
index 15a9242..9402146 100644
--- a/src/com/android/settings/password/IFingerprintManager.java
+++ b/src/com/android/settings/password/IFingerprintManager.java
@@ -16,6 +16,9 @@
 
 package com.android.settings.password;
 
+import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
+import android.os.CancellationSignal;
+
 /**
  * This is the workaround to allow us test {@link SetNewPasswordController} which uses a new hidden
  * API {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints(int)} that
@@ -28,4 +31,9 @@
     boolean hasEnrolledFingerprints(int userId);
 
     long preEnroll();
+
+    void setActiveUser(int userId);
+
+    void enroll(byte [] token, CancellationSignal cancel, int flags,
+            int userId, EnrollmentCallback callback);
 }
diff --git a/src/com/android/settings/search2/SearchFragment.java b/src/com/android/settings/search2/SearchFragment.java
index 5ee22b5..2a5c961 100644
--- a/src/com/android/settings/search2/SearchFragment.java
+++ b/src/com/android/settings/search2/SearchFragment.java
@@ -291,6 +291,9 @@
      */
     @Override
     public void onIndexingFinished() {
+        if (getActivity() == null) {
+            return;
+        }
         if (mShowingSavedQuery) {
             mSavedQueryController.loadSavedQueries();
         } else {
diff --git a/src/com/android/settings/utils/NotificationChannelHelper.java b/src/com/android/settings/utils/NotificationChannelHelper.java
deleted file mode 100644
index bf008dc..0000000
--- a/src/com/android/settings/utils/NotificationChannelHelper.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.utils;
-
-import android.app.INotificationManager;
-import android.app.NotificationChannel;
-import android.os.RemoteException;
-
-/**
- * Wrappers around methods in {@link INotificationManager} and {@link NotificationChannel} to
- * facilitate unit testing.
- *
- * TODO: delete this class once robolectric supports Android O
- */
-public class NotificationChannelHelper {
-    private INotificationManager mNotificationManager;
-
-    public NotificationChannelHelper(
-            INotificationManager notificationManager) {
-        mNotificationManager = notificationManager;
-    }
-
-    /**
-     * Returns the notification channel settings for a app given its package name, user id, and
-     * channel id.
-     */
-    public NotificationChannelWrapper getNotificationChannelForPackage(String pkg, int uid,
-            String channelId, boolean includeDeleted) throws RemoteException {
-        NotificationChannel channel = mNotificationManager.getNotificationChannelForPackage(
-                pkg, uid, channelId, includeDeleted);
-        return channel == null ? null : new NotificationChannelWrapper(channel);
-    }
-
-    /**
-     * Wrapper around {@link NotificationChannel} to facilitate unit testing.
-     *
-     * TODO: delete this class once robolectric supports Android O
-     */
-    public class NotificationChannelWrapper {
-        private NotificationChannel mChannel;
-
-        public NotificationChannelWrapper(NotificationChannel channel) {
-            mChannel = channel;
-        }
-
-        public int getImportance() {
-            return mChannel.getImportance();
-        }
-    }
-}
diff --git a/src/com/android/settings/wifi/ConfigureWifiSettings.java b/src/com/android/settings/wifi/ConfigureWifiSettings.java
index 24d62ad..af80fd4 100644
--- a/src/com/android/settings/wifi/ConfigureWifiSettings.java
+++ b/src/com/android/settings/wifi/ConfigureWifiSettings.java
@@ -15,13 +15,15 @@
  */
 package com.android.settings.wifi;
 
-import android.app.INotificationManager;
+import static android.content.Context.NETWORK_SCORE_SERVICE;
+import static android.content.Context.WIFI_SERVICE;
+
 import android.content.Context;
 import android.content.Intent;
 import android.net.NetworkScoreManager;
 import android.net.wifi.WifiManager;
-import android.os.ServiceManager;
 import android.provider.SearchIndexableResource;
+
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.SettingsActivity;
@@ -32,7 +34,6 @@
 import com.android.settings.network.WifiCallingPreferenceController;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
-import com.android.settings.utils.NotificationChannelHelper;
 import com.android.settings.wifi.p2p.WifiP2pPreferenceController;
 
 import java.util.ArrayList;
@@ -72,18 +73,14 @@
     protected List<PreferenceController> getPreferenceControllers(Context context) {
         final NetworkScoreManagerWrapper networkScoreManagerWrapper =
                 new NetworkScoreManagerWrapper(context.getSystemService(NetworkScoreManager.class));
-        final NotificationChannelHelper notificationChannelHelper =
-                new NotificationChannelHelper(INotificationManager.Stub.asInterface(
-                        ServiceManager.getService(Context.NOTIFICATION_SERVICE)));
-        final WifiManager wifiManager = context.getSystemService(WifiManager.class);
         mUseOpenWifiPreferenceController = new UseOpenWifiPreferenceController(context, this,
                 networkScoreManagerWrapper, getLifecycle());
+        final WifiManager wifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
         final List<PreferenceController> controllers = new ArrayList<>();
         controllers.add(new WifiWakeupPreferenceController(context, getLifecycle()));
         controllers.add(new NetworkScorerPickerPreferenceController(context,
                 networkScoreManagerWrapper));
-        controllers.add(new NotifyOpenNetworksPreferenceController(context,
-                networkScoreManagerWrapper, notificationChannelHelper, getPackageManager()));
+        controllers.add(new NotifyOpenNetworksPreferenceController(context, getLifecycle()));
         controllers.add(mUseOpenWifiPreferenceController);
         controllers.add(new WifiSleepPolicyPreferenceController(context));
         controllers.add(new WifiInfoPreferenceController(context, getLifecycle(), wifiManager));
diff --git a/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java b/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java
index a85a266..6e88d79 100644
--- a/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java
+++ b/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java
@@ -16,46 +16,75 @@
 
 package com.android.settings.wifi;
 
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
+import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.net.NetworkScorerAppData;
-import android.os.RemoteException;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
 import android.provider.Settings;
-import android.support.annotation.Nullable;
+import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
 import android.text.TextUtils;
-import android.util.Log;
-import com.android.settings.R;
+
 import com.android.settings.core.PreferenceController;
-import com.android.settings.network.NetworkScoreManagerWrapper;
-import com.android.settings.utils.NotificationChannelHelper;
-import com.android.settings.utils.NotificationChannelHelper.NotificationChannelWrapper;
+import com.android.settings.core.lifecycle.Lifecycle;
+import com.android.settings.core.lifecycle.LifecycleObserver;
+import com.android.settings.core.lifecycle.events.OnPause;
+import com.android.settings.core.lifecycle.events.OnResume;
 
 /**
- * {@link PreferenceController} that shows whether we should notify user when open network is
- * available. The preference links to {@link NotificationChannel} settings.
+ * {@link PreferenceController} that controls whether we should notify user when open network is
+ * available.
  */
-public class NotifyOpenNetworksPreferenceController extends PreferenceController {
+public class NotifyOpenNetworksPreferenceController extends PreferenceController implements
+        LifecycleObserver, OnResume, OnPause {
 
-    private static final String TAG = "OpenNetworks";
     private static final String KEY_NOTIFY_OPEN_NETWORKS = "notify_open_networks";
+    private SettingObserver mSettingObserver;
 
-    private NetworkScoreManagerWrapper mNetworkScoreManager;
-    private NotificationChannelHelper mNotificationChannelHelper;
-    private PackageManager mPackageManager;
-
-    public NotifyOpenNetworksPreferenceController(
-            Context context,
-            NetworkScoreManagerWrapper networkScoreManager,
-            NotificationChannelHelper notificationChannelHelper,
-            PackageManager packageManager) {
+    public NotifyOpenNetworksPreferenceController(Context context, Lifecycle lifecycle) {
         super(context);
-        mNetworkScoreManager = networkScoreManager;
-        mNotificationChannelHelper = notificationChannelHelper;
-        mPackageManager = packageManager;
+        lifecycle.addObserver(this);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mSettingObserver = new SettingObserver(screen.findPreference(KEY_NOTIFY_OPEN_NETWORKS));
+    }
+
+    @Override
+    public void onResume() {
+        if (mSettingObserver != null) {
+            mSettingObserver.register(mContext.getContentResolver(), true /* register */);
+        }
+    }
+
+    @Override
+    public void onPause() {
+        if (mSettingObserver != null) {
+            mSettingObserver.register(mContext.getContentResolver(), false /* register */);
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), KEY_NOTIFY_OPEN_NETWORKS)) {
+            return false;
+        }
+        if (!(preference instanceof SwitchPreference)) {
+            return false;
+        }
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+                ((SwitchPreference) preference).isChecked() ? 1 : 0);
+        return true;
     }
 
     @Override
@@ -64,59 +93,40 @@
     }
 
     @Override
-    public boolean isAvailable() {
-        return getNotificationChannel() != null;
-    }
-
-    @Override
-    public boolean handlePreferenceTreeClick(Preference preference) {
-        if (!TextUtils.equals(preference.getKey(), KEY_NOTIFY_OPEN_NETWORKS)) {
-            return false;
-        }
-        NetworkScorerAppData scorer = mNetworkScoreManager.getActiveScorer();
-        if (scorer == null) {
-            return false;
-        }
-
-        Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
-        intent.putExtra(Settings.EXTRA_CHANNEL_ID,
-                scorer.getNetworkAvailableNotificationChannelId());
-        intent.putExtra(Settings.EXTRA_APP_PACKAGE, scorer.getRecommendationServicePackageName());
-        mContext.startActivity(intent);
-        return true;
-    }
-
-    @Override
     public void updateState(Preference preference) {
-        NotificationChannelWrapper channel = getNotificationChannel();
-        if (channel == null) {
-            preference.setSummary(null);
-        } else {
-            preference.setSummary(channel.getImportance() != NotificationManager.IMPORTANCE_NONE ?
-                    R.string.notification_toggle_on : R.string.notification_toggle_off);
+        if (!(preference instanceof SwitchPreference)) {
+            return;
         }
+        final SwitchPreference notifyOpenNetworks = (SwitchPreference) preference;
+        notifyOpenNetworks.setChecked(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
     }
 
-    @Nullable
-    private NotificationChannelWrapper getNotificationChannel() {
-        NetworkScorerAppData scorer = mNetworkScoreManager.getActiveScorer();
-        if (scorer == null) {
-            return null;
+    class SettingObserver extends ContentObserver {
+        private final Uri NETWORKS_AVAILABLE_URI = Settings.Global.getUriFor(
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON);
+
+        private final Preference mPreference;
+
+        public SettingObserver(Preference preference) {
+            super(new Handler());
+            mPreference = preference;
         }
-        String packageName = scorer.getRecommendationServicePackageName();
-        String channelId = scorer.getNetworkAvailableNotificationChannelId();
-        if (packageName == null || channelId == null) {
-            return null;
+
+        public void register(ContentResolver cr, boolean register) {
+            if (register) {
+                cr.registerContentObserver(NETWORKS_AVAILABLE_URI, false, this);
+            } else {
+                cr.unregisterContentObserver(this);
+            }
         }
-        try {
-            return mNotificationChannelHelper.getNotificationChannelForPackage(
-                    packageName,
-                    mPackageManager.getPackageUid(packageName, 0 /* flags */),
-                    channelId,
-                    false /* includeDeleted */ );
-        } catch (RemoteException | PackageManager.NameNotFoundException e) {
-            Log.d(TAG, "Failed to get notification channel.", e);
-            return null;
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            if (NETWORKS_AVAILABLE_URI.equals(uri)) {
+                updateState(mPreference);
+            }
         }
     }
 }
diff --git a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java
new file mode 100644
index 0000000..646774d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.fingerprint;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.verify;
+import static org.robolectric.RuntimeEnvironment.application;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback;
+import android.os.CancellationSignal;
+import android.widget.Button;
+
+import com.android.settings.ChooseLockSettingsHelper;
+import com.android.settings.R;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.password.IFingerprintManager;
+import com.android.settings.testutils.shadow.SettingsShadowResources;
+import com.android.settings.testutils.shadow.ShadowDynamicIndexableContentMonitor;
+import com.android.settings.testutils.shadow.ShadowEventLogWriter;
+import com.android.settings.testutils.shadow.ShadowUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowActivity;
+import org.robolectric.shadows.ShadowActivity.IntentForResult;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(
+        manifest = TestConfig.MANIFEST_PATH,
+        sdk = TestConfig.SDK_VERSION,
+        shadows = {
+                SettingsShadowResources.class,
+                SettingsShadowResources.SettingsShadowTheme.class,
+                ShadowDynamicIndexableContentMonitor.class,
+                ShadowEventLogWriter.class,
+                ShadowUtils.class
+        })
+public class FingerprintEnrollFindSensorTest {
+
+    @Mock
+    private IFingerprintManager mFingerprintManager;
+
+    private FingerprintEnrollFindSensor mActivity;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        ShadowUtils.setFingerprintManager(mFingerprintManager);
+
+        RuntimeEnvironment.getAppResourceLoader().getResourceIndex();
+
+        mActivity = Robolectric.buildActivity(
+                FingerprintEnrollFindSensor.class,
+                new Intent()
+                        // Set the challenge token so the confirm screen will not be shown
+                        .putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]))
+                .setup().get();
+    }
+
+    @After
+    public void tearDown() {
+        ShadowUtils.reset();
+    }
+
+    @Test
+    public void clickNextAndFingerprint_shouldNotCrash() {
+        ArgumentCaptor<EnrollmentCallback> callbackCaptor =
+                ArgumentCaptor.forClass(EnrollmentCallback.class);
+        verify(mFingerprintManager).enroll(
+                any(byte[].class),
+                any(CancellationSignal.class),
+                anyInt(),
+                anyInt(),
+                callbackCaptor.capture());
+
+        Button nextButton = mActivity.findViewById(R.id.next_button);
+        nextButton.performClick();
+        callbackCaptor.getValue().onEnrollmentProgress(123);
+        nextButton.performClick();
+
+        ShadowActivity shadowActivity = Shadows.shadowOf(mActivity);
+        IntentForResult startedActivity =
+                shadowActivity.getNextStartedActivityForResult();
+        assertThat(startedActivity).named("Next activity 1").isNotNull();
+        assertThat(startedActivity.intent.getComponent())
+                .isEqualTo(new ComponentName(application, FingerprintEnrollEnrolling.class));
+
+        // Should only start one next activity
+        assertThat(shadowActivity.getNextStartedActivityForResult()).named("Next activity 2")
+                .isNull();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
index 3556d09..3d5d5dc 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageSummaryTest.java
@@ -17,6 +17,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.os.Bundle;
 import android.os.PowerManager;
 import android.os.Process;
 import android.text.TextUtils;
@@ -128,8 +129,6 @@
     @Mock
     private LayoutPreference mBatteryLayoutPref;
     @Mock
-    private TextView mBatteryPercentText;
-    @Mock
     private TextView mSummary1;
     @Mock
     private BatteryInfo mBatteryInfo;
@@ -140,6 +139,7 @@
     @Mock
     private SettingsActivity mSettingsActivity;
 
+    private TextView mBatteryPercentText;
     private List<BatterySipper> mUsageList;
     private Context mRealContext;
     private TestFragment mFragment;
@@ -163,7 +163,7 @@
         mLastFullChargePref = new PowerGaugePreference(mRealContext);
         mFragment = spy(new TestFragment(mContext));
         mFragment.initFeatureProvider();
-        mBatteryMeterView = new BatteryMeterView(mRealContext);
+        mBatteryMeterView = spy(new BatteryMeterView(mRealContext));
         mBatteryMeterView.mDrawable = new BatteryMeterView.BatteryMeterDrawable(mRealContext, 0);
 
         when(mFragment.getActivity()).thenReturn(mSettingsActivity);
@@ -185,6 +185,7 @@
         mCellBatterySipper.drainType = BatterySipper.DrainType.CELL;
         mCellBatterySipper.totalPowerMah = POWER_MAH;
 
+        mBatteryPercentText = new TextView(mRealContext);
         when(mBatteryLayoutPref.findViewById(R.id.summary1)).thenReturn(mSummary1);
         when(mBatteryLayoutPref.findViewById(R.id.battery_percent)).thenReturn(mBatteryPercentText);
         when(mBatteryLayoutPref.findViewById(R.id.battery_header_icon))
@@ -278,6 +279,50 @@
     }
 
     @Test
+    public void testInitHeaderPreference_initCorrectly() {
+        mFragment.mBatteryLevel = 100;
+
+        mFragment.initHeaderPreference();
+
+        assertThat(mBatteryMeterView.getBatteryLevel()).isEqualTo(100);
+        assertThat(mBatteryPercentText.getText().toString()).isEqualTo("100%");
+    }
+
+    @Test
+    public void testStartBatteryHeaderAnimationIfNecessary_batteryLevelChanged_animationStarted() {
+        final int prevLevel = 100;
+        final int curLevel = 80;
+
+        mFragment.startBatteryHeaderAnimationIfNecessary(mBatteryMeterView, mBatteryPercentText,
+                prevLevel, curLevel);
+
+        assertThat(mBatteryMeterView.getBatteryLevel()).isEqualTo(curLevel);
+        assertThat(mBatteryPercentText.getText().toString()).isEqualTo("80%");
+    }
+
+    @Test
+    public void testOnSaveInstanceState_saveBatteryLevel() {
+        Bundle bundle = new Bundle();
+        mFragment.mBatteryLevel = BATTERY_LEVEL;
+        // mock it to stop crash in getPreferenceScreen
+        doReturn(null).when(mFragment).getPreferenceScreen();
+
+        mFragment.onSaveInstanceState(bundle);
+
+        assertThat(bundle.getInt(PowerUsageSummary.ARG_BATTERY_LEVEL)).isEqualTo(BATTERY_LEVEL);
+    }
+
+    @Test
+    public void testOnActivityCreated_setBatteryLevel() {
+        Bundle bundle = new Bundle();
+        bundle.putInt(PowerUsageSummary.ARG_BATTERY_LEVEL, BATTERY_LEVEL);
+
+        mFragment.onActivityCreated(bundle);
+
+        assertThat(mFragment.mBatteryLevel).isEqualTo(BATTERY_LEVEL);
+    }
+
+    @Test
     public void testExtractKeyFromSipper_typeAPPUidObjectNull_returnPackageNames() {
         mNormalBatterySipper.uidObj = null;
         mNormalBatterySipper.drainType = BatterySipper.DrainType.APP;
diff --git a/tests/robotests/src/com/android/settings/notification/BadgingNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/BadgingNotificationPreferenceControllerTest.java
new file mode 100644
index 0000000..618574c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/notification/BadgingNotificationPreferenceControllerTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.notification;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.TwoStatePreference;
+
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
+import static android.provider.Settings.Secure.NOTIFICATION_BADGING;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class BadgingNotificationPreferenceControllerTest {
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private PreferenceScreen mScreen;
+
+    private BadgingNotificationPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new BadgingNotificationPreferenceController(mContext);
+    }
+
+    @Test
+    public void display_configIsTrue_shouldDisplay() {
+        when(mContext.getResources().
+                getBoolean(com.android.internal.R.bool.config_notificationBadging))
+                .thenReturn(true);
+        mController.displayPreference(mScreen);
+
+        verify(mScreen, never()).removePreference(any(Preference.class));
+    }
+
+    @Test
+    public void display_configIsFalse_shouldNotDisplay() {
+        when(mContext.getResources().
+                getBoolean(com.android.internal.R.bool.config_notificationBadging))
+                .thenReturn(false);
+        final Preference preference = mock(Preference.class);
+        when(mScreen.getPreferenceCount()).thenReturn(1);
+        when(mScreen.getPreference(0)).thenReturn(preference);
+        when(preference.getKey()).thenReturn(mController.getPreferenceKey());
+
+        mController.displayPreference(mScreen);
+
+        verify(mScreen).removePreference(any(Preference.class));
+    }
+
+    @Test
+    public void updateState_preferenceSetCheckedWhenSettingIsOn() {
+        final TwoStatePreference preference = mock(TwoStatePreference.class);
+        final Context context = ShadowApplication.getInstance().getApplicationContext();
+        Settings.Secure.putInt(context.getContentResolver(), NOTIFICATION_BADGING, 1);
+
+        mController = new BadgingNotificationPreferenceController(context);
+        mController.updateState(preference);
+
+        verify(preference).setChecked(true);
+    }
+
+    @Test
+    public void updateState_preferenceSetUncheckedWhenSettingIsOff() {
+        final TwoStatePreference preference = mock(TwoStatePreference.class);
+        final Context context = ShadowApplication.getInstance().getApplicationContext();
+        Settings.Secure.putInt(context.getContentResolver(), NOTIFICATION_BADGING, 0);
+
+        mController = new BadgingNotificationPreferenceController(context);
+        mController.updateState(preference);
+
+        verify(preference).setChecked(false);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java b/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java
index 2296370..2e91ec6 100644
--- a/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/search2/SearchFragmentTest.java
@@ -349,4 +349,21 @@
 
         verify(fragment.mSavedQueryController).loadSavedQueries();
     }
+
+    @Test
+    public void onIndexingFinished_noActivity_shouldNotCrash() {
+        ActivityController<SearchActivity> activityController =
+            Robolectric.buildActivity(SearchActivity.class);
+        activityController.setup();
+        SearchFragment fragment = (SearchFragment) spy(activityController.get().getFragmentManager()
+            .findFragmentById(R.id.main_content));
+        when(mFeatureFactory.searchFeatureProvider.isIndexingComplete(any(Context.class)))
+            .thenReturn(true);
+        fragment.mQuery = "bright";
+        ReflectionHelpers.setField(fragment, "mLoaderManager", null);
+        ReflectionHelpers.setField(fragment, "mHost", null);
+
+        fragment.onIndexingFinished();
+        // no crash
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java b/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java
index 565aff9..cb02d3e 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/SettingsShadowResources.java
@@ -149,10 +149,14 @@
             // Replace all private string references with a placeholder.
             if (set != null) {
                 for (int i = 0; i < set.getAttributeCount(); ++i) {
-                    if (set.getAttributeValue(i).startsWith("@*android:string")) {
-                        Node node = ReflectionHelpers.callInstanceMethod(
-                                XmlResourceParserImpl.class, set, "getAttributeAt",
-                                ReflectionHelpers.ClassParameter.from(int.class, i));
+                    String attributeValue = set.getAttributeValue(i);
+                    Node node = ReflectionHelpers.callInstanceMethod(
+                            XmlResourceParserImpl.class, set, "getAttributeAt",
+                            ReflectionHelpers.ClassParameter.from(int.class, i));
+                    if (attributeValue.contains("attr/fingerprint_layout_theme")) {
+                        // Workaround for https://github.com/robolectric/robolectric/issues/2641
+                        node.setNodeValue("@style/FingerprintLayoutTheme");
+                    } else if (attributeValue.startsWith("@*android:string")) {
                         node.setNodeValue("PLACEHOLDER");
                     }
                 }
@@ -166,7 +170,6 @@
                     ReflectionHelpers.getField(assetManager, "appliedStyles");
             for (Long idx : appliedStylesList.keySet()) {
                 List<Object> appliedStyles = appliedStylesList.get(idx);
-                int i = 1;
                 for (Object appliedStyle : appliedStyles) {
                     StyleResolver styleResolver = ReflectionHelpers.getField(appliedStyle, "style");
                     List<StyleData> styleDatas =
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java
index 81cc607..eb82362 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 
 import com.android.settings.Utils;
+import com.android.settings.password.IFingerprintManager;
 
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
@@ -26,8 +27,23 @@
 @Implements(Utils.class)
 public class ShadowUtils {
 
+    private static IFingerprintManager sFingerprintManager = null;
+
     @Implementation
     public static int enforceSameOwner(Context context, int userId) {
         return userId;
     }
+
+    @Implementation
+    public static IFingerprintManager getFingerprintManagerWrapperOrNull(Context context) {
+        return sFingerprintManager;
+    }
+
+    public static void setFingerprintManager(IFingerprintManager fingerprintManager) {
+        sFingerprintManager = fingerprintManager;
+    }
+
+    public static void reset() {
+        sFingerprintManager = null;
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java
index 78dbcbd..75b304e 100644
--- a/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java
@@ -16,29 +16,25 @@
 
 package com.android.settings.wifi;
 
-import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.when;
+import static android.provider.Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON;
 
-import android.app.NotificationManager;
-import android.content.ComponentName;
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
 import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.NetworkScorerAppData;
-import android.os.RemoteException;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
 import android.support.v7.preference.Preference;
-import com.android.settings.R;
+
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
-import com.android.settings.network.NetworkScoreManagerWrapper;
-import com.android.settings.utils.NotificationChannelHelper;
-import com.android.settings.utils.NotificationChannelHelper.NotificationChannelWrapper;
+import com.android.settings.core.lifecycle.Lifecycle;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
@@ -47,123 +43,67 @@
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class NotifyOpenNetworkPreferenceControllerTest {
 
-    private static final String TEST_SCORER_PACKAGE = "Test Package";
-    private static final String TEST_SCORER_CLASS = "Test Class";
-    private static final String TEST_SCORER_LABEL = "Test Label";
-    private static final String NOTIFICATION_ID = "Notification Id";
-    private static final CharSequence NOTIFICATION_NAME = "Notification Name";
-
     private Context mContext;
     private NotifyOpenNetworksPreferenceController mController;
-    @Mock private NetworkScoreManagerWrapper mNetworkScorer;
-    @Mock private NotificationChannelHelper mNotificationChannelHelper;
-    @Mock private PackageManager mPackageManager;
-    @Mock private NotificationChannelWrapper mChannel;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         mContext = RuntimeEnvironment.application;
-        mController = new NotifyOpenNetworksPreferenceController(
-                mContext, mNetworkScorer, mNotificationChannelHelper, mPackageManager);
-        ComponentName scorer = new ComponentName(TEST_SCORER_PACKAGE, TEST_SCORER_CLASS);
-
-        NetworkScorerAppData scorerAppData = new NetworkScorerAppData(
-                0, scorer, TEST_SCORER_LABEL, null /* enableUseOpenWifiActivity */,
-                NOTIFICATION_ID);
-        when(mNetworkScorer.getActiveScorer()).thenReturn(scorerAppData);
+        mController = new NotifyOpenNetworksPreferenceController(mContext, mock(Lifecycle.class));
     }
 
     @Test
-    public void testIsAvailable_shouldReturnFalseWhenScorerDoesNotExist()
-            throws RemoteException {
-        when(mNetworkScorer.getActiveScorer()).thenReturn(null);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void testIsAvailable_shouldReturnFalseWhenNotificationChannelIdDoesNotExist()
-            throws RemoteException {
-        ComponentName scorer = new ComponentName(TEST_SCORER_PACKAGE, TEST_SCORER_CLASS);
-        NetworkScorerAppData scorerAppData = new NetworkScorerAppData(
-                0, scorer, TEST_SCORER_LABEL, null /* enableUseOpenWifiActivity */,
-                null /* networkAvailableNotificationChannelId */);
-        when(mNetworkScorer.getActiveScorer()).thenReturn(scorerAppData);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void testIsAvailable_shouldReturnFalseWhenNotificationChannelDoesNotExist()
-            throws RemoteException {
-        when(mNotificationChannelHelper.getNotificationChannelForPackage(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(null);
-
-        assertThat(mController.isAvailable()).isFalse();
-    }
-
-    @Test
-    public void testIsAvailable_shouldReturnTrueWhenNotificationChannelExists()
-            throws RemoteException {
-        when(mNotificationChannelHelper.getNotificationChannelForPackage(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(mChannel);
-
+    public void testIsAvailable_shouldAlwaysReturnTrue() {
         assertThat(mController.isAvailable()).isTrue();
     }
 
     @Test
     public void handlePreferenceTreeClick_nonMatchingKey_shouldDoNothing() {
-        final Preference pref = new Preference(mContext);
+        final SwitchPreference pref = new SwitchPreference(mContext);
 
         assertThat(mController.handlePreferenceTreeClick(pref)).isFalse();
     }
 
     @Test
-    public void handlePreferenceTreeClick_nullScorer_shouldDoNothing() {
+    public void handlePreferenceTreeClick_nonMatchingType_shouldDoNothing() {
         final Preference pref = new Preference(mContext);
         pref.setKey(mController.getPreferenceKey());
-        when(mNetworkScorer.getActiveScorer()).thenReturn(null);
 
         assertThat(mController.handlePreferenceTreeClick(pref)).isFalse();
     }
 
     @Test
-    public void handlePreferenceTreeClick_matchingKeyAndScorerExists_shouldLaunchActivity()
-            throws RemoteException {
-        final Preference pref = new Preference(mContext);
+    public void handlePreferenceTreeClick_matchingKeyAndType_shouldUpdateSetting() {
+        final SwitchPreference pref = new SwitchPreference(mContext);
+        pref.setChecked(true);
         pref.setKey(mController.getPreferenceKey());
-        when(mNotificationChannelHelper.getNotificationChannelForPackage(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(mChannel);
 
         assertThat(mController.handlePreferenceTreeClick(pref)).isTrue();
+        assertThat(Settings.Global.getInt(mContext.getContentResolver(),
+                WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0))
+                .isEqualTo(1);
     }
 
     @Test
-    public void updateState_notificationsEnabled_shouldShowEnabledSummary() throws RemoteException {
-        final Preference pref = new Preference(mContext);
-        pref.setKey(mController.getPreferenceKey());
-        when(mNotificationChannelHelper.getNotificationChannelForPackage(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(mChannel);
-        when(mChannel.getImportance()).thenReturn(NotificationManager.IMPORTANCE_DEFAULT);
-        mController.updateState(pref);
+    public void updateState_preferenceSetCheckedWhenSettingsAreEnabled() {
+        final SwitchPreference preference = mock(SwitchPreference.class);
+        Settings.System.putInt(mContext.getContentResolver(),
+                WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 1);
 
-        assertThat(pref.getSummary()).isEqualTo(
-                mContext.getString(R.string.notification_toggle_on));
+        mController.updateState(preference);
+
+        verify(preference).setChecked(true);
     }
 
     @Test
-    public void updateState_notificationsEnabled_shouldShowDisabledSummary()
-            throws RemoteException {
-        final Preference pref = new Preference(mContext);
-        pref.setKey(mController.getPreferenceKey());
-        when(mNotificationChannelHelper.getNotificationChannelForPackage(
-                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(mChannel);
-        when(mChannel.getImportance()).thenReturn(NotificationManager.IMPORTANCE_NONE);
-        mController.updateState(pref);
+    public void updateState_preferenceSetCheckedWhenSettingsAreDisabled() {
+        final SwitchPreference preference = mock(SwitchPreference.class);
+        Settings.System.putInt(mContext.getContentResolver(),
+                WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0);
 
-        assertThat(pref.getSummary()).isEqualTo(
-                mContext.getString(R.string.notification_toggle_off));
+        mController.updateState(preference);
+
+        verify(preference).setChecked(false);
     }
-
 }