Merge "Fix EmergencyAffordanceService" into rvc-dev
This commit is contained in:
@@ -3496,10 +3496,9 @@
|
||||
|
||||
<!-- Do not translate. Mcc codes whose existence trigger the presence of emergency
|
||||
affordances-->
|
||||
<integer-array name="config_emergency_mcc_codes" translatable="false">
|
||||
<item>404</item>
|
||||
<item>405</item>
|
||||
</integer-array>
|
||||
<string-array name="config_emergency_iso_country_codes" translatable="false">
|
||||
<item>in</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Package name for the device provisioning package. -->
|
||||
<string name="config_deviceProvisioningPackage"></string>
|
||||
|
||||
@@ -3085,7 +3085,7 @@
|
||||
<java-symbol type="string" name="global_action_emergency" />
|
||||
<java-symbol type="string" name="config_emergency_call_number" />
|
||||
<java-symbol type="string" name="config_emergency_dialer_package" />
|
||||
<java-symbol type="array" name="config_emergency_mcc_codes" />
|
||||
<java-symbol type="array" name="config_emergency_iso_country_codes" />
|
||||
|
||||
<java-symbol type="string" name="config_dozeDoubleTapSensorType" />
|
||||
<java-symbol type="string" name="config_dozeTapSensorType" />
|
||||
|
||||
@@ -20,90 +20,80 @@ import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.CellInfo;
|
||||
import android.telephony.CellInfoGsm;
|
||||
import android.telephony.CellInfoLte;
|
||||
import android.telephony.CellInfoWcdma;
|
||||
import android.telephony.CellLocation;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Slog;
|
||||
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A service that listens to connectivity and SIM card changes and determines if the emergency mode
|
||||
* should be enabled
|
||||
* A service that listens to connectivity and SIM card changes and determines if the emergency
|
||||
* affordance should be enabled.
|
||||
*/
|
||||
public class EmergencyAffordanceService extends SystemService {
|
||||
|
||||
private static final String TAG = "EmergencyAffordanceService";
|
||||
private static final boolean DBG = false;
|
||||
|
||||
private static final int NUM_SCANS_UNTIL_ABORT = 4;
|
||||
private static final String SERVICE_NAME = "emergency_affordance";
|
||||
|
||||
private static final int INITIALIZE_STATE = 1;
|
||||
private static final int CELL_INFO_STATE_CHANGED = 2;
|
||||
private static final int SUBSCRIPTION_CHANGED = 3;
|
||||
|
||||
/**
|
||||
* Global setting, whether the last scan of the sim cards reveal that a sim was inserted that
|
||||
* requires the emergency affordance. The value is a boolean (1 or 0).
|
||||
* @hide
|
||||
* @param arg1 slot Index
|
||||
* @param arg2 0
|
||||
* @param obj ISO country code
|
||||
*/
|
||||
private static final String EMERGENCY_SIM_INSERTED_SETTING = "emergency_sim_inserted_before";
|
||||
private static final int NETWORK_COUNTRY_CHANGED = 2;
|
||||
private static final int SUBSCRIPTION_CHANGED = 3;
|
||||
private static final int UPDATE_AIRPLANE_MODE_STATUS = 4;
|
||||
|
||||
// Global Settings to override emergency affordance country ISO for debugging.
|
||||
// Available only on debug build. The value is a country ISO string in lower case (eg. "us").
|
||||
private static final String EMERGENCY_AFFORDANCE_OVERRIDE_ISO =
|
||||
"emergency_affordance_override_iso";
|
||||
|
||||
private final Context mContext;
|
||||
private final ArrayList<Integer> mEmergencyCallMccNumbers;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private TelephonyManager mTelephonyManager;
|
||||
// Country ISOs that require affordance
|
||||
private final ArrayList<String> mEmergencyCallCountryIsos;
|
||||
private SubscriptionManager mSubscriptionManager;
|
||||
private boolean mEmergencyAffordanceNeeded;
|
||||
private TelephonyManager mTelephonyManager;
|
||||
private MyHandler mHandler;
|
||||
private int mScansCompleted;
|
||||
private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
|
||||
@Override
|
||||
public void onCellInfoChanged(List<CellInfo> cellInfo) {
|
||||
if (!isEmergencyAffordanceNeeded()) {
|
||||
requestCellScan();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCellLocationChanged(CellLocation location) {
|
||||
if (!isEmergencyAffordanceNeeded()) {
|
||||
requestCellScan();
|
||||
}
|
||||
}
|
||||
};
|
||||
private BroadcastReceiver mAirplaneModeReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (Settings.Global.getInt(context.getContentResolver(),
|
||||
Settings.Global.AIRPLANE_MODE_ON, 0) == 0) {
|
||||
startScanning();
|
||||
requestCellScan();
|
||||
}
|
||||
}
|
||||
};
|
||||
private boolean mSimNeedsEmergencyAffordance;
|
||||
private boolean mNetworkNeedsEmergencyAffordance;
|
||||
private boolean mAnySimNeedsEmergencyAffordance;
|
||||
private boolean mAnyNetworkNeedsEmergencyAffordance;
|
||||
private boolean mEmergencyAffordanceNeeded;
|
||||
private boolean mAirplaneModeEnabled;
|
||||
private boolean mVoiceCapable;
|
||||
|
||||
private void requestCellScan() {
|
||||
mHandler.obtainMessage(CELL_INFO_STATE_CHANGED).sendToTarget();
|
||||
}
|
||||
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED.equals(intent.getAction())) {
|
||||
String countryCode = intent.getStringExtra(TelephonyManager.EXTRA_NETWORK_COUNTRY);
|
||||
int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX,
|
||||
SubscriptionManager.INVALID_SIM_SLOT_INDEX);
|
||||
mHandler.obtainMessage(
|
||||
NETWORK_COUNTRY_CHANGED, slotId, 0, countryCode).sendToTarget();
|
||||
} else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction())) {
|
||||
mHandler.obtainMessage(UPDATE_AIRPLANE_MODE_STATUS).sendToTarget();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener
|
||||
= new SubscriptionManager.OnSubscriptionsChangedListener() {
|
||||
@@ -116,207 +106,200 @@ public class EmergencyAffordanceService extends SystemService {
|
||||
public EmergencyAffordanceService(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
int[] numbers = context.getResources().getIntArray(
|
||||
com.android.internal.R.array.config_emergency_mcc_codes);
|
||||
mEmergencyCallMccNumbers = new ArrayList<>(numbers.length);
|
||||
for (int i = 0; i < numbers.length; i++) {
|
||||
mEmergencyCallMccNumbers.add(numbers[i]);
|
||||
String[] isos = context.getResources().getStringArray(
|
||||
com.android.internal.R.array.config_emergency_iso_country_codes);
|
||||
mEmergencyCallCountryIsos = new ArrayList<>(isos.length);
|
||||
for (String iso : isos) {
|
||||
mEmergencyCallCountryIsos.add(iso);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateEmergencyAffordanceNeeded() {
|
||||
synchronized (mLock) {
|
||||
mEmergencyAffordanceNeeded = mVoiceCapable && (mSimNeedsEmergencyAffordance ||
|
||||
mNetworkNeedsEmergencyAffordance);
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
|
||||
mEmergencyAffordanceNeeded ? 1 : 0);
|
||||
if (mEmergencyAffordanceNeeded) {
|
||||
stopScanning();
|
||||
if (Build.IS_DEBUGGABLE) {
|
||||
String overrideIso = Settings.Global.getString(
|
||||
mContext.getContentResolver(), EMERGENCY_AFFORDANCE_OVERRIDE_ISO);
|
||||
if (!TextUtils.isEmpty(overrideIso)) {
|
||||
if (DBG) Slog.d(TAG, "Override ISO to " + overrideIso);
|
||||
mEmergencyCallCountryIsos.clear();
|
||||
mEmergencyCallCountryIsos.add(overrideIso);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stopScanning() {
|
||||
synchronized (mLock) {
|
||||
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
|
||||
mScansCompleted = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEmergencyAffordanceNeeded() {
|
||||
synchronized (mLock) {
|
||||
return mEmergencyAffordanceNeeded;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
if (DBG) Slog.i(TAG, "onStart");
|
||||
publishBinderService(SERVICE_NAME, new BinderService());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
|
||||
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
|
||||
mVoiceCapable = mTelephonyManager.isVoiceCapable();
|
||||
if (!mVoiceCapable) {
|
||||
updateEmergencyAffordanceNeeded();
|
||||
return;
|
||||
}
|
||||
mSubscriptionManager = SubscriptionManager.from(mContext);
|
||||
HandlerThread thread = new HandlerThread(TAG);
|
||||
thread.start();
|
||||
mHandler = new MyHandler(thread.getLooper());
|
||||
mHandler.obtainMessage(INITIALIZE_STATE).sendToTarget();
|
||||
startScanning();
|
||||
IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
mContext.registerReceiver(mAirplaneModeReceiver, filter);
|
||||
mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionChangedListener);
|
||||
if (DBG) Slog.i(TAG, "onBootPhase");
|
||||
handleThirdPartyBootPhase();
|
||||
}
|
||||
}
|
||||
|
||||
private void startScanning() {
|
||||
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_INFO
|
||||
| PhoneStateListener.LISTEN_CELL_LOCATION);
|
||||
}
|
||||
|
||||
/** Handler to do the heavier work on */
|
||||
private class MyHandler extends Handler {
|
||||
|
||||
public MyHandler(Looper l) {
|
||||
super(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
if (DBG) Slog.d(TAG, "handleMessage: " + msg.what);
|
||||
switch (msg.what) {
|
||||
case INITIALIZE_STATE:
|
||||
handleInitializeState();
|
||||
break;
|
||||
case CELL_INFO_STATE_CHANGED:
|
||||
handleUpdateCellInfo();
|
||||
case NETWORK_COUNTRY_CHANGED:
|
||||
final String countryIso = (String) msg.obj;
|
||||
final int slotId = msg.arg1;
|
||||
handleNetworkCountryChanged(countryIso, slotId);
|
||||
break;
|
||||
case SUBSCRIPTION_CHANGED:
|
||||
handleUpdateSimSubscriptionInfo();
|
||||
break;
|
||||
case UPDATE_AIRPLANE_MODE_STATUS:
|
||||
handleUpdateAirplaneModeStatus();
|
||||
break;
|
||||
default:
|
||||
Slog.e(TAG, "Unexpected message received: " + msg.what);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleInitializeState() {
|
||||
if (handleUpdateSimSubscriptionInfo()) {
|
||||
return;
|
||||
}
|
||||
if (handleUpdateCellInfo()) {
|
||||
return;
|
||||
}
|
||||
if (DBG) Slog.d(TAG, "handleInitializeState");
|
||||
handleUpdateAirplaneModeStatus();
|
||||
handleUpdateSimSubscriptionInfo();
|
||||
updateNetworkCountry();
|
||||
updateEmergencyAffordanceNeeded();
|
||||
}
|
||||
|
||||
private boolean handleUpdateSimSubscriptionInfo() {
|
||||
boolean neededBefore = simNeededAffordanceBefore();
|
||||
boolean neededNow = neededBefore;
|
||||
private void handleThirdPartyBootPhase() {
|
||||
if (DBG) Slog.d(TAG, "handleThirdPartyBootPhase");
|
||||
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
|
||||
mVoiceCapable = mTelephonyManager.isVoiceCapable();
|
||||
if (!mVoiceCapable) {
|
||||
updateEmergencyAffordanceNeeded();
|
||||
return;
|
||||
}
|
||||
|
||||
HandlerThread thread = new HandlerThread(TAG);
|
||||
thread.start();
|
||||
mHandler = new MyHandler(thread.getLooper());
|
||||
|
||||
mSubscriptionManager = SubscriptionManager.from(mContext);
|
||||
mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionChangedListener);
|
||||
|
||||
IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
filter.addAction(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED);
|
||||
mContext.registerReceiver(mBroadcastReceiver, filter);
|
||||
|
||||
mHandler.obtainMessage(INITIALIZE_STATE).sendToTarget();
|
||||
}
|
||||
|
||||
private void handleUpdateAirplaneModeStatus() {
|
||||
mAirplaneModeEnabled = Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
|
||||
if (DBG) Slog.d(TAG, "APM status updated to " + mAirplaneModeEnabled);
|
||||
}
|
||||
|
||||
private void handleUpdateSimSubscriptionInfo() {
|
||||
List<SubscriptionInfo> activeSubscriptionInfoList =
|
||||
mSubscriptionManager.getActiveSubscriptionInfoList();
|
||||
if (DBG) Slog.d(TAG, "handleUpdateSimSubscriptionInfo: " + activeSubscriptionInfoList);
|
||||
if (activeSubscriptionInfoList == null) {
|
||||
setSimNeedsEmergencyAffordance(neededNow);
|
||||
return neededNow;
|
||||
return;
|
||||
}
|
||||
|
||||
boolean needsAffordance = false;
|
||||
for (SubscriptionInfo info : activeSubscriptionInfoList) {
|
||||
int mcc = info.getMcc();
|
||||
if (mccRequiresEmergencyAffordance(mcc)) {
|
||||
neededNow = true;
|
||||
if (isoRequiresEmergencyAffordance(info.getCountryIso())) {
|
||||
needsAffordance = true;
|
||||
break;
|
||||
} else if (mcc != 0 && mcc != Integer.MAX_VALUE){
|
||||
// a Sim with a different mcc code was found
|
||||
neededNow = false;
|
||||
}
|
||||
String simOperator = mTelephonyManager
|
||||
.createForSubscriptionId(info.getSubscriptionId()).getSimOperator();
|
||||
mcc = 0;
|
||||
if (simOperator != null && simOperator.length() >= 3) {
|
||||
mcc = Integer.parseInt(simOperator.substring(0, 3));
|
||||
}
|
||||
if (mcc != 0) {
|
||||
if (mccRequiresEmergencyAffordance(mcc)) {
|
||||
neededNow = true;
|
||||
break;
|
||||
} else {
|
||||
// a Sim with a different mcc code was found
|
||||
neededNow = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
setSimNeedsEmergencyAffordance(neededNow);
|
||||
return neededNow;
|
||||
|
||||
mAnySimNeedsEmergencyAffordance = needsAffordance;
|
||||
updateEmergencyAffordanceNeeded();
|
||||
}
|
||||
|
||||
private void setSimNeedsEmergencyAffordance(boolean simNeedsEmergencyAffordance) {
|
||||
if (simNeededAffordanceBefore() != simNeedsEmergencyAffordance) {
|
||||
private void handleNetworkCountryChanged(String countryIso, int slotId) {
|
||||
if (DBG) {
|
||||
Slog.d(TAG, "handleNetworkCountryChanged: countryIso=" + countryIso
|
||||
+ ", slotId=" + slotId);
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(countryIso) && mAirplaneModeEnabled) {
|
||||
Slog.w(TAG, "Ignore empty countryIso report when APM is on.");
|
||||
return;
|
||||
}
|
||||
|
||||
updateNetworkCountry();
|
||||
|
||||
updateEmergencyAffordanceNeeded();
|
||||
}
|
||||
|
||||
private void updateNetworkCountry() {
|
||||
boolean needsAffordance = false;
|
||||
|
||||
final int activeModems = mTelephonyManager.getActiveModemCount();
|
||||
for (int i = 0; i < activeModems; i++) {
|
||||
String countryIso = mTelephonyManager.getNetworkCountryIso(i);
|
||||
if (DBG) Slog.d(TAG, "UpdateNetworkCountry: slotId=" + i + " countryIso=" + countryIso);
|
||||
if (isoRequiresEmergencyAffordance(countryIso)) {
|
||||
needsAffordance = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mAnyNetworkNeedsEmergencyAffordance = needsAffordance;
|
||||
|
||||
updateEmergencyAffordanceNeeded();
|
||||
}
|
||||
|
||||
private boolean isoRequiresEmergencyAffordance(String iso) {
|
||||
return mEmergencyCallCountryIsos.contains(iso);
|
||||
}
|
||||
|
||||
private void updateEmergencyAffordanceNeeded() {
|
||||
if (DBG) {
|
||||
Slog.d(TAG, "updateEmergencyAffordanceNeeded: mEmergencyAffordanceNeeded="
|
||||
+ mEmergencyAffordanceNeeded + ", mVoiceCapable=" + mVoiceCapable
|
||||
+ ", mAnySimNeedsEmergencyAffordance=" + mAnySimNeedsEmergencyAffordance
|
||||
+ ", mAnyNetworkNeedsEmergencyAffordance="
|
||||
+ mAnyNetworkNeedsEmergencyAffordance);
|
||||
}
|
||||
boolean lastAffordanceNeeded = mEmergencyAffordanceNeeded;
|
||||
|
||||
mEmergencyAffordanceNeeded = mVoiceCapable
|
||||
&& (mAnySimNeedsEmergencyAffordance || mAnyNetworkNeedsEmergencyAffordance);
|
||||
|
||||
if (lastAffordanceNeeded != mEmergencyAffordanceNeeded) {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
EMERGENCY_SIM_INSERTED_SETTING,
|
||||
simNeedsEmergencyAffordance ? 1 : 0);
|
||||
}
|
||||
if (simNeedsEmergencyAffordance != mSimNeedsEmergencyAffordance) {
|
||||
mSimNeedsEmergencyAffordance = simNeedsEmergencyAffordance;
|
||||
updateEmergencyAffordanceNeeded();
|
||||
Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
|
||||
mEmergencyAffordanceNeeded ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean simNeededAffordanceBefore() {
|
||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||
EMERGENCY_SIM_INSERTED_SETTING, 0) != 0;
|
||||
private void dumpInternal(IndentingPrintWriter ipw) {
|
||||
ipw.println("EmergencyAffordanceService (dumpsys emergency_affordance) state:\n");
|
||||
ipw.println("mEmergencyAffordanceNeeded=" + mEmergencyAffordanceNeeded);
|
||||
ipw.println("mVoiceCapable=" + mVoiceCapable);
|
||||
ipw.println("mAnySimNeedsEmergencyAffordance=" + mAnySimNeedsEmergencyAffordance);
|
||||
ipw.println("mAnyNetworkNeedsEmergencyAffordance=" + mAnyNetworkNeedsEmergencyAffordance);
|
||||
ipw.println("mEmergencyCallCountryIsos=" + String.join(",", mEmergencyCallCountryIsos));
|
||||
}
|
||||
|
||||
private boolean handleUpdateCellInfo() {
|
||||
List<CellInfo> cellInfos = mTelephonyManager.getAllCellInfo();
|
||||
if (cellInfos == null) {
|
||||
return false;
|
||||
}
|
||||
boolean stopScanningAfterScan = false;
|
||||
for (CellInfo cellInfo : cellInfos) {
|
||||
int mcc = 0;
|
||||
if (cellInfo instanceof CellInfoGsm) {
|
||||
mcc = ((CellInfoGsm) cellInfo).getCellIdentity().getMcc();
|
||||
} else if (cellInfo instanceof CellInfoLte) {
|
||||
mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMcc();
|
||||
} else if (cellInfo instanceof CellInfoWcdma) {
|
||||
mcc = ((CellInfoWcdma) cellInfo).getCellIdentity().getMcc();
|
||||
private final class BinderService extends Binder {
|
||||
@Override
|
||||
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) {
|
||||
return;
|
||||
}
|
||||
if (mccRequiresEmergencyAffordance(mcc)) {
|
||||
setNetworkNeedsEmergencyAffordance(true);
|
||||
return true;
|
||||
} else if (mcc != 0 && mcc != Integer.MAX_VALUE) {
|
||||
// we found an mcc that isn't in the list, abort
|
||||
stopScanningAfterScan = true;
|
||||
}
|
||||
}
|
||||
if (stopScanningAfterScan) {
|
||||
stopScanning();
|
||||
} else {
|
||||
onCellScanFinishedUnsuccessful();
|
||||
}
|
||||
setNetworkNeedsEmergencyAffordance(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setNetworkNeedsEmergencyAffordance(boolean needsAffordance) {
|
||||
synchronized (mLock) {
|
||||
mNetworkNeedsEmergencyAffordance = needsAffordance;
|
||||
updateEmergencyAffordanceNeeded();
|
||||
dumpInternal(new IndentingPrintWriter(pw, " "));
|
||||
}
|
||||
}
|
||||
|
||||
private void onCellScanFinishedUnsuccessful() {
|
||||
synchronized (mLock) {
|
||||
mScansCompleted++;
|
||||
if (mScansCompleted >= NUM_SCANS_UNTIL_ABORT) {
|
||||
stopScanning();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean mccRequiresEmergencyAffordance(int mcc) {
|
||||
return mEmergencyCallMccNumbers.contains(mcc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.emergency;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.SubscriptionInfo;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.test.mock.MockContentResolver;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import com.android.internal.util.test.BroadcastInterceptingContext;
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.server.SystemService;
|
||||
|
||||
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.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Unit test for EmergencyAffordanceService (EAS for short) which determines when
|
||||
* should we enable Emergency Affordance feature (EA for short).
|
||||
*
|
||||
* Please refer to https://source.android.com/devices/tech/connect/emergency-affordance
|
||||
* to see the details of the feature.
|
||||
*/
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper
|
||||
public class EmergencyAffordanceServiceTest {
|
||||
|
||||
// Default country ISO that should enable EA. Value comes from resource
|
||||
// com.android.internal.R.array.config_emergency_iso_country_codes
|
||||
private static final String EMERGENCY_ISO_CODE = "in";
|
||||
// Randomly picked country ISO that should not enable EA.
|
||||
private static final String NON_EMERGENCY_ISO_CODE = "us";
|
||||
|
||||
// Valid values for Settings.Global.EMERGENCY_AFFORDANCE_NEEDED
|
||||
private static final int OFF = 0; // which means feature disabled
|
||||
private static final int ON = 1; // which means feature enabled
|
||||
|
||||
private static final int ACTIVE_MODEM_COUNT = 2;
|
||||
|
||||
@Mock private Resources mResources;
|
||||
@Mock private SubscriptionManager mSubscriptionManager;
|
||||
@Mock private TelephonyManager mTelephonyManager;
|
||||
|
||||
private TestContext mServiceContext;
|
||||
private MockContentResolver mContentResolver;
|
||||
private OnSubscriptionsChangedListener mSubscriptionChangedListener;
|
||||
private EmergencyAffordanceService mService;
|
||||
|
||||
// Testable Context that mocks resources, content resolver and system services
|
||||
private class TestContext extends BroadcastInterceptingContext {
|
||||
TestContext(Context base) {
|
||||
super(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentResolver getContentResolver() {
|
||||
return mContentResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resources getResources() {
|
||||
return mResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSystemService(String name) {
|
||||
switch (name) {
|
||||
case Context.TELEPHONY_SUBSCRIPTION_SERVICE:
|
||||
return mSubscriptionManager;
|
||||
case Context.TELEPHONY_SERVICE:
|
||||
return mTelephonyManager;
|
||||
default:
|
||||
return super.getSystemService(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
doReturn(new String[] { EMERGENCY_ISO_CODE }).when(mResources)
|
||||
.getStringArray(com.android.internal.R.array.config_emergency_iso_country_codes);
|
||||
|
||||
final Context context = InstrumentationRegistry.getContext();
|
||||
mServiceContext = new TestContext(context);
|
||||
mContentResolver = new MockContentResolver(mServiceContext);
|
||||
mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
|
||||
|
||||
// Initialize feature off, to have constant starting
|
||||
Settings.Global.putInt(mContentResolver, Settings.Global.EMERGENCY_AFFORDANCE_NEEDED, 0);
|
||||
mService = new EmergencyAffordanceService(mServiceContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the device is not voice capable, the feature should be disabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOff_whenVoiceCapableIsFalse() throws Exception {
|
||||
// Given: the device is not voice capable
|
||||
// When: setup device and boot service
|
||||
setUpDevice(false /* withVoiceCapable */, true /* withEmergencyIsoInSim */,
|
||||
true /* withEmergencyIsoInCell */);
|
||||
|
||||
// Then: EA setting will should be 0
|
||||
verifyEmergencyAffordanceNeededSettings(OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the voice capable device is booted up without EA-enabled cell network, with
|
||||
* no EA-enabled SIM installed, feature should be disabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOff_whenWithoutEAEanbledNetworkNorSim() throws Exception {
|
||||
// Given: the device is voice capble, no EA-enable SIM, no EA-enabled Cell
|
||||
setUpDevice(true /* withVoiceCapable */, false /* withEmergencyIsoInSim */,
|
||||
false /* withEmergencyIsoInCell */);
|
||||
|
||||
// Then: EA setting will should be 0
|
||||
verifyEmergencyAffordanceNeededSettings(OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the voice capable device is booted up with EA-enabled SIM installed, the
|
||||
* feature should be enabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOn_whenBootUpWithEAEanbledSim() throws Exception {
|
||||
// Given: the device is voice capble, with EA-enable SIM, no EA-enabled Cell
|
||||
setUpDevice(true /* withVoiceCapable */, true /* withEmergencyIsoInSim */,
|
||||
false /* withEmergencyIsoInCell */);
|
||||
|
||||
// Then: EA setting will immediately update to 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the voice capable device is booted up with EA-enabled Cell network, the
|
||||
* feature should be enabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOn_whenBootUpWithEAEanbledCell() throws Exception {
|
||||
// Given: the device is voice capble, with EA-enable SIM, with EA-enabled Cell
|
||||
setUpDevice(true /* withVoiceCapable */, false /* withEmergencyIsoInSim */,
|
||||
true /* withEmergencyIsoInCell */);
|
||||
|
||||
// Then: EA setting will immediately update to 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify when device boot up with no EA-enabled SIM, but later install one,
|
||||
* feature should be enabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOn_whenSubscriptionInfoChangedWithEmergencyIso()
|
||||
throws Exception {
|
||||
// Given: the device is voice capable, boot up with no EA-enabled SIM, no EA-enabled Cell
|
||||
setUpDevice(true /* withVoiceCapable */, false/* withEmergencyIsoInSim */,
|
||||
false /* withEmergencyIsoInCell */);
|
||||
|
||||
// When: Insert EA-enabled SIM and get notified
|
||||
setUpSim(true /* withEmergencyIsoInSim */);
|
||||
mSubscriptionChangedListener.onSubscriptionsChanged();
|
||||
|
||||
// Then: EA Setting will update to 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify when feature was on, device re-insert with no EA-enabled SIMs,
|
||||
* feature should be disabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOff_whenSubscriptionInfoChangedWithoutEmergencyIso()
|
||||
throws Exception {
|
||||
// Given: the device is voice capable, no EA-enabled Cell, with EA-enabled SIM
|
||||
setUpDevice(true /* withVoiceCapable */, true /* withEmergencyIsoInSim */,
|
||||
false /* withEmergencyIsoInCell */);
|
||||
|
||||
// When: All SIMs are replaced with EA-disabled ones.
|
||||
setUpSim(false /* withEmergencyIsoInSim */);
|
||||
mSubscriptionChangedListener.onSubscriptionsChanged();
|
||||
|
||||
// Then: EA Setting will update to 0
|
||||
verifyEmergencyAffordanceNeededSettings(OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify when device boot up with no EA-enabled Cell, but later move into one,
|
||||
* feature should be enabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOn_whenCountryIsoChangedWithEmergencyIso()
|
||||
throws Exception {
|
||||
// Given: the device is voice capable, boot up with no EA-enabled SIM, no EA-enabled Cell
|
||||
setUpDevice(true /* withVoiceCapable */, false/* withEmergencyIsoInSim */,
|
||||
false /* withEmergencyIsoInCell */);
|
||||
|
||||
// When: device locale change to EA-enabled Cell and get notified
|
||||
resetCell(true /* withEmergencyIsoInSim */);
|
||||
sendBroadcastNetworkCountryChanged(EMERGENCY_COUNTRY_ISO);
|
||||
|
||||
// Then: EA Setting will update to 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify when device boot up with EA-enabled Cell, but later move out of it,
|
||||
* feature should be enabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOff_whenCountryIsoChangedWithoutEmergencyIso()
|
||||
throws Exception {
|
||||
// Given: the device is voice capable, boot up with no EA-enabled SIM, with EA-enabled Cell
|
||||
setUpDevice(true /* withVoiceCapable */, false/* withEmergencyIsoInSim */,
|
||||
true /* withEmergencyIsoInCell */);
|
||||
|
||||
// When: device locale change to no EA-enabled Cell and get notified
|
||||
resetCell(false /* withEmergencyIsoInSim */);
|
||||
sendBroadcastNetworkCountryChanged(NON_EMERGENCY_COUNTRY_ISO);
|
||||
|
||||
// Then: EA Setting will update to 0
|
||||
verifyEmergencyAffordanceNeededSettings(OFF);
|
||||
}
|
||||
/**
|
||||
* Verify if device is not in EA-enabled Mobile Network without EA-enable SIM(s) installed,
|
||||
* when receive SubscriptionInfo change, the feature should not be enabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOff_whenNoEmergencyIsoInCellNorSim() throws Exception {
|
||||
// Given: the device is voice capable, no EA-enabled Cell, no EA-enabled SIM
|
||||
setUpDevice(true /* withVoiceCapable */, false /* withEmergencyIsoInSim */,
|
||||
false /* withEmergencyIsoInCell */);
|
||||
|
||||
// When: Subscription changed event received
|
||||
mSubscriptionChangedListener.onSubscriptionsChanged();
|
||||
|
||||
// Then: EA Settings should be 0
|
||||
verifyEmergencyAffordanceNeededSettings(OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify while feature was on, when device receive empty country iso change, while APM is
|
||||
* enabled, feature status should keep on.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldOn_whenReceiveEmptyISOWithAPMEnabled() throws Exception {
|
||||
// Given: the device is voice capable, no EA-enabled SIM, with EA-enabled Cell
|
||||
setUpDevice(true /* withVoiceCapable */, false /* withEmergencyIsoInSim */,
|
||||
true /* withEmergencyIsoInCell */);
|
||||
|
||||
// Then: EA Settings will update to 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
|
||||
// When: Airplane mode is enabled, and we receive EMPTY ISO in locale change
|
||||
setAirplaneMode(true);
|
||||
sendBroadcastNetworkCountryChanged(EMPTY_COUNTRY_ISO);
|
||||
|
||||
// Then: EA Settings will keep to 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify while feature was on, when device receive empty country iso change, while APM is
|
||||
* disabled, feature should be disabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldOff_whenReceiveEmptyISOWithAPMDisabled() throws Exception {
|
||||
// Given: the device is voice capable, no EA-enabled SIM, with EA-enabled Cell
|
||||
setUpDevice(true /* withVoiceCapable */, false /* withEmergencyIsoInSim */,
|
||||
true /* withEmergencyIsoInCell */);
|
||||
|
||||
// Then: EA Settings will update to 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
|
||||
// When: Airplane mode is disabled, and we receive valid empty ISO in locale change
|
||||
setUpCell(false /* withEmergencyIsoInCell */);
|
||||
setAirplaneMode(false);
|
||||
sendBroadcastNetworkCountryChanged(EMPTY_COUNTRY_ISO);
|
||||
|
||||
// Then: EA Settings will keep to 0
|
||||
verifyEmergencyAffordanceNeededSettings(OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify when airplane mode is turn on and off in cell network with EA-enabled ISO,
|
||||
* feature should keep enabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOn_whenAirplaneModeOnOffWithEmergencyIsoInCell()
|
||||
throws Exception {
|
||||
// Given: the device is voice capable, no EA-enabled SIM, with EA-enabled Cell
|
||||
setUpDevice(true /* withVoiceCapable */, false /* withEmergencyIsoInSim */,
|
||||
true /* withEmergencyIsoInCell */);
|
||||
|
||||
// When: Device receive locale change with EA-enabled iso
|
||||
sendBroadcastNetworkCountryChanged(EMERGENCY_COUNTRY_ISO);
|
||||
|
||||
// When: Airplane mode is disabled
|
||||
setAirplaneMode(false);
|
||||
|
||||
// Then: EA Settings will keep with 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
|
||||
// When: Airplane mode is enabled
|
||||
setAirplaneMode(true);
|
||||
|
||||
// Then: EA Settings is still 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify when airplane mode is turn on and off with EA-enabled ISO in SIM,
|
||||
* feature should keep enabled.
|
||||
*/
|
||||
@Test
|
||||
public void testSettings_shouldBeOn_whenAirplaneModeOnOffWithEmergencyIsoInSim()
|
||||
throws Exception {
|
||||
// Given: the device is voice capable, no EA-enabled Cell Network, with EA-enabled SIM
|
||||
setUpDevice(true /* withVoiceCapable */, true /* withEmergencyIsoInSim */,
|
||||
false /* withEmergencyIsoInCell */);
|
||||
|
||||
// When: Airplane mode is disabled
|
||||
setAirplaneMode(false);
|
||||
|
||||
// Then: EA Settings will keep with 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
|
||||
// When: Airplane mode is enabled
|
||||
setAirplaneMode(true);
|
||||
|
||||
// Then: EA Settings is still 1
|
||||
verifyEmergencyAffordanceNeededSettings(ON);
|
||||
}
|
||||
|
||||
// EAS reads voice capable during boot up and cache it. To test non voice capable device,
|
||||
// we can not put this in setUp
|
||||
private void setUpDevice(boolean withVoiceCapable, boolean withEmergencyIsoInSim,
|
||||
boolean withEmergencyIsoInCell) throws Exception {
|
||||
setUpVoiceCapable(withVoiceCapable);
|
||||
|
||||
setUpSim(withEmergencyIsoInSim);
|
||||
|
||||
setUpCell(withEmergencyIsoInCell);
|
||||
|
||||
// bypass onStart which is used to publish binder service and need sepolicy policy update
|
||||
// mService.onStart();
|
||||
|
||||
mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
|
||||
|
||||
if (!withVoiceCapable) {
|
||||
return;
|
||||
}
|
||||
|
||||
captureSubscriptionChangeListener();
|
||||
}
|
||||
|
||||
private void setUpVoiceCapable(boolean voiceCapable) {
|
||||
doReturn(voiceCapable).when(mTelephonyManager).isVoiceCapable();
|
||||
}
|
||||
|
||||
private static final Supplier<String> EMPTY_COUNTRY_ISO = () -> "";
|
||||
private static final Supplier<String> EMERGENCY_COUNTRY_ISO = () -> EMERGENCY_ISO_CODE;
|
||||
private static final Supplier<String> NON_EMERGENCY_COUNTRY_ISO = () -> NON_EMERGENCY_ISO_CODE;
|
||||
private void sendBroadcastNetworkCountryChanged(Supplier<String> countryIso) {
|
||||
Intent intent = new Intent(TelephonyManager.ACTION_NETWORK_COUNTRY_CHANGED);
|
||||
intent.putExtra(TelephonyManager.EXTRA_NETWORK_COUNTRY, countryIso.get());
|
||||
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, 0);
|
||||
mServiceContext.sendBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
|
||||
private void setUpSim(boolean withEmergencyIsoInSim) {
|
||||
List<SubscriptionInfo> subInfos = getSubscriptionInfoList(withEmergencyIsoInSim);
|
||||
doReturn(subInfos).when(mSubscriptionManager).getActiveSubscriptionInfoList();
|
||||
}
|
||||
|
||||
private void setUpCell(boolean withEmergencyIsoInCell) {
|
||||
doReturn(ACTIVE_MODEM_COUNT).when(mTelephonyManager).getActiveModemCount();
|
||||
doReturn(NON_EMERGENCY_ISO_CODE).when(mTelephonyManager).getNetworkCountryIso(0);
|
||||
doReturn(withEmergencyIsoInCell ? EMERGENCY_ISO_CODE : NON_EMERGENCY_ISO_CODE)
|
||||
.when(mTelephonyManager).getNetworkCountryIso(1);
|
||||
}
|
||||
|
||||
private void resetCell(boolean withEmergencyIsoInCell) {
|
||||
doReturn(withEmergencyIsoInCell ? EMERGENCY_ISO_CODE : NON_EMERGENCY_ISO_CODE)
|
||||
.when(mTelephonyManager).getNetworkCountryIso(1);
|
||||
}
|
||||
|
||||
private void captureSubscriptionChangeListener() {
|
||||
final ArgumentCaptor<OnSubscriptionsChangedListener> subChangedListenerCaptor =
|
||||
ArgumentCaptor.forClass(OnSubscriptionsChangedListener.class);
|
||||
verify(mSubscriptionManager).addOnSubscriptionsChangedListener(
|
||||
subChangedListenerCaptor.capture());
|
||||
mSubscriptionChangedListener = subChangedListenerCaptor.getValue();
|
||||
}
|
||||
|
||||
private void setAirplaneMode(boolean enabled) {
|
||||
// Change the system settings
|
||||
Settings.Global.putInt(mContentResolver, Settings.Global.AIRPLANE_MODE_ON,
|
||||
enabled ? 1 : 0);
|
||||
|
||||
// Post the intent
|
||||
final Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
intent.putExtra("state", enabled);
|
||||
mServiceContext.sendBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
|
||||
private List<SubscriptionInfo> getSubscriptionInfoList(boolean withEmergencyIso) {
|
||||
List<SubscriptionInfo> subInfos = new ArrayList<>(2);
|
||||
|
||||
// Test with Multiple SIMs. SIM1 is a non-EA SIM
|
||||
// Only country iso is valuable, all other info are filled with dummy values
|
||||
SubscriptionInfo subInfo = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, "T-mobile",
|
||||
"T-mobile", 0, 255, "12345", 0, null,
|
||||
"310", "226", NON_EMERGENCY_ISO_CODE, false, null, null);
|
||||
subInfos.add(subInfo);
|
||||
|
||||
// SIM2 can configured to be non-EA or EA SIM according parameter withEmergencyIso
|
||||
SubscriptionInfo subInfo2 = new SubscriptionInfo(1, "890126042XXXXXXXXXXX", 0, "Airtel",
|
||||
"Aritel", 0, 255, "12345", 0, null, "310", "226",
|
||||
withEmergencyIso ? EMERGENCY_ISO_CODE : NON_EMERGENCY_ISO_CODE,
|
||||
false, null, null);
|
||||
subInfos.add(subInfo2);
|
||||
|
||||
return subInfos;
|
||||
}
|
||||
|
||||
// EAS has handler thread to perform heavy work, while FakeSettingProvider does not support
|
||||
// ContentObserver. To make sure consistent result, we use a simple sleep & retry to wait for
|
||||
// real work finished before verify result.
|
||||
private static final int TIME_DELAY_BEFORE_VERIFY_IN_MS = 50;
|
||||
private static final int RETRIES_BEFORE_VERIFY = 20;
|
||||
private void verifyEmergencyAffordanceNeededSettings(int expected) throws Exception {
|
||||
try {
|
||||
int ct = 0;
|
||||
int actual = -1;
|
||||
while (ct++ < RETRIES_BEFORE_VERIFY
|
||||
&& (actual = Settings.Global.getInt(mContentResolver,
|
||||
Settings.Global.EMERGENCY_AFFORDANCE_NEEDED)) != expected) {
|
||||
Thread.sleep(TIME_DELAY_BEFORE_VERIFY_IN_MS);
|
||||
}
|
||||
assertEquals(expected, actual);
|
||||
} catch (Settings.SettingNotFoundException e) {
|
||||
fail("SettingNotFoundException thrown for Settings.Global.EMERGENCY_AFFORDANCE_NEEDED");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user