Create Developer options settings page.

This change creates a Preference to open the Developer options screen.
This preference is only visible if developer options has been enabled.

The developer options screen is empty, except for a toggle in the action
bar, which allows you to disable developer options if so desired. When
enabling developer options from the action bar, it throws up the same
dialog as the phone settings version.

Bug: 117289448
Test: Build, Manual, Robolectric
Change-Id: I51a96ac515099e3062798fb2a2029c9e4e5cd071
diff --git a/res/drawable/ic_settings_development.xml b/res/drawable/ic_settings_development.xml
new file mode 100644
index 0000000..5e0e64d
--- /dev/null
+++ b/res/drawable/ic_settings_development.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="@dimen/primary_icon_size"
+    android:height="@dimen/primary_icon_size"
+    android:viewportHeight="256.0"
+    android:viewportWidth="256.0">
+    <path
+        android:fillColor="@color/car_tint"
+        android:pathData="m66.641,197.718c-7.73,-7.73 -7.974,-8.747 -7.974,-33.186 0,-26.1 -1.346,-29.646 -12,-31.605 -9.22,-1.696 -8.063,-11.352 1.884,-15.729l8.783,-3.864 1.333,-26.241c1.262,-24.834 1.744,-26.593 8.986,-32.813 9.335,-8.017 21.681,-7.817 21.681,0.351 0,3.149 -2.974,6.723 -7.333,8.812 -7.171,3.437 -7.333,4.03 -7.333,26.776 0,16.737 -1.164,24.923 -4.151,29.188 -3.757,5.364 -3.757,6.489 0,11.853 3.037,4.336 4.151,12.604 4.151,30.805v24.879l8.145,2.839c6.138,2.14 7.945,4.241 7.333,8.528 -1.331,9.333 -13.894,9.016 -23.504,-0.593zM167.111,203.556c-4.355,-4.355 -1.269,-11.211 6.222,-13.823l8,-2.789v-24.879c0,-18.201 1.114,-26.469 4.151,-30.805 3.757,-5.364 3.757,-6.489 0,-11.853 -2.987,-4.264 -4.151,-12.451 -4.151,-29.188 0,-22.746 -0.162,-23.339 -7.333,-26.776 -4.359,-2.089 -7.333,-5.663 -7.333,-8.812 0,-8.168 12.346,-8.369 21.681,-0.351 7.242,6.22 7.724,7.979 8.986,32.813l1.333,26.241 8.783,3.864c9.947,4.377 11.104,14.033 1.884,15.729 -10.654,1.959 -12,5.505 -12,31.605 0,24.31 -0.279,25.491 -7.795,33.007 -7.235,7.235 -18.253,10.191 -22.427,6.017z"/>
+</vector>
diff --git a/res/values/preference_keys.xml b/res/values/preference_keys.xml
index 8601ce8..9bae45f 100644
--- a/res/values/preference_keys.xml
+++ b/res/values/preference_keys.xml
@@ -131,6 +131,7 @@
     <string name="pk_about_settings_entry" translatable="false">about_settings_entry</string>
     <string name="pk_legal_information_entry" translatable="false">legal_information_entry</string>
     <string name="pk_reset_options_entry" translatable="false">reset_options_entry</string>
+    <string name="pk_developer_options_entry" translatable="false">developer_options_entry</string>
 
     <!-- Language Settings -->
     <string name="pk_language_settings_entry" translatable="false">language_settings_entry</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 06272c5..cc05830 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -346,6 +346,8 @@
     <string name="show_dev_on">You are now a developer!</string>
     <!-- Device Info screen. Okay we get it, stop pressing, you already have it on. [CHAR LIMIT=NONE] -->
     <string name="show_dev_already">No need, you are already a developer.</string>
+    <!-- Title of Developer options preference screen. [CHAR LIMIT=30] -->
+    <string name="developer_options_settings">Developer options</string>
 
     <!-- Reset options --><skip/>
     <!-- Title for a screen containing all device reset options. [CHAR LIMIT=50] -->
