Merge "Remove summary template in sleep timeout setting." into oc-dev
diff --git a/res/layout/enable_accessibility_service_dialog_content.xml b/res/layout/enable_accessibility_service_dialog_content.xml
index 3ca40ac..f212eb1 100644
--- a/res/layout/enable_accessibility_service_dialog_content.xml
+++ b/res/layout/enable_accessibility_service_dialog_content.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
+    android:textDirection="locale"
     android:scrollbarStyle="outsideOverlay"
     android:gravity="top">
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 58703a5..28c6b4b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4304,6 +4304,11 @@
          can't verify user consent. [CHAR LIMIT=NONE] -->
     <string name="touch_filtered_warning">Because an app is obscuring a permission request, Settings
         can’t verify your response.</string>
+    <!-- Warning shown when user input has been blocked due to another app overlaying screen
+         content. Since we don't know what the app is showing on top of the input target, we
+         can't verify user consent. [CHAR LIMIT=NONE] -->
+    <string name="window_obscured_warning">Because another app is displaying on top of these options,
+        Settings can\u2019t respond to your action.</string>
     <!-- Warning that the device data will not be encrypted with password or PIN if
         enabling an accessibility service and there is a secure lock setup. [CHAR LIMIT=NONE] -->
     <string name="enable_service_encryption_warning">If you turn on <xliff:g id="service"
diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java
index fb2f29f..3bb82cf 100644
--- a/src/com/android/settings/DeviceAdminAdd.java
+++ b/src/com/android/settings/DeviceAdminAdd.java
@@ -65,6 +65,8 @@
 import com.android.settings.users.UserDialogs;
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import com.android.settingslib.SecureTouchListener;
+
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
@@ -350,6 +352,8 @@
 
         final View restrictedAction = findViewById(R.id.restricted_action);
         restrictedAction.setFilterTouchesWhenObscured(true);
