DeviceInfo: move more prefereces in PreferenceController

Bug: 34774945
Test: make RunSettingsRoboTests
Change-Id: Ie5e113a6df85bab5be50c947bd7b91cfacdccb7f
diff --git a/src/com/android/settings/DeviceInfoSettings.java b/src/com/android/settings/DeviceInfoSettings.java
index 404e687..47cb9829 100644
--- a/src/com/android/settings/DeviceInfoSettings.java
+++ b/src/com/android/settings/DeviceInfoSettings.java
@@ -20,63 +20,39 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
-import android.os.Bundle;
-import android.os.SELinux;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
 import android.provider.SearchIndexableResource;
-import android.provider.Settings;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceGroup;
-import android.text.TextUtils;
-import android.util.Log;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.core.PreferenceController;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.dashboard.SummaryLoader;
 import com.android.settings.deviceinfo.AdditionalSystemUpdatePreferenceController;
+import com.android.settings.deviceinfo.BasebandVersionPreferenceController;
 import com.android.settings.deviceinfo.BuildNumberPreferenceController;
+import com.android.settings.deviceinfo.DeviceModelPreferenceController;
+import com.android.settings.deviceinfo.FccEquipmentIdPreferenceController;
 import com.android.settings.deviceinfo.FeedbackPreferenceController;
+import com.android.settings.deviceinfo.FirmwareVersionPreferenceController;
 import com.android.settings.deviceinfo.KernelVersionPreferenceController;
 import com.android.settings.deviceinfo.ManualPreferenceController;
+import com.android.settings.deviceinfo.RegulatoryInfoPreferenceController;
+import com.android.settings.deviceinfo.SELinuxStatusPreferenceController;
+import com.android.settings.deviceinfo.SafetyInfoPreferenceController;
 import com.android.settings.deviceinfo.SafetyLegalPreferenceController;
+import com.android.settings.deviceinfo.SecurityPatchPreferenceController;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.search.Indexable;
-import com.android.settingslib.DeviceInfoUtils;
-import com.android.settingslib.RestrictedLockUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-
 public class DeviceInfoSettings extends DashboardFragment implements Indexable {
 
     private static final String LOG_TAG = "DeviceInfoSettings";
 
-    private static final String KEY_REGULATORY_INFO = "regulatory_info";
-    private static final String PROPERTY_SELINUX_STATUS = "ro.build.selinux";
-    private static final String KEY_DEVICE_MODEL = "device_model";
-    private static final String KEY_SELINUX_STATUS = "selinux_status";
-    private static final String KEY_BASEBAND_VERSION = "baseband_version";
-    private static final String KEY_FIRMWARE_VERSION = "firmware_version";
-    private static final String KEY_SECURITY_PATCH = "security_patch";
-    private static final String KEY_EQUIPMENT_ID = "fcc_equipment_id";
-    private static final String PROPERTY_EQUIPMENT_ID = "ro.ril.fccid";
-
-
-    long[] mHits = new long[3];
     private BuildNumberPreferenceController mBuildNumberPreferenceController;
 
-    private UserManager mUm;
-
-    private EnforcedAdmin mFunDisallowedAdmin;
-    private boolean mFunDisallowedBySystem;
-
     @Override
     public int getMetricsCategory() {
         return MetricsEvent.DEVICEINFO;
@@ -88,12 +64,6 @@
     }
 
     @Override
-    public void onAttach(Context context) {
-        super.onAttach(context);
-        mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);
-    }
-
-    @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (mBuildNumberPreferenceController.onActivityResult(requestCode, resultCode, data)) {
             return;
@@ -102,97 +72,6 @@
     }
 
     @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        setStringSummary(KEY_FIRMWARE_VERSION, Build.VERSION.RELEASE);
