Merge "CountryDetector: Enable detector class override for automotive" into qt-qpr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
6ac8c0d096
@@ -4273,7 +4273,11 @@
|
||||
<!-- Boolean indicating whether frameworks needs to reset cell broadcast geo-fencing
|
||||
check after reboot or airplane mode toggling -->
|
||||
<bool translatable="false" name="reset_geo_fencing_check_after_boot_or_apm">false</bool>
|
||||
|
||||
<!-- Boolean indicating that the system will use autoSuspend. If set to false, autoSuspend
|
||||
is not used and the system will only suspend upon an explicit request. -->
|
||||
<bool translatable="false" name="config_enableAutoSuspend">true</bool>
|
||||
|
||||
<!-- Class name of the custom country detector to be used. -->
|
||||
<string name="config_customCountryDetector" translatable="false">com.android.server.location.ComprehensiveCountryDetector</string>
|
||||
</resources>
|
||||
|
||||
@@ -3689,6 +3689,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" />
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -193,11 +210,33 @@ public class CountryDetectorService extends ICountryDetector.Stub {
|
||||
mHandler.post(() -> mCountryDetector.setCountryListener(listener));
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user