Merge "Remove sysprop based radio reset sync mechanism"
diff --git a/src/java/com/android/internal/telephony/Connection.java b/src/java/com/android/internal/telephony/Connection.java
index 4c42d71..74ee5c5 100644
--- a/src/java/com/android/internal/telephony/Connection.java
+++ b/src/java/com/android/internal/telephony/Connection.java
@@ -34,6 +34,7 @@
* {@hide}
*/
public abstract class Connection {
+ private static final String TAG = "Connection";
public interface PostDialListener {
void onPostDialWait();
@@ -827,6 +828,16 @@
public void setConnectionExtras(Bundle extras) {
if (extras != null) {
mExtras = new Bundle(extras);
+
+ int previousCount = mExtras.size();
+ // Prevent vendors from passing in extras other than primitive types and android API
+ // parcelables.
+ mExtras = mExtras.filterValues();
+ int filteredCount = mExtras.size();
+ if (filteredCount != previousCount) {
+ Rlog.i(TAG, "setConnectionExtras: filtering " + (previousCount - filteredCount)
+ + " invalid extras.");
+ }
} else {
mExtras = null;
}
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 9873d97..0c34749 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -283,7 +283,7 @@
tm.setPhoneType(getPhoneId(), PhoneConstants.PHONE_TYPE_GSM);
mIccCardProxy.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
} else {
- mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
+ mCdmaSubscriptionSource = mCdmaSSM.getCdmaSubscriptionSource();
// This is needed to handle phone process crashes
mIsPhoneInEcmState = getInEcmMode();
if (mIsPhoneInEcmState) {
@@ -502,7 +502,7 @@
ret = PhoneConstants.DataState.DISCONNECTED;
} else if (mSST.getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE
- && (isPhoneTypeCdma() ||
+ && (isPhoneTypeCdma() || isPhoneTypeCdmaLte() ||
(isPhoneTypeGsm() && !apnType.equals(PhoneConstants.APN_TYPE_EMERGENCY)))) {
// If we're out of service, open TCP sockets may still work
// but no data will flow
@@ -1852,6 +1852,8 @@
@Override
public void setTTYMode(int ttyMode, Message onComplete) {
+ // Send out the TTY Mode change over RIL as well
+ super.setTTYMode(ttyMode, onComplete);
if (mImsPhone != null) {
mImsPhone.setTTYMode(ttyMode, onComplete);
}
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 1ccf1c4..fad0ddb 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -224,6 +224,9 @@
// Key used to read/write "disable DNS server check" pref (used for testing)
private static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key";
+ // Integer used to let the calling application know that the we are ignoring auto mode switch.
+ private static final int ALREADY_IN_AUTO_SELECTION = 1;
+
/**
* Small container class used to hold information relevant to
* the carrier selection process. operatorNumeric can be ""
@@ -1175,6 +1178,11 @@
mCi.setNetworkSelectionModeAutomatic(msg);
} else {
Rlog.d(LOG_TAG, "setNetworkSelectionModeAutomatic - already auto, ignoring");
+ // let the calling application know that the we are ignoring automatic mode switch.
+ if (nsm.message != null) {
+ nsm.message.arg1 = ALREADY_IN_AUTO_SELECTION;
+ }
+
ar.userObj = nsm;
handleSetSelectNetwork(ar);
}
diff --git a/src/java/com/android/internal/telephony/TelephonyTester.java b/src/java/com/android/internal/telephony/TelephonyTester.java
index 3de356f..3608c20 100644
--- a/src/java/com/android/internal/telephony/TelephonyTester.java
+++ b/src/java/com/android/internal/telephony/TelephonyTester.java
@@ -20,11 +20,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Build;
-import android.preference.PreferenceManager;
import android.telephony.Rlog;
import android.telephony.ServiceState;
@@ -33,10 +31,10 @@
import com.android.ims.ImsConferenceState;
import com.android.ims.ImsExternalCallState;
import com.android.ims.ImsReasonInfo;
+import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
-import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
import com.android.internal.telephony.test.TestConferenceEventPackageParser;
import java.io.File;
@@ -83,6 +81,17 @@
private static final String ACTION_TEST_HANDOVER_FAIL =
"com.android.internal.telephony.TestHandoverFail";
+ /**
+ * Test-only intent used to trigger signalling of a
+ * {@link com.android.internal.telephony.gsm.SuppServiceNotification} to the {@link ImsPhone}.
+ * Use {@link #EXTRA_CODE} to specify the
+ * {@link com.android.internal.telephony.gsm.SuppServiceNotification#code}.
+ */
+ private static final String ACTION_TEST_SUPP_SRVC_NOTIFICATION =
+ "com.android.internal.telephony.TestSuppSrvcNotification";
+
+ private static final String EXTRA_CODE = "code";
+
private static List<ImsExternalCallState> mImsExternalCallStates = null;
private Phone mPhone;
@@ -111,6 +120,9 @@
} else if (action.equals(ACTION_TEST_HANDOVER_FAIL)) {
log("handle handover fail test intent");
handleHandoverFailedIntent();
+ } else if (action.equals(ACTION_TEST_SUPP_SRVC_NOTIFICATION)) {
+ log("handle supp service notification test intent");
+ sendTestSuppServiceNotification(intent);
} else {
if (DBG) log("onReceive: unknown action=" + action);
}
@@ -137,6 +149,7 @@
filter.addAction(ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
filter.addAction(ACTION_TEST_DIALOG_EVENT_PACKAGE);
filter.addAction(ACTION_TEST_HANDOVER_FAIL);
+ filter.addAction(ACTION_TEST_SUPP_SRVC_NOTIFICATION);
mImsExternalCallStates = new ArrayList<ImsExternalCallState>();
}
@@ -251,4 +264,18 @@
mImsExternalCallStates.add(state);
}
}
+
+ private void sendTestSuppServiceNotification(Intent intent) {
+ if (intent.hasExtra(EXTRA_CODE)) {
+ int code = intent.getIntExtra(EXTRA_CODE, -1);
+ ImsPhone imsPhone = (ImsPhone) mPhone;
+ if (imsPhone == null) {
+ return;
+ }
+ log("Test supp service notification:" + code);
+ SuppServiceNotification suppServiceNotification = new SuppServiceNotification();
+ suppServiceNotification.code = code;
+ imsPhone.notifySuppSvcNotification(suppServiceNotification);
+ }
+ }
}
diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java
index a242de4..6e4c899 100644
--- a/src/java/com/android/internal/telephony/cat/CatService.java
+++ b/src/java/com/android/internal/telephony/cat/CatService.java
@@ -881,8 +881,9 @@
// This sends an intent with CARD_ABSENT (0 - false) /CARD_PRESENT (1 - true).
intent.putExtra(AppInterface.CARD_STATUS, cardPresent);
intent.setComponent(AppInterface.getDefaultSTKApplication());
+ intent.putExtra("SLOT_ID", mSlotId);
CatLog.d(this, "Sending Card Status: "
- + cardState + " " + "cardPresent: " + cardPresent);
+ + cardState + " " + "cardPresent: " + cardPresent + "SLOT_ID: " + mSlotId);
mContext.sendBroadcast(intent, AppInterface.STK_PERMISSION);
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index 1f7c243..9b86712 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -705,7 +705,6 @@
@Override
public void setTTYMode(int ttyMode, Message onComplete) {
- super.setTTYMode(ttyMode, onComplete);
mCT.setTtyMode(ttyMode);
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 0898093..9b4aced 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -132,6 +132,7 @@
"UTLTE", "UTWiFi"};
private TelephonyMetrics mMetrics;
+ private boolean mCarrierConfigLoaded = false;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -216,6 +217,7 @@
log("onReceive : Updating mAllowEmergencyVideoCalls = " +
mAllowEmergencyVideoCalls);
}
+ mCarrierConfigLoaded = true;
} else if (TelecomManager.ACTION_CHANGE_DEFAULT_DIALER.equals(intent.getAction())) {
mDefaultDialerUid.set(getPackageUid(context, intent.getStringExtra(
TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME)));
@@ -302,6 +304,7 @@
private ImsCall mCallExpectedToResume = null;
private boolean mAllowEmergencyVideoCalls = false;
private boolean mIgnoreDataEnabledChangedForVideoCalls = false;
+ private boolean mIsViLteDataMetered = false;
/**
* Listeners to changes in the phone state. Intended for use by other interested IMS components
@@ -704,6 +707,8 @@
return NetworkStats.UID_ALL;
}
+ // Initialize to UID_ALL so at least it can be counted to overall data usage if
+ // the dialer's package uid is not available.
int uid = NetworkStats.UID_ALL;
try {
uid = context.getPackageManager().getPackageUid(pkg, 0);
@@ -756,6 +761,11 @@
multiEndpoint.setExternalCallStateListener(
mPhone.getExternalCallTracker().getExternalCallStateListener());
}
+
+ if (mCarrierConfigLoaded) {
+ ImsManager.updateImsServiceConfig(mPhone.getContext(),
+ mPhone.getPhoneId(), true);
+ }
}
private void stopListeningForCalls() {
@@ -978,6 +988,8 @@
CarrierConfigManager.KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL);
mIgnoreDataEnabledChangedForVideoCalls = carrierConfig.getBoolean(
CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS);
+ mIsViLteDataMetered = carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_VILTE_DATA_IS_METERED_BOOL);
mSupportPauseVideo = carrierConfig.getBoolean(
CarrierConfigManager.KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL);
@@ -2498,7 +2510,7 @@
ImsReasonInfo reasonInfo) {
if (DBG) {
log("onCallHandover :: srcAccessTech=" + srcAccessTech + ", targetAccessTech=" +
- targetAccessTech + ", reasonInfo=" + reasonInfo);
+ targetAccessTech + ", reasonInfo=" + reasonInfo);
}
// Only consider it a valid handover to WIFI if the source radio tech is known.
@@ -2510,19 +2522,28 @@
removeMessages(EVENT_CHECK_FOR_WIFI_HANDOVER);
}
- // Only consider it a handover from WIFI if the source and target radio tech is known.
- boolean isHandoverFromWifi = srcAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
- && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
- && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
- if (mNotifyHandoverVideoFromWifiToLTE && isHandoverFromWifi && imsCall.isVideoCall()) {
- log("onCallHandover :: notifying of WIFI to LTE handover.");
- ImsPhoneConnection conn = findConnection(imsCall);
- if (conn != null) {
- conn.onConnectionEvent(
- TelephonyManager.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE, null);
- } else {
- loge("onCallHandover :: failed to notify of handover; connection is null.");
+ ImsPhoneConnection conn = findConnection(imsCall);
+ if (conn != null) {
+ // Only consider it a handover from WIFI if the source and target radio tech is known.
+ boolean isHandoverFromWifi =
+ srcAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+ && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
+ && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+ if (isHandoverFromWifi && imsCall.isVideoCall()) {
+ if (mNotifyHandoverVideoFromWifiToLTE && mIsDataEnabled) {
+ log("onCallHandover :: notifying of WIFI to LTE handover.");
+ conn.onConnectionEvent(
+ TelephonyManager.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE, null);
+ }
+
+ if (!mIsDataEnabled && mIsViLteDataMetered) {
+ // Call was downgraded from WIFI to LTE and data is metered; downgrade the
+ // call now.
+ downgradeVideoCall(ImsReasonInfo.CODE_WIFI_LOST, conn);
+ }
}
+ } else {
+ loge("onCallHandover :: connection null.");
}
mMetrics.writeOnImsCallHandoverEvent(mPhone.getPhoneId(),
@@ -2959,6 +2980,17 @@
// a separate entry if uid is different from the previous snapshot.
NetworkStats vtDataUsageUidSnapshot = new NetworkStats(currentTime, 1);
vtDataUsageUidSnapshot.combineAllValues(mVtDataUsageUidSnapshot);
+
+ // The dialer uid might not be initialized correctly during boot up due to telecom service
+ // not ready or its default dialer cache not ready. So we double check again here to see if
+ // default dialer uid is really not available.
+ if (mDefaultDialerUid.get() == NetworkStats.UID_ALL) {
+ final TelecomManager telecomManager =
+ (TelecomManager) mPhone.getContext().getSystemService(Context.TELECOM_SERVICE);
+ mDefaultDialerUid.set(
+ getPackageUid(mPhone.getContext(), telecomManager.getDefaultDialerPackage()));
+ }
+
// Since the modem only reports the total vt data usage rather than rx/tx separately,
// the only thing we can do here is splitting the usage into half rx and half tx.
vtDataUsageUidSnapshot.combineValues(new NetworkStats.Entry(
@@ -3346,27 +3378,46 @@
ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId()).setDataEnabled(enabled);
mIsDataEnabled = enabled;
- if (mIgnoreDataEnabledChangedForVideoCalls) {
- log("Ignore data " + ((enabled) ? "enabled" : "disabled") + " due to carrier policy.");
+ if (!mIsViLteDataMetered) {
+ log("Ignore data " + ((enabled) ? "enabled" : "disabled") + " - carrier policy "
+ + "indicates that data is not metered for ViLTE calls.");
return;
}
- if (mIgnoreDataEnabledChangedForVideoCalls) {
- log("Ignore data " + ((enabled) ? "enabled" : "disabled") + " due to carrier policy.");
- return;
+ // Inform connections that data has been disabled to ensure we turn off video capability
+ // if this is an LTE call.
+ for (ImsPhoneConnection conn : mConnections) {
+ conn.handleDataEnabledChange(enabled);
}
+ int reasonCode;
+ if (reason == DataEnabledSettings.REASON_POLICY_DATA_ENABLED) {
+ reasonCode = ImsReasonInfo.CODE_DATA_LIMIT_REACHED;
+ } else if (reason == DataEnabledSettings.REASON_USER_DATA_ENABLED) {
+ reasonCode = ImsReasonInfo.CODE_DATA_DISABLED;
+ } else {
+ // Unexpected code, default to data disabled.
+ reasonCode = ImsReasonInfo.CODE_DATA_DISABLED;
+ }
+
+ // Potentially send connection events so the InCall UI knows that video calls are being
+ // downgraded due to data being enabled/disabled.
+ maybeNotifyDataDisabled(enabled, reasonCode);
+ // Handle video state changes required as a result of data being enabled/disabled.
+ handleDataEnabledChange(enabled, reasonCode);
+
+ // We do not want to update the ImsConfig for REASON_REGISTERED, since it can happen before
+ // the carrier config has loaded and will deregister IMS.
+ if (!mShouldUpdateImsConfigOnDisconnect
+ && reason != DataEnabledSettings.REASON_REGISTERED) {
+ // This will call into updateVideoCallFeatureValue and eventually all clients will be
+ // asynchronously notified that the availability of VT over LTE has changed.
+ ImsManager.updateImsServiceConfig(mPhone.getContext(), mPhone.getPhoneId(), true);
+ }
+ }
+
+ private void maybeNotifyDataDisabled(boolean enabled, int reasonCode) {
if (!enabled) {
- int reasonCode;
- if (reason == DataEnabledSettings.REASON_POLICY_DATA_ENABLED) {
- reasonCode = ImsReasonInfo.CODE_DATA_LIMIT_REACHED;
- } else if (reason == DataEnabledSettings.REASON_USER_DATA_ENABLED) {
- reasonCode = ImsReasonInfo.CODE_DATA_DISABLED;
- } else {
- // Unexpected code, default to data disabled.
- reasonCode = ImsReasonInfo.CODE_DATA_DISABLED;
- }
-
// If data is disabled while there are ongoing VT calls which are not taking place over
// wifi, then they should be disconnected to prevent the user from incurring further
// data charges.
@@ -3386,27 +3437,38 @@
conn.onConnectionEvent(
TelephonyManager.EVENT_DOWNGRADE_DATA_LIMIT_REACHED, null);
}
- modifyVideoCall(imsCall, VideoProfile.STATE_AUDIO_ONLY);
- } else if (mSupportPauseVideo) {
- // The carrier supports video pause signalling, so pause the video.
- mShouldUpdateImsConfigOnDisconnect = true;
- conn.pauseVideo(VideoPauseTracker.SOURCE_DATA_ENABLED);
- } else {
- // At this point the only choice we have is to terminate the call.
- try {
- imsCall.terminate(ImsReasonInfo.CODE_USER_TERMINATED, reasonCode);
- } catch (ImsException ie) {
- loge("Couldn't terminate call " + imsCall);
- }
}
}
}
+ }
+ }
+
+ /**
+ * Handles changes to the enabled state of mobile data.
+ * When data is disabled, handles auto-downgrade of video calls over LTE.
+ * When data is enabled, handled resuming of video calls paused when data was disabled.
+ * @param enabled {@code true} if mobile data is enabled, {@code false} if mobile data is
+ * disabled.
+ * @param reasonCode The {@link ImsReasonInfo} code for the data enabled state change.
+ */
+ private void handleDataEnabledChange(boolean enabled, int reasonCode) {
+ if (!enabled) {
+ // If data is disabled while there are ongoing VT calls which are not taking place over
+ // wifi, then they should be disconnected to prevent the user from incurring further
+ // data charges.
+ for (ImsPhoneConnection conn : mConnections) {
+ ImsCall imsCall = conn.getImsCall();
+ if (imsCall != null && imsCall.isVideoCall() && !imsCall.isWifiCall()) {
+ log("handleDataEnabledChange - downgrading " + conn);
+ downgradeVideoCall(reasonCode, conn);
+ }
+ }
} else if (mSupportPauseVideo) {
// Data was re-enabled, so un-pause previously paused video calls.
for (ImsPhoneConnection conn : mConnections) {
// If video is paused, check to see if there are any pending pauses due to enabled
// state of data changing.
- log("onDataEnabledChanged - resuming " + conn);
+ log("handleDataEnabledChange - resuming " + conn);
if (VideoProfile.isPaused(conn.getVideoState()) &&
conn.wasVideoPausedFromSource(VideoPauseTracker.SOURCE_DATA_ENABLED)) {
// The data enabled state was a cause of a pending pause, so potentially
@@ -3416,15 +3478,40 @@
}
mShouldUpdateImsConfigOnDisconnect = false;
}
+ }
+ /**
+ * Handles downgrading a video call. The behavior depends on carrier capabilities; we will
+ * attempt to take one of the following actions (in order of precedence):
+ * 1. If supported by the carrier, the call will be downgraded to an audio-only call.
+ * 2. If the carrier supports video pause signalling, the video will be paused.
+ * 3. The call will be disconnected.
+ * @param reasonCode The {@link ImsReasonInfo} reason code for the downgrade.
+ * @param conn The {@link ImsPhoneConnection} to downgrade.
+ */
+ private void downgradeVideoCall(int reasonCode, ImsPhoneConnection conn) {
+ ImsCall imsCall = conn.getImsCall();
+ if (imsCall != null) {
+ if (conn.hasCapabilities(
+ Connection.Capability.SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL |
+ Connection.Capability.SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE)) {
- // We do not want to update the ImsConfig for REASON_REGISTERED, since it can happen before
- // the carrier config has loaded and will deregister IMS.
- if (!mShouldUpdateImsConfigOnDisconnect
- && reason != DataEnabledSettings.REASON_REGISTERED) {
- // This will call into updateVideoCallFeatureValue and eventually all clients will be
- // asynchronously notified that the availability of VT over LTE has changed.
- ImsManager.updateImsServiceConfig(mPhone.getContext(), mPhone.getPhoneId(), true);
+ // If the carrier supports downgrading to voice, then we can simply issue a
+ // downgrade to voice instead of terminating the call.
+ modifyVideoCall(imsCall, VideoProfile.STATE_AUDIO_ONLY);
+ } else if (mSupportPauseVideo && reasonCode != ImsReasonInfo.CODE_WIFI_LOST) {
+ // The carrier supports video pause signalling, so pause the video if we didn't just
+ // lose wifi; in that case just disconnect.
+ mShouldUpdateImsConfigOnDisconnect = true;
+ conn.pauseVideo(VideoPauseTracker.SOURCE_DATA_ENABLED);
+ } else {
+ // At this point the only choice we have is to terminate the call.
+ try {
+ imsCall.terminate(ImsReasonInfo.CODE_USER_TERMINATED, reasonCode);
+ } catch (ImsException ie) {
+ loge("Couldn't terminate call " + imsCall);
+ }
+ }
}
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
index b39a6fb..0ad81d2 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
@@ -107,6 +107,14 @@
private ImsRttTextHandler mRttTextHandler;
private android.telecom.Connection.RttTextStream mRttTextStream;
+ /**
+ * Used as an override to determine whether video is locally available for this call.
+ * This allows video availability to be overridden in the case that the modem says video is
+ * currently available, but mobile data is off and the carrier is metering data for video
+ * calls.
+ */
+ private boolean mIsVideoEnabled = true;
+
//***** Event Constants
private static final int EVENT_DTMF_DONE = 1;
private static final int EVENT_PAUSE_DONE = 2;
@@ -242,11 +250,15 @@
return (a == null) ? (b == null) : (b != null && a.startsWith (b));
}
- private static int applyLocalCallCapabilities(ImsCallProfile localProfile, int capabilities) {
- Rlog.w(LOG_TAG, "applyLocalCallCapabilities - localProfile = "+localProfile);
+ private int applyLocalCallCapabilities(ImsCallProfile localProfile, int capabilities) {
+ Rlog.i(LOG_TAG, "applyLocalCallCapabilities - localProfile = " + localProfile);
capabilities = removeCapability(capabilities,
Connection.Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
+ if (!mIsVideoEnabled) {
+ Rlog.i(LOG_TAG, "applyLocalCallCapabilities - disabling video (overidden)");
+ return capabilities;
+ }
switch (localProfile.mCallType) {
case ImsCallProfile.CALL_TYPE_VT:
// Fall-through
@@ -1185,6 +1197,7 @@
Rlog.i(LOG_TAG, "ImsPhoneConnection: changeToPausedState - setting paused bit; "
+ "newVideoState=" + VideoProfile.videoStateToString(newVideoState));
updateVideoState(newVideoState);
+ mShouldIgnoreVideoStateChanges = true;
}
public void changeToUnPausedState() {
@@ -1192,5 +1205,17 @@
Rlog.i(LOG_TAG, "ImsPhoneConnection: changeToUnPausedState - unsetting paused bit; "
+ "newVideoState=" + VideoProfile.videoStateToString(newVideoState));
updateVideoState(newVideoState);
+ mShouldIgnoreVideoStateChanges = false;
+ }
+
+ public void handleDataEnabledChange(boolean isDataEnabled) {
+ mIsVideoEnabled = isDataEnabled;
+ Rlog.i(LOG_TAG, "handleDataEnabledChange: isDataEnabled=" + isDataEnabled
+ + "; updating local video availability.");
+ updateMediaCapabilities(getImsCall());
+ if (mImsVideoCallProviderWrapper != null) {
+ mImsVideoCallProviderWrapper.setIsVideoEnabled(
+ hasCapabilities(Connection.Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
+ }
}
}
diff --git a/src/java/com/android/internal/telephony/uicc/AdnRecord.java b/src/java/com/android/internal/telephony/uicc/AdnRecord.java
index 203236c..4414caf 100644
--- a/src/java/com/android/internal/telephony/uicc/AdnRecord.java
+++ b/src/java/com/android/internal/telephony/uicc/AdnRecord.java
@@ -19,8 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
import android.telephony.Rlog;
+import android.text.TextUtils;
import com.android.internal.telephony.GsmAlphabet;
@@ -248,7 +248,8 @@
Rlog.w(LOG_TAG, "[buildAdnString] Max length of tag is " + footerOffset);
return null;
} else {
- bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(mNumber);
+ bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(
+ mNumber, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
System.arraycopy(bcdNumber, 0, adnString,
footerOffset + ADN_TON_AND_NPI, bcdNumber.length);
@@ -289,7 +290,10 @@
}
mNumber += PhoneNumberUtils.calledPartyBCDFragmentToString(
- extRecord, 2, 0xff & extRecord[1]);
+ extRecord,
+ 2,
+ 0xff & extRecord[1],
+ PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
// We don't support ext record chaining.
@@ -327,7 +331,10 @@
// the ME (see note 2)."
mNumber = PhoneNumberUtils.calledPartyBCDToString(
- record, footerOffset + 1, numberLength);
+ record,
+ footerOffset + 1,
+ numberLength,
+ PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
mExtRecord = 0xff & record[record.length - 1];
diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
index 724b478..dad1ee2 100755
--- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
@@ -563,7 +563,8 @@
// Spec reference for EF_CFIS contents, TS 51.011 section 10.3.46.
if (enable && !TextUtils.isEmpty(dialNumber)) {
logv("EF_CFIS: updating cf number, " + Rlog.pii(LOG_TAG, dialNumber));
- byte[] bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(dialNumber);
+ byte[] bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(
+ dialNumber, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
System.arraycopy(bcdNumber, 0, mEfCfis, CFIS_TON_NPI_OFFSET, bcdNumber.length);
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
index 93d54d0..68b72c8 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
@@ -56,7 +56,10 @@
private static final String LOG_TAG = "UiccCarrierPrivilegeRules";
private static final boolean DBG = false;
- private static final String AID = "A00000015141434C00";
+ private static final String ARAM_AID = "A00000015141434C00";
+ private static final String ARAD_AID = "A00000015144414300";
+ private static final int ARAM = 1;
+ private static final int ARAD = 0;
private static final int CLA = 0x80;
private static final int COMMAND = 0xCA;
private static final int P1 = 0xFF;
@@ -210,18 +213,21 @@
private String mStatusMessage; // Only used for debugging.
private int mChannelId; // Channel Id for communicating with UICC.
private int mRetryCount; // Number of retries for open logical channel.
+ private boolean mCheckedRules = false; // Flag that used to mark whether get rules from ARA-D.
+ private int mAIDInUse; // Message component to identify which AID is currently in-use.
private final Runnable mRetryRunnable = new Runnable() {
@Override
public void run() {
- openChannel();
+ openChannel(mAIDInUse);
}
};
- private void openChannel() {
+ private void openChannel(int aidId) {
// Send open logical channel request.
+ String aid = (aidId == ARAD) ? ARAD_AID : ARAM_AID;
int p2 = 0x00;
- mUiccCard.iccOpenLogicalChannel(AID, p2, /* supported p2 value */
- obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, null));
+ mUiccCard.iccOpenLogicalChannel(aid, p2, /* supported p2 value */
+ obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, 0, aidId, null));
}
public UiccCarrierPrivilegeRules(UiccCard uiccCard, Message loadedCallback) {
@@ -233,7 +239,9 @@
mRules = "";
mAccessRules = new ArrayList<AccessRule>();
- openChannel();
+ // Open logical channel with ARA_D.
+ mAIDInUse = ARAD;
+ openChannel(mAIDInUse);
}
/**
@@ -412,6 +420,7 @@
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
+ mAIDInUse = msg.arg2; // 0 means ARA-D and 1 means ARA-M.
switch (msg.what) {
@@ -421,23 +430,34 @@
if (ar.exception == null && ar.result != null) {
mChannelId = ((int[]) ar.result)[0];
mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2, P3,
- DATA, obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE,
- mChannelId));
+ DATA, obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, mChannelId,
+ mAIDInUse));
} else {
// MISSING_RESOURCE could be due to logical channels temporarily unavailable,
// so we retry up to MAX_RETRY times, with an interval of RETRY_INTERVAL_MS.
if (ar.exception instanceof CommandException && mRetryCount < MAX_RETRY
&& ((CommandException) (ar.exception)).getCommandError()
- == CommandException.Error.MISSING_RESOURCE) {
+ == CommandException.Error.MISSING_RESOURCE) {
mRetryCount++;
removeCallbacks(mRetryRunnable);
postDelayed(mRetryRunnable, RETRY_INTERVAL_MS);
} else {
- // if rules cannot be read from ARA applet,
- // fallback to PKCS15-based ARF.
- log("No ARA, try ARF next.");
- mUiccPkcs15 = new UiccPkcs15(mUiccCard,
- obtainMessage(EVENT_PKCS15_READ_DONE));
+ if (mAIDInUse == ARAD) {
+ // Open logical channel with ARA_M.
+ mRules = "";
+ openChannel(1);
+ }
+ if (mAIDInUse == ARAM) {
+ if (mCheckedRules) {
+ updateState(STATE_LOADED, "Success!");
+ } else {
+ // if rules cannot be read from both ARA_D and ARA_M applet,
+ // fallback to PKCS15-based ARF.
+ log("No ARA, try ARF next.");
+ mUiccPkcs15 = new UiccPkcs15(mUiccCard,
+ obtainMessage(EVENT_PKCS15_READ_DONE));
+ }
+ }
}
}
break;
@@ -453,34 +473,49 @@
mRules += IccUtils.bytesToHexString(response.payload)
.toUpperCase(Locale.US);
if (isDataComplete()) {
- mAccessRules = parseRules(mRules);
- updateState(STATE_LOADED, "Success!");
+ mAccessRules.addAll(parseRules(mRules));
+ if (mAIDInUse == ARAD) {
+ mCheckedRules = true;
+ } else {
+ updateState(STATE_LOADED, "Success!");
+ }
} else {
mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND,
P1, P2_EXTENDED_DATA, P3, DATA,
obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE,
- mChannelId));
+ mChannelId, mAIDInUse));
break;
}
} catch (IllegalArgumentException | IndexOutOfBoundsException ex) {
- updateState(STATE_ERROR, "Error parsing rules: " + ex);
+ if (mAIDInUse == ARAM) {
+ updateState(STATE_ERROR, "Error parsing rules: " + ex);
+ }
}
} else {
- String errorMsg = "Invalid response: payload=" + response.payload
- + " sw1=" + response.sw1 + " sw2=" + response.sw2;
- updateState(STATE_ERROR, errorMsg);
+ if (mAIDInUse == ARAM) {
+ String errorMsg = "Invalid response: payload=" + response.payload
+ + " sw1=" + response.sw1 + " sw2=" + response.sw2;
+ updateState(STATE_ERROR, errorMsg);
+ }
}
} else {
- updateState(STATE_ERROR, "Error reading value from SIM.");
+ if (mAIDInUse == ARAM) {
+ updateState(STATE_ERROR, "Error reading value from SIM.");
+ }
}
mUiccCard.iccCloseLogicalChannel(mChannelId, obtainMessage(
- EVENT_CLOSE_LOGICAL_CHANNEL_DONE));
+ EVENT_CLOSE_LOGICAL_CHANNEL_DONE, 0, mAIDInUse));
mChannelId = -1;
break;
case EVENT_CLOSE_LOGICAL_CHANNEL_DONE:
log("EVENT_CLOSE_LOGICAL_CHANNEL_DONE");
+ if (mAIDInUse == ARAD) {
+ // Close logical channel with ARA_D and then open logical channel with ARA_M.
+ mRules = "";
+ openChannel(1);
+ }
break;
case EVENT_PKCS15_READ_DONE:
@@ -513,7 +548,7 @@
String lengthBytes = allRules.parseLength(mRules);
log("isDataComplete lengthBytes: " + lengthBytes);
if (mRules.length() == TAG_ALL_REF_AR_DO.length() + lengthBytes.length() +
- allRules.length) {
+ allRules.length) {
log("isDataComplete yes");
return true;
} else {
@@ -543,7 +578,7 @@
if (accessRule != null) {
accessRules.add(accessRule);
} else {
- Rlog.e(LOG_TAG, "Skip unrecognized rule." + refArDo.value);
+ Rlog.e(LOG_TAG, "Skip unrecognized rule." + refArDo.value);
}
}
return accessRules;
@@ -678,15 +713,15 @@
* Converts state into human readable format.
*/
private String getStateString(int state) {
- switch (state) {
- case STATE_LOADING:
- return "STATE_LOADING";
- case STATE_LOADED:
- return "STATE_LOADED";
- case STATE_ERROR:
- return "STATE_ERROR";
- default:
- return "UNKNOWN";
- }
+ switch (state) {
+ case STATE_LOADING:
+ return "STATE_LOADING";
+ case STATE_LOADED:
+ return "STATE_LOADED";
+ case STATE_ERROR:
+ return "STATE_ERROR";
+ default:
+ return "UNKNOWN";
+ }
}
-}
+}
\ No newline at end of file
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsCallProfileTest.java b/tests/telephonytests/src/android/telephony/ims/ImsCallProfileTest.java
new file mode 100644
index 0000000..bc8d4e1
--- /dev/null
+++ b/tests/telephonytests/src/android/telephony/ims/ImsCallProfileTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+// Note: Package name is intentionally wrong for this test; the internal junk class is used to test
+// that parcelables of types other than android.* are stripped out.
+package com.android.telephony.ims;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.test.runner.AndroidJUnit4;
+import android.telecom.DisconnectCause;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.ims.ImsCallProfile;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the {@link com.android.ims.ImsCallProfile} class.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ImsCallProfileTest {
+ // A test-only parcelable class which is not in the android.* namespace.
+ private static class JunkParcelable implements Parcelable {
+ private int mTest;
+
+ JunkParcelable() {
+ }
+
+ protected JunkParcelable(Parcel in) {
+ mTest = in.readInt();
+ }
+
+ public static final Creator<JunkParcelable> CREATOR = new Creator<JunkParcelable>() {
+ @Override
+ public JunkParcelable createFromParcel(Parcel in) {
+ return new JunkParcelable(in);
+ }
+
+ @Override
+ public JunkParcelable[] newArray(int size) {
+ return new JunkParcelable[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mTest);
+ }
+ }
+
+ /**
+ * Ensures that the {@link ImsCallProfile} will discard invalid extras when it is parceled.
+ */
+ @Test
+ @SmallTest
+ public void testExtrasCleanup() {
+ ImsCallProfile srcParcel = new ImsCallProfile();
+ // Put in a private parcelable type.
+ srcParcel.mCallExtras.putParcelable("JUNK", new JunkParcelable());
+ // Put in an api defined parcelable type.
+ srcParcel.mCallExtras.putParcelable("NOTJUNK", new DisconnectCause(DisconnectCause.BUSY));
+ // Put in some valid things.
+ srcParcel.mCallExtras.putInt("INT", 1);
+ srcParcel.mCallExtras.putString("STRING", "hello");
+
+ // Parcel it.
+ Parcel parcel = Parcel.obtain();
+ srcParcel.writeToParcel(parcel, 0);
+ byte[] parcelBytes = parcel.marshall();
+ parcel.recycle();
+
+ // Unparcel it.
+ parcel = Parcel.obtain();
+ parcel.unmarshall(parcelBytes, 0, parcelBytes.length);
+ parcel.setDataPosition(0);
+ ImsCallProfile unparceledProfile = ImsCallProfile.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertNotNull(unparceledProfile.mCallExtras);
+ assertEquals(3, unparceledProfile.mCallExtras.size());
+ assertEquals(1, unparceledProfile.getCallExtraInt("INT"));
+ assertEquals("hello", unparceledProfile.getCallExtra("STRING"));
+ assertFalse(unparceledProfile.mCallExtras.containsKey("JUNK"));
+
+ DisconnectCause parceledCause = unparceledProfile.mCallExtras.getParcelable("NOTJUNK");
+ assertEquals(DisconnectCause.BUSY, parceledCause.getCode());
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
index f2e5da1..06cd54f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
@@ -41,6 +41,10 @@
assertEquals("+14155551212", sms.getServiceCenterAddress());
assertEquals("+16505551111", sms.getOriginatingAddress());
assertEquals("(Subject)Test", sms.getMessageBody());
+
+ pdu = "07914151551512F20409E1BADCBE5AF100006060605130308A04D4F29C0E";
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+ assertEquals("*#abc#*51", sms.getOriginatingAddress());
}
@SmallTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index f4caf48..faeabd5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -201,6 +201,20 @@
@SmallTest
@Test
+ public void testNonIntegerAddress() {
+ byte[] b = new byte[6];
+ b[0] = (byte) 0x81; b[1] = (byte) 0xba; b[2] = (byte) 0xdc; b[3] = (byte) 0xbe;
+ b[4] = (byte) 0x5a; b[5] = (byte) 0xf1;
+ assertEquals("*#abc#*51",
+ PhoneNumberUtils.calledPartyBCDToString(
+ b, 0, 6, PhoneNumberUtils.BCD_EXTENDED_TYPE_CALLED_PARTY));
+ assertEquals("*#,N;#*51",
+ PhoneNumberUtils.calledPartyBCDToString(
+ b, 0, 6, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN));
+ }
+
+ @SmallTest
+ @Test
public void testExtractNetworkPortionAlt() throws Exception {
assertEquals(
"+17005554141",
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
index 43763ec..82a3466 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
@@ -651,6 +651,11 @@
}
@Override
+ public boolean isAlwaysOnVpnPackageSupported(int userId, String packageName) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdownEnabled) {
throw new RuntimeException("not implemented");
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
index 78944eb..a7c3c48 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
@@ -208,9 +208,9 @@
waitForMs(50);
assertTrue(mUicccard.areCarrierPriviligeRulesLoaded());
- verify(mSimulatedCommandsVerifier, times(1)).iccOpenLogicalChannel(isA(String.class),
+ verify(mSimulatedCommandsVerifier, times(2)).iccOpenLogicalChannel(isA(String.class),
anyInt(), isA(Message.class));
- verify(mSimulatedCommandsVerifier, times(1)).iccTransmitApduLogicalChannel(
+ verify(mSimulatedCommandsVerifier, times(2)).iccTransmitApduLogicalChannel(
eq(mChannelId), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyString(),
isA(Message.class)
);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
index e6ca407..8bb5d8c 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.doAnswer;
@@ -124,6 +125,14 @@
}).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
anyInt(), anyInt(), anyString(), any(Message.class));
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
setReady(false);
@@ -133,7 +142,7 @@
@Test
@SmallTest
- public void testHandleMessage_Normal() {
+ public void testParseRule_Normal() {
/**
* FF40 45
* E2 43
@@ -150,7 +159,7 @@
testHelper(hexString);
assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
- assertEquals(1, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals(2, mUiccCarrierPrivilegeRules.getPackageNames().size());
assertEquals("com.google.android.apps.myapp",
mUiccCarrierPrivilegeRules.getPackageNames().get(0));
Signature signature = new Signature("abcd92cbb156b280fa4e1429a6eceeb6e5c1bfe4");
@@ -160,7 +169,7 @@
@Test
@SmallTest
- public void testHandleMessage_With4FD0D1() {
+ public void testParseRule_With4FD0D1() {
/**
* FF40 34
* E2 32
@@ -183,7 +192,7 @@
@Test
@SmallTest
- public void testHandleMessage_With4FD0() {
+ public void testParseRule_With4FD0() {
/**
* FF40 31
* E2 2F
@@ -205,7 +214,7 @@
@Test
@SmallTest
- public void testHandleMessage_TwoMessages() {
+ public void testParseRule_TwoMessages() {
/**
* FF40 68
* E2 39
@@ -232,7 +241,7 @@
testHelper(hexString);
assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
- assertEquals(2, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals(4, mUiccCarrierPrivilegeRules.getPackageNames().size());
assertEquals("com.google.android.apps.myapp",
mUiccCarrierPrivilegeRules.getPackageNames().get(0));
Signature signature1 = new Signature("b61b");
@@ -248,7 +257,7 @@
@Test
@SmallTest
- public void testHandleMessage_InvalidRulesWith4F00() {
+ public void testParseRule_InvalidRulesWith4F00() {
/**
* FF40 24
* E2 22
@@ -270,7 +279,7 @@
@Test
@SmallTest
- public void testHandleMessage_InvalidRulesWithoutDB() {
+ public void testParseRule_InvalidRulesWithoutDB() {
/**
* FF40 2A
* E2 28
@@ -289,4 +298,323 @@
assertTrue(!mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
assertEquals(0, mUiccCarrierPrivilegeRules.getPackageNames().size());
}
+
+ private static final String ARAM = "A00000015141434C00";
+ private static final String ARAD = "A00000015144414300";
+ private static final String PKCS15_AID = "A000000063504B43532D3135";
+
+ @Test
+ @SmallTest
+ public void testAID_OnlyARAM() {
+ final String hexString =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001";
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String aid = (String) invocation.getArguments()[0];
+ Message message = (Message) invocation.getArguments()[2];
+ if (aid.equals(ARAM)) {
+ AsyncResult ar = new AsyncResult(null, new int[]{0}, null);
+ message.obj = ar;
+ message.arg2 = 1;
+ message.sendToTarget();
+ } else {
+ AsyncResult ar = new AsyncResult(null, null, null);
+ message.obj = ar;
+ message.sendToTarget();
+ }
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ anyInt(), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(1, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0));
+ Signature signature = new Signature("abcd92cbb156b280fa4e1429a6eceeb6e5c1bfe4");
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+ }
+
+ @Test
+ @SmallTest
+ public void testAID_OnlyARAD() {
+ final String hexString =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001";
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String aid = (String) invocation.getArguments()[0];
+ Message message = (Message) invocation.getArguments()[2];
+ if (aid.equals(ARAD)) {
+ AsyncResult ar = new AsyncResult(null, new int[]{0}, null);
+ message.obj = ar;
+ message.arg2 = 0;
+ message.sendToTarget();
+ } else {
+ AsyncResult ar = new AsyncResult(null, null, null);
+ message.obj = ar;
+ message.arg2 = 1;
+ message.sendToTarget();
+ }
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ anyInt(), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(1, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0));
+ Signature signature = new Signature("abcd92cbb156b280fa4e1429a6eceeb6e5c1bfe4");
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+ }
+
+ @Test
+ @SmallTest
+ public void testAID_BothARAMandARAD() {
+ final String hexString =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001";
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String aid = (String) invocation.getArguments()[0];
+ Message message = (Message) invocation.getArguments()[2];
+ AsyncResult ar = new AsyncResult(null, new int[]{0}, null);
+ message.obj = ar;
+ if (aid.equals(ARAD)) {
+ message.arg2 = 0;
+ } else {
+ message.arg2 = 1;
+ }
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ anyInt(), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+
+ Signature signature = new Signature("abcd92cbb156b280fa4e1429a6eceeb6e5c1bfe4");
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(2, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0));
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(1));
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(1)));
+ }
+
+ @Test
+ @SmallTest
+ public void testAID_NeitherARAMorARAD() {
+ final String hexString =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001";
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String aid = (String) invocation.getArguments()[0];
+ Message message = (Message) invocation.getArguments()[2];
+ AsyncResult ar = new AsyncResult(null, null, null);
+ if (aid.equals(ARAM)) {
+ message.arg2 = 1;
+ } else if (aid.equals(ARAD)) {
+ message.arg2 = 0;
+ } else {
+ // PKCS15
+ ar = new AsyncResult(null, null, new Throwable());
+ }
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+
+ assertTrue(!mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ }
+
+ private static final int P2 = 0x40;
+ private static final int P2_EXTENDED_DATA = 0x60;
+ @Test
+ @SmallTest
+ public void testAID_RetransmitLogicalChannel() {
+ final String hexString1 =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30A";
+
+ final String hexString2 =
+ "DB080000000000000001";
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String aid = (String) invocation.getArguments()[0];
+ Message message = (Message) invocation.getArguments()[2];
+ if (aid.equals(ARAD)) {
+ AsyncResult ar = new AsyncResult(null, new int[]{0}, null);
+ message.obj = ar;
+ message.arg2 = 0;
+ message.sendToTarget();
+ } else {
+ AsyncResult ar = new AsyncResult(null, null, null);
+ message.obj = ar;
+ message.arg2 = 1;
+ message.sendToTarget();
+ }
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00,
+ IccUtils.hexStringToBytes(hexString1));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ eq(P2), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00,
+ IccUtils.hexStringToBytes(hexString2));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ eq(P2_EXTENDED_DATA), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(1, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0));
+ Signature signature = new Signature("abcd92cbb156b280fa4e1429a6eceeb6e5c1bfe4");
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+ }
}