+        restrictedAction.setOnTouchListener(
+                new SecureTouchListener(getString(R.string.window_obscured_warning)));
         restrictedAction.setOnClickListener(new View.OnClickListener() {
             public void onClick(View v) {
                 if (mAdding) {
diff --git a/src/com/android/settings/accessibility/AccessibilityServiceWarning.java b/src/com/android/settings/accessibility/AccessibilityServiceWarning.java
index 9f89bc1..e0c58db 100644
--- a/src/com/android/settings/accessibility/AccessibilityServiceWarning.java
+++ b/src/com/android/settings/accessibility/AccessibilityServiceWarning.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.os.storage.StorageManager;
+import android.text.BidiFormatter;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -34,6 +35,7 @@
 import com.android.settings.R;
 
 import java.util.List;
+import java.util.Locale;
 
 /**
  * Utility class for creating the dialog that asks users for explicit permission to grant
@@ -44,7 +46,7 @@
             AccessibilityServiceInfo info, DialogInterface.OnClickListener listener) {
         final AlertDialog ad = new AlertDialog.Builder(parentActivity)
                 .setTitle(parentActivity.getString(R.string.enable_service_title,
-                        info.getResolveInfo().loadLabel(parentActivity.getPackageManager())))
+                        getServiceName(parentActivity, info)))
                 .setView(createEnableDialogContentView(parentActivity, info))
                 .setCancelable(true)
                 .setPositiveButton(android.R.string.ok, listener)
@@ -97,7 +99,7 @@
                 R.id.encryption_warning);
         if (isFullDiskEncrypted()) {
             String text = context.getString(R.string.enable_service_encryption_warning,
-                    info.getResolveInfo().loadLabel(context.getPackageManager()));
+                    getServiceName(context, info));
             encryptionWarningView.setText(text);
             encryptionWarningView.setVisibility(View.VISIBLE);
         } else {
@@ -107,7 +109,7 @@
         TextView capabilitiesHeaderView = (TextView) content.findViewById(
                 R.id.capabilities_header);
         capabilitiesHeaderView.setText(context.getString(R.string.capabilities_list_title,
-                info.getResolveInfo().loadLabel(context.getPackageManager())));
+                getServiceName(context, info)));
 
         LinearLayout capabilitiesView = (LinearLayout) content.findViewById(R.id.capabilities);
 
@@ -161,4 +163,12 @@
 
         return content;
     }
+
+    // Get the service name and bidi wrap it to protect from bidi side effects.
+    private static CharSequence getServiceName(Context context, AccessibilityServiceInfo info) {
+        final Locale locale = context.getResources().getConfiguration().getLocales().get(0);
+        final CharSequence label =
+                info.getResolveInfo().loadLabel(context.getPackageManager());
+        return BidiFormatter.getInstance(locale).unicodeWrap(label);
+    }
 }
diff --git a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
index 51225aa..2499478 100644
--- a/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
+++ b/src/com/android/settings/applications/AppAndNotificationDashboardFragment.java
@@ -23,6 +23,7 @@
 import com.android.settings.R;
 import com.android.settings.core.PreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.notification.EmergencyBroadcastPreferenceController;
 import com.android.settings.search.BaseSearchIndexProvider;
 
 import java.util.ArrayList;
@@ -61,6 +62,8 @@
 
     private static List<PreferenceController> buildPreferenceControllers(Context context) {
         final List<PreferenceController> controllers = new ArrayList<>();
+        controllers.add(new EmergencyBroadcastPreferenceController(context,
+                "app_and_notif_cell_broadcast_settings"));
         controllers.add(new SpecialAppAccessPreferenceController(context));
         return controllers;
     }
diff --git a/src/com/android/settings/applications/AppCounter.java b/src/com/android/settings/applications/AppCounter.java
index 8758b14..8eff526 100644
--- a/src/com/android/settings/applications/AppCounter.java
+++ b/src/com/android/settings/applications/AppCounter.java
@@ -32,7 +32,7 @@
 
     public AppCounter(Context context, PackageManagerWrapper packageManager) {
         mPm = packageManager;
-        mUm = UserManager.get(context);
+        mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
     }
 
     @Override
diff --git a/src/com/android/settings/applications/AppStateAppOpsBridge.java b/src/com/android/settings/applications/AppStateAppOpsBridge.java
index cfbb2fc..420d955 100644
--- a/src/com/android/settings/applications/AppStateAppOpsBridge.java
+++ b/src/com/android/settings/applications/AppStateAppOpsBridge.java
@@ -19,12 +19,12 @@
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.PackageOps;
 import android.content.Context;
-import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
@@ -46,7 +46,7 @@
 
     private static final String TAG = "AppStateAppOpsBridge";
 
-    private final IPackageManager mIPackageManager;
+    private final IPackageManagerWrapper mIPackageManager;
     private final UserManager mUserManager;
     private final List<UserHandle> mProfiles;
     private final AppOpsManager mAppOpsManager;
@@ -56,9 +56,16 @@
 
     public AppStateAppOpsBridge(Context context, ApplicationsState appState, Callback callback,
             int appOpsOpCode, String[] permissions) {
+        this(context, appState, callback, appOpsOpCode, permissions,
+            new IPackageManagerWrapperImpl(AppGlobals.getPackageManager()));
+    }
+
+    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+    AppStateAppOpsBridge(Context context, ApplicationsState appState, Callback callback,
+            int appOpsOpCode, String[] permissions, IPackageManagerWrapper packageManager) {
         super(appState, callback);
         mContext = context;
-        mIPackageManager = AppGlobals.getPackageManager();
+        mIPackageManager = packageManager;
         mUserManager = UserManager.get(context);
         mProfiles = mUserManager.getUserProfiles();
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
@@ -92,18 +99,21 @@
                 .getUserId(uid)));
         try {
             permissionState.packageInfo = mIPackageManager.getPackageInfo(pkg,
-                    PackageManager.GET_PERMISSIONS | PackageManager.MATCH_UNINSTALLED_PACKAGES,
+                    PackageManager.GET_PERMISSIONS | PackageManager.MATCH_ANY_USER,
                     permissionState.userHandle.getIdentifier());
-            // Check static permission state (whatever that is declared in package manifest)
-            String[] requestedPermissions = permissionState.packageInfo.requestedPermissions;
-            int[] permissionFlags = permissionState.packageInfo.requestedPermissionsFlags;
-            if (requestedPermissions != null) {
-                for (int i = 0; i < requestedPermissions.length; i++) {
-                    if (doesAnyPermissionMatch(requestedPermissions[i], mPermissions)) {
-                        permissionState.permissionDeclared = true;
-                        if ((permissionFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
-                            permissionState.staticPermissionGranted = true;
-                            break;
+            if (permissionState.packageInfo != null) {
+                // Check static permission state (whatever that is declared in package manifest)
+                String[] requestedPermissions = permissionState.packageInfo.requestedPermissions;
+                int[] permissionFlags = permissionState.packageInfo.requestedPermissionsFlags;
+                if (requestedPermissions != null) {
+                    for (int i = 0; i < requestedPermissions.length; i++) {
+                        if (doesAnyPermissionMatch(requestedPermissions[i], mPermissions)) {
+                            permissionState.permissionDeclared = true;
+                            if ((permissionFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED)
+                                    != 0) {
+                                permissionState.staticPermissionGranted = true;
+                                break;
+                            }
                         }
                     }
                 }
diff --git a/src/com/android/settings/applications/IPackageManagerWrapper.java b/src/com/android/settings/applications/IPackageManagerWrapper.java
index f885985..b4d1b85 100644
--- a/src/com/android/settings/applications/IPackageManagerWrapper.java
+++ b/src/com/android/settings/applications/IPackageManagerWrapper.java
@@ -17,6 +17,8 @@
 package com.android.settings.applications;
 
 import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.os.RemoteException;
 
@@ -41,4 +43,33 @@
      * @see android.content.pm.IPackageManager#findPersistentPreferredActivity
      */
     ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) throws RemoteException;
+
+    /**
+     * Calls {@code IPackageManager.getPackageInfo()}.
+     *
+     * @see android.content.pm.IPackageManager#getPackageInfo
+     */
+    PackageInfo getPackageInfo(String packageName, int flags, int userId) throws RemoteException;
+
+    /**
+     * Calls {@code IPackageManager.getAppOpPermissionPackages()}.
+     *
+     * @see android.content.pm.IPackageManager#getAppOpPermissionPackages
+     */
+    String[] getAppOpPermissionPackages(String permissionName) throws RemoteException;
+
+    /**
+     * Calls {@code IPackageManager.isPackageAvailable()}.
+     *
+     * @see android.content.pm.IPackageManager#isPackageAvailable
+     */
+    boolean isPackageAvailable(String packageName, int userId) throws RemoteException;
+
+    /**
+     * Calls {@code IPackageManager.getPackagesHoldingPermissions()}.
+     *
+     * @see android.content.pm.IPackageManager#getPackagesHoldingPermissions
+     */
+    ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
+        String[] permissions, int flags, int userId) throws RemoteException;
 }
diff --git a/src/com/android/settings/applications/IPackageManagerWrapperImpl.java b/src/com/android/settings/applications/IPackageManagerWrapperImpl.java
index 5ea15b9..af5f378 100644
--- a/src/com/android/settings/applications/IPackageManagerWrapperImpl.java
+++ b/src/com/android/settings/applications/IPackageManagerWrapperImpl.java
@@ -18,6 +18,8 @@
 
 import android.content.Intent;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.os.RemoteException;
 
@@ -39,4 +41,27 @@
             throws RemoteException {
         return mPms.findPersistentPreferredActivity(intent, userId);
     }
+
+    @Override
+    public PackageInfo getPackageInfo(String packageName, int flags, int userId)
+            throws RemoteException {
+        return mPms.getPackageInfo(packageName, flags, userId);
+    }
+
+    @Override
+    public String[] getAppOpPermissionPackages(String permissionName) throws RemoteException {
+        return mPms.getAppOpPermissionPackages(permissionName);
+    }
+
+    @Override
+    public boolean isPackageAvailable(String packageName, int userId) throws RemoteException {
+        return mPms.isPackageAvailable(packageName, userId);
+    }
+
+    @Override
+    public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
+        String[] permissions, int flags, int userId) throws RemoteException {
+        return mPms.getPackagesHoldingPermissions(permissions, flags, userId);
+    }
+
 }
