Files
app_Settings/src/com/android/settings/sim/receivers/SimSlotChangeReceiver.java
Jiashen Wang b54d25ee13 Slot Change Receiver Migration
Implemented slot change cases when pSIM is inserted and removed.
Bug: 153811431
Bug: 170508680
Test: Manually tested

Change-Id: Ib0a96da1d7d702f7c64e75b929c73b8548f8e459
2021-01-28 14:15:53 -08:00

148 lines
5.4 KiB
Java

/*
* 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.settings.sim.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.telephony.UiccCardInfo;
import android.telephony.UiccSlotInfo;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Nullable;
import com.android.settings.R;
import com.android.settingslib.utils.ThreadUtils;
import java.util.List;
/** The receiver when the slot status changes. */
public class SimSlotChangeReceiver extends BroadcastReceiver {
private static final String TAG = "SlotChangeReceiver";
private final SimSlotChangeHandler mSlotChangeHandler = SimSlotChangeHandler.get();
private final Object mLock = new Object();
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (!TelephonyManager.ACTION_SIM_SLOT_STATUS_CHANGED.equals(action)) {
Log.e(TAG, "Ignore slot changes due to unexpected action: " + action);
return;
}
final PendingResult pendingResult = goAsync();
ThreadUtils.postOnBackgroundThread(
() -> {
synchronized (mLock) {
if (!shouldHandleSlotChange(context)) {
return;
}
mSlotChangeHandler.onSlotsStatusChange(context.getApplicationContext());
}
ThreadUtils.postOnMainThread(pendingResult::finish);
});
}
// Checks whether the slot event should be handled.
private boolean shouldHandleSlotChange(Context context) {
if (!context.getResources().getBoolean(R.bool.config_handle_sim_slot_change)) {
Log.i(TAG, "The flag is off. Ignore slot changes.");
return false;
}
final EuiccManager euiccManager = context.getSystemService(EuiccManager.class);
if (euiccManager == null || !euiccManager.isEnabled()) {
Log.i(TAG, "Ignore slot changes because EuiccManager is disabled.");
return false;
}
if (euiccManager.getOtaStatus() == EuiccManager.EUICC_OTA_IN_PROGRESS) {
Log.i(TAG, "Ignore slot changes because eSIM OTA is in progress.");
return false;
}
if (!isSimSlotStateValid(context)) {
Log.i(TAG, "Ignore slot changes because SIM states are not valid.");
return false;
}
return true;
}
// Checks whether the SIM slot state is valid for slot change event.
private boolean isSimSlotStateValid(Context context) {
final TelephonyManager telMgr = context.getSystemService(TelephonyManager.class);
UiccSlotInfo[] slotInfos = telMgr.getUiccSlotsInfo();
if (slotInfos == null) {
Log.e(TAG, "slotInfos is null. Unable to get slot infos.");
return false;
}
boolean isAllCardStringsEmpty = true;
for (int i = 0; i < slotInfos.length; i++) {
UiccSlotInfo slotInfo = slotInfos[i];
if (slotInfo == null) {
return false;
}
// After pSIM is inserted, there might be a short period that the status of both slots
// are not accurate. We drop the event if any of sim presence state is ERROR or
// RESTRICTED.
if (slotInfo.getCardStateInfo() == UiccSlotInfo.CARD_STATE_INFO_ERROR
|| slotInfo.getCardStateInfo() == UiccSlotInfo.CARD_STATE_INFO_RESTRICTED) {
Log.i(TAG, "The SIM state is in an error. Drop the event. SIM info: " + slotInfo);
return false;
}
UiccCardInfo cardInfo = findUiccCardInfoBySlot(telMgr, i);
if (cardInfo == null) {
continue;
}
if (!TextUtils.isEmpty(slotInfo.getCardId())
|| !TextUtils.isEmpty(cardInfo.getIccId())) {
isAllCardStringsEmpty = false;
}
}
// We also drop the event if both the card strings are empty, which usually means it's
// between SIM slots switch the slot status is not stable at this moment.
if (isAllCardStringsEmpty) {
Log.i(TAG, "All UICC card strings are empty. Drop this event.");
return false;
}
return true;
}
@Nullable
private UiccCardInfo findUiccCardInfoBySlot(TelephonyManager telMgr, int physicalSlotIndex) {
List<UiccCardInfo> cardInfos = telMgr.getUiccCardsInfo();
if (cardInfos == null) {
return null;
}
return cardInfos.stream()
.filter(info -> info.getSlotIndex() == physicalSlotIndex)
.findFirst()
.orElse(null);
}
}