/* * Copyright (C) 2019 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.server; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.location.Country; import android.location.CountryListener; import android.location.ICountryListener; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import androidx.test.core.app.ApplicationProvider; import com.android.internal.R; import com.android.server.location.countrydetector.ComprehensiveCountryDetector; import com.android.server.location.countrydetector.CustomCountryDetectorTestClass; import com.google.common.truth.Expect; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class CountryDetectorServiceTest { private static final String VALID_CUSTOM_TEST_CLASS = "com.android.server.location.countrydetector.CustomCountryDetectorTestClass"; private static final String INVALID_CUSTOM_TEST_CLASS = "com.android.server.location.MissingCountryDetectorTestClass"; private static class CountryListenerTester extends ICountryListener.Stub { private Country mCountry; @Override public void onCountryDetected(Country country) { mCountry = country; } Country getCountry() { return mCountry; } public boolean isNotified() { return mCountry != null; } } private static class CountryDetectorServiceTester extends CountryDetectorService { private CountryListener mListener; CountryDetectorServiceTester(Context context, Handler handler) { super(context, handler); } @Override public void notifyReceivers(Country country) { super.notifyReceivers(country); } @Override protected void setCountryListener(final CountryListener listener) { mListener = listener; } boolean isListenerSet() { return mListener != null; } } @Rule public final Expect expect = Expect.create(); @Spy private Context mContext = ApplicationProvider.getApplicationContext(); @Spy private Handler mHandler = new Handler(Looper.myLooper()); @Mock private Resources mResources; private CountryDetectorServiceTester mCountryDetectorService; @BeforeClass public static void oneTimeInitialization() { if (Looper.myLooper() == null) { Looper.prepare(); } } @Before public void setUp() { mCountryDetectorService = new CountryDetectorServiceTester(mContext, mHandler); // Immediately invoke run on the Runnable posted to the handler doAnswer(invocation -> { Message message = invocation.getArgument(0); message.getCallback().run(); return true; }).when(mHandler).sendMessageAtTime(any(Message.class), anyLong()); doReturn(mResources).when(mContext).getResources(); } @Test public void addCountryListener_validListener_listenerAdded() throws RemoteException { CountryListenerTester countryListener = new CountryListenerTester(); mCountryDetectorService.systemRunning(); expect.that(mCountryDetectorService.isListenerSet()).isFalse(); mCountryDetectorService.addCountryListener(countryListener); expect.that(mCountryDetectorService.isListenerSet()).isTrue(); } @Test public void removeCountryListener_validListener_listenerRemoved() throws RemoteException { CountryListenerTester countryListener = new CountryListenerTester(); mCountryDetectorService.systemRunning(); mCountryDetectorService.addCountryListener(countryListener); expect.that(mCountryDetectorService.isListenerSet()).isTrue(); mCountryDetectorService.removeCountryListener(countryListener); expect.that(mCountryDetectorService.isListenerSet()).isFalse(); } @Test(expected = RemoteException.class) public void addCountryListener_serviceNotReady_throwsException() throws RemoteException { CountryListenerTester countryListener = new CountryListenerTester(); expect.that(mCountryDetectorService.isSystemReady()).isFalse(); mCountryDetectorService.addCountryListener(countryListener); } @Test(expected = RemoteException.class) public void removeCountryListener_serviceNotReady_throwsException() throws RemoteException { CountryListenerTester countryListener = new CountryListenerTester(); expect.that(mCountryDetectorService.isSystemReady()).isFalse(); mCountryDetectorService.removeCountryListener(countryListener); } @Test public void detectCountry_serviceNotReady_returnNull() { expect.that(mCountryDetectorService.isSystemReady()).isFalse(); expect.that(mCountryDetectorService.detectCountry()).isNull(); } @Test public void notifyReceivers_twoListenersRegistered_bothNotified() throws RemoteException { CountryListenerTester countryListenerA = new CountryListenerTester(); CountryListenerTester countryListenerB = new CountryListenerTester(); Country country = new Country("US", Country.COUNTRY_SOURCE_NETWORK); mCountryDetectorService.systemRunning(); mCountryDetectorService.addCountryListener(countryListenerA); mCountryDetectorService.addCountryListener(countryListenerB); //Immediate Callback Info support at ag/20470367 expect.that(countryListenerA.isNotified()).isTrue(); expect.that(countryListenerB.isNotified()).isTrue(); mCountryDetectorService.notifyReceivers(country); expect.that(countryListenerA.isNotified()).isTrue(); expect.that(countryListenerB.isNotified()).isTrue(); expect.that(countryListenerA.getCountry().equalsIgnoreSource(country)).isTrue(); expect.that(countryListenerB.getCountry().equalsIgnoreSource(country)).isTrue(); } @Test public void initialize_deviceWithCustomDetector_useCustomDetectorClass() { when(mResources.getString(R.string.config_customCountryDetector)) .thenReturn(VALID_CUSTOM_TEST_CLASS); mCountryDetectorService.initialize(); expect.that(mCountryDetectorService.getCountryDetector()) .isInstanceOf(CustomCountryDetectorTestClass.class); } @Test public void initialize_deviceWithInvalidCustomDetector_useDefaultDetector() { when(mResources.getString(R.string.config_customCountryDetector)) .thenReturn(INVALID_CUSTOM_TEST_CLASS); mCountryDetectorService.initialize(); expect.that(mCountryDetectorService.getCountryDetector()) .isInstanceOf(ComprehensiveCountryDetector.class); } }