diff options
| author | 2020-01-07 22:07:03 +0000 | |
|---|---|---|
| committer | 2020-01-07 22:07:03 +0000 | |
| commit | 318d9e82dd55c76e687e43dfca3274501f43cdb9 (patch) | |
| tree | 9a2ea38ea9206869b5f0521ac2f4231964350898 | |
| parent | 986dad6da341250ffa874f95afc0e23d5b36161a (diff) | |
| parent | 34147601d85517847722d12ab8fad2be48cd0d31 (diff) | |
Merge "CountryDetector: Enable detector class override for automotive"
5 files changed, 159 insertions, 14 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index e839709c9c88..6691d4c5955b 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -4284,4 +4284,12 @@ <!-- Whether or not to use assistant stream volume separately from music volume --> <bool name="config_useAssistantVolume">false</bool> + + <!-- Whether to use a custom Bugreport handling. When true, ACTION_CUSTOM_BUGREPORT_REQUESTED + intent is broadcasted on bugreporting chord (instead of the default full bugreport + generation). --> + <bool name="config_customBugreport">false</bool> + + <!-- Class name of the custom country detector to be used. --> + <string name="config_customCountryDetector" translatable="false">com.android.server.location.ComprehensiveCountryDetector</string> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 129c862c09e7..01bd510dcf27 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3605,6 +3605,8 @@ <java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" /> + <java-symbol type="string" name="config_customCountryDetector" /> + <!-- For Foldables --> <java-symbol type="bool" name="config_lidControlsDisplayFold" /> <java-symbol type="string" name="config_foldedArea" /> diff --git a/services/core/java/com/android/server/CountryDetectorService.java b/services/core/java/com/android/server/CountryDetectorService.java index 861c731c69e0..b0132d35fa3b 100644 --- a/services/core/java/com/android/server/CountryDetectorService.java +++ b/services/core/java/com/android/server/CountryDetectorService.java @@ -24,21 +24,29 @@ import android.location.ICountryListener; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; +import android.text.TextUtils; import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.Slog; +import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.BackgroundThread; import com.android.internal.util.DumpUtils; import com.android.server.location.ComprehensiveCountryDetector; +import com.android.server.location.CountryDetectorBase; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.reflect.InvocationTargetException; import java.util.HashMap; /** - * This class detects the country that the user is in through {@link ComprehensiveCountryDetector}. + * This class detects the country that the user is in. The default country detection is made through + * {@link com.android.server.location.ComprehensiveCountryDetector}. It is possible to overlay the + * detection algorithm by overlaying the attribute R.string.config_customCountryDetector with the + * custom class name to use instead. The custom class must extend + * {@link com.android.server.location.CountryDetectorBase} * * @hide */ @@ -88,7 +96,7 @@ public class CountryDetectorService extends ICountryDetector.Stub { private final HashMap<IBinder, Receiver> mReceivers; private final Context mContext; - private ComprehensiveCountryDetector mCountryDetector; + private CountryDetectorBase mCountryDetector; private boolean mSystemReady; private Handler mHandler; private CountryListener mLocationBasedDetectorListener; @@ -184,8 +192,17 @@ public class CountryDetectorService extends ICountryDetector.Stub { }); } - private void initialize() { - mCountryDetector = new ComprehensiveCountryDetector(mContext); + @VisibleForTesting + void initialize() { + final String customCountryClass = mContext.getString(R.string.config_customCountryDetector); + if (!TextUtils.isEmpty(customCountryClass)) { + mCountryDetector = loadCustomCountryDetectorIfAvailable(customCountryClass); + } + + if (mCountryDetector == null) { + Slog.d(TAG, "Using default country detector"); + mCountryDetector = new ComprehensiveCountryDetector(mContext); + } mLocationBasedDetectorListener = country -> mHandler.post(() -> notifyReceivers(country)); } @@ -194,10 +211,32 @@ public class CountryDetectorService extends ICountryDetector.Stub { } @VisibleForTesting + CountryDetectorBase getCountryDetector() { + return mCountryDetector; + } + + @VisibleForTesting boolean isSystemReady() { return mSystemReady; } + private CountryDetectorBase loadCustomCountryDetectorIfAvailable( + final String customCountryClass) { + CountryDetectorBase customCountryDetector = null; + + Slog.d(TAG, "Using custom country detector class: " + customCountryClass); + try { + customCountryDetector = Class.forName(customCountryClass).asSubclass( + CountryDetectorBase.class).getConstructor(Context.class).newInstance( + mContext); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException + | NoSuchMethodException | InvocationTargetException e) { + Slog.e(TAG, "Could not instantiate the custom country detector class"); + } + + return customCountryDetector; + } + @SuppressWarnings("unused") @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) { @@ -206,9 +245,10 @@ public class CountryDetectorService extends ICountryDetector.Stub { try { final Printer p = new PrintWriterPrinter(fout); p.println("CountryDetectorService state:"); + p.println("Country detector class=" + mCountryDetector.getClass().getName()); p.println(" Number of listeners=" + mReceivers.keySet().size()); if (mCountryDetector == null) { - p.println(" ComprehensiveCountryDetector not initialized"); + p.println(" CountryDetector not initialized"); } else { p.println(" " + mCountryDetector.toString()); } diff --git a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java index e9c5ce7127de..d5483ffa5445 100644 --- a/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/CountryDetectorServiceTest.java @@ -19,8 +19,11 @@ 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; @@ -31,6 +34,10 @@ import android.os.RemoteException; import androidx.test.core.app.ApplicationProvider; +import com.android.internal.R; +import com.android.server.location.ComprehensiveCountryDetector; +import com.android.server.location.CustomCountryDetectorTestClass; + import com.google.common.truth.Expect; import org.junit.Before; @@ -38,12 +45,18 @@ 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.CustomCountryDetectorTestClass"; + private static final String INVALID_CUSTOM_TEST_CLASS = + "com.android.server.location.MissingCountryDetectorTestClass"; + private static class CountryListenerTester extends ICountryListener.Stub { private Country mCountry; @@ -83,12 +96,11 @@ public class CountryDetectorServiceTest { } } - @Rule - public final Expect expect = Expect.create(); - @Spy - private Context mContext = ApplicationProvider.getApplicationContext(); - @Spy - private Handler mHandler = new Handler(Looper.myLooper()); + @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 @@ -108,10 +120,12 @@ public class CountryDetectorServiceTest { message.getCallback().run(); return true; }).when(mHandler).sendMessageAtTime(any(Message.class), anyLong()); + + doReturn(mResources).when(mContext).getResources(); } @Test - public void countryListener_add_successful() throws RemoteException { + public void addCountryListener_validListener_listenerAdded() throws RemoteException { CountryListenerTester countryListener = new CountryListenerTester(); mCountryDetectorService.systemRunning(); @@ -122,7 +136,7 @@ public class CountryDetectorServiceTest { } @Test - public void countryListener_remove_successful() throws RemoteException { + public void removeCountryListener_validListener_listenerRemoved() throws RemoteException { CountryListenerTester countryListener = new CountryListenerTester(); mCountryDetectorService.systemRunning(); @@ -133,8 +147,31 @@ public class CountryDetectorServiceTest { 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 countryListener_notify_successful() throws RemoteException { + 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); @@ -151,4 +188,26 @@ public class CountryDetectorServiceTest { 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); + } } diff --git a/services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java b/services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java new file mode 100644 index 000000000000..e159012f1b54 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/location/CustomCountryDetectorTestClass.java @@ -0,0 +1,36 @@ +/* + * 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.location; + +import android.content.Context; +import android.location.Country; + +public class CustomCountryDetectorTestClass extends CountryDetectorBase { + public CustomCountryDetectorTestClass(Context ctx) { + super(ctx); + } + + @Override + public Country detectCountry() { + return null; + } + + @Override + public void stop() { + + } +} |