diff --git a/src/com/android/settings/applications/RunningState.java b/src/com/android/settings/applications/RunningState.java
index dd44887..d4abe6c 100644
--- a/src/com/android/settings/applications/RunningState.java
+++ b/src/com/android/settings/applications/RunningState.java
@@ -500,7 +500,7 @@
                 si.mRunningService = service;
                 try {
                     si.mServiceInfo = ActivityThread.getPackageManager().getServiceInfo(
-                            service.service, PackageManager.MATCH_UNINSTALLED_PACKAGES,
+                            service.service, PackageManager.MATCH_ANY_USER,
                             UserHandle.getUserId(service.uid));
 
                     if (si.mServiceInfo == null) {
diff --git a/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java b/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java
index 718094e..6dcf7b8 100644
--- a/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java
+++ b/src/com/android/settings/applications/defaultapps/DefaultAutofillPicker.java
@@ -181,7 +181,14 @@
     }
 
     public static String getDefaultKey(Context context) {
-        return Settings.Secure.getString(context.getContentResolver(), SETTING);
+        String setting = Settings.Secure.getString(context.getContentResolver(), SETTING);
+        if (setting != null) {
+            ComponentName componentName = ComponentName.unflattenFromString(setting);
+            if (componentName != null) {
+                return componentName.flattenToString();
+            }
+        }
+        return null;
     }
 
     @Override
diff --git a/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java b/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java
index 6c23b39..69f174b 100644
--- a/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java
+++ b/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java
@@ -144,7 +144,7 @@
             } catch (Exception e) {
             }
             try {
-                pm.getPackageInfo(value, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                pm.getPackageInfo(value, PackageManager.MATCH_ANY_USER);
                 logPackageName(key, value);
             } catch (PackageManager.NameNotFoundException e) {
                 // Clearly not a package, and it's unlikely this preference is in prefSet, so
diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
index ac54c17..4ce785a 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
@@ -300,6 +300,10 @@
     }
 
     private Intent getAudioIntent() {
+        if (mVolume == null) {
+            return null;
+        }
+
         Bundle args = new Bundle();
         args.putString(ManageApplications.EXTRA_CLASSNAME,
                 Settings.StorageUseActivity.class.getName());
@@ -312,6 +316,10 @@
     }
 
     private Intent getAppsIntent() {
+        if (mVolume == null) {
+            return null;
+        }
+
         Bundle args = new Bundle();
         args.putString(ManageApplications.EXTRA_CLASSNAME,
                 Settings.StorageUseActivity.class.getName());
diff --git a/src/com/android/settings/network/TetherPreferenceController.java b/src/com/android/settings/network/TetherPreferenceController.java
index f23118a..19a22ba 100644
--- a/src/com/android/settings/network/TetherPreferenceController.java
+++ b/src/com/android/settings/network/TetherPreferenceController.java
@@ -19,8 +19,12 @@
 import android.bluetooth.BluetoothPan;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
+import android.database.ContentObserver;
 import android.net.ConnectivityManager;
+import android.net.Uri;
+import android.os.Handler;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.support.annotation.VisibleForTesting;
 import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceScreen;
@@ -31,6 +35,8 @@
 import com.android.settings.core.lifecycle.Lifecycle;
 import com.android.settings.core.lifecycle.LifecycleObserver;
 import com.android.settings.core.lifecycle.events.OnDestroy;
+import com.android.settings.core.lifecycle.events.OnPause;
+import com.android.settings.core.lifecycle.events.OnResume;
 
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -39,7 +45,7 @@
 import static com.android.settingslib.RestrictedLockUtils.hasBaseUserRestriction;
 
 public class TetherPreferenceController extends PreferenceController
-        implements LifecycleObserver, OnDestroy {
+        implements LifecycleObserver, OnResume, OnPause, OnDestroy {
 
     private static final String KEY_TETHER_SETTINGS = "tether_settings";
 
@@ -47,7 +53,6 @@
     private final AtomicReference<BluetoothPan> mBluetoothPan;
     private final ConnectivityManager mConnectivityManager;
     private final BluetoothAdapter mBluetoothAdapter;
-
     private final BluetoothProfile.ServiceListener mBtProfileServiceListener =
             new android.bluetooth.BluetoothProfile.ServiceListener() {
                 public void onServiceConnected(int profile, BluetoothProfile proxy) {
@@ -60,6 +65,7 @@
                 }
             };
 
+    private SettingObserver mAirplaneModeObserver;
     private Preference mPreference;
 
     @VisibleForTesting(otherwise = VisibleForTesting.NONE)
@@ -121,6 +127,22 @@
     }
 
     @Override
+    public void onResume() {
+        if (mAirplaneModeObserver == null) {
+            mAirplaneModeObserver = new SettingObserver();
+        }
+        mContext.getContentResolver()
+                .registerContentObserver(mAirplaneModeObserver.uri, false, mAirplaneModeObserver);
+    }
+
+    @Override
+    public void onPause() {
+        if (mAirplaneModeObserver != null) {
+            mContext.getContentResolver().unregisterContentObserver(mAirplaneModeObserver);
+        }
+    }
+
+    @Override
     public void onDestroy() {
         final BluetoothProfile profile = mBluetoothPan.getAndSet(null);
         if (profile != null && mBluetoothAdapter != null) {
@@ -128,7 +150,7 @@
         }
     }
 
-    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    @VisibleForTesting
     void updateSummary() {
         if (mPreference == null) {
             // Preference is not ready yet.
@@ -183,4 +205,37 @@
             mPreference.setSummary(R.string.tether_settings_summary_hotspot_off_tether_on);
         }
     }
+
+    private void updateSummaryToOff() {
+        if (mPreference == null) {
+            // Preference is not ready yet.
+            return;
+        }
+        mPreference.setSummary(R.string.switch_off_text);
+    }
+
+    class SettingObserver extends ContentObserver {
+
+        public final Uri uri;
+
+        public SettingObserver() {
+            super(new Handler());
+            uri = Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            if (this.uri.equals(uri)) {
+                boolean isAirplaneMode = Settings.Global.getInt(mContext.getContentResolver(),
+                        Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+                if (isAirplaneMode) {
+                    // Airplane mode is on. Update summary to say tether is OFF directly. We cannot
+                    // go through updateSummary() because turning off tether takes time, and we
+                    // might still get "ON" status when rerun updateSummary(). So, just say it's off
+                    updateSummaryToOff();
+                }
+            }
+        }
+    }
 }
diff --git a/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java b/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java
index 8f26ed8..39250c6 100644
--- a/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java
+++ b/src/com/android/settings/notification/EmergencyBroadcastPreferenceController.java
@@ -20,9 +20,9 @@
 import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.support.annotation.VisibleForTesting;
 import android.support.v7.preference.Preference;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.accounts.AccountRestrictionHelper;
 import com.android.settings.core.PreferenceController;
 import com.android.settingslib.RestrictedPreference;
@@ -33,20 +33,22 @@
  */
 public class EmergencyBroadcastPreferenceController extends PreferenceController {
 
-    private static final String KEY_CELL_BROADCAST_SETTINGS = "cell_broadcast_settings";
+    private final String mPrefKey;
 
     private AccountRestrictionHelper mHelper;
     private UserManager mUserManager;
     private PackageManager mPm;
     private boolean mCellBroadcastAppLinkEnabled;
 
-    public EmergencyBroadcastPreferenceController(Context context) {
-        this(context, new AccountRestrictionHelper(context));
+    public EmergencyBroadcastPreferenceController(Context context, String prefKey) {
+        this(context, new AccountRestrictionHelper(context), prefKey);
     }
 
-    @VisibleForTesting
-    EmergencyBroadcastPreferenceController(Context context, AccountRestrictionHelper helper) {
+    @VisibleForTesting(otherwise = VisibleForTesting.NONE)
+    EmergencyBroadcastPreferenceController(Context context, AccountRestrictionHelper helper,
+            String prefKey) {
         super(context);
+        mPrefKey = prefKey;
         mHelper = helper;
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mPm = mContext.getPackageManager();
@@ -60,7 +62,7 @@
             return;
         }
         ((RestrictedPreference) preference).checkRestrictionAndSetDisabled(
-            UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
+                UserManager.DISALLOW_CONFIG_CELL_BROADCASTS);
     }
 
     @Override
@@ -70,23 +72,23 @@
 
     @Override
     public String getPreferenceKey() {
-        return KEY_CELL_BROADCAST_SETTINGS;
+        return mPrefKey;
     }
 
     @Override
     public boolean isAvailable() {
         return mUserManager.isAdminUser() && mCellBroadcastAppLinkEnabled
-            && !mHelper.hasBaseUserRestriction(
+                && !mHelper.hasBaseUserRestriction(
                 UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, UserHandle.myUserId());
     }
 
     private boolean isCellBroadcastAppLinkEnabled() {
         boolean enabled = mContext.getResources().getBoolean(
-            com.android.internal.R.bool.config_cellBroadcastAppLinks);
+                com.android.internal.R.bool.config_cellBroadcastAppLinks);
         if (enabled) {
             try {
                 if (mPm.getApplicationEnabledSetting("com.android.cellbroadcastreceiver")
-                    == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
+                        == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
                     enabled = false;  // CMAS app disabled
                 }
             } catch (IllegalArgumentException ignored) {
diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java
index 0e30940..a92c5dd 100644
--- a/src/com/android/settings/notification/SoundSettings.java
+++ b/src/com/android/settings/notification/SoundSettings.java
@@ -186,7 +186,8 @@
             Lifecycle lifecycle) {
         final List<PreferenceController> controllers = new ArrayList<>();
         controllers.add(new ZenModePreferenceController(context));
-        controllers.add(new EmergencyBroadcastPreferenceController(context));
+        controllers.add(new EmergencyBroadcastPreferenceController(
+                context, "cell_broadcast_settings"));
         controllers.add(new VibrateWhenRingPreferenceController(context));
 
         // === Volumes ===
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 341daa1..dd1e4a4 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -15,6 +15,9 @@
  */
 package com.android.settings.wifi.details;
 
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
 import android.app.Fragment;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -28,8 +31,8 @@
 import android.net.Network;
 import android.net.NetworkBadging;
 import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
 import android.net.NetworkInfo;
+import android.net.NetworkRequest;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.wifi.WifiConfiguration;
@@ -41,19 +44,21 @@
 import android.support.v7.preference.PreferenceScreen;
 import android.text.TextUtils;
 import android.util.Log;
-import android.widget.Button;
 import android.view.View;
+import android.widget.Button;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.applications.LayoutPreference;
 import com.android.settings.core.PreferenceController;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
 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;
-import com.android.settings.wifi.WifiDetailPreference;
 import com.android.settings.vpn2.ConnectivityManagerWrapper;
+import com.android.settings.wifi.WifiDetailPreference;
 import com.android.settingslib.wifi.AccessPoint;
 
 import java.net.Inet4Address;
@@ -63,9 +68,6 @@
 import java.util.List;
 import java.util.StringJoiner;
 
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
-
 /**
  * Controller for logic pertaining to displaying Wifi information for the
  * {@link WifiNetworkDetailsFragment}.
@@ -115,10 +117,12 @@
     private final WifiConfiguration mWifiConfig;
     private WifiInfo mWifiInfo;
     private final WifiManager mWifiManager;
+    private final MetricsFeatureProvider mMetricsFeatureProvider;
 
     // UI elements - in order of appearance
     private Preference mConnectionDetailPref;
     private LayoutPreference mButtonsPref;
+    private Button mForgetButton;
     private Button mSignInButton;
     private WifiDetailPreference mSignalStrengthPref;
     private WifiDetailPreference mLinkSpeedPref;
@@ -129,8 +133,8 @@
     private WifiDetailPreference mGatewayPref;
     private WifiDetailPreference mSubnetPref;
     private WifiDetailPreference mDnsPref;
-    private PreferenceCategory mIpv6AddressCategory;
 
+    private PreferenceCategory mIpv6AddressCategory;
     private final IntentFilter mFilter;
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
@@ -179,7 +183,8 @@
             Fragment fragment,
             Handler handler,
             Lifecycle lifecycle,
-            WifiManager wifiManager) {
+            WifiManager wifiManager,
+            MetricsFeatureProvider metricsFeatureProvider) {
         super(context);
 
         mAccessPoint = accessPoint;
@@ -187,11 +192,10 @@
         mConnectivityManagerWrapper = connectivityManagerWrapper;
         mFragment = fragment;
         mHandler = handler;
-        mNetworkInfo = accessPoint.getNetworkInfo();
-        mRssi = accessPoint.getRssi();
         mSignalStr = context.getResources().getStringArray(R.array.wifi_signal);
         mWifiConfig = accessPoint.getConfig();
         mWifiManager = wifiManager;
+        mMetricsFeatureProvider = metricsFeatureProvider;
 
         mFilter = new IntentFilter();
         mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
@@ -241,22 +245,18 @@
                 (PreferenceCategory) screen.findPreference(KEY_IPV6_ADDRESS_CATEGORY);
 
         mSecurityPref.setDetailText(mAccessPoint.getSecurityString(false /* concise */));
-    }
-
-    public WifiInfo getWifiInfo() {
-        return mWifiInfo;
+        mForgetButton = (Button) mButtonsPref.findViewById(R.id.left_button);
+        mForgetButton.setText(R.string.forget);
+        mForgetButton.setOnClickListener(view -> forgetNetwork());
+        updateInfo();
     }
 
     @Override
     public void onResume() {
         mConnectivityManagerWrapper.registerNetworkCallback(mNetworkRequest, mNetworkCallback,
                 mHandler);
-        mNetwork = mWifiManager.getCurrentNetwork();
-        mLinkProperties = mConnectivityManager.getLinkProperties(mNetwork);
-        mNetworkCapabilities = mConnectivityManager.getNetworkCapabilities(mNetwork);
-
-        updateInfo();
-
+        // updateInfo() will be called during registration because NETWORK_STATE_CHANGED_ACTION is
+        // a sticky broadcast.
         mContext.registerReceiver(mReceiver, mFilter);
     }
 
@@ -265,11 +265,16 @@
         mNetwork = null;
         mLinkProperties = null;
         mNetworkCapabilities = null;
+        mNetworkInfo = null;
+        mWifiInfo = null;
         mContext.unregisterReceiver(mReceiver);
         mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);
     }
 
     private void updateInfo() {
+        mNetwork = mWifiManager.getCurrentNetwork();
+        mLinkProperties = mConnectivityManager.getLinkProperties(mNetwork);
+        mNetworkCapabilities = mConnectivityManager.getNetworkCapabilities(mNetwork);
         mNetworkInfo = mConnectivityManager.getNetworkInfo(mNetwork);
         mWifiInfo = mWifiManager.getConnectionInfo();
         if (mNetwork == null || mNetworkInfo == null || mWifiInfo == null) {
@@ -277,6 +282,9 @@
             return;
         }
 
+        // Update whether the forgot button should be displayed.
+        mForgetButton.setVisibility(canForgetNetwork() ? View.VISIBLE : View.INVISIBLE);
+
         refreshNetworkState();
 
         // Update Connection Header icon and Signal Strength Preference
@@ -307,6 +315,8 @@
         mFrequencyPref.setDetailText(band);
 
         updateIpLayerInfo();
+        mButtonsPref.setVisible(mForgetButton.getVisibility() == View.VISIBLE
+                || mSignInButton.getVisibility() == View.VISIBLE);
     }
 
     private void exitActivity() {
@@ -422,7 +432,7 @@
     /**
      * Returns whether the network represented by this preference can be forgotten.
      */
-    public boolean canForgetNetwork() {
+    private boolean canForgetNetwork() {
         return mWifiInfo != null && mWifiInfo.isEphemeral() || mWifiConfig != null;
     }
 
@@ -437,7 +447,7 @@
     /**
      * Forgets the wifi network associated with this preference.
      */
-    public void forgetNetwork() {
+    private void forgetNetwork() {
         if (mWifiInfo != null && mWifiInfo.isEphemeral()) {
             mWifiManager.disableEphemeralNetwork(mWifiInfo.getSSID());
         } else if (mWifiConfig != null) {
@@ -447,6 +457,8 @@
                 mWifiManager.forget(mWifiConfig.networkId, null /* action listener */);
             }
         }
+        mMetricsFeatureProvider.action(
+                mFragment.getActivity(), MetricsProto.MetricsEvent.ACTION_WIFI_FORGET);
         mFragment.getActivity().finish();
     }
 }
diff --git a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
index fe16cdb..664ac7f 100644
--- a/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
+++ b/src/com/android/settings/wifi/details/WifiNetworkDetailsFragment.java
@@ -17,17 +17,13 @@
 
 import android.content.Context;
 import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.NetworkRequest;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
-import android.widget.Button;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
-import com.android.settings.applications.LayoutPreference;
 import com.android.settings.core.PreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.vpn2.ConnectivityManagerWrapperImpl;
@@ -46,7 +42,6 @@
     private static final String TAG = "WifiNetworkDetailsFrg";
 
     private AccessPoint mAccessPoint;
-    private Button mForgetButton;
     private WifiDetailPreferenceController mWifiDetailPreferenceController;
 
     @Override
@@ -56,26 +51,6 @@
     }
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        // Header Title set automatically from launching Preference
-
-        LayoutPreference buttonsPreference = ((LayoutPreference) findPreference(
-                WifiDetailPreferenceController.KEY_BUTTONS_PREF));
-        buttonsPreference.setVisible(mWifiDetailPreferenceController.canForgetNetwork());
-
-        mForgetButton = (Button) buttonsPreference.findViewById(R.id.left_button);
-        mForgetButton.setText(R.string.forget);
-        mForgetButton.setOnClickListener(view -> forgetNetwork());
-    }
-
-    private void forgetNetwork() {
-        mMetricsFeatureProvider.action(getActivity(), MetricsProto.MetricsEvent.ACTION_WIFI_FORGET);
-        mWifiDetailPreferenceController.forgetNetwork();
-    }
-
-    @Override
     public int getMetricsCategory() {
         return MetricsProto.MetricsEvent.WIFI_NETWORK_DETAILS;
     }
@@ -100,7 +75,8 @@
                 this,
                 new Handler(Looper.getMainLooper()),  // UI thread.
                 getLifecycle(),
-                context.getSystemService(WifiManager.class));
+                context.getSystemService(WifiManager.class),
+                mMetricsFeatureProvider);
 
         ArrayList<PreferenceController> controllers = new ArrayList(1);
         controllers.add(mWifiDetailPreferenceController);