-        findPreference(KEY_FIRMWARE_VERSION).setEnabled(true);
-
-        final String patch = DeviceInfoUtils.getSecurityPatch();
-        if (!TextUtils.isEmpty(patch)) {
-            setStringSummary(KEY_SECURITY_PATCH, patch);
-        } else {
-            getPreferenceScreen().removePreference(findPreference(KEY_SECURITY_PATCH));
-        }
-
-        setValueSummary(KEY_BASEBAND_VERSION, "gsm.version.baseband");
-        setStringSummary(KEY_DEVICE_MODEL, Build.MODEL + DeviceInfoUtils.getMsvSuffix());
-        setValueSummary(KEY_EQUIPMENT_ID, PROPERTY_EQUIPMENT_ID);
-
-        if (!SELinux.isSELinuxEnabled()) {
-            String status = getResources().getString(R.string.selinux_status_disabled);
-            setStringSummary(KEY_SELINUX_STATUS, status);
-        } else if (!SELinux.isSELinuxEnforced()) {
-            String status = getResources().getString(R.string.selinux_status_permissive);
-            setStringSummary(KEY_SELINUX_STATUS, status);
-        }
-
-        // Remove selinux information if property is not present
-        removePreferenceIfPropertyMissing(getPreferenceScreen(), KEY_SELINUX_STATUS,
-                PROPERTY_SELINUX_STATUS);
-
-        // Remove Equipment id preference if FCC ID is not set by RIL
-        removePreferenceIfPropertyMissing(getPreferenceScreen(), KEY_EQUIPMENT_ID,
-                PROPERTY_EQUIPMENT_ID);
-
-        // Remove Baseband version if wifi-only device
-        if (Utils.isWifiOnly(getActivity())) {
-            getPreferenceScreen().removePreference(findPreference(KEY_BASEBAND_VERSION));
-        }
-
-        // Remove regulatory labels if no activity present to handle intent.
-        removePreferenceIfActivityMissing(
-                KEY_REGULATORY_INFO, Settings.ACTION_SHOW_REGULATORY_INFO);
-
-        removePreferenceIfActivityMissing(
-                "safety_info", "android.settings.SHOW_SAFETY_AND_REGULATORY_INFO");
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        mFunDisallowedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(
-                getActivity(), UserManager.DISALLOW_FUN, UserHandle.myUserId());
-        mFunDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction(
-                getActivity(), UserManager.DISALLOW_FUN, UserHandle.myUserId());
-    }
-
-    @Override
-    public boolean onPreferenceTreeClick(Preference preference) {
-        if (preference.getKey().equals(KEY_FIRMWARE_VERSION)) {
-            System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);
-            mHits[mHits.length - 1] = SystemClock.uptimeMillis();
-            if (mHits[0] >= (SystemClock.uptimeMillis() - 500)) {
-                if (mUm.hasUserRestriction(UserManager.DISALLOW_FUN)) {
-                    if (mFunDisallowedAdmin != null && !mFunDisallowedBySystem) {
-                        RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getActivity(),
-                                mFunDisallowedAdmin);
-                    }
-                    Log.d(LOG_TAG, "Sorry, no fun for you!");
-                    return false;
-                }
-
-                Intent intent = new Intent(Intent.ACTION_MAIN);
-                intent.setClassName("android",
-                        com.android.internal.app.PlatLogoActivity.class.getName());
-                try {
-                    startActivity(intent);
-                } catch (Exception e) {
-                    Log.e(LOG_TAG, "Unable to start activity " + intent.toString());
-                }
-            }
-        } else if (preference.getKey().equals(KEY_SECURITY_PATCH)) {
-            if (getPackageManager().queryIntentActivities(preference.getIntent(), 0).isEmpty()) {
-                // Don't send out the intent to stop crash
-                Log.w(LOG_TAG, "Stop click action on " + KEY_SECURITY_PATCH + ": "
-                        + "queryIntentActivities() returns empty");
-                return true;
-            }
-        }
-        return super.onPreferenceTreeClick(preference);
-    }
-
-    @Override
     protected String getLogTag() {
         return LOG_TAG;
     }
@@ -213,51 +92,17 @@
         controllers.add(new ManualPreferenceController(context));
         controllers.add(new FeedbackPreferenceController(this, context));
         controllers.add(new KernelVersionPreferenceController(context));
+        controllers.add(new BasebandVersionPreferenceController(context));
+        controllers.add(new FirmwareVersionPreferenceController(context, getLifecycle()));
+        controllers.add(new RegulatoryInfoPreferenceController(context));
+        controllers.add(new DeviceModelPreferenceController(context));
+        controllers.add(new SecurityPatchPreferenceController(context));
+        controllers.add(new FccEquipmentIdPreferenceController(context));
+        controllers.add(new SELinuxStatusPreferenceController(context));
+        controllers.add(new SafetyInfoPreferenceController(context));
         return controllers;
     }
 
