Improve location package test coverage

Bug: 190855176
Test: atest CarSettingsUnitTests
Change-Id: I29eeaca7ad26203d3e9af55fee2287df51e0b2f4
diff --git a/src/com/android/car/settings/location/RecentLocationRequestsEntryPreferenceController.java b/src/com/android/car/settings/location/RecentLocationRequestsEntryPreferenceController.java
index 882517c..10146a4 100644
--- a/src/com/android/car/settings/location/RecentLocationRequestsEntryPreferenceController.java
+++ b/src/com/android/car/settings/location/RecentLocationRequestsEntryPreferenceController.java
@@ -16,7 +16,6 @@
 
 package com.android.car.settings.location;
 
-import android.app.Service;
 import android.car.drivingstate.CarUxRestrictions;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -24,6 +23,7 @@
 import android.content.IntentFilter;
 import android.location.LocationManager;
 
+import androidx.annotation.VisibleForTesting;
 import androidx.preference.Preference;
 
 import com.android.car.settings.common.FragmentController;
@@ -35,7 +35,8 @@
 public class RecentLocationRequestsEntryPreferenceController extends
         PreferenceController<Preference> {
 
-    private static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =
+    @VisibleForTesting
+    static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =
             new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
 
     private final LocationManager mLocationManager;
@@ -49,8 +50,7 @@
     public RecentLocationRequestsEntryPreferenceController(Context context, String preferenceKey,
             FragmentController fragmentController, CarUxRestrictions uxRestrictions) {
         super(context, preferenceKey, fragmentController, uxRestrictions);
-        mLocationManager = (LocationManager) getContext().getSystemService(
-                Service.LOCATION_SERVICE);
+        mLocationManager = getContext().getSystemService(LocationManager.class);
     }
 
 
diff --git a/tests/robotests/src/com/android/car/settings/location/LocationServicesPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/location/LocationServicesPreferenceControllerTest.java
deleted file mode 100644
index bd25e20..0000000
--- a/tests/robotests/src/com/android/car/settings/location/LocationServicesPreferenceControllerTest.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.location;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.content.Intent;
-import android.location.SettingInjectorService;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-
-import androidx.lifecycle.Lifecycle;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceGroup;
-
-import com.android.car.settings.common.PreferenceControllerTestHelper;
-import com.android.settingslib.location.SettingsInjector;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-@RunWith(RobolectricTestRunner.class)
-public class LocationServicesPreferenceControllerTest {
-
-    private static final int PROFILE_ID = UserHandle.USER_CURRENT;
-
-    @Mock
-    private SettingsInjector mSettingsInjector;
-    private Context mContext;
-    private PreferenceControllerTestHelper<LocationServicesPreferenceController> mControllerHelper;
-    private LocationServicesPreferenceController mController;
-    private PreferenceGroup mCategory;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mCategory = new PreferenceCategory(mContext);
-        mControllerHelper = new PreferenceControllerTestHelper<>(mContext,
-                LocationServicesPreferenceController.class, mCategory);
-        mController = mControllerHelper.getController();
-        mController.setSettingsInjector(mSettingsInjector);
-    }
-
-    @Test
-    public void onStart_registersBroadcastReceiver() {
-        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
-        mContext.sendBroadcast(new Intent(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED));
-        verify(mSettingsInjector).reloadStatusMessages();
-    }
-
-    @Test
-    public void onStop_unregistersBroadcastReceiver() {
-        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
-        mContext.sendBroadcast(new Intent(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED));
-        verify(mSettingsInjector).reloadStatusMessages();
-
-        clearInvocations(mSettingsInjector);
-        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_STOP);
-        mContext.sendBroadcast(new Intent(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED));
-        verify(mSettingsInjector, never()).reloadStatusMessages();
-    }
-
-    @Test
-    public void updateState_addsInjectedSettingsToPreferenceCategory() {
-        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
-        Map<Integer, List<Preference>> samplePrefs = getSamplePreferences();
-        doReturn(samplePrefs).when(mSettingsInjector)
-                .getInjectedSettings(any(Context.class), anyInt());
-
-        mController.updateState(mCategory);
-
-        assertThat(mCategory.getPreferenceCount()).isEqualTo(samplePrefs.get(PROFILE_ID).size());
-    }
-
-    @Test
-    public void updateState_updatesPreferenceSummary() {
-        Map<Integer, List<Preference>> samplePrefs = getSamplePreferences();
-        doReturn(samplePrefs).when(mSettingsInjector)
-                .getInjectedSettings(any(Context.class), anyInt());
-        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
-        String summary = "Summary";
-        samplePrefs.get(PROFILE_ID).get(0).setSummary(summary);
-
-        mController.updateState(mCategory);
-
-        assertThat(mCategory.getPreference(0).getSummary()).isEqualTo(summary);
-    }
-
-    @Test
-    public void preferenceCategory_isVisibleIfThereAreInjectedSettings() {
-        doReturn(getSamplePreferences()).when(mSettingsInjector)
-                .getInjectedSettings(any(Context.class), anyInt());
-        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
-        mController.refreshUi();
-
-        assertThat(mCategory.isVisible()).isTrue();
-    }
-
-    @Test
-    public void preferenceCategory_isHiddenIfThereAreNoInjectedSettings() {
-        mControllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
-        mController.refreshUi();
-
-        assertThat(mCategory.isVisible()).isFalse();
-    }
-
-    private Map<Integer, List<Preference>> getSamplePreferences() {
-        Map<Integer, List<Preference>> preferences = new ArrayMap<>();
-        preferences.put(PROFILE_ID,
-                Arrays.asList(new Preference(mContext), new Preference(mContext),
-                        new Preference(mContext)));
-        return preferences;
-    }
-}
diff --git a/tests/robotests/src/com/android/car/settings/location/RecentLocationRequestsEntryPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/location/RecentLocationRequestsEntryPreferenceControllerTest.java
deleted file mode 100644
index cf87388..0000000
--- a/tests/robotests/src/com/android/car/settings/location/RecentLocationRequestsEntryPreferenceControllerTest.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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.location;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.content.Context;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import androidx.lifecycle.Lifecycle;
-import androidx.preference.Preference;
-
-import com.android.car.settings.common.PreferenceControllerTestHelper;
-import com.android.car.settings.testutils.ShadowLocationManager;
-import com.android.car.settings.testutils.ShadowSecureSettings;
-import com.android.settingslib.Utils;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowSecureSettings.class, ShadowLocationManager.class})
-public class RecentLocationRequestsEntryPreferenceControllerTest {
-
-    private RecentLocationRequestsEntryPreferenceController mController;
-    private Preference mPreference;
-
-    @Before
-    public void setUp() {
-        Context context = RuntimeEnvironment.application;
-        mPreference = new Preference(context);
-        PreferenceControllerTestHelper<RecentLocationRequestsEntryPreferenceController>
-                controllerHelper = new PreferenceControllerTestHelper<>(context,
-                RecentLocationRequestsEntryPreferenceController.class, mPreference);
-        mController = controllerHelper.getController();
-        controllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_START);
-    }
-
-    @After
-    public void tearDown() {
-        ShadowSecureSettings.reset();
-    }
-
-    @Test
-    public void refreshUi_locationOn_preferenceIsEnabled() {
-        setLocationEnabled(true);
-        mController.refreshUi();
-
-        assertThat(mPreference.isEnabled()).isTrue();
-    }
-
-    @Test
-    public void refreshUi_locationOff_preferenceIsDisabled() {
-        setLocationEnabled(false);
-        mController.refreshUi();
-
-        assertThat(mPreference.isEnabled()).isFalse();
-    }
-
-    @Test
-    public void locationModeChangedBroadcastSent_locationOff_preferenceIsDisabled() {
-        setLocationEnabled(true);
-        mController.refreshUi();
-        setLocationEnabled(false);
-
-        assertThat(mPreference.isEnabled()).isFalse();
-    }
-
-    @Test
-    public void locationModeChangedBroadcastSent_locationOn_preferenceIsEnabled() {
-        setLocationEnabled(false);
-        mController.refreshUi();
-        setLocationEnabled(true);
-
-        assertThat(mPreference.isEnabled()).isTrue();
-    }
-
-    private void setLocationEnabled(boolean enabled) {
-        Utils.updateLocationEnabled(RuntimeEnvironment.application, enabled, UserHandle.myUserId(),
-                Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS);
-    }
-}
diff --git a/tests/robotests/src/com/android/car/settings/location/RecentLocationRequestsPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/location/RecentLocationRequestsPreferenceControllerTest.java
deleted file mode 100644
index ccc58d2..0000000
--- a/tests/robotests/src/com/android/car/settings/location/RecentLocationRequestsPreferenceControllerTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.location;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-
-import androidx.lifecycle.Lifecycle;
-import androidx.preference.PreferenceManager;
-import androidx.preference.PreferenceScreen;
-
-import com.android.car.settings.R;
-import com.android.car.settings.common.PreferenceControllerTestHelper;
-import com.android.settingslib.location.RecentLocationApps;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-@RunWith(RobolectricTestRunner.class)
-public class RecentLocationRequestsPreferenceControllerTest {
-
-    @Mock
-    private RecentLocationApps mRecentLocationApps;
-
-    private RecentLocationRequestsPreferenceController mController;
-    private PreferenceScreen mScreen;
-    private Context mContext;
-
-    @Before
-    public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
-        mScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
-        PreferenceControllerTestHelper<RecentLocationRequestsPreferenceController>
-                controllerHelper = new PreferenceControllerTestHelper<>(mContext,
-                RecentLocationRequestsPreferenceController.class, mScreen);
-        mController = controllerHelper.getController();
-        mController.setRecentLocationApps(mRecentLocationApps);
-        controllerHelper.sendLifecycleEvent(Lifecycle.Event.ON_CREATE);
-    }
-
-    @Test
-    public void refreshUi_noRecentRequests_messageDisplayed() {
-        when(mRecentLocationApps.getAppListSorted(true)).thenReturn(Collections.emptyList());
-        mController.refreshUi();
-
-        assertThat(mScreen.getPreference(0).getTitle()).isEqualTo(
-                mContext.getString(R.string.location_settings_recent_requests_empty_message));
-    }
-
-    @Test
-    public void refreshUi_someRecentRequests_preferencesAddedToScreen() {
-        List<RecentLocationApps.Request> list = Arrays.asList(
-                mock(RecentLocationApps.Request.class),
-                mock(RecentLocationApps.Request.class),
-                mock(RecentLocationApps.Request.class));
-        when(mRecentLocationApps.getAppListSorted(true)).thenReturn(list);
-        mController.refreshUi();
-
-        assertThat(mScreen.getPreferenceCount()).isEqualTo(list.size());
-    }
-
-    @Test
-    public void refreshUi_newRecentRequests_listIsUpdated() {
-        List<RecentLocationApps.Request> list1 = Arrays.asList(
-                mock(RecentLocationApps.Request.class),
-                mock(RecentLocationApps.Request.class),
-                mock(RecentLocationApps.Request.class));
-        when(mRecentLocationApps.getAppListSorted(true)).thenReturn(list1);
-
-        List<RecentLocationApps.Request> list2 = new ArrayList<>(list1);
-        list2.add(mock(RecentLocationApps.Request.class));
-
-        mController.refreshUi();
-        assertThat(mScreen.getPreferenceCount()).isEqualTo(list1.size());
-
-        when(mRecentLocationApps.getAppListSorted(true)).thenReturn(list2);
-        mController.refreshUi();
-
-        assertThat(mScreen.getPreferenceCount()).isEqualTo(list2.size());
-    }
-}
diff --git a/tests/unit/src/com/android/car/settings/location/LocationServicesPreferenceControllerTest.java b/tests/unit/src/com/android/car/settings/location/LocationServicesPreferenceControllerTest.java
new file mode 100644
index 0000000..5f7586e
--- /dev/null
+++ b/tests/unit/src/com/android/car/settings/location/LocationServicesPreferenceControllerTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 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.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.settings.common.FragmentController;
+import com.android.car.settings.common.PreferenceControllerTestUtil;
+import com.android.car.settings.testutils.TestLifecycleOwner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+@RunWith(AndroidJUnit4.class)
+public class LocationServicesPreferenceControllerTest {
+    private static final int PROFILE_ID = UserHandle.USER_CURRENT;
+
+    private Context mContext = spy(ApplicationProvider.getApplicationContext());
+    private LifecycleOwner mLifecycleOwner;
+    private PreferenceCategory mPreference;
+    private LocationServicesPreferenceController mPreferenceController;
+    private CarUxRestrictions mCarUxRestrictions;
+
+    @Mock
+    private FragmentController mFragmentController;
+    @Mock
+    private CarLocationSettingsInjector mSettingsInjector;
+
+    @Before
+    @UiThreadTest
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mLifecycleOwner = new TestLifecycleOwner();
+        mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
+                CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
+
+        PreferenceManager preferenceManager = new PreferenceManager(mContext);
+        PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+        mPreference = new PreferenceCategory(mContext);
+        screen.addPreference(mPreference);
+        mPreferenceController = new LocationServicesPreferenceController(mContext,
+                "key", mFragmentController, mCarUxRestrictions);
+        mPreferenceController.setSettingsInjector(mSettingsInjector);
+        PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
+    }
+
+    @Test
+    public void onStart_registersBroadcastReceiver() {
+        mPreferenceController.onCreate(mLifecycleOwner);
+        mPreferenceController.onStart(mLifecycleOwner);
+        ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(
+                BroadcastReceiver.class);
+        verify(mContext).registerReceiver(captor.capture(), any());
+
+        captor.getValue().onReceive(mContext, new Intent());
+        verify(mSettingsInjector).reloadStatusMessages();
+    }
+
+    @Test
+    public void onStop_unregistersBroadcastReceiver() {
+        mPreferenceController.onCreate(mLifecycleOwner);
+        mPreferenceController.onStart(mLifecycleOwner);
+        ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(
+                BroadcastReceiver.class);
+        verify(mContext).registerReceiver(captor.capture(), any());
+
+        mPreferenceController.onStop(mLifecycleOwner);
+        verify(mContext).unregisterReceiver(captor.getValue());
+    }
+
+    @Test
+    public void updateState_addsInjectedSettingsToPreferenceCategory() {
+        mPreferenceController.onCreate(mLifecycleOwner);
+        mPreferenceController.onStart(mLifecycleOwner);
+        Map<Integer, List<Preference>> samplePrefs = getSamplePreferences();
+        doReturn(samplePrefs).when(mSettingsInjector)
+                .getInjectedSettings(any(Context.class), anyInt());
+
+        mPreferenceController.updateState(mPreference);
+
+        assertThat(mPreference.getPreferenceCount()).isEqualTo(samplePrefs.get(PROFILE_ID).size());
+    }
+
+    @Test
+    public void updateState_updatesPreferenceSummary() {
+        Map<Integer, List<Preference>> samplePrefs = getSamplePreferences();
+        doReturn(samplePrefs).when(mSettingsInjector)
+                .getInjectedSettings(any(Context.class), anyInt());
+        mPreferenceController.onCreate(mLifecycleOwner);
+        mPreferenceController.onStart(mLifecycleOwner);
+        String summary = "Summary";
+        samplePrefs.get(PROFILE_ID).get(0).setSummary(summary);
+
+        mPreferenceController.updateState(mPreference);
+
+        assertThat(mPreference.getPreference(0).getSummary()).isEqualTo(summary);
+    }
+
+    @Test
+    public void preferenceCategory_isVisibleIfThereAreInjectedSettings() {
+        doReturn(getSamplePreferences()).when(mSettingsInjector)
+                .getInjectedSettings(any(Context.class), anyInt());
+        mPreferenceController.onCreate(mLifecycleOwner);
+        mPreferenceController.refreshUi();
+
+        assertThat(mPreference.isVisible()).isTrue();
+    }
+
+    @Test
+    public void preferenceCategory_isHiddenIfThereAreNoInjectedSettings() {
+        mPreferenceController.onCreate(mLifecycleOwner);
+        mPreferenceController.refreshUi();
+
+        assertThat(mPreference.isVisible()).isFalse();
+    }
+
+    private Map<Integer, List<Preference>> getSamplePreferences() {
+        Map<Integer, List<Preference>> preferences = new ArrayMap<>();
+        preferences.put(PROFILE_ID,
+                Arrays.asList(new Preference(mContext), new Preference(mContext),
+                        new Preference(mContext)));
+        return preferences;
+    }
+}
diff --git a/tests/unit/src/com/android/car/settings/location/RecentLocationRequestsEntryPreferenceControllerTest.java b/tests/unit/src/com/android/car/settings/location/RecentLocationRequestsEntryPreferenceControllerTest.java
new file mode 100644
index 0000000..b18c817
--- /dev/null
+++ b/tests/unit/src/com/android/car/settings/location/RecentLocationRequestsEntryPreferenceControllerTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2021 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.location;
+
+import static com.android.car.settings.location.RecentLocationRequestsEntryPreferenceController.INTENT_FILTER_LOCATION_MODE_CHANGED;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.LocationManager;
+import android.os.UserHandle;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.settings.common.FragmentController;
+import com.android.car.settings.common.PreferenceControllerTestUtil;
+import com.android.car.settings.testutils.TestLifecycleOwner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class RecentLocationRequestsEntryPreferenceControllerTest {
+    private static final long TIMEOUT_MS = 5000;
+
+    private Context mContext = spy(ApplicationProvider.getApplicationContext());
+    private LifecycleOwner mLifecycleOwner;
+    private Preference mPreference;
+    private RecentLocationRequestsEntryPreferenceController mPreferenceController;
+    private CarUxRestrictions mCarUxRestrictions;
+    private LocationManager mLocationManager;
+
+    @Mock
+    private FragmentController mFragmentController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mLifecycleOwner = new TestLifecycleOwner();
+        mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
+                CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
+
+        mLocationManager = mContext.getSystemService(LocationManager.class);
+
+        mPreference = new Preference(mContext);
+        mPreferenceController = new RecentLocationRequestsEntryPreferenceController(mContext,
+                "key", mFragmentController, mCarUxRestrictions);
+        PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference);
+
+        mPreferenceController.onCreate(mLifecycleOwner);
+    }
+
+    @Test
+    public void onStart_registersBroadcastReceiver() {
+        mPreferenceController.onStart(mLifecycleOwner);
+        verify(mContext).registerReceiver(any(BroadcastReceiver.class),
+                eq(INTENT_FILTER_LOCATION_MODE_CHANGED));
+    }
+
+    @Test
+    public void onStop_unregistersBroadcastReceiver() {
+        mPreferenceController.onStart(mLifecycleOwner);
+        ArgumentCaptor<BroadcastReceiver> captor = ArgumentCaptor.forClass(
+                BroadcastReceiver.class);
+        verify(mContext).registerReceiver(captor.capture(),
+                eq(INTENT_FILTER_LOCATION_MODE_CHANGED));
+
+        mPreferenceController.onStop(mLifecycleOwner);
+        verify(mContext).unregisterReceiver(captor.getValue());
+    }
+
+    @Test
+    public void refreshUi_locationOn_preferenceIsEnabled() {
+        setLocationEnabled(true);
+        mPreferenceController.refreshUi();
+
+        assertThat(mPreference.isEnabled()).isTrue();
+    }
+
+    @Test
+    public void refreshUi_locationOff_preferenceIsDisabled() {
+        setLocationEnabled(false);
+        mPreferenceController.refreshUi();
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void locationModeChangedBroadcastSent_locationOff_preferenceIsDisabled() {
+        mPreferenceController.onStart(mLifecycleOwner);
+        setLocationEnabled(true);
+        mPreferenceController.refreshUi();
+        setLocationEnabled(false);
+
+        assertThat(mPreference.isEnabled()).isFalse();
+    }
+
+    @Test
+    public void locationModeChangedBroadcastSent_locationOn_preferenceIsEnabled() {
+        mPreferenceController.onStart(mLifecycleOwner);
+        setLocationEnabled(false);
+        mPreferenceController.refreshUi();
+        setLocationEnabled(true);
+
+        assertThat(mPreference.isEnabled()).isTrue();
+    }
+
+    private void setLocationEnabled(boolean enabled) {
+        CountDownLatch latch = new CountDownLatch(1);
+        BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                latch.countDown();
+            }
+        };
+        mContext.registerReceiver(receiver, new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
+        try {
+            mLocationManager.setLocationEnabledForUser(enabled,
+                    UserHandle.of(UserHandle.myUserId()));
+            assertWithMessage("%s intent reveiced in %sms", LocationManager.MODE_CHANGED_ACTION,
+                    TIMEOUT_MS).that(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
+        } catch (InterruptedException e) {
+            assertThat(mLocationManager.isLocationEnabled()).isEqualTo(enabled);
+        } finally {
+            mContext.unregisterReceiver(receiver);
+        }
+    }
+}
diff --git a/tests/unit/src/com/android/car/settings/location/RecentLocationRequestsPreferenceControllerTest.java b/tests/unit/src/com/android/car/settings/location/RecentLocationRequestsPreferenceControllerTest.java
new file mode 100644
index 0000000..e3e6866
--- /dev/null
+++ b/tests/unit/src/com/android/car/settings/location/RecentLocationRequestsPreferenceControllerTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 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.location;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
+
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.FragmentController;
+import com.android.car.settings.common.LogicalPreferenceGroup;
+import com.android.car.settings.common.PreferenceControllerTestUtil;
+import com.android.car.settings.testutils.TestLifecycleOwner;
+import com.android.settingslib.location.RecentLocationApps;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+public class RecentLocationRequestsPreferenceControllerTest {
+    private Context mContext = ApplicationProvider.getApplicationContext();
+    private LifecycleOwner mLifecycleOwner;
+    private PreferenceGroup mPreferenceGroup;
+    private RecentLocationRequestsPreferenceController mPreferenceController;
+    private CarUxRestrictions mCarUxRestrictions;
+
+    @Mock
+    private FragmentController mFragmentController;
+    @Mock
+    private RecentLocationApps mRecentLocationApps;
+
+    @Before
+    @UiThreadTest
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mLifecycleOwner = new TestLifecycleOwner();
+        mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true,
+                CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build();
+
+        PreferenceManager preferenceManager = new PreferenceManager(mContext);
+        PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+        mPreferenceGroup = new LogicalPreferenceGroup(mContext);
+        screen.addPreference(mPreferenceGroup);
+        mPreferenceController = new RecentLocationRequestsPreferenceController(mContext,
+                "key", mFragmentController, mCarUxRestrictions);
+        mPreferenceController.setRecentLocationApps(mRecentLocationApps);
+        PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreferenceGroup);
+        mPreferenceController.onCreate(mLifecycleOwner);
+    }
+
+    @Test
+    public void refreshUi_noRecentRequests_messageDisplayed() {
+        when(mRecentLocationApps.getAppListSorted(true)).thenReturn(Collections.emptyList());
+        mPreferenceController.refreshUi();
+
+        assertThat(mPreferenceGroup.getPreference(0).getTitle()).isEqualTo(
+                mContext.getString(R.string.location_settings_recent_requests_empty_message));
+    }
+
+    @Test
+    public void refreshUi_someRecentRequests_preferencesAddedToScreen() {
+        List<RecentLocationApps.Request> list = Arrays.asList(
+                mock(RecentLocationApps.Request.class),
+                mock(RecentLocationApps.Request.class),
+                mock(RecentLocationApps.Request.class));
+        when(mRecentLocationApps.getAppListSorted(true)).thenReturn(list);
+        mPreferenceController.refreshUi();
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(list.size());
+    }
+
+    @Test
+    public void refreshUi_newRecentRequests_listIsUpdated() {
+        List<RecentLocationApps.Request> list1 = Arrays.asList(
+                mock(RecentLocationApps.Request.class),
+                mock(RecentLocationApps.Request.class),
+                mock(RecentLocationApps.Request.class));
+        when(mRecentLocationApps.getAppListSorted(true)).thenReturn(list1);
+
+        List<RecentLocationApps.Request> list2 = new ArrayList<>(list1);
+        list2.add(mock(RecentLocationApps.Request.class));
+
+        mPreferenceController.refreshUi();
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(list1.size());
+
+        when(mRecentLocationApps.getAppListSorted(true)).thenReturn(list2);
+        mPreferenceController.refreshUi();
+
+        assertThat(mPreferenceGroup.getPreferenceCount()).isEqualTo(list2.size());
+    }
+}