diff --git a/tests/robotests/src/com/android/settings/applications/AppStateAppOpsBridgeTest.java b/tests/robotests/src/com/android/settings/applications/AppStateAppOpsBridgeTest.java
new file mode 100644
index 0000000..f17509a
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/applications/AppStateAppOpsBridgeTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+
+import android.Manifest;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.UserManager;
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+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 final class AppStateAppOpsBridgeTest {
+
+    @Mock private Context mContext;
+    @Mock private UserManager mUserManager;
+    @Mock private IPackageManagerWrapper mPackageManagerService;
+    @Mock private AppOpsManager mAppOpsManager;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+        when(mContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mAppOpsManager);
+    }
+
+    @Test
+    public void getPermissionInfo_nullPackageInfo_shouldNotCrash() throws RemoteException {
+        when(mPackageManagerService.getPackageInfo(anyString(), anyInt(), anyInt()))
+            .thenReturn(null);
+        TestAppStateAppOpsBridge appStateAppOpsBridge = new TestAppStateAppOpsBridge();
+
+        appStateAppOpsBridge.getPermissionInfo("pkg1", 1);
+        // should not crash
+    }
+
+    private class TestAppStateAppOpsBridge extends AppStateAppOpsBridge {
+        public TestAppStateAppOpsBridge() {
+            super(mContext, null, null, AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+                new String[] {Manifest.permission.SYSTEM_ALERT_WINDOW},
+                mPackageManagerService);
+        }
+
+        @Override
+        protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPickerTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPickerTest.java
index 78d0bda..f564755 100644
--- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPickerTest.java
+++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAutofillPickerTest.java
@@ -23,6 +23,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.Activity;
+import android.content.ComponentName;
 import android.content.Context;
 import android.os.UserManager;
 
@@ -41,12 +42,12 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
-
 @RunWith(SettingsRobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class DefaultAutofillPickerTest {
 
-    private static final String TEST_APP_KEY = "123";
+    private static final String TEST_APP_KEY = new ComponentName("foo.bar",
+            "foo.bar.Baz").flattenToString();
 
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Activity mActivity;
@@ -81,6 +82,4 @@
         when(info.loadLabel()).thenReturn("test_app_name");
         assertThat(mPicker.getConfirmationMessage(info)).isNotNull();
     }
-
-
 }
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 fb65993..bc42d1f 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -147,6 +147,14 @@
     }
 
     @Test
