Main location switch toggle off warning.

Bug: 193048804
Test: unit tests and manual test.

Change-Id: Icbceb19a4280a742081d4d8b85c04c9c3d924d50
diff --git a/res/values/overlayable.xml b/res/values/overlayable.xml
index a513719..77fc291 100644
--- a/res/values/overlayable.xml
+++ b/res/values/overlayable.xml
@@ -916,6 +916,7 @@
       <item type="string" name="location_state_switch_content_description"/>
       <item type="string" name="location_toggle_title"/>
       <item type="string" name="location_use_location_title"/>
+      <item type="string" name="location_toggle_off_warning"/>
       <item type="string" name="lock_settings_enter_password"/>
       <item type="string" name="lock_settings_enter_pattern"/>
       <item type="string" name="lock_settings_enter_pin"/>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7b50652..bd1950b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -827,6 +827,12 @@
     <string name="location_settings_title">Location</string>
     <!-- Title of location toggle setting [CHAR LIMIT=40] -->
     <string name="location_toggle_title">Use location</string>
+    <!-- Warning message when users try to toggle location off [CHAR LIMIT=NONE] -->
+    <string name="location_toggle_off_warning">
+        Turning off Location will turn off location access for all apps, Driver assistance features
+        will still have access. Turning off Driver assistance toggle will stop Driver assistance
+        features from using your location.
+    </string>
     <!-- Title of Recent Location Requests setting [CHAR LIMIT=60] -->
     <string name="location_settings_recent_requests_title">Recent Location Requests</string>
     <!-- Message indicating that no apps have requested location recently [CHAR LIMIT=60] -->
diff --git a/src/com/android/car/settings/location/LocationStateSwitchPreferenceController.java b/src/com/android/car/settings/location/LocationStateSwitchPreferenceController.java
index 9f7468a..c3f3f33 100644
--- a/src/com/android/car/settings/location/LocationStateSwitchPreferenceController.java
+++ b/src/com/android/car/settings/location/LocationStateSwitchPreferenceController.java
@@ -32,6 +32,7 @@
 
 import com.android.car.settings.R;
 import com.android.car.settings.common.ClickableWhileDisabledSwitchPreference;
+import com.android.car.settings.common.ConfirmationDialogFragment;
 import com.android.car.settings.common.FragmentController;
 import com.android.car.settings.common.PowerPolicyListener;
 import com.android.car.settings.common.PreferenceController;
@@ -85,6 +86,11 @@
     protected boolean handlePreferenceChanged(ClickableWhileDisabledSwitchPreference preference,
             Object newValue) {
         boolean locationEnabled = (Boolean) newValue;
+        if (!locationEnabled) {
+            getFragmentController().showDialog(getConfirmationDialog(),
+                    ConfirmationDialogFragment.TAG);
+            return false;
+        }
         Utils.updateLocationEnabled(
                 mContext,
                 locationEnabled,
@@ -132,4 +138,17 @@
             boolean enabled) {
         preference.setEnabled(enabled);
     }
+
+    private ConfirmationDialogFragment getConfirmationDialog() {
+        return new ConfirmationDialogFragment.Builder(getContext())
+                .setMessage(mContext.getString(R.string.location_toggle_off_warning))
+                .setPositiveButton(android.R.string.ok, arguments -> {
+                    Utils.updateLocationEnabled(
+                            mContext,
+                            false,
+                            UserHandle.myUserId(),
+                            Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS);
+                })
+                .build();
+    }
 }
diff --git a/tests/unit/src/com/android/car/settings/location/LocationStateSwitchPreferenceControllerTest.java b/tests/unit/src/com/android/car/settings/location/LocationStateSwitchPreferenceControllerTest.java
index 883f726..729f015 100644
--- a/tests/unit/src/com/android/car/settings/location/LocationStateSwitchPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/car/settings/location/LocationStateSwitchPreferenceControllerTest.java
@@ -19,13 +19,18 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.AlertDialog;
 import android.car.drivingstate.CarUxRestrictions;
 import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.location.LocationManager;
 import android.os.UserHandle;
@@ -34,13 +39,18 @@
 import androidx.preference.SwitchPreference;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
 
 import com.android.car.settings.common.ClickableWhileDisabledSwitchPreference;
+import com.android.car.settings.common.ConfirmationDialogFragment;
 import com.android.car.settings.common.FragmentController;
 import com.android.car.settings.common.PreferenceControllerTestUtil;
