diff options
author | Simon Shields <simon@lineageos.org> | 2017-04-04 19:05:28 +1000 |
---|---|---|
committer | Dan Pasanen <dan.pasanen@gmail.com> | 2017-04-04 09:36:37 -0500 |
commit | a17ff1d7e2ac871e17a9f77aff0a1930d1bbf373 (patch) | |
tree | 3ea819fa680c6054ae126b833db3ad1449d39dc9 | |
parent | c31cf84871831c1881d9525f48f0bc52f61fee11 (diff) | |
parent | 37392ec092a43a2f66f192b54895769d8f6ce09d (diff) | |
download | android_frameworks_opt_telephony-a17ff1d7e2ac871e17a9f77aff0a1930d1bbf373.tar.gz android_frameworks_opt_telephony-a17ff1d7e2ac871e17a9f77aff0a1930d1bbf373.tar.bz2 android_frameworks_opt_telephony-a17ff1d7e2ac871e17a9f77aff0a1930d1bbf373.zip |
Merge tag 'android-7.1.2_r2' into cm-14.1staging/cm-14.1_android-7.1.2_r2
Android 7.1.2 Release 2 (N2G47E)
Change-Id: Ic4e01f328b050179df40b25940ea48d8f63c1b03
41 files changed, 1629 insertions, 369 deletions
diff --git a/proto/telephony.proto b/proto/telephony.proto index 066375953..70d210bb3 100644 --- a/proto/telephony.proto +++ b/proto/telephony.proto @@ -1018,6 +1018,13 @@ message TelephonyCallSession { optional CallState state = 2; optional Type type = 3; + + // For possible values for a call end reason check + // frameworks/base/telephony/java/android/telephony/DisconnectCause.java + optional int32 call_end_reason = 4; + + // This field is true for Conference Calls + optional bool is_multiparty = 5; } // Single Radio Voice Call Continuity(SRVCC) progress state diff --git a/src/java/com/android/internal/telephony/CallFailCause.java b/src/java/com/android/internal/telephony/CallFailCause.java index 4197bd248..dd3938206 100644 --- a/src/java/com/android/internal/telephony/CallFailCause.java +++ b/src/java/com/android/internal/telephony/CallFailCause.java @@ -31,6 +31,7 @@ public interface CallFailCause { // Unassigned/Unobtainable number int UNOBTAINABLE_NUMBER = 1; + int OPERATOR_DETERMINED_BARRING = 8; int NORMAL_CLEARING = 16; // Busy Tone int USER_BUSY = 17; @@ -61,7 +62,6 @@ public interface CallFailCause { // Supplementary int NO_ROUTE_TO_DESTINAON = 3; int CHANNEL_UNACCEPTABLE = 6; - int OPERATOR_DETERMINED_BARRING = 8; int CALL_FAIL_NO_USER_RESPONDING = 18; int CALL_FAIL_NO_ANSWER_FROM_USER = 19; int CALL_REJECTED = 21; diff --git a/src/java/com/android/internal/telephony/CallStateException.java b/src/java/com/android/internal/telephony/CallStateException.java index 57cbeb852..cac701a70 100644 --- a/src/java/com/android/internal/telephony/CallStateException.java +++ b/src/java/com/android/internal/telephony/CallStateException.java @@ -27,6 +27,7 @@ public class CallStateException extends Exception public static final int ERROR_INVALID = -1; public static final int ERROR_DISCONNECTED = 1; + public static final int ERROR_POWER_OFF = 2; public CallStateException() diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java new file mode 100644 index 000000000..735bfe2ea --- /dev/null +++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony; + +import android.app.PendingIntent; +import android.app.Notification; +import android.app.NotificationManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.Message; +import android.os.PersistableBundle; +import android.provider.Settings; +import android.telephony.CarrierConfigManager; +import android.telephony.Rlog; + +/** + * This contains Carrier specific logic based on the states/events + * managed in ServiceStateTracker. + * {@hide} + */ +public class CarrierServiceStateTracker extends Handler { + private static final String LOG_TAG = "CSST"; + protected static final int CARRIER_EVENT_BASE = 100; + protected static final int CARRIER_EVENT_VOICE_REGISTRATION = CARRIER_EVENT_BASE + 1; + protected static final int CARRIER_EVENT_VOICE_DEREGISTRATION = CARRIER_EVENT_BASE + 2; + protected static final int CARRIER_EVENT_DATA_REGISTRATION = CARRIER_EVENT_BASE + 3; + protected static final int CARRIER_EVENT_DATA_DEREGISTRATION = CARRIER_EVENT_BASE + 4; + private static final int SHOW_NOTIFICATION = 200; + private static final int NOTIFICATION_ID = 1000; + private static final int UNINITIALIZED_DELAY_VALUE = -1; + private int mDelay = UNINITIALIZED_DELAY_VALUE; + private Phone mPhone; + private boolean mIsPhoneRegistered = false; + private ServiceStateTracker mSST; + + public CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst) { + this.mPhone = phone; + this.mSST = sst; + phone.getContext().registerReceiver(mBroadcastReceiver, new IntentFilter( + CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case CARRIER_EVENT_VOICE_REGISTRATION: + case CARRIER_EVENT_DATA_REGISTRATION: + mIsPhoneRegistered = true; + handleConfigChanges(); + break; + case CARRIER_EVENT_VOICE_DEREGISTRATION: + case CARRIER_EVENT_DATA_DEREGISTRATION: + if (isGlobalModeOrRadioOffOrAirplaneMode()) { + break; + } + mIsPhoneRegistered = false; + handleConfigChanges(); + break; + case SHOW_NOTIFICATION: + sendNotification(); + break; + } + } + + /** + * Returns true if the preferred network is set to 'Global' or the radio is off or in + * Airplane Mode else returns false. + */ + private boolean isGlobalModeOrRadioOffOrAirplaneMode() { + Context context = mPhone.getContext(); + int preferredNetworkSetting = -1; + int airplaneMode = -1; + int subId = mPhone.getSubId(); + try { + preferredNetworkSetting = + android.provider.Settings.Global.getInt(context.getContentResolver(), + android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, + Phone.PREFERRED_NT_MODE); + airplaneMode = Settings.Global.getInt(context.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0); + } catch (Exception e) { + Rlog.e(LOG_TAG, "Unable to get PREFERRED_NETWORK_MODE."); + return true; + } + return ((preferredNetworkSetting == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA) || + !mSST.isRadioOn() || (airplaneMode != 0)); + } + + /** + * Contains logic to decide when to create/cancel notifications. + */ + private void handleConfigChanges() { + + if (mDelay == UNINITIALIZED_DELAY_VALUE) { + cancelNotification(); + return; + } + // send a notification if the device is registerd to a network. + if (mIsPhoneRegistered) { + cancelNotification(); + Rlog.i(LOG_TAG, "canceling all notifications. "); + } else { + Message notificationMsg; + notificationMsg = obtainMessage(SHOW_NOTIFICATION, null); + Rlog.i(LOG_TAG, "starting timer for notifications. "); + sendMessageDelayed(notificationMsg, mDelay); + } + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + CarrierConfigManager carrierConfigManager = (CarrierConfigManager) + context.getSystemService(Context.CARRIER_CONFIG_SERVICE); + PersistableBundle b = carrierConfigManager.getConfig(); + mDelay = b.getInt(CarrierConfigManager.KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT); + Rlog.i(LOG_TAG, "reading time to delay notification: " + mDelay); + handleConfigChanges(); + } + }; + + /** + * Post a notification to the NotificationManager for changing network type. + */ + private void sendNotification() { + Context context = mPhone.getContext(); + + Rlog.i(LOG_TAG, "w/values: " + "," + mIsPhoneRegistered + "," + mDelay + + "," + isGlobalModeOrRadioOffOrAirplaneMode() + "," + mSST.isRadioOn()); + + // exit if the network preference is set to Global or if the phone is registered. + if (isGlobalModeOrRadioOffOrAirplaneMode() || mIsPhoneRegistered) { + return; + } + + NotificationManager notificationManager = (NotificationManager) + context.getSystemService(Context.NOTIFICATION_SERVICE); + + + Intent notificationIntent = new Intent(Settings.ACTION_DATA_ROAMING_SETTINGS); + PendingIntent settingsIntent = PendingIntent.getActivity(context, 0, notificationIntent, + PendingIntent.FLAG_ONE_SHOT); + + CharSequence title = + context.getText(com.android.internal.R.string.NetworkPreferenceSwitchTitle); + CharSequence details = + context.getText(com.android.internal.R.string.NetworkPreferenceSwitchSummary); + + + Notification mNotification = new Notification.Builder(context) + .setWhen(System.currentTimeMillis()) + .setAutoCancel(true) + .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning) + .setContentTitle(title) + .setColor(context.getResources().getColor( + com.android.internal.R.color.system_notification_accent_color)) + .setStyle(new Notification.BigTextStyle().bigText(details)) + .setContentText(details) + .setContentIntent(settingsIntent) + .build(); + + notificationManager.notify(NOTIFICATION_ID, mNotification); + } + + /** + * Cancel notifications if a registration is pending or has been sent. + */ + private void cancelNotification() { + Context context = mPhone.getContext(); + mIsPhoneRegistered = true; + NotificationManager notificationManager = (NotificationManager) + context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.cancel(NOTIFICATION_ID); + } +}
\ No newline at end of file diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java index 1ed421057..090ea30b9 100755 --- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java +++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java @@ -88,6 +88,8 @@ public class GsmCdmaCallTracker extends CallTracker { public PhoneConstants.State mState = PhoneConstants.State.IDLE; + private TelephonyMetrics mMetrics = TelephonyMetrics.getInstance(); + // Following member variables are for CDMA only private RegistrantList mCallWaitingRegistrants = new RegistrantList(); private boolean mPendingCallInEcm; @@ -303,6 +305,8 @@ public class GsmCdmaCallTracker extends CallTracker { mPendingMO = new GsmCdmaConnection(mPhone, checkForTestEmergencyNumber(dialString), this, mForegroundCall, isEmergencyCall); mHangupPendingMO = false; + mMetrics.writeRilDial(mPhone.getPhoneId(), mPendingMO, clirMode, uusInfo); + if ( mPendingMO.getAddress() == null || mPendingMO.getAddress().length() == 0 || mPendingMO.getAddress().indexOf(PhoneNumberUtils.WILD) >= 0) { @@ -715,7 +719,7 @@ public class GsmCdmaCallTracker extends CallTracker { } if (mState != oldState) { mPhone.notifyPhoneStateChanged(); - TelephonyMetrics.getInstance().writePhoneState(mPhone.getPhoneId(), mState); + mMetrics.writePhoneState(mPhone.getPhoneId(), mState); } } @@ -863,9 +867,6 @@ public class GsmCdmaCallTracker extends CallTracker { // Connection missing in CLCC response that we were // tracking. mDroppedDuringPoll.add(conn); - // Dropped connections are removed from the CallTracker - // list but kept in the GsmCdmaCall list - mConnections[i] = null; } else { // This case means the RIL has no more active call anymore and // we need to clean up the foregroundCall and ringingCall. @@ -892,12 +893,10 @@ public class GsmCdmaCallTracker extends CallTracker { } // If emergency call is not going through while dialing checkAndEnableDataCallAfterEmergencyCallDropped(); - - // Dropped connections are removed from the CallTracker - // list but kept in the Call list - mConnections[i] = null; - } + // Dropped connections are removed from the CallTracker + // list but kept in the Call list + mConnections[i] = null; } else if (conn != null && dc != null && !conn.compareTo(dc) && isPhoneTypeGsm()) { // Connection in CLCC response does not match what // we were tracking. Assume dropped call and new call @@ -987,6 +986,7 @@ public class GsmCdmaCallTracker extends CallTracker { // clear the "local hangup" and "missed/rejected call" // cases from the "dropped during poll" list // These cases need no "last call fail" reason + ArrayList<GsmCdmaConnection> locallyDisconnectedConnections = new ArrayList<>(); for (int i = mDroppedDuringPoll.size() - 1; i >= 0 ; i--) { GsmCdmaConnection conn = mDroppedDuringPoll.get(i); //CDMA @@ -1008,11 +1008,13 @@ public class GsmCdmaCallTracker extends CallTracker { mDroppedDuringPoll.remove(i); hasAnyCallDisconnected |= conn.onDisconnect(cause); wasDisconnected = true; + locallyDisconnectedConnections.add(conn); } else if (conn.mCause == DisconnectCause.LOCAL || conn.mCause == DisconnectCause.INVALID_NUMBER) { mDroppedDuringPoll.remove(i); hasAnyCallDisconnected |= conn.onDisconnect(conn.mCause); wasDisconnected = true; + locallyDisconnectedConnections.add(conn); } if (!isPhoneTypeGsm() && wasDisconnected && unknownConnectionAppeared @@ -1021,6 +1023,9 @@ public class GsmCdmaCallTracker extends CallTracker { newUnknownConnectionCdma = null; } } + if (locallyDisconnectedConnections.size() > 0) { + mMetrics.writeRilCallList(mPhone.getPhoneId(), locallyDisconnectedConnections); + } /* Disconnect any pending Handover connections */ for (Iterator<Connection> it = mHandoverConnections.iterator(); @@ -1033,6 +1038,7 @@ public class GsmCdmaCallTracker extends CallTracker { } else { hoConnection.onDisconnect(DisconnectCause.NOT_VALID); } + // TODO: Do we need to update these hoConnections in Metrics ? it.remove(); } @@ -1071,6 +1077,7 @@ public class GsmCdmaCallTracker extends CallTracker { if (hasNonHangupStateChanged || newRinging != null || hasAnyCallDisconnected) { mPhone.notifyPreciseCallStateChanged(); + updateMetrics(mConnections); } // If all handover connections are mapped during this poll process clean it up @@ -1083,6 +1090,14 @@ public class GsmCdmaCallTracker extends CallTracker { //dumpState(); } + private void updateMetrics(GsmCdmaConnection []connections) { + ArrayList<GsmCdmaConnection> activeConnections = new ArrayList<>(); + for(GsmCdmaConnection conn : connections) { + if(conn != null) activeConnections.add(conn); + } + mMetrics.writeRilCallList(mPhone.getPhoneId(), activeConnections); + } + private void handleRadioNotAvailable() { // handlePollCalls will clear out its // call list when it gets the CommandException @@ -1156,6 +1171,7 @@ public class GsmCdmaCallTracker extends CallTracker { return; } else { try { + mMetrics.writeRilHangup(mPhone.getPhoneId(), conn, conn.getGsmCdmaIndex()); mCi.hangupConnection (conn.getGsmCdmaIndex(), obtainCompleteMessage()); } catch (CallStateException ex) { // Ignore "connection not found" @@ -1204,6 +1220,7 @@ public class GsmCdmaCallTracker extends CallTracker { if (call == mRingingCall) { if (Phone.DEBUG_PHONE) log("(ringing) hangup waiting or background"); + logHangupEvent(call); mCi.hangupWaitingOrBackground(obtainCompleteMessage()); } else if (call == mForegroundCall) { if (call.isDialingOrAlerting()) { @@ -1217,6 +1234,7 @@ public class GsmCdmaCallTracker extends CallTracker { log("hangup all conns in active/background call, without affecting ringing call"); hangupAllConnections(call); } else { + logHangupEvent(call); hangupForegroundResumeBackground(); } } else if (call == mBackgroundCall) { @@ -1237,8 +1255,24 @@ public class GsmCdmaCallTracker extends CallTracker { mPhone.notifyPreciseCallStateChanged(); } + private void logHangupEvent(GsmCdmaCall call) { + int count = call.mConnections.size(); + for (int i = 0; i < count; i++) { + GsmCdmaConnection cn = (GsmCdmaConnection) call.mConnections.get(i); + int call_index; + try { + call_index = cn.getGsmCdmaIndex(); + } catch (CallStateException ex) { + call_index = -1; + } + mMetrics.writeRilHangup(mPhone.getPhoneId(), cn, call_index); + } + if (VDBG) Rlog.v(LOG_TAG, "logHangupEvent logged " + count + " Connections "); + } + public void hangupWaitingOrBackground() { if (Phone.DEBUG_PHONE) log("hangupWaitingOrBackground"); + logHangupEvent(mBackgroundCall); mCi.hangupWaitingOrBackground(obtainCompleteMessage()); } @@ -1253,6 +1287,7 @@ public class GsmCdmaCallTracker extends CallTracker { for (int i = 0; i < count; i++) { GsmCdmaConnection cn = (GsmCdmaConnection)call.mConnections.get(i); if (cn.getGsmCdmaIndex() == index) { + mMetrics.writeRilHangup(mPhone.getPhoneId(), cn, cn.getGsmCdmaIndex()); mCi.hangupConnection(index, obtainCompleteMessage()); return; } @@ -1266,6 +1301,7 @@ public class GsmCdmaCallTracker extends CallTracker { int count = call.mConnections.size(); for (int i = 0; i < count; i++) { GsmCdmaConnection cn = (GsmCdmaConnection)call.mConnections.get(i); + mMetrics.writeRilHangup(mPhone.getPhoneId(), cn, cn.getGsmCdmaIndex()); mCi.hangupConnection(cn.getGsmCdmaIndex(), obtainCompleteMessage()); } } catch (CallStateException ex) { @@ -1422,6 +1458,7 @@ public class GsmCdmaCallTracker extends CallTracker { updatePhoneState(); mPhone.notifyPreciseCallStateChanged(); + mMetrics.writeRilCallList(mPhone.getPhoneId(), mDroppedDuringPoll); mDroppedDuringPoll.clear(); break; diff --git a/src/java/com/android/internal/telephony/GsmCdmaConnection.java b/src/java/com/android/internal/telephony/GsmCdmaConnection.java index 28c94c841..364960055 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaConnection.java +++ b/src/java/com/android/internal/telephony/GsmCdmaConnection.java @@ -446,9 +446,6 @@ public class GsmCdmaConnection extends Connection { case CallFailCause.CHANNEL_UNACCEPTABLE: return DisconnectCause.CHANNEL_UNACCEPTABLE; - case CallFailCause.OPERATOR_DETERMINED_BARRING: - return DisconnectCause.OPERATOR_DETERMINED_BARRING; - case CallFailCause.CALL_FAIL_NO_USER_RESPONDING: return DisconnectCause.CALL_FAIL_NO_USER_RESPONDING; @@ -587,6 +584,7 @@ public class GsmCdmaConnection extends Connection { case CallFailCause.ACM_LIMIT_EXCEEDED: return DisconnectCause.LIMIT_EXCEEDED; + case CallFailCause.OPERATOR_DETERMINED_BARRING: case CallFailCause.CALL_BARRED: return DisconnectCause.CALL_BARRED; diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 19b14c26a..c9501d453 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -1156,6 +1156,14 @@ public class GsmCdmaPhone extends Phone { && mSST.mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && !isEmergency) { throw new CallStateException("cannot dial in current state"); } + // Check non-emergency voice CS call - shouldn't dial when POWER_OFF + if (mSST != null && mSST.mSS.getState() == ServiceState.STATE_POWER_OFF /* CS POWER_OFF */ + && !VideoProfile.isVideo(videoState) /* voice call */ + && !isEmergency /* non-emergency call */) { + throw new CallStateException( + CallStateException.ERROR_POWER_OFF, + "cannot dial voice call in airplane mode"); + } if (DBG) logd("Trying (non-IMS) CS call"); if (isPhoneTypeGsm()) { @@ -1938,6 +1946,19 @@ public class GsmCdmaPhone extends Phone { } } + public boolean supports3gppCallForwardingWhileRoaming() { + CarrierConfigManager configManager = (CarrierConfigManager) + getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); + PersistableBundle b = configManager.getConfig(); + if (b != null) { + return b.getBoolean( + CarrierConfigManager.KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true); + } else { + // Default value set in CarrierConfigManager + return true; + } + } + private void onNetworkInitiatedUssd(MmiCode mmi) { mMmiCompleteRegistrants.notifyRegistrants( new AsyncResult(null, mmi, null)); diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java index e19648f26..71962f8f2 100644 --- a/src/java/com/android/internal/telephony/InboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java @@ -79,7 +79,9 @@ import com.android.internal.util.StateMachine; import java.io.ByteArrayOutputStream; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * This class broadcasts incoming SMS messages to interested apps after storing them in @@ -114,9 +116,19 @@ public abstract class InboundSmsHandler extends StateMachine { private static final String[] PDU_SEQUENCE_PORT_PROJECTION = { "pdu", "sequence", - "destination_port" + "destination_port", + "display_originating_addr" }; + /** Mapping from DB COLUMN to PDU_SEQUENCE_PORT PROJECTION index */ + private static final Map<Integer, Integer> PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING = + new HashMap<Integer, Integer>() {{ + put(PDU_COLUMN, 0); + put(SEQUENCE_COLUMN, 1); + put(DESTINATION_PORT_COLUMN, 2); + put(DISPLAY_ADDRESS_COLUMN, 3); + }}; + public static final int PDU_COLUMN = 0; public static final int SEQUENCE_COLUMN = 1; public static final int DESTINATION_PORT_COLUMN = 2; @@ -126,6 +138,7 @@ public abstract class InboundSmsHandler extends StateMachine { public static final int ADDRESS_COLUMN = 6; public static final int ID_COLUMN = 7; public static final int MESSAGE_BODY_COLUMN = 8; + public static final int DISPLAY_ADDRESS_COLUMN = 9; public static final String SELECT_BY_ID = "_id=?"; public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND " + @@ -724,7 +737,8 @@ public abstract class InboundSmsHandler extends StateMachine { tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(sms.getPdu(), sms.getTimestampMillis(), destPort, is3gpp2(), false, - sms.getDisplayOriginatingAddress(), sms.getMessageBody()); + sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(), + sms.getMessageBody()); } else { // Create a tracker for this message segment. SmsHeader.ConcatRef concatRef = smsHeader.concatRef; @@ -732,7 +746,7 @@ public abstract class InboundSmsHandler extends StateMachine { int destPort = (portAddrs != null ? portAddrs.destPort : -1); tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(sms.getPdu(), - sms.getTimestampMillis(), destPort, is3gpp2(), + sms.getTimestampMillis(), destPort, is3gpp2(), sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(), concatRef.refNumber, concatRef.seqNumber, concatRef.msgCount, false, sms.getMessageBody()); } @@ -778,10 +792,12 @@ public abstract class InboundSmsHandler extends StateMachine { int messageCount = tracker.getMessageCount(); byte[][] pdus; int destPort = tracker.getDestPort(); + boolean block = false; if (messageCount == 1) { // single-part message pdus = new byte[][]{tracker.getPdu()}; + block = BlockChecker.isBlocked(mContext, tracker.getDisplayAddress()); } else { // multi-part message Cursor cursor = null; @@ -810,20 +826,36 @@ public abstract class InboundSmsHandler extends StateMachine { pdus = new byte[messageCount][]; while (cursor.moveToNext()) { // subtract offset to convert sequence to 0-based array index - int index = cursor.getInt(SEQUENCE_COLUMN) - tracker.getIndexOffset(); + int index = cursor.getInt(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING + .get(SEQUENCE_COLUMN)) - tracker.getIndexOffset(); - pdus[index] = HexDump.hexStringToByteArray(cursor.getString(PDU_COLUMN)); + pdus[index] = HexDump.hexStringToByteArray(cursor.getString( + PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING.get(PDU_COLUMN))); // Read the destination port from the first segment (needed for CDMA WAP PDU). // It's not a bad idea to prefer the port from the first segment in other cases. - if (index == 0 && !cursor.isNull(DESTINATION_PORT_COLUMN)) { - int port = cursor.getInt(DESTINATION_PORT_COLUMN); + if (index == 0 && !cursor.isNull(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING + .get(DESTINATION_PORT_COLUMN))) { + int port = cursor.getInt(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING + .get(DESTINATION_PORT_COLUMN)); // strip format flags and convert to real port number, or -1 port = InboundSmsTracker.getRealDestPort(port); if (port != -1) { destPort = port; } } + // check if display address should be blocked or not + if (!block) { + // Depending on the nature of the gateway, the display origination address + // is either derived from the content of the SMS TP-OA field, or the TP-OA + // field contains a generic gateway address and the from address is added + // at the beginning in the message body. In that case only the first SMS + // (part of Multi-SMS) comes with the display originating address which + // could be used for block checking purpose. + block = BlockChecker.isBlocked(mContext, + cursor.getString(PDU_SEQUENCE_PORT_PROJECTION_INDEX_MAPPING + .get(DISPLAY_ADDRESS_COLUMN))); + } } } catch (SQLException e) { loge("Can't access multipart SMS database", e); @@ -877,7 +909,7 @@ public abstract class InboundSmsHandler extends StateMachine { } } - if (BlockChecker.isBlocked(mContext, tracker.getAddress())) { + if (block) { deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(), DELETE_PERMANENTLY); return false; diff --git a/src/java/com/android/internal/telephony/InboundSmsTracker.java b/src/java/com/android/internal/telephony/InboundSmsTracker.java index 89ea681b7..9db83ab38 100644 --- a/src/java/com/android/internal/telephony/InboundSmsTracker.java +++ b/src/java/com/android/internal/telephony/InboundSmsTracker.java @@ -38,10 +38,9 @@ public class InboundSmsTracker { private final boolean mIs3gpp2; private final boolean mIs3gpp2WapPdu; private final String mMessageBody; - // Copied from SmsMessageBase#getDisplayOriginatingAddress used for blocking messages. - private final String mAddress; // Fields for concatenating multi-part SMS messages + private final String mAddress; private final int mReferenceNumber; private final int mSequenceNumber; private final int mMessageCount; @@ -50,6 +49,16 @@ public class InboundSmsTracker { private String mDeleteWhere; private String[] mDeleteWhereArgs; + /** + * Copied from SmsMessageBase#getDisplayOriginatingAddress used for blocking messages. + * DisplayAddress could be email address if this message was from an email gateway, otherwise + * same as mAddress. Email gateway might set a generic gateway address as the mAddress which + * could not be used for blocking check and append the display email address at the beginning + * of the message body. In that case, display email address is only available for the first SMS + * in the Multi-part SMS. + */ + private final String mDisplayAddress; + /** Destination port flag bit for no destination port. */ private static final int DEST_PORT_FLAG_NO_PORT = (1 << 16); @@ -73,10 +82,12 @@ public class InboundSmsTracker { * @param destPort the destination port * @param is3gpp2 true for 3GPP2 format; false for 3GPP format * @param is3gpp2WapPdu true for 3GPP2 format WAP PDU; false otherwise - * @param address originating address, or email if this message was from an email gateway + * @param address originating address + * @param displayAddress email address if this message was from an email gateway, otherwise same + * as originating address */ public InboundSmsTracker(byte[] pdu, long timestamp, int destPort, boolean is3gpp2, - boolean is3gpp2WapPdu, String address, String messageBody) { + boolean is3gpp2WapPdu, String address, String displayAddress, String messageBody) { mPdu = pdu; mTimestamp = timestamp; mDestPort = destPort; @@ -84,6 +95,7 @@ public class InboundSmsTracker { mIs3gpp2WapPdu = is3gpp2WapPdu; mMessageBody = messageBody; mAddress = address; + mDisplayAddress = displayAddress; // fields for multi-part SMS mReferenceNumber = -1; mSequenceNumber = getIndexOffset(); // 0 or 1, depending on type @@ -102,22 +114,26 @@ public class InboundSmsTracker { * @param destPort the destination port * @param is3gpp2 true for 3GPP2 format; false for 3GPP format * @param address originating address, or email if this message was from an email gateway + * @param displayAddress email address if this message was from an email gateway, otherwise same + * as originating address * @param referenceNumber the concatenated reference number * @param sequenceNumber the sequence number of this segment (0-based) * @param messageCount the total number of segments * @param is3gpp2WapPdu true for 3GPP2 format WAP PDU; false otherwise */ public InboundSmsTracker(byte[] pdu, long timestamp, int destPort, boolean is3gpp2, - String address, int referenceNumber, int sequenceNumber, int messageCount, - boolean is3gpp2WapPdu, String messageBody) { + String address, String displayAddress, int referenceNumber, int sequenceNumber, + int messageCount, boolean is3gpp2WapPdu, String messageBody) { mPdu = pdu; mTimestamp = timestamp; mDestPort = destPort; mIs3gpp2 = is3gpp2; mIs3gpp2WapPdu = is3gpp2WapPdu; mMessageBody = messageBody; - mAddress = address; + // fields used for check blocking message + mDisplayAddress = displayAddress; // fields for multi-part SMS + mAddress = address; mReferenceNumber = referenceNumber; mSequenceNumber = sequenceNumber; mMessageCount = messageCount; @@ -150,6 +166,7 @@ public class InboundSmsTracker { mTimestamp = cursor.getLong(InboundSmsHandler.DATE_COLUMN); mAddress = cursor.getString(InboundSmsHandler.ADDRESS_COLUMN); + mDisplayAddress = cursor.getString(InboundSmsHandler.DISPLAY_ADDRESS_COLUMN); if (cursor.isNull(InboundSmsHandler.COUNT_COLUMN)) { // single-part message @@ -203,6 +220,7 @@ public class InboundSmsTracker { values.put("destination_port", destPort); if (mAddress != null) { values.put("address", mAddress); + values.put("display_originating_addr", mDisplayAddress); values.put("reference_number", mReferenceNumber); values.put("sequence", mSequenceNumber); values.put("count", mMessageCount); @@ -241,6 +259,7 @@ public class InboundSmsTracker { builder.append(" is3gpp2=").append(mIs3gpp2); if (mAddress != null) { builder.append(" address=").append(mAddress); + builder.append(" display_originating_addr=").append(mDisplayAddress); builder.append(" refNumber=").append(mReferenceNumber); builder.append(" seqNumber=").append(mSequenceNumber); builder.append(" msgCount=").append(mMessageCount); @@ -287,6 +306,10 @@ public class InboundSmsTracker { return mAddress; } + public String getDisplayAddress() { + return mDisplayAddress; + } + public String getMessageBody() { return mMessageBody; } diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index e6168cde5..7f0b1b804 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -51,10 +51,12 @@ import android.telephony.TelephonyManager; import android.telephony.VoLteServiceState; import android.text.TextUtils; +import com.android.ims.ImsCall; import com.android.ims.ImsConfig; import com.android.ims.ImsManager; import com.android.internal.R; import com.android.internal.telephony.dataconnection.DcTracker; +import com.android.internal.telephony.imsphone.ImsPhoneCall; import com.android.internal.telephony.test.SimulatedRadioControl; import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; import com.android.internal.telephony.uicc.IccFileHandler; @@ -2134,23 +2136,40 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return videoState; } - private boolean isVideoCall(Call call) { - int videoState = getVideoState(call); - return (VideoProfile.isVideo(videoState)); + /** + * Determines if the specified call currently is or was at some point a video call, or if it is + * a conference call. + * @param call The call. + * @return {@code true} if the call is or was a video call or is a conference call, + * {@code false} otherwise. + */ + private boolean isVideoCallOrConference(Call call) { + if (call.isMultiparty()) { + return true; + } + + boolean isDowngradedVideoCall = false; + if (call instanceof ImsPhoneCall) { + ImsPhoneCall imsPhoneCall = (ImsPhoneCall) call; + ImsCall imsCall = imsPhoneCall.getImsCall(); + return imsCall != null && (imsCall.isVideoCall() || + imsCall.wasVideoCall()); + } + return isDowngradedVideoCall; } /** - * @return {@code true} if video call is present, false otherwise. + * @return {@code true} if an IMS video call or IMS conference is present, false otherwise. */ - public boolean isVideoCallPresent() { - boolean isVideoCallActive = false; + public boolean isImsVideoCallOrConferencePresent() { + boolean isPresent = false; if (mImsPhone != null) { - isVideoCallActive = isVideoCall(mImsPhone.getForegroundCall()) || - isVideoCall(mImsPhone.getBackgroundCall()) || - isVideoCall(mImsPhone.getRingingCall()); + isPresent = isVideoCallOrConference(mImsPhone.getForegroundCall()) || + isVideoCallOrConference(mImsPhone.getBackgroundCall()) || + isVideoCallOrConference(mImsPhone.getRingingCall()); } - Rlog.d(LOG_TAG, "isVideoCallActive: " + isVideoCallActive); - return isVideoCallActive; + Rlog.d(LOG_TAG, "isImsVideoCallOrConferencePresent: " + isPresent); + return isPresent; } /** @@ -2926,6 +2945,9 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { * Return if UT capability of ImsPhone is enabled or not */ public boolean isUtEnabled() { + if (mImsPhone != null) { + return mImsPhone.isUtEnabled(); + } return false; } diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java index 68bf12e2e..410146353 100644 --- a/src/java/com/android/internal/telephony/RIL.java +++ b/src/java/com/android/internal/telephony/RIL.java @@ -1089,8 +1089,6 @@ public class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - mMetrics.writeRilDial(mInstanceId, rr.mSerial, clirMode, uusInfo); - send(rr); } @@ -1149,8 +1147,6 @@ public class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + gsmIndex); - mMetrics.writeRilHangup(mInstanceId, rr.mSerial, gsmIndex); - rr.mParcel.writeInt(1); rr.mParcel.writeInt(gsmIndex); @@ -1165,8 +1161,6 @@ public class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - mMetrics.writeRilHangup(mInstanceId, rr.mSerial, -1); - send(rr); } @@ -1179,8 +1173,6 @@ public class RIL extends BaseCommands implements CommandsInterface { result); if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - mMetrics.writeRilHangup(mInstanceId, rr.mSerial, -1); - send(rr); } diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java index 12f5d4e45..abbc1f74c 100644 --- a/src/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java @@ -155,6 +155,7 @@ public class ServiceStateTracker extends Handler { protected RegistrantList mDetachedRegistrants = new RegistrantList(); private RegistrantList mDataRegStateOrRatChangedRegistrants = new RegistrantList(); private RegistrantList mNetworkAttachedRegistrants = new RegistrantList(); + private RegistrantList mNetworkDetachedRegistrants = new RegistrantList(); private RegistrantList mPsRestrictEnabledRegistrants = new RegistrantList(); private RegistrantList mPsRestrictDisabledRegistrants = new RegistrantList(); @@ -284,6 +285,7 @@ public class ServiceStateTracker extends Handler { private final LocalLog mAttachLog = new LocalLog(10); private final LocalLog mPhoneTypeLog = new LocalLog(10); private final LocalLog mRatLog = new LocalLog(20); + private final LocalLog mRadioPowerLog = new LocalLog(20); private class SstSubscriptionsChangedListener extends OnSubscriptionsChangedListener { public final AtomicInteger mPreviousSubId = @@ -423,6 +425,8 @@ public class ServiceStateTracker extends Handler { private boolean mStartedGprsRegCheck; /** Already sent the event-log for no gprs register. */ private boolean mReportedGprsNoReg; + + private CarrierServiceStateTracker mCSST; /** * The Notification object given to the NotificationManager. */ @@ -528,6 +532,9 @@ public class ServiceStateTracker extends Handler { int enableCellularOnBoot = Settings.Global.getInt(mCr, Settings.Global.ENABLE_CELLULAR_ON_BOOT, 1); mDesiredPowerState = (enableCellularOnBoot > 0) && ! (airplaneMode > 0); + mRadioPowerLog.log("init : airplane mode = " + airplaneMode + " enableCellularOnBoot = " + + enableCellularOnBoot); + mCr.registerContentObserver( Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true, @@ -549,6 +556,17 @@ public class ServiceStateTracker extends Handler { mPhone.notifyOtaspChanged(OTASP_UNINITIALIZED); updatePhoneType(); + + mCSST = new CarrierServiceStateTracker(phone, this); + + registerForNetworkAttached(mCSST, + CarrierServiceStateTracker.CARRIER_EVENT_VOICE_REGISTRATION, null); + registerForNetworkDetached(mCSST, + CarrierServiceStateTracker.CARRIER_EVENT_VOICE_DEREGISTRATION, null); + registerForDataConnectionAttached(mCSST, + CarrierServiceStateTracker.CARRIER_EVENT_DATA_REGISTRATION, null); + registerForDataConnectionDetached(mCSST, + CarrierServiceStateTracker.CARRIER_EVENT_DATA_DEREGISTRATION, null); } @VisibleForTesting @@ -2337,12 +2355,14 @@ public class ServiceStateTracker extends Handler { protected void setPowerStateToDesired() { if (DBG) { - log("mDeviceShuttingDown=" + mDeviceShuttingDown + + String tmpLog = "mDeviceShuttingDown=" + mDeviceShuttingDown + ", mDesiredPowerState=" + mDesiredPowerState + ", getRadioState=" + mCi.getRadioState() + ", mPowerOffDelayNeed=" + mPowerOffDelayNeed + ", mAlarmSwitch=" + mAlarmSwitch + - ", mRadioDisabledByCarrier=" + mRadioDisabledByCarrier); + ", mRadioDisabledByCarrier=" + mRadioDisabledByCarrier; + log(tmpLog); + mRadioPowerLog.log(tmpLog); } if (mPhone.isPhoneTypeGsm() && mAlarmSwitch) { @@ -2720,6 +2740,10 @@ public class ServiceStateTracker extends Handler { mNitzUpdatedTime = false; } + if (hasDeregistered) { + mNetworkDetachedRegistrants.notifyRegistrants(); + } + if (hasChanged) { String operatorNumeric; @@ -2878,6 +2902,10 @@ public class ServiceStateTracker extends Handler { mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE && mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE; + boolean hasDeregistered = + mSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE + && mNewSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE; + boolean hasCdmaDataConnectionAttached = mSS.getDataRegState() != ServiceState.STATE_IN_SERVICE && mNewSS.getDataRegState() == ServiceState.STATE_IN_SERVICE; @@ -2952,6 +2980,10 @@ public class ServiceStateTracker extends Handler { mNetworkAttachedRegistrants.notifyRegistrants(); } + if (hasDeregistered) { + mNetworkDetachedRegistrants.notifyRegistrants(); + } + if (hasChanged) { updateSpnDisplay(); @@ -3191,6 +3223,10 @@ public class ServiceStateTracker extends Handler { mNetworkAttachedRegistrants.notifyRegistrants(); } + if (hasDeregistered) { + mNetworkDetachedRegistrants.notifyRegistrants(); + } + if (hasChanged) { updateSpnDisplay(); @@ -4304,11 +4340,31 @@ public class ServiceStateTracker extends Handler { r.notifyRegistrant(); } } + public void unregisterForNetworkAttached(Handler h) { mNetworkAttachedRegistrants.remove(h); } /** + * Registration point for transition into network detached. + * @param h handler to notify + * @param what what code of message when delivered + * @param obj in Message.obj + */ + public void registerForNetworkDetached(Handler h, int what, Object obj) { + Registrant r = new Registrant(h, what, obj); + + mNetworkDetachedRegistrants.add(r); + if (mSS.getVoiceRegState() != ServiceState.STATE_IN_SERVICE) { + r.notifyRegistrant(); + } + } + + public void unregisterForNetworkDetached(Handler h) { + mNetworkDetachedRegistrants.remove(h); + } + + /** * Registration point for transition into packet service restricted zone. * @param h handler to notify * @param what what code of message when delivered @@ -4676,6 +4732,21 @@ public class ServiceStateTracker extends Handler { } } + private void dumpCellInfoList(PrintWriter pw) { + pw.print(" mLastCellInfoList={"); + if(mLastCellInfoList != null) { + boolean first = true; + for(CellInfo info : mLastCellInfoList) { + if(first == false) { + pw.print(","); + } + first = false; + pw.print(info.toString()); + } + } + pw.println("}"); + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("ServiceStateTracker:"); pw.println(" mSubId=" + mSubId); @@ -4695,6 +4766,8 @@ public class ServiceStateTracker extends Handler { pw.println(" mCellLoc=" + mCellLoc); pw.println(" mNewCellLoc=" + mNewCellLoc); pw.println(" mLastCellInfoListTime=" + mLastCellInfoListTime); + dumpCellInfoList(pw); + pw.flush(); pw.println(" mPreferredNetworkType=" + mPreferredNetworkType); pw.println(" mMaxDataCalls=" + mMaxDataCalls); pw.println(" mNewMaxDataCalls=" + mNewMaxDataCalls); @@ -4768,6 +4841,11 @@ public class ServiceStateTracker extends Handler { ipw.increaseIndent(); mRatLog.dump(fd, ipw, args); ipw.decreaseIndent(); + + ipw.println(" Radio power Log:"); + ipw.increaseIndent(); + mRadioPowerLog.dump(fd, ipw, args); + ipw.decreaseIndent(); } public boolean isImsRegistered() { diff --git a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java index dde4d2db5..7f87e43f2 100644 --- a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java +++ b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java @@ -60,7 +60,8 @@ public class SmsBroadcastUndelivered { "count", "address", "_id", - "message_body" + "message_body", + "display_originating_addr" }; private static SmsBroadcastUndelivered instance; diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java index 7c12c522e..c15402c52 100644 --- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java +++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java @@ -140,21 +140,22 @@ public class TelephonyComponentFactory { * Create a tracker for a single-part SMS. */ public InboundSmsTracker makeInboundSmsTracker(byte[] pdu, long timestamp, int destPort, - boolean is3gpp2, boolean is3gpp2WapPdu, String address, String messageBody) { + boolean is3gpp2, boolean is3gpp2WapPdu, String address, String displayAddr, + String messageBody) { Rlog.d(LOG_TAG, "makeInboundSmsTracker"); return new InboundSmsTracker(pdu, timestamp, destPort, is3gpp2, is3gpp2WapPdu, address, - messageBody); + displayAddr, messageBody); } /** * Create a tracker for a multi-part SMS. */ public InboundSmsTracker makeInboundSmsTracker(byte[] pdu, long timestamp, int destPort, - boolean is3gpp2, String address, int referenceNumber, int sequenceNumber, + boolean is3gpp2, String address, String displayAddr, int referenceNumber, int sequenceNumber, int messageCount, boolean is3gpp2WapPdu, String messageBody) { Rlog.d(LOG_TAG, "makeInboundSmsTracker"); - return new InboundSmsTracker(pdu, timestamp, destPort, is3gpp2, address, referenceNumber, - sequenceNumber, messageCount, is3gpp2WapPdu, messageBody); + return new InboundSmsTracker(pdu, timestamp, destPort, is3gpp2, address, displayAddr, + referenceNumber, sequenceNumber, messageCount, is3gpp2WapPdu, messageBody); } /** diff --git a/src/java/com/android/internal/telephony/TelephonyTester.java b/src/java/com/android/internal/telephony/TelephonyTester.java index ba59e6d33..3de356fa9 100644 --- a/src/java/com/android/internal/telephony/TelephonyTester.java +++ b/src/java/com/android/internal/telephony/TelephonyTester.java @@ -22,6 +22,7 @@ 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; @@ -92,24 +93,29 @@ public class TelephonyTester { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (DBG) log("sIntentReceiver.onReceive: action=" + action); - if (action.equals(mPhone.getActionDetached())) { - log("simulate detaching"); - mPhone.getServiceStateTracker().mDetachedRegistrants.notifyRegistrants(); - } else if (action.equals(mPhone.getActionAttached())) { - log("simulate attaching"); - mPhone.getServiceStateTracker().mAttachedRegistrants.notifyRegistrants(); - } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) { - log("inject simulated conference event package"); - handleTestConferenceEventPackage(context, intent.getStringExtra(EXTRA_FILENAME)); - } else if (action.equals(ACTION_TEST_DIALOG_EVENT_PACKAGE)) { - log("handle test dialog event package intent"); - handleTestDialogEventPackageIntent(intent); - } else if (action.equals(ACTION_TEST_HANDOVER_FAIL)) { - log("handle handover fail test intent"); - handleHandoverFailedIntent(); - } else { - if (DBG) log("onReceive: unknown action=" + action); + try { + if (DBG) log("sIntentReceiver.onReceive: action=" + action); + if (action.equals(mPhone.getActionDetached())) { + log("simulate detaching"); + mPhone.getServiceStateTracker().mDetachedRegistrants.notifyRegistrants(); + } else if (action.equals(mPhone.getActionAttached())) { + log("simulate attaching"); + mPhone.getServiceStateTracker().mAttachedRegistrants.notifyRegistrants(); + } else if (action.equals(ACTION_TEST_CONFERENCE_EVENT_PACKAGE)) { + log("inject simulated conference event package"); + handleTestConferenceEventPackage(context, + intent.getStringExtra(EXTRA_FILENAME)); + } else if (action.equals(ACTION_TEST_DIALOG_EVENT_PACKAGE)) { + log("handle test dialog event package intent"); + handleTestDialogEventPackageIntent(intent); + } else if (action.equals(ACTION_TEST_HANDOVER_FAIL)) { + log("handle handover fail test intent"); + handleHandoverFailedIntent(); + } else { + if (DBG) log("onReceive: unknown action=" + action); + } + } catch (BadParcelableException e) { + Rlog.w(LOG_TAG, e); } } }; diff --git a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java index 0ed4bc413..fbc60d481 100644 --- a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java +++ b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java @@ -174,7 +174,8 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler { if (SmsEnvelope.TELESERVICE_WAP == teleService) { return processCdmaWapPdu(sms.getUserData(), sms.mMessageRef, - sms.getOriginatingAddress(), sms.getTimestampMillis()); + sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(), + sms.getTimestampMillis()); } else if (SmsEnvelope.TELESERVICE_CT_WAP == teleService) { /* China Telecom WDP header contains Message identifier and User data subparametrs extract these fields */ @@ -182,7 +183,8 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler { return Intents.RESULT_SMS_HANDLED; } return processCdmaWapPdu(sms.getUserData(), sms.mMessageRef, - sms.getOriginatingAddress(), sms.getTimestampMillis()); + sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(), + sms.getTimestampMillis()); } return dispatchNormalMessage(smsb); @@ -269,7 +271,7 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler { * {@link Activity#RESULT_OK} if the message has been broadcast * to applications */ - private int processCdmaWapPdu(byte[] pdu, int referenceNumber, String address, + private int processCdmaWapPdu(byte[] pdu, int referenceNumber, String address, String dispAddr, long timestamp) { int index = 0; @@ -314,8 +316,8 @@ public class CdmaInboundSmsHandler extends InboundSmsHandler { System.arraycopy(pdu, index, userData, 0, pdu.length - index); InboundSmsTracker tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker( - userData, timestamp, destinationPort, true, address, referenceNumber, segment, - totalSegments, true, HexDump.toHexString(userData)); + userData, timestamp, destinationPort, true, address, dispAddr, referenceNumber, + segment, totalSegments, true, HexDump.toHexString(userData)); // de-duping is done only for text messages return addTrackerToRawTableAndSendMessage(tracker, false /* don't de-dup */); diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java b/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java index 7e81d750d..3a4049e7c 100644 --- a/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java +++ b/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java @@ -114,18 +114,6 @@ public class ApnSetting { * */ public boolean permanentFailed = false; - /** - * Metered APN types which would be accounted for in data usage. This is a map of subId -> - * set of metered apn strings for the carrier. - */ - private static HashMap<Integer, HashSet<String>> sMeteredApnTypes = new HashMap<>(); - - /** - * Metered Roaming APN types which would be accounted for in data usage. This is a map of - * subId -> set of metered roaming apn strings for the carrier. - */ - private static HashMap<Integer, HashSet<String>> sMeteredRoamingApnTypes = new HashMap<>(); - public ApnSetting(int id, String numeric, String carrier, String apn, String proxy, String port, String mmsc, String mmsProxy, String mmsPort, @@ -354,10 +342,12 @@ public class ApnSetting { public boolean canHandleType(String type) { if (!carrierEnabled) return false; + boolean wildcardable = true; + if (PhoneConstants.APN_TYPE_IA.equalsIgnoreCase(type)) wildcardable = false; for (String t : types) { // DEFAULT handles all, and HIPRI is handled by DEFAULT if (t.equalsIgnoreCase(type) || - t.equalsIgnoreCase(PhoneConstants.APN_TYPE_ALL) || + (wildcardable && t.equalsIgnoreCase(PhoneConstants.APN_TYPE_ALL)) || (t.equalsIgnoreCase(PhoneConstants.APN_TYPE_DEFAULT) && type.equalsIgnoreCase(PhoneConstants.APN_TYPE_HIPRI))) { return true; @@ -428,64 +418,55 @@ public class ApnSetting { public static boolean isMeteredApnType(String type, Context context, int subId, boolean isRoaming) { - HashMap<Integer, HashSet<String>> meteredApnTypesCache = (isRoaming) ? - sMeteredApnTypes : sMeteredRoamingApnTypes; String carrierConfig = (isRoaming) ? CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS : CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS; - synchronized (meteredApnTypesCache) { - HashSet<String> meteredApnSet = meteredApnTypesCache.get(subId); - - // In case of cache miss, we need to look up the settings from carrier config. - if (meteredApnSet == null) { - // Retrieve the metered APN types from carrier config - CarrierConfigManager configManager = (CarrierConfigManager) - context.getSystemService(Context.CARRIER_CONFIG_SERVICE); - if (configManager == null) { - Rlog.e(LOG_TAG, "Carrier config service is not available"); - return true; - } + CarrierConfigManager configManager = (CarrierConfigManager) + context.getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager == null) { + Rlog.e(LOG_TAG, "Carrier config service is not available"); + return true; + } - PersistableBundle b = configManager.getConfigForSubId(subId); - if (b == null) { - Rlog.e(LOG_TAG, "Can't get the config. subId = " + subId); - return true; - } + PersistableBundle b = configManager.getConfigForSubId(subId); + if (b == null) { + Rlog.e(LOG_TAG, "Can't get the config. subId = " + subId); + return true; + } - String[] meteredApnTypes = b.getStringArray(carrierConfig); - if (meteredApnTypes == null) { - Rlog.e(LOG_TAG, carrierConfig + " is not available. " + "subId = " + subId); - return true; - } + String[] meteredApnTypes = b.getStringArray(carrierConfig); + if (meteredApnTypes == null) { + Rlog.e(LOG_TAG, carrierConfig + " is not available. " + "subId = " + subId); + return true; + } - meteredApnSet = new HashSet<String>(Arrays.asList(meteredApnTypes)); - meteredApnTypesCache.put(subId, meteredApnSet); - if (DBG) { - Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " + - Arrays.toString(meteredApnSet.toArray()) + - " isRoaming: " + isRoaming); - } - } - // If all types of APN are metered, then this APN setting must be metered. - if (meteredApnSet.contains(PhoneConstants.APN_TYPE_ALL)) { - if (DBG) Rlog.d(LOG_TAG, "All APN types are metered. isRoaming: " + isRoaming); - return true; - } + HashSet<String> meteredApnSet = new HashSet<>(Arrays.asList(meteredApnTypes)); + if (DBG) { + Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " + + Arrays.toString(meteredApnSet.toArray()) + + " isRoaming: " + isRoaming); + } + + // If all types of APN are metered, then this APN setting must be metered. + if (meteredApnSet.contains(PhoneConstants.APN_TYPE_ALL)) { + if (DBG) Rlog.d(LOG_TAG, "All APN types are metered. isRoaming: " + isRoaming); + return true; + } - if (meteredApnSet.contains(type)) { - if (DBG) Rlog.d(LOG_TAG, type + " is metered. isRoaming: " + isRoaming); + if (meteredApnSet.contains(type)) { + if (DBG) Rlog.d(LOG_TAG, type + " is metered. isRoaming: " + isRoaming); + return true; + } else if (type.equals(PhoneConstants.APN_TYPE_ALL)) { + // Assuming no configuration error, if at least one APN type is + // metered, then this APN setting is metered. + if (meteredApnSet.size() > 0) { + if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered. isRoaming: " + + isRoaming); return true; - } else if (type.equals(PhoneConstants.APN_TYPE_ALL)) { - // Assuming no configuration error, if at least one APN type is - // metered, then this APN setting is metered. - if (meteredApnSet.size() > 0) { - if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered. isRoaming: " + - isRoaming); - return true; - } } } + if (DBG) Rlog.d(LOG_TAG, type + " is not metered. isRoaming: " + isRoaming); return false; } @@ -520,7 +501,10 @@ public class ApnSetting { proxy.equals(other.proxy) && mmsc.equals(other.mmsc) && mmsProxy.equals(other.mmsProxy) && + TextUtils.equals(mmsPort, other.mmsPort) && port.equals(other.port) && + TextUtils.equals(user, other.user) && + TextUtils.equals(password, other.password) && authType == other.authType && Arrays.deepEquals(types, other.types) && protocol.equals(other.protocol) && diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java index cb6f0d90e..2f33d3b46 100644 --- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java +++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java @@ -47,6 +47,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; +import android.os.PersistableBundle; import android.os.RegistrantList; import android.os.ServiceManager; import android.os.SystemClock; @@ -56,6 +57,7 @@ import android.preference.PreferenceManager; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.provider.Telephony; +import android.telephony.CarrierConfigManager; import android.telephony.CellLocation; import android.telephony.PcoData; import android.telephony.Rlog; @@ -315,6 +317,14 @@ public class DcTracker extends Handler { log("WIFI_STATE_CHANGED_ACTION: enabled=" + enabled + " mIsWifiConnected=" + mIsWifiConnected); } + } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { + CarrierConfigManager configMgr = (CarrierConfigManager) + mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configMgr != null) { + PersistableBundle cfg = configMgr.getConfigForSubId(mPhone.getSubId()); + if (cfg != null) mAllowUserEditTetherApn = + cfg.getBoolean(CarrierConfigManager.KEY_EDITABLE_TETHER_APN_BOOL); + } } else { if (DBG) log("onReceive: Unknown action=" + action); } @@ -617,6 +627,22 @@ public class DcTracker extends Handler { private boolean mMeteredApnDisabled = false; /** + * int to remember whether has setDataProfiles and with roaming or not. + * 0: default, has never set data profile + * 1: has set data profile with home protocol + * 2: has set data profile with roaming protocol + * This is not needed once RIL command is updated to support both home and roaming protocol. + */ + private int mSetDataProfileStatus = 0; + + /** + * Whether carrier allow user edited tether APN. Updated by carrier config + * KEY_EDITABLE_TETHER_APN_BOOL + * If true, APN with dun type from database will be used, see fetchDunApn for details. + */ + private boolean mAllowUserEditTetherApn = false; + + /** * Handles changes to the APN db. */ private class ApnChangeObserver extends ContentObserver { @@ -688,6 +714,7 @@ public class DcTracker extends Handler { filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); filter.addAction(INTENT_DATA_STALL_ALARM); filter.addAction(INTENT_PROVISIONING_APN_ALARM); + filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); // TODO - redundent with update call below? mDataEnabledSettings.setUserDataEnabled(getDataEnabled()); @@ -1038,6 +1065,7 @@ public class DcTracker extends Handler { public void onReceive(Context context, Intent intent) { // Turning back on the radio can take time on the order of a minute, so show user a // spinner so they know something is going on. + log("onReceive : ProvisionNotificationBroadcastReceiver"); mProvisioningSpinner = new ProgressDialog(context); mProvisioningSpinner.setTitle(mNetworkOperator); mProvisioningSpinner.setMessage( @@ -1857,50 +1885,56 @@ public class DcTracker extends Handler { return null; } int bearer = mPhone.getServiceState().getRilDataRadioTechnology(); + IccRecords r = mIccRecords.get(); + String operator = (r != null) ? r.getOperatorNumeric() : ""; + ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>(); ApnSetting retDunSetting = null; + + // Places to look for tether APN in order: TETHER_DUN_APN setting, APN database if + // carrier allows it, and config_tether_apndata resource. String apnData = Settings.Global.getString(mResolver, Settings.Global.TETHER_DUN_APN); - List<ApnSetting> dunSettings = ApnSetting.arrayFromString(apnData); - IccRecords r = mIccRecords.get(); - for (ApnSetting dunSetting : dunSettings) { - String operator = mPhone.getOperatorNumeric(); - if (!ServiceState.bitmaskHasTech(dunSetting.bearerBitmask, bearer)) continue; - if (dunSetting.numeric.equals(operator)) { - if (dunSetting.hasMvnoParams()) { - if (r != null && ApnSetting.mvnoMatches(r, dunSetting.mvnoType, - dunSetting.mvnoMatchData)) { - if (VDBG) { - log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting); - } - return dunSetting; - } - } else if (mMvnoMatched == false) { - if (VDBG) log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting); - return dunSetting; + if (!TextUtils.isEmpty(apnData)) { + dunCandidates.addAll(ApnSetting.arrayFromString(apnData)); + if (VDBG) log("fetchDunApn: dunCandidates from Setting: " + dunCandidates); + } else if (mAllowUserEditTetherApn) { + for (ApnSetting apn : mAllApnSettings) { + if (apn.canHandleType(PhoneConstants.APN_TYPE_DUN)) { + dunCandidates.add(apn); } } + if (VDBG) log("fetchDunApn: dunCandidates from database: " + dunCandidates); + } + // If TETHER_DUN_APN isn't set or + // mAllowUserEditTetherApn is true but APN database doesn't have dun APN, + // try the resource as last resort. + if (dunCandidates.isEmpty()) { + String[] apnArrayData = mPhone.getContext().getResources() + .getStringArray(R.array.config_tether_apndata); + for (String apnString : apnArrayData) { + ApnSetting apn = ApnSetting.fromString(apnString); + // apn may be null if apnString isn't valid or has error parsing + if (apn != null) dunCandidates.add(apn); + } + if (VDBG) log("fetchDunApn: dunCandidates from resource: " + dunCandidates); } - Context c = mPhone.getContext(); - String[] apnArrayData = c.getResources().getStringArray(R.array.config_tether_apndata); - for (String apn : apnArrayData) { - ApnSetting dunSetting = ApnSetting.fromString(apn); - if (dunSetting != null) { - if (!ServiceState.bitmaskHasTech(dunSetting.bearerBitmask, bearer)) continue; + for (ApnSetting dunSetting : dunCandidates) { + if (!ServiceState.bitmaskHasTech(dunSetting.bearerBitmask, bearer)) continue; + if (dunSetting.numeric.equals(operator)) { if (dunSetting.hasMvnoParams()) { if (r != null && ApnSetting.mvnoMatches(r, dunSetting.mvnoType, dunSetting.mvnoMatchData)) { - if (VDBG) { - log("fetchDunApn: config_tether_apndata mvno dunSetting=" + dunSetting); - } - return dunSetting; + retDunSetting = dunSetting; + break; } } else if (mMvnoMatched == false) { retDunSetting = dunSetting; + break; } } } - if (VDBG) log("fetchDunApn: config_tether_apndata dunSetting=" + retDunSetting); + if (VDBG) log("fetchDunApn: dunSetting=" + retDunSetting); return retDunSetting; } @@ -2183,15 +2217,15 @@ public class DcTracker extends Handler { log("setInitialApn: E mPreferredApn=" + mPreferredApn); - if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) { + if (mPreferredApn != null && mPreferredApn.canHandleType(PhoneConstants.APN_TYPE_IA)) { + iaApnSetting = mPreferredApn; + } else if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) { firstApnSetting = mAllApnSettings.get(0); log("setInitialApn: firstApnSetting=" + firstApnSetting); // Search for Initial APN setting and the first apn that can handle default for (ApnSetting apn : mAllApnSettings) { - // Can't use apn.canHandleType(), as that returns true for APNs that have no type. - if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_IA) && - apn.carrierEnabled) { + if (apn.canHandleType(PhoneConstants.APN_TYPE_IA)) { // The Initial Attach APN is highest priority so use it if there is one log("setInitialApn: iaApnSetting=" + apn); iaApnSetting = apn; @@ -2460,6 +2494,10 @@ public class DcTracker extends Handler { // Tear down all metered apns cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN); } else { + // Re-evauluate Otasp state + int otaspState = mPhone.getServiceStateTracker().getOtasp(); + mPhone.notifyOtaspChanged(otaspState); + teardownRestrictedMeteredConnections(); setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED); } @@ -2703,6 +2741,16 @@ public class DcTracker extends Handler { // TODO change our retry manager to use the appropriate numbers for the new APN if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState"); applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet()); + + if ((enabled == DctConstants.DISABLED) && + isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology()) && + !isHigherPriorityApnContextActive(apnContext)) { + + if(DBG) log("onEnableApn: isOnlySingleDcAllowed true & higher priority APN disabled"); + // If the highest priority APN is disabled and only single + // data call is allowed, try to setup data call on other connectable APN. + setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION); + } } // TODO: We shouldnt need this. @@ -2823,6 +2871,10 @@ public class DcTracker extends Handler { if (!mDataEnabledSettings.isUserDataEnabled()) return; + // Note onRoamingOff will be called immediately when DcTracker registerForDataRoamingOff, + // and will be called again if SST calls mDataRoamingOffRegistrants.notify(). + setDataProfilesAsNeeded(); + if (getDataOnRoamingEnabled() == false) { notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF); setupDataOnConnectableApns(Phone.REASON_ROAMING_OFF); @@ -3357,27 +3409,29 @@ public class DcTracker extends Handler { } protected void setDataProfilesAsNeeded() { - if (DBG) log("setDataProfilesAsNeeded"); + if (DBG) log("setDataProfilesAsNeeded mSetDataProfileStatus: " + mSetDataProfileStatus); if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) { ArrayList<DataProfile> dps = new ArrayList<DataProfile>(); + // Note getDataRoaming is also false if data not registered + boolean isRoaming = mPhone.getServiceState().getDataRoaming(); + // If has set profile with home, and isRoaming is also false, no need to resend + // Also skip if has set profile with roaming and isRoaming is true. + if ((mSetDataProfileStatus == 1 && !isRoaming) || + (mSetDataProfileStatus == 2 && isRoaming)) { + return; + } for (ApnSetting apn : mAllApnSettings) { if (apn.modemCognitive) { - DataProfile dp = new DataProfile(apn, - mPhone.getServiceState().getDataRoaming()); - boolean isDup = false; - for(DataProfile dpIn : dps) { - if (dp.equals(dpIn)) { - isDup = true; - break; - } - } - if (!isDup) { + DataProfile dp = new DataProfile(apn, isRoaming); + // ArrayList.contains will call object.equals + if (!dps.contains(dp)) { dps.add(dp); } } } if(dps.size() > 0) { mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[0]), null); + mSetDataProfileStatus = isRoaming ? 2 : 1; } } } @@ -4295,6 +4349,7 @@ public class DcTracker extends Handler { pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation.get()); pw.println(" mIsScreenOn=" + mIsScreenOn); pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator); + pw.println(" mSetDataProfileStatus=" + mSetDataProfileStatus); pw.flush(); pw.println(" ***************************************"); DcController dcc = mDcc; diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 30c9f161f..f98e360ad 100644 --- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -34,7 +34,6 @@ import android.util.Log; import android.widget.Toast; import static com.android.internal.telephony.CommandsInterface.*; -import com.android.internal.telephony.gsm.SsData; import java.util.regex.Pattern; import java.util.regex.Matcher; @@ -1254,6 +1253,17 @@ public final class GsmMmiCode extends Handler implements MmiCode { } else if (err == CommandException.Error.FDN_CHECK_FAILURE) { Rlog.i(LOG_TAG, "FDN_CHECK_FAILURE"); sb.append(mContext.getText(com.android.internal.R.string.mmiFdnError)); + } else if (err == CommandException.Error.MODEM_ERR) { + // Some carriers do not allow changing call forwarding settings while roaming + // and will return an error from the modem. + if (isServiceCodeCallForwarding(mSc) + && mPhone.getServiceState().getVoiceRoaming() + && !mPhone.supports3gppCallForwardingWhileRoaming()) { + sb.append(mContext.getText( + com.android.internal.R.string.mmiErrorWhileRoaming)); + } else { + sb.append(getErrorMessage(ar)); + } } else { sb.append(getErrorMessage(ar)); } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java index 5514a3b6c..9e711210e 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java @@ -844,7 +844,7 @@ public class ImsPhone extends ImsPhoneBase { dialingNumber, serviceClass, timerSeconds, - onComplete); + resp); } catch (ImsException e) { sendErrorResponse(onComplete, e); } diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java index ffb404c61..4c0edb444 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java @@ -66,6 +66,7 @@ import com.android.ims.ImsUtInterface; import com.android.ims.internal.IImsVideoCallProvider; import com.android.ims.internal.ImsCallSession; import com.android.ims.internal.ImsVideoCallProviderWrapper; +import com.android.ims.internal.VideoPauseTracker; import com.android.internal.telephony.Call; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CallTracker; @@ -261,6 +262,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private Call.SrvccState mSrvccState = Call.SrvccState.NONE; private boolean mIsInEmergencyCall = false; + private boolean mIsDataEnabled = false; private int pendingCallClirMode; private int mPendingCallVideoState; @@ -269,6 +271,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private boolean mSwitchingFgAndBgCalls = false; private ImsCall mCallExpectedToResume = null; private boolean mAllowEmergencyVideoCalls = false; + private boolean mIgnoreDataEnabledChangedForVideoCalls = false; private Object mAddParticipantLock = new Object(); private Message mAddPartResp; @@ -317,6 +320,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private boolean mNotifyHandoverVideoFromWifiToLTE = false; /** + * Carrier configuration option which determines whether the carrier supports the + * {@link VideoProfile#STATE_PAUSED} signalling. + * See {@link CarrierConfigManager#KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL} for more information. + */ + private boolean mSupportPauseVideo = false; + + /** * Carrier configuration option which defines a mapping from pairs of * {@link ImsReasonInfo#getCode()} and {@link ImsReasonInfo#getExtraMessage()} values to a new * {@code ImsReasonInfo#CODE_*} value. @@ -325,6 +335,17 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { */ private Map<Pair<Integer, String>, Integer> mImsReasonCodeMap = new ArrayMap<>(); + /** + * TODO: Remove this code; it is a workaround. + * When {@code true}, forces {@link ImsManager#updateImsServiceConfig(Context, int, boolean)} to + * be called when an ongoing video call is disconnected. In some cases, where video pause is + * supported by the carrier, when {@link #onDataEnabledChanged(boolean, int)} reports that data + * has been disabled we will pause the video rather than disconnecting the call. When this + * happens we need to prevent the IMS service config from being updated, as this will cause VT + * to be disabled mid-call, resulting in an inability to un-pause the video. + */ + private boolean mShouldUpdateImsConfigOnDisconnect = false; + //***** Events @@ -617,6 +638,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { CarrierConfigManager.KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL); mNotifyHandoverVideoFromWifiToLTE = carrierConfig.getBoolean( CarrierConfigManager.KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL); + mIgnoreDataEnabledChangedForVideoCalls = carrierConfig.getBoolean( + CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS); + mSupportPauseVideo = carrierConfig.getBoolean( + CarrierConfigManager.KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL); String[] mappings = carrierConfig .getStringArray(CarrierConfigManager.KEY_IMS_REASONINFO_MAPPING_STRING_ARRAY); @@ -1719,6 +1744,13 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mCallExpectedToResume = null; } } + + if (mShouldUpdateImsConfigOnDisconnect) { + // Ensure we update the IMS config when the call is disconnected; we delayed this + // because a video call was paused. + ImsManager.updateImsServiceConfig(mPhone.getContext(), mPhone.getPhoneId(), true); + mShouldUpdateImsConfigOnDisconnect = false; + } } @Override @@ -2261,16 +2293,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { mPhone.notifyForVideoCapabilityChanged(isVideoCallEnabled()); } - // TODO: Use the ImsCallSession or ImsCallProfile to tell the initial Wifi state and - // {@link ImsCallSession.Listener#callSessionHandover} to listen for changes to - // wifi capability caused by a handover. if (DBG) log("onFeatureCapabilityChanged: isVolteEnabled=" + isVolteEnabled() + ", isVideoCallEnabled=" + isVideoCallEnabled() + ", isVowifiEnabled=" + isVowifiEnabled() + ", isUtEnabled=" + isUtEnabled()); - for (ImsPhoneConnection connection : mConnections) { - connection.updateWifiState(); - } mPhone.onFeatureCapabilityChanged(); @@ -2825,7 +2851,14 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { private void onDataEnabledChanged(boolean enabled, int reason) { log("onDataEnabledChanged: enabled=" + enabled + ", reason=" + reason); + ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId()).setDataEnabled(enabled); + mIsDataEnabled = enabled; + + if (mIgnoreDataEnabledChangedForVideoCalls) { + log("Ignore data " + ((enabled) ? "enabled" : "disabled") + " due to carrier policy."); + return; + } if (!enabled) { int reasonCode; @@ -2858,9 +2891,12 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { 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 { - // If the carrier does not support downgrading to voice, the only choice we - // have is to terminate the call. + // At this point the only choice we have is to terminate the call. try { imsCall.terminate(ImsReasonInfo.CODE_USER_TERMINATED, reasonCode); } catch (ImsException ie) { @@ -2869,11 +2905,27 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall { } } } + } 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); + if (VideoProfile.isPaused(conn.getVideoState()) && + conn.wasVideoPausedFromSource(VideoPauseTracker.SOURCE_DATA_ENABLED)) { + // The data enabled state was a cause of a pending pause, so potentially + // resume the video now. + conn.resumeVideo(VideoPauseTracker.SOURCE_DATA_ENABLED); + } + } + mShouldUpdateImsConfigOnDisconnect = false; } - // 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 (!mShouldUpdateImsConfigOnDisconnect) { + // 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); + } } /** diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java index 39096f5aa..87e91c78d 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java @@ -101,15 +101,7 @@ public class ImsPhoneConnection extends Connection implements */ private boolean mShouldIgnoreVideoStateChanges = false; - /** - * Used to indicate whether the wifi state is based on - * {@link com.android.ims.ImsConnectionStateListener# - * onFeatureCapabilityChanged(int, int[], int[])} callbacks, or values received via the - * {@link ImsCallProfile#EXTRA_CALL_RAT_TYPE} extra. Util we receive a value via the extras, - * we will use the wifi state based on the {@code onFeatureCapabilityChanged}. Once a value - * is received via the extras, we will prefer those values going forward. - */ - private boolean mIsWifiStateFromExtras = false; + private ImsVideoCallProviderWrapper mImsVideoCallProviderWrapper; //***** Event Constants private static final int EVENT_DTMF_DONE = 1; @@ -180,8 +172,6 @@ public class ImsPhoneConnection extends Connection implements mCreateTime = System.currentTimeMillis(); mUusInfo = null; - updateWifiState(); - // Ensure any extras set on the ImsCallProfile at the start of the call are cached locally // in the ImsPhoneConnection. This isn't going to inform any listeners (since the original // connection is not likely to be associated with a TelephonyConnection yet). @@ -697,13 +687,11 @@ public class ImsPhoneConnection extends Connection implements } boolean updateParent = mParent.update(this, imsCall, state); - boolean updateWifiState = updateWifiState(); boolean updateAddressDisplay = updateAddressDisplay(imsCall); boolean updateMediaCapabilities = updateMediaCapabilities(imsCall); boolean updateExtras = updateExtras(imsCall); - return updateParent || updateWifiState || updateAddressDisplay || updateMediaCapabilities - || updateExtras; + return updateParent || updateAddressDisplay || updateMediaCapabilities || updateExtras; } @Override @@ -902,28 +890,6 @@ public class ImsPhoneConnection extends Connection implements } /** - * Check for a change in the wifi state of the ImsPhoneCallTracker and update the - * {@link ImsPhoneConnection} with this information. - * - * @return Whether the ImsPhoneCallTracker's usage of wifi has been changed. - */ - public boolean updateWifiState() { - // If we've received the wifi state via the ImsCallProfile.EXTRA_CALL_RAT_TYPE extra, we - // will no longer use state updates which are based on the onFeatureCapabilityChanged - // callback. - if (mIsWifiStateFromExtras) { - return false; - } - - Rlog.d(LOG_TAG, "updateWifiState: " + mOwner.isVowifiEnabled()); - if (isWifi() != mOwner.isVowifiEnabled()) { - setWifi(mOwner.isVowifiEnabled()); - return true; - } - return false; - } - - /** * Updates the wifi state based on the {@link ImsCallProfile#EXTRA_CALL_RAT_TYPE}. * The call is considered to be a WIFI call if the extra value is * {@link ServiceState#RIL_RADIO_TECHNOLOGY_IWLAN}. @@ -934,10 +900,6 @@ public class ImsPhoneConnection extends Connection implements if (extras.containsKey(ImsCallProfile.EXTRA_CALL_RAT_TYPE) || extras.containsKey(ImsCallProfile.EXTRA_CALL_RAT_TYPE_ALT)) { - // We've received the extra indicating the radio technology, so we will continue to - // prefer the radio technology received via this extra going forward. - mIsWifiStateFromExtras = true; - ImsCall call = getImsCall(); boolean isWifi = false; if (call != null) { @@ -1059,6 +1021,15 @@ public class ImsPhoneConnection extends Connection implements return sb.toString(); } + @Override + public void setVideoProvider(android.telecom.Connection.VideoProvider videoProvider) { + super.setVideoProvider(videoProvider); + + if (videoProvider instanceof ImsVideoCallProviderWrapper) { + mImsVideoCallProviderWrapper = (ImsVideoCallProviderWrapper) videoProvider; + } + } + /** * Indicates whether current phone connection is emergency or not * @return boolean: true if emergency, false otherwise @@ -1110,4 +1081,46 @@ public class ImsPhoneConnection extends Connection implements setVideoState(currentVideoState); } } + + /** + * Issues a request to pause the video using {@link VideoProfile#STATE_PAUSED} from a source + * other than the InCall UI. + * + * @param source The source of the pause request. + */ + public void pauseVideo(int source) { + if (mImsVideoCallProviderWrapper == null) { + return; + } + + mImsVideoCallProviderWrapper.pauseVideo(getVideoState(), source); + } + + /** + * Issues a request to resume the video using {@link VideoProfile#STATE_PAUSED} from a source + * other than the InCall UI. + * + * @param source The source of the resume request. + */ + public void resumeVideo(int source) { + if (mImsVideoCallProviderWrapper == null) { + return; + } + + mImsVideoCallProviderWrapper.resumeVideo(getVideoState(), source); + } + + /** + * Determines if a specified source has issued a pause request. + * + * @param source The source. + * @return {@code true} if the source issued a pause request, {@code false} otherwise. + */ + public boolean wasVideoPausedFromSource(int source) { + if (mImsVideoCallProviderWrapper == null) { + return false; + } + + return mImsVideoCallProviderWrapper.wasVideoPausedFromSource(source); + } } diff --git a/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java b/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java index 1cf0825f5..42d38a4b3 100644 --- a/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java +++ b/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java @@ -21,6 +21,7 @@ import com.android.internal.telephony.TelephonyProto.ImsConnectionState; import com.android.internal.telephony.TelephonyProto.ImsReasonInfo; import com.android.internal.telephony.TelephonyProto.RilDataCall; import com.android.internal.telephony.TelephonyProto.TelephonyCallSession; +import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.RilCall; import com.android.internal.telephony.TelephonyProto.TelephonyServiceState; import com.android.internal.telephony.TelephonyProto.TelephonySettings; @@ -124,4 +125,9 @@ public class CallSessionEventBuilder { mEvent.setNitzTimestampMillis(timestamp); return this; } + + public CallSessionEventBuilder setRilCalls(RilCall[] rilCalls) { + mEvent.calls = rilCalls; + return this; + } } diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java index 92e3f0af7..eddb1c0c4 100644 --- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java +++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java @@ -21,11 +21,14 @@ import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.TelephonyHistogram; import android.util.Base64; +import android.util.Log; import android.util.SparseArray; import com.android.ims.ImsConfig; import com.android.ims.ImsReasonInfo; import com.android.ims.internal.ImsCallSession; +import com.android.internal.telephony.Call; +import com.android.internal.telephony.GsmCdmaConnection; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.RIL; import com.android.internal.telephony.RILConstants; @@ -36,6 +39,9 @@ import com.android.internal.telephony.TelephonyProto.ImsConnectionState; import com.android.internal.telephony.TelephonyProto.RilDataCall; import com.android.internal.telephony.TelephonyProto.SmsSession; import com.android.internal.telephony.TelephonyProto.TelephonyCallSession; +import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.RilCall; +import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.RilCall.Type.*; +import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.CallState.*; import com.android.internal.telephony.TelephonyProto.TelephonyEvent; import com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilDeactivateDataCall; import com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilSetupDataCall; @@ -58,6 +64,7 @@ import java.util.Deque; import java.util.List; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; + import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ANSWER; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_CDMA_SEND_SMS; import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE_DATA_CALL; @@ -1012,22 +1019,106 @@ public class TelephonyMetrics { } /** + * Write CS call list event + * + * @param phoneId Phone id + * @param connections Array of GsmCdmaConnection objects + */ + public void writeRilCallList(int phoneId, ArrayList<GsmCdmaConnection> connections) { + if (VDBG) { + Rlog.v(TAG, "Logging CallList Changed Connections Size = " + connections.size()); + } + InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId); + if (callSession == null) { + Rlog.e(TAG, "writeRilCallList: Call session is missing"); + } else { + RilCall[] calls = convertConnectionsToRilCalls(connections); + callSession.addEvent( + new CallSessionEventBuilder( + TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED) + .setRilCalls(calls) + ); + if (VDBG) Rlog.v(TAG, "Logged Call list changed"); + } + } + + private RilCall[] convertConnectionsToRilCalls(ArrayList<GsmCdmaConnection> mConnections) { + RilCall[] calls = new RilCall[mConnections.size()]; + for (int i = 0; i < mConnections.size(); i++) { + calls[i] = new RilCall(); + calls[i].setIndex(i); + convertConnectionToRilCall(mConnections.get(i), calls[i]); + } + return calls; + } + + private void convertConnectionToRilCall(GsmCdmaConnection conn, RilCall call) { + if (conn.isIncoming()) { + call.setType(TelephonyCallSession.Event.RilCall.Type.MT); + } else { + call.setType(TelephonyCallSession.Event.RilCall.Type.MO); + } + switch (conn.getState()) { + case IDLE: + call.setState(TelephonyCallSession.Event.CallState.CALL_IDLE); + break; + case ACTIVE: + call.setState(TelephonyCallSession.Event.CallState.CALL_ACTIVE); + break; + case HOLDING: + call.setState(TelephonyCallSession.Event.CallState.CALL_HOLDING); + break; + case DIALING: + call.setState(TelephonyCallSession.Event.CallState.CALL_DIALING); + break; + case ALERTING: + call.setState(TelephonyCallSession.Event.CallState.CALL_ALERTING); + break; + case INCOMING: + call.setState(TelephonyCallSession.Event.CallState.CALL_INCOMING); + break; + case WAITING: + call.setState(TelephonyCallSession.Event.CallState.CALL_WAITING); + break; + case DISCONNECTED: + call.setState(TelephonyCallSession.Event.CallState.CALL_DISCONNECTED); + break; + case DISCONNECTING: + call.setState(TelephonyCallSession.Event.CallState.CALL_DISCONNECTING); + break; + default: + call.setState(TelephonyCallSession.Event.CallState.CALL_UNKNOWN); + break; + } + call.setCallEndReason(conn.getDisconnectCause()); + call.setIsMultiparty(conn.isMultiparty()); + } + + /** * Write dial event * * @param phoneId Phone id - * @param rilSerial RIL request serial number + * @param conn Connection object created to track this call * @param clirMode CLIR (Calling Line Identification Restriction) mode * @param uusInfo User-to-User signaling Info */ - public void writeRilDial(int phoneId, int rilSerial, int clirMode, UUSInfo uusInfo) { + public void writeRilDial(int phoneId, GsmCdmaConnection conn, int clirMode, UUSInfo uusInfo) { InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId); - - callSession.addEvent(callSession.startElapsedTimeMs, - new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST) - .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL) - .setRilRequestId(rilSerial) - ); + if (VDBG) Rlog.v(TAG, "Logging Dial Connection = " + conn); + if (callSession == null) { + Rlog.e(TAG, "writeRilDial: Call session is missing"); + } else { + RilCall[] calls = new RilCall[1]; + calls[0] = new RilCall(); + calls[0].setIndex(-1); + convertConnectionToRilCall(conn, calls[0]); + callSession.addEvent(callSession.startElapsedTimeMs, + new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST) + .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL) + .setRilCalls(calls)); + if (VDBG) Rlog.v(TAG, "Logged Dial event"); + } } /** @@ -1047,19 +1138,23 @@ public class TelephonyMetrics { * Write call hangup event * * @param phoneId Phone id - * @param rilSerial RIL request serial number + * @param conn Connection object associated with the call that is being hung-up * @param callId Call id */ - public void writeRilHangup(int phoneId, int rilSerial, int callId) { + public void writeRilHangup(int phoneId, GsmCdmaConnection conn, int callId) { InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); if (callSession == null) { - Rlog.e(TAG, "Call session is missing"); + Rlog.e(TAG, "writeRilHangup: Call session is missing"); } else { + RilCall[] calls = new RilCall[1]; + calls[0] = new RilCall(); + calls[0].setIndex(callId); + convertConnectionToRilCall(conn, calls[0]); callSession.addEvent( new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST) .setRilRequest(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_HANGUP) - .setRilRequestId(rilSerial) - .setCallIndex(callId)); + .setRilCalls(calls)); + if (VDBG) Rlog.v(TAG, "Logged Hangup event"); } } @@ -1072,7 +1167,7 @@ public class TelephonyMetrics { public void writeRilAnswer(int phoneId, int rilSerial) { InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); if (callSession == null) { - Rlog.e(TAG, "Call session is missing"); + Rlog.e(TAG, "writeRilAnswer: Call session is missing"); } else { callSession.addEvent( new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST) @@ -1090,7 +1185,7 @@ public class TelephonyMetrics { public void writeRilSrvcc(int phoneId, int rilSrvccState) { InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); if (callSession == null) { - Rlog.e(TAG, "Call session is missing"); + Rlog.e(TAG, "writeRilSrvcc: Call session is missing"); } else { callSession.addEvent( new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_CALL_SRVCC) @@ -1180,7 +1275,7 @@ public class TelephonyMetrics { int rilRequest) { InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); if (callSession == null) { - Rlog.e(TAG, "Call session is missing"); + Rlog.e(TAG, "writeOnCallSolicitedResponse: Call session is missing"); } else { callSession.addEvent(new CallSessionEventBuilder( TelephonyCallSession.Event.Type.RIL_RESPONSE) @@ -1295,7 +1390,7 @@ public class TelephonyMetrics { InProgressCallSession callSession = mInProgressCallSessions.get(phoneId); if (callSession == null) { - Rlog.e(TAG, "Call session is missing"); + Rlog.e(TAG, "writePhoneState: Call session is missing"); } else { if (state == TelephonyCallSession.Event.PhoneState.STATE_IDLE) { finishCallSession(callSession); diff --git a/src/java/com/android/internal/telephony/uicc/IccConstants.java b/src/java/com/android/internal/telephony/uicc/IccConstants.java index 5ed699ec9..01c3570dc 100644 --- a/src/java/com/android/internal/telephony/uicc/IccConstants.java +++ b/src/java/com/android/internal/telephony/uicc/IccConstants.java @@ -30,21 +30,21 @@ public interface IccConstants { static final int EF_EXT2 = 0x6F4B; static final int EF_EXT3 = 0x6F4C; static final int EF_EXT5 = 0x6F4E; - static final int EF_EXT6 = 0x6fc8; // Ext record for EF[MBDN] + static final int EF_EXT6 = 0x6FC8; // Ext record for EF[MBDN] static final int EF_MWIS = 0x6FCA; - static final int EF_MBDN = 0x6fc7; - static final int EF_PNN = 0x6fc5; - static final int EF_OPL = 0x6fc6; + static final int EF_MBDN = 0x6FC7; + static final int EF_PNN = 0x6FC5; + static final int EF_OPL = 0x6FC6; static final int EF_SPN = 0x6F46; static final int EF_SMS = 0x6F3C; - static final int EF_ICCID = 0x2fe2; + static final int EF_ICCID = 0x2FE2; static final int EF_AD = 0x6FAD; - static final int EF_MBI = 0x6fc9; - static final int EF_MSISDN = 0x6f40; - static final int EF_SPDI = 0x6fcd; - static final int EF_SST = 0x6f38; + static final int EF_MBI = 0x6FC9; + static final int EF_MSISDN = 0x6F40; + static final int EF_SPDI = 0x6FCD; + static final int EF_SST = 0x6F38; static final int EF_CFIS = 0x6FCB; - static final int EF_IMG = 0x4f20; + static final int EF_IMG = 0x4F20; // USIM SIM file ids from TS 131.102 public static final int EF_PBR = 0x4F30; @@ -54,13 +54,13 @@ public interface IccConstants { static final int EF_MAILBOX_CPHS = 0x6F17; static final int EF_VOICE_MAIL_INDICATOR_CPHS = 0x6F11; static final int EF_CFF_CPHS = 0x6F13; - static final int EF_SPN_CPHS = 0x6f14; - static final int EF_SPN_SHORT_CPHS = 0x6f18; - static final int EF_INFO_CPHS = 0x6f16; - static final int EF_CSP_CPHS = 0x6f15; + static final int EF_SPN_CPHS = 0x6F14; + static final int EF_SPN_SHORT_CPHS = 0x6F18; + static final int EF_INFO_CPHS = 0x6F16; + static final int EF_CSP_CPHS = 0x6F15; // CDMA RUIM file ids from 3GPP2 C.S0023-0 - static final int EF_CST = 0x6f32; + static final int EF_CST = 0x6F32; static final int EF_RUIM_SPN =0x6F41; // ETSI TS.102.221 @@ -79,12 +79,27 @@ public interface IccConstants { static final int EF_CSIM_MIPUPP = 0x6F4D; //ISIM access - static final int EF_IMPU = 0x6f04; - static final int EF_IMPI = 0x6f02; - static final int EF_DOMAIN = 0x6f03; - static final int EF_IST = 0x6f07; - static final int EF_PCSCF = 0x6f09; - static final int EF_PSI = 0x6fe5; + static final int EF_IMPU = 0x6F04; + static final int EF_IMPI = 0x6F02; + static final int EF_DOMAIN = 0x6F03; + static final int EF_IST = 0x6F07; + static final int EF_PCSCF = 0x6F09; + static final int EF_PSI = 0x6FE5; + + //PLMN Selection Information w/ Access Technology TS 131.102 + static final int EF_PLMN_W_ACT = 0x6F60; + static final int EF_OPLMN_W_ACT = 0x6F61; + static final int EF_HPLMN_W_ACT = 0x6F62; + + //Equivalent Home and Forbidden PLMN Lists TS 131.102 + static final int EF_EHPLMN = 0x6FD9; + static final int EF_FPLMN = 0x6F7B; + + // Last Roaming Selection Indicator + static final int EF_LRPLMNSI = 0x6FDC; + + //Search interval for higher priority PLMNs + static final int EF_HPPLMN = 0x6F31; //plmnwact static final int EF_PLMNWACT = 0x6F60; diff --git a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java index 54e05f7ca..6f944bda1 100644 --- a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java @@ -17,6 +17,7 @@ package com.android.internal.telephony.uicc; import android.os.*; + import com.android.internal.telephony.CommandsInterface; import java.util.ArrayList; @@ -25,6 +26,7 @@ import java.util.ArrayList; * {@hide} */ public abstract class IccFileHandler extends Handler implements IccConstants { + private static final boolean VDBG = false; //from TS 11.11 9.1 or elsewhere static protected final int COMMAND_READ_BINARY = 0xb0; @@ -550,6 +552,11 @@ public abstract class IccFileHandler extends Handler implements IccConstants { size = tlvData.mFileSize; } else { + if (VDBG) { + logd(String.format("Contents of the Select Response for command %x: ", fileid) + + IccUtils.bytesToHexString(data)); + } + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { throw new IccFileTypeMismatch(); } @@ -663,7 +670,6 @@ public abstract class IccFileHandler extends Handler implements IccConstants { protected abstract String getEFPath(int efid); protected abstract void logd(String s); - protected abstract void loge(String s); } diff --git a/src/java/com/android/internal/telephony/uicc/IccIoResult.java b/src/java/com/android/internal/telephony/uicc/IccIoResult.java index 6f0b5c3fd..4a35e1460 100644 --- a/src/java/com/android/internal/telephony/uicc/IccIoResult.java +++ b/src/java/com/android/internal/telephony/uicc/IccIoResult.java @@ -22,6 +22,147 @@ package com.android.internal.telephony.uicc; */ public class IccIoResult { + + private static final String UNKNOWN_ERROR = "unknown"; + + private String getErrorString() { + // Errors from 3gpp 11.11 9.4.1 + // Additional Errors from ETSI 102.221 + // + // All error codes below are copied directly from their respective specification + // without modification except in cases where necessary string formatting has been omitted. + switch(sw1) { + case 0x62: + switch(sw2) { + case 0x00: return "No information given," + + " state of non volatile memory unchanged"; + case 0x81: return "Part of returned data may be corrupted"; + case 0x82: return "End of file/record reached before reading Le bytes"; + case 0x83: return "Selected file invalidated"; + case 0x84: return "Selected file in termination state"; + case 0xF1: return "More data available"; + case 0xF2: return "More data available and proactive command pending"; + case 0xF3: return "Response data available"; + } + break; + case 0x63: + if (sw2 >> 4 == 0x0C) { + return "Command successful but after using an internal" + + "update retry routine but Verification failed"; + } + switch(sw2) { + case 0xF1: return "More data expected"; + case 0xF2: return "More data expected and proactive command pending"; + } + break; + case 0x64: + switch(sw2) { + case 0x00: return "No information given," + + " state of non-volatile memory unchanged"; + } + break; + case 0x65: + switch(sw2) { + case 0x00: return "No information given, state of non-volatile memory changed"; + case 0x81: return "Memory problem"; + } + break; + case 0x67: + switch(sw2) { + case 0x00: return "incorrect parameter P3"; + default: return "The interpretation of this status word is command dependent"; + } + // break; + case 0x6B: return "incorrect parameter P1 or P2"; + case 0x6D: return "unknown instruction code given in the command"; + case 0x6E: return "wrong instruction class given in the command"; + case 0x6F: + switch(sw2) { + case 0x00: return "technical problem with no diagnostic given"; + default: return "The interpretation of this status word is command dependent"; + } + // break; + case 0x68: + switch(sw2) { + case 0x00: return "No information given"; + case 0x81: return "Logical channel not supported"; + case 0x82: return "Secure messaging not supported"; + } + break; + case 0x69: + switch(sw2) { + case 0x00: return "No information given"; + case 0x81: return "Command incompatible with file structure"; + case 0x82: return "Security status not satisfied"; + case 0x83: return "Authentication/PIN method blocked"; + case 0x84: return "Referenced data invalidated"; + case 0x85: return "Conditions of use not satisfied"; + case 0x86: return "Command not allowed (no EF selected)"; + case 0x89: return "Command not allowed - secure channel -" + + " security not satisfied"; + } + break; + case 0x6A: + switch(sw2) { + case 0x80: return "Incorrect parameters in the data field"; + case 0x81: return "Function not supported"; + case 0x82: return "File not found"; + case 0x83: return "Record not found"; + case 0x84: return "Not enough memory space"; + case 0x86: return "Incorrect parameters P1 to P2"; + case 0x87: return "Lc inconsistent with P1 to P2"; + case 0x88: return "Referenced data not found"; + } + break; + case 0x90: return null; // success + case 0x91: return null; // success + //Status Code 0x92 has contradictory meanings from 11.11 and 102.221 10.2.1.1 + case 0x92: + if (sw2 >> 4 == 0) { + return "command successful but after using an internal update retry routine"; + } + switch(sw2) { + case 0x40: return "memory problem"; + } + break; + case 0x93: + switch(sw2) { + case 0x00: + return "SIM Application Toolkit is busy. Command cannot be executed" + + " at present, further normal commands are allowed."; + } + break; + case 0x94: + switch(sw2) { + case 0x00: return "no EF selected"; + case 0x02: return "out f range (invalid address)"; + case 0x04: return "file ID not found/pattern not found"; + case 0x08: return "file is inconsistent with the command"; + } + break; + case 0x98: + switch(sw2) { + case 0x02: return "no CHV initialized"; + case 0x04: return "access condition not fulfilled/" + + "unsuccessful CHV verification, at least one attempt left/" + + "unsuccessful UNBLOCK CHV verification, at least one attempt left/" + + "authentication failed"; + case 0x08: return "in contradiction with CHV status"; + case 0x10: return "in contradiction with invalidation status"; + case 0x40: return "unsuccessful CHV verification, no attempt left/" + + "unsuccessful UNBLOCK CHV verification, no attempt left/" + + "CHV blocked" + + "UNBLOCK CHV blocked"; + case 0x50: return "increase cannot be performed, Max value reached"; + } + break; + case 0x9E: return null; // success + case 0x9F: return null; // success + } + return UNKNOWN_ERROR; + } + + public int sw1; public int sw2; @@ -39,8 +180,8 @@ IccIoResult { @Override public String toString() { - return "IccIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x" - + Integer.toHexString(sw2); + return "IccIoResult sw1:0x" + Integer.toHexString(sw1) + " sw2:0x" + + Integer.toHexString(sw2) + ((!success()) ? " Error: " + getErrorString() : ""); } /** diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java index 41dbe46e2..b180010ac 100644 --- a/src/java/com/android/internal/telephony/uicc/IccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java @@ -22,6 +22,7 @@ import android.os.Handler; import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; + import android.telephony.Rlog; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; @@ -90,6 +91,13 @@ public abstract class IccRecords extends Handler implements IccConstants { protected String mGid2; protected String mPrefLang; + protected PlmnActRecord[] mHplmnActRecords; + protected PlmnActRecord[] mOplmnActRecords; + protected PlmnActRecord[] mPlmnActRecords; + + protected String[] mEhplmns; + protected String[] mFplmns; + private final Object mLock = new Object(); // ***** Constants @@ -103,7 +111,6 @@ public abstract class IccRecords extends Handler implements IccConstants { public static final int SPN_RULE_SHOW_PLMN = 0x02; // ***** Event Constants - protected static final int EVENT_SET_MSISDN_DONE = 30; public static final int EVENT_MWI = 0; // Message Waiting indication public static final int EVENT_CFI = 1; // Call Forwarding indication public static final int EVENT_SPN = 2; // Service Provider Name @@ -332,34 +339,13 @@ public abstract class IccRecords extends Handler implements IccConstants { return null; } - /** - * Set subscriber number to SIM record - * - * The subscriber number is stored in EF_MSISDN (TS 51.011) - * - * When the operation is complete, onComplete will be sent to its handler - * - * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters) - * @param number dailing nubmer (up to 20 digits) - * if the number starts with '+', then set to international TOA - * @param onComplete - * onComplete.obj will be an AsyncResult - * ((AsyncResult)onComplete.obj).exception == null on success - * ((AsyncResult)onComplete.obj).exception != null on fail - */ public void setMsisdnNumber(String alphaTag, String number, Message onComplete) { - - mMsisdn = number; - mMsisdnTag = alphaTag; - - if (DBG) log("Set MSISDN: " + mMsisdnTag +" " + mMsisdn); - - - AdnRecord adn = new AdnRecord(mMsisdnTag, mMsisdn); - - new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null, - obtainMessage(EVENT_SET_MSISDN_DONE, onComplete)); + loge("setMsisdn() should not be invoked on base IccRecords"); + // synthesize a "File Not Found" exception and return it + AsyncResult.forMessage(onComplete).exception = + (new IccIoResult(0x6A, 0x82, (byte[]) null)).getException(); + onComplete.sendToTarget(); } public String getMsisdnAlphaTag() { diff --git a/src/java/com/android/internal/telephony/uicc/IccUtils.java b/src/java/com/android/internal/telephony/uicc/IccUtils.java index fdcc12537..67de87f2b 100644 --- a/src/java/com/android/internal/telephony/uicc/IccUtils.java +++ b/src/java/com/android/internal/telephony/uicc/IccUtils.java @@ -23,6 +23,7 @@ import android.graphics.Color; import android.telephony.Rlog; import com.android.internal.telephony.GsmAlphabet; + import java.io.UnsupportedEncodingException; /** @@ -61,6 +62,28 @@ public class IccUtils { } /** + * PLMN (MCC/MNC) is encoded as per 24.008 10.5.1.3 + * Returns a concatenated string of MCC+MNC, stripping + * a trailing character for a 2-digit MNC + */ + public static String bcdPlmnToString(byte[] data, int offset) { + if (offset + 3 > data.length) { + return null; + } + byte[] trans = new byte[3]; + trans[0] = (byte) ((data[0 + offset] << 4) | ((data[0 + offset] >> 4) & 0xF)); + trans[1] = (byte) ((data[1 + offset] << 4) | (data[2 + offset] & 0xF)); + trans[2] = (byte) ((data[2 + offset] & 0xF0) | ((data[1 + offset] >> 4) & 0xF)); + String ret = bytesToHexString(trans); + + // For a 2-digit MNC we trim the trailing 'f' + if (ret.endsWith("f")) { + ret = ret.substring(0, ret.length() - 1); + } + return ret; + } + + /** * Some fields (like ICC ID) in GSM SIMs are stored as nibble-swizzled BCH */ public static String diff --git a/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java b/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java new file mode 100644 index 000000000..a4cf7cc1c --- /dev/null +++ b/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.uicc; + +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.Rlog; + +import java.util.Arrays; + +/** + * {@hide} + */ +public class PlmnActRecord implements Parcelable { + private static final String LOG_TAG = "PlmnActRecord"; + + // Values specified in 3GPP 31.102 sec. 4.2.5 + public static final int ACCESS_TECH_UTRAN = 0x8000; + public static final int ACCESS_TECH_EUTRAN = 0x4000; + public static final int ACCESS_TECH_GSM = 0x0080; + public static final int ACCESS_TECH_GSM_COMPACT = 0x0040; + public static final int ACCESS_TECH_CDMA2000_HRPD = 0x0020; + public static final int ACCESS_TECH_CDMA2000_1XRTT = 0x0010; + public static final int ACCESS_TECH_RESERVED = 0x3F0F; + + public static final int ENCODED_LENGTH = 5; + + public final String plmn; + public final int accessTechs; + + private static final boolean VDBG = true; + + public static final Parcelable.Creator<PlmnActRecord> CREATOR = + new Parcelable.Creator<PlmnActRecord>() { + @Override + public PlmnActRecord createFromParcel(Parcel source) { + return new PlmnActRecord(source.readString(), source.readInt()); + } + + @Override + public PlmnActRecord[] newArray(int size) { + return new PlmnActRecord[size]; + } + }; + + /* From 3gpp 31.102 section 4.2.5 + * Bytes 0-2 bcd-encoded PLMN-ID + * Bytes 3-4 bitfield of access technologies + */ + public PlmnActRecord(byte[] bytes, int offset) { + if (VDBG) Rlog.v(LOG_TAG, "Creating PlmnActRecord " + offset); + this.plmn = IccUtils.bcdPlmnToString(bytes, offset); + this.accessTechs = ((int) bytes[offset + 3] << 8) | bytes[offset + 4]; + } + + private PlmnActRecord(String plmn, int accessTechs) { + this.plmn = plmn; + this.accessTechs = accessTechs; + } + + private String accessTechString() { + if (accessTechs == 0) { + return "NONE"; + } + + StringBuilder sb = new StringBuilder(); + if ((accessTechs & ACCESS_TECH_UTRAN) != 0) { + sb.append("UTRAN|"); + } + if ((accessTechs & ACCESS_TECH_EUTRAN) != 0) { + sb.append("EUTRAN|"); + } + if ((accessTechs & ACCESS_TECH_GSM) != 0) { + sb.append("GSM|"); + } + if ((accessTechs & ACCESS_TECH_GSM_COMPACT) != 0) { + sb.append("GSM_COMPACT|"); + } + if ((accessTechs & ACCESS_TECH_CDMA2000_HRPD) != 0) { + sb.append("CDMA2000_HRPD|"); + } + if ((accessTechs & ACCESS_TECH_CDMA2000_1XRTT) != 0) { + sb.append("CDMA2000_1XRTT|"); + } + if ((accessTechs & ACCESS_TECH_RESERVED) != 0) { + sb.append(String.format("UNKNOWN:%x|", accessTechs & ACCESS_TECH_RESERVED)); + } + // Trim the tailing pipe character + return sb.substring(0, sb.length() - 1); + } + + @Override + public String toString() { + return String.format("{PLMN=%s,AccessTechs=%s}", plmn, accessTechString()); + } + + /** + * Convenience method for extracting all records from encoded bytes + */ + public static PlmnActRecord[] getRecords(byte[] recordBytes) { + if (recordBytes == null || recordBytes.length == 0 + || recordBytes.length % ENCODED_LENGTH != 0) { + Rlog.e(LOG_TAG, "Malformed PlmnActRecord, bytes: " + + ((recordBytes != null) ? Arrays.toString(recordBytes) : null)); + return null; + } + int numRecords = recordBytes.length / ENCODED_LENGTH; + if (VDBG) Rlog.v(LOG_TAG, "Extracting Logs, count=" + numRecords); + + PlmnActRecord[] records = new PlmnActRecord[numRecords]; + + for(int i = 0; i < numRecords; i++) { + records[i] = new PlmnActRecord(recordBytes, i * ENCODED_LENGTH); + } + return records; + } + + // Parcelable Implementation + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(plmn); + dest.writeInt(accessTechs); + } + +} diff --git a/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java b/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java index 4d782a31f..2bcf04275 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java @@ -56,8 +56,6 @@ public final class SIMFileHandler extends IccFileHandler implements IccConstants case EF_CFIS: case EF_GID1: case EF_GID2: - return MF_SIM + DF_GSM; - case EF_MAILBOX_CPHS: case EF_VOICE_MAIL_INDICATOR_CPHS: case EF_CFF_CPHS: diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index f50d5d392..ccae4b33a 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -20,10 +20,12 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.os.AsyncResult; import android.os.Message; import android.telephony.CarrierConfigManager; import android.telephony.PhoneNumberUtils; +import android.telephony.Rlog; import android.telephony.SmsMessage; import android.telephony.SubscriptionInfo; import android.text.TextUtils; @@ -52,6 +54,8 @@ public class SIMRecords extends IccRecords { private static final boolean CRASH_RIL = false; + private static final boolean VDBG = false; + // ***** Instance Variables VoiceMailConstants mVmConfig; @@ -139,35 +143,46 @@ public class SIMRecords extends IccRecords { private static final int CFIS_ADN_EXTENSION_ID_OFFSET = 15; // ***** Event Constants - private static final int EVENT_GET_IMSI_DONE = 3; - private static final int EVENT_GET_ICCID_DONE = 4; - private static final int EVENT_GET_MBI_DONE = 5; - private static final int EVENT_GET_MBDN_DONE = 6; - private static final int EVENT_GET_MWIS_DONE = 7; - private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8; - protected static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM - protected static final int EVENT_GET_MSISDN_DONE = 10; - private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11; - private static final int EVENT_GET_SPN_DONE = 12; - private static final int EVENT_GET_SPDI_DONE = 13; - private static final int EVENT_UPDATE_DONE = 14; - private static final int EVENT_GET_PNN_DONE = 15; - protected static final int EVENT_GET_SST_DONE = 17; - private static final int EVENT_GET_ALL_SMS_DONE = 18; - private static final int EVENT_MARK_SMS_READ_DONE = 19; - private static final int EVENT_SET_MBDN_DONE = 20; - private static final int EVENT_SMS_ON_SIM = 21; - private static final int EVENT_GET_SMS_DONE = 22; - private static final int EVENT_GET_CFF_DONE = 24; - private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25; - private static final int EVENT_GET_INFO_CPHS_DONE = 26; - // private static final int EVENT_SET_MSISDN_DONE = 30; Defined in IccRecords as 30 - private static final int EVENT_GET_CFIS_DONE = 32; - private static final int EVENT_GET_CSP_CPHS_DONE = 33; - private static final int EVENT_GET_GID1_DONE = 34; - private static final int EVENT_APP_LOCKED = 35; - private static final int EVENT_GET_GID2_DONE = 36; - private static final int EVENT_CARRIER_CONFIG_CHANGED = 37; + private static final int SIM_RECORD_EVENT_BASE = 0x00; + private static final int EVENT_GET_IMSI_DONE = 3 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_ICCID_DONE = 4 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_MBI_DONE = 5 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_MBDN_DONE = 6 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_MWIS_DONE = 7 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_AD_DONE = 9 + SIM_RECORD_EVENT_BASE; // Admin data on SIM + private static final int EVENT_GET_MSISDN_DONE = 10 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_SPN_DONE = 12 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_SPDI_DONE = 13 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_UPDATE_DONE = 14 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_PNN_DONE = 15 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_SST_DONE = 17 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_ALL_SMS_DONE = 18 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_MARK_SMS_READ_DONE = 19 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_SET_MBDN_DONE = 20 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_SMS_ON_SIM = 21 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_SMS_DONE = 22 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_CFF_DONE = 24 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_INFO_CPHS_DONE = 26 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_SET_MSISDN_DONE = 30 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_CFIS_DONE = 32 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_CSP_CPHS_DONE = 33 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_GID1_DONE = 34 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_GID2_DONE = 36 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_PLMN_W_ACT_DONE = 37 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_OPLMN_W_ACT_DONE = 38 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_HPLMN_W_ACT_DONE = 39 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_EHPLMN_DONE = 40 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_FPLMN_DONE = 41 + SIM_RECORD_EVENT_BASE; + + // TODO: Possibly move these to IccRecords.java + private static final int SYSTEM_EVENT_BASE = 0x100; + private static final int EVENT_CARRIER_CONFIG_CHANGED = 1 + SYSTEM_EVENT_BASE; + private static final int EVENT_APP_LOCKED = 2 + SYSTEM_EVENT_BASE; + private static final int EVENT_SIM_REFRESH = 3 + SYSTEM_EVENT_BASE; + // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length. @@ -260,6 +275,11 @@ public class SIMRecords extends IccRecords { mPnnHomeName = null; mGid1 = null; mGid2 = null; + mPlmnActRecords = null; + mOplmnActRecords = null; + mHplmnActRecords = null; + mFplmns = null; + mEhplmns = null; mAdnCache.reset(); @@ -1230,6 +1250,72 @@ public class SIMRecords extends IccRecords { break; + case EVENT_GET_PLMN_W_ACT_DONE: + ar = (AsyncResult) msg.obj; + data = (byte[]) ar.result; + + if (ar.exception != null || data == null) { + loge("Failed getting User PLMN with Access Tech Records: " + ar.exception); + break; + } else { + log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data)); + mPlmnActRecords = PlmnActRecord.getRecords(data); + if (VDBG) log("PlmnActRecords=" + Arrays.toString(mPlmnActRecords)); + } + break; + + case EVENT_GET_OPLMN_W_ACT_DONE: + ar = (AsyncResult) msg.obj; + data = (byte[]) ar.result; + + if (ar.exception != null || data == null) { + loge("Failed getting Operator PLMN with Access Tech Records: " + + ar.exception); + break; + } else { + log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data)); + mOplmnActRecords = PlmnActRecord.getRecords(data); + if (VDBG) log("OplmnActRecord[]=" + Arrays.toString(mOplmnActRecords)); + } + break; + + case EVENT_GET_HPLMN_W_ACT_DONE: + ar = (AsyncResult) msg.obj; + data = (byte[]) ar.result; + + if (ar.exception != null || data == null) { + loge("Failed getting Home PLMN with Access Tech Records: " + ar.exception); + break; + } else { + log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data)); + mHplmnActRecords = PlmnActRecord.getRecords(data); + log("HplmnActRecord[]=" + Arrays.toString(mHplmnActRecords)); + } + break; + + case EVENT_GET_EHPLMN_DONE: + ar = (AsyncResult) msg.obj; + data = (byte[]) ar.result; + if (ar.exception != null || data == null) { + loge("Failed getting Equivalent Home PLMNs: " + ar.exception); + break; + } else { + mEhplmns = parseBcdPlmnList(data, "Equivalent Home"); + } + break; + + case EVENT_GET_FPLMN_DONE: + isRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + data = (byte[]) ar.result; + if (ar.exception != null || data == null) { + loge("Failed getting Forbidden PLMNs: " + ar.exception); + break; + } else { + mFplmns = parseBcdPlmnList(data, "Forbidden"); + } + break; + case EVENT_CARRIER_CONFIG_CHANGED: handleCarrierNameOverride(); break; @@ -1620,6 +1706,17 @@ public class SIMRecords extends IccRecords { mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE)); mRecordsToLoad++; + mFh.loadEFTransparent(EF_PLMN_W_ACT, obtainMessage(EVENT_GET_PLMN_W_ACT_DONE)); + + mFh.loadEFTransparent(EF_OPLMN_W_ACT, obtainMessage(EVENT_GET_OPLMN_W_ACT_DONE)); + + mFh.loadEFTransparent(EF_HPLMN_W_ACT, obtainMessage(EVENT_GET_HPLMN_W_ACT_DONE)); + + mFh.loadEFTransparent(EF_EHPLMN, obtainMessage(EVENT_GET_EHPLMN_DONE)); + + mFh.loadEFTransparent(EF_FPLMN, obtainMessage(EVENT_GET_FPLMN_DONE)); + mRecordsToLoad++; + loadEfLiAndEfPl(); mFh.getEFLinearRecordSize(EF_SMS, obtainMessage(EVENT_GET_SMS_RECORD_SIZE_DONE)); @@ -1913,6 +2010,25 @@ public class SIMRecords extends IccRecords { } /** + * convert a byte array of packed plmns to an array of strings + */ + private String[] parseBcdPlmnList(byte[] data, String description) { + final int packedBcdPlmnLenBytes = 3; + log("Received " + description + " PLMNs, raw=" + IccUtils.bytesToHexString(data)); + if (data.length == 0 || (data.length % packedBcdPlmnLenBytes) != 0) { + loge("Received invalid " + description + " PLMN list"); + return null; + } + int numPlmns = data.length / packedBcdPlmnLenBytes; + String[] ret = new String[numPlmns]; + for (int i = 0; i < numPlmns; i++) { + ret[i] = IccUtils.bcdPlmnToString(data, i * packedBcdPlmnLenBytes); + } + if (VDBG) logv(description + " PLMNs: " + Arrays.toString(ret)); + return ret; + } + + /** * check to see if Mailbox Number is allocated and activated in CPHS SST */ private boolean isCphsMailboxEnabled() { @@ -2009,6 +2125,11 @@ public class SIMRecords extends IccRecords { pw.println(" mUsimServiceTable=" + mUsimServiceTable); pw.println(" mGid1=" + mGid1); pw.println(" mGid2=" + mGid2); + pw.println(" mPlmnActRecords[]=" + Arrays.toString(mPlmnActRecords)); + pw.println(" mOplmnActRecords[]=" + Arrays.toString(mOplmnActRecords)); + pw.println(" mHplmnActRecords[]=" + Arrays.toString(mHplmnActRecords)); + pw.println(" mFplmns[]=" + Arrays.toString(mFplmns)); + pw.println(" mEhplmns[]=" + Arrays.toString(mEhplmns)); pw.flush(); } } diff --git a/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java b/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java index 97d9d4083..f2834f7ec 100644 --- a/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java @@ -61,8 +61,13 @@ public final class UsimFileHandler extends IccFileHandler implements IccConstant case EF_GID1: case EF_GID2: case EF_LI: - case EF_PLMNWACT: - case EF_HPLMNWACT: + case EF_PLMN_W_ACT: + case EF_OPLMN_W_ACT: + case EF_HPLMN_W_ACT: + case EF_EHPLMN: + case EF_FPLMN: + case EF_LRPLMNSI: + case EF_HPPLMN: return MF_SIM + DF_ADF; case EF_PBR: diff --git a/tests/telephonytests/src/com/android/internal/telephony/FakeSmsContentProvider.java b/tests/telephonytests/src/com/android/internal/telephony/FakeSmsContentProvider.java index 1806c3cb1..17c18ecd6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/FakeSmsContentProvider.java +++ b/tests/telephonytests/src/com/android/internal/telephony/FakeSmsContentProvider.java @@ -62,7 +62,8 @@ public class FakeSmsContentProvider extends MockContentProvider { SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " + "pdu TEXT," + // the raw PDU for this part "deleted INTEGER DEFAULT 0," + // bool to indicate if row is deleted - "message_body TEXT);"); // message body + "message_body TEXT," + // message body + "display_originating_addr TEXT);");// display address } @Override diff --git a/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java index 4c8ccc10e..a036c621e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/InboundSmsTrackerTest.java @@ -34,6 +34,7 @@ public class InboundSmsTrackerTest { private static final long FAKE_TIMESTAMP = 123456L; private static final int FAKE_DEST_PORT = 1234; private static final String FAKE_ADDRESS = "address"; + private static final String FAKE_DISPLAY_ADDRESS = "disp_addr"; private static final int FAKE_REFERENCE_NUMBER = 345; private static final int FAKE_SEQUENCE_NUMBER = 3; private static final int FAKE_MESSAGE_COUNT = 5; @@ -42,19 +43,22 @@ public class InboundSmsTrackerTest { @Before public void setUp() throws Exception { mInboundSmsTracker = new InboundSmsTracker(FAKE_PDU, FAKE_TIMESTAMP, FAKE_DEST_PORT, false, - FAKE_ADDRESS, FAKE_REFERENCE_NUMBER, FAKE_SEQUENCE_NUMBER, FAKE_MESSAGE_COUNT, - false, FAKE_MESSAGE_BODY); + FAKE_ADDRESS, FAKE_DISPLAY_ADDRESS, FAKE_REFERENCE_NUMBER, FAKE_SEQUENCE_NUMBER, + FAKE_MESSAGE_COUNT, false, FAKE_MESSAGE_BODY); } public static MatrixCursor createFakeCursor() { MatrixCursor mc = new MatrixCursor( - new String[]{"pdu", "seq", "dest", "date", "ref", "cnt", "addr", "id", "msg_body"}); + new String[]{"pdu", "seq", "dest", "date", "ref", "cnt", "addr", "id", "msg_body", + "display_originating_addr"}); mc.addRow(new Object[]{HexDump.toHexString(FAKE_PDU), FAKE_SEQUENCE_NUMBER, FAKE_DEST_PORT, FAKE_TIMESTAMP, - FAKE_REFERENCE_NUMBER, FAKE_MESSAGE_COUNT, FAKE_ADDRESS, 1, FAKE_MESSAGE_BODY}); + FAKE_REFERENCE_NUMBER, FAKE_MESSAGE_COUNT, FAKE_ADDRESS, 1, FAKE_MESSAGE_BODY, + FAKE_DISPLAY_ADDRESS}); mc.addRow(new Object[]{HexDump.toHexString(FAKE_PDU), FAKE_SEQUENCE_NUMBER, FAKE_DEST_PORT, FAKE_TIMESTAMP, - FAKE_REFERENCE_NUMBER, FAKE_MESSAGE_COUNT, FAKE_ADDRESS, 2, FAKE_MESSAGE_BODY}); + FAKE_REFERENCE_NUMBER, FAKE_MESSAGE_COUNT, FAKE_ADDRESS, 2, FAKE_MESSAGE_BODY, + FAKE_DISPLAY_ADDRESS}); mc.moveToFirst(); return mc; } @@ -73,6 +77,7 @@ public class InboundSmsTrackerTest { assertEquals(1, mInboundSmsTracker.getIndexOffset()); assertEquals(SmsConstants.FORMAT_3GPP, mInboundSmsTracker.getFormat()); assertEquals(FAKE_MESSAGE_BODY, mInboundSmsTracker.getMessageBody()); + assertEquals(FAKE_DISPLAY_ADDRESS, mInboundSmsTracker.getDisplayAddress()); String[] args = new String[]{"123"}; mInboundSmsTracker.setDeleteWhere(InboundSmsHandler.SELECT_BY_ID, args); diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java index 805ee931f..30c8d032f 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java @@ -329,10 +329,11 @@ public abstract class TelephonyTest { .makeWspTypeDecoder(any(byte[].class)); doReturn(mInboundSmsTracker).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), - anyBoolean(), anyString(), anyString()); + anyBoolean(), anyString(), anyString(), anyString()); doReturn(mInboundSmsTracker).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), - anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString()); + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); doReturn(mInboundSmsTracker).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(Cursor.class), anyBoolean()); doReturn(mImsCT).when(mTelephonyComponentFactory) diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java index 652f18fe4..8bc881ef7 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java @@ -212,7 +212,7 @@ public class CdmaInboundSmsHandlerTest extends TelephonyTest { @MediumTest public void testNewSmsFromBlockedNumber_noBroadcastsSent() { String blockedNumber = "123456789"; - doReturn(blockedNumber).when(mInboundSmsTracker).getAddress(); + doReturn(blockedNumber).when(mInboundSmsTracker).getDisplayAddress(); mFakeBlockedNumberContentProvider.mBlockedNumbers.add(blockedNumber); transitionFromStartupToIdle(); diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java index 4e03553b5..92d8c34fc 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java @@ -28,13 +28,23 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; +import static com.android.internal.telephony.PhoneConstants.APN_TYPE_ALL; +import static com.android.internal.telephony.PhoneConstants.APN_TYPE_DEFAULT; +import static com.android.internal.telephony.PhoneConstants.APN_TYPE_HIPRI; +import static com.android.internal.telephony.PhoneConstants.APN_TYPE_IA; +import static com.android.internal.telephony.PhoneConstants.APN_TYPE_MMS; +import static com.android.internal.telephony.PhoneConstants.APN_TYPE_SUPL; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; +import static junit.framework.Assert.fail; import static org.junit.Assert.assertEquals; + public class ApnSettingTest extends TelephonyTest { private PersistableBundle mBundle; @@ -52,6 +62,14 @@ public class ApnSettingTest extends TelephonyTest { } private ApnSetting createApnSetting(String[] apnTypes) { + return createApnSettingInternal(apnTypes, true); + } + + private ApnSetting createDisabledApnSetting(String[] apnTypes) { + return createApnSettingInternal(apnTypes, false); + } + + private ApnSetting createApnSettingInternal(String[] apnTypes, boolean carrierEnabled) { return new ApnSetting( 2163, // id "44010", // numeric @@ -68,7 +86,7 @@ public class ApnSettingTest extends TelephonyTest { apnTypes, // types "IP", // protocol "IP", // roaming_protocol - true, // carrier_enabled + carrierEnabled, // carrier_enabled 0, // bearer 0, // bearer_bitmask 0, // profile_id @@ -243,7 +261,6 @@ public class ApnSettingTest extends TelephonyTest { new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_CBS}). isMetered(mContext, 1, isRoaming)); - //reuse the cached result for subId 1 assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mContext, 1, isRoaming)); assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, @@ -260,6 +277,15 @@ public class ApnSettingTest extends TelephonyTest { mContext, 1, isRoaming)); assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI, mContext, 1, isRoaming)); + + // Carrier config settings changes. + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS, + new String[]{PhoneConstants.APN_TYPE_DEFAULT}); + + assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, + mContext, 1, isRoaming)); + assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, + mContext, 1, isRoaming)); } @Test @@ -300,6 +326,17 @@ public class ApnSettingTest extends TelephonyTest { assertFalse(createApnSetting( new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_CBS}). isMetered(mContext, 1, isRoaming)); + + // Carrier config settings changes. + mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS, + new String[]{PhoneConstants.APN_TYPE_FOTA}); + + assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, + mContext, 1, isRoaming)); + assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, + mContext, 1, isRoaming)); + assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, + mContext, 1, isRoaming)); } @Test @@ -380,7 +417,6 @@ public class ApnSettingTest extends TelephonyTest { new String[]{PhoneConstants.APN_TYPE_IMS}). isMetered(mContext, 2, isRoaming)); - //reuse the cached result for subId 2 assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL, mContext, 2, isRoaming)); assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS, @@ -493,6 +529,102 @@ public class ApnSettingTest extends TelephonyTest { assertTrue(createApnSetting( new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_DUN}). isMetered(mContext, 4, isRoaming)); + } + @Test + @SmallTest + public void testCanHandleType() throws Exception { + String types[] = {"mms"}; + + // empty string replaced with ALL ('*') when loaded to db + assertFalse(createApnSetting(new String[]{}). + canHandleType(APN_TYPE_MMS)); + + assertTrue(createApnSetting(new String[]{APN_TYPE_ALL}). + canHandleType(APN_TYPE_MMS)); + + assertFalse(createApnSetting(new String[]{APN_TYPE_DEFAULT}). + canHandleType(APN_TYPE_MMS)); + + assertTrue(createApnSetting(new String[]{"DEfAULT"}). + canHandleType("defAult")); + + // Hipri is asymmetric + assertTrue(createApnSetting(new String[]{APN_TYPE_DEFAULT}). + canHandleType(APN_TYPE_HIPRI)); + assertFalse(createApnSetting(new String[]{APN_TYPE_HIPRI}). + canHandleType(APN_TYPE_DEFAULT)); + + + assertTrue(createApnSetting(new String[]{APN_TYPE_DEFAULT, APN_TYPE_MMS}). + canHandleType(APN_TYPE_DEFAULT)); + + assertTrue(createApnSetting(new String[]{APN_TYPE_DEFAULT, APN_TYPE_MMS}). + canHandleType(APN_TYPE_MMS)); + + assertFalse(createApnSetting(new String[]{APN_TYPE_DEFAULT, APN_TYPE_MMS}). + canHandleType(APN_TYPE_SUPL)); + + // special IA case - doesn't match wildcards + assertFalse(createApnSetting(new String[]{APN_TYPE_DEFAULT, APN_TYPE_MMS}). + canHandleType(APN_TYPE_IA)); + assertFalse(createApnSetting(new String[]{APN_TYPE_ALL}). + canHandleType(APN_TYPE_IA)); + assertFalse(createApnSetting(new String[]{APN_TYPE_ALL}). + canHandleType("iA")); + assertTrue(createApnSetting(new String[]{APN_TYPE_DEFAULT, APN_TYPE_MMS, APN_TYPE_IA}). + canHandleType(APN_TYPE_IA)); + + // check carrier disabled + assertFalse(createDisabledApnSetting(new String[]{APN_TYPE_ALL}). + canHandleType(APN_TYPE_MMS)); + assertFalse(createDisabledApnSetting(new String[]{"DEfAULT"}). + canHandleType("defAult")); + assertFalse(createDisabledApnSetting(new String[]{APN_TYPE_DEFAULT}). + canHandleType(APN_TYPE_HIPRI)); + assertFalse(createDisabledApnSetting(new String[]{APN_TYPE_DEFAULT, APN_TYPE_MMS}). + canHandleType(APN_TYPE_DEFAULT)); + assertFalse(createDisabledApnSetting(new String[]{APN_TYPE_DEFAULT, APN_TYPE_MMS}). + canHandleType(APN_TYPE_MMS)); + assertFalse(createDisabledApnSetting(new String[] + {APN_TYPE_DEFAULT, APN_TYPE_MMS, APN_TYPE_IA}). + canHandleType(APN_TYPE_IA)); + } + + @Test + @SmallTest + public void testEquals() throws Exception { + final int dummyInt = 1; + final String dummyString = "dummy"; + final String[] dummyStringArr = new String[] {"dummy"}; + // base apn + ApnSetting baseApn = createApnSetting(new String[] {"mms", "default"}); + Field[] fields = ApnSetting.class.getDeclaredFields(); + for (Field f : fields) { + int modifiers = f.getModifiers(); + if (Modifier.isStatic(modifiers) || !Modifier.isFinal(modifiers)) { + continue; + } + f.setAccessible(true); + ApnSetting testApn = null; + if (int.class.equals(f.getType())) { + testApn = new ApnSetting(baseApn); + f.setInt(testApn, dummyInt + f.getInt(testApn)); + } else if (boolean.class.equals(f.getType())) { + testApn = new ApnSetting(baseApn); + f.setBoolean(testApn, !f.getBoolean(testApn)); + } else if (String.class.equals(f.getType())) { + testApn = new ApnSetting(baseApn); + f.set(testApn, dummyString); + } else if (String[].class.equals(f.getType())) { + testApn = new ApnSetting(baseApn); + f.set(testApn, dummyStringArr); + } else { + fail("Unsupported field:" + f.getName()); + } + if (testApn != null) { + assertFalse(f.getName() + " is NOT checked", testApn.equals(baseApn)); + } + } } -}
\ No newline at end of file +} diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java index 41415ecc2..6d44d029a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java @@ -144,6 +144,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { mInboundSmsTrackerCV.put("count", 1); mInboundSmsTrackerCV.put("date", System.currentTimeMillis()); mInboundSmsTrackerCV.put("message_body", mMessageBody); + mInboundSmsTrackerCV.put("display_originating_addr", "1234567890"); doReturn(1).when(mInboundSmsTracker).getMessageCount(); doReturn(1).when(mInboundSmsTracker).getReferenceNumber(); @@ -272,8 +273,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { @Test @MediumTest public void testNewSmsFromBlockedNumber_noBroadcastsSent() { - String blockedNumber = "123456789"; - doReturn(blockedNumber).when(mInboundSmsTracker).getAddress(); + String blockedNumber = "1234567890"; + doReturn(blockedNumber).when(mInboundSmsTracker).getDisplayAddress(); mFakeBlockedNumberContentProvider.mBlockedNumbers.add(blockedNumber); transitionFromStartupToIdle(); @@ -351,6 +352,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { mInboundSmsTrackerCVPart1.put("count", 2); mInboundSmsTrackerCVPart1.put("date", System.currentTimeMillis()); mInboundSmsTrackerCVPart1.put("message_body", mMessageBodyPart1); + mInboundSmsTrackerCVPart1.put("display_originating_addr", "1234567890"); doReturn(2).when(mInboundSmsTrackerPart1).getMessageCount(); doReturn(1).when(mInboundSmsTrackerPart1).getReferenceNumber(); @@ -374,6 +376,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { mInboundSmsTrackerCVPart2.put("count", 2); mInboundSmsTrackerCVPart2.put("date", System.currentTimeMillis()); mInboundSmsTrackerCVPart2.put("message_body", mMessageBodyPart2); + mInboundSmsTrackerCVPart2.put("display_originating_addr", "1234567890"); doReturn(2).when(mInboundSmsTrackerPart2).getMessageCount(); doReturn(1).when(mInboundSmsTrackerPart2).getReferenceNumber(); @@ -402,7 +405,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), - anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString()); + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(100); @@ -412,7 +416,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), - anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString()); + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(100); @@ -427,7 +432,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { // additional copy of part 2 of message doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), - anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString()); + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(100); @@ -444,7 +450,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { // part 1 of new sms doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), - anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString()); + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(100); @@ -475,7 +482,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), - anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString()); + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(100); @@ -485,7 +493,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), - anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString()); + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(100); @@ -512,7 +521,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), - anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString()); + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); @@ -523,7 +533,46 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest { doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory) .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), - anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), anyString()); + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); + mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, + mSmsMessage, null)); + waitForMs(100); + + verify(mContext, never()).sendBroadcast(any(Intent.class)); + assertEquals("IdleState", getCurrentState().getName()); + } + + @Test + @MediumTest + public void testMultipartSmsFromBlockedEmail_noBroadcastsSent() { + mFakeBlockedNumberContentProvider.mBlockedNumbers.add("1234567890@test.com"); + + transitionFromStartupToIdle(); + + // prepare SMS part 1 and part 2 + prepareMultiPartSms(); + // only the first SMS is configured with the display originating email address + mInboundSmsTrackerCVPart1.put("display_originating_addr", "1234567890@test.com"); + + mSmsHeader.concatRef = new SmsHeader.ConcatRef(); + doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader(); + doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory) + .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); + + mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, + mSmsMessage, null)); + waitForMs(100); + + // State machine should go back to idle and wait for second part + assertEquals("IdleState", getCurrentState().getName()); + + doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory) + .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(), + anyString(), anyString(), anyInt(), anyInt(), anyInt(), anyBoolean(), + anyString()); mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null, mSmsMessage, null)); waitForMs(100); diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java index c8517a259..8eaefb6dd 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneConnectionTest.java @@ -248,8 +248,6 @@ public class ImsPhoneConnectionTest extends TelephonyTest { ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + ""); assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE)); assertTrue(mConnectionUT.isWifi()); - //keep using the wifi state from extra, not update - assertFalse(mConnectionUT.updateWifiState()); } @Test @@ -265,7 +263,5 @@ public class ImsPhoneConnectionTest extends TelephonyTest { ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN + ""); assertTrue(mConnectionUT.update(mImsCall, Call.State.ACTIVE)); assertTrue(mConnectionUT.isWifi()); - //keep using the wifi state from extra, not update - assertFalse(mConnectionUT.updateWifiState()); } } diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java index 810533519..572cf41fe 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java @@ -24,6 +24,7 @@ import com.android.ims.ImsConfig; import com.android.ims.ImsReasonInfo; import com.android.ims.internal.ImsCallSession; import com.android.internal.telephony.Call; +import com.android.internal.telephony.GsmCdmaConnection; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.SmsResponse; import com.android.internal.telephony.TelephonyProto; @@ -33,6 +34,7 @@ import com.android.internal.telephony.TelephonyProto.RadioAccessTechnology; import com.android.internal.telephony.TelephonyProto.TelephonyCallSession; import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.CallState; import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.ImsCommand; +import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.RilCall; import com.android.internal.telephony.TelephonyProto.TelephonyEvent; import com.android.internal.telephony.TelephonyProto.TelephonyLog; import com.android.internal.telephony.TelephonyProto.TelephonyServiceState; @@ -71,6 +73,9 @@ public class TelephonyMetricsTest extends TelephonyTest { @Mock private ServiceState mServiceState; + @Mock + private GsmCdmaConnection mConnection; + private TelephonyMetrics mMetrics; private UUSInfo mUusInfo; @@ -460,8 +465,10 @@ public class TelephonyMetricsTest extends TelephonyTest { @Test @SmallTest public void testWriteRilDialHangup() throws Exception { - mMetrics.writeRilDial(mPhone.getPhoneId(), 1, 2, mUusInfo); - mMetrics.writeRilHangup(mPhone.getPhoneId(), 2, 3); + doReturn(Call.State.DIALING).when(mConnection).getState(); + mMetrics.writeRilDial(mPhone.getPhoneId(), mConnection, 2, mUusInfo); + doReturn(Call.State.DISCONNECTED).when(mConnection).getState(); + mMetrics.writeRilHangup(mPhone.getPhoneId(), mConnection, 3); mMetrics.writePhoneState(mPhone.getPhoneId(), PhoneConstants.State.IDLE); TelephonyLog log = buildProto(); @@ -479,16 +486,18 @@ public class TelephonyMetricsTest extends TelephonyTest { assertTrue(events[0].hasRilRequest()); assertEquals(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL, events[0].getRilRequest()); - assertTrue(events[0].hasRilRequestId()); - assertEquals(1, events[0].getRilRequestId()); + RilCall[] calls = events[0].calls; + assertEquals(CallState.CALL_DIALING, calls[0].getState()); assertTrue(events[1].hasType()); assertEquals(TelephonyCallSession.Event.Type.RIL_REQUEST, events[1].getType()); assertTrue(events[1].hasRilRequest()); assertEquals(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_HANGUP, events[1].getRilRequest()); - assertTrue(events[1].hasCallIndex()); - assertEquals(3, events[1].getCallIndex()); + calls = events[1].calls; + assertTrue(calls[0].hasIndex()); + assertEquals(3, calls[0].getIndex()); + assertEquals(CallState.CALL_DISCONNECTED, calls[0].getState()); } // Test write RIL setup data call @@ -612,4 +621,4 @@ public class TelephonyMetricsTest extends TelephonyTest { byte[] decodedString = Base64.decode(encodedString, Base64.DEFAULT); assertArrayEquals(TelephonyProto.TelephonyLog.toByteArray(log), decodedString); } -}
\ No newline at end of file +} |