+    public void handlePreferenceTreeClick_tappingAudioWhileUninitializedDoesntCrash() {
+        mController.setVolume(null);
+
+        mPreference.setKey("pref_music_audio");
+        mController.handlePreferenceTreeClick(mPreference);
+    }
+
+    @Test
     public void testClickApps() {
         mPreference.setKey("pref_other_apps");
         mController.handlePreferenceTreeClick(mPreference);
@@ -165,6 +173,14 @@
     }
 
     @Test
+    public void handlePreferenceTreeClick_tappingAppsWhileUninitializedDoesntCrash() {
+        mController.setVolume(null);
+
+        mPreference.setKey("pref_other_apps");
+        mController.handlePreferenceTreeClick(mPreference);
+    }
+
+    @Test
     public void testClickFiles() {
         when(mSvp.findEmulatedForPrivate(any(VolumeInfo.class))).thenReturn(mVolume);
         mPreference.setKey("pref_files");
diff --git a/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java
index 6f751eb..7e92bc5 100644
--- a/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/TetherPreferenceControllerTest.java
@@ -21,7 +21,9 @@
 import android.bluetooth.BluetoothPan;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
+import android.database.ContentObserver;
 import android.net.ConnectivityManager;
+import android.provider.Settings;
 import android.support.v7.preference.Preference;
 
 import com.android.settings.R;
@@ -33,6 +35,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
@@ -42,6 +45,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 @RunWith(SettingsRobolectricTestRunner.class)
@@ -66,6 +70,7 @@
         ReflectionHelpers.setField(mController, "mContext", mContext);
         ReflectionHelpers.setField(mController, "mConnectivityManager", mConnectivityManager);
         ReflectionHelpers.setField(mController, "mBluetoothAdapter", mBluetoothAdapter);
+        ReflectionHelpers.setField(mController, "mPreference", mPreference);
     }
 
     @Test