+import com.android.car.settings.testutils.BaseCarSettingsTestActivity;
 import com.android.car.settings.testutils.TestLifecycleOwner;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -60,6 +70,9 @@
     private FragmentController mFragmentController;
     @Mock
     private LocationManager mLocationManager;
+    @Rule
+    public ActivityTestRule<BaseCarSettingsTestActivity> mActivityTestRule =
+            new ActivityTestRule<>(BaseCarSettingsTestActivity.class);
 
     @Before
     public void setUp() {
@@ -94,23 +107,78 @@
     }
 
     @Test
-    public void onPreferenceClicked_locationDisabled_shouldEnable() {
+    public void onPreferenceClicked_locationDisabled_shouldEnable_notShowDialog() {
         initializePreference(/* checked= */ false, /* enabled= */ true);
 
         mSwitchPreference.performClick();
 
         assertThat(mSwitchPreference.isChecked()).isTrue();
         verify(mLocationManager).setLocationEnabledForUser(/* enabled= */ true, mUserHandle);
+        verify(mFragmentController, never()).showDialog(any(ConfirmationDialogFragment.class),
+                any());
     }
 
     @Test
-    public void onPreferenceClicked_locationEnabled_shouldDisable() {
+    public void onPreferenceClicked_locationEnabled_shouldStayEnable_showDialog() {
         initializePreference(/* checked= */ true, /* enabled= */ true);
 
         mSwitchPreference.performClick();
 
-        assertThat(mSwitchPreference.isChecked()).isFalse();
-        verify(mLocationManager).setLocationEnabledForUser(/* enabled= */ false, mUserHandle);
+        assertThat(mSwitchPreference.isChecked()).isTrue();
+        verify(mLocationManager, never()).setLocationEnabledForUser(/* enabled= */ anyBoolean(),
+                any());
+        verify(mFragmentController).showDialog(any(ConfirmationDialogFragment.class),
+                eq(ConfirmationDialogFragment.TAG));
+    }
+
+    @Test
+    public void confirmDialog_turnOffLocation() throws Throwable {
+        initializePreference(/* checked= */ true, /* enabled= */ true);
+
+        mSwitchPreference.performClick();
+
+        // Capture the dialog that is shown on toggle.
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mFragmentController).showDialog(dialogCaptor.capture(),
+                eq(ConfirmationDialogFragment.TAG));
+
+        // Show the captured dialog on press the confirmation button.
+        ConfirmationDialogFragment dialog = dialogCaptor.getValue();
+        assertThat(dialogCaptor).isNotNull();
+        AlertDialog alertDialog = showDialog(dialog);
+        mActivityTestRule.runOnUiThread(() -> {
+            alertDialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick();
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(mLocationManager).setLocationEnabledForUser(/* enabled= */ false,
+                mUserHandle);
+    }
+
+    @Test
+    public void cancelDialog_LocationStaysOn() throws Throwable {
+        initializePreference(/* checked= */ true, /* enabled= */ true);
+
+        mSwitchPreference.performClick();
+
+        // Capture the dialog that is shown on toggle.
+        ArgumentCaptor<ConfirmationDialogFragment> dialogCaptor = ArgumentCaptor.forClass(
+                ConfirmationDialogFragment.class);
+        verify(mFragmentController).showDialog(dialogCaptor.capture(),
+                eq(ConfirmationDialogFragment.TAG));
+
+        // Show the captured dialog on press the confirmation button.
+        ConfirmationDialogFragment dialog = dialogCaptor.getValue();
+        assertThat(dialogCaptor).isNotNull();
+        AlertDialog alertDialog = showDialog(dialog);
+        mActivityTestRule.runOnUiThread(() -> {
+            alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL).performClick();
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+        verify(mLocationManager, never()).setLocationEnabledForUser(/* enabled= */ false,
+                mUserHandle);
     }
 
     @Test
@@ -138,4 +206,13 @@
         mSwitchPreference.setChecked(checked);
         mSwitchPreference.setEnabled(enabled);
     }
+
+    private AlertDialog showDialog(ConfirmationDialogFragment dialog) throws Throwable {
+        mActivityTestRule.runOnUiThread(() -> {
+            dialog.show(mActivityTestRule.getActivity().getSupportFragmentManager(),
+                    /* tag= */ null);
+        });
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        return (AlertDialog) dialog.getDialog();
+    }
 }