Merge "Fix EmergencyAffordanceService"
This commit is contained in:
@@ -3578,10 +3578,9 @@
|
|||||||
|
|
||||||
<!-- Do not translate. Mcc codes whose existence trigger the presence of emergency
|
<!-- Do not translate. Mcc codes whose existence trigger the presence of emergency
|
||||||
affordances-->
|
affordances-->
|
||||||
<integer-array name="config_emergency_mcc_codes" translatable="false">
|
<string-array name="config_emergency_iso_country_codes" translatable="false">
|
||||||
<item>404</item>
|
<item>in</item>
|
||||||
<item>405</item>
|
</string-array>
|
||||||
</integer-array>
|
|
||||||
|
|
||||||
<!-- Package name for the device provisioning package. -->
|
<!-- Package name for the device provisioning package. -->
|
||||||
<string name="config_deviceProvisioningPackage"></string>
|
<string name="config_deviceProvisioningPackage"></string>
|
||||||
|
|||||||
@@ -3168,7 +3168,7 @@
|
|||||||
<java-symbol type="string" name="global_action_emergency" />
|
<java-symbol type="string" name="global_action_emergency" />
|
||||||
<java-symbol type="string" name="config_emergency_call_number" />
|
<java-symbol type="string" name="config_emergency_call_number" />
|
||||||
<java-symbol type="string" name="config_emergency_dialer_package" />
|
<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_dozeDoubleTapSensorType" />
|
||||||
<java-symbol type="string" name="config_dozeTapSensorType" />
|
<java-symbol type="string" name="config_dozeTapSensorType" />
|
||||||
|
|||||||
@@ -20,90 +20,80 @@ import android.content.BroadcastReceiver;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
import android.provider.Settings;
|
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.SubscriptionInfo;
|
||||||
import android.telephony.SubscriptionManager;
|
import android.telephony.SubscriptionManager;
|
||||||
import android.telephony.TelephonyManager;
|
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 com.android.server.SystemService;
|
||||||
|
|
||||||
|
import java.io.FileDescriptor;
|
||||||
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service that listens to connectivity and SIM card changes and determines if the emergency mode
|
* A service that listens to connectivity and SIM card changes and determines if the emergency
|
||||||
* should be enabled
|
* affordance should be enabled.
|
||||||
*/
|
*/
|
||||||
public class EmergencyAffordanceService extends SystemService {
|
public class EmergencyAffordanceService extends SystemService {
|
||||||
|
|
||||||
private static final String TAG = "EmergencyAffordanceService";
|
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 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
|
* @param arg1 slot Index
|
||||||
* requires the emergency affordance. The value is a boolean (1 or 0).
|
* @param arg2 0
|
||||||
* @hide
|
* @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 Context mContext;
|
||||||
private final ArrayList<Integer> mEmergencyCallMccNumbers;
|
// Country ISOs that require affordance
|
||||||
|
private final ArrayList<String> mEmergencyCallCountryIsos;
|
||||||
private final Object mLock = new Object();
|
|
||||||
|
|
||||||
private TelephonyManager mTelephonyManager;
|
|
||||||
private SubscriptionManager mSubscriptionManager;
|
private SubscriptionManager mSubscriptionManager;
|
||||||
private boolean mEmergencyAffordanceNeeded;
|
private TelephonyManager mTelephonyManager;
|
||||||
private MyHandler mHandler;
|
private MyHandler mHandler;
|
||||||
private int mScansCompleted;
|
private boolean mAnySimNeedsEmergencyAffordance;
|
||||||
private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
|
private boolean mAnyNetworkNeedsEmergencyAffordance;
|
||||||
@Override
|
private boolean mEmergencyAffordanceNeeded;
|
||||||
public void onCellInfoChanged(List<CellInfo> cellInfo) {
|
private boolean mAirplaneModeEnabled;
|
||||||
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 mVoiceCapable;
|
private boolean mVoiceCapable;
|
||||||
|
|
||||||
private void requestCellScan() {
|
private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||||
mHandler.obtainMessage(CELL_INFO_STATE_CHANGED).sendToTarget();
|
@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
|
private SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionChangedListener
|
||||||
= new SubscriptionManager.OnSubscriptionsChangedListener() {
|
= new SubscriptionManager.OnSubscriptionsChangedListener() {
|
||||||
@@ -116,207 +106,200 @@ public class EmergencyAffordanceService extends SystemService {
|
|||||||
public EmergencyAffordanceService(Context context) {
|
public EmergencyAffordanceService(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
mContext = context;
|
mContext = context;
|
||||||
int[] numbers = context.getResources().getIntArray(
|
String[] isos = context.getResources().getStringArray(
|
||||||
com.android.internal.R.array.config_emergency_mcc_codes);
|
com.android.internal.R.array.config_emergency_iso_country_codes);
|
||||||
mEmergencyCallMccNumbers = new ArrayList<>(numbers.length);
|
mEmergencyCallCountryIsos = new ArrayList<>(isos.length);
|
||||||
for (int i = 0; i < numbers.length; i++) {
|
for (String iso : isos) {
|
||||||
mEmergencyCallMccNumbers.add(numbers[i]);
|
mEmergencyCallCountryIsos.add(iso);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void updateEmergencyAffordanceNeeded() {
|
if (Build.IS_DEBUGGABLE) {
|
||||||
synchronized (mLock) {
|
String overrideIso = Settings.Global.getString(
|
||||||
mEmergencyAffordanceNeeded = mVoiceCapable && (mSimNeedsEmergencyAffordance ||
|
mContext.getContentResolver(), EMERGENCY_AFFORDANCE_OVERRIDE_ISO);
|
||||||
mNetworkNeedsEmergencyAffordance);
|
if (!TextUtils.isEmpty(overrideIso)) {
|
||||||
Settings.Global.putInt(mContext.getContentResolver(),
|
if (DBG) Slog.d(TAG, "Override ISO to " + overrideIso);
|
||||||
Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
|
mEmergencyCallCountryIsos.clear();
|
||||||
mEmergencyAffordanceNeeded ? 1 : 0);
|
mEmergencyCallCountryIsos.add(overrideIso);
|
||||||
if (mEmergencyAffordanceNeeded) {
|
|
||||||
stopScanning();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopScanning() {
|
|
||||||
synchronized (mLock) {
|
|
||||||
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
|
|
||||||
mScansCompleted = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isEmergencyAffordanceNeeded() {
|
|
||||||
synchronized (mLock) {
|
|
||||||
return mEmergencyAffordanceNeeded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
|
if (DBG) Slog.i(TAG, "onStart");
|
||||||
|
publishBinderService(SERVICE_NAME, new BinderService());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBootPhase(int phase) {
|
public void onBootPhase(int phase) {
|
||||||
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
|
if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
|
||||||
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
|
if (DBG) Slog.i(TAG, "onBootPhase");
|
||||||
mVoiceCapable = mTelephonyManager.isVoiceCapable();
|
handleThirdPartyBootPhase();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startScanning() {
|
|
||||||
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CELL_INFO
|
|
||||||
| PhoneStateListener.LISTEN_CELL_LOCATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Handler to do the heavier work on */
|
/** Handler to do the heavier work on */
|
||||||
private class MyHandler extends Handler {
|
private class MyHandler extends Handler {
|
||||||
|
|
||||||
public MyHandler(Looper l) {
|
public MyHandler(Looper l) {
|
||||||
super(l);
|
super(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(Message msg) {
|
public void handleMessage(Message msg) {
|
||||||
|
if (DBG) Slog.d(TAG, "handleMessage: " + msg.what);
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case INITIALIZE_STATE:
|
case INITIALIZE_STATE:
|
||||||
handleInitializeState();
|
handleInitializeState();
|
||||||
break;
|
break;
|
||||||
case CELL_INFO_STATE_CHANGED:
|
case NETWORK_COUNTRY_CHANGED:
|
||||||
handleUpdateCellInfo();
|
final String countryIso = (String) msg.obj;
|
||||||
|
final int slotId = msg.arg1;
|
||||||
|
handleNetworkCountryChanged(countryIso, slotId);
|
||||||
break;
|
break;
|
||||||
case SUBSCRIPTION_CHANGED:
|
case SUBSCRIPTION_CHANGED:
|
||||||
handleUpdateSimSubscriptionInfo();
|
handleUpdateSimSubscriptionInfo();
|
||||||
break;
|
break;
|
||||||
|
case UPDATE_AIRPLANE_MODE_STATUS:
|
||||||
|
handleUpdateAirplaneModeStatus();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Slog.e(TAG, "Unexpected message received: " + msg.what);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleInitializeState() {
|
private void handleInitializeState() {
|
||||||
if (handleUpdateSimSubscriptionInfo()) {
|
if (DBG) Slog.d(TAG, "handleInitializeState");
|
||||||
return;
|
handleUpdateAirplaneModeStatus();
|
||||||
}
|
handleUpdateSimSubscriptionInfo();
|
||||||
if (handleUpdateCellInfo()) {
|
updateNetworkCountry();
|
||||||
return;
|
|
||||||
}
|
|
||||||
updateEmergencyAffordanceNeeded();
|
updateEmergencyAffordanceNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean handleUpdateSimSubscriptionInfo() {
|
private void handleThirdPartyBootPhase() {
|
||||||
boolean neededBefore = simNeededAffordanceBefore();
|
if (DBG) Slog.d(TAG, "handleThirdPartyBootPhase");
|
||||||
boolean neededNow = neededBefore;
|
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 =
|
List<SubscriptionInfo> activeSubscriptionInfoList =
|
||||||
mSubscriptionManager.getActiveSubscriptionInfoList();
|
mSubscriptionManager.getActiveSubscriptionInfoList();
|
||||||
|
if (DBG) Slog.d(TAG, "handleUpdateSimSubscriptionInfo: " + activeSubscriptionInfoList);
|
||||||
if (activeSubscriptionInfoList == null) {
|
if (activeSubscriptionInfoList == null) {
|
||||||
setSimNeedsEmergencyAffordance(neededNow);
|
return;
|
||||||
return neededNow;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean needsAffordance = false;
|
||||||
for (SubscriptionInfo info : activeSubscriptionInfoList) {
|
for (SubscriptionInfo info : activeSubscriptionInfoList) {
|
||||||
int mcc = info.getMcc();
|
if (isoRequiresEmergencyAffordance(info.getCountryIso())) {
|
||||||
if (mccRequiresEmergencyAffordance(mcc)) {
|
needsAffordance = true;
|
||||||
neededNow = true;
|
|
||||||
break;
|
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) {
|
private void handleNetworkCountryChanged(String countryIso, int slotId) {
|
||||||
if (simNeededAffordanceBefore() != simNeedsEmergencyAffordance) {
|
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(),
|
Settings.Global.putInt(mContext.getContentResolver(),
|
||||||
EMERGENCY_SIM_INSERTED_SETTING,
|
Settings.Global.EMERGENCY_AFFORDANCE_NEEDED,
|
||||||
simNeedsEmergencyAffordance ? 1 : 0);
|
mEmergencyAffordanceNeeded ? 1 : 0);
|
||||||
}
|
|
||||||
if (simNeedsEmergencyAffordance != mSimNeedsEmergencyAffordance) {
|
|
||||||
mSimNeedsEmergencyAffordance = simNeedsEmergencyAffordance;
|
|
||||||
updateEmergencyAffordanceNeeded();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean simNeededAffordanceBefore() {
|
private void dumpInternal(IndentingPrintWriter ipw) {
|
||||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
ipw.println("EmergencyAffordanceService (dumpsys emergency_affordance) state:\n");
|
||||||
EMERGENCY_SIM_INSERTED_SETTING, 0) != 0;
|
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() {
|
private final class BinderService extends Binder {
|
||||||
List<CellInfo> cellInfos = mTelephonyManager.getAllCellInfo();
|
@Override
|
||||||
if (cellInfos == null) {
|
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
return false;
|
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) {
|
||||||
}
|
return;
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
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) {
|
dumpInternal(new IndentingPrintWriter(pw, " "));
|
||||||
synchronized (mLock) {
|
|
||||||
mNetworkNeedsEmergencyAffordance = needsAffordance;
|
|
||||||
updateEmergencyAffordanceNeeded();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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