@@ -82,13 +87,13 @@
 
     @Test
     public void updateSummary_noPreference_noInteractionWithConnectivityManager() {
+        ReflectionHelpers.setField(mController, "mPreference", null);
         mController.updateSummary();
         verifyNoMoreInteractions(mConnectivityManager);
     }
 
     @Test
     public void updateSummary_wifiTethered_shouldShowHotspotMessage() {
-        ReflectionHelpers.setField(mController, "mPreference", mPreference);
         when(mConnectivityManager.getTetheredIfaces()).thenReturn(new String[]{"123"});
         when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"123"});
 
@@ -98,7 +103,6 @@
 
     @Test
     public void updateSummary_btThetherOn_shouldShowTetherMessage() {
-        ReflectionHelpers.setField(mController, "mPreference", mPreference);
         when(mConnectivityManager.getTetheredIfaces()).thenReturn(new String[]{"123"});
         when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[]{"123"});
 
@@ -108,7 +112,6 @@
 
     @Test
     public void updateSummary_tetherOff_shouldShowTetherOffMessage() {
-        ReflectionHelpers.setField(mController, "mPreference", mPreference);
         when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[]{"123"});
         when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"456"});
 
@@ -118,7 +121,6 @@
 
     @Test
     public void updateSummary_wifiBtTetherOn_shouldShowHotspotAndTetherMessage() {
-        ReflectionHelpers.setField(mController, "mPreference", mPreference);
         when(mConnectivityManager.getTetheredIfaces()).thenReturn(new String[]{"123", "456"});
         when(mConnectivityManager.getTetherableWifiRegexs()).thenReturn(new String[]{"456"});
         when(mConnectivityManager.getTetherableBluetoothRegexs()).thenReturn(new String[]{"23"});
@@ -127,4 +129,25 @@
         verify(mPreference).setSummary(R.string.tether_settings_summary_hotspot_on_tether_on);
     }
 
+    @Test
+    public void airplaneModeOn_shouldUpdateSummaryToOff() {
+        ReflectionHelpers.setField(mController, "mContext", RuntimeEnvironment.application);
+
+        Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 0);
+
+        mController.onResume();
+
+        verifyZeroInteractions(mPreference);
+
+        Settings.Global.putInt(RuntimeEnvironment.application.getContentResolver(),
+                Settings.Global.AIRPLANE_MODE_ON, 1);
+
+        final ContentObserver observer = ReflectionHelpers.getField(mController,
+                "mAirplaneModeObserver");
+        observer.onChange(true, Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON));
+
+        verify(mPreference).setSummary(R.string.switch_off_text);
+    }
+
 }
diff --git a/tests/robotests/src/com/android/settings/notification/EmergencyBroadcastPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/EmergencyBroadcastPreferenceControllerTest.java
index 98951d1..392bd2c 100644
--- a/tests/robotests/src/com/android/settings/notification/EmergencyBroadcastPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/EmergencyBroadcastPreferenceControllerTest.java
@@ -44,6 +44,8 @@
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
 public class EmergencyBroadcastPreferenceControllerTest {
 
+    private static final String PREF_TEST_KEY = "test_key";
+
     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     private Context mContext;
     @Mock
@@ -62,7 +64,8 @@
         MockitoAnnotations.initMocks(this);
         when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
         when(mContext.getPackageManager()).thenReturn(mPackageManager);
-        mController = new EmergencyBroadcastPreferenceController(mContext, mAccountHelper);
+        mController = new EmergencyBroadcastPreferenceController(mContext, mAccountHelper,
+                PREF_TEST_KEY);
     }
 
     @Test
@@ -73,12 +76,17 @@
     }
 
     @Test