diff --git a/res/xml/developer_options_fragment.xml b/res/xml/developer_options_fragment.xml
new file mode 100644
index 0000000..d05fe88
--- /dev/null
+++ b/res/xml/developer_options_fragment.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright 2018 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:title="@string/developer_options_settings"/>
diff --git a/res/xml/system_settings_fragment.xml b/res/xml/system_settings_fragment.xml
index 039f095..75a175e 100644
--- a/res/xml/system_settings_fragment.xml
+++ b/res/xml/system_settings_fragment.xml
@@ -58,4 +58,10 @@
         android:summary="@string/reset_options_summary"
         android:title="@string/reset_options_title"
         settings:controller="com.android.car.settings.common.NoSetupPreferenceController"/>
+    <Preference
+        android:fragment="com.android.car.settings.development.DeveloperOptionsFragment"
+        android:icon="@drawable/ic_settings_development"
+        android:key="@string/pk_developer_options_entry"
+        android:title="@string/developer_options_settings"
+        settings:controller="com.android.car.settings.system.DeveloperOptionsEntryPreferenceController"/>
 </PreferenceScreen>
diff --git a/src/com/android/car/settings/development/DeveloperOptionsFragment.java b/src/com/android/car/settings/development/DeveloperOptionsFragment.java
new file mode 100644
index 0000000..f8d8fb4
--- /dev/null
+++ b/src/com/android/car/settings/development/DeveloperOptionsFragment.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.settings.development;
+
+import android.car.userlib.CarUserManagerHelper;
+import android.os.Bundle;
+import android.widget.Switch;
+
+import androidx.annotation.LayoutRes;
+import androidx.annotation.XmlRes;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.BasePreferenceFragment;
+
+/**
+ * Fragment which displays all of the developer options. It also has a switch to disable developer
+ * options, if desired.
+ */
+public class DeveloperOptionsFragment extends BasePreferenceFragment {
+
+    private Switch mOnOffSwitch;
+
+    private final EnableDeveloperSettingsWarningDialog.DeveloperSettingsToggleListener mListener =
+            new EnableDeveloperSettingsWarningDialog.DeveloperSettingsToggleListener() {
+                @Override
+                public void onEnableDeveloperSettingsConfirmed() {
+                    DevelopmentSettingsUtil.setDevelopmentSettingsEnabled(getContext(), true);
+                }
+
+                @Override
+                public void onEnableDeveloperSettingsRejected() {
+                    mOnOffSwitch.setChecked(false);
+                }
+            };
+
+    @Override
+    @XmlRes
+    protected int getPreferenceScreenResId() {
+        return R.xml.developer_options_fragment;
+    }
+
+    @Override
+    @LayoutRes
+    protected int getActionBarLayoutId() {
+        return R.layout.action_bar_with_toggle;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        EnableDeveloperSettingsWarningDialog dialog =
+                (EnableDeveloperSettingsWarningDialog) getFragmentController().findDialogByTag(
+                        EnableDeveloperSettingsWarningDialog.TAG);
+        if (dialog != null) {
+            dialog.setEnableDeveloperSettingsWarningListener(mListener);
+        }
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        mOnOffSwitch = requireActivity().findViewById(R.id.toggle_switch);
+
+        CarUserManagerHelper carUserManagerHelper = new CarUserManagerHelper(getContext());
+        mOnOffSwitch.setChecked(DevelopmentSettingsUtil.isDevelopmentSettingsEnabled(getContext(),
+                carUserManagerHelper));
+        mOnOffSwitch.setOnCheckedChangeListener(
+                (buttonView, isChecked) -> {
+                    if (isChecked) {
+                        EnableDeveloperSettingsWarningDialog dialog =
+                                new EnableDeveloperSettingsWarningDialog();
+                        dialog.setEnableDeveloperSettingsWarningListener(mListener);
+                        DeveloperOptionsFragment.this.getFragmentController().showDialog(dialog,
+                                EnableDeveloperSettingsWarningDialog.TAG);
+                    } else {
+                        DevelopmentSettingsUtil.setDevelopmentSettingsEnabled(getContext(), false);
+                    }
+                });
+    }
+}
diff --git a/src/com/android/car/settings/development/EnableDeveloperSettingsWarningDialog.java b/src/com/android/car/settings/development/EnableDeveloperSettingsWarningDialog.java
new file mode 100644
index 0000000..6033e8c
--- /dev/null
+++ b/src/com/android/car/settings/development/EnableDeveloperSettingsWarningDialog.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.settings.development;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+
+import androidx.fragment.app.DialogFragment;
+
+import com.android.car.settings.R;
+
+/** A dialog which confirms that the user wants to enable developer settings. */
+public class EnableDeveloperSettingsWarningDialog extends DialogFragment {
+
+    /**
+     * Tag used to open and identify the dialog fragment from the FragmentManager or
+     * FragmentController.
+     */
+    public static final String TAG = "EnableDeveloperSettingsWarningDialog";
+
+    private DeveloperSettingsToggleListener mListener;
+
+    /**
+     * Sets a listener which determines the action for the positive and negative actions on this
+     * dialog.
+     */
+    public void setEnableDeveloperSettingsWarningListener(
+            DeveloperSettingsToggleListener listener) {
+        mListener = listener;
+    }
+
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        return new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.dev_settings_warning_title)
+                .setMessage(R.string.dev_settings_warning_message)
+                .setPositiveButton(android.R.string.yes,
+                        (dialog, which) -> mListener.onEnableDeveloperSettingsConfirmed())
+                .setNegativeButton(android.R.string.no,
+                        (dialog, which) -> mListener.onEnableDeveloperSettingsRejected())
+                .create();
+    }
+
+    /**
+     * Interface for listeners that want a callback when a user selects the positive or negative
+     * button on this dialog.
+     */
+    public interface DeveloperSettingsToggleListener {
+        /** Action to take on positive button selected. */
+        void onEnableDeveloperSettingsConfirmed();
+
+        /** Action to take on negative button selected. */
+        void onEnableDeveloperSettingsRejected();
+    }
+}
diff --git a/src/com/android/car/settings/system/DeveloperOptionsEntryPreferenceController.java b/src/com/android/car/settings/system/DeveloperOptionsEntryPreferenceController.java
new file mode 100644
index 0000000..7cf27f8
--- /dev/null
+++ b/src/com/android/car/settings/system/DeveloperOptionsEntryPreferenceController.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.settings.system;
+
+import android.car.userlib.CarUserManagerHelper;
+import android.content.Context;
+
+import com.android.car.settings.common.FragmentController;
+import com.android.car.settings.common.NoSetupPreferenceController;
+import com.android.car.settings.development.DevelopmentSettingsUtil;
+
+/** Controls the visibility of the developer options setting. */
+public class DeveloperOptionsEntryPreferenceController extends NoSetupPreferenceController {
+
+    private CarUserManagerHelper mCarUserManagerHelper;
+
+    public DeveloperOptionsEntryPreferenceController(Context context,
+            String preferenceKey,
+            FragmentController fragmentController) {
+        super(context, preferenceKey, fragmentController);
+        mCarUserManagerHelper = new CarUserManagerHelper(mContext);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return DevelopmentSettingsUtil.isDevelopmentSettingsEnabled(mContext, mCarUserManagerHelper)
+                ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+    }
+}
diff --git a/tests/robotests/src/com/android/car/settings/development/DeveloperOptionsFragmentTest.java b/tests/robotests/src/com/android/car/settings/development/DeveloperOptionsFragmentTest.java
new file mode 100644
index 0000000..9e7b6ba
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/development/DeveloperOptionsFragmentTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.settings.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.car.userlib.CarUserManagerHelper;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.widget.Switch;
+
+import androidx.fragment.app.DialogFragment;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.R;
+import com.android.car.settings.testutils.BaseTestActivity;
+import com.android.car.settings.testutils.DialogTestUtils;
+import com.android.car.settings.testutils.ShadowCarUserManagerHelper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(CarSettingsRobolectricTestRunner.class)
+@Config(shadows = {ShadowCarUserManagerHelper.class})
+public class DeveloperOptionsFragmentTest {
+
+    private BaseTestActivity mTestActivity;
+    private DeveloperOptionsFragment mDeveloperOptionsFragment;
+    private Context mContext;
+    @Mock
+    private CarUserManagerHelper mCarUserManagerHelper;
+
+    @Before
+    public void setUpTestActivity() {
+        MockitoAnnotations.initMocks(this);
+        ShadowCarUserManagerHelper.setMockInstance(mCarUserManagerHelper);
+        mContext = RuntimeEnvironment.application;
+        mTestActivity = Robolectric.setupActivity(BaseTestActivity.class);
+        mDeveloperOptionsFragment = new DeveloperOptionsFragment();
+
+        // Setup admin user who is able to enable developer settings.
+        UserInfo userInfo = new UserInfo();
+        when(mCarUserManagerHelper.isCurrentProcessAdminUser()).thenReturn(true);
+        when(mCarUserManagerHelper.isCurrentProcessDemoUser()).thenReturn(false);
+        when(mCarUserManagerHelper.getCurrentProcessUserInfo()).thenReturn(userInfo);
+        new CarUserManagerHelper(mContext).setUserRestriction(userInfo,
+                UserManager.DISALLOW_DEBUGGING_FEATURES, false);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowCarUserManagerHelper.reset();
+    }
+
+    @Test
+    public void testOnActivityCreated_devSettingsEnabled_switchOn() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+        mTestActivity.launchFragment(mDeveloperOptionsFragment);
+        Switch onOffSwitch = mTestActivity.findViewById(R.id.toggle_switch);
+        assertThat(onOffSwitch.isChecked()).isTrue();
+    }
+
+    @Test
+    public void testOnActivityCreated_devSettingsDisabled_switchOff() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
+        mTestActivity.launchFragment(mDeveloperOptionsFragment);
+        Switch onOffSwitch = mTestActivity.findViewById(R.id.toggle_switch);
+        assertThat(onOffSwitch.isChecked()).isFalse();
+    }
+
+    @Test
+    public void testToggleSwitchOff_devSettingsDisabled() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+        mTestActivity.launchFragment(mDeveloperOptionsFragment);
+        Switch onOffSwitch = mTestActivity.findViewById(R.id.toggle_switch);
+        onOffSwitch.setChecked(false);
+
+        assertThat(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1)).isEqualTo(0);
+    }
+
+    @Test
+    public void testToggleSwitchOn_dialogShown() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
+        mTestActivity.launchFragment(mDeveloperOptionsFragment);
+        Switch onOffSwitch = mTestActivity.findViewById(R.id.toggle_switch);
+        onOffSwitch.setChecked(true);
+
+        assertThat(mDeveloperOptionsFragment.getFragmentController().findDialogByTag(
+                EnableDeveloperSettingsWarningDialog.TAG)).isNotNull();
+    }
+
+    @Test
+    public void testDialogListener_positiveClick_devSettingsEnabled() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
+        mTestActivity.launchFragment(mDeveloperOptionsFragment);
+        Switch onOffSwitch = mTestActivity.findViewById(R.id.toggle_switch);
+        onOffSwitch.setChecked(true);
+        DialogFragment dialog = mDeveloperOptionsFragment.getFragmentController().findDialogByTag(
+                EnableDeveloperSettingsWarningDialog.TAG);
+
+        DialogTestUtils.clickPositiveButton(dialog);
+
+        assertThat(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0)).isEqualTo(1);
+    }
+
+    @Test
+    public void testDialogListener_negativeClick_switchOff() {
+        mTestActivity.launchFragment(mDeveloperOptionsFragment);
+        Switch onOffSwitch = mTestActivity.findViewById(R.id.toggle_switch);
+        onOffSwitch.setChecked(true);
+        DialogFragment dialog = mDeveloperOptionsFragment.getFragmentController().findDialogByTag(
+                EnableDeveloperSettingsWarningDialog.TAG);
+
+        DialogTestUtils.clickNegativeButton(dialog);
+
+        assertThat(onOffSwitch.isChecked()).isFalse();
+    }
+}
diff --git a/tests/robotests/src/com/android/car/settings/development/EnableDeveloperSettingsWarningDialogTest.java b/tests/robotests/src/com/android/car/settings/development/EnableDeveloperSettingsWarningDialogTest.java
new file mode 100644
index 0000000..dfe2f8c
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/development/EnableDeveloperSettingsWarningDialogTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.settings.development;
+
+import static org.mockito.Mockito.verify;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.testutils.BaseTestActivity;
+import com.android.car.settings.testutils.DialogTestUtils;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.Robolectric;
+
+@RunWith(CarSettingsRobolectricTestRunner.class)
+public class EnableDeveloperSettingsWarningDialogTest {
+
+    private BaseTestActivity mTestActivity;
+    private EnableDeveloperSettingsWarningDialog mDialog;
+    @Mock
+    private EnableDeveloperSettingsWarningDialog.DeveloperSettingsToggleListener mListener;
+
+    @Before
+    public void setUpTestActivity() {
+        MockitoAnnotations.initMocks(this);
+
+        mTestActivity = Robolectric.setupActivity(BaseTestActivity.class);
+        mDialog = new EnableDeveloperSettingsWarningDialog();
+        mDialog.setEnableDeveloperSettingsWarningListener(mListener);
+        mTestActivity.showDialog(mDialog, EnableDeveloperSettingsWarningDialog.TAG);
+    }
+
+    @Test
+    public void testPositiveButton_confirmListenerCalled() {
+        DialogTestUtils.clickPositiveButton(mDialog);
+        verify(mListener).onEnableDeveloperSettingsConfirmed();
+    }
+
+    @Test
+    public void testNegativeButton_rejectListenerCalled() {
+        DialogTestUtils.clickNegativeButton(mDialog);
+        verify(mListener).onEnableDeveloperSettingsRejected();
+    }
+}
diff --git a/tests/robotests/src/com/android/car/settings/system/DeveloperOptionsEntryPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/system/DeveloperOptionsEntryPreferenceControllerTest.java
new file mode 100644
index 0000000..f4b6291
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/system/DeveloperOptionsEntryPreferenceControllerTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.car.settings.system;
+
+import static com.android.car.settings.common.BasePreferenceController.AVAILABLE;
+import static com.android.car.settings.common.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.car.userlib.CarUserManagerHelper;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserManager;
+import android.provider.Settings;
+
+import androidx.preference.Preference;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.common.FragmentController;
+import com.android.car.settings.testutils.ShadowCarUserManagerHelper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(CarSettingsRobolectricTestRunner.class)
+@Config(shadows = {ShadowCarUserManagerHelper.class})
+public class DeveloperOptionsEntryPreferenceControllerTest {
+
+    private static final String PREFERENCE_KEY = "preference_key";
+
+    private Context mContext;
+    private DeveloperOptionsEntryPreferenceController mController;
+    private Preference mPreference;
+    private UserInfo mUserInfo;
+    @Mock
+    private CarUserManagerHelper mShadowCarUserManagerHelper;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        ShadowCarUserManagerHelper.setMockInstance(mShadowCarUserManagerHelper);
+        mContext = RuntimeEnvironment.application;
+        mController = new DeveloperOptionsEntryPreferenceController(mContext, PREFERENCE_KEY,
+                mock(FragmentController.class));
+        mPreference = new Preference(mContext);
+        mPreference.setKey(PREFERENCE_KEY);
+
+        // Setup admin user who is able to enable developer settings.
+        mUserInfo = new UserInfo();
+        when(mShadowCarUserManagerHelper.isCurrentProcessAdminUser()).thenReturn(true);
+        when(mShadowCarUserManagerHelper.isCurrentProcessDemoUser()).thenReturn(false);
+        when(mShadowCarUserManagerHelper.getCurrentProcessUserInfo()).thenReturn(mUserInfo);
+        new CarUserManagerHelper(mContext).setUserRestriction(mUserInfo,
+                UserManager.DISALLOW_DEBUGGING_FEATURES, false);
+    }
+
+    @After
+    public void tearDown() {
+        ShadowCarUserManagerHelper.reset();
+    }
+
+    @Test
+    public void testGetAvailabilityStatus_devOptionsEnabled_isAvailable() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    public void testGetAvailabilityStatus_devOptionsDisabled_isUnavailable() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+    }
+
+    @Test
+    public void testGetAvailabilityStatus_devOptionsEnabled_hasUserRestriction_isUnavailable() {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+        new CarUserManagerHelper(mContext).setUserRestriction(mUserInfo,
+                UserManager.DISALLOW_DEBUGGING_FEATURES, true);
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+    }
+}