Merge cherrypicks of ['googleplex-android-review.googlesource.com/29488085', 'googleplex-android-review.googlesource.com/29479905', 'googleplex-android-review.googlesource.com/29599066', 'googleplex-android-review.googlesource.com/29599393', 'googleplex-android-review.googlesource.com/29599397'] into 24Q4-release.
Change-Id: If35291ba2b4bf75be3db51f5535f185425464a6e
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 695887e..8ae6cf4 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -62,6 +62,7 @@
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
+import android.app.StatusBarManager;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -126,6 +127,7 @@
import android.telephony.satellite.SatelliteSubscriberInfo;
import android.telephony.satellite.SatelliteSubscriberProvisionStatus;
import android.telephony.satellite.SatelliteSubscriptionInfo;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -566,6 +568,11 @@
private String mConfigSatelliteGatewayServicePackage = "";
private String mConfigSatelliteCarrierRoamingEsosProvisionedClass = "";
+ private boolean mIsNotificationShowing = false;
+ private static final String OPEN_MESSAGE_BUTTON = "open_message_button";
+ private static final String HOW_IT_WORKS_BUTTON = "how_it_works_button";
+ private static final String ACTION_NOTIFICATION_CLICK = "action_notification_click";
+ private static final String ACTION_NOTIFICATION_DISMISS = "action_notification_dismiss";
private BroadcastReceiver
mDefaultSmsSubscriptionChangedBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -5138,14 +5145,18 @@
for (Phone phone : PhoneFactory.getPhones()) {
int subId = phone.getSubId();
ServiceState serviceState = phone.getServiceState();
- if (serviceState == null) {
+ if (serviceState == null || subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
continue;
}
synchronized (mSatelliteConnectedLock) {
CarrierRoamingSatelliteSessionStats sessionStats =
mCarrierRoamingSatelliteSessionStatsMap.get(subId);
-
+ if (DEBUG) {
+ plogd("handleServiceStateForSatelliteConnectionViaCarrier : SubId = " + subId
+ + " isUsingNonTerrestrialNetwork = "
+ + serviceState.isUsingNonTerrestrialNetwork());
+ }
if (serviceState.isUsingNonTerrestrialNetwork()) {
if (sessionStats != null) {
sessionStats.onSignalStrength(phone);
@@ -5197,7 +5208,6 @@
private void updateLastNotifiedNtnModeAndNotify(@Nullable Phone phone) {
if (!mFeatureFlags.carrierEnabledSatelliteFlag()) return;
-
if (phone == null) {
return;
}
@@ -5212,6 +5222,9 @@
mLastNotifiedNtnMode.put(subId, currNtnMode);
phone.notifyCarrierRoamingNtnModeChanged(currNtnMode);
logCarrierRoamingSatelliteSessionStats(phone, lastNotifiedNtnMode, currNtnMode);
+ if(mIsNotificationShowing && !currNtnMode) {
+ dismissSatelliteNotification();
+ }
}
}
}
@@ -5659,29 +5672,31 @@
}
Pair<Boolean, Integer> isNtn = isUsingNonTerrestrialNetworkViaCarrier();
+ boolean notificationKeyStatus = mSharedPreferences.getBoolean(
+ SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, false);
+ if (DEBUG) {
+ logd("determineAutoConnectSystemNotification: isNtn.first = " + isNtn.first
+ + " IsNotiToShow = " + !notificationKeyStatus + " mIsNotificationShowing = "
+ + mIsNotificationShowing);
+ }
if (isNtn.first) {
- if (mSharedPreferences == null) {
- try {
- mSharedPreferences = mContext.getSharedPreferences(SATELLITE_SHARED_PREF,
- Context.MODE_PRIVATE);
- } catch (Exception e) {
- loge("Cannot get default shared preferences: " + e);
- }
- }
- if (mSharedPreferences == null) {
- loge("determineSystemNotification: Cannot get default shared preferences");
- return;
- }
- if (!mSharedPreferences.getBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, false)) {
+ if (!notificationKeyStatus) {
updateSatelliteSystemNotification(isNtn.second,
CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC,
/*visible*/ true);
- mSharedPreferences.edit().putBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY,
- true).apply();
}
+ } else if (mIsNotificationShowing
+ && !isSatelliteConnectedViaCarrierWithinHysteresisTime()) {
+ // Dismiss the notification if it is still displaying.
+ dismissSatelliteNotification();
}
}
+ private void dismissSatelliteNotification() {
+ mIsNotificationShowing = false;
+ updateSatelliteSystemNotification(-1, -1,/*visible*/ false);
+ }
+
/**
* Update the system notification to reflect the current satellite status, that's either already
* connected OR needs to be manually enabled. The device should only display one notification
@@ -5695,15 +5710,13 @@
*/
private void updateSatelliteSystemNotification(int subId,
@CARRIER_ROAMING_NTN_CONNECT_TYPE int carrierRoamingNtnConnectType, boolean visible) {
- plogd("updateSatelliteSystemNotification subId=" + subId
- + ", carrierRoamingNtnConnectType=" + SatelliteServiceUtils
- .carrierRoamingNtnConnectTypeToString(carrierRoamingNtnConnectType)
- + ", visible=" + visible);
+ plogd("updateSatelliteSystemNotification subId=" + subId + ", carrierRoamingNtnConnectType="
+ + SatelliteServiceUtils.carrierRoamingNtnConnectTypeToString(
+ carrierRoamingNtnConnectType) + ", visible=" + visible);
final NotificationChannel notificationChannel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL,
- NotificationManager.IMPORTANCE_DEFAULT
- );
+ NotificationManager.IMPORTANCE_DEFAULT);
notificationChannel.setSound(null, null);
NotificationManager notificationManager = mContext.getSystemService(
NotificationManager.class);
@@ -5736,54 +5749,130 @@
com.android.internal.R.color.system_notification_accent_color))
.setVisibility(Notification.VISIBILITY_PUBLIC);
- // Add action to invoke message application.
- // getDefaultSmsPackage and getLaunchIntentForPackage are nullable.
- Optional<Intent> nullableIntent = Optional.ofNullable(
- Telephony.Sms.getDefaultSmsPackage(mContext))
- .flatMap(packageName -> {
- PackageManager pm = mContext.getPackageManager();
- return Optional.ofNullable(pm.getLaunchIntentForPackage(packageName));
- });
- // If nullableIntent is null, create new Intent for most common way to invoke message app.
- Intent finalIntent = nullableIntent.map(intent -> {
- // Invoke the home screen of default message application.
- intent.setAction(Intent.ACTION_MAIN);
- intent.addCategory(Intent.CATEGORY_HOME);
- return intent;
- }).orElseGet(() -> {
- ploge("showSatelliteSystemNotification: no default sms package name, Invoke "
- + "default sms compose window instead");
- Intent newIntent = new Intent(Intent.ACTION_VIEW);
- newIntent.setData(Uri.parse("sms:"));
- return newIntent;
- });
-
- PendingIntent pendingIntentOpenMessage = PendingIntent.getActivity(mContext, 0,
- finalIntent, PendingIntent.FLAG_IMMUTABLE);
+ // Intent for `Open Messages` [Button 1]
+ Intent openMessageIntent = new Intent();
+ openMessageIntent.setAction(OPEN_MESSAGE_BUTTON);
+ PendingIntent openMessagePendingIntent = PendingIntent.getBroadcast(mContext, 0,
+ openMessageIntent, PendingIntent.FLAG_IMMUTABLE);
Notification.Action actionOpenMessage = new Notification.Action.Builder(0,
mContext.getResources().getString(R.string.satellite_notification_open_message),
- pendingIntentOpenMessage).build();
- notificationBuilder.addAction(actionOpenMessage);
+ openMessagePendingIntent).build();
+ notificationBuilder.addAction(actionOpenMessage); // Handle `Open Messages` button
- // Add action to invoke Satellite setting activity in Settings.
- Intent intentSatelliteSetting = new Intent(ACTION_SATELLITE_SETTING);
- intentSatelliteSetting.putExtra("sub_id", subId);
- PendingIntent pendingIntentSatelliteSetting = PendingIntent.getActivity(mContext, 0,
- intentSatelliteSetting, PendingIntent.FLAG_IMMUTABLE);
-
- Notification.Action actionOpenSatelliteSetting = new Notification.Action.Builder(null,
+ // Button for `How it works` [Button 2]
+ Intent howItWorksIntent = new Intent();
+ howItWorksIntent.setAction(HOW_IT_WORKS_BUTTON);
+ howItWorksIntent.putExtra("SUBID", subId);
+ PendingIntent howItWorksPendingIntent = PendingIntent.getBroadcast(mContext, 0,
+ howItWorksIntent, PendingIntent.FLAG_IMMUTABLE);
+ Notification.Action actionHowItWorks = new Notification.Action.Builder(0,
mContext.getResources().getString(R.string.satellite_notification_how_it_works),
- pendingIntentSatelliteSetting).build();
- notificationBuilder.addAction(actionOpenSatelliteSetting);
+ howItWorksPendingIntent).build();
+ notificationBuilder.addAction(actionHowItWorks); // Handle `How it works` button
+
+ // Intent for clicking the main notification body
+ Intent notificationClickIntent = new Intent(ACTION_NOTIFICATION_CLICK);
+ PendingIntent notificationClickPendingIntent = PendingIntent.getBroadcast(mContext, 0,
+ notificationClickIntent, PendingIntent.FLAG_IMMUTABLE);
+ notificationBuilder.setContentIntent(
+ notificationClickPendingIntent); // Handle notification body click
+
+ // Intent for dismissing/swiping the notification
+ Intent deleteIntent = new Intent(ACTION_NOTIFICATION_DISMISS);
+ PendingIntent deletePendingIntent = PendingIntent.getBroadcast(mContext, 0, deleteIntent,
+ PendingIntent.FLAG_IMMUTABLE);
+ notificationBuilder.setDeleteIntent(
+ deletePendingIntent); // Handle notification swipe/dismiss
notificationManager.notifyAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
notificationBuilder.build(), UserHandle.ALL);
+ // The Intent filter is to receive the above four events.
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(OPEN_MESSAGE_BUTTON);
+ filter.addAction(HOW_IT_WORKS_BUTTON);
+ filter.addAction(ACTION_NOTIFICATION_CLICK);
+ filter.addAction(ACTION_NOTIFICATION_DISMISS);
+ mContext.registerReceiver(mNotificationInteractionBroadcastReceiver, filter,
+ Context.RECEIVER_EXPORTED);
+
+ mIsNotificationShowing = true;
mCarrierRoamingSatelliteControllerStats.reportCountOfSatelliteNotificationDisplayed();
mCarrierRoamingSatelliteControllerStats.reportCarrierId(getSatelliteCarrierId());
mSessionMetricsStats.addCountOfSatelliteNotificationDisplayed();
}
+ private final BroadcastReceiver mNotificationInteractionBroadcastReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent receivedIntent) {
+ String intentAction = receivedIntent.getAction();
+ if (TextUtils.isEmpty(intentAction)) {
+ loge("Received empty action from the notification");
+ return;
+ }
+ if (DBG) {
+ plogd("Notification Broadcast recvd action = "
+ + receivedIntent.getAction());
+ }
+ boolean closeStatusBar = true;
+ switch (intentAction) {
+ case OPEN_MESSAGE_BUTTON -> {
+ // Add action to invoke message application.
+ // getDefaultSmsPackage and getLaunchIntentForPackage are nullable.
+ Optional<Intent> nullableIntent = Optional.ofNullable(
+ Telephony.Sms.getDefaultSmsPackage(context)).flatMap(
+ packageName -> {
+ PackageManager pm = context.getPackageManager();
+ return Optional.ofNullable(
+ pm.getLaunchIntentForPackage(packageName));
+ });
+ // If nullableIntent is null, create new Intent for most common way to
+ // invoke
+ // message app.
+ Intent finalIntent = nullableIntent.map(intent -> {
+ // Invoke the home screen of default message application.
+ intent.setAction(Intent.ACTION_MAIN);
+ intent.addCategory(Intent.CATEGORY_HOME);
+ return intent;
+ }).orElseGet(() -> {
+ ploge("showSatelliteSystemNotification: no default sms package "
+ + "name, Invoke default sms compose window instead");
+ Intent newIntent = new Intent(Intent.ACTION_VIEW);
+ newIntent.setData(Uri.parse("sms:"));
+ return newIntent;
+ });
+ context.startActivity(finalIntent);
+ }
+ case HOW_IT_WORKS_BUTTON -> {
+ int subId = receivedIntent.getIntExtra("SUBID", -1);
+ Intent intentSatelliteSetting = new Intent(ACTION_SATELLITE_SETTING);
+ intentSatelliteSetting.putExtra("sub_id", subId);
+ intentSatelliteSetting.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intentSatelliteSetting);
+
+ }
+ case ACTION_NOTIFICATION_DISMISS -> closeStatusBar = false;
+ }
+ // Note : ACTION_NOTIFICATION_DISMISS is not required to handled
+ dismissNotificationAndUpdatePref(closeStatusBar);
+ }
+ };
+
+ private void dismissNotificationAndUpdatePref(boolean closeStatusBar) {
+ dismissSatelliteNotification();
+ if (closeStatusBar) {
+ // Collapse the status bar once user interact with notification.
+ StatusBarManager statusBarManager = mContext.getSystemService(StatusBarManager.class);
+ if (statusBarManager != null) {
+ statusBarManager.collapsePanels();
+ }
+ }
+ // update the sharedpref only when user interacted with the notification.
+ mSharedPreferences.edit().putBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, true).apply();
+ mContext.unregisterReceiver(mNotificationInteractionBroadcastReceiver);
+ }
+
private void resetCarrierRoamingSatelliteModeParams() {
if (!mFeatureFlags.carrierEnabledSatelliteFlag()) return;
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
index 0bf8184..cca973f 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
@@ -124,6 +124,8 @@
@Nullable private PersistentLogger mPersistentLogger = null;
+ private boolean mIsTestEmergencyNumber = false;
+
/**
* Create an instance of SatelliteSOSMessageRecommender.
*
@@ -213,11 +215,13 @@
* @param connection The connection created by TelephonyConnectionService for the emergency
* call.
*/
- public void onEmergencyCallStarted(@NonNull Connection connection) {
+ public void onEmergencyCallStarted(@NonNull Connection connection,
+ boolean isTestEmergencyNumber) {
if (!isSatelliteSupported()) {
plogd("onEmergencyCallStarted: satellite is not supported");
return;
}
+ mIsTestEmergencyNumber = isTestEmergencyNumber;
if (hasMessages(EVENT_EMERGENCY_CALL_STARTED)) {
logd("onEmergencyCallStarted: Ignoring due to ongoing event:");
@@ -321,7 +325,8 @@
|| isSatelliteConnectedViaCarrierWithinHysteresisTime())
&& shouldTrackCall(mEmergencyConnection.getState())) {
plogd("handleTimeoutEvent: Sent EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer");
- Bundle extras = createExtraBundleForEventDisplayEmergencyMessage();
+ Bundle extras = createExtraBundleForEventDisplayEmergencyMessage(
+ mIsTestEmergencyNumber);
mEmergencyConnection.sendConnectionEvent(
TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, extras);
isDialerNotified = true;
@@ -426,6 +431,7 @@
mIsTimerTimedOut = false;
mCheckingAccessRestrictionInProgress = false;
mIsSatelliteAllowedForCurrentLocation = false;
+ mIsTestEmergencyNumber = false;
}
}
@@ -585,11 +591,13 @@
@Nullable
private static String getSatelliteEmergencyHandoverIntentActionFromOverlayConfig(
- @NonNull Context context) {
+ @NonNull Context context, boolean isTestEmergencyNumber) {
String action;
try {
- action = context.getResources().getString(
- R.string.config_satellite_emergency_handover_intent_action);
+ int actionIntent = isTestEmergencyNumber
+ ? R.string.config_satellite_test_with_esp_replies_intent_action
+ : R.string.config_satellite_emergency_handover_intent_action;
+ action = context.getResources().getString(actionIntent);
} catch (Resources.NotFoundException ex) {
loge("getSatelliteEmergencyHandoverIntentFilterActionFromOverlayConfig: ex=" + ex);
action = null;
@@ -635,13 +643,15 @@
return callback;
}
- @NonNull private Bundle createExtraBundleForEventDisplayEmergencyMessage() {
+ @NonNull private Bundle createExtraBundleForEventDisplayEmergencyMessage(
+ boolean isTestEmergencyNumber) {
int handoverType = EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
Pair<String, String> oemSatelliteMessagingApp =
getOemEnabledSatelliteHandoverAppFromOverlayConfig(mContext);
String packageName = oemSatelliteMessagingApp.first;
String className = oemSatelliteMessagingApp.second;
- String action = getSatelliteEmergencyHandoverIntentActionFromOverlayConfig(mContext);
+ String action = getSatelliteEmergencyHandoverIntentActionFromOverlayConfig(mContext,
+ isTestEmergencyNumber);
if (isSatelliteConnectedViaCarrierWithinHysteresisTime()
|| isEmergencyCallToSatelliteHandoverTypeT911Enforced()) {
@@ -710,7 +720,8 @@
@NonNull Connection connection) {
plogd("Sent EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer forcefully.");
mEmergencyConnection = connection;
- Bundle extras = createExtraBundleForEventDisplayEmergencyMessage();
+ Bundle extras = createExtraBundleForEventDisplayEmergencyMessage(
+ /* isTestEmergencyNumber= */ true);
connection.sendConnectionEvent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, extras);
mEmergencyConnection = null;
}
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java
index 7bdec47..3bd66f8 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/EuiccPort.java
@@ -133,8 +133,7 @@
UiccCard card, MultipleEnabledProfilesMode supportedMepMode) {
super(c, ci, ics, phoneId, lock, card);
// TODO: Set supportExtendedApdu based on ATR.
- mApduSender = new ApduSender(c, phoneId, ci, ISD_R_AID,
- false /* supportExtendedApdu */);
+ mApduSender = new ApduSender(ci, ISD_R_AID, false /* supportExtendedApdu */);
if (TextUtils.isEmpty(ics.eid)) {
loge("no eid given in constructor for phone " + phoneId);
} else {
diff --git a/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java b/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
index b17a0fd..0a56b2b 100644
--- a/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
+++ b/src/java/com/android/internal/telephony/uicc/euicc/apdu/ApduSender.java
@@ -17,17 +17,11 @@
package com.android.internal.telephony.uicc.euicc.apdu;
import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Build;
import android.os.Handler;
import android.os.Looper;
-import android.preference.PreferenceManager;
import android.telephony.IccOpenLogicalChannelResponse;
-import android.util.Base64;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.euicc.EuiccSession;
import com.android.internal.telephony.uicc.IccIoResult;
import com.android.internal.telephony.uicc.euicc.async.AsyncResultCallback;
import com.android.internal.telephony.uicc.euicc.async.AsyncResultHelper;
@@ -42,14 +36,7 @@
* before sending and closed after all APDU commands are sent. The complete response of the last
* APDU command will be returned. If any APDU command returns an error status (other than
* {@link #STATUS_NO_ERROR}) or causing an exception, an {@link ApduException} will be returned
- * immediately without sending the rest of commands.
- *
- * <p>If {@link EuiccSession} indicates ongoing session(s), the behavior changes: 1) before
- * sending, check if a channel is opened already. If yes, reuse the channel and send APDU commands
- * directly. If no, open a channel before sending. 2) The channel is closed when EuiccSession
- * class ends all sessions, independent of APDU sending.
- *
- * <p>This class is thread-safe.
+ * immediately without sending the rest of commands. This class is thread-safe.
*
* @hide
*/
@@ -63,12 +50,8 @@
// Status code of APDU response
private static final int STATUS_NO_ERROR = 0x9000;
private static final int SW1_NO_ERROR = 0x91;
- private static final int STATUS_CHANNEL_CLOSED = 0x6881; // b/359336875
private static final int WAIT_TIME_MS = 2000;
- private static final String CHANNEL_ID_PRE = "esim-channel";
- static final String ISD_R_AID = "A0000005591010FFFFFFFF8900000100";
- private static final String CHANNEL_RESPONSE_ID_PRE = "esim-res-id";
private static void logv(String msg) {
Rlog.v(LOG_TAG, msg);
@@ -78,50 +61,26 @@
Rlog.d(LOG_TAG, msg);
}
- private static void loge(String msg) {
- Rlog.e(LOG_TAG, msg);
- }
-
private final String mAid;
private final boolean mSupportExtendedApdu;
private final OpenLogicalChannelInvocation mOpenChannel;
private final CloseLogicalChannelInvocation mCloseChannel;
private final TransmitApduLogicalChannelInvocation mTransmitApdu;
- private final Context mContext;
- private final String mChannelKey;
- private final String mChannelResponseKey;
- // closeAnyOpenChannel() needs a handler for its async callbacks.
- private final Handler mHandler;
- // Lock for accessing mChannelInUse. We only allow to open a single logical
- // channel at any time for an AID and to invoke one command at any time.
- // Only the thread (and its async callbacks) that sets mChannelInUse
- // can open/close/send, and update mChannelOpened.
- private final Object mChannelInUseLock = new Object();
- @GuardedBy("mChannelInUseLock")
- private boolean mChannelInUse;
+ // Lock for accessing mChannelOpened. We only allow to open a single logical channel at any
+ // time for an AID.
+ private final Object mChannelLock = new Object();
private boolean mChannelOpened;
/**
* @param aid The AID that will be used to open a logical channel to.
*/
- public ApduSender(Context context, int phoneId, CommandsInterface ci, String aid,
- boolean supportExtendedApdu) {
- if (!aid.equals(ISD_R_AID) && !"user".equals(Build.TYPE)) {
- throw new IllegalArgumentException("Only ISD-R AID is supported.");
- }
+ public ApduSender(CommandsInterface ci, String aid, boolean supportExtendedApdu) {
mAid = aid;
- mContext = context;
mSupportExtendedApdu = supportExtendedApdu;
mOpenChannel = new OpenLogicalChannelInvocation(ci);
mCloseChannel = new CloseLogicalChannelInvocation(ci);
mTransmitApdu = new TransmitApduLogicalChannelInvocation(ci);
- mChannelKey = CHANNEL_ID_PRE + "_" + phoneId;
- mChannelResponseKey = CHANNEL_RESPONSE_ID_PRE + "_" + phoneId;
- mHandler = new Handler();
-
- mChannelInUse = false;
- closeAnyOpenChannel();
}
/**
@@ -140,125 +99,79 @@
RequestProvider requestProvider,
ApduSenderResultCallback resultCallback,
Handler handler) {
- if (!acquireChannelLock()) {
- AsyncResultHelper.throwException(
- new ApduException("The logical channel is still in use."),
- resultCallback,
- handler);
- return;
- }
-
- boolean euiccSession = EuiccSession.get().hasSession();
- // Case 1, channel was already opened AND EuiccSession is ongoing.
- // sendCommand directly. Do not immediately close channel after sendCommand.
- // Case 2, channel was already opened AND EuiccSession is not ongoing. This means
- // EuiccSession#endSession is already called but closeAnyOpenChannel() is not
- // yet executed because of waiting to acquire lock hold by this thread.
- // sendCommand directly. Close channel immediately anyways after sendCommand.
- // Case 3, channel is not open AND EuiccSession is ongoing. Open channel
- // before sendCommand. Do not immediately close channel after sendCommand.
- // Case 4, channel is not open AND EuiccSession is not ongoing. Open channel
- // before sendCommand. Close channel immediately after sendCommand.
- if (mChannelOpened) { // Case 1 or 2
- if (euiccSession) {
- EuiccSession.get().noteChannelOpen(this);
- }
- RequestBuilder builder = getRequestBuilderWithOpenedChannel(requestProvider,
- !euiccSession /* closeChannelImmediately */, resultCallback, handler);
- if (builder == null) {
- return;
- }
- sendCommand(builder.getCommands(), 0 /* index */,
- !euiccSession /* closeChannelImmediately */, resultCallback, handler);
- } else { // Case 3 or 4
- if (euiccSession) {
- EuiccSession.get().noteChannelOpen(this);
- }
- openChannel(requestProvider,
- !euiccSession /* closeChannelImmediately */, resultCallback, handler);
- }
- }
-
- private RequestBuilder getRequestBuilderWithOpenedChannel(
- RequestProvider requestProvider,
- boolean closeChannelImmediately,
- ApduSenderResultCallback resultCallback,
- Handler handler) {
- Throwable requestException = null;
- int channel =
- PreferenceManager.getDefaultSharedPreferences(mContext)
- .getInt(mChannelKey, IccOpenLogicalChannelResponse.INVALID_CHANNEL);
- String storedResponse =
- PreferenceManager.getDefaultSharedPreferences(mContext)
- .getString(mChannelResponseKey, "");
- byte[] selectResponse = Base64.decode(storedResponse, Base64.DEFAULT);
- RequestBuilder builder = new RequestBuilder(channel, mSupportExtendedApdu);
- try {
- requestProvider.buildRequest(selectResponse, builder);
- } catch (Throwable e) {
- requestException = e;
- }
- if (builder.getCommands().isEmpty() || requestException != null) {
- logd("Release as commands are empty or exception occurred");
- returnRespnseOrException(channel, closeChannelImmediately,
- null /* response */, requestException, resultCallback, handler);
- return null;
- }
- return builder;
- }
-
- private void openChannel(
- RequestProvider requestProvider,
- boolean closeChannelImmediately,
- ApduSenderResultCallback resultCallback,
- Handler handler) {
- mOpenChannel.invoke(mAid, new AsyncResultCallback<IccOpenLogicalChannelResponse>() {
- @Override
- public void onResult(IccOpenLogicalChannelResponse openChannelResponse) {
- int channel = openChannelResponse.getChannel();
- int status = openChannelResponse.getStatus();
- byte[] selectResponse = openChannelResponse.getSelectResponse();
- if (status == IccOpenLogicalChannelResponse.STATUS_NO_SUCH_ELEMENT) {
- channel = PreferenceManager.getDefaultSharedPreferences(mContext)
- .getInt(mChannelKey,
- IccOpenLogicalChannelResponse.INVALID_CHANNEL);
- if (channel != IccOpenLogicalChannelResponse.INVALID_CHANNEL) {
- logv("Try to use already opened channel: " + channel);
- status = IccOpenLogicalChannelResponse.STATUS_NO_ERROR;
- String storedResponse = PreferenceManager
- .getDefaultSharedPreferences(mContext)
- .getString(mChannelResponseKey, "");
- selectResponse = Base64.decode(storedResponse, Base64.DEFAULT);
- }
- }
-
- if (channel == IccOpenLogicalChannelResponse.INVALID_CHANNEL
- || status != IccOpenLogicalChannelResponse.STATUS_NO_ERROR) {
- mChannelOpened = false;
- resultCallback.onException(
- new ApduException("Failed to open logical channel for AID: "
- + mAid + ", with status: " + status));
- return;
- }
- PreferenceManager.getDefaultSharedPreferences(mContext)
- .edit()
- .putInt(mChannelKey, channel)
- .putString(mChannelResponseKey,
- Base64.encodeToString(selectResponse, Base64.DEFAULT)).apply();
- mChannelOpened = true;
-
- RequestBuilder builder =
- getRequestBuilderWithOpenedChannel(requestProvider,
- closeChannelImmediately, resultCallback, handler);
- if (builder == null) {
- return;
- }
-
- sendCommand(builder.getCommands(), 0 /* index */,
- closeChannelImmediately, resultCallback, handler);
+ synchronized (mChannelLock) {
+ if (mChannelOpened) {
+ if (!Looper.getMainLooper().equals(Looper.myLooper())) {
+ logd("Logical channel has already been opened. Wait.");
+ try {
+ mChannelLock.wait(WAIT_TIME_MS);
+ } catch (InterruptedException e) {
+ // nothing to do
}
- },
- handler);
+ if (mChannelOpened) {
+ AsyncResultHelper.throwException(
+ new ApduException("The logical channel is still in use."),
+ resultCallback, handler);
+ return;
+ }
+ } else {
+ AsyncResultHelper.throwException(
+ new ApduException("The logical channel is in use."),
+ resultCallback, handler);
+ return;
+ }
+ }
+ mChannelOpened = true;
+ }
+
+ mOpenChannel.invoke(mAid, new AsyncResultCallback<IccOpenLogicalChannelResponse>() {
+ @Override
+ public void onResult(IccOpenLogicalChannelResponse openChannelResponse) {
+ int channel = openChannelResponse.getChannel();
+ int status = openChannelResponse.getStatus();
+ if (channel == IccOpenLogicalChannelResponse.INVALID_CHANNEL
+ || status != IccOpenLogicalChannelResponse.STATUS_NO_ERROR) {
+ synchronized (mChannelLock) {
+ mChannelOpened = false;
+ mChannelLock.notify();
+ }
+ resultCallback.onException(
+ new ApduException("Failed to open logical channel opened for AID: "
+ + mAid + ", with status: " + status));
+ return;
+ }
+
+ RequestBuilder builder = new RequestBuilder(channel, mSupportExtendedApdu);
+ Throwable requestException = null;
+ try {
+ requestProvider.buildRequest(openChannelResponse.getSelectResponse(), builder);
+ } catch (Throwable e) {
+ requestException = e;
+ }
+ if (builder.getCommands().isEmpty() || requestException != null) {
+ // Just close the channel if we don't have commands to send or an error
+ // was encountered.
+ closeAndReturn(channel, null /* response */, requestException, resultCallback,
+ handler);
+ return;
+ }
+ sendCommand(builder.getCommands(), 0 /* index */, resultCallback, handler);
+ }
+ }, handler);
+ }
+
+ /**
+ * Closes any open channel.
+ *
+ * <p>Used by EuiccSession#endSession.
+ */
+ public void closeAnyOpenChannel() {
+ // TODO: implement this. Different from existing closeExistingChannelIfExists()
+ // which is only used in constructor and don't worry about multi-thread racing.
+ // 1. Acquire channel lock
+ // 2. Check sharedpref for existing open channel
+ // 3. Close any open channel
+ // 4. Release channel lock
}
/**
@@ -271,7 +184,6 @@
private void sendCommand(
List<ApduCommand> commands,
int index,
- boolean closeChannelImmediately,
ApduSenderResultCallback resultCallback,
Handler handler) {
ApduCommand command = commands.get(index);
@@ -286,21 +198,9 @@
public void onResult(IccIoResult fullResponse) {
logv("Full APDU response: " + fullResponse);
int status = (fullResponse.sw1 << 8) | fullResponse.sw2;
- if (status != STATUS_NO_ERROR
- && fullResponse.sw1 != SW1_NO_ERROR) {
- if (status == STATUS_CHANNEL_CLOSED) {
- // Channel is closed by EUICC e.g. REFRESH.
- tearDownPreferences();
- mChannelOpened = false;
- // TODO: add retry
- }
- returnRespnseOrException(
- command.channel,
- closeChannelImmediately,
- null /* response */,
- new ApduException(status),
- resultCallback,
- handler);
+ if (status != STATUS_NO_ERROR && fullResponse.sw1 != SW1_NO_ERROR) {
+ closeAndReturn(command.channel, null /* response */,
+ new ApduException(status), resultCallback, handler);
return;
}
@@ -310,17 +210,11 @@
fullResponse);
if (continueSendCommand) {
// Sends the next command
- sendCommand(commands, index + 1,
- closeChannelImmediately, resultCallback, handler);
+ sendCommand(commands, index + 1, resultCallback, handler);
} else {
// Returns the result of the last command
- returnRespnseOrException(
- command.channel,
- closeChannelImmediately,
- fullResponse.payload,
- null /* exception */,
- resultCallback,
- handler);
+ closeAndReturn(command.channel, fullResponse.payload,
+ null /* exception */, resultCallback, handler);
}
}
}, handler);
@@ -343,7 +237,7 @@
AsyncResultCallback<IccIoResult> resultCallback,
Handler handler) {
ByteArrayOutputStream resultBuilder =
- responseBuilder == null ? new ByteArrayOutputStream() : responseBuilder;
+ responseBuilder == null ? new ByteArrayOutputStream() : responseBuilder;
if (lastResponse.payload != null) {
try {
resultBuilder.write(lastResponse.payload);
@@ -369,41 +263,6 @@
}, handler);
}
- private void tearDownPreferences() {
- PreferenceManager.getDefaultSharedPreferences(mContext)
- .edit()
- .remove(mChannelKey)
- .remove(mChannelResponseKey)
- .apply();
- }
-
- /**
- * Fires the {@code resultCallback} to return a response or exception. Also
- * closes the open logical channel if {@code closeChannelImmediately} is {@code true}.
- */
- private void returnRespnseOrException(
- int channel,
- boolean closeChannelImmediately,
- @Nullable byte[] response,
- @Nullable Throwable exception,
- ApduSenderResultCallback resultCallback,
- Handler handler) {
- if (closeChannelImmediately) {
- closeAndReturn(
- channel,
- response,
- exception,
- resultCallback,
- handler);
- } else {
- releaseChannelLockAndReturn(
- response,
- exception,
- resultCallback,
- handler);
- }
- }
-
/**
* Closes the opened logical channel.
*
@@ -421,9 +280,10 @@
mCloseChannel.invoke(channel, new AsyncResultCallback<Boolean>() {
@Override
public void onResult(Boolean aBoolean) {
- tearDownPreferences();
- mChannelOpened = false;
- releaseChannelLock();
+ synchronized (mChannelLock) {
+ mChannelOpened = false;
+ mChannelLock.notify();
+ }
if (exception == null) {
resultCallback.onResult(response);
@@ -433,99 +293,4 @@
}
}, handler);
}
-
- /**
- * Cleanup the existing opened channel which remained opened earlier due
- * to:
- *
- * <p> 1) onging EuiccSession. This will be called by {@link EuiccSession#endSession()}
- * from non-main-thread. Or,
- *
- * <p> 2) telephony crash. This will be called by constructor from main-thread.
- */
- public void closeAnyOpenChannel() {
- if (!acquireChannelLock()) {
- // This cannot happen for case 2) when called by constructor
- loge("[closeAnyOpenChannel] failed to acquire channel lock");
- return;
- }
- int channelId = PreferenceManager.getDefaultSharedPreferences(mContext)
- .getInt(mChannelKey, IccOpenLogicalChannelResponse.INVALID_CHANNEL);
- if (channelId == IccOpenLogicalChannelResponse.INVALID_CHANNEL) {
- releaseChannelLock();
- return;
- }
- logv("[closeAnyOpenChannel] closing the open channel : " + channelId);
- mCloseChannel.invoke(channelId, new AsyncResultCallback<Boolean>() {
- @Override
- public void onResult(Boolean isSuccess) {
- if (isSuccess) {
- logv("[closeAnyOpenChannel] Channel closed successfully: " + channelId);
- tearDownPreferences();
- }
- // Even if CloseChannel failed, pretend that the channel is closed.
- // So next send() will try open the channel again. If the channel is
- // indeed still open, we use the channelId saved in sharedPref.
- mChannelOpened = false;
- releaseChannelLock();
- }
- }, mHandler);
- }
-
- // releases channel and callback
- private void releaseChannelLockAndReturn(
- @Nullable byte[] response,
- @Nullable Throwable exception,
- ApduSenderResultCallback resultCallback,
- Handler handler) {
- handler.post(
- () -> {
- releaseChannelLock();
- if (exception == null) {
- resultCallback.onResult(response);
- } else {
- resultCallback.onException(exception);
- }
- });
- }
-
- private void releaseChannelLock() {
- synchronized (mChannelInUseLock) {
- logd("Channel lock released.");
- mChannelInUse = false;
- mChannelInUseLock.notify();
- }
- }
-
- /**
- * Acquires channel lock and returns {@code true} if successful.
- *
- * <p>It fails and returns {@code false} when:
- * <ul>
- * <li>Called from main thread, and mChannelInUse=true, fails immediately.
- * <li>Called from non main thread, and mChannelInUse=true after 2 seconds waiting, fails.
- * </ul>
- */
- private boolean acquireChannelLock() {
- synchronized (mChannelInUseLock) {
- if (mChannelInUse) {
- if (!Looper.getMainLooper().equals(Looper.myLooper())) {
- logd("Logical channel is in use. Wait.");
- try {
- mChannelInUseLock.wait(WAIT_TIME_MS);
- } catch (InterruptedException e) {
- // nothing to do
- }
- if (mChannelInUse) {
- return false;
- }
- } else {
- return false;
- }
- }
- mChannelInUse = true;
- logd("Channel lock acquired.");
- return true;
- }
- }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
index 7f31f30..db46a00 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -3593,12 +3593,14 @@
processAllMessages();
verify(mMockNotificationManager, times(1)).notifyAsUser(anyString(), anyInt(), any(),
any());
- assertTrue(mSharedPreferences.getBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, false));
+ // Just by showing notification we do not update the pref file , only once user interact
+ // only we will update the pref value to true.
+ assertFalse(mSharedPreferences.getBoolean(SATELLITE_SYSTEM_NOTIFICATION_DONE_KEY, false));
// Check don't display again after displayed already a system notification.
sendServiceStateChangedEvent();
processAllMessages();
- verify(mMockNotificationManager, times(1)).notifyAsUser(anyString(), anyInt(), any(),
+ verify(mMockNotificationManager, times(2)).notifyAsUser(anyString(), anyInt(), any(),
any());
}
@@ -4116,7 +4118,7 @@
assertTrue(mSatelliteControllerUT.isCarrierRoamingNtnEligible(mPhone));
verify(mPhone, times(0)).notifyCarrierRoamingNtnEligibleStateChanged(eq(true));
verify(mPhone2, times(0)).notifyCarrierRoamingNtnEligibleStateChanged(anyBoolean());
- verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(), anyInt(),
+ verify(mMockNotificationManager, times(2)).cancelAsUser(anyString(), anyInt(),
any());
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
index 358ec47..230a9b1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
@@ -204,7 +204,7 @@
when(mServiceState.getState()).thenReturn(STATE_OUT_OF_SERVICE);
when(mServiceState2.getState()).thenReturn(STATE_OUT_OF_SERVICE);
mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
- mTestSOSMessageRecommender.onEmergencyCallStarted(null);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(null, false);
processAllMessages();
assertFalse(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -213,7 +213,7 @@
private void testTimeoutBeforeEmergencyCallEnd(int expectedHandoverType,
String expectedPackageName, String expectedClassName, String expectedAction) {
mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
@@ -246,7 +246,7 @@
mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
mTestSatelliteController.setIsSatelliteViaOemProvisioned(false);
mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
@@ -273,7 +273,7 @@
mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
mTestSatelliteController.isOemEnabledSatelliteSupported = false;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1);
@@ -312,7 +312,7 @@
@Test
public void testNetworkStateChangedBeforeTimeout() {
mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -341,7 +341,7 @@
@Test
public void testSatelliteProvisionStateChangedBeforeTimeout() {
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -358,7 +358,7 @@
assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1);
assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 1);
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -392,7 +392,7 @@
@Test
public void testEmergencyCallRedialBeforeTimeout() {
mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -400,7 +400,7 @@
assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 1);
assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -454,7 +454,7 @@
@Test
public void testOnEmergencyCallConnectionStateChangedWithWrongCallId() {
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -476,7 +476,7 @@
@Test
public void testSatelliteNotAllowedInCurrentLocation() {
mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -508,7 +508,7 @@
mContext,
Looper.myLooper(),
satelliteController, mTestImsManager);
- testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertFalse(testSOSMessageRecommender.isTimerStarted());
@@ -538,13 +538,13 @@
// Both OEM and carrier don't support satellite
mTestSatelliteController.isSatelliteEmergencyMessagingSupportedViaCarrier = false;
mTestSatelliteController.isOemEnabledSatelliteSupported = false;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertEquals(0, mTestSOSMessageRecommender.getTimeOutMillis());
// Only OEM support satellite
mTestSatelliteController.isOemEnabledSatelliteSupported = true;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertEquals(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
mTestSOSMessageRecommender.getTimeOutMillis());
@@ -556,7 +556,7 @@
mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
mTestSatelliteController.carrierEmergencyCallWaitForConnectionTimeoutMillis =
carrierTimeoutMillis;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertEquals(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
mTestSOSMessageRecommender.getTimeOutMillis());
@@ -567,7 +567,7 @@
mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
mTestSatelliteController.carrierEmergencyCallWaitForConnectionTimeoutMillis =
carrierTimeoutMillis;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertEquals(carrierTimeoutMillis, mTestSOSMessageRecommender.getTimeOutMillis());
}
@@ -578,7 +578,7 @@
mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
mTestSatelliteController.mIsSatelliteViaOemProvisioned = true;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
mTestSOSMessageRecommender.getEmergencyCallToSatelliteHandoverType());
@@ -591,7 +591,7 @@
mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
mTestSatelliteController.mIsSatelliteViaOemProvisioned = false;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
mTestSOSMessageRecommender.getEmergencyCallToSatelliteHandoverType());
@@ -604,13 +604,13 @@
mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
mTestSatelliteController.mIsSatelliteViaOemProvisioned = true;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
mTestSOSMessageRecommender.getEmergencyCallToSatelliteHandoverType());
mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
mTestSatelliteController.mIsSatelliteViaOemProvisioned = false;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
assertEquals(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
mTestSOSMessageRecommender.getEmergencyCallToSatelliteHandoverType());
@@ -619,7 +619,7 @@
private void testStopTrackingCallBeforeTimeout(
@Connection.ConnectionState int connectionState) {
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
@@ -641,7 +641,7 @@
@ServiceState.RegState int availableServiceState,
@ServiceState.RegState int unavailableServiceState) {
mTestSOSMessageRecommender.isSatelliteAllowedCallback = null;
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, false);
processAllMessages();
assertNull(mTestSOSMessageRecommender.isSatelliteAllowedCallback);
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java
index 172211c..a65814e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/apdu/ApduSenderTest.java
@@ -16,52 +16,36 @@
package com.android.internal.telephony.uicc.euicc.apdu;
-import static com.android.internal.telephony.CommandException.Error.RADIO_NOT_AVAILABLE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.os.Handler;
import android.os.Looper;
-import android.platform.test.flag.junit.SetFlagsRule;
-import android.preference.PreferenceManager;
-import android.telephony.IccOpenLogicalChannelResponse;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
-import androidx.test.InstrumentationRegistry;
-
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.euicc.EuiccSession;
-import com.android.internal.telephony.flags.Flags;
import com.android.internal.telephony.uicc.IccIoResult;
import com.android.internal.telephony.uicc.IccUtils;
import org.junit.After;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.InOrder;
-import org.mockito.Mockito;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
public class ApduSenderTest {
- @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static class ResponseCaptor extends ApduSenderResultCallback {
public byte[] response;
@@ -91,13 +75,6 @@
}
}
- private static final int PHONE_ID = 0;
- private static final String SESSION_ID = "TEST";
- // keep in sync with ApduSender.mChannelKey
- private static final String SHARED_PREFS_KEY_CHANNEL_ID = "esim-channel_0";
- // keep in sync with ApduSender.mChannelResponseKey
- private static final String SHARED_PREFS_KEY_CHANNEL_RESPONSE = "esim-res-id_0";
-
// Mocked classes
private CommandsInterface mMockCi;
@@ -105,20 +82,19 @@
private Handler mHandler;
private ResponseCaptor mResponseCaptor;
private byte[] mSelectResponse;
+ private static final String AID = "B2C3D4";
private ApduSender mSender;
@Before
public void setUp() {
- mSetFlagsRule.enableFlags(Flags.FLAG_OPTIMIZATION_APDU_SENDER);
-
mMockCi = mock(CommandsInterface.class);
- mLooper = TestableLooper.get(this);
- mHandler = new Handler(mLooper.getLooper());
+ mHandler = new Handler(Looper.myLooper());
+
mResponseCaptor = new ResponseCaptor();
mSelectResponse = null;
- mSender = new ApduSender(InstrumentationRegistry.getContext(), PHONE_ID,
- mMockCi, ApduSender.ISD_R_AID, false /* supportExtendedApdu */);
+ mSender = new ApduSender(mMockCi, AID, false /* supportExtendedApdu */);
+ mLooper = TestableLooper.get(this);
}
@After
@@ -129,19 +105,6 @@
mResponseCaptor = null;
mSelectResponse = null;
mSender = null;
-
- EuiccSession.get().endSession(SESSION_ID);
- clearSharedPreferences();
- }
-
- @Test
- public void testWrongAid_throwsIllegalArgumentException() {
- String wrongAid = "-1";
-
- assertThrows(IllegalArgumentException.class, () -> {
- new ApduSender(InstrumentationRegistry.getContext(), 0 /* phoneId= */,
- mMockCi, wrongAid, false /* supportExtendedApdu */);
- });
}
@Test
@@ -156,7 +119,7 @@
assertEquals("A1A1A19000", IccUtils.bytesToHexString(mSelectResponse));
assertNull(mResponseCaptor.response);
assertNull(mResponseCaptor.exception);
- verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
+ verify(mMockCi).iccOpenLogicalChannel(eq(AID), anyInt(), any());
verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
}
@@ -172,7 +135,7 @@
assertNull("Request provider should not be called when failed to open channel.",
mSelectResponse);
assertTrue(mResponseCaptor.exception instanceof ApduException);
- verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
+ verify(mMockCi).iccOpenLogicalChannel(eq(AID), anyInt(), any());
}
@Test
@@ -186,11 +149,8 @@
mLooper.processAllMessages();
assertEquals("A1A1A1", IccUtils.bytesToHexString(mResponseCaptor.response));
- InOrder inOrder = inOrder(mMockCi);
- inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
- inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10),
- eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
- inOrder.verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
+ verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2),
+ eq(3), eq(0), eq("a"), anyBoolean(), any());
}
@Test
@@ -209,17 +169,14 @@
mLooper.processAllMessages();
assertEquals("A4", IccUtils.bytesToHexString(mResponseCaptor.response));
- InOrder inOrder = inOrder(mMockCi);
- inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
- inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10),
- eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
- inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10),
- eq(1), eq(2), eq(3), eq(1), eq("ab"), anyBoolean(), any());
- inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10),
- eq(1), eq(2), eq(3), eq(0), eq(""), anyBoolean(), any());
- inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81),
- eq(0xE2), eq(0x91), eq(0), eq(2), eq("abcd"), anyBoolean(), any());
- inOrder.verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
+ verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2),
+ eq(3), eq(0), eq("a"), anyBoolean(), any());
+ verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2),
+ eq(3), eq(1), eq("ab"), anyBoolean(), any());
+ verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10), eq(1), eq(2),
+ eq(3), eq(0), eq(""), anyBoolean(), any());
+ verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(0x81), eq(0xE2), eq(0x91),
+ eq(0), eq(2), eq("abcd"), anyBoolean(), any());
}
@Test
@@ -382,157 +339,6 @@
assertNull("Should not open channel when another one is already opened.", mSelectResponse);
assertTrue(mResponseCaptor.exception instanceof ApduException);
- verify(mMockCi, times(1)).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
- }
-
- @Test
- public void testConstructor_closeOpenChannelInSharedPreference() throws InterruptedException {
- // Open a channel and not close it, by making CI.iccTransmitApduLogicalChannel throw.
- int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
- doThrow(new RuntimeException()).when(mMockCi).iccTransmitApduLogicalChannel(
- eq(channel), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), any(),
- anyBoolean(), any());
- mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
- 10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
- mLooper.processAllMessages();
- // Stub close channel
- reset(mMockCi);
- LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel, /* error= */ null);
-
- // Call constructor
- mSender = new ApduSender(InstrumentationRegistry.getContext(), PHONE_ID,
- mMockCi, ApduSender.ISD_R_AID, false /* supportExtendedApdu */);
- mLooper.processAllMessages();
-
- // The constructor should have closed channel
- verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
- assertEquals(-1, getChannelIdFromSharedPreferences());
- }
-
- @Test
- public void testSend_OpenChannelFailedNoSuchElement_useChannelInSharedPreference() {
- // Open a channel but not close, by making CI.iccTransmitApduLogicalChannel throw.
- int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
- doThrow(new RuntimeException()).when(mMockCi).iccTransmitApduLogicalChannel(
- eq(channel), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), any(),
- anyBoolean(), any());
- mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
- 10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
- mLooper.processAllMessages();
- reset(mMockCi);
- // Constructor fails to close channel
- LogicalChannelMocker.mockCloseLogicalChannel(
- mMockCi, channel, new CommandException(RADIO_NOT_AVAILABLE));
- mSender = new ApduSender(InstrumentationRegistry.getContext(), PHONE_ID,
- mMockCi, ApduSender.ISD_R_AID, false /* supportExtendedApdu */);
- mLooper.processAllMessages();
- reset(mMockCi);
- // Stub open channel failure NO_SUCH_ELEMENT
- LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi,
- new CommandException(CommandException.Error.NO_SUCH_ELEMENT));
- LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel, "A1A1A19000");
- LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel, /* error= */ null);
-
- mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
- 10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
- mLooper.processAllMessages();
-
- // open channel would fail, and send/close would succeed because of
- // previous open response saved in sharedPref
- InOrder inOrder = inOrder(mMockCi);
- inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
- inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel),
- eq(channel | 10), eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
- inOrder.verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void testSend_euiccSession_shouldNotCloseChannel()
- throws InterruptedException {
- int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
- LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel, "A1A1A19000");
- LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel, /* error= */ null);
- EuiccSession.get().startSession(SESSION_ID);
-
- mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
- 10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
- mLooper.processAllMessages();
-
- assertEquals("A1A1A1", IccUtils.bytesToHexString(mResponseCaptor.response));
- InOrder inOrder = inOrder(mMockCi);
- inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
- inOrder.verify(mMockCi).iccTransmitApduLogicalChannel(eq(channel), eq(channel | 10),
- eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
- // No iccCloseLogicalChannel
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void testSendTwice_euiccSession_shouldOpenChannelOnceNotCloseChannel()
- throws InterruptedException {
- int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
- LogicalChannelMocker.mockSendToLogicalChannel(
- mMockCi, channel, "A1A1A19000", "A1A1A19000");
- LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel, /* error= */ null);
- EuiccSession.get().startSession(SESSION_ID);
-
- mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
- 10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
- mLooper.processAllMessages();
- mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
- 10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
- mLooper.processAllMessages();
-
- assertEquals("A1A1A1", IccUtils.bytesToHexString(mResponseCaptor.response));
- InOrder inOrder = inOrder(mMockCi);
- // iccOpenLogicalChannel once
- inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
- // iccTransmitApduLogicalChannel twice
- inOrder.verify(mMockCi, times(2)).iccTransmitApduLogicalChannel(eq(channel),
- eq(channel | 10), eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
- // No iccCloseLogicalChannel
- inOrder.verifyNoMoreInteractions();
- }
-
- @Test
- public void testSendTwice_thenEndSession() throws InterruptedException {
- int channel = LogicalChannelMocker.mockOpenLogicalChannelResponse(mMockCi, "9000");
- LogicalChannelMocker.mockSendToLogicalChannel(mMockCi, channel,
- "A1A1A19000", "A1A1A19000");
- LogicalChannelMocker.mockCloseLogicalChannel(mMockCi, channel, /* error= */ null);
- EuiccSession.get().startSession(SESSION_ID);
-
- mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
- 10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
- mLooper.processAllMessages();
- mSender.send((selectResponse, requestBuilder) -> requestBuilder.addApdu(
- 10, 1, 2, 3, 0, "a"), mResponseCaptor, mHandler);
- mLooper.processAllMessages();
- EuiccSession.get().endSession(SESSION_ID);
- mLooper.processAllMessages();
-
- assertEquals("A1A1A1", IccUtils.bytesToHexString(mResponseCaptor.response));
- InOrder inOrder = inOrder(mMockCi);
- // iccOpenLogicalChannel once
- inOrder.verify(mMockCi).iccOpenLogicalChannel(eq(ApduSender.ISD_R_AID), anyInt(), any());
- // iccTransmitApduLogicalChannel twice
- inOrder.verify(mMockCi, times(2)).iccTransmitApduLogicalChannel(eq(channel),
- eq(channel | 10), eq(1), eq(2), eq(3), eq(0), eq("a"), anyBoolean(), any());
- // iccCloseLogicalChannel once
- inOrder.verify(mMockCi).iccCloseLogicalChannel(eq(channel), eq(true /*isEs10*/), any());
- }
-
- private int getChannelIdFromSharedPreferences() {
- return PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getContext())
- .getInt(SHARED_PREFS_KEY_CHANNEL_ID, -1);
- }
-
- private void clearSharedPreferences() {
- PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getContext())
- .edit()
- .remove(SHARED_PREFS_KEY_CHANNEL_ID)
- .remove(SHARED_PREFS_KEY_CHANNEL_RESPONSE)
- .apply();
+ verify(mMockCi, times(1)).iccOpenLogicalChannel(eq(AID), anyInt(), any());
}
}