+    public void getPreferenceKey_shouldReturnKeyDefinedInConstructor() {
+        assertThat(mController.getPreferenceKey()).isEqualTo(PREF_TEST_KEY);
+    }
+
+    @Test
     public void isAvailable_notAdminUser_shouldReturnFalse() {
         when(mUserManager.isAdminUser()).thenReturn(false);
         when(mContext.getResources().getBoolean(
-            com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(true);
+                com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(true);
         when(mPackageManager.getApplicationEnabledSetting(anyString()))
-            .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
         when(mAccountHelper.hasBaseUserRestriction(anyString(), anyInt())).thenReturn(false);
 
         assertThat(mController.isAvailable()).isFalse();
@@ -88,11 +96,11 @@
     public void isAvailable_hasConfigCellBroadcastRestriction_shouldReturnFalse() {
         when(mUserManager.isAdminUser()).thenReturn(true);
         when(mContext.getResources().getBoolean(
-            com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(true);
+                com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(true);
         when(mPackageManager.getApplicationEnabledSetting(anyString()))
-            .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
         when(mAccountHelper.hasBaseUserRestriction(
-            eq(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS), anyInt())).thenReturn(true);
+                eq(UserManager.DISALLOW_CONFIG_CELL_BROADCASTS), anyInt())).thenReturn(true);
 
         assertThat(mController.isAvailable()).isFalse();
     }
@@ -101,9 +109,9 @@
     public void isAvailable_cellBroadcastAppLinkDisabled_shouldReturnFalse() {
         when(mUserManager.isAdminUser()).thenReturn(true);
         when(mContext.getResources().getBoolean(
-            com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(false);
+                com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(false);
         when(mPackageManager.getApplicationEnabledSetting(anyString()))
-            .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
         when(mAccountHelper.hasBaseUserRestriction(anyString(), anyInt())).thenReturn(false);
 
         assertThat(mController.isAvailable()).isFalse();
@@ -113,9 +121,9 @@
     public void isAvailable_cellBroadcastReceiverDisabled_shouldReturnFalse() {
         when(mUserManager.isAdminUser()).thenReturn(true);
         when(mContext.getResources().getBoolean(
-            com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(true);
+                com.android.internal.R.bool.config_cellBroadcastAppLinks)).thenReturn(true);
         when(mPackageManager.getApplicationEnabledSetting(anyString()))
-            .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
         when(mAccountHelper.hasBaseUserRestriction(anyString(), anyInt())).thenReturn(false);
 
         assertThat(mController.isAvailable()).isFalse();
diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
index b9dde37..208c157 100644
--- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java
@@ -52,14 +52,15 @@
 import android.view.View.OnClickListener;
 import android.widget.Button;
 
+import com.android.internal.logging.nano.MetricsProto;
 import com.android.settings.R;
 import com.android.settings.SettingsRobolectricTestRunner;
 import com.android.settings.TestConfig;
 import com.android.settings.applications.LayoutPreference;
+import com.android.settings.core.instrumentation.MetricsFeatureProvider;
 import com.android.settings.core.lifecycle.Lifecycle;
-import com.android.settings.wifi.WifiDetailPreference;
-import com.android.settings.vpn2.ConnectivityManagerWrapper;
 import com.android.settings.vpn2.ConnectivityManagerWrapperImpl;
+import com.android.settings.wifi.WifiDetailPreference;
 import com.android.settingslib.wifi.AccessPoint;
 
 import org.junit.Before;
@@ -67,6 +68,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
 import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
@@ -103,6 +105,7 @@
     @Mock private WifiInfo mockWifiInfo;
     @Mock private WifiNetworkDetailsFragment mockFragment;
     @Mock private WifiManager mockWifiManager;
+    @Mock private MetricsFeatureProvider mockMetricsFeatureProvider;
 
     @Mock private Preference mockConnectionDetailPref;
     @Mock private LayoutPreference mockButtonsPref;
@@ -116,9 +119,12 @@
     @Mock private WifiDetailPreference mockGatewayPref;
     @Mock private WifiDetailPreference mockSubnetPref;
     @Mock private WifiDetailPreference mockDnsPref;
+    @Mock private Button mockForgetButton;
     @Mock private PreferenceCategory mockIpv6AddressCategory;
 
-    private ArgumentCaptor<NetworkCallback> mCallbackCaptor;
+    @Captor private ArgumentCaptor<NetworkCallback> mCallbackCaptor;
+    @Captor private ArgumentCaptor<View.OnClickListener> mForgetClickListener;
+
     private Context mContext = RuntimeEnvironment.application;
     private Lifecycle mLifecycle;
     private LinkProperties mLinkProperties;
@@ -143,12 +149,8 @@
             throw new RuntimeException(e);
         }
 
-        mCallbackCaptor = ArgumentCaptor.forClass(NetworkCallback.class);
-
         when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfig);
         when(mockAccessPoint.getLevel()).thenReturn(LEVEL);
-        when(mockAccessPoint.getNetworkInfo()).thenReturn(mockNetworkInfo);
-        when(mockAccessPoint.getRssi()).thenReturn(RSSI);
         when(mockAccessPoint.getSecurityString(false)).thenReturn(SECURITY);
 
         when(mockConnectivityManagerWrapper.getConnectivityManager())
@@ -157,6 +159,7 @@
                 .thenReturn(mockNetworkInfo);
         doNothing().when(mockConnectivityManagerWrapper).registerNetworkCallback(
                 any(NetworkRequest.class), mCallbackCaptor.capture(), any(Handler.class));
+        doNothing().when(mockForgetButton).setOnClickListener(mForgetClickListener.capture());
 
         when(mockWifiInfo.getLinkSpeed()).thenReturn(LINK_SPEED);
         when(mockWifiInfo.getRssi()).thenReturn(RSSI);
@@ -169,9 +172,8 @@
 
         when(mockFragment.getActivity()).thenReturn(mockActivity);
 
-        mController = newWifiDetailPreferenceController();
-
         setupMockedPreferenceScreen();
+        mController = newWifiDetailPreferenceController();
     }
 
     private WifiDetailPreferenceController newWifiDetailPreferenceController() {
@@ -182,7 +184,8 @@
                 mockFragment,
                 null,  // Handler
                 mLifecycle,
-                mockWifiManager);
+                mockWifiManager,
+                mockMetricsFeatureProvider);
     }
 
     private void setupMockedPreferenceScreen() {
@@ -192,6 +195,8 @@
                 .thenReturn(mockConnectionDetailPref);
         when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_BUTTONS_PREF))
                 .thenReturn(mockButtonsPref);
+        when(mockButtonsPref.findViewById(R.id.left_button))
+                .thenReturn(mockForgetButton);
         when(mockButtonsPref.findViewById(R.id.right_button))
                 .thenReturn(mockSignInButton);
         when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_SIGNAL_STRENGTH_PREF))
@@ -214,30 +219,32 @@
                 .thenReturn(mockDnsPref);
         when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_ADDRESS_CATEGORY))
                 .thenReturn(mockIpv6AddressCategory);
-
-        mController.displayPreference(mockScreen);
     }
 
     @Test
     public void isAvailable_shouldAlwaysReturnTrue() {
+        mController.displayPreference(mockScreen);
+
         assertThat(mController.isAvailable()).isTrue();
     }
 
     @Test
     public void securityPreference_stringShouldBeSet() {
+        mController.displayPreference(mockScreen);
+
         verify(mockSecurityPref).setDetailText(SECURITY);
     }
 
     @Test
-    public void latestWifiInfo_shouldBeFetchedOnResume() {
-        mController.onResume();
+    public void latestWifiInfo_shouldBeFetchedInDisplayPreference() {
+        mController.displayPreference(mockScreen);
 
         verify(mockWifiManager, times(1)).getConnectionInfo();
     }
 
     @Test
-    public void latestNetworkInfo_shouldBeFetchedOnResume() {
-        mController.onResume();
+    public void latestNetworkInfo_shouldBeFetchedInDisplayPreference() {
+        mController.displayPreference(mockScreen);
 
         verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class));
     }
@@ -264,7 +271,7 @@
         Drawable expectedIcon =
                 NetworkBadging.getWifiIcon(LEVEL, NetworkBadging.BADGING_NONE, mContext.getTheme());
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockConnectionDetailPref).setIcon(expectedIcon);
     }
@@ -274,14 +281,14 @@
         String summary = "summary";
         when(mockAccessPoint.getSettingsSummary()).thenReturn(summary);
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockConnectionDetailPref).setTitle(summary);
     }
 
     @Test
     public void signalStrengthPref_shouldHaveIconSet() {
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockSignalStrengthPref).setIcon(any(Drawable.class));
     }
@@ -291,7 +298,7 @@
         String expectedStrength =
                 mContext.getResources().getStringArray(R.array.wifi_signal)[LEVEL];
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockSignalStrengthPref).setDetailText(expectedStrength);
     }
@@ -300,7 +307,7 @@
     public void linkSpeedPref_shouldHaveDetailTextSet() {
         String expectedLinkSpeed = mContext.getString(R.string.link_speed, LINK_SPEED);
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockLinkSpeedPref).setDetailText(expectedLinkSpeed);
     }
@@ -309,14 +316,14 @@
     public void linkSpeedPref_shouldNotShowIfNotSet() {
         when(mockWifiInfo.getLinkSpeed()).thenReturn(-1);
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockLinkSpeedPref).setVisible(false);
     }
 
     @Test
     public void macAddressPref_shouldHaveDetailTextSet() {
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockMacAddressPref).setDetailText(MAC_ADDRESS);
     }
@@ -327,7 +334,7 @@
 
         mLinkProperties.addLinkAddress(ipv4Address);
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockIpAddressPref).setDetailText(mIpv4Address.getHostAddress());
     }