-    private void removePreferenceIfPropertyMissing(PreferenceGroup preferenceGroup,
-            String preference, String property) {
-        if (SystemProperties.get(property).equals("")) {
-            // Property is missing so remove preference from group
-            try {
-                preferenceGroup.removePreference(findPreference(preference));
-            } catch (RuntimeException e) {
-                Log.d(LOG_TAG, "Property '" + property + "' missing and no '"
-                        + preference + "' preference");
-            }
-        }
-    }
-
-    private void removePreferenceIfActivityMissing(String preferenceKey, String action) {
-        final Intent intent = new Intent(action);
-        if (getPackageManager().queryIntentActivities(intent, 0).isEmpty()) {
-            Preference pref = findPreference(preferenceKey);
-            if (pref != null) {
-                getPreferenceScreen().removePreference(pref);
-            }
-        }
-    }
-
-    private void setStringSummary(String preference, String value) {
-        try {
-            findPreference(preference).setSummary(value);
-        } catch (RuntimeException e) {
-            findPreference(preference).setSummary(
-                getResources().getString(R.string.device_info_default));
-        }
-    }
-
-    private void setValueSummary(String preference, String property) {
-        try {
-            findPreference(preference).setSummary(
-                    SystemProperties.get(property,
-                            getResources().getString(R.string.device_info_default)));
-        } catch (RuntimeException e) {
-            // No recovery
-        }
-    }
-
     private static class SummaryProvider implements SummaryLoader.SummaryProvider {
 
         private final Context mContext;
@@ -281,7 +126,7 @@
             = new SummaryLoader.SummaryProviderFactory() {
         @Override
         public SummaryLoader.SummaryProvider createSummaryProvider(Activity activity,
-                                                                   SummaryLoader summaryLoader) {
+                SummaryLoader summaryLoader) {
             return new SummaryProvider(activity, summaryLoader);
         }
     };
@@ -290,41 +135,30 @@
      * For Search.
      */
     public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
-        new BaseSearchIndexProvider() {
+            new BaseSearchIndexProvider() {
 
-            @Override
-            public List<SearchIndexableResource> getXmlResourcesToIndex(
-                    Context context, boolean enabled) {
-                final SearchIndexableResource sir = new SearchIndexableResource(context);
-                sir.xmlResId = R.xml.device_info_settings;
-                return Arrays.asList(sir);
-            }
-
-            @Override
-            public List<String> getNonIndexableKeys(Context context) {
-                final List<String> keys = new ArrayList<String>();
-                if (isPropertyMissing(PROPERTY_SELINUX_STATUS)) {
-                    keys.add(KEY_SELINUX_STATUS);
-                }
-                new SafetyLegalPreferenceController(context).updateNonIndexableKeys(keys);
-                if (isPropertyMissing(PROPERTY_EQUIPMENT_ID)) {
-                    keys.add(KEY_EQUIPMENT_ID);
-                }
-                // Remove Baseband version if wifi-only device
-                if (Utils.isWifiOnly(context)) {
-                    keys.add((KEY_BASEBAND_VERSION));
+                @Override
+                public List<SearchIndexableResource> getXmlResourcesToIndex(
+                        Context context, boolean enabled) {
+                    final SearchIndexableResource sir = new SearchIndexableResource(context);
+                    sir.xmlResId = R.xml.device_info_settings;
+                    return Arrays.asList(sir);
                 }
 
-                new FeedbackPreferenceController(null, context)
-                        .updateNonIndexableKeys(keys);
-                new AdditionalSystemUpdatePreferenceController(context)
-                        .updateNonIndexableKeys(keys);
-                return keys;
-            }
-
-            private boolean isPropertyMissing(String property) {
-                return SystemProperties.get(property).equals("");
-            }
-        };
-
+                @Override
+                public List<String> getNonIndexableKeys(Context context) {
+                    final List<String> keys = new ArrayList<>();
+                    new SafetyLegalPreferenceController(context).updateNonIndexableKeys(keys);
+                    new BasebandVersionPreferenceController(context).updateNonIndexableKeys(keys);
+                    new FeedbackPreferenceController(null, context).updateNonIndexableKeys(keys);
+                    new AdditionalSystemUpdatePreferenceController(context)
+                            .updateNonIndexableKeys(keys);
+                    new RegulatoryInfoPreferenceController(context).updateNonIndexableKeys(keys);
+                    new SecurityPatchPreferenceController(context).updateNonIndexableKeys(keys);
+                    new FccEquipmentIdPreferenceController(context).updateNonIndexableKeys(keys);
+                    new SELinuxStatusPreferenceController(context).updateNonIndexableKeys(keys);
+                    new SafetyInfoPreferenceController(context).updateNonIndexableKeys(keys);
+                    return keys;
+                }
+            };
 }
diff --git a/src/com/android/settings/deviceinfo/BasebandVersionPreferenceController.java b/src/com/android/settings/deviceinfo/BasebandVersionPreferenceController.java
new file mode 100644
index 0000000..1153d12
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/BasebandVersionPreferenceController.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+import android.os.SystemProperties;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.PreferenceController;
+
+public class BasebandVersionPreferenceController extends PreferenceController {
+
+    private static final String BASEBAND_PROPERTY = "gsm.version.baseband";
+    private static final String KEY_BASEBAND_VERSION = "baseband_version";
+
+    public BasebandVersionPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return !Utils.isWifiOnly(mContext);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_BASEBAND_VERSION;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        preference.setSummary(SystemProperties.get(BASEBAND_PROPERTY,
+                mContext.getResources().getString(R.string.device_info_default)));
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java b/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
new file mode 100644
index 0000000..1b47561
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/DeviceModelPreferenceController.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+import android.os.Build;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.core.PreferenceController;
+import com.android.settingslib.DeviceInfoUtils;
+
+public class DeviceModelPreferenceController extends PreferenceController {
+
+    private static final String KEY_DEVICE_MODEL = "device_model";
+
+    public DeviceModelPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        final Preference pref = screen.findPreference(KEY_DEVICE_MODEL);
+        if (pref != null) {
+            pref.setSummary(Build.MODEL + DeviceInfoUtils.getMsvSuffix());
+        }
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_DEVICE_MODEL;
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/FccEquipmentIdPreferenceController.java b/src/com/android/settings/deviceinfo/FccEquipmentIdPreferenceController.java
new file mode 100644
index 0000000..4f8de71
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/FccEquipmentIdPreferenceController.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+import android.os.SystemProperties;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceController;
+
+public class FccEquipmentIdPreferenceController extends PreferenceController {
+
+
+    private static final String PROPERTY_EQUIPMENT_ID = "ro.ril.fccid";
+    private static final String KEY_EQUIPMENT_ID = "fcc_equipment_id";
+
+    public FccEquipmentIdPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return !TextUtils.isEmpty(SystemProperties.get(PROPERTY_EQUIPMENT_ID));
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        final Preference pref = screen.findPreference(KEY_EQUIPMENT_ID);
+        if (pref != null) {
+            final String summary = SystemProperties.get(PROPERTY_EQUIPMENT_ID,
+                    mContext.getResources().getString(R.string.device_info_default));
+            pref.setSummary(summary);
+        }
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_EQUIPMENT_ID;
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/FeedbackPreferenceController.java b/src/com/android/settings/deviceinfo/FeedbackPreferenceController.java
index 6efc115..ed61a92 100644
--- a/src/com/android/settings/deviceinfo/FeedbackPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/FeedbackPreferenceController.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.android.settings.deviceinfo;
 
 import android.app.Fragment;
@@ -11,15 +26,25 @@
 
 public class FeedbackPreferenceController extends PreferenceController {
     private static final String KEY_DEVICE_FEEDBACK = "device_feedback";
+
     private final Fragment mHost;
+    private final Intent intent;
 
     public FeedbackPreferenceController(Fragment host, Context context) {
         super(context);
         this.mHost = host;
+        intent = new Intent("android.intent.action.BUG_REPORT");
     }
 
     public boolean isAvailable() {
-        return !TextUtils.isEmpty(DeviceInfoUtils.getFeedbackReporterPackage(this.mContext));
+        return !TextUtils.isEmpty(DeviceInfoUtils.getFeedbackReporterPackage(mContext));
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        super.updateState(preference);
+        intent.setPackage(DeviceInfoUtils.getFeedbackReporterPackage(mContext));
+        preference.setIntent(intent);
     }
 
     public String getPreferenceKey() {
@@ -33,9 +58,7 @@
         if (!this.isAvailable()) {
             return false;
         }
-        String reporterPackage = DeviceInfoUtils.getFeedbackReporterPackage(this.mContext);
-        Intent intent = new Intent("android.intent.action.BUG_REPORT");
-        intent.setPackage(reporterPackage);
+
         this.mHost.startActivityForResult(intent, 0);
         return true;
     }
diff --git a/src/com/android/settings/deviceinfo/FirmwareVersionPreferenceController.java b/src/com/android/settings/deviceinfo/FirmwareVersionPreferenceController.java
new file mode 100644
index 0000000..e8792f2
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/FirmwareVersionPreferenceController.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.settings.core.PreferenceController;
+import com.android.settings.core.lifecycle.Lifecycle;
+import com.android.settings.core.lifecycle.LifecycleObserver;
+import com.android.settings.core.lifecycle.events.OnResume;
+import com.android.settingslib.RestrictedLockUtils;
+
+
+public class FirmwareVersionPreferenceController extends PreferenceController
+        implements LifecycleObserver, OnResume {
+
+    private static final String TAG = "FirmwareVersionPref";
+    private static final String KEY_FIRMWARE_VERSION = "firmware_version";
+
+    private final UserManager mUserManager;
+
+    private RestrictedLockUtils.EnforcedAdmin mFunDisallowedAdmin;
+    private boolean mFunDisallowedBySystem;
+
+    private long[] mHits = new long[3];
+
+    public FirmwareVersionPreferenceController(Context context, Lifecycle lifecycle) {
+        super(context);
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        if (lifecycle != null) {
+            lifecycle.addObserver(this);
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        final Preference pref = screen.findPreference(KEY_FIRMWARE_VERSION);
+        if (pref != null) {
+            pref.setSummary(Build.VERSION.RELEASE);
+        }
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_FIRMWARE_VERSION;
+    }
+
+    @Override
+    public void onResume() {
+        mFunDisallowedAdmin = RestrictedLockUtils.checkIfRestrictionEnforced(
+                mContext, UserManager.DISALLOW_FUN, UserHandle.myUserId());
+        mFunDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction(
+                mContext, UserManager.DISALLOW_FUN, UserHandle.myUserId());
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), KEY_FIRMWARE_VERSION)) {
+            return false;
+        }
+        System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1);
+        mHits[mHits.length - 1] = SystemClock.uptimeMillis();
+        if (mHits[0] >= (SystemClock.uptimeMillis() - 500)) {
+            if (mUserManager.hasUserRestriction(UserManager.DISALLOW_FUN)) {
+                if (mFunDisallowedAdmin != null && !mFunDisallowedBySystem) {
+                    RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext,
+                            mFunDisallowedAdmin);
+                }
+                Log.d(TAG, "Sorry, no fun for you!");
+                return false;
+            }
+
+            final Intent intent = new Intent(Intent.ACTION_MAIN)
+                    .setClassName(
+                            "android", com.android.internal.app.PlatLogoActivity.class.getName());
+            try {
+                mContext.startActivity(intent);
+                return true;
+            } catch (Exception e) {
+                Log.e(TAG, "Unable to start activity " + intent.toString());
+            }
+        }
+        return false;
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/KernelVersionPreferenceController.java b/src/com/android/settings/deviceinfo/KernelVersionPreferenceController.java
index c5f5a9b..3a84c1e 100644
--- a/src/com/android/settings/deviceinfo/KernelVersionPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/KernelVersionPreferenceController.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.android.settings.deviceinfo;
 
 import android.content.Context;
diff --git a/src/com/android/settings/deviceinfo/RegulatoryInfoPreferenceController.java b/src/com/android/settings/deviceinfo/RegulatoryInfoPreferenceController.java
new file mode 100644
index 0000000..f82fd0b
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/RegulatoryInfoPreferenceController.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+
+import com.android.settings.core.PreferenceController;
+
+public class RegulatoryInfoPreferenceController extends PreferenceController {
+
+    private static final String KEY_REGULATORY_INFO = "regulatory_info";
+    private static final Intent INTENT_PROBE = new Intent(Settings.ACTION_SHOW_REGULATORY_INFO);
+
+    public RegulatoryInfoPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return !mContext.getPackageManager().queryIntentActivities(INTENT_PROBE, 0).isEmpty();
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_REGULATORY_INFO;
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/SELinuxStatusPreferenceController.java b/src/com/android/settings/deviceinfo/SELinuxStatusPreferenceController.java
new file mode 100644
index 0000000..b8529d2
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/SELinuxStatusPreferenceController.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+import android.os.SELinux;
+import android.os.SystemProperties;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceController;
+
+public class SELinuxStatusPreferenceController extends PreferenceController {
+
+    private static final String PROPERTY_SELINUX_STATUS = "ro.build.selinux";
+    private static final String KEY_SELINUX_STATUS = "selinux_status";
+
+    public SELinuxStatusPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return !TextUtils.isEmpty(SystemProperties.get(PROPERTY_SELINUX_STATUS));
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_SELINUX_STATUS;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        final Preference pref = screen.findPreference(KEY_SELINUX_STATUS);
+        if (pref == null) {
+            return;
+        }
+        if (!SELinux.isSELinuxEnabled()) {
+            String status = mContext.getResources().getString(R.string.selinux_status_disabled);
+            pref.setSummary(status);
+        } else if (!SELinux.isSELinuxEnforced()) {
+            String status = mContext.getResources().getString(R.string.selinux_status_permissive);
+            pref.setSummary(status);
+        }
+    }
+}
+
diff --git a/src/com/android/settings/deviceinfo/SafetyInfoPreferenceController.java b/src/com/android/settings/deviceinfo/SafetyInfoPreferenceController.java
new file mode 100644
index 0000000..bde4dd0
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/SafetyInfoPreferenceController.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+
+import com.android.settings.core.PreferenceController;
+
+public class SafetyInfoPreferenceController extends PreferenceController {
+
+    private static final Intent INTENT_PROBE =
+            new Intent("android.settings.SHOW_SAFETY_AND_REGULATORY_INFO");
+
+    private final PackageManager mPackageManager;
+
+    public SafetyInfoPreferenceController(Context context) {
+        super(context);
+        mPackageManager = mContext.getPackageManager();
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return !mPackageManager.queryIntentActivities(INTENT_PROBE, 0).isEmpty();
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return "safety_info";
+    }
+}
diff --git a/src/com/android/settings/deviceinfo/SafetyLegalPreferenceController.java b/src/com/android/settings/deviceinfo/SafetyLegalPreferenceController.java
index 139597b..c158d64 100644
--- a/src/com/android/settings/deviceinfo/SafetyLegalPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/SafetyLegalPreferenceController.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.android.settings.deviceinfo;
 
 import android.content.Context;
diff --git a/src/com/android/settings/deviceinfo/SecurityPatchPreferenceController.java b/src/com/android/settings/deviceinfo/SecurityPatchPreferenceController.java
new file mode 100644
index 0000000..64a1159
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/SecurityPatchPreferenceController.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.settings.core.PreferenceController;
+import com.android.settingslib.DeviceInfoUtils;
+
+public class SecurityPatchPreferenceController extends PreferenceController {
+
+    private static final String KEY_SECURITY_PATCH = "security_patch";
+    private static final String TAG = "SecurityPatchPref";
+
+    private final String mPatch;
+    private final PackageManager mPackageManager;
+
+    public SecurityPatchPreferenceController(Context context) {
+        super(context);
+        mPackageManager = mContext.getPackageManager();
+        mPatch = DeviceInfoUtils.getSecurityPatch();
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return !TextUtils.isEmpty(mPatch);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_SECURITY_PATCH;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        final Preference pref = screen.findPreference(KEY_SECURITY_PATCH);
+        if (pref != null) {
+            pref.setSummary(mPatch);
+        }
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), KEY_SECURITY_PATCH)) {
+            return false;
+        }
+        if (mPackageManager.queryIntentActivities(preference.getIntent(), 0).isEmpty()) {
+            // Don't send out the intent to stop crash
+            Log.w(TAG, "Stop click action on " + KEY_SECURITY_PATCH + ": "
+                    + "queryIntentActivities() returns empty");
+            return true;
+        }
+        return false;
+    }
+}