@@ -339,7 +346,7 @@
         InetAddress gateway = mIpv4Address;
         mLinkProperties.addRoute(new RouteInfo(subnet, gateway));
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockSubnetPref).setDetailText("255.255.255.0");
         verify(mockGatewayPref).setDetailText(mIpv4Address.getHostAddress());
@@ -350,7 +357,7 @@
         mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[]{8,8,4,4}));
         mLinkProperties.addDnsServer(InetAddress.getByAddress(new byte[]{8,8,8,8}));
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockDnsPref).setDetailText("8.8.4.4,8.8.8.8");
     }
@@ -361,7 +368,7 @@
         // nor connecting and WifiStateMachine has not reached L2ConnectedState.
         when(mockWifiManager.getCurrentNetwork()).thenReturn(null);
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockActivity).finish();
     }
@@ -372,7 +379,7 @@
         reset(mockIpv6AddressCategory, mockIpAddressPref, mockSubnetPref, mockGatewayPref,
                 mockDnsPref);
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         verify(mockIpv6AddressCategory).setVisible(false);
         verify(mockIpAddressPref).setVisible(false);
@@ -389,27 +396,28 @@
     @Test
     public void canForgetNetwork_noNetwork() {
         when(mockAccessPoint.getConfig()).thenReturn(null);
+
         mController = newWifiDetailPreferenceController();
         mController.displayPreference(mockScreen);
-        mController.onResume();
 
-        assertThat(mController.canForgetNetwork()).isFalse();
+        verify(mockForgetButton).setVisibility(View.INVISIBLE);
     }
 
     @Test
     public void canForgetNetwork_ephemeral() {
         when(mockWifiInfo.isEphemeral()).thenReturn(true);
         when(mockAccessPoint.getConfig()).thenReturn(null);
-        mController = newWifiDetailPreferenceController();
-        mController.displayPreference(mockScreen);
-        mController.onResume();
 
-        assertThat(mController.canForgetNetwork()).isTrue();
+        mController.displayPreference(mockScreen);
+
+        verify(mockForgetButton).setVisibility(View.VISIBLE);
     }
 
     @Test
     public void canForgetNetwork_saved() {
-        assertThat(mController.canForgetNetwork()).isTrue();
+        mController.displayPreference(mockScreen);
+
+        verify(mockForgetButton).setVisibility(View.VISIBLE);
     }
 
     @Test
@@ -418,25 +426,31 @@
         when(mockWifiInfo.isEphemeral()).thenReturn(true);
         when(mockWifiInfo.getSSID()).thenReturn(ssid);
 
-        mController.onResume();
-
-        mController.forgetNetwork();
+        mController.displayPreference(mockScreen);
+        mForgetClickListener.getValue().onClick(null);
 
         verify(mockWifiManager).disableEphemeralNetwork(ssid);
+        verify(mockMetricsFeatureProvider)
+                .action(mockActivity, MetricsProto.MetricsEvent.ACTION_WIFI_FORGET);
     }
 
     @Test
     public void forgetNetwork_saved() {
         mockWifiConfig.networkId = 5;
 
-        mController.forgetNetwork();
+        mController.displayPreference(mockScreen);
+        mForgetClickListener.getValue().onClick(null);
 
         verify(mockWifiManager).forget(mockWifiConfig.networkId, null);
+        verify(mockMetricsFeatureProvider)
+                .action(mockActivity, MetricsProto.MetricsEvent.ACTION_WIFI_FORGET);
     }
 
     @Test
     public void networkStateChangedIntent_shouldRefetchInfo() {
+        mController.displayPreference(mockScreen);
         mController.onResume();
+
         verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class));
         verify(mockWifiManager, times(1)).getConnectionInfo();
 
@@ -448,7 +462,9 @@
 
     @Test
     public void rssiChangedIntent_shouldRefetchInfo() {
+        mController.displayPreference(mockScreen);
         mController.onResume();
+
         verify(mockConnectivityManager, times(1)).getNetworkInfo(any(Network.class));
         verify(mockWifiManager, times(1)).getConnectionInfo();
 
@@ -470,6 +486,7 @@
 
     @Test
     public void networkOnLost_shouldFinishActivity() {
+        mController.displayPreference(mockScreen);
         mController.onResume();
 
         mCallbackCaptor.getValue().onLost(mockNetwork);
@@ -483,7 +500,7 @@
 
         mLinkProperties.addLinkAddress(ipv6Address);
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         ArgumentCaptor<Preference> preferenceCaptor = ArgumentCaptor.forClass(Preference.class);
         verify(mockIpv6AddressCategory).addPreference(preferenceCaptor.capture());
@@ -496,7 +513,7 @@
 
         mLinkProperties.addLinkAddress(ipv6Address);
 
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         ArgumentCaptor<Preference> preferenceCaptor = ArgumentCaptor.forClass(Preference.class);
         verify(mockIpv6AddressCategory).addPreference(preferenceCaptor.capture());
@@ -505,9 +522,11 @@
 
     @Test
     public void captivePortal_shouldShowSignInButton() {
-        reset(mockSignInButton);
         InOrder inOrder = inOrder(mockSignInButton);
+
+        mController.displayPreference(mockScreen);
         mController.onResume();
+
         inOrder.verify(mockSignInButton).setVisibility(View.INVISIBLE);
 
         NetworkCapabilities nc = new NetworkCapabilities();
@@ -531,11 +550,41 @@
 
     @Test
     public void testSignInButton_shouldStartCaptivePortalApp() {
-        mController.onResume();
+        mController.displayPreference(mockScreen);
 
         ArgumentCaptor<OnClickListener> captor = ArgumentCaptor.forClass(OnClickListener.class);
         verify(mockSignInButton).setOnClickListener(captor.capture());
         captor.getValue().onClick(mockSignInButton);
         verify(mockConnectivityManagerWrapper).startCaptivePortalApp(mockNetwork);
     }
+
+    @Test
+    public void signInButtonVisible_buttonPanelShouldBeVisible() {
+        when(mockSignInButton.getVisibility()).thenReturn(View.VISIBLE);
+        when(mockForgetButton.getVisibility()).thenReturn(View.INVISIBLE);
+
+        mController.displayPreference(mockScreen);
+
+        verify(mockButtonsPref).setVisible(true);
+    }
+
+    @Test
+    public void forgetButtonVisible_buttonPanelShouldBeVisible() {
+        when(mockSignInButton.getVisibility()).thenReturn(View.INVISIBLE);
+        when(mockForgetButton.getVisibility()).thenReturn(View.VISIBLE);
+
+        mController.displayPreference(mockScreen);
+
+        verify(mockButtonsPref).setVisible(true);
+    }
+
+    @Test
+    public void neitherButtonVisible_buttonPanelShouldBeInvisible() {
+        when(mockSignInButton.getVisibility()).thenReturn(View.INVISIBLE);
+        when(mockForgetButton.getVisibility()).thenReturn(View.INVISIBLE);
+
+        mController.displayPreference(mockScreen);
+
+        verify(mockButtonsPref).setVisible(false);
+    }
 }