diff options
147 files changed, 15667 insertions, 9709 deletions
diff --git a/Android.mk b/Android.mk index ad2d518dd004..ea10716c5405 100644 --- a/Android.mk +++ b/Android.mk @@ -106,8 +106,8 @@ LOCAL_SRC_FILES += \ telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \ telephony/java/com/android/internal/telephony/ITelephony.aidl \ telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \ -telephony/java/com/android/internal/telephony/IIccPhoneBook.aidl \ - telephony/java/com/android/internal/telephony/gsm/ISms.aidl \ + telephony/java/com/android/internal/telephony/IIccPhoneBook.aidl \ + telephony/java/com/android/internal/telephony/ISms.aidl \ wifi/java/android/net/wifi/IWifiManager.aidl LOCAL_AIDL_INCLUDES += $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 42bbf6c53592..b81d5457719f 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -115,28 +115,28 @@ public class MobileDataStateTracker extends NetworkStateTracker { mMobileDataState = state; switch (state) { - case DISCONNECTED: - setDetailedState(DetailedState.DISCONNECTED, reason, apnName); - if (mInterfaceName != null) { - NetworkUtils.resetConnections(mInterfaceName); - } - mInterfaceName = null; - mDefaultGatewayAddr = 0; - break; - case CONNECTING: - setDetailedState(DetailedState.CONNECTING, reason, apnName); - break; - case SUSPENDED: - setDetailedState(DetailedState.SUSPENDED, reason, apnName); - break; - case CONNECTED: - mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY); - if (mInterfaceName == null) { - Log.d(TAG, "CONNECTED event did not supply interface name."); - } - setupDnsProperties(); - setDetailedState(DetailedState.CONNECTED, reason, apnName); - break; + case DISCONNECTED: + setDetailedState(DetailedState.DISCONNECTED, reason, apnName); + if (mInterfaceName != null) { + NetworkUtils.resetConnections(mInterfaceName); + } + mInterfaceName = null; + mDefaultGatewayAddr = 0; + break; + case CONNECTING: + setDetailedState(DetailedState.CONNECTING, reason, apnName); + break; + case SUSPENDED: + setDetailedState(DetailedState.SUSPENDED, reason, apnName); + break; + case CONNECTED: + mInterfaceName = intent.getStringExtra(Phone.DATA_IFACE_NAME_KEY); + if (mInterfaceName == null) { + Log.d(TAG, "CONNECTED event did not supply interface name."); + } + setupDnsProperties(); + setDetailedState(DetailedState.CONNECTED, reason, apnName); + break; } } } else if (intent.getAction().equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { @@ -227,26 +227,26 @@ public class MobileDataStateTracker extends NetworkStateTracker { * for this network. */ public String getTcpBufferSizesPropName() { - String networkTypeStr = "unknown"; + String networkTypeStr = "unknown"; TelephonyManager tm = new TelephonyManager(mContext); //TODO We have to edit the parameter for getNetworkType regarding CDMA switch(tm.getNetworkType()) { - case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_GPRS: networkTypeStr = "gprs"; break; - case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_EDGE: networkTypeStr = "edge"; break; - case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_UMTS: networkTypeStr = "umts"; break; - case TelephonyManager.NETWORK_TYPE_CDMA: + case TelephonyManager.NETWORK_TYPE_CDMA: networkTypeStr = "cdma"; break; - case TelephonyManager.NETWORK_TYPE_EVDO_0: + case TelephonyManager.NETWORK_TYPE_EVDO_0: networkTypeStr = "evdo"; break; - case TelephonyManager.NETWORK_TYPE_EVDO_A: + case TelephonyManager.NETWORK_TYPE_EVDO_A: networkTypeStr = "evdo"; break; } diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java index d6e8899a3f38..36a1114031eb 100644 --- a/core/java/android/provider/Checkin.java +++ b/core/java/android/provider/Checkin.java @@ -127,10 +127,12 @@ public final class Checkin { PHONE_GPRS_ATTEMPTED, PHONE_GPRS_CONNECTED, PHONE_RADIO_RESETS, - PHONE_CDMA_REGISTERED, TEST, NETWORK_RX_MOBILE, NETWORK_TX_MOBILE, + PHONE_CDMA_REGISTERED, + PHONE_CDMA_DATA_ATTEMPTED, + PHONE_CDMA_DATA_CONNECTED, } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ea5edfd1d836..cf7f6b481493 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -813,8 +813,8 @@ public final class Settings { public static final String WAIT_FOR_DEBUGGER = "wait_for_debugger"; /** - * represents current acitve phone class - * 0 = GSM-Phone, 1 = CDMA-Phone + * represents current active phone class + * 1 = GSM-Phone, 0 = CDMA-Phone */ public static final String CURRENT_ACTIVE_PHONE = "current_active_phone"; @@ -1106,6 +1106,14 @@ public final class Settings { "preferred_network_mode"; /** + * CDMA Cell Broadcast SMS + * 0 = CDMA Cell Broadcast SMS disabled + * 1 = CDMA Cell Broadcast SMS enabled + */ + public static final String CDMA_CELL_BROADCAST_SMS = + "cdma_cell_broadcast_sms"; + + /** * The cdma subscription 0 = Subscription from RUIM, when available * 1 = Subscription from NV */ @@ -2072,9 +2080,10 @@ public final class Settings { /** * Returns the GTalk JID resource associated with this device. * - * @return String the JID resource of the device. It uses the device IMEI in the computation - * of the JID resource. If IMEI is not ready (i.e. telephony module not ready), we'll return - * an empty string. + * @return String the JID resource of the device. It uses the Device ID (IMEI for GSM and MEID + * for CDMA) in the computation. + * of the JID resource. If Device ID is not ready (i.e. telephony module not ready), we'll + * return an empty string. * @hide */ // TODO: we shouldn't not have a permenant Jid resource, as that's an easy target for @@ -2093,13 +2102,13 @@ public final class Settings { throw new RuntimeException("this should never happen"); } - String imei = TelephonyManager.getDefault().getDeviceId(); - if (TextUtils.isEmpty(imei)) { + String deviceId = TelephonyManager.getDefault().getDeviceId(); + if (TextUtils.isEmpty(deviceId)) { return ""; } - byte[] hashedImei = digest.digest(imei.getBytes()); - String id = new String(Base64.encodeBase64(hashedImei), 0, 12); + byte[] hashedDeviceId = digest.digest(deviceId.getBytes()); + String id = new String(Base64.encodeBase64(hashedDeviceId), 0, 12); id = id.replaceAll("/", "_"); sJidResource = JID_RESOURCE_PREFIX + id; return sJidResource; diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index 776a2664b16a..1ffbde7e6244 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -28,16 +28,16 @@ import android.content.Intent; import android.database.Cursor; import android.net.Uri; import android.telephony.PhoneNumberUtils; +import android.telephony.SmsMessage; import android.telephony.TelephonyManager; -import android.telephony.gsm.SmsMessage; import android.text.TextUtils; import android.text.util.Regex; import android.util.Config; import java.util.HashSet; -import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.Set; /** * The Telephony provider contains data related to phone operation. @@ -49,6 +49,10 @@ public final class Telephony { private static final boolean DEBUG = false; private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; + // Constructor + public Telephony() { + } + /** * Base columns for tables that contain text based SMSs. */ diff --git a/core/java/android/webkit/gears/AndroidRadioDataProvider.java b/core/java/android/webkit/gears/AndroidRadioDataProvider.java index 8887b24ec53a..2d431a8d6162 100644 --- a/core/java/android/webkit/gears/AndroidRadioDataProvider.java +++ b/core/java/android/webkit/gears/AndroidRadioDataProvider.java @@ -46,8 +46,8 @@ public final class AndroidRadioDataProvider extends PhoneStateListener { private static final int RADIO_TYPE_UNKNOWN = 0; private static final int RADIO_TYPE_GSM = 1; private static final int RADIO_TYPE_WCDMA = 2; - private static final int RADIO_TYPE_CDMA = 3; - private static final int RADIO_TYPE_EVDO = 4; + private static final int RADIO_TYPE_CDMA = 3; + private static final int RADIO_TYPE_EVDO = 4; private static final int RADIO_TYPE_1xRTT = 5; /** Simple container for radio data */ diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index bec3bc870179..55052daf688e 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -67,6 +67,12 @@ <string name="BaMmi">Call barring</string> <string name="PwdMmi">Password change</string> <string name="PinMmi">PIN change</string> + <string name="CnipMmi">Calling number present</string> + <string name="CnirMmi">Calling number restricted</string> + <string name="ThreeWCMmi">Three way calling</string> + <string name="RuacMmi">Rejection of undesired annoying calls</string> + <string name="CndMmi">Calling number delivery</string> + <string name="DndMmi">Do not disturb</string> <string name="CLIRDefaultOnNextCallOn">Caller ID defaults to restricted. Next call: Restricted</string> <string name="CLIRDefaultOnNextCallOff">Caller ID defaults to restricted. Next call: Not restricted</string> @@ -0,0 +1,44 @@ +telephony/java/android/telephony/SmsManager.java +telephony/java/android/telephony/SmsMessage.java +telephony/java/android/telephony/cdma/package.html +telephony/java/android/telephony/gsm/SmsMessage.java +telephony/java/com/android/internal/telephony/CommandException.java +telephony/java/com/android/internal/telephony/DataConnection.java +telephony/java/com/android/internal/telephony/DataConnectionTracker.java +telephony/java/com/android/internal/telephony/DataLink.java +telephony/java/com/android/internal/telephony/DataLinkInterface.java +telephony/java/com/android/internal/telephony/EncodeException.java +telephony/java/com/android/internal/telephony/GsmAlphabet.java +telephony/java/com/android/internal/telephony/ISms.aidl +telephony/java/com/android/internal/telephony/SMSDispatcher.java +telephony/java/com/android/internal/telephony/SmsAddress.java +telephony/java/com/android/internal/telephony/SmsHeader.java +telephony/java/com/android/internal/telephony/SmsMessageBase.java +telephony/java/com/android/internal/telephony/SmsRawData.aidl +telephony/java/com/android/internal/telephony/SmsRawData.java +telephony/java/com/android/internal/telephony/SmsResponse.java +telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java +telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java +telephony/java/com/android/internal/telephony/cdma/FeatureCode.java +telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java +telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java +telephony/java/com/android/internal/telephony/cdma/SmsMessage.java +telephony/java/com/android/internal/telephony/cdma/TtyIntent.java +telephony/java/com/android/internal/telephony/cdma/package.html +telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java +telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java +telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java +telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java +telephony/java/com/android/internal/telephony/cdma/sms/UserData.java +telephony/java/com/android/internal/telephony/cdma/sms/package.html +telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java +telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java +telephony/java/com/android/internal/telephony/gsm/MccTable.java +telephony/java/com/android/internal/telephony/gsm/PdpConnection.java +telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java +telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java +telephony/jni/cdmasms/Android.mk +telephony/jni/cdmasms/cdma_sms_jni.cpp +telephony/jni/cdmasms/cdma_sms_jni.h diff --git a/location/java/com/android/internal/location/CellState.java b/location/java/com/android/internal/location/CellState.java index 868d84a39b45..96fe145a1649 100644 --- a/location/java/com/android/internal/location/CellState.java +++ b/location/java/com/android/internal/location/CellState.java @@ -81,7 +81,7 @@ public class CellState { // Get Home MCC/MNC String homeOperator = SystemProperties.get( - TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC); + TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC); if (homeOperator != null && !homeOperator.equals("")) { String mcc = homeOperator.substring(0, 3); String mnc = homeOperator.substring(3); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index d58879deb743..a7d1385b5859 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -568,11 +568,15 @@ class DatabaseHelper extends SQLiteOpenHelper { // Set the preferred network mode to 0 = Global, CDMA default loadSetting(stmt, Settings.System.PREFERRED_NETWORK_MODE, - RILConstants.NETWORK_MODE_GLOBAL); + RILConstants.PREFERRED_NETWORK_MODE); + + // Enable or disable Cell Broadcast SMS + loadSetting(stmt, Settings.System.CDMA_CELL_BROADCAST_SMS, + RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED); // Set the preferred cdma subscription to 0 = Subscription from RUIM, when available loadSetting(stmt, Settings.System.PREFERRED_CDMA_SUBSCRIPTION, - RILConstants.SUBSCRIPTION_FROM_RUIM); + RILConstants.PREFERRED_CDMA_SUBSCRIPTION); // Don't do this. The SystemServer will initialize ADB_ENABLED from a // persistent system property instead. diff --git a/preloaded-classes b/preloaded-classes index 4d5e9b69ca6b..3a637cd4e193 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -270,8 +270,8 @@ android.speech.recognition.impl.MicrophoneImpl android.speech.recognition.impl.System android.telephony.PhoneNumberUtils android.telephony.ServiceState -android.telephony.gsm.SmsManager -android.telephony.gsm.SmsMessage +android.telephony.SmsManager +android.telephony.SmsMessage android.text.AutoText android.text.BoringLayout android.text.BoringLayout$Metrics @@ -490,6 +490,8 @@ com.android.internal.policy.impl.PhoneWindow$PanelFeatureState com.android.internal.policy.impl.PhoneWindow$PanelFeatureState$SavedState com.android.internal.telephony.BaseCommands com.android.internal.telephony.CommandsInterface +com.android.internal.telephony.GsmAlphabet +com.android.internal.telephony.ISms$Stub com.android.internal.telephony.Phone com.android.internal.telephony.Phone$DataActivityState com.android.internal.telephony.Phone$DataState @@ -498,9 +500,6 @@ com.android.internal.telephony.PhoneBase com.android.internal.telephony.PhoneStateIntentReceiver com.android.internal.telephony.RIL com.android.internal.telephony.gsm.GSMPhone -com.android.internal.telephony.gsm.GsmAlphabet -com.android.internal.telephony.gsm.ISms$Stub -com.android.internal.telephony.gsm.PdpConnection$PdpFailCause com.android.internal.telephony.gsm.GsmServiceStateTracker com.android.internal.telephony.gsm.SimCard com.android.internal.view.menu.MenuDialogHelper diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java index 8789d580c80d..ab19e3c25f0f 100644 --- a/services/java/com/android/server/status/StatusBarPolicy.java +++ b/services/java/com/android/server/status/StatusBarPolicy.java @@ -52,7 +52,7 @@ import com.android.internal.R; import com.android.internal.location.GpsLocationProvider; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.TelephonyIntents; -import android.telephony.cdma.TtyIntent; +import com.android.internal.telephony.cdma.TtyIntent; import java.util.Calendar; import java.util.TimeZone; @@ -193,7 +193,7 @@ public class StatusBarPolicy { private IBinder mVolumeIcon; private IconData mVolumeData; private boolean mVolumeVisible; - + // bluetooth device status private IBinder mBluetoothIcon; private IconData mBluetoothData; @@ -325,13 +325,13 @@ public class StatusBarPolicy { mWifiIcon = service.addIcon(mWifiData, null); service.setIconVisibility(mWifiIcon, false); // wifi will get updated by the sticky intents - + // TTY status mTTYModeEnableIconData = IconData.makeIcon("tty", null, com.android.internal.R.drawable.stat_sys_tty_mode, 0, 0); mTTYModeIcon = service.addIcon(mTTYModeEnableIconData, null); service.setIconVisibility(mTTYModeIcon, false); - + // bluetooth status mBluetoothData = IconData.makeIcon("bluetooth", null, com.android.internal.R.drawable.stat_sys_data_bluetooth, 0, 0); @@ -366,7 +366,7 @@ public class StatusBarPolicy { null, com.android.internal.R.drawable.stat_sys_ringer_silent, 0, 0); mVolumeIcon = service.addIcon(mVolumeData, null); service.setIconVisibility(mVolumeIcon, false); - + IntentFilter filter = new IntentFilter(); // Register for Intent broadcasts for... @@ -520,7 +520,7 @@ public class StatusBarPolicy { com.android.internal.R.styleable.Theme); lp.dimAmount = a.getFloat(android.R.styleable.Theme_backgroundDimAmount, 0.5f); a.recycle(); - + lp.setTitle("Battery"); TextView levelTextView = (TextView)v.findViewById(com.android.internal.R.id.level_percent); @@ -729,15 +729,15 @@ public class StatusBarPolicy { || ss.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_IS95A || ss.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_IS95B) { switch(ss.getExtendedCdmaRoaming()) { - case ServiceState.REGISTRATION_STATE_ROAMING: - iconList = this.sSignalImages_r_cdma; - break; - case ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE: - iconList = this.sSignalImages_ra_cdma; - break; - default: - iconList = this.sSignalImages_cdma; - break; + case ServiceState.REGISTRATION_STATE_ROAMING: + iconList = this.sSignalImages_r_cdma; + break; + case ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE: + iconList = this.sSignalImages_ra_cdma; + break; + default: + iconList = this.sSignalImages_cdma; + break; } } @@ -750,31 +750,31 @@ public class StatusBarPolicy { ServiceState ss = this.mServiceState; switch (net) { - case TelephonyManager.NETWORK_TYPE_EDGE: - mDataIconList = sDataNetType_e; - break; - case TelephonyManager.NETWORK_TYPE_UMTS: - mDataIconList = sDataNetType_3g; - break; - case TelephonyManager.NETWORK_TYPE_CDMA: - //TODO check if IS95 has to be displayed or if the warning can be removed! - if( (ss.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_IS95A) || - ss.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_IS95B) { - Log.w(TAG, "Warning! CDMA radio technology is either IS95A or IS95B," - + " but you will see 1xRTT!"); - } - mDataIconList = this.sDataNetType_1xrtt; - break; + case TelephonyManager.NETWORK_TYPE_EDGE: + mDataIconList = sDataNetType_e; + break; + case TelephonyManager.NETWORK_TYPE_UMTS: + mDataIconList = sDataNetType_3g; + break; + case TelephonyManager.NETWORK_TYPE_CDMA: + // display 1xRTT for IS95A/B + if( (ss.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_IS95A) || + ss.getRadioTechnology() == ServiceState.RADIO_TECHNOLOGY_IS95B) { + Log.w(TAG, "Warning! CDMA radio technology is either IS95A or IS95B," + + " but you will see 1xRTT!"); + } + mDataIconList = this.sDataNetType_1xrtt; + break; case TelephonyManager.NETWORK_TYPE_1xRTT: mDataIconList = this.sDataNetType_1xrtt; break; - case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through - case TelephonyManager.NETWORK_TYPE_EVDO_A: - mDataIconList = sDataNetType_evdo; + case TelephonyManager.NETWORK_TYPE_EVDO_0: //fall through + case TelephonyManager.NETWORK_TYPE_EVDO_A: + mDataIconList = sDataNetType_evdo; break; - default: - mDataIconList = sDataNetType_g; - break; + default: + mDataIconList = sDataNetType_g; + break; } } @@ -784,7 +784,7 @@ public class StatusBarPolicy { if (mSimState == IccCard.State.READY || mSimState == IccCard.State.UNKNOWN) { int data = mDataState; - + int[] list = mDataIconList; ServiceState ss = mServiceState; @@ -827,7 +827,7 @@ public class StatusBarPolicy { private final void updateVolume(Intent intent) { // This can be called from two different received intents, so don't use extras. - + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); final int ringerMode = audioManager.getRingerMode(); final boolean visible = ringerMode == AudioManager.RINGER_MODE_SILENT || @@ -881,17 +881,17 @@ public class StatusBarPolicy { private final void updateWifi(Intent intent) { final String action = intent.getAction(); if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - + final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED; - + if (!enabled) { // If disabled, hide the icon. (We show icon when connected.) mService.setIconVisibility(mWifiIcon, false); } - + } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { - + final NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO); @@ -903,10 +903,10 @@ public class StatusBarPolicy { } else { iconId = sWifiSignalImages[mLastWifiSignalLevel]; } - + // Show the icon since wi-fi is connected mService.setIconVisibility(mWifiIcon, true); - + } else { mLastWifiSignalLevel = -1; mIsWifiConnected = false; @@ -956,16 +956,16 @@ public class StatusBarPolicy { final String action = intent.getAction(); final boolean enabled = intent.getBooleanExtra(TtyIntent.TTY_ENABLED, false); - Log.w(TAG, "updateTTY: enabled: " + enabled); - + Log.i(TAG, "updateTTY: enabled: " + enabled); + if (enabled) { // TTY is on - Log.w(TAG, "updateTTY: set TTY on"); + Log.i(TAG, "updateTTY: set TTY on"); mService.updateIcon(mTTYModeIcon, mTTYModeEnableIconData, null); mService.setIconVisibility(mTTYModeIcon, true); } else { // TTY is off - Log.w(TAG, "updateTTY: set TTY off"); + Log.i(TAG, "updateTTY: set TTY off"); mService.setIconVisibility(mTTYModeIcon, false); } } diff --git a/telephony/java/android/telephony/CellLocation.java b/telephony/java/android/telephony/CellLocation.java index 5d2cb2d32e72..5df97684048c 100644 --- a/telephony/java/android/telephony/CellLocation.java +++ b/telephony/java/android/telephony/CellLocation.java @@ -62,8 +62,10 @@ public abstract class CellLocation { * @hide */ public static CellLocation newFromBundle(Bundle bundle) { - if (RILConstants.CDMA_PHONE == - SystemProperties.getInt(Settings.System.CURRENT_ACTIVE_PHONE, 0)) { + // NOTE here TelephonyManager.getDefault().getPhoneType() cannot be used since at startup + // ITelephony have not been created + if (RILConstants.CDMA_PHONE == + SystemProperties.getInt(Settings.System.CURRENT_ACTIVE_PHONE, 0)) { return new CdmaCellLocation(bundle); } else { return new GsmCellLocation(bundle); @@ -80,13 +82,15 @@ public abstract class CellLocation { * */ public static CellLocation getEmpty() { - if (RILConstants.CDMA_PHONE == - SystemProperties.getInt(Settings.System.CURRENT_ACTIVE_PHONE, 0)) { + // NOTE here TelephonyManager.getDefault().getPhoneType() cannot be used since at startup + // ITelephony have not been created + if (RILConstants.CDMA_PHONE == + SystemProperties.getInt(Settings.System.CURRENT_ACTIVE_PHONE, 0)) { return new CdmaCellLocation(); } else { return new GsmCellLocation(); } } - + } diff --git a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java index 0bc6c041a82a..8a4733941622 100644 --- a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java +++ b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java @@ -25,7 +25,7 @@ import java.util.Locale; /** * Watches a {@link TextView} and if a phone number is entered will format it using - * {@link PhoneNumberUtils#formatNumber(Editable, int)}. The formatting is based on + * {@link PhoneNumberUtils#formatNumber(Editable, int)}. The formatting is based on * the current system locale when this object is created and future locale changes * may not take effect on this instance. */ @@ -35,7 +35,7 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher { static private Locale sCachedLocale; private boolean mFormatting; private boolean mDeletingHyphen; - private int mHyphenStart; + private int mHyphenStart; private boolean mDeletingBackward; public PhoneNumberFormattingTextWatcher() { @@ -60,7 +60,7 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher { text.delete(mHyphenStart, mHyphenStart + 1); } } - + PhoneNumberUtils.formatNumber(text, sFormatType); mFormatting = false; @@ -73,8 +73,8 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher { // Make sure user is deleting one char, without a selection final int selStart = Selection.getSelectionStart(s); final int selEnd = Selection.getSelectionEnd(s); - if (s.length() > 1 // Can delete another character - && count == 1 // Deleting only one character + if (s.length() > 1 // Can delete another character + && count == 1 // Deleting only one character && after == 0 // Deleting && s.charAt(start) == '-' // a hyphen && selStart == selEnd) { // no selection @@ -89,7 +89,7 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher { } else { mDeletingHyphen = false; } - } + } } public void onTextChanged(CharSequence s, int start, int before, int count) { diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index f2b63cc0dfef..3578c9936dd1 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -932,7 +932,7 @@ public class PhoneNumberUtils return; } CharSequence saved = text.subSequence(0, length); - + // Strip the dashes first, as we're going to add them back int p = 0; while (p < text.length()) { @@ -1013,7 +1013,7 @@ public class PhoneNumberUtils int pos = dashPositions[i]; text.replace(pos + i, pos + i, "-"); } - + // Remove trailing dashes int len = text.length(); while (len > 0) { @@ -1040,10 +1040,10 @@ public class PhoneNumberUtils * listed in the ril / sim, then return true, otherwise false. */ public static boolean isEmergencyNumber(String number) { - // Strip the separators from the number before comparing it + // Strip the separators from the number before comparing it // to the list. number = extractNetworkPortion(number); - + // retrieve the list of emergency numbers String numbers = SystemProperties.get("ro.ril.ecclist"); diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 8a8a675e7c47..df6860b08365 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -11,18 +11,18 @@ import com.android.internal.telephony.IPhoneStateListener; /** * A listener class for monitoring changes in specific telephony states - * on the device, including service state, signal strength, message + * on the device, including service state, signal strength, message * waiting indicator (voicemail), and others. * <p> - * Override the methods for the state that you wish to receive updates for, and + * Override the methods for the state that you wish to receive updates for, and * pass your PhoneStateListener object, along with bitwise-or of the LISTEN_ * flags to {@link TelephonyManager#listen TelephonyManager.listen()}. * <p> * Note that access to some telephony information is - * permission-protected. Your application won't receive updates for protected - * information unless it has the appropriate permissions declared in + * permission-protected. Your application won't receive updates for protected + * information unless it has the appropriate permissions declared in * its manifest file. Where permissions apply, they are noted in the - * appropriate LISTEN_ flags. + * appropriate LISTEN_ flags. */ public class PhoneStateListener { @@ -67,17 +67,17 @@ public class PhoneStateListener { public static final int LISTEN_CALL_FORWARDING_INDICATOR = 0x00000008; /** - * Listen for changes to the device's cell location. Note that + * Listen for changes to the device's cell location. Note that * this will result in frequent callbacks to the listener. * {@more} * Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION * ACCESS_COARSE_LOCATION} * <p> - * If you need regular location updates but want more control over - * the update interval or location precision, you can set up a listener - * through the {@link android.location.LocationManager location manager} - * instead. - * + * If you need regular location updates but want more control over + * the update interval or location precision, you can set up a listener + * through the {@link android.location.LocationManager location manager} + * instead. + * * @see #onCellLocationChanged */ public static final int LISTEN_CELL_LOCATION = 0x00000010; @@ -100,7 +100,7 @@ public class PhoneStateListener { * Listen for changes to the direction of data traffic on the data * connection (cellular). * - * Example: The status bar uses this to display the appropriate + * Example: The status bar uses this to display the appropriate * data-traffic icon. * * @see #onDataActivity @@ -111,7 +111,7 @@ public class PhoneStateListener { } /** - * Callback invoked when device service state changes. + * Callback invoked when device service state changes. * * @see ServiceState#STATE_EMERGENCY_ONLY * @see ServiceState#STATE_IN_SERVICE @@ -135,28 +135,28 @@ public class PhoneStateListener { } /** - * Callback invoked when the message-waiting indicator changes. + * Callback invoked when the message-waiting indicator changes. */ public void onMessageWaitingIndicatorChanged(boolean mwi) { // default implementation empty } /** - * Callback invoked when the call-forwarding indicator changes. + * Callback invoked when the call-forwarding indicator changes. */ public void onCallForwardingIndicatorChanged(boolean cfi) { // default implementation empty } /** - * Callback invoked when device cell location changes. + * Callback invoked when device cell location changes. */ public void onCellLocationChanged(CellLocation location) { // default implementation empty } /** - * Callback invoked when device call state changes. + * Callback invoked when device call state changes. * * @see TelephonyManager#CALL_STATE_IDLE * @see TelephonyManager#CALL_STATE_RINGING @@ -167,7 +167,7 @@ public class PhoneStateListener { } /** - * Callback invoked when connection state changes. + * Callback invoked when connection state changes. * * @see TelephonyManager#DATA_DISCONNECTED * @see TelephonyManager#DATA_CONNECTING @@ -179,7 +179,7 @@ public class PhoneStateListener { } /** - * Callback invoked when data activity state changes. + * Callback invoked when data activity state changes. * * @see TelephonyManager#DATA_ACTIVITY_NONE * @see TelephonyManager#DATA_ACTIVITY_IN diff --git a/telephony/java/android/telephony/ServiceState.aidl b/telephony/java/android/telephony/ServiceState.aidl index b1cf3790ead5..852288937ef0 100644 --- a/telephony/java/android/telephony/ServiceState.aidl +++ b/telephony/java/android/telephony/ServiceState.aidl @@ -2,16 +2,16 @@ ** ** Copyright 2007, 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 +** 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 +** 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 +** 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. */ diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 7414a2c5c913..7098b7753df7 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -35,7 +35,7 @@ import android.util.Log; */ public class ServiceState implements Parcelable { - static final String LOG_TAG = "ServiceState"; + static final String LOG_TAG = "PHONE"; /** * Normal operation condition, the phone is registered @@ -278,7 +278,7 @@ public class ServiceState implements Parcelable { @Override public boolean equals (Object o) { ServiceState s; - + try { s = (ServiceState) o; } catch (ClassCastException ex) { @@ -400,7 +400,7 @@ public class ServiceState implements Parcelable { public void setIsManualSelection(boolean isManual) { mIsManualNetworkSelection = isManual; } - + /** * Test whether two objects hold the same data values or both are null * diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java new file mode 100644 index 000000000000..8f271083a298 --- /dev/null +++ b/telephony/java/android/telephony/SmsManager.java @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2008 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 android.telephony; + +import android.app.PendingIntent; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.text.TextUtils; + +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.ISms; +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.SmsRawData; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static android.telephony.SmsMessage.ENCODING_7BIT; +import static android.telephony.SmsMessage.ENCODING_8BIT; +import static android.telephony.SmsMessage.ENCODING_16BIT; +import static android.telephony.SmsMessage.ENCODING_UNKNOWN; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER; + +/** + * Manages SMS operations such as sending data, text, and pdu SMS messages. + * Get this object by calling the static method SmsManager.getDefault(). + */ +public final class SmsManager { + private static SmsManager sInstance; + + /** + * Send a text based SMS. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param text the body of the message to send + * @param sentIntent if not NULL this <code>PendingIntent</code> is + * broadcast when the message is sucessfully sent, or failed. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors: + * <code>RESULT_ERROR_GENERIC_FAILURE</code> + * <code>RESULT_ERROR_RADIO_OFF</code> + * <code>RESULT_ERROR_NULL_PDU</code>. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this <code>PendingIntent</code> is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or text are empty + */ + public void sendTextMessage( + String destinationAddress, String scAddress, String text, + PendingIntent sentIntent, PendingIntent deliveryIntent) { + if (TextUtils.isEmpty(destinationAddress)) { + throw new IllegalArgumentException("Invalid destinationAddress"); + } + + if (TextUtils.isEmpty(text)) { + throw new IllegalArgumentException("Invalid message body"); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu( + scAddress, destinationAddress, text, (deliveryIntent != null)); + sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + } + + /** + * Divide a text message into several messages, none bigger than + * the maximum SMS message size. + * + * @param text the original message. Must not be null. + * @return an <code>ArrayList</code> of strings that, in order, + * comprise the original message + */ + public ArrayList<String> divideMessage(String text) { + int size = text.length(); + int[] params = SmsMessage.calculateLength(text, false); + /* SmsMessage.calculateLength returns an int[4] with: + * int[0] being the number of SMS's required, + * int[1] the number of code units used, + * int[2] is the number of code units remaining until the next message. + * int[3] is the encoding type that should be used for the message. + */ + int messageCount = params[0]; + int encodingType = params[3]; + ArrayList<String> result = new ArrayList<String>(messageCount); + + int start = 0; + int limit; + + if (messageCount > 1) { + limit = (encodingType == ENCODING_7BIT)? + MAX_USER_DATA_SEPTETS_WITH_HEADER: MAX_USER_DATA_BYTES_WITH_HEADER; + } else { + limit = (encodingType == ENCODING_7BIT)? + MAX_USER_DATA_SEPTETS: MAX_USER_DATA_BYTES; + } + + try { + while (start < size) { + int end = GsmAlphabet.findLimitIndex(text, start, limit, encodingType); + result.add(text.substring(start, end)); + start = end; + } + } + catch (EncodeException e) { + // ignore it. + } + return result; + } + + /** + * Send a multi-part text based SMS. The callee should have already + * divided the message into correctly sized parts by calling + * <code>divideMessage</code>. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param parts an <code>ArrayList</code> of strings that, in order, + * comprise the original message + * @param sentIntents if not null, an <code>ArrayList</code> of + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors: + * <code>RESULT_ERROR_GENERIC_FAILURE</code> + * <code>RESULT_ERROR_RADIO_OFF</code> + * <code>RESULT_ERROR_NULL_PDU</code>. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applicaitons, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntents if not null, an <code>ArrayList</code> of + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or data are empty + */ + public void sendMultipartTextMessage( + String destinationAddress, String scAddress, ArrayList<String> parts, + ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { + if (TextUtils.isEmpty(destinationAddress)) { + throw new IllegalArgumentException("Invalid destinationAddress"); + } + if (parts == null || parts.size() < 1) { + throw new IllegalArgumentException("Invalid message body"); + } + + if (parts.size() > 1) { + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + iccISms.sendMultipartText(destinationAddress, scAddress, parts, + sentIntents, deliveryIntents); + } + } catch (RemoteException ex) { + // ignore it + } + } else { + PendingIntent sentIntent = null; + PendingIntent deliveryIntent = null; + if (sentIntents != null && sentIntents.size() > 0) { + sentIntent = sentIntents.get(0); + } + if (deliveryIntents != null && deliveryIntents.size() > 0) { + deliveryIntent = deliveryIntents.get(0); + } + sendTextMessage(destinationAddress, scAddress, parts.get(0), + sentIntent, deliveryIntent); + } + } + + /** + * Send a data based SMS to a specific application port. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param destinationPort the port to deliver the message to + * @param data the body of the message to send + * @param sentIntent if not NULL this <code>PendingIntent</code> is + * broadcast when the message is sucessfully sent, or failed. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors: + * <code>RESULT_ERROR_GENERIC_FAILURE</code> + * <code>RESULT_ERROR_RADIO_OFF</code> + * <code>RESULT_ERROR_NULL_PDU</code>. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applicaitons, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this <code>PendingIntent</code> is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or data are empty + */ + public void sendDataMessage( + String destinationAddress, String scAddress, short destinationPort, + byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { + if (TextUtils.isEmpty(destinationAddress)) { + throw new IllegalArgumentException("Invalid destinationAddress"); + } + + if (data == null || data.length == 0) { + throw new IllegalArgumentException("Invalid message data"); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu( + scAddress, destinationAddress, + destinationPort, data, (deliveryIntent != null)); + sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + } + + /** + * Send a raw SMS PDU. + * + * @param smsc the SMSC to send the message through, or NULL for the + * default SMSC + * @param pdu the raw PDU to send + * @param sentIntent if not NULL this <code>PendingIntent</code> is + * broadcast when the message is successfully sent, or failed. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors: + * <code>RESULT_ERROR_GENERIC_FAILURE</code> + * <code>RESULT_ERROR_RADIO_OFF</code> + * <code>RESULT_ERROR_NULL_PDU</code>. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this <code>PendingIntent</code> is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * + * @hide + */ + private void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + iccISms.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); + } + } catch (RemoteException ex) { + // ignore it + } + } + + /** + * Get the default instance of the SmsManager + * + * @return the default instance of the SmsManager + */ + public static SmsManager getDefault() { + if (sInstance == null) { + sInstance = new SmsManager(); + } + return sInstance; + } + + private SmsManager() { + //nothing + } + + /** + * Copy a raw SMS PDU to the ICC. + * + * @param smsc the SMSC for this message, or NULL for the default SMSC + * @param pdu the raw PDU to store + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) + * @return true for success + * + * {@hide} + */ + public boolean copyMessageToIcc(byte[] smsc, byte[] pdu, int status) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.copyMessageToIccEf(status, pdu, smsc); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Delete the specified message from the ICC. + * + * @param messageIndex is the record index of the message on ICC + * @return true for success + * + * {@hide} + */ + public boolean + deleteMessageFromIcc(int messageIndex) { + boolean success = false; + byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1]; + Arrays.fill(pdu, (byte)0xff); + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.updateMessageOnIccEf(messageIndex, STATUS_ON_ICC_FREE, pdu); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Update the specified message on the ICC. + * + * @param messageIndex record index of message to update + * @param newStatus new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) + * @param pdu the raw PDU to store + * @return true for success + * + * {@hide} + */ + public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) { + boolean success = false; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + success = iccISms.updateMessageOnIccEf(messageIndex, newStatus, pdu); + } + } catch (RemoteException ex) { + // ignore it + } + + return success; + } + + /** + * Retrieves all messages currently stored on ICC. + * + * @return <code>ArrayList</code> of <code>SmsMessage</code> objects + * + * {@hide} + */ + public ArrayList<SmsMessage> getAllMessagesFromIcc() { + List<SmsRawData> records = null; + + try { + ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); + if (iccISms != null) { + records = iccISms.getAllMessagesFromIccEf(); + } + } catch (RemoteException ex) { + // ignore it + } + + return createMessageListFromRawRecords(records); + } + + /** + * Create a list of <code>SmsMessage</code>s from a list of RawSmsData + * records returned by <code>getAllMessagesFromIcc()</code> + * + * @param records SMS EF records, returned by + * <code>getAllMessagesFromIcc</code> + * @return <code>ArrayList</code> of <code>SmsMessage</code> objects. + */ + private ArrayList<SmsMessage> createMessageListFromRawRecords(List records) { + ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>(); + if (records != null) { + int count = records.size(); + for (int i = 0; i < count; i++) { + SmsRawData data = (SmsRawData)records.get(i); + // List contains all records, including "free" records (null) + if (data != null) { + SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes()); + messages.add(sms); + } + } + } + return messages; + } + + // see SmsMessage.getStatusOnIcc + + /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_FREE = 0; + + /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_READ = 1; + + /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_UNREAD = 3; + + /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_SENT = 5; + + /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ + static public final int STATUS_ON_ICC_UNSENT = 7; + + // SMS send failure result codes + + /** Generic failure cause */ + static public final int RESULT_ERROR_GENERIC_FAILURE = 1; + /** Failed because radio was explicitly turned off */ + static public final int RESULT_ERROR_RADIO_OFF = 2; + /** Failed because no pdu provided */ + static public final int RESULT_ERROR_NULL_PDU = 3; + /** Failed because service is currently unavailable */ + static public final int RESULT_ERROR_NO_SERVICE = 4; +} diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java new file mode 100644 index 000000000000..1790bba86f9b --- /dev/null +++ b/telephony/java/android/telephony/SmsMessage.java @@ -0,0 +1,607 @@ +/* + * Copyright (C) 2008 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 android.telephony; + +import android.os.Parcel; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; + +import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; + + +/** + * A Short Message Service message. + * + */ +public class SmsMessage { + private static final boolean LOCAL_DEBUG = true; + private static final String LOG_TAG = "SMS"; + + /** + * SMS Class enumeration. + * See TS 23.038. + * + */ + public enum MessageClass{ + UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; + } + + /** Unknown encoding scheme (see TS 23.038) */ + public static final int ENCODING_UNKNOWN = 0; + /** 7-bit encoding scheme (see TS 23.038) */ + public static final int ENCODING_7BIT = 1; + /** 8-bit encoding scheme (see TS 23.038) */ + public static final int ENCODING_8BIT = 2; + /** 16-bit encoding scheme (see TS 23.038) */ + public static final int ENCODING_16BIT = 3; + + /** The maximum number of payload bytes per message */ + public static final int MAX_USER_DATA_BYTES = 140; + + /** + * The maximum number of payload bytes per message if a user data header + * is present. This assumes the header only contains the + * CONCATENATED_8_BIT_REFERENCE element. + * + * @hide pending API Council approval to extend the public API + */ + public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; + + /** The maximum number of payload septets per message */ + public static final int MAX_USER_DATA_SEPTETS = 160; + + /** + * The maximum number of payload septets per message if a user data header + * is present. This assumes the header only contains the + * CONCATENATED_8_BIT_REFERENCE element. + */ + public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; + + /** Contains actual SmsMessage. Only public for debugging and for framework layer. + * {@hide} + */ + public SmsMessageBase mWrappedSmsMessage; + + public static class SubmitPdu extends SubmitPduBase { + + //Constructor + public SubmitPdu() { + } + + /* {@hide} */ + protected SubmitPdu(SubmitPduBase spb) { + this.encodedMessage = spb.encodedMessage; + this.encodedScAddress = spb.encodedScAddress; + } + + } + + // Constructor + public SmsMessage() { + this(getSmsFacility()); + } + + private SmsMessage(SmsMessageBase smb) { + mWrappedSmsMessage = smb; + } + + /** + * Create an SmsMessage from a raw PDU. + */ + public static SmsMessage createFromPdu(byte[] pdu) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); + } + + return new SmsMessage(wrappedMessage); + } + + /** + * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the + * +CMT unsolicited response (PDU mode, of course) + * +CMT: [<alpha>],<length><CR><LF><pdu> + * + * Only public for debugging and for RIL + * + * {@hide} + */ + public static SmsMessage newFromCMT(String[] lines){ + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMT(lines); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines); + } + + return new SmsMessage(wrappedMessage); + } + + /** @hide */ + protected static SmsMessage newFromCMTI(String line) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMTI(line); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMTI(line); + } + + return new SmsMessage(wrappedMessage); + } + + /** @hide */ + public static SmsMessage newFromCDS(String line) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCDS(line); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCDS(line); + } + + return new SmsMessage(wrappedMessage); + } + + /** @hide */ + public static SmsMessage newFromParcel(Parcel p) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromParcel(p); + } + + return new SmsMessage(wrappedMessage); + } + + /** + * Create an SmsMessage from an SMS EF record. + * + * @param index Index of SMS record. This should be index in ArrayList + * returned by SmsManager.getAllMessagesFromSim + 1. + * @param data Record data. + * @return An SmsMessage representing the record. + * + * @hide + */ + public static SmsMessage createFromEfRecord(int index, byte[] data) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord( + index, data); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord( + index, data); + } + + return new SmsMessage(wrappedMessage); + } + + /** + * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the + * length in bytes (not hex chars) less the SMSC header + */ + public static int getTPLayerLengthForPDU(String pdu) { + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu); + } else { + return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu); + } + } + + /** + * Calculates the number of SMS's required to encode the message body and + * the number of characters remaining until the next message, given the + * current encoding. + * + * @param messageBody the message to encode + * @param use7bitOnly if true, characters that are not part of the GSM + * alphabet are counted as a single space char. If false, a + * messageBody containing non-GSM alphabet characters is calculated + * for 16-bit encoding. + * @return an int[4] with int[0] being the number of SMS's required, int[1] + * the number of code units used, and int[2] is the number of code + * units remaining until the next message. int[3] is the encoding + * type that should be used for the message. + */ + public static int[] calculateLength(String messageBody, boolean use7bitOnly) { + int ret[] = new int[4]; + + try { + // Try GSM alphabet + int septets = GsmAlphabet.countGsmSeptets(messageBody, !use7bitOnly); + ret[1] = septets; + if (septets > MAX_USER_DATA_SEPTETS) { + ret[0] = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1; + ret[2] = septets % MAX_USER_DATA_SEPTETS_WITH_HEADER; + } else { + ret[0] = 1; + ret[2] = MAX_USER_DATA_SEPTETS - septets; + } + ret[3] = ENCODING_7BIT; + } catch (EncodeException ex) { + // fall back to USC-2 + int octets = messageBody.length() * 2; + ret[1] = octets; + if (octets > MAX_USER_DATA_BYTES) { + // 6 is the size of the user data header + ret[0] = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1; + ret[2] = octets % MAX_USER_DATA_BYTES_WITH_HEADER; + } else { + ret[0] = 1; + ret[2] = MAX_USER_DATA_BYTES - octets; + } + ret[3] = ENCODING_16BIT; + } + + return ret; + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @hide + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested, byte[] header) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, header); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, header); + } + + return new SubmitPdu(spb); + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, boolean statusReportRequested) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested); + } + + return new SubmitPdu(spb); + } + + /** + * Get an SMS-SUBMIT PDU for a data message to a destination address & port + * + * @param scAddress Service Centre address. null == use default + * @param destinationAddress the address of the destination for the message + * @param destinationPort the port to deliver the message to at the + * destination + * @param data the dat for the message + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, short destinationPort, byte[] data, + boolean statusReportRequested) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); + } + + return new SubmitPdu(spb); + } + + /** + * Returns the address of the SMS service center that relayed this message + * or null if there is none. + */ + public String getServiceCenterAddress() { + return mWrappedSmsMessage.getServiceCenterAddress(); + } + + /** + * Returns the originating address (sender) of this SMS message in String + * form or null if unavailable + */ + public String getOriginatingAddress() { + return mWrappedSmsMessage.getOriginatingAddress(); + } + + /** + * Returns the originating address, or email from address if this message + * was from an email gateway. Returns null if originating address + * unavailable. + */ + public String getDisplayOriginatingAddress() { + return mWrappedSmsMessage.getDisplayOriginatingAddress(); + } + + /** + * Returns the message body as a String, if it exists and is text based. + * @return message body is there is one, otherwise null + */ + public String getMessageBody() { + return mWrappedSmsMessage.getMessageBody(); + } + + /** + * Returns the class of this message. + */ + public MessageClass getMessageClass() { + return mWrappedSmsMessage.getMessageClass(); + } + + /** + * Returns the message body, or email message body if this message was from + * an email gateway. Returns null if message body unavailable. + */ + public String getDisplayMessageBody() { + return mWrappedSmsMessage.getDisplayMessageBody(); + } + + /** + * Unofficial convention of a subject line enclosed in parens empty string + * if not present + */ + public String getPseudoSubject() { + return mWrappedSmsMessage.getPseudoSubject(); + } + + /** + * Returns the service centre timestamp in currentTimeMillis() format + */ + public long getTimestampMillis() { + return mWrappedSmsMessage.getTimestampMillis(); + } + + /** + * Returns true if message is an email. + * + * @return true if this message came through an email gateway and email + * sender / subject / parsed body are available + */ + public boolean isEmail() { + return mWrappedSmsMessage.isEmail(); + } + + /** + * @return if isEmail() is true, body of the email sent through the gateway. + * null otherwise + */ + public String getEmailBody() { + return mWrappedSmsMessage.getEmailBody(); + } + + /** + * @return if isEmail() is true, email from address of email sent through + * the gateway. null otherwise + */ + public String getEmailFrom() { + return mWrappedSmsMessage.getEmailFrom(); + } + + /** + * Get protocol identifier. + */ + public int getProtocolIdentifier() { + return mWrappedSmsMessage.getProtocolIdentifier(); + } + + /** + * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" + * SMS + */ + public boolean isReplace() { + return mWrappedSmsMessage.isReplace(); + } + + /** + * Returns true for CPHS MWI toggle message. + * + * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section + * B.4.2 + */ + public boolean isCphsMwiMessage() { + return mWrappedSmsMessage.isCphsMwiMessage(); + } + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) clear message + */ + public boolean isMWIClearMessage() { + return mWrappedSmsMessage.isMWIClearMessage(); + } + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) set message + */ + public boolean isMWISetMessage() { + return mWrappedSmsMessage.isMWISetMessage(); + } + + /** + * returns true if this message is a "Message Waiting Indication Group: + * Discard Message" notification and should not be stored. + */ + public boolean isMwiDontStore() { + return mWrappedSmsMessage.isMwiDontStore(); + } + + /** + * returns the user data section minus the user data header if one was + * present. + */ + public byte[] getUserData() { + return mWrappedSmsMessage.getUserData(); + } + + /* Not part of the SDK interface and only needed by specific classes: + protected SmsHeader getUserDataHeader() + */ + + /** + * Returns the raw PDU for the message. + * + * @return the raw PDU for the message. + */ + public byte[] getPdu() { + return mWrappedSmsMessage.getPdu(); + } + + /** + * Returns the status of the message on the SIM (read, unread, sent, unsent). + * + * @return the status of the message on the SIM. These are: + * SmsManager.STATUS_ON_SIM_FREE + * SmsManager.STATUS_ON_SIM_READ + * SmsManager.STATUS_ON_SIM_UNREAD + * SmsManager.STATUS_ON_SIM_SEND + * SmsManager.STATUS_ON_SIM_UNSENT + * @deprecated Use getStatusOnIcc instead. + */ + @Deprecated public int getStatusOnSim() { + return mWrappedSmsMessage.getStatusOnIcc(); + } + + /** + * Returns the status of the message on the ICC (read, unread, sent, unsent). + * + * @return the status of the message on the ICC. These are: + * SmsManager.STATUS_ON_ICC_FREE + * SmsManager.STATUS_ON_ICC_READ + * SmsManager.STATUS_ON_ICC_UNREAD + * SmsManager.STATUS_ON_ICC_SEND + * SmsManager.STATUS_ON_ICC_UNSENT + */ + public int getStatusOnIcc() { + + return mWrappedSmsMessage.getStatusOnIcc(); + } + + /** + * Returns the record index of the message on the SIM (1-based index). + * @return the record index of the message on the SIM, or -1 if this + * SmsMessage was not created from a SIM SMS EF record. + * @deprecated Use getIndexOnIcc instead. + */ + @Deprecated public int getIndexOnSim() { + return mWrappedSmsMessage.getIndexOnIcc(); + } + + /** + * Returns the record index of the message on the ICC (1-based index). + * @return the record index of the message on the ICC, or -1 if this + * SmsMessage was not created from a ICC SMS EF record. + */ + public int getIndexOnIcc() { + + return mWrappedSmsMessage.getIndexOnIcc(); + } + + /** + * GSM: + * For an SMS-STATUS-REPORT message, this returns the status field from + * the status report. This field indicates the status of a previously + * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a + * description of values. + * CDMA: + * For not interfering with status codes from GSM, the value is + * shifted to the bits 31-16. + * The value is composed of an error class (bits 25-24) and a status code (bits 23-16). + * Possible codes are described in C.S0015-B, v2.0, 4.5.21. + * + * @return 0 indicates the previously sent message was received. + * See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21 + * for a description of other possible values. + */ + public int getStatus() { + return mWrappedSmsMessage.getStatus(); + } + + /** + * Return true iff the message is a SMS-STATUS-REPORT message. + */ + public boolean isStatusReportMessage() { + return mWrappedSmsMessage.isStatusReportMessage(); + } + + /** + * Returns true iff the <code>TP-Reply-Path</code> bit is set in + * this message. + */ + public boolean isReplyPathPresent() { + return mWrappedSmsMessage.isReplyPathPresent(); + } + + /** This method returns the reference to a specific + * SmsMessage object, which is used for accessing its static methods. + * @return Specific SmsMessage. + */ + private static final SmsMessageBase getSmsFacility(){ + int activePhone = TelephonyManager.getDefault().getPhoneType(); + if (PHONE_TYPE_CDMA == activePhone) { + return new com.android.internal.telephony.cdma.SmsMessage(); + } else { + return new com.android.internal.telephony.gsm.SmsMessage(); + } + } +} diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 82e612073df7..55983d19a385 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -21,30 +21,31 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; -import android.telephony.CellLocation; +import android.telephony.CellLocation; import com.android.internal.telephony.IPhoneSubInfo; import com.android.internal.telephony.ITelephony; import com.android.internal.telephony.ITelephonyRegistry; +import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.TelephonyProperties; /** * Provides access to information about the telephony services on * the device. Applications can use the methods in this class to * determine telephony services and states, as well as to access some - * types of subscriber information. Applications can also register - * a listener to receive notification of telephony state changes. + * types of subscriber information. Applications can also register + * a listener to receive notification of telephony state changes. * <p> * You do not instantiate this class directly; instead, you retrieve - * a reference to an instance through + * a reference to an instance through * {@link android.content.Context#getSystemService * Context.getSystemService(Context.TELEPHONY_SERVICE)}. * <p> * Note that acess to some telephony information is - * permission-protected. Your application cannot access the protected - * information unless it has the appropriate permissions declared in - * its manifest file. Where permissions apply, they are noted in the - * the methods through which you access the protected information. + * permission-protected. Your application cannot access the protected + * information unless it has the appropriate permissions declared in + * its manifest file. Where permissions apply, they are noted in the + * the methods through which you access the protected information. */ public class TelephonyManager { private static final String TAG = "TelephonyManager"; @@ -77,10 +78,10 @@ public class TelephonyManager { // /** - * Returns the software version number for the device, for example, + * Returns the software version number for the device, for example, * the IMEI/SV for GSM phones. * - * <p>Requires Permission: + * <p>Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceSoftwareVersion() { @@ -92,10 +93,10 @@ public class TelephonyManager { } /** - * Returns the unique device ID, for example,the IMEI for GSM + * Returns the unique device ID, for example, the IMEI for GSM and the MEID for CDMA * phones. * - * <p>Requires Permission: + * <p>Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceId() { @@ -115,9 +116,7 @@ public class TelephonyManager { public CellLocation getCellLocation() { try { Bundle bundle = getITelephony().getCellLocation(); - // TODO remove cdma and gsmCellLocation make CellLocation - // active and define different impl in the phone - return CellLocation.newFromBundle(bundle); + return CellLocation.newFromBundle(bundle); } catch (RemoteException ex) { } return null; @@ -127,7 +126,7 @@ public class TelephonyManager { * Enables location update notifications. {@link PhoneStateListener#onCellLocationChanged * PhoneStateListener.onCellLocationChanged} will be called on location updates. * - * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES + * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES * CONTROL_LOCATION_UPDATES} * * @hide @@ -166,23 +165,36 @@ public class TelephonyManager { public static final int PHONE_TYPE_GSM = 1; /** - * Returns a constant indicating the device phone type. - * + * CDMA phone + */ + public static final int PHONE_TYPE_CDMA = 2; + + /** + * Returns a constant indicating the device phone type. + * * @see #PHONE_TYPE_NONE * @see #PHONE_TYPE_GSM + * @see #PHONE_TYPE_CDMA */ public int getPhoneType() { - // in the future, we should really check this - return PHONE_TYPE_GSM; + try{ + if(getITelephony().getActivePhoneType() == RILConstants.CDMA_PHONE) { + return PHONE_TYPE_CDMA; + } else { + return PHONE_TYPE_GSM; + } + }catch(RemoteException ex){ + return PHONE_TYPE_NONE; + } } // - // + // // Current Network // // - /** + /** * Returns the alphabetic name of current registered operator. * <p> * Availability: Only when user is registered to a network @@ -191,7 +203,7 @@ public class TelephonyManager { return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ALPHA); } - /** + /** * Returns the numeric name (MCC+MNC) of current registered operator. * <p> * Availability: Only when user is registered to a network @@ -200,7 +212,7 @@ public class TelephonyManager { return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC); } - /** + /** * Returns true if the device is considered roaming on the current * network, for GSM purposes. * <p> @@ -210,7 +222,7 @@ public class TelephonyManager { return "true".equals(SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING)); } - /** + /** * Returns the ISO country code equivilent of the current registered * operator's MCC (Mobile Country Code). * <p> @@ -237,7 +249,7 @@ public class TelephonyManager { public static final int NETWORK_TYPE_1xRTT = 7; /** - * Returns a constant indicating the radio technology (network type) + * Returns a constant indicating the radio technology (network type) * currently in use on the device. * * @see #NETWORK_TYPE_UNKNOWN @@ -285,7 +297,7 @@ public class TelephonyManager { /** SIM card state: Unknown. Signifies that the SIM is in transition * between states. For example, when the user inputs the SIM pin - * under PIN_REQUIRED state, a query for sim status returns + * under PIN_REQUIRED state, a query for sim status returns * this state before turning to SIM_STATE_READY. */ public static final int SIM_STATE_UNKNOWN = 0; /** SIM card state: no SIM card is available in the device */ @@ -298,11 +310,11 @@ public class TelephonyManager { public static final int SIM_STATE_NETWORK_LOCKED = 4; /** SIM card state: Ready */ public static final int SIM_STATE_READY = 5; - - /** - * Returns a constant indicating the state of the + + /** + * Returns a constant indicating the state of the * device SIM card. - * + * * @see #SIM_STATE_UNKNOWN * @see #SIM_STATE_ABSENT * @see #SIM_STATE_PIN_REQUIRED @@ -332,7 +344,7 @@ public class TelephonyManager { } } - /** + /** * Returns the MCC+MNC (mobile country code + mobile network code) of the * provider of the SIM. 5 or 6 decimal digits. * <p> @@ -341,31 +353,31 @@ public class TelephonyManager { * @see #getSimState */ public String getSimOperator() { - return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC); + return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC); } - /** - * Returns the Service Provider Name (SPN). + /** + * Returns the Service Provider Name (SPN). * <p> * Availability: SIM state must be {@link #SIM_STATE_READY} * * @see #getSimState */ public String getSimOperatorName() { - return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_ALPHA); + return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA); } - /** + /** * Returns the ISO country code equivalent for the SIM provider's country code. */ public String getSimCountryIso() { - return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_ISO_COUNTRY); + return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY); } /** * Returns the serial number of the SIM, if applicable. * <p> - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getSimSerialNumber() { @@ -385,7 +397,7 @@ public class TelephonyManager { /** * Returns the unique subscriber ID, for example, the IMSI for a GSM phone. * <p> - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getSubscriberId() { @@ -397,10 +409,10 @@ public class TelephonyManager { } /** - * Returns the phone number string for line 1, for example, the MSISDN + * Returns the phone number string for line 1, for example, the MSISDN * for a GSM phone. * <p> - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getLine1Number() { @@ -412,9 +424,9 @@ public class TelephonyManager { } /** - * Returns the alphabetic identifier associated with the line 1 number. + * Returns the alphabetic identifier associated with the line 1 number. * <p> - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * @hide * nobody seems to call this. @@ -430,7 +442,7 @@ public class TelephonyManager { /** * Returns the voice mail number. * <p> - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getVoiceMailNumber() { @@ -445,7 +457,7 @@ public class TelephonyManager { * Retrieves the alphabetic identifier associated with the voice * mail number. * <p> - * Requires Permission: + * Requires Permission: * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getVoiceMailAlphaTag() { @@ -465,10 +477,10 @@ public class TelephonyManager { /** Device call state: No activity. */ public static final int CALL_STATE_IDLE = 0; /** Device call state: Ringing. A new call arrived and is - * ringing or waiting. In the latter case, another call is + * ringing or waiting. In the latter case, another call is * already active. */ public static final int CALL_STATE_RINGING = 1; - /** Device call state: Off-hook. At least one call exists + /** Device call state: Off-hook. At least one call exists * that is dialing, active, or on hold, and no calls are ringing * or waiting. */ public static final int CALL_STATE_OFFHOOK = 2; @@ -519,13 +531,13 @@ public class TelephonyManager { public static final int DATA_CONNECTING = 1; /** Data connection state: Connected. IP traffic should be available. */ public static final int DATA_CONNECTED = 2; - /** Data connection state: Suspended. The connection is up, but IP - * traffic is temporarily unavailable. For example, in a 2G network, + /** Data connection state: Suspended. The connection is up, but IP + * traffic is temporarily unavailable. For example, in a 2G network, * data activity may be suspended when a voice call arrives. */ public static final int DATA_SUSPENDED = 3; /** - * Returns a constant indicating the current data connection state + * Returns a constant indicating the current data connection state * (cellular). * * @see #DATA_DISCONNECTED @@ -553,26 +565,26 @@ public class TelephonyManager { // /** - * Registers a listener object to receive notification of changes - * in specified telephony states. + * Registers a listener object to receive notification of changes + * in specified telephony states. * <p> * To register a listener, pass a {@link PhoneStateListener} - * and specify at least one telephony state of interest in - * the events argument. - * + * and specify at least one telephony state of interest in + * the events argument. + * * At registration, and when a specified telephony state - * changes, the telephony manager invokes the appropriate - * callback method on the listener object and passes the + * changes, the telephony manager invokes the appropriate + * callback method on the listener object and passes the * current (udpated) values. * <p> * To unregister a listener, pass the listener object and set the - * events argument to + * events argument to * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0). - * + * * @param listener The {@link PhoneStateListener} object to register * (or unregister) * @param events The telephony state(s) of interest to the listener, - * as a bitwise-OR combination of {@link PhoneStateListener} + * as a bitwise-OR combination of {@link PhoneStateListener} * LISTEN_ flags. */ public void listen(PhoneStateListener listener, int events) { @@ -624,8 +636,8 @@ public class TelephonyManager { * These have not been implemented because they're not public IMHO. -joeo */ - /* - * Baseband version + /* + * Baseband version * Availability: property is available any time radio is on */ /* diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java index 7cf8a9a66b0a..18e62f836dfb 100644 --- a/telephony/java/android/telephony/cdma/CdmaCellLocation.java +++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java @@ -78,7 +78,7 @@ public class CdmaCellLocation extends CellLocation { /** * Set the cell location data. */ - public void setCellLocationData(int baseStationId, int baseStationLatitude, + public void setCellLocationData(int baseStationId, int baseStationLatitude, int baseStationLongitude) { // The following values have to be written in the correct sequence this.mBaseStationId = baseStationId; @@ -114,7 +114,7 @@ public class CdmaCellLocation extends CellLocation { @Override public String toString() { return "[" + this.mBaseStationId + "," - + this.mBaseStationLatitude + "," + + this.mBaseStationLatitude + "," + this.mBaseStationLongitude + "]"; } diff --git a/telephony/java/android/telephony/cdma/TtyIntent.java b/telephony/java/android/telephony/cdma/TtyIntent.java deleted file mode 100644 index 4b8759c214d9..000000000000 --- a/telephony/java/android/telephony/cdma/TtyIntent.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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 android.telephony.cdma; - -/*import android.os.RemoteException; -import android.util.Log; -import com.android.internal.telephony.Phone; -import android.os.Message; -import android.os.Handler; -import android.os.AsyncResult; -*/ - -public class TtyIntent { - - private static final String TAG = "TtyIntent"; - -// private Phone mPhone; -// private boolean mTTYenabled = false; - - /** Event for TTY mode change */ -// private static final int EVENT_TTY_EXECUTED = 1; - - /** - * Broadcast intent action indicating that the TTY has either been - * enabled or disabled. An intent extra provides this state as a boolean, - * where {@code true} means enabled. - * @see #TTY_ENABLED - * - * {@hide} - */ - public static final String TTY_ENABLED_CHANGE_ACTION = - "android.telephony.cdma.intent.action.TTY_ENABLED_CHANGE"; - - /** - * The lookup key for a boolean that indicates whether TTY mode is enabled or - * disabled. {@code true} means TTY mode is enabled. Retrieve it with - * {@link android.content.Intent#getBooleanExtra(String,boolean)}. - * - * {@hide} - */ - public static final String TTY_ENABLED = "ttyEnabled"; - - /** - * Get the current status of TTY status. - * - * @return true if TTY Mode enabled, false otherwise. - */ -/* public boolean isEnabled() { - mPhone.queryTTYModeEnabled(Message.obtain(mQueryTTYComplete, EVENT_TTY_EXECUTED)); - - return mTTYenabled; - } - - private Handler mQueryTTYComplete = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_TTY_EXECUTED: - //handleQueryTTYModeMessage((AsyncResult) msg.obj); - AsyncResult ar = (AsyncResult) msg.obj; - if (ar.exception != null) { - Log.w(TAG, "handleMessage: Error getting TTY enable state."); - } - else { - int ttyArray[] = (int[]) ar.result; - if (ttyArray[0] == 1) { - //TTY Mode enabled - mTTYenabled = true; - Log.w(TAG, "handleMessage: mTTYenabled: " + mTTYenabled); - } - else { - // TTY disabled - mTTYenabled = false; - Log.w(TAG, "handleMessage: mTTYenabled: " + mTTYenabled); - } - } - break; - default: - // TODO: should never reach this, may want to throw exception - } - } - }; - */ -} diff --git a/telephony/java/android/telephony/cdma/package.html b/telephony/java/android/telephony/cdma/package.html new file mode 100644 index 000000000000..ee4af5e30f09 --- /dev/null +++ b/telephony/java/android/telephony/cdma/package.html @@ -0,0 +1,5 @@ +<HTML> +<BODY> +Provides APIs for utilizing CDMA-specific telephony features. +</BODY> +</HTML>
\ No newline at end of file diff --git a/telephony/java/android/telephony/gsm/GsmCellLocation.java b/telephony/java/android/telephony/gsm/GsmCellLocation.java index 7a5218c1ff17..637a11cb819f 100644 --- a/telephony/java/android/telephony/gsm/GsmCellLocation.java +++ b/telephony/java/android/telephony/gsm/GsmCellLocation.java @@ -80,7 +80,7 @@ public class GsmCellLocation extends CellLocation { @Override public boolean equals(Object o) { GsmCellLocation s; - + try { s = (GsmCellLocation)o; } catch (ClassCastException ex) { @@ -98,7 +98,7 @@ public class GsmCellLocation extends CellLocation { public String toString() { return "["+ mLac + "," + mCid + "]"; } - + /** * Test whether two objects hold the same data values or both are null * diff --git a/telephony/java/android/telephony/gsm/SmsManager.java b/telephony/java/android/telephony/gsm/SmsManager.java index fd7521199f47..cdd707e629a2 100644 --- a/telephony/java/android/telephony/gsm/SmsManager.java +++ b/telephony/java/android/telephony/gsm/SmsManager.java @@ -17,28 +17,35 @@ package android.telephony.gsm; import android.app.PendingIntent; -import android.os.RemoteException; -import android.os.IServiceManager; -import android.os.ServiceManager; -import android.os.ServiceManagerNative; -import android.text.TextUtils; - -import com.android.internal.telephony.gsm.EncodeException; -import com.android.internal.telephony.gsm.GsmAlphabet; -import com.android.internal.telephony.gsm.ISms; -import com.android.internal.telephony.IccConstants; -import com.android.internal.telephony.gsm.SmsRawData; import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; + /** * Manages SMS operations such as sending data, text, and pdu SMS messages. * Get this object by calling the static method SmsManager.getDefault(). + * @deprecated Replaced by android.telephony.SmsManager that supports both GSM and CDMA. */ -public final class SmsManager { +@Deprecated public final class SmsManager { private static SmsManager sInstance; + private android.telephony.SmsManager mSmsMgrProxy; + + /** Get the default instance of the SmsManager + * + * @return the default instance of the SmsManager + * @deprecated Use android.telephony.SmsManager. + */ + @Deprecated + public static final SmsManager getDefault() { + if (sInstance == null) { + sInstance = new SmsManager(); + } + return sInstance; + } + + private SmsManager() { + mSmsMgrProxy = android.telephony.SmsManager.getDefault(); + } /** * Send a text based SMS. @@ -55,28 +62,21 @@ public final class SmsManager { * <code>RESULT_ERROR_RADIO_OFF</code> * <code>RESULT_ERROR_NULL_PDU</code>. * The per-application based SMS control checks sentIntent. If sentIntent - * is NULL the caller will be checked against all unknown applicaitons, + * is NULL the caller will be checked against all unknown applications, * which cause smaller number of SMS to be sent in checking period. * @param deliveryIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is delivered to the recipient. The * raw pdu of the status report is in the extended data ("pdu"). * * @throws IllegalArgumentException if destinationAddress or text are empty + * @deprecated Use android.telephony.SmsManager. */ - public void sendTextMessage( + @Deprecated + public final void sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { - if (TextUtils.isEmpty(destinationAddress)) { - throw new IllegalArgumentException("Invalid destinationAddress"); - } - - if (TextUtils.isEmpty(text)) { - throw new IllegalArgumentException("Invalid message body"); - } - - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu( - scAddress, destinationAddress, text, (deliveryIntent != null)); - sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + mSmsMgrProxy.sendTextMessage(destinationAddress, scAddress, text, + sentIntent, deliveryIntent); } /** @@ -86,56 +86,24 @@ public final class SmsManager { * @param text the original message. Must not be null. * @return an <code>ArrayList</code> of strings that, in order, * comprise the original message + * @deprecated Use android.telephony.SmsManager. */ - public ArrayList<String> divideMessage(String text) { - int size = text.length(); - int[] params = SmsMessage.calculateLength(text, false); - /* SmsMessage.calculateLength returns an int[4] with: - * int[0] being the number of SMS's required, - * int[1] the number of code units used, - * int[2] is the number of code units remaining until the next message. - * int[3] is the encoding type that should be used for the message. - */ - int messageCount = params[0]; - int encodingType = params[3]; - ArrayList<String> result = new ArrayList<String>(messageCount); - - int start = 0; - int limit; - - if (messageCount > 1) { - limit = (encodingType == SmsMessage.ENCODING_7BIT)? - SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER - : SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; - } else { - limit = (encodingType == SmsMessage.ENCODING_7BIT)? - SmsMessage.MAX_USER_DATA_SEPTETS: SmsMessage.MAX_USER_DATA_BYTES; - } - - try { - while (start < size) { - int end = GsmAlphabet.findLimitIndex(text, start, limit, encodingType); - result.add(text.substring(start, end)); - start = end; - } - } - catch (EncodeException e) { - // ignore it. - } - return result; + @Deprecated + public final ArrayList<String> divideMessage(String text) { + return mSmsMgrProxy.divideMessage(text); } /** * Send a multi-part text based SMS. The callee should have already * divided the message into correctly sized parts by calling * <code>divideMessage</code>. - * + * * @param destinationAddress the address to send the message to * @param scAddress is the service center address or null to use * the current default SMSC * @param parts an <code>ArrayList</code> of strings that, in order, * comprise the original message - * @param sentIntents if not null, an <code>ArrayList</code> of + * @param sentIntents if not null, an <code>ArrayList</code> of * <code>PendingIntent</code>s (one for each message part) that is * broadcast when the corresponding message part has been sent. * The result code will be <code>Activity.RESULT_OK<code> for success, @@ -146,44 +114,21 @@ public final class SmsManager { * The per-application based SMS control checks sentIntent. If sentIntent * is NULL the caller will be checked against all unknown applicaitons, * which cause smaller number of SMS to be sent in checking period. - * @param deliveryIntents if not null, an <code>ArrayList</code> of + * @param deliveryIntents if not null, an <code>ArrayList</code> of * <code>PendingIntent</code>s (one for each message part) that is * broadcast when the corresponding message part has been delivered * to the recipient. The raw pdu of the status report is in the * extended data ("pdu"). + * + * @throws IllegalArgumentException if destinationAddress or data are empty + * @deprecated Use android.telephony.SmsManager. */ - public void sendMultipartTextMessage( + @Deprecated + public final void sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { - if (TextUtils.isEmpty(destinationAddress)) { - throw new IllegalArgumentException("Invalid destinationAddress"); - } - if (parts == null || parts.size() < 1) { - throw new IllegalArgumentException("Invalid message body"); - } - - if (parts.size() > 1) { - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - simISms.sendMultipartText(destinationAddress, scAddress, parts, - sentIntents, deliveryIntents); - } - } catch (RemoteException ex) { - // ignore it - } - } else { - PendingIntent sentIntent = null; - PendingIntent deliveryIntent = null; - if (sentIntents != null && sentIntents.size() > 0) { - sentIntent = sentIntents.get(0); - } - if (deliveryIntents != null && deliveryIntents.size() > 0) { - deliveryIntent = deliveryIntents.get(0); - } - sendTextMessage(destinationAddress, scAddress, parts.get(0), - sentIntent, deliveryIntent); - } + mSmsMgrProxy.sendMultipartTextMessage(destinationAddress, scAddress, parts, + sentIntents, deliveryIntents); } /** @@ -209,70 +154,14 @@ public final class SmsManager { * raw pdu of the status report is in the extended data ("pdu"). * * @throws IllegalArgumentException if destinationAddress or data are empty + * @deprecated Use android.telephony.SmsManager. */ - public void sendDataMessage( + @Deprecated + public final void sendDataMessage( String destinationAddress, String scAddress, short destinationPort, byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { - if (TextUtils.isEmpty(destinationAddress)) { - throw new IllegalArgumentException("Invalid destinationAddress"); - } - - if (data == null || data.length == 0) { - throw new IllegalArgumentException("Invalid message data"); - } - - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - destinationPort, data, (deliveryIntent != null)); - sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); - } - - /** - * Send a raw SMS PDU. - * - * @param smsc the SMSC to send the message through, or NULL for the - * default SMSC - * @param pdu the raw PDU to send - * @param sentIntent if not NULL this <code>PendingIntent</code> is - * broadcast when the message is sucessfully sent, or failed. - * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. - * The per-application based SMS control checks sentIntent. If sentIntent - * is NULL the caller will be checked against all unknown applicaitons, - * which cause smaller number of SMS to be sent in checking period. - * @param deliveryIntent if not NULL this <code>PendingIntent</code> is - * broadcast when the message is delivered to the recipient. The - * raw pdu of the status report is in the extended data ("pdu"). - * - */ - private void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, - PendingIntent deliveryIntent) { - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - simISms.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); - } - } catch (RemoteException ex) { - // ignore it - } - } - - /** - * Get the default instance of the SmsManager - * - * @return the default instance of the SmsManager - */ - public static SmsManager getDefault() { - if (sInstance == null) { - sInstance = new SmsManager(); - } - return sInstance; - } - - private SmsManager() { - // nothing to see here + mSmsMgrProxy.sendDataMessage(destinationAddress, scAddress, destinationPort, + data, sentIntent, deliveryIntent); } /** @@ -283,22 +172,12 @@ public final class SmsManager { * @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD, * STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT) * @return true for success - * + * @deprecated Use android.telephony.SmsManager. * {@hide} */ - public boolean copyMessageToSim(byte[] smsc, byte[] pdu, int status) { - boolean success = false; - - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - success = simISms.copyMessageToSimEf(status, pdu, smsc); - } - } catch (RemoteException ex) { - // ignore it - } - - return success; + @Deprecated + public final boolean copyMessageToSim(byte[] smsc, byte[] pdu, int status) { + return mSmsMgrProxy.copyMessageToIcc(smsc, pdu, status); } /** @@ -306,26 +185,12 @@ public final class SmsManager { * * @param messageIndex is the record index of the message on SIM * @return true for success - * + * @deprecated Use android.telephony.SmsManager. * {@hide} */ - public boolean - deleteMessageFromSim(int messageIndex) { - boolean success = false; - byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1]; - Arrays.fill(pdu, (byte)0xff); - - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - success = simISms.updateMessageOnSimEf(messageIndex, - STATUS_ON_SIM_FREE, pdu); - } - } catch (RemoteException ex) { - // ignore it - } - - return success; + @Deprecated + public final boolean deleteMessageFromSim(int messageIndex) { + return mSmsMgrProxy.deleteMessageFromIcc(messageIndex); } /** @@ -337,97 +202,59 @@ public final class SmsManager { * STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE) * @param pdu the raw PDU to store * @return true for success - * + * @deprecated Use android.telephony.SmsManager. * {@hide} */ - public boolean updateMessageOnSim(int messageIndex, int newStatus, - byte[] pdu) { - boolean success = false; - - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - success = simISms.updateMessageOnSimEf(messageIndex, newStatus, pdu); - } - } catch (RemoteException ex) { - // ignore it - } - - return success; + @Deprecated + public final boolean updateMessageOnSim(int messageIndex, int newStatus, byte[] pdu) { + return mSmsMgrProxy.updateMessageOnIcc(messageIndex, newStatus, pdu); } - /** * Retrieves all messages currently stored on SIM. - * * @return <code>ArrayList</code> of <code>SmsMessage</code> objects - * + * @deprecated Use android.telephony.SmsManager. * {@hide} */ - public ArrayList<SmsMessage> getAllMessagesFromSim() { - List<SmsRawData> records = null; + @Deprecated + public final ArrayList<android.telephony.SmsMessage> getAllMessagesFromSim() { + return mSmsMgrProxy.getAllMessagesFromIcc(); + } - try { - ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); - if (simISms != null) { - records = simISms.getAllMessagesFromSimEf(); - } - } catch (RemoteException ex) { - // ignore it - } - - return createMessageListFromRawRecords(records); - } + /** Free space (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_FREE = 0; - /** - * Create a list of <code>SmsMessage</code>s from a list of RawSmsData - * records returned by <code>getAllMessagesFromSim()</code> - * - * @param records SMS EF records, returned by - * <code>getAllMessagesFromSim</code> - * @return <code>ArrayList</code> of <code>SmsMessage</code> objects. - */ - private ArrayList<SmsMessage> createMessageListFromRawRecords(List records) { - ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>(); - if (records != null) { - int count = records.size(); - for (int i = 0; i < count; i++) { - SmsRawData data = (SmsRawData)records.get(i); - // List contains all records, including "free" records (null) - if (data != null) { - SmsMessage sms = - SmsMessage.createFromEfRecord(i+1, data.getBytes()); - messages.add(sms); - } - } - } - return messages; - } + /** Received and read (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_READ = 1; - /** Free space (TS 51.011 10.5.3). */ - static public final int STATUS_ON_SIM_FREE = 0; + /** Received and unread (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_UNREAD = 3; - /** Received and read (TS 51.011 10.5.3). */ - static public final int STATUS_ON_SIM_READ = 1; + /** Stored and sent (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_SENT = 5; - /** Received and unread (TS 51.011 10.5.3). */ - static public final int STATUS_ON_SIM_UNREAD = 3; + /** Stored and unsent (TS 51.011 10.5.3). + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int STATUS_ON_SIM_UNSENT = 7; - /** Stored and sent (TS 51.011 10.5.3). */ - static public final int STATUS_ON_SIM_SENT = 5; + /** Generic failure cause + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_GENERIC_FAILURE = 1; - /** Stored and unsent (TS 51.011 10.5.3). */ - static public final int STATUS_ON_SIM_UNSENT = 7; + /** Failed because radio was explicitly turned off + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_RADIO_OFF = 2; + /** Failed because no pdu provided + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_NULL_PDU = 3; - // SMS send failure result codes + /** Failed because service is currently unavailable + * @deprecated Use android.telephony.SmsManager. */ + @Deprecated static public final int RESULT_ERROR_NO_SERVICE = 4; - /** Generic failure cause */ - static public final int RESULT_ERROR_GENERIC_FAILURE = 1; - /** Failed because radio was explicitly turned off */ - static public final int RESULT_ERROR_RADIO_OFF = 2; - /** Failed because no pdu provided */ - static public final int RESULT_ERROR_NULL_PDU = 3; - /** Failed because service is currently unavailable */ - static public final int RESULT_ERROR_NO_SERVICE = 4; } diff --git a/telephony/java/android/telephony/gsm/SmsMessage.java b/telephony/java/android/telephony/gsm/SmsMessage.java index 9ccfa90d2e24..0bc1567e9e93 100644 --- a/telephony/java/android/telephony/gsm/SmsMessage.java +++ b/telephony/java/android/telephony/gsm/SmsMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2008 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. @@ -16,323 +16,117 @@ package android.telephony.gsm; -import android.pim.Time; -import android.telephony.PhoneNumberUtils; -import android.util.Config; -import android.util.Log; -import android.telephony.PhoneNumberUtils; -import com.android.internal.telephony.IccUtils; -import com.android.internal.telephony.gsm.EncodeException; -import com.android.internal.telephony.gsm.GsmAlphabet; -import com.android.internal.telephony.gsm.SmsHeader; - -import java.io.ByteArrayOutputStream; -import java.io.UnsupportedEncodingException; -import java.util.Arrays; - -class SmsAddress { - // From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118 - static final int TON_UNKNOWN = 0; - - static final int TON_INTERNATIONAL = 1; - - static final int TON_NATIONAL = 2; - - static final int TON_NETWORK = 3; - - static final int TON_SUBSCRIBER = 4; - - static final int TON_ALPHANUMERIC = 5; +import android.os.Parcel; +import android.telephony.TelephonyManager; - static final int TON_APPREVIATED = 6; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; - static final int OFFSET_ADDRESS_LENGTH = 0; - - static final int OFFSET_TOA = 1; - - static final int OFFSET_ADDRESS_VALUE = 2; +import java.util.Arrays; - int ton; +import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; - String address; - byte[] origBytes; +/** + * A Short Message Service message. + * @deprecated Replaced by android.telephony.SmsMessage that supports both GSM and CDMA. + */ +@Deprecated +public class SmsMessage { + private static final boolean LOCAL_DEBUG = true; + private static final String LOG_TAG = "SMS"; /** - * New SmsAddress from TS 23.040 9.1.2.5 Address Field - * - * @param offset the offset of the Address-Length byte - * @param length the length in bytes rounded up, e.g. "2 + - * (addressLength + 1) / 2" + * SMS Class enumeration. + * See TS 23.038. + * @deprecated Use android.telephony.SmsMessage. */ - - SmsAddress(byte[] data, int offset, int length) { - origBytes = new byte[length]; - System.arraycopy(data, offset, origBytes, 0, length); - - // addressLength is the count of semi-octets, not bytes - int addressLength = origBytes[OFFSET_ADDRESS_LENGTH] & 0xff; - - int toa = origBytes[OFFSET_TOA] & 0xff; - ton = 0x7 & (toa >> 4); - - // TOA must have its high bit set - if ((toa & 0x80) != 0x80) { - throw new RuntimeException("Invalid TOA - high bit must be set"); - } - - if (isAlphanumeric()) { - // An alphanumeric address - int countSeptets = addressLength * 4 / 7; - - address = GsmAlphabet.gsm7BitPackedToString(origBytes, - OFFSET_ADDRESS_VALUE, countSeptets); - } else { - // TS 23.040 9.1.2.5 says - // that "the MS shall interpret reserved values as 'Unknown' - // but shall store them exactly as received" - - byte lastByte = origBytes[length - 1]; - - if ((addressLength & 1) == 1) { - // Make sure the final unused BCD digit is 0xf - origBytes[length - 1] |= 0xf0; - } - address = PhoneNumberUtils.calledPartyBCDToString(origBytes, - OFFSET_TOA, length - OFFSET_TOA); - - // And restore origBytes - origBytes[length - 1] = lastByte; - } - } - - public String getAddressString() { - return address; + @Deprecated + public enum MessageClass{ + UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; } - /** - * Returns true if this is an alphanumeric addres + /** Unknown encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. */ - public boolean isAlphanumeric() { - return ton == TON_ALPHANUMERIC; - } - - public boolean isNetworkSpecific() { - return ton == TON_NETWORK; - } + @Deprecated public static final int ENCODING_UNKNOWN = 0; - /** - * Returns true of this is a valid CPHS voice message waiting indicator - * address + /** 7-bit encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. */ - public boolean isCphsVoiceMessageIndicatorAddress() { - // CPHS-style MWI message - // See CPHS 4.7 B.4.2.1 - // - // Basically: - // - // - Originating address should be 4 bytes long and alphanumeric - // - Decode will result with two chars: - // - Char 1 - // 76543210 - // ^ set/clear indicator (0 = clear) - // ^^^ type of indicator (000 = voice) - // ^^^^ must be equal to 0001 - // - Char 2: - // 76543210 - // ^ line number (0 = line 1) - // ^^^^^^^ set to 0 - // - // Remember, since the alpha address is stored in 7-bit compact form, - // the "line number" is really the top bit of the first address value - // byte - - return (origBytes[OFFSET_ADDRESS_LENGTH] & 0xff) == 4 - && isAlphanumeric() && (origBytes[OFFSET_TOA] & 0x0f) == 0; - } + @Deprecated public static final int ENCODING_7BIT = 1; - /** - * Returns true if this is a valid CPHS voice message waiting indicator - * address indicating a "set" of "indicator 1" of type "voice message - * waiting" + /** 8-bit encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. */ - public boolean isCphsVoiceMessageSet() { - // 0x11 means "set" "voice message waiting" "indicator 1" - return isCphsVoiceMessageIndicatorAddress() - && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x11; + @Deprecated public static final int ENCODING_8BIT = 2; - } - - /** - * Returns true if this is a valid CPHS voice message waiting indicator - * address indicationg a "clear" of "indicator 1" of type "voice message - * waiting" + /** 16-bit encoding scheme (see TS 23.038) + * @deprecated Use android.telephony.SmsMessage. */ - public boolean isCphsVoiceMessageClear() { - // 0x10 means "clear" "voice message waiting" "indicator 1" - return isCphsVoiceMessageIndicatorAddress() - && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x10; + @Deprecated public static final int ENCODING_16BIT = 3; - } - - public boolean couldBeEmailGateway() { - // Some carriers seems to send email gateway messages in this form: - // from: an UNKNOWN TON, 3 or 4 digits long, beginning with a 5 - // PID: 0x00, Data coding scheme 0x03 - // So we just attempt to treat any message from an address length <= 4 - // as an email gateway - - return address.length() <= 4; - } - -} - -/** - * A Short Message Service message. - * - */ -public class SmsMessage { - static final String LOG_TAG = "GSM"; - - /** - * SMS Class enumeration. - * See TS 23.038. - * + /** The maximum number of payload bytes per message + * @deprecated Use android.telephony.SmsMessage. */ - public enum MessageClass { - UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; - } - - /** Unknown encoding scheme (see TS 23.038) */ - public static final int ENCODING_UNKNOWN = 0; - /** 7-bit encoding scheme (see TS 23.038) */ - public static final int ENCODING_7BIT = 1; - /** 8-bit encoding scheme (see TS 23.038) */ - public static final int ENCODING_8BIT = 2; - /** 16-bit encoding scheme (see TS 23.038) */ - public static final int ENCODING_16BIT = 3; - - /** The maximum number of payload bytes per message */ - public static final int MAX_USER_DATA_BYTES = 140; + @Deprecated public static final int MAX_USER_DATA_BYTES = 140; /** * The maximum number of payload bytes per message if a user data header * is present. This assumes the header only contains the * CONCATENATED_8_BIT_REFERENCE element. - * + * + * @deprecated Use android.telephony.SmsMessage. * @hide pending API Council approval to extend the public API */ - public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; + @Deprecated public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; - /** The maximum number of payload septets per message */ - public static final int MAX_USER_DATA_SEPTETS = 160; + /** The maximum number of payload septets per message + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated public static final int MAX_USER_DATA_SEPTETS = 160; /** * The maximum number of payload septets per message if a user data header * is present. This assumes the header only contains the * CONCATENATED_8_BIT_REFERENCE element. + * @deprecated Use android.telephony.SmsMessage. */ - public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; - - /** The address of the SMSC. May be null */ - String scAddress; - - /** The address of the sender */ - SmsAddress originatingAddress; - - /** The message body as a string. May be null if the message isn't text */ - String messageBody; - - String pseudoSubject; - - /** Non-null this is an email gateway message */ - String emailFrom; - - /** Non-null if this is an email gateway message */ - String emailBody; - - boolean isEmail; - - long scTimeMillis; - - /** The raw PDU of the message */ - byte[] mPdu; - - /** The raw bytes for the user data section of the message */ - byte[] userData; - - SmsHeader userDataHeader; - - /** - * TP-Message-Type-Indicator - * 9.2.3 - */ - int mti; - - /** TP-Protocol-Identifier (TP-PID) */ - int protocolIdentifier; - - // TP-Data-Coding-Scheme - // see TS 23.038 - int dataCodingScheme; - - // TP-Reply-Path - // e.g. 23.040 9.2.2.1 - boolean replyPathPresent = false; - - // "Message Marked for Automatic Deletion Group" - // 23.038 Section 4 - boolean automaticDeletion; - - // "Message Waiting Indication Group" - // 23.038 Section 4 - private boolean isMwi; - - private boolean mwiSense; - - private boolean mwiDontStore; - - MessageClass messageClass; - - /** - * Indicates status for messages stored on the SIM. - */ - int statusOnSim = -1; + @Deprecated public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; - /** - * Record index of message in the EF. + /** Contains actual SmsMessage. Only public for debugging and for framework layer. + * @deprecated Use android.telephony.SmsMessage. + * {@hide} */ - int indexOnSim = -1; - - /** TP-Message-Reference - Message Reference of sent message. @hide */ - public int messageRef; - - /** True if Status Report is for SMS-SUBMIT; false for SMS-COMMAND. */ - boolean forSubmit; - - /** The address of the receiver. */ - SmsAddress recipientAddress; - - /** Time when SMS-SUBMIT was delivered from SC to MSE. */ - long dischargeTimeMillis; + @Deprecated public SmsMessageBase mWrappedSmsMessage; - /** - * TP-Status - status of a previously submitted SMS. - * This field applies to SMS-STATUS-REPORT messages. 0 indicates success; - * see TS 23.040, 9.2.3.15 for description of other possible values. - */ - int status; + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated + public static class SubmitPdu { + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public byte[] encodedScAddress; // Null if not applicable. + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public byte[] encodedMessage; - /** - * TP-Status - status of a previously submitted SMS. - * This field is true iff the message is a SMS-STATUS-REPORT message. - */ - boolean isStatusReportMessage = false; + //Constructor + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated + public SubmitPdu() { + } - public static class SubmitPdu { - public byte[] encodedScAddress; // Null if not applicable. - public byte[] encodedMessage; + /** @deprecated Use android.telephony.SmsMessage. + * {@hide} + */ + @Deprecated + protected SubmitPdu(SubmitPduBase spb) { + this.encodedMessage = spb.encodedMessage; + this.encodedScAddress = spb.encodedScAddress; + } + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String toString() { return "SubmitPdu: encodedScAddress = " + Arrays.toString(encodedScAddress) @@ -341,18 +135,33 @@ public class SmsMessage { } } + // Constructor + /** @deprecated Use android.telephony.SmsMessage. */ + @Deprecated + public SmsMessage() { + this(getSmsFacility()); + } + + private SmsMessage(SmsMessageBase smb) { + mWrappedSmsMessage = smb; + } + /** * Create an SmsMessage from a raw PDU. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public static SmsMessage createFromPdu(byte[] pdu) { - try { - SmsMessage msg = new SmsMessage(); - msg.parsePdu(pdu); - return msg; - } catch (RuntimeException ex) { - Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); - return null; + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu); } + + return new SmsMessage(wrappedMessage); } /** @@ -360,38 +169,70 @@ public class SmsMessage { * +CMT unsolicited response (PDU mode, of course) * +CMT: [<alpha>],<length><CR><LF><pdu> * - * Only public for debugging - * + * Only public for debugging and for RIL + * @deprecated Use android.telephony.SmsMessage. * {@hide} */ - /* package */ public static SmsMessage newFromCMT(String[] lines) { - try { - SmsMessage msg = new SmsMessage(); - msg.parsePdu(IccUtils.hexStringToBytes(lines[1])); - return msg; - } catch (RuntimeException ex) { - Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); - return null; + @Deprecated + public static SmsMessage newFromCMT(String[] lines){ + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMT(lines); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines); } + + return new SmsMessage(wrappedMessage); } - /* pacakge */ static SmsMessage newFromCMTI(String line) { - // the thinking here is not to read the message immediately - // FTA test case - Log.e(LOG_TAG, "newFromCMTI: not yet supported"); - return null; + /** @deprecated Use android.telephony.SmsMessage. + * @hide */ + @Deprecated + protected static SmsMessage newFromCMTI(String line) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMTI(line); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMTI(line); + } + + return new SmsMessage(wrappedMessage); } - /** @hide */ - /* package */ public static SmsMessage newFromCDS(String line) { - try { - SmsMessage msg = new SmsMessage(); - msg.parsePdu(IccUtils.hexStringToBytes(line)); - return msg; - } catch (RuntimeException ex) { - Log.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex); - return null; + /** @deprecated Use android.telephony.SmsMessage. + * @hide */ + @Deprecated + public static SmsMessage newFromCDS(String line) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCDS(line); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCDS(line); + } + + return new SmsMessage(wrappedMessage); + } + + /** @deprecated Use android.telephony.SmsMessage. + * @hide */ + @Deprecated + public static SmsMessage newFromParcel(Parcel p) { + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); + + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromParcel(p); } + + return new SmsMessage(wrappedMessage); } /** @@ -401,51 +242,40 @@ public class SmsMessage { * returned by SmsManager.getAllMessagesFromSim + 1. * @param data Record data. * @return An SmsMessage representing the record. - * + * + * @deprecated Use android.telephony.SmsMessage. * @hide */ + @Deprecated public static SmsMessage createFromEfRecord(int index, byte[] data) { - try { - SmsMessage msg = new SmsMessage(); - - msg.indexOnSim = index; - - // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, - // or STORED_UNSENT - // See TS 51.011 10.5.3 - if ((data[0] & 1) == 0) { - Log.w(LOG_TAG, - "SMS parsing failed: Trying to parse a free record"); - return null; - } else { - msg.statusOnSim = data[0] & 0x07; - } + SmsMessageBase wrappedMessage; + int activePhone = TelephonyManager.getDefault().getPhoneType(); - int size = data.length - 1; - - // Note: Data may include trailing FF's. That's OK; message - // should still parse correctly. - byte[] pdu = new byte[size]; - System.arraycopy(data, 1, pdu, 0, size); - msg.parsePdu(pdu); - return msg; - } catch (RuntimeException ex) { - Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); - return null; + if (PHONE_TYPE_CDMA == activePhone) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord( + index, data); + } else { + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord( + index, data); } + + return new SmsMessage(wrappedMessage); } /** * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the * length in bytes (not hex chars) less the SMSC header + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public static int getTPLayerLengthForPDU(String pdu) { - int len = pdu.length() / 2; - int smscLen = 0; - - smscLen = Integer.parseInt(pdu.substring(0, 2), 16); + int activePhone = TelephonyManager.getDefault().getPhoneType(); - return len - smscLen - 1; + if (PHONE_TYPE_CDMA == activePhone) { + return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu); + } else { + return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu); + } } /** @@ -462,7 +292,9 @@ public class SmsMessage { * the number of code units used, and int[2] is the number of code * units remaining until the next message. int[3] is the encoding * type that should be used for the message. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public static int[] calculateLength(String messageBody, boolean use7bitOnly) { int ret[] = new int[4]; @@ -496,7 +328,6 @@ public class SmsMessage { return ret; } - /** * Get an SMS-SUBMIT PDU for a destination address and a message * @@ -504,88 +335,27 @@ public class SmsMessage { * @return a <code>SubmitPdu</code> containing the encoded SC * address, if applicable, and the encoded message. * Returns null on encode error. + * @deprecated Use android.telephony.SmsMessage. * @hide */ + @Deprecated public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, String message, boolean statusReportRequested, byte[] header) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); - // Perform null parameter checks. - if (message == null || destinationAddress == null) { - return null; - } - - SubmitPdu ret = new SubmitPdu(); - // MTI = SMS-SUBMIT, UDHI = header != null - byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00)); - ByteArrayOutputStream bo = getSubmitPduHead( - scAddress, destinationAddress, mtiByte, - statusReportRequested, ret); - - try { - // First, try encoding it with the GSM alphabet - - // User Data (and length) - byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header); - - if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) { - // Message too long - return null; - } - - // TP-Data-Coding-Scheme - // Default encoding, uncompressed - bo.write(0x00); - - // (no TP-Validity-Period) - - bo.write(userData, 0, userData.length); - } catch (EncodeException ex) { - byte[] userData, textPart; - // Encoding to the 7-bit alphabet failed. Let's see if we can - // send it as a UCS-2 encoded message - - try { - textPart = message.getBytes("utf-16be"); - } catch (UnsupportedEncodingException uex) { - Log.e(LOG_TAG, - "Implausible UnsupportedEncodingException ", - uex); - return null; - } - - if (header != null) { - userData = new byte[header.length + textPart.length]; - - System.arraycopy(header, 0, userData, 0, header.length); - System.arraycopy(textPart, 0, userData, header.length, textPart.length); - } - else { - userData = textPart; - } - - if (userData.length > MAX_USER_DATA_BYTES) { - // Message too long - return null; - } - - // TP-Data-Coding-Scheme - // Class 3, UCS-2 encoding, uncompressed - bo.write(0x0b); - - // (no TP-Validity-Period) - - // TP-UDL - bo.write(userData.length); - - bo.write(userData, 0, userData.length); + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, header); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested, header); } - ret.encodedMessage = bo.toByteArray(); - return ret; + return new SubmitPdu(spb); } - /** * Get an SMS-SUBMIT PDU for a destination address and a message * @@ -593,12 +363,23 @@ public class SmsMessage { * @return a <code>SubmitPdu</code> containing the encoded SC * address, if applicable, and the encoded message. * Returns null on encode error. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public static SubmitPdu getSubmitPdu(String scAddress, - String destinationAddress, String message, - boolean statusReportRequested) { + String destinationAddress, String message, boolean statusReportRequested) { + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); - return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested); + } else { + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, message, statusReportRequested); + } + + return new SubmitPdu(spb); } /** @@ -612,475 +393,105 @@ public class SmsMessage { * @return a <code>SubmitPdu</code> containing the encoded SC * address, if applicable, and the encoded message. * Returns null on encode error. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public static SubmitPdu getSubmitPdu(String scAddress, String destinationAddress, short destinationPort, byte[] data, boolean statusReportRequested) { - if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) { - Log.e(LOG_TAG, "SMS data message may only contain " - + (MAX_USER_DATA_BYTES - 7) + " bytes"); - return null; - } - - SubmitPdu ret = new SubmitPdu(); - ByteArrayOutputStream bo = getSubmitPduHead( - scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT, - // TP-UDHI = true - statusReportRequested, ret); - - // TP-Data-Coding-Scheme - // No class, 8 bit data - bo.write(0x04); - - // (no TP-Validity-Period) - - // User data size - bo.write(data.length + 7); - - // User data header size - bo.write(0x06); // header is 6 octets - - // User data header, indicating the destination port - bo.write(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT); // port - // addressing - // header - bo.write(0x04); // each port is 2 octets - bo.write((destinationPort >> 8) & 0xFF); // MSB of destination port - bo.write(destinationPort & 0xFF); // LSB of destination port - bo.write(0x00); // MSB of originating port - bo.write(0x00); // LSB of originating port - - // User data - bo.write(data, 0, data.length); - - ret.encodedMessage = bo.toByteArray(); - return ret; - } + SubmitPduBase spb; + int activePhone = TelephonyManager.getDefault().getPhoneType(); - /** - * Create the beginning of a SUBMIT PDU. This is the part of the - * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu}, - * one of which takes a byte array and the other of which takes a - * <code>String</code>. - * - * @param scAddress Service Centre address. null == use default - * @param destinationAddress the address of the destination for the message - * @param mtiByte - * @param ret <code>SubmitPdu</code> containing the encoded SC - * address, if applicable, and the encoded message - */ - private static ByteArrayOutputStream getSubmitPduHead( - String scAddress, String destinationAddress, byte mtiByte, - boolean statusReportRequested, SubmitPdu ret) { - ByteArrayOutputStream bo = new ByteArrayOutputStream( - MAX_USER_DATA_BYTES + 40); - - // SMSC address with length octet, or 0 - if (scAddress == null) { - ret.encodedScAddress = null; + if (PHONE_TYPE_CDMA == activePhone) { + spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); } else { - ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( - scAddress); - } - - // TP-Message-Type-Indicator (and friends) - if (statusReportRequested) { - // Set TP-Status-Report-Request bit. - mtiByte |= 0x20; - if (Config.LOGD) Log.d(LOG_TAG, "SMS status report requested"); - } - bo.write(mtiByte); - - // space for TP-Message-Reference - bo.write(0); - - byte[] daBytes; - - daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress); - - // destination address length in BCD digits, ignoring TON byte and pad - // TODO Should be better. - bo.write((daBytes.length - 1) * 2 - - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0)); - - // destination address - bo.write(daBytes, 0, daBytes.length); - - // TP-Protocol-Identifier - bo.write(0); - return bo; - } - - static class PduParser { - byte pdu[]; - - int cur; - - SmsHeader userDataHeader; - - byte[] userData; - - int mUserDataSeptetPadding; - - int mUserDataSize; - - PduParser(String s) { - this(IccUtils.hexStringToBytes(s)); + spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress, + destinationAddress, destinationPort, data, statusReportRequested); } - PduParser(byte[] pdu) { - this.pdu = pdu; - cur = 0; - mUserDataSeptetPadding = 0; - } - - /** - * Parse and return the SC address prepended to SMS messages coming via - * the TS 27.005 / AT interface. Returns null on invalid address - */ - String getSCAddress() { - int len; - String ret; - - // length of SC Address - len = getByte(); - - if (len == 0) { - // no SC address - ret = null; - } else { - // SC address - try { - ret = PhoneNumberUtils - .calledPartyBCDToString(pdu, cur, len); - } catch (RuntimeException tr) { - Log.d(LOG_TAG, "invalid SC address: ", tr); - ret = null; - } - } - - cur += len; - - return ret; - } - - /** - * returns non-sign-extended byte value - */ - int getByte() { - return pdu[cur++] & 0xff; - } - - /** - * Any address except the SC address (eg, originating address) See TS - * 23.040 9.1.2.5 - */ - SmsAddress getAddress() { - SmsAddress ret; - - // "The Address-Length field is an integer representation of - // the number field, i.e. excludes any semi octet containing only - // fill bits." - // The TOA field is not included as part of this - int addressLength = pdu[cur] & 0xff; - int lengthBytes = 2 + (addressLength + 1) / 2; - - ret = new SmsAddress(pdu, cur, lengthBytes); - - cur += lengthBytes; - - return ret; - } - - /** - * Parses an SC timestamp and returns a currentTimeMillis()-style - * timestamp - */ - - long getSCTimestampMillis() { - // TP-Service-Centre-Time-Stamp - int year = IccUtils.bcdByteToInt(pdu[cur++]); - int month = IccUtils.bcdByteToInt(pdu[cur++]); - int day = IccUtils.bcdByteToInt(pdu[cur++]); - int hour = IccUtils.bcdByteToInt(pdu[cur++]); - int minute = IccUtils.bcdByteToInt(pdu[cur++]); - int second = IccUtils.bcdByteToInt(pdu[cur++]); - - // For the timezone, the most significant bit of the - // least signficant nibble is the sign byte - // (meaning the max range of this field is 79 quarter-hours, - // which is more than enough) - - byte tzByte = pdu[cur++]; - - // Mask out sign bit. - int timezoneOffset = IccUtils - .bcdByteToInt((byte) (tzByte & (~0x08))); - - timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset - : -timezoneOffset; - - Time time = new Time(Time.TIMEZONE_UTC); - - // It's 2006. Should I really support years < 2000? - time.year = year >= 90 ? year + 1900 : year + 2000; - time.month = month - 1; - time.monthDay = day; - time.hour = hour; - time.minute = minute; - time.second = second; - - // Timezone offset is in quarter hours. - return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); - } - - /** - * Pulls the user data out of the PDU, and separates the payload from - * the header if there is one. - * - * @param hasUserDataHeader true if there is a user data header - * @param dataInSeptets true if the data payload is in septets instead - * of octets - * @return the number of septets or octets in the user data payload - */ - int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) { - int offset = cur; - int userDataLength = pdu[offset++] & 0xff; - int headerSeptets = 0; - - if (hasUserDataHeader) { - int userDataHeaderLength = pdu[offset++] & 0xff; - - byte[] udh = new byte[userDataHeaderLength]; - System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength); - userDataHeader = SmsHeader.parse(udh); - offset += userDataHeaderLength; - - int headerBits = (userDataHeaderLength + 1) * 8; - headerSeptets = headerBits / 7; - headerSeptets += (headerBits % 7) > 0 ? 1 : 0; - mUserDataSeptetPadding = (headerSeptets * 7) - headerBits; - } - - /* - * Here we just create the user data length to be the remainder of - * the pdu minus the user data hearder. This is because the count - * could mean the number of uncompressed sepets if the userdata is - * encoded in 7-bit. - */ - userData = new byte[pdu.length - offset]; - System.arraycopy(pdu, offset, userData, 0, userData.length); - cur = offset; - - if (dataInSeptets) { - // Return the number of septets - return userDataLength - headerSeptets; - } else { - // Return the number of octets - return userData.length; - } - } - - /** - * Returns the user data payload, not including the headers - * - * @return the user data payload, not including the headers - */ - byte[] getUserData() { - return userData; - } - - /** - * Returns the number of padding bits at the begining of the user data - * array before the start of the septets. - * - * @return the number of padding bits at the begining of the user data - * array before the start of the septets - */ - int getUserDataSeptetPadding() { - return mUserDataSeptetPadding; - } - - /** - * Returns an object representing the user data headers - * - * @return an object representing the user data headers - * - * {@hide} - */ - SmsHeader getUserDataHeader() { - return userDataHeader; - } - -/* - XXX Not sure what this one is supposed to be doing, and no one is using - it. - String getUserDataGSM8bit() { - // System.out.println("remainder of pud:" + - // HexDump.dumpHexString(pdu, cur, pdu.length - cur)); - int count = pdu[cur++] & 0xff; - int size = pdu[cur++]; - - // skip over header for now - cur += size; - - if (pdu[cur - 1] == 0x01) { - int tid = pdu[cur++] & 0xff; - int type = pdu[cur++] & 0xff; - - size = pdu[cur++] & 0xff; - - int i = cur; - - while (pdu[i++] != '\0') { - } - - int length = i - cur; - String mimeType = new String(pdu, cur, length); - - cur += length; - - if (false) { - System.out.println("tid = 0x" + HexDump.toHexString(tid)); - System.out.println("type = 0x" + HexDump.toHexString(type)); - System.out.println("header size = " + size); - System.out.println("mimeType = " + mimeType); - System.out.println("remainder of header:" + - HexDump.dumpHexString(pdu, cur, (size - mimeType.length()))); - } - - cur += size - mimeType.length(); - - // System.out.println("data count = " + count + " cur = " + cur - // + " :" + HexDump.dumpHexString(pdu, cur, pdu.length - cur)); - - MMSMessage msg = MMSMessage.parseEncoding(mContext, pdu, cur, - pdu.length - cur); - } else { - System.out.println(new String(pdu, cur, pdu.length - cur - 1)); - } - - return IccUtils.bytesToHexString(pdu); - } -*/ - - /** - * Interprets the user data payload as pack GSM 7bit characters, and - * decodes them into a String. - * - * @param septetCount the number of septets in the user data payload - * @return a String with the decoded characters - */ - String getUserDataGSM7Bit(int septetCount) { - String ret; - - ret = GsmAlphabet.gsm7BitPackedToString(pdu, cur, septetCount, - mUserDataSeptetPadding); - - cur += (septetCount * 7) / 8; - - return ret; - } - - /** - * Interprets the user data payload as UCS2 characters, and - * decodes them into a String. - * - * @param byteCount the number of bytes in the user data payload - * @return a String with the decoded characters - */ - String getUserDataUCS2(int byteCount) { - String ret; - - try { - ret = new String(pdu, cur, byteCount, "utf-16"); - } catch (UnsupportedEncodingException ex) { - ret = ""; - Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); - } - - cur += byteCount; - return ret; - } - - boolean moreDataPresent() { - return (pdu.length > cur); - } + return new SubmitPdu(spb); } /** * Returns the address of the SMS service center that relayed this message * or null if there is none. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getServiceCenterAddress() { - return scAddress; + return mWrappedSmsMessage.getServiceCenterAddress(); } /** * Returns the originating address (sender) of this SMS message in String * form or null if unavailable + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getOriginatingAddress() { - if (originatingAddress == null) { - return null; - } - - return originatingAddress.getAddressString(); + return mWrappedSmsMessage.getOriginatingAddress(); } /** * Returns the originating address, or email from address if this message * was from an email gateway. Returns null if originating address * unavailable. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getDisplayOriginatingAddress() { - if (isEmail) { - return emailFrom; - } else { - return getOriginatingAddress(); - } + return mWrappedSmsMessage.getDisplayOriginatingAddress(); } /** * Returns the message body as a String, if it exists and is text based. * @return message body is there is one, otherwise null + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getMessageBody() { - return messageBody; + return mWrappedSmsMessage.getMessageBody(); } /** * Returns the class of this message. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public MessageClass getMessageClass() { - return messageClass; + int index = mWrappedSmsMessage.getMessageClass().ordinal(); + + return MessageClass.values()[index]; } /** * Returns the message body, or email message body if this message was from * an email gateway. Returns null if message body unavailable. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getDisplayMessageBody() { - if (isEmail) { - return emailBody; - } else { - return getMessageBody(); - } + return mWrappedSmsMessage.getDisplayMessageBody(); } /** * Unofficial convention of a subject line enclosed in parens empty string * if not present + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getPseudoSubject() { - return pseudoSubject == null ? "" : pseudoSubject; + return mWrappedSmsMessage.getPseudoSubject(); } /** * Returns the service centre timestamp in currentTimeMillis() format + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public long getTimestampMillis() { - return scTimeMillis; + return mWrappedSmsMessage.getTimestampMillis(); } /** @@ -1088,129 +499,114 @@ public class SmsMessage { * * @return true if this message came through an email gateway and email * sender / subject / parsed body are available + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isEmail() { - return isEmail; + return mWrappedSmsMessage.isEmail(); } - /** + /** * @return if isEmail() is true, body of the email sent through the gateway. * null otherwise + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getEmailBody() { - return emailBody; + return mWrappedSmsMessage.getEmailBody(); } /** * @return if isEmail() is true, email from address of email sent through * the gateway. null otherwise + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public String getEmailFrom() { - return emailFrom; + return mWrappedSmsMessage.getEmailFrom(); } /** * Get protocol identifier. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public int getProtocolIdentifier() { - return protocolIdentifier; + return mWrappedSmsMessage.getProtocolIdentifier(); } /** - * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" - * SMS + * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" SMS + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isReplace() { - return (protocolIdentifier & 0xc0) == 0x40 - && (protocolIdentifier & 0x3f) > 0 - && (protocolIdentifier & 0x3f) < 8; + return mWrappedSmsMessage.isReplace(); } /** * Returns true for CPHS MWI toggle message. * - * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section - * B.4.2 + * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section B.4.2 + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isCphsMwiMessage() { - return originatingAddress.isCphsVoiceMessageClear() - || originatingAddress.isCphsVoiceMessageSet(); + return mWrappedSmsMessage.isCphsMwiMessage(); } /** * returns true if this message is a CPHS voicemail / message waiting * indicator (MWI) clear message + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isMWIClearMessage() { - if (isMwi && (mwiSense == false)) { - return true; - } - - return originatingAddress != null - && originatingAddress.isCphsVoiceMessageClear(); + return mWrappedSmsMessage.isMWIClearMessage(); } /** * returns true if this message is a CPHS voicemail / message waiting * indicator (MWI) set message + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isMWISetMessage() { - if (isMwi && (mwiSense == true)) { - return true; - } - - return originatingAddress != null - && originatingAddress.isCphsVoiceMessageSet(); + return mWrappedSmsMessage.isMWISetMessage(); } /** * returns true if this message is a "Message Waiting Indication Group: * Discard Message" notification and should not be stored. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isMwiDontStore() { - if (isMwi && mwiDontStore) { - return true; - } - - if (isCphsMwiMessage()) { - // See CPHS 4.2 Section B.4.2.1 - // If the user data is a single space char, do not store - // the message. Otherwise, store and display as usual - if (" ".equals(getMessageBody())) { - ; - } - return true; - } - - return false; + return mWrappedSmsMessage.isMwiDontStore(); } /** - * returns the user data section minus the user data header if one was - * present. + * returns the user data section minus the user data header if one was present. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public byte[] getUserData() { - return userData; + return mWrappedSmsMessage.getUserData(); } - /** - * Returns an object representing the user data header - * - * @return an object representing the user data header - * - * {@hide} - */ - public SmsHeader getUserDataHeader() { - return userDataHeader; - } + /* Not part of the SDK interface and only needed by specific classes: + protected SmsHeader getUserDataHeader() + */ /** * Returns the raw PDU for the message. * * @return the raw PDU for the message. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public byte[] getPdu() { - return mPdu; + return mWrappedSmsMessage.getPdu(); } /** @@ -1222,369 +618,105 @@ public class SmsMessage { * SmsManager.STATUS_ON_SIM_UNREAD * SmsManager.STATUS_ON_SIM_SEND * SmsManager.STATUS_ON_SIM_UNSENT + * @deprecated Use android.telephony.SmsMessage and getStatusOnIcc instead. */ + @Deprecated public int getStatusOnSim() { - return statusOnSim; + return mWrappedSmsMessage.getStatusOnIcc(); + } + + /** + * Returns the status of the message on the ICC (read, unread, sent, unsent). + * + * @return the status of the message on the ICC. These are: + * SmsManager.STATUS_ON_ICC_FREE + * SmsManager.STATUS_ON_ICC_READ + * SmsManager.STATUS_ON_ICC_UNREAD + * SmsManager.STATUS_ON_ICC_SEND + * SmsManager.STATUS_ON_ICC_UNSENT + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public int getStatusOnIcc() { + + return mWrappedSmsMessage.getStatusOnIcc(); } /** * Returns the record index of the message on the SIM (1-based index). * @return the record index of the message on the SIM, or -1 if this * SmsMessage was not created from a SIM SMS EF record. + * @deprecated Use android.telephony.SmsMessage and getIndexOnIcc instead. */ + @Deprecated public int getIndexOnSim() { - return indexOnSim; + return mWrappedSmsMessage.getIndexOnIcc(); } /** + * Returns the record index of the message on the ICC (1-based index). + * @return the record index of the message on the ICC, or -1 if this + * SmsMessage was not created from a ICC SMS EF record. + * @deprecated Use android.telephony.SmsMessage. + */ + @Deprecated + public int getIndexOnIcc() { + + return mWrappedSmsMessage.getIndexOnIcc(); + } + + /** + * GSM: * For an SMS-STATUS-REPORT message, this returns the status field from - * the status report. This field indicates the status of a previousely + * the status report. This field indicates the status of a previously * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a * description of values. + * CDMA: + * For not interfering with status codes from GSM, the value is + * shifted to the bits 31-16. + * The value is composed of an error class (bits 25-24) and a status code (bits 23-16). + * Possible codes are described in C.S0015-B, v2.0, 4.5.21. * * @return 0 indicates the previously sent message was received. - * See TS 23.040, 9.9.2.3.15 for a description of other possible - * values. + * See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21 + * for a description of other possible values. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public int getStatus() { - return status; + return mWrappedSmsMessage.getStatus(); } /** * Return true iff the message is a SMS-STATUS-REPORT message. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isStatusReportMessage() { - return isStatusReportMessage; + return mWrappedSmsMessage.isStatusReportMessage(); } /** * Returns true iff the <code>TP-Reply-Path</code> bit is set in * this message. + * @deprecated Use android.telephony.SmsMessage. */ + @Deprecated public boolean isReplyPathPresent() { - return replyPathPresent; + return mWrappedSmsMessage.isReplyPathPresent(); } - /** - * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6] - * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format: - * ME/TA converts each octet of TP data unit into two IRA character long - * hexad number (e.g. octet with integer value 42 is presented to TE as two - * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast, - * something else... + /** This method returns the reference to a specific + * SmsMessage object, which is used for accessing its static methods. + * @return Specific SmsMessage. + * @deprecated Use android.telephony.SmsMessage. */ - private void parsePdu(byte[] pdu) { - mPdu = pdu; - // Log.d(LOG_TAG, "raw sms mesage:"); - // Log.d(LOG_TAG, s); - - PduParser p = new PduParser(pdu); - - scAddress = p.getSCAddress(); - - if (scAddress != null) { - if (Config.LOGD) Log.d(LOG_TAG, "SMS SC address: " + scAddress); - } - - // TODO(mkf) support reply path, user data header indicator - - // TP-Message-Type-Indicator - // 9.2.3 - int firstByte = p.getByte(); - - mti = firstByte & 0x3; - switch (mti) { - // TP-Message-Type-Indicator - // 9.2.3 - case 0: - parseSmsDeliver(p, firstByte); - break; - case 2: - parseSmsStatusReport(p, firstByte); - break; - default: - // TODO(mkf) the rest of these - throw new RuntimeException("Unsupported message type"); - } - } - - /** - * Parses a SMS-STATUS-REPORT message. - * - * @param p A PduParser, cued past the first byte. - * @param firstByte The first byte of the PDU, which contains MTI, etc. - */ - private void parseSmsStatusReport(PduParser p, int firstByte) { - isStatusReportMessage = true; - - // TP-Status-Report-Qualifier bit == 0 for SUBMIT - forSubmit = (firstByte & 0x20) == 0x00; - // TP-Message-Reference - messageRef = p.getByte(); - // TP-Recipient-Address - recipientAddress = p.getAddress(); - // TP-Service-Centre-Time-Stamp - scTimeMillis = p.getSCTimestampMillis(); - // TP-Discharge-Time - dischargeTimeMillis = p.getSCTimestampMillis(); - // TP-Status - status = p.getByte(); - - // The following are optional fields that may or may not be present. - if (p.moreDataPresent()) { - // TP-Parameter-Indicator - int extraParams = p.getByte(); - int moreExtraParams = extraParams; - while ((moreExtraParams & 0x80) != 0) { - // We only know how to parse a few extra parameters, all - // indicated in the first TP-PI octet, so skip over any - // additional TP-PI octets. - moreExtraParams = p.getByte(); - } - // TP-Protocol-Identifier - if ((extraParams & 0x01) != 0) { - protocolIdentifier = p.getByte(); - } - // TP-Data-Coding-Scheme - if ((extraParams & 0x02) != 0) { - dataCodingScheme = p.getByte(); - } - // TP-User-Data-Length (implies existence of TP-User-Data) - if ((extraParams & 0x04) != 0) { - boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; - parseUserData(p, hasUserDataHeader); - } - } - } - - private void parseSmsDeliver(PduParser p, int firstByte) { - replyPathPresent = (firstByte & 0x80) == 0x80; - - originatingAddress = p.getAddress(); - - if (originatingAddress != null) { - if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " - + originatingAddress.address); - } - - // TP-Protocol-Identifier (TP-PID) - // TS 23.040 9.2.3.9 - protocolIdentifier = p.getByte(); - - // TP-Data-Coding-Scheme - // see TS 23.038 - dataCodingScheme = p.getByte(); - - if (Config.LOGV) { - Log.v(LOG_TAG, "SMS TP-PID:" + protocolIdentifier - + " data coding scheme: " + dataCodingScheme); - } - - scTimeMillis = p.getSCTimestampMillis(); - - if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); - - boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; - - parseUserData(p, hasUserDataHeader); - } - - /** - * Parses the User Data of an SMS. - * - * @param p The current PduParser. - * @param hasUserDataHeader Indicates whether a header is present in the - * User Data. - */ - private void parseUserData(PduParser p, boolean hasUserDataHeader) { - boolean hasMessageClass = false; - boolean userDataCompressed = false; - - int encodingType = ENCODING_UNKNOWN; - - // Look up the data encoding scheme - if ((dataCodingScheme & 0x80) == 0) { - // Bits 7..4 == 0xxx - automaticDeletion = (0 != (dataCodingScheme & 0x40)); - userDataCompressed = (0 != (dataCodingScheme & 0x20)); - hasMessageClass = (0 != (dataCodingScheme & 0x10)); - - if (userDataCompressed) { - Log.w(LOG_TAG, "4 - Unsupported SMS data coding scheme " - + "(compression) " + (dataCodingScheme & 0xff)); - } else { - switch ((dataCodingScheme >> 2) & 0x3) { - case 0: // GSM 7 bit default alphabet - encodingType = ENCODING_7BIT; - break; - - case 2: // UCS 2 (16bit) - encodingType = ENCODING_16BIT; - break; - - case 1: // 8 bit data - case 3: // reserved - Log.w(LOG_TAG, "1 - Unsupported SMS data coding scheme " - + (dataCodingScheme & 0xff)); - encodingType = ENCODING_8BIT; - break; - } - } - } else if ((dataCodingScheme & 0xf0) == 0xf0) { - automaticDeletion = false; - hasMessageClass = true; - userDataCompressed = false; - - if (0 == (dataCodingScheme & 0x04)) { - // GSM 7 bit default alphabet - encodingType = ENCODING_7BIT; - } else { - // 8 bit data - encodingType = ENCODING_8BIT; - } - } else if ((dataCodingScheme & 0xF0) == 0xC0 - || (dataCodingScheme & 0xF0) == 0xD0 - || (dataCodingScheme & 0xF0) == 0xE0) { - // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 - - // 0xC0 == 7 bit, don't store - // 0xD0 == 7 bit, store - // 0xE0 == UCS-2, store - - if ((dataCodingScheme & 0xF0) == 0xE0) { - encodingType = ENCODING_16BIT; - } else { - encodingType = ENCODING_7BIT; - } - - userDataCompressed = false; - boolean active = ((dataCodingScheme & 0x08) == 0x08); - - // bit 0x04 reserved - - if ((dataCodingScheme & 0x03) == 0x00) { - isMwi = true; - mwiSense = active; - mwiDontStore = ((dataCodingScheme & 0xF0) == 0xC0); - } else { - isMwi = false; - - Log.w(LOG_TAG, "MWI for fax, email, or other " - + (dataCodingScheme & 0xff)); - } - } else { - Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " - + (dataCodingScheme & 0xff)); - } - - // set both the user data and the user data header. - int count = p.constructUserData(hasUserDataHeader, - encodingType == ENCODING_7BIT); - this.userData = p.getUserData(); - this.userDataHeader = p.getUserDataHeader(); - - switch (encodingType) { - case ENCODING_UNKNOWN: - case ENCODING_8BIT: - messageBody = null; - break; - - case ENCODING_7BIT: - messageBody = p.getUserDataGSM7Bit(count); - break; - - case ENCODING_16BIT: - messageBody = p.getUserDataUCS2(count); - break; - } - - if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'"); - - if (messageBody != null) { - parseMessageBody(); - } - - if (!hasMessageClass) { - messageClass = MessageClass.UNKNOWN; + private static final SmsMessageBase getSmsFacility(){ + int activePhone = TelephonyManager.getDefault().getPhoneType(); + if (PHONE_TYPE_CDMA == activePhone) { + return new com.android.internal.telephony.cdma.SmsMessage(); } else { - switch (dataCodingScheme & 0x3) { - case 0: - messageClass = MessageClass.CLASS_0; - break; - case 1: - messageClass = MessageClass.CLASS_1; - break; - case 2: - messageClass = MessageClass.CLASS_2; - break; - case 3: - messageClass = MessageClass.CLASS_3; - break; - } - } - } - - private void parseMessageBody() { - if (originatingAddress.couldBeEmailGateway()) { - extractEmailAddressFromMessageBody(); - } - } - - /** - * Try to parse this message as an email gateway message -> Neither - * of the standard ways are currently supported: There are two ways - * specified in TS 23.040 Section 3.8 (not supported via this mechanism) - - * SMS message "may have its TP-PID set for internet electronic mail - MT - * SMS format: [<from-address><space>]<message> - "Depending on the - * nature of the gateway, the destination/origination address is either - * derived from the content of the SMS TP-OA or TP-DA field, or the - * TP-OA/TP-DA field contains a generic gateway address and the to/from - * address is added at the beginning as shown above." - multiple addreses - * separated by commas, no spaces - subject field delimited by '()' or '##' - * and '#' Section 9.2.3.24.11 - */ - private void extractEmailAddressFromMessageBody() { - - /* - * a little guesswork here. I haven't found doc for this. - * the format could be either - * - * 1. [x@y][ ]/[subject][ ]/[body] - * -or- - * 2. [x@y][ ]/[body] - */ - int slash = 0, slash2 = 0, atSymbol = 0; - - try { - slash = messageBody.indexOf(" /"); - if (slash == -1) { - return; - } - - atSymbol = messageBody.indexOf('@'); - if (atSymbol == -1 || atSymbol > slash) { - return; - } - - emailFrom = messageBody.substring(0, slash); - - slash2 = messageBody.indexOf(" /", slash + 2); - - if (slash2 == -1) { - pseudoSubject = null; - emailBody = messageBody.substring(slash + 2); - } else { - pseudoSubject = messageBody.substring(slash + 2, slash2); - emailBody = messageBody.substring(slash2 + 2); - } - - isEmail = true; - } catch (Exception ex) { - Log.w(LOG_TAG, - "extractEmailAddressFromMessageBody: exception slash=" - + slash + ", atSymbol=" + atSymbol + ", slash2=" - + slash2, ex); + return new com.android.internal.telephony.gsm.SmsMessage(); } } - } diff --git a/telephony/java/com/android/internal/telephony/ATResponseParser.java b/telephony/java/com/android/internal/telephony/ATResponseParser.java index 93ec45588418..fdb05262da4c 100644 --- a/telephony/java/com/android/internal/telephony/ATResponseParser.java +++ b/telephony/java/com/android/internal/telephony/ATResponseParser.java @@ -34,7 +34,7 @@ public class ATResponseParser { this.line = line; } - + public boolean nextBoolean() { @@ -147,7 +147,7 @@ public class ATResponseParser } } - + /** Throws ATParseEx if whitespace extends to the end of string */ private char skipWhiteSpace (char c) diff --git a/telephony/java/com/android/internal/telephony/AdnRecord.aidl b/telephony/java/com/android/internal/telephony/AdnRecord.aidl index d3576be2b923..b4a1a298aefd 100644 --- a/telephony/java/com/android/internal/telephony/AdnRecord.aidl +++ b/telephony/java/com/android/internal/telephony/AdnRecord.aidl @@ -18,4 +18,3 @@ package com.android.internal.telephony; parcelable AdnRecord; -// TODO T: move to telephony and implement proxy-service as for all AIDL diff --git a/telephony/java/com/android/internal/telephony/AdnRecord.java b/telephony/java/com/android/internal/telephony/AdnRecord.java index 6273b0f1008a..5f40579b272a 100644 --- a/telephony/java/com/android/internal/telephony/AdnRecord.java +++ b/telephony/java/com/android/internal/telephony/AdnRecord.java @@ -16,21 +16,16 @@ package com.android.internal.telephony; -import com.android.internal.telephony.*; import android.os.Parcel; import android.os.Parcelable; -import android.os.Message; -import android.os.Handler; -import android.os.Looper; -import android.os.AsyncResult; -import android.util.Log; import android.telephony.PhoneNumberUtils; -import java.util.ArrayList; -import com.android.internal.telephony.gsm.GsmAlphabet; +import android.util.Log; + +import com.android.internal.telephony.GsmAlphabet; /** - * + * * Used to load or store ADNs (Abbreviated Dialing Numbers). * * {@hide} @@ -38,7 +33,7 @@ import com.android.internal.telephony.gsm.GsmAlphabet; */ public class AdnRecord implements Parcelable { static final String LOG_TAG = "GSM"; - + //***** Instance Variables String alphaTag = ""; @@ -111,7 +106,7 @@ public class AdnRecord implements Parcelable { AdnRecord (String alphaTag, String number) { this(0, 0, alphaTag, number); } - + public AdnRecord (int efid, int recordNumber, String alphaTag, String number) { this.efid = efid; @@ -119,7 +114,7 @@ public class AdnRecord implements Parcelable { this.alphaTag = alphaTag; this.number = number; } - + //***** Instance Methods public String getAlphaTag() { @@ -219,7 +214,7 @@ public class AdnRecord implements Parcelable { * See TS 51.011 10.5.10 */ public void - appendExtRecord (byte[] extRecord) { + appendExtRecord (byte[] extRecord) { try { if (extRecord.length != EXT_RECORD_LENGTH_BYTES) { return; @@ -268,9 +263,9 @@ public class AdnRecord implements Parcelable { // Please note 51.011 10.5.1: // - // "If the Dialling Number/SSC String does not contain - // a dialling number, e.g. a control string deactivating - // a service, the TON/NPI byte shall be set to 'FF' by + // "If the Dialling Number/SSC String does not contain + // a dialling number, e.g. a control string deactivating + // a service, the TON/NPI byte shall be set to 'FF' by // the ME (see note 2)." number = PhoneNumberUtils.calledPartyBCDToString( @@ -283,6 +278,6 @@ public class AdnRecord implements Parcelable { Log.w(LOG_TAG, "Error parsing AdnRecord", ex); number = ""; alphaTag = ""; - } + } } } diff --git a/telephony/java/com/android/internal/telephony/AdnRecordCache.java b/telephony/java/com/android/internal/telephony/AdnRecordCache.java index 2654e427691d..c270ae5087b8 100644 --- a/telephony/java/com/android/internal/telephony/AdnRecordCache.java +++ b/telephony/java/com/android/internal/telephony/AdnRecordCache.java @@ -34,7 +34,7 @@ public final class AdnRecordCache extends Handler implements IccConstants { PhoneBase phone; // Indexed by EF ID - SparseArray<ArrayList<AdnRecord>> adnLikeFiles + SparseArray<ArrayList<AdnRecord>> adnLikeFiles = new SparseArray<ArrayList<AdnRecord>>(); // People waiting for ADN-like files to be loaded @@ -52,7 +52,7 @@ public final class AdnRecordCache extends Handler implements IccConstants { //***** Constructor - + public AdnRecordCache(PhoneBase phone) { this.phone = phone; } @@ -67,7 +67,7 @@ public final class AdnRecordCache extends Handler implements IccConstants { clearWaiters(); clearUserWriters(); - + } private void clearWaiters() { @@ -98,7 +98,7 @@ public final class AdnRecordCache extends Handler implements IccConstants { } /** - * Returns extension ef associated with ADN-like EF or -1 if + * Returns extension ef associated with ADN-like EF or -1 if * we don't know. * * See 3GPP TS 51.011 for this mapping @@ -110,9 +110,9 @@ public final class AdnRecordCache extends Handler implements IccConstants { case EF_ADN: return EF_EXT1; case EF_SDN: return EF_EXT3; case EF_FDN: return EF_EXT2; - case EF_MSISDN: return EF_EXT1; + case EF_MSISDN: return EF_EXT1; default: return -1; - } + } } private void sendErrorResponse(Message response, String errString) { @@ -250,25 +250,25 @@ public final class AdnRecordCache extends Handler implements IccConstants { waiters.add(response); return; } - + // Start loading efid - + waiters = new ArrayList<Message>(); waiters.add(response); adnLikeWaiters.put(efid, waiters); int extensionEF = extensionEfForEf(efid); - + if (extensionEF < 0) { // respond with error if not known ADN-like record if (response != null) { - AsyncResult.forMessage(response).exception + AsyncResult.forMessage(response).exception = new RuntimeException("EF is not known ADN-like EF:" + efid); response.sendToTarget(); } - + return; } diff --git a/telephony/java/com/android/internal/telephony/AdnRecordLoader.java b/telephony/java/com/android/internal/telephony/AdnRecordLoader.java index 721cce9ecadc..cfb5aaa84b39 100644 --- a/telephony/java/com/android/internal/telephony/AdnRecordLoader.java +++ b/telephony/java/com/android/internal/telephony/AdnRecordLoader.java @@ -25,7 +25,7 @@ import android.util.Log; public class AdnRecordLoader extends Handler { - static final String LOG_TAG = "AdnRecordLoader"; + static String LOG_TAG; //***** Instance Variables @@ -59,9 +59,10 @@ public class AdnRecordLoader extends Handler { public AdnRecordLoader(PhoneBase phone) { // The telephony unit-test cases may create AdnRecords // in secondary threads - super(phone.h.getLooper()); + super(phone.getHandler().getLooper()); this.phone = phone; + LOG_TAG = phone.getPhoneName(); } /** @@ -69,16 +70,16 @@ public class AdnRecordLoader extends Handler { * or response.obj.exception is set */ public void - loadFromEF(int ef, int extensionEF, int recordNumber, + loadFromEF(int ef, int extensionEF, int recordNumber, Message response) { this.ef = ef; this.extensionEF = extensionEF; this.recordNumber = recordNumber; this.userResponse = response; - + phone.mIccFileHandler.loadEFLinearFixed( - ef, recordNumber, - obtainMessage(EVENT_ADN_LOAD_DONE)); + ef, recordNumber, + obtainMessage(EVENT_ADN_LOAD_DONE)); } @@ -88,15 +89,15 @@ public class AdnRecordLoader extends Handler { * or response.obj.exception is set */ public void - loadAllFromEF(int ef, int extensionEF, + loadAllFromEF(int ef, int extensionEF, Message response) { this.ef = ef; this.extensionEF = extensionEF; this.userResponse = response; - + phone.mIccFileHandler.loadEFLinearFixedAll( - ef, - obtainMessage(EVENT_ADN_LOAD_ALL_DONE)); + ef, + obtainMessage(EVENT_ADN_LOAD_ALL_DONE)); } @@ -127,7 +128,7 @@ public class AdnRecordLoader extends Handler { //***** Overridden from Handler - public void + public void handleMessage(Message msg) { AsyncResult ar; byte data[]; @@ -180,18 +181,18 @@ public class AdnRecordLoader extends Handler { case EVENT_ADN_LOAD_DONE: ar = (AsyncResult)(msg.obj); data = (byte[])(ar.result); - + if (ar.exception != null) { throw new RuntimeException("load failed", ar.exception); } if (false) { - Log.d(LOG_TAG,"ADN EF: 0x" + Log.d(LOG_TAG,"ADN EF: 0x" + Integer.toHexString(ef) + ":" + recordNumber + "\n" + IccUtils.bytesToHexString(data)); } - + adn = new AdnRecord(ef, recordNumber, data); result = adn; @@ -201,10 +202,10 @@ public class AdnRecordLoader extends Handler { // ext record and append it pendingExtLoads = 1; - + phone.mIccFileHandler.loadEFLinearFixed( - extensionEF, adn.extRecord, - obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); + extensionEF, adn.extRecord, + obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); } break; @@ -212,12 +213,12 @@ public class AdnRecordLoader extends Handler { ar = (AsyncResult)(msg.obj); data = (byte[])(ar.result); adn = (AdnRecord)(ar.userObj); - + if (ar.exception != null) { throw new RuntimeException("load failed", ar.exception); } - Log.d(LOG_TAG,"ADN extention EF: 0x" + Log.d(LOG_TAG,"ADN extention EF: 0x" + Integer.toHexString(extensionEF) + ":" + adn.extRecord + "\n" + IccUtils.bytesToHexString(data)); @@ -225,14 +226,14 @@ public class AdnRecordLoader extends Handler { adn.appendExtRecord(data); pendingExtLoads--; - // result should have been set in + // result should have been set in // EVENT_ADN_LOAD_DONE or EVENT_ADN_LOAD_ALL_DONE - break; + break; case EVENT_ADN_LOAD_ALL_DONE: ar = (AsyncResult)(msg.obj); ArrayList<byte[]> datas = (ArrayList<byte[]>)(ar.result); - + if (ar.exception != null) { throw new RuntimeException("load failed", ar.exception); } @@ -251,17 +252,17 @@ public class AdnRecordLoader extends Handler { // ext record and append it pendingExtLoads++; - + phone.mIccFileHandler.loadEFLinearFixed( - extensionEF, adn.extRecord, - obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); + extensionEF, adn.extRecord, + obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); } } break; } - } catch (RuntimeException exc) { + } catch (RuntimeException exc) { if (userResponse != null) { - AsyncResult.forMessage(userResponse) + AsyncResult.forMessage(userResponse) .exception = exc; userResponse.sendToTarget(); // Loading is all or nothing--either every load succeeds @@ -272,13 +273,13 @@ public class AdnRecordLoader extends Handler { } if (userResponse != null && pendingExtLoads == 0) { - AsyncResult.forMessage(userResponse).result + AsyncResult.forMessage(userResponse).result = result; userResponse.sendToTarget(); userResponse = null; } } - + } diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java index 37117e67923c..f603ddc17426 100644 --- a/telephony/java/com/android/internal/telephony/BaseCommands.java +++ b/telephony/java/com/android/internal/telephony/BaseCommands.java @@ -22,7 +22,6 @@ import android.os.RegistrantList; import android.os.Registrant; import android.os.Handler; import android.os.AsyncResult; -import android.os.SystemProperties; import android.provider.Checkin; import android.util.Config; import android.util.Log; @@ -50,8 +49,11 @@ public abstract class BaseCommands implements CommandsInterface { protected RegistrantList mNVReadyRegistrants = new RegistrantList(); protected RegistrantList mCallStateRegistrants = new RegistrantList(); protected RegistrantList mNetworkStateRegistrants = new RegistrantList(); - protected RegistrantList mPDPRegistrants = new RegistrantList(); - protected RegistrantList mRadioTechnologyChangedRegistrants= new RegistrantList(); + protected RegistrantList mDataConnectionRegistrants = new RegistrantList(); + protected RegistrantList mRadioTechnologyChangedRegistrants = new RegistrantList(); + protected RegistrantList mIccStatusChangedRegistrants = new RegistrantList(); + protected RegistrantList mVoicePrivacyOnRegistrants = new RegistrantList(); + protected RegistrantList mVoicePrivacyOffRegistrants = new RegistrantList(); protected Registrant mSMSRegistrant; protected Registrant mNITZTimeRegistrant; protected Registrant mSignalStrengthRegistrant; @@ -65,8 +67,8 @@ public abstract class BaseCommands implements CommandsInterface { protected Registrant mStkProCmdRegistrant; protected Registrant mStkEventRegistrant; protected Registrant mStkCallSetUpRegistrant; - /** Registrant for handling SIM SMS storage full messages */ - protected Registrant mSimSmsFullRegistrant; + /** Registrant for handling SIM/RUIM SMS storage full messages */ + protected Registrant mIccSmsFullRegistrant; /** Registrant for handling Icc Refresh notifications */ protected Registrant mIccRefreshRegistrant; /** Registrant for handling RING notifications */ @@ -76,25 +78,22 @@ public abstract class BaseCommands implements CommandsInterface { protected int mNetworkMode; //CDMA subscription received from PhoneFactory protected int mCdmaSubscription; - //Type of Phone, GSM or CDMA. Set by CDMAPhone or GSMPhone. - //TODO check if at init has to be set from mNetworkMode - protected int mPhoneType; + //Type of Phone, GSM or CDMA. Set by CDMAPhone or GSMPhone. + protected int mPhoneType; + - public BaseCommands(Context context) { mContext = context; // May be null (if so we won't log statistics) } //***** CommandsInterface implementation - public RadioState - getRadioState() { + public RadioState getRadioState() { return mState; } - public void - registerForRadioStateChanged(Handler h, int what, Object obj) { + public void registerForRadioStateChanged(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); synchronized (mStateMonitor) { @@ -103,8 +102,13 @@ public abstract class BaseCommands implements CommandsInterface { } } - public void - registerForOn(Handler h, int what, Object obj) { + public void unregisterForRadioStateChanged(Handler h) { + synchronized (mStateMonitor) { + mRadioStateChangedRegistrants.remove(h); + } + } + + public void registerForOn(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); synchronized (mStateMonitor) { @@ -115,10 +119,14 @@ public abstract class BaseCommands implements CommandsInterface { } } } - + public void unregisterForOn(Handler h) { + synchronized (mStateMonitor) { + mOnRegistrants.remove(h); + } + } + - public void - registerForAvailable(Handler h, int what, Object obj) { + public void registerForAvailable(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); synchronized (mStateMonitor) { @@ -130,8 +138,13 @@ public abstract class BaseCommands implements CommandsInterface { } } - public void - registerForNotAvailable(Handler h, int what, Object obj) { + public void unregisterForAvailable(Handler h) { + synchronized(mStateMonitor) { + mAvailRegistrants.remove(h); + } + } + + public void registerForNotAvailable(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); synchronized (mStateMonitor) { @@ -143,8 +156,13 @@ public abstract class BaseCommands implements CommandsInterface { } } - public void - registerForOffOrNotAvailable(Handler h, int what, Object obj) { + public void unregisterForNotAvailable(Handler h) { + synchronized (mStateMonitor) { + mNotAvailRegistrants.remove(h); + } + } + + public void registerForOffOrNotAvailable(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); synchronized (mStateMonitor) { @@ -155,11 +173,15 @@ public abstract class BaseCommands implements CommandsInterface { } } } + public void unregisterForOffOrNotAvailable(Handler h) { + synchronized(mStateMonitor) { + mOffOrNotAvailRegistrants.remove(h); + } + } /** Any transition into SIM_READY */ - public void - registerForSIMReady(Handler h, int what, Object obj) { + public void registerForSIMReady(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); synchronized (mStateMonitor) { @@ -171,9 +193,14 @@ public abstract class BaseCommands implements CommandsInterface { } } + public void unregisterForSIMReady(Handler h) { + synchronized (mStateMonitor) { + mSIMReadyRegistrants.remove(h); + } + } + /** Any transition into RUIM_READY */ - public void - registerForRUIMReady(Handler h, int what, Object obj) { + public void registerForRUIMReady(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); synchronized (mStateMonitor) { @@ -184,10 +211,15 @@ public abstract class BaseCommands implements CommandsInterface { } } } - + + public void unregisterForRUIMReady(Handler h) { + synchronized(mStateMonitor) { + mRUIMReadyRegistrants.remove(h); + } + } + /** Any transition into NV_READY */ - public void - registerForNVReady(Handler h, int what, Object obj) { + public void registerForNVReady(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); synchronized (mStateMonitor) { @@ -199,8 +231,13 @@ public abstract class BaseCommands implements CommandsInterface { } } - public void - registerForSIMLockedOrAbsent(Handler h, int what, Object obj) { + public void unregisterForNVReady(Handler h) { + synchronized (mStateMonitor) { + mNVReadyRegistrants.remove(h); + } + } + + public void registerForSIMLockedOrAbsent(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); synchronized (mStateMonitor) { @@ -212,8 +249,13 @@ public abstract class BaseCommands implements CommandsInterface { } } - public void - registerForRUIMLockedOrAbsent(Handler h, int what, Object obj) { + public void unregisterForSIMLockedOrAbsent(Handler h) { + synchronized (mStateMonitor) { + mSIMLockedRegistrants.remove(h); + } + } + + public void registerForRUIMLockedOrAbsent(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); synchronized (mStateMonitor) { @@ -224,101 +266,192 @@ public abstract class BaseCommands implements CommandsInterface { } } } - - public void - registerForCallStateChanged(Handler h, int what, Object obj) { + + public void unregisterForRUIMLockedOrAbsent(Handler h) { + synchronized (mStateMonitor) { + mRUIMLockedRegistrants.remove(h); + } + } + + public void registerForCallStateChanged(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); mCallStateRegistrants.add(r); } - public void - registerForNetworkStateChanged(Handler h, int what, Object obj) { + public void unregisterForCallStateChanged(Handler h) { + mCallStateRegistrants.remove(h); + } + + public void registerForNetworkStateChanged(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); mNetworkStateRegistrants.add(r); } - public void - registerForPDPStateChanged(Handler h, int what, Object obj) { + public void unregisterForNetworkStateChanged(Handler h) { + mNetworkStateRegistrants.remove(h); + } + + public void registerForDataStateChanged(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); - mPDPRegistrants.add(r); + mDataConnectionRegistrants.add(r); + } + + public void unregisterForDataStateChanged(Handler h) { + mDataConnectionRegistrants.remove(h); } - public void - registerForRadioTechnologyChanged(Handler h, int what, Object obj) { + public void registerForRadioTechnologyChanged(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); mRadioTechnologyChangedRegistrants.add(r); } - - public void - setOnNewSMS(Handler h, int what, Object obj) { + + public void unregisterForRadioTechnologyChanged(Handler h) { + mRadioTechnologyChangedRegistrants.remove(h); + } + + public void registerForIccStatusChanged(Handler h, int what, Object obj) { + Registrant r = new Registrant (h, what, obj); + mIccStatusChangedRegistrants.add(r); + } + + public void unregisterForIccStatusChanged(Handler h) { + mIccStatusChangedRegistrants.remove(h); + } + + public void setOnNewSMS(Handler h, int what, Object obj) { mSMSRegistrant = new Registrant (h, what, obj); } - public void - setOnSmsOnSim(Handler h, int what, Object obj) { + public void unSetOnNewSMS(Handler h) { + mSMSRegistrant.clear(); + } + + public void setOnSmsOnSim(Handler h, int what, Object obj) { mSmsOnSimRegistrant = new Registrant (h, what, obj); } - + + public void unSetOnSmsOnSim(Handler h) { + mSmsOnSimRegistrant.clear(); + } + public void setOnSmsStatus(Handler h, int what, Object obj) { mSmsStatusRegistrant = new Registrant (h, what, obj); } - public void - setOnSignalStrengthUpdate(Handler h, int what, Object obj) { + public void unSetOnSmsStatus(Handler h) { + mSmsStatusRegistrant.clear(); + } + + public void setOnSignalStrengthUpdate(Handler h, int what, Object obj) { mSignalStrengthRegistrant = new Registrant (h, what, obj); } - public void - setOnNITZTime(Handler h, int what, Object obj) { + public void unSetOnSignalStrengthUpdate(Handler h) { + mSignalStrengthRegistrant.clear(); + } + + public void setOnNITZTime(Handler h, int what, Object obj) { mNITZTimeRegistrant = new Registrant (h, what, obj); } - - public void - setOnUSSD(Handler h, int what, Object obj) { + + public void unSetOnNITZTime(Handler h) { + mNITZTimeRegistrant.clear(); + } + + public void setOnUSSD(Handler h, int what, Object obj) { mUSSDRegistrant = new Registrant (h, what, obj); } - public void - setOnSuppServiceNotification(Handler h, int what, Object obj) { + public void unSetOnUSSD(Handler h) { + mUSSDRegistrant.clear(); + } + + public void setOnSuppServiceNotification(Handler h, int what, Object obj) { mSsnRegistrant = new Registrant (h, what, obj); } - public void - setOnStkSessionEnd(Handler h, int what, Object obj) { + public void unSetOnSuppServiceNotification(Handler h) { + mSsnRegistrant.clear(); + } + + public void setOnStkSessionEnd(Handler h, int what, Object obj) { mStkSessionEndRegistrant = new Registrant (h, what, obj); } - public void - setOnStkProactiveCmd(Handler h, int what, Object obj) { + public void unSetOnStkSessionEnd(Handler h) { + mStkSessionEndRegistrant.clear(); + } + + public void setOnStkProactiveCmd(Handler h, int what, Object obj) { mStkProCmdRegistrant = new Registrant (h, what, obj); } - public void - setOnStkEvent(Handler h, int what, Object obj) { + public void unSetOnStkProactiveCmd(Handler h) { + mStkProCmdRegistrant.clear(); + } + + public void setOnStkEvent(Handler h, int what, Object obj) { mStkEventRegistrant = new Registrant (h, what, obj); } - public void - setOnStkCallSetUp(Handler h, int what, Object obj) { + public void unSetOnStkEvent(Handler h) { + mStkEventRegistrant.clear(); + } + + public void setOnStkCallSetUp(Handler h, int what, Object obj) { mStkCallSetUpRegistrant = new Registrant (h, what, obj); } - public void setOnSimSmsFull(Handler h, int what, Object obj) { - mSimSmsFullRegistrant = new Registrant (h, what, obj); + public void unSetOnStkCallSetUp(Handler h) { + mStkCallSetUpRegistrant.clear(); + } + + public void setOnIccSmsFull(Handler h, int what, Object obj) { + mIccSmsFullRegistrant = new Registrant (h, what, obj); + } + + public void unSetOnIccSmsFull(Handler h) { + mIccSmsFullRegistrant.clear(); } public void setOnIccRefresh(Handler h, int what, Object obj) { mIccRefreshRegistrant = new Registrant (h, what, obj); } - + + public void unSetOnIccRefresh(Handler h) { + mIccRefreshRegistrant.clear(); + } + public void setOnCallRing(Handler h, int what, Object obj) { mRingRegistrant = new Registrant (h, what, obj); } - - + + public void unSetOnCallRing(Handler h) { + mRingRegistrant.clear(); + } + + public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){ + Registrant r = new Registrant (h, what, obj); + mVoicePrivacyOnRegistrants.add(r); + } + + public void unregisterForInCallVoicePrivacyOn(Handler h){ + mVoicePrivacyOnRegistrants.remove(h); + } + + public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){ + Registrant r = new Registrant (h, what, obj); + mVoicePrivacyOffRegistrants.add(r); + } + + public void unregisterForInCallVoicePrivacyOff(Handler h){ + mVoicePrivacyOffRegistrants.remove(h); + } + + //***** Protected Methods /** * Store new RadioState and send notification based on the changes @@ -333,24 +466,24 @@ public abstract class BaseCommands implements CommandsInterface { */ protected void setRadioState(RadioState newState) { RadioState oldState; - + synchronized (mStateMonitor) { if (Config.LOGV) { Log.v(LOG_TAG, "setRadioState old: " + mState + " new " + newState); } - + oldState = mState; mState = newState; - + if (oldState == mState) { // no state transition return; } if (mContext != null && - newState == RadioState.RADIO_UNAVAILABLE && - oldState != RadioState.RADIO_OFF) { + newState == RadioState.RADIO_UNAVAILABLE && + oldState != RadioState.RADIO_OFF) { Checkin.updateStats(mContext.getContentResolver(), Checkin.Stats.Tag.PHONE_RADIO_RESETS, 1, 0.0); } @@ -376,7 +509,7 @@ public abstract class BaseCommands implements CommandsInterface { if (mState == RadioState.SIM_LOCKED_OR_ABSENT) { Log.d(LOG_TAG,"Notifying: SIM locked or absent"); mSIMLockedRegistrants.notifyRegistrants(); - } + } if (mState.isRUIMReady() && !oldState.isRUIMReady()) { Log.d(LOG_TAG,"Notifying: RUIM ready"); @@ -386,7 +519,7 @@ public abstract class BaseCommands implements CommandsInterface { if (mState == RadioState.RUIM_LOCKED_OR_ABSENT) { Log.d(LOG_TAG,"Notifying: RUIM locked or absent"); mRUIMLockedRegistrants.notifyRegistrants(); - } + } if (mState.isNVReady() && !oldState.isNVReady()) { Log.d(LOG_TAG,"Notifying: NV ready"); mNVReadyRegistrants.notifyRegistrants(); @@ -395,34 +528,44 @@ public abstract class BaseCommands implements CommandsInterface { if (mState.isOn() && !oldState.isOn()) { Log.d(LOG_TAG,"Notifying: Radio On"); mOnRegistrants.notifyRegistrants(); - } + } - if ((!mState.isOn() || !mState.isAvailable()) + if ((!mState.isOn() || !mState.isAvailable()) && !((!oldState.isOn() || !oldState.isAvailable())) ) { Log.d(LOG_TAG,"Notifying: radio off or not available"); mOffOrNotAvailRegistrants.notifyRegistrants(); } - if ((mState.isGsm() && !oldState.isGsm()) - || (mState.isCdma() && !oldState.isCdma())) { - Log.d(LOG_TAG,"Notifying: radio technology change"); + /* Radio Technology Change events + * NOTE: isGsm and isCdma have no common states in RADIO_OFF or RADIO_UNAVAILABLE; the + * current phone is determined by mPhoneType + * NOTE: at startup no phone have been created and the RIL determines the mPhoneType + * looking based on the networkMode set by the PhoneFactory in the constructor + */ + + if (mState.isGsm() && oldState.isCdma()) { + Log.d(LOG_TAG,"Notifying: radio technology change CDMA to GSM"); + mRadioTechnologyChangedRegistrants.notifyRegistrants(); + } + + if (mState.isGsm() && !oldState.isOn() && (mPhoneType == RILConstants.CDMA_PHONE)) { + Log.d(LOG_TAG,"Notifying: radio technology change CDMA OFF to GSM"); + mRadioTechnologyChangedRegistrants.notifyRegistrants(); + } + + if (mState.isCdma() && oldState.isGsm()) { + Log.d(LOG_TAG,"Notifying: radio technology change GSM to CDMA"); mRadioTechnologyChangedRegistrants.notifyRegistrants(); } - if ( (mState.isGsm() && !mState.isCdma() &&!oldState.isOn() - && (mPhoneType == RILConstants.CDMA_PHONE)) - || (mState.isCdma() && !mState.isCdma() &&!oldState.isOn() - && (mPhoneType == RILConstants.GSM_PHONE)) ){ - //NOTE isGsm and isCdma shares 2 common states - //NOTE second || should never happen - Log.d(LOG_TAG,"Notifying: radio technology change at startup"); + if (mState.isCdma() && !oldState.isOn() && (mPhoneType == RILConstants.GSM_PHONE)) { + Log.d(LOG_TAG,"Notifying: radio technology change GSM OFF to CDMA"); mRadioTechnologyChangedRegistrants.notifyRegistrants(); } } } - protected void - onRadioAvailable() { + protected void onRadioAvailable() { } } diff --git a/telephony/java/com/android/internal/telephony/Call.java b/telephony/java/com/android/internal/telephony/Call.java index 75485e0fd5ad..70471b634153 100644 --- a/telephony/java/com/android/internal/telephony/Call.java +++ b/telephony/java/com/android/internal/telephony/Call.java @@ -40,13 +40,13 @@ public abstract class Call { } } - + /* Instance Variables */ - + public State state = State.IDLE; - - + + /* Instance Methods */ /** Do not modify the List result!!! This list is not yours to keep @@ -61,28 +61,28 @@ public abstract class Call { /** * hasConnection - * + * * @param c a Connection object * @return true if the call contains the connection object passed in */ public boolean hasConnection(Connection c) { return c.getCall() == this; } - + /** * hasConnections * @return true if the call contains one or more connections */ public boolean hasConnections() { List connections = getConnections(); - + if (connections == null) { return false; } - + return connections.size() > 0; } - + /** * getState * @return state of class call @@ -90,10 +90,10 @@ public abstract class Call { public State getState() { return state; } - + /** * isIdle - * + * * FIXME rename * @return true if the call contains only disconnected connections (if any) */ @@ -111,27 +111,27 @@ public abstract class Call { long time = Long.MAX_VALUE; Connection c; Connection earliest = null; - + l = getConnections(); - + if (l.size() == 0) { return null; } - + for (int i = 0, s = l.size() ; i < s ; i++) { c = (Connection) l.get(i); long t; - + t = c.getCreateTime(); - + if (t < time) { earliest = c; } } - + return earliest; } - + public long getEarliestCreateTime() { List l; diff --git a/telephony/java/com/android/internal/telephony/CallTracker.java b/telephony/java/com/android/internal/telephony/CallTracker.java index 770236e3231e..eb339f869b8a 100644 --- a/telephony/java/com/android/internal/telephony/CallTracker.java +++ b/telephony/java/com/android/internal/telephony/CallTracker.java @@ -16,40 +16,34 @@ package com.android.internal.telephony; -import java.util.ArrayList; -import java.util.List; - -import com.android.internal.telephony.gsm.CommandException; -//import com.android.internal.telephony.gsm.DriverCall; -//import com.android.internal.telephony.gsm.GsmConnection; - import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.util.Log; +import com.android.internal.telephony.CommandException; + + /** * {@hide} */ public abstract class CallTracker extends Handler { - static final String LOG_TAG = "CallTracker"; - + private static final boolean DBG_POLL = false; - + //***** Constants static final int POLL_DELAY_MSEC = 250; - + protected int pendingOperations; protected boolean needsPoll; protected Message lastRelevantPoll; - + public CommandsInterface cm; - - - + + //***** Events - + protected static final int EVENT_POLL_CALLS_RESULT = 1; protected static final int EVENT_CALL_STATE_CHANGE = 2; protected static final int EVENT_REPOLL_AFTER_DELAY = 3; @@ -62,20 +56,17 @@ public abstract class CallTracker extends Handler { protected static final int EVENT_CONFERENCE_RESULT = 11; protected static final int EVENT_SEPARATE_RESULT = 12; protected static final int EVENT_ECT_RESULT = 13; - - // Events for CDMA support - protected void pollCallsWhenSafe() { needsPoll = true; if (checkNoOperationsPending()) { lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); - cm.getCurrentCalls(lastRelevantPoll); + cm.getCurrentCalls(lastRelevantPoll); } } - + protected void pollCallsAfterDelay() { Message msg = obtainMessage(); @@ -84,27 +75,24 @@ public abstract class CallTracker extends Handler { sendMessageDelayed(msg, POLL_DELAY_MSEC); } - - protected boolean isCommandExceptionRadioNotAvailable(Throwable e) { return e != null && e instanceof CommandException && ((CommandException)e).getCommandError() == CommandException.Error.RADIO_NOT_AVAILABLE; } - + protected abstract void handlePollCalls(AsyncResult ar); - protected void handleRadioAvailable() { pollCallsWhenSafe(); } - + /** * Obtain a complete message that indicates that this operation * does not require polling of getCurrentCalls(). However, if other - * operations that do need getCurrentCalls() are pending or are - * scheduled while this operation is pending, the invocatoin + * operations that do need getCurrentCalls() are pending or are + * scheduled while this operation is pending, the invocation * of getCurrentCalls() will be postponed until this * operation is also complete. */ @@ -114,7 +102,7 @@ public abstract class CallTracker extends Handler { lastRelevantPoll = null; return obtainMessage(what); } - + /** * @return true if we're idle or there's a call to getCurrentCalls() pending * but nothing else @@ -125,15 +113,11 @@ public abstract class CallTracker extends Handler { pendingOperations); return pendingOperations == 0; } - - - - - //***** Overridden from Handler + + + //***** Overridden from Handler public abstract void handleMessage (Message msg); - private void log(String msg) { - Log.d(LOG_TAG, "[CallTracker] " + msg); - } - + protected abstract void log(String msg); + } diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index 5f630f80b860..9bf64e91eadf 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -46,13 +46,13 @@ public class CallerInfo { /* Split up the phoneLabel into number type and label name */ public int numberType; public String numberLabel; - + public int photoResource; public long person_id; public boolean needUpdate; public Uri contactRefUri; - - // fields to hold individual contact preference data, + + // fields to hold individual contact preference data, // including the send to voicemail flag and the ringtone // uri reference. public Uri contactRingtoneUri; @@ -82,7 +82,7 @@ public class CallerInfo { * number. The returned CallerInfo is null if no number is supplied. */ public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) { - + CallerInfo info = new CallerInfo(); info.photoResource = 0; info.phoneLabel = null; @@ -90,9 +90,9 @@ public class CallerInfo { info.numberLabel = null; info.cachedPhoto = null; info.isCachedPhotoCurrent = false; - + if (Config.LOGV) Log.v(TAG, "construct callerInfo from cursor"); - + if (cursor != null) { if (cursor.moveToFirst()) { @@ -109,7 +109,7 @@ public class CallerInfo { if (columnIndex != -1) { info.phoneNumber = cursor.getString(columnIndex); } - + // Look for the label/type combo columnIndex = cursor.getColumnIndex(Phones.LABEL); if (columnIndex != -1) { @@ -133,7 +133,7 @@ public class CallerInfo { info.person_id = cursor.getLong(columnIndex); } } - + // look for the custom ringtone, create from the string stored // in the database. columnIndex = cursor.getColumnIndex(People.CUSTOM_RINGTONE); @@ -146,7 +146,7 @@ public class CallerInfo { // look for the send to voicemail flag, set it to true only // under certain circumstances. columnIndex = cursor.getColumnIndex(People.SEND_TO_VOICEMAIL); - info.shouldSendToVoicemail = (columnIndex != -1) && + info.shouldSendToVoicemail = (columnIndex != -1) && ((cursor.getInt(columnIndex)) == 1); } cursor.close(); @@ -158,7 +158,7 @@ public class CallerInfo { return info; } - + /** * getCallerInfo given a URI, look up in the call-log database * for the uri unique key. @@ -168,11 +168,11 @@ public class CallerInfo { * number. The returned CallerInfo is null if no number is supplied. */ public static CallerInfo getCallerInfo(Context context, Uri contactRef) { - - return getCallerInfo(context, contactRef, + + return getCallerInfo(context, contactRef, context.getContentResolver().query(contactRef, null, null, null, null)); } - + /** * getCallerInfo given a phone number, look up in the call-log database * for the matching caller id info. @@ -188,7 +188,7 @@ public class CallerInfo { return null; } else { // Change the callerInfo number ONLY if it is an emergency number - // or if it is the voicemail number. If it is either, take a + // or if it is the voicemail number. If it is either, take a // shortcut and skip the query. if (PhoneNumberUtils.isEmergencyNumber(number)) { CallerInfo ci = new CallerInfo(); @@ -206,7 +206,7 @@ public class CallerInfo { return ci; } } catch (SecurityException ex) { - // Don't crash if this process doesn't have permission to + // Don't crash if this process doesn't have permission to // retrieve VM number. It's still allowed to look up caller info. // But don't try it again. sSkipVmCheck = true; @@ -214,16 +214,16 @@ public class CallerInfo { } } - Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, number); - + Uri contactUri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, number); + CallerInfo info = getCallerInfo(context, contactUri); - // if no query results were returned with a viable number, - // fill in the original number value we used to query with. + // if no query results were returned with a viable number, + // fill in the original number value we used to query with. if (TextUtils.isEmpty(info.phoneNumber)) { info.phoneNumber = number; } - + return info; } @@ -235,9 +235,9 @@ public class CallerInfo { * @param number a phone number. * @return if the number belongs to a contact, the contact's name is * returned; otherwise, the number itself is returned. - * - * TODO NOTE: This MAY need to refer to the Asynchronous Query API - * [startQuery()], instead of getCallerInfo, but since it looks like + * + * TODO NOTE: This MAY need to refer to the Asynchronous Query API + * [startQuery()], instead of getCallerInfo, but since it looks like * it is only being used by the provider calls in the messaging app: * 1. android.provider.Telephony.Mms.getDisplayAddress() * 2. android.provider.Telephony.Sms.getDisplayAddress() @@ -267,5 +267,5 @@ public class CallerInfo { return null; } } -} +} diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index 6cb829d0d0b4..98ef4dd443a0 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -35,10 +35,10 @@ import android.util.Log; */ public class CallerInfoAsyncQuery { - + private static final boolean DBG = false; private static final String LOG_TAG = "CallerInfoAsyncQuery"; - + private static final int EVENT_NEW_QUERY = 1; private static final int EVENT_ADD_LISTENER = 2; private static final int EVENT_END_OF_QUEUE = 3; @@ -55,24 +55,24 @@ public class CallerInfoAsyncQuery { */ public interface OnQueryCompleteListener { /** - * Called when the query is complete. - */ + * Called when the query is complete. + */ public void onQueryComplete(int token, Object cookie, CallerInfo ci); } - - + + /** * Wrap the cookie from the WorkerArgs with additional information needed by our - * classes. + * classes. */ private static final class CookieWrapper { public OnQueryCompleteListener listener; public Object cookie; public int event; public String number; - } - - + } + + /** * Simple exception used to communicate problems with the query pool. */ @@ -81,12 +81,12 @@ public class CallerInfoAsyncQuery { super(error); } } - + /** * Our own implementation of the AsyncQueryHandler. */ private class CallerInfoAsyncQueryHandler extends AsyncQueryHandler { - + /** * The information relevant to each CallerInfo query. Each query may have multiple * listeners, so each AsyncCursorInfo is associated with 2 or more CookieWrapper @@ -96,20 +96,20 @@ public class CallerInfoAsyncQuery { private Context mQueryContext; private Uri mQueryUri; private CallerInfo mCallerInfo; - + /** * Our own query worker thread. - * + * * This thread handles the messages enqueued in the looper. The normal sequence * of events is that a new query shows up in the looper queue, followed by 0 or * more add listener requests, and then an end request. Of course, these requests * can be interlaced with requests from other tokens, but is irrelevant to this * handler since the handler has no state. - * + * * Note that we depend on the queue to keep things in order; in other words, the - * looper queue must be FIFO with respect to input from the synchronous startQuery + * looper queue must be FIFO with respect to input from the synchronous startQuery * calls and output to this handleMessage call. - * + * * This use of the queue is required because CallerInfo objects may be accessed * multiple times before the query is complete. All accesses (listeners) must be * queued up and informed in order when the query is complete. @@ -123,22 +123,22 @@ public class CallerInfoAsyncQuery { public void handleMessage(Message msg) { WorkerArgs args = (WorkerArgs) msg.obj; CookieWrapper cw = (CookieWrapper) args.cookie; - + if (cw == null) { // Normally, this should never be the case for calls originating // from within this code. - // However, if there is any code that this Handler calls (such as in + // However, if there is any code that this Handler calls (such as in // super.handleMessage) that DOES place unexpected messages on the // queue, then we need pass these messages on. - if (DBG) log("Unexpected command (CookieWrapper is null): " + msg.what + + if (DBG) log("Unexpected command (CookieWrapper is null): " + msg.what + " ignored by CallerInfoWorkerHandler, passing onto parent."); - + super.handleMessage(msg); } else { - - if (DBG) log("Processing event: " + cw.event + " token (arg1): " + msg.arg1 + + + if (DBG) log("Processing event: " + cw.event + " token (arg1): " + msg.arg1 + " command: " + msg.what + " query URI: " + args.uri); - + switch (cw.event) { case EVENT_NEW_QUERY: //start the sql command. @@ -148,7 +148,7 @@ public class CallerInfoAsyncQuery { // shortcuts to avoid query for recognized numbers. case EVENT_EMERGENCY_NUMBER: case EVENT_VOICEMAIL_NUMBER: - + case EVENT_ADD_LISTENER: case EVENT_END_OF_QUEUE: // query was already completed, so just send the reply. @@ -157,17 +157,17 @@ public class CallerInfoAsyncQuery { Message reply = args.handler.obtainMessage(msg.what); reply.obj = args; reply.arg1 = msg.arg1; - + reply.sendToTarget(); - + break; default: } } } } - - + + /** * Asynchronous query handler class for the contact / callerinfo object. */ @@ -182,29 +182,29 @@ public class CallerInfoAsyncQuery { /** * Overrides onQueryComplete from AsyncQueryHandler. - * + * * This method takes into account the state of this class; we construct the CallerInfo * object only once for each set of listeners. When the query thread has done its work - * and calls this method, we inform the remaining listeners in the queue, until we're - * out of listeners. Once we get the message indicating that we should expect no new - * listeners for this CallerInfo object, we release the AsyncCursorInfo back into the + * and calls this method, we inform the remaining listeners in the queue, until we're + * out of listeners. Once we get the message indicating that we should expect no new + * listeners for this CallerInfo object, we release the AsyncCursorInfo back into the * pool. */ @Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { if (DBG) log("query complete for token: " + token); - + //get the cookie and notify the listener. CookieWrapper cw = (CookieWrapper) cookie; if (cw == null) { // Normally, this should never be the case for calls originating // from within this code. - // However, if there is any code that calls this method, we should + // However, if there is any code that calls this method, we should // check the parameters to make sure they're viable. if (DBG) log("Cookie is null, ignoring onQueryComplete() request."); return; } - + if (cw.event == EVENT_END_OF_QUEUE) { release(); return; @@ -216,11 +216,11 @@ public class CallerInfoAsyncQuery { throw new QueryPoolException ("Bad context or query uri, or CallerInfoAsyncQuery already released."); } - + // adjust the callerInfo data as needed, and only if it was set from the // initial query request. // Change the callerInfo number ONLY if it is an emergency number or the - // voicemail number, and adjust other data (including photoResource) + // voicemail number, and adjust other data (including photoResource) // accordingly. if (cw.event == EVENT_EMERGENCY_NUMBER) { mCallerInfo = new CallerInfo(); @@ -238,80 +238,80 @@ public class CallerInfoAsyncQuery { // permission to retrieve VM number and would not generate // an EVENT_VOICEMAIL_NUMBER. But if it happens, don't crash. } - } else { + } else { mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor); // Use the number entered by the user for display. if (!TextUtils.isEmpty(cw.number)) { mCallerInfo.phoneNumber = PhoneNumberUtils.formatNumber(cw.number); } } - + if (DBG) log("constructing CallerInfo object for token: " + token); - + //notify that we can clean up the queue after this. CookieWrapper endMarker = new CookieWrapper(); endMarker.event = EVENT_END_OF_QUEUE; startQuery (token, endMarker, null, null, null, null, null); } - + //notify the listener that the query is complete. if (cw.listener != null) { - if (DBG) log("notifying listener: " + cw.listener.getClass().toString() + + if (DBG) log("notifying listener: " + cw.listener.getClass().toString() + " for token: " + token); cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo); } } } - + /** * Private constructor for factory methods. */ private CallerInfoAsyncQuery() { } - + /** * Factory method to start query with a Uri query spec */ - public static CallerInfoAsyncQuery startQuery(int token, Context context, Uri contactRef, + public static CallerInfoAsyncQuery startQuery(int token, Context context, Uri contactRef, OnQueryCompleteListener listener, Object cookie) { - + CallerInfoAsyncQuery c = new CallerInfoAsyncQuery(); c.allocate(context, contactRef); if (DBG) log("starting query for URI: " + contactRef + " handler: " + c.toString()); - + //create cookieWrapper, start query CookieWrapper cw = new CookieWrapper(); cw.listener = listener; cw.cookie = cookie; cw.event = EVENT_NEW_QUERY; - + c.mHandler.startQuery (token, cw, contactRef, null, null, null, null); - + return c; } - + /** * Factory method to start query with a number */ - public static CallerInfoAsyncQuery startQuery(int token, Context context, String number, + public static CallerInfoAsyncQuery startQuery(int token, Context context, String number, OnQueryCompleteListener listener, Object cookie) { //contruct the URI object and start Query. Uri contactRef = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, number); - + CallerInfoAsyncQuery c = new CallerInfoAsyncQuery(); c.allocate(context, contactRef); if (DBG) log("starting query for number: " + number + " handler: " + c.toString()); - + //create cookieWrapper, start query CookieWrapper cw = new CookieWrapper(); cw.listener = listener; cw.cookie = cookie; cw.number = number; - // check to see if these are recognized numbers, and use shortcuts if we can. + // check to see if these are recognized numbers, and use shortcuts if we can. if (PhoneNumberUtils.isEmergencyNumber(number)) { cw.event = EVENT_EMERGENCY_NUMBER; } else { @@ -320,13 +320,13 @@ public class CallerInfoAsyncQuery { try { vmNumber = TelephonyManager.getDefault().getVoiceMailNumber(); } catch (SecurityException ex) { - // Don't crash if this process doesn't have permission to + // Don't crash if this process doesn't have permission to // retrieve VM number. It's still allowed to look up caller info. // But don't try it again. sSkipVmCheck = true; } } - if (PhoneNumberUtils.compare(number, vmNumber)) { + if (PhoneNumberUtils.compare(number, vmNumber)) { cw.event = EVENT_VOICEMAIL_NUMBER; } else { cw.event = EVENT_NEW_QUERY; @@ -334,24 +334,24 @@ public class CallerInfoAsyncQuery { } c.mHandler.startQuery (token, cw, contactRef, null, null, null, null); - + return c; } - + /** * Method to add listeners to a currently running query */ public void addQueryListener(int token, OnQueryCompleteListener listener, Object cookie) { - if (DBG) log("adding listener to query: " + mHandler.mQueryUri + " handler: " + + if (DBG) log("adding listener to query: " + mHandler.mQueryUri + " handler: " + mHandler.toString()); - + //create cookieWrapper, add query request to end of queue. CookieWrapper cw = new CookieWrapper(); cw.listener = listener; cw.cookie = cookie; cw.event = EVENT_ADD_LISTENER; - + mHandler.startQuery (token, cw, null, null, null, null, null); } @@ -377,12 +377,12 @@ public class CallerInfoAsyncQuery { mHandler.mCallerInfo = null; mHandler = null; } - + /** * static logging method */ private static void log(String msg) { Log.d(LOG_TAG, msg); - } + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/CommandException.java b/telephony/java/com/android/internal/telephony/CommandException.java index 6c57580b17cd..a5d11cf250d8 100644 --- a/telephony/java/com/android/internal/telephony/gsm/CommandException.java +++ b/telephony/java/com/android/internal/telephony/CommandException.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import com.android.internal.telephony.RILConstants; @@ -48,19 +48,19 @@ public class CommandException extends RuntimeException { fromRilErrno(int ril_errno) { switch(ril_errno) { case RILConstants.SUCCESS: return null; - case RILConstants.RIL_ERRNO_INVALID_RESPONSE: + case RILConstants.RIL_ERRNO_INVALID_RESPONSE: return new CommandException(Error.INVALID_RESPONSE); - case RILConstants.RADIO_NOT_AVAILABLE: + case RILConstants.RADIO_NOT_AVAILABLE: return new CommandException(Error.RADIO_NOT_AVAILABLE); - case RILConstants.GENERIC_FAILURE: + case RILConstants.GENERIC_FAILURE: return new CommandException(Error.GENERIC_FAILURE); - case RILConstants.PASSWORD_INCORRECT: + case RILConstants.PASSWORD_INCORRECT: return new CommandException(Error.PASSWORD_INCORRECT); - case RILConstants.SIM_PIN2: + case RILConstants.SIM_PIN2: return new CommandException(Error.SIM_PIN2); - case RILConstants.SIM_PUK2: + case RILConstants.SIM_PUK2: return new CommandException(Error.SIM_PUK2); - case RILConstants.REQUEST_NOT_SUPPORTED: + case RILConstants.REQUEST_NOT_SUPPORTED: return new CommandException(Error.REQUEST_NOT_SUPPORTED); case RILConstants.OP_NOT_ALLOWED_DURING_VOICE_CALL: return new CommandException(Error.OP_NOT_ALLOWED_DURING_VOICE_CALL); diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java index 439bcb0fc901..ee743f8b9d99 100644 --- a/telephony/java/com/android/internal/telephony/CommandsInterface.java +++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java @@ -16,10 +16,10 @@ package com.android.internal.telephony; -//import com.android.internal.telephony.*; import android.os.Message; import android.os.Handler; + /** * {@hide} */ @@ -28,12 +28,12 @@ public interface CommandsInterface { RADIO_OFF, /* Radio explictly powered off (eg CFUN=0) */ RADIO_UNAVAILABLE, /* Radio unavailable (eg, resetting or not booted) */ SIM_NOT_READY, /* Radio is on, but the SIM interface is not ready */ - SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network + SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network personalization, or SIM absent */ SIM_READY, /* Radio is on and SIM interface is available */ RUIM_NOT_READY, /* Radio is on, but the RUIM interface is not ready */ RUIM_READY, /* Radio is on and the RUIM interface is available */ - RUIM_LOCKED_OR_ABSENT, /* RUIM PIN locked, PUK required, network + RUIM_LOCKED_OR_ABSENT, /* RUIM PIN locked, PUK required, network personalization locked, or RUIM absent */ NV_NOT_READY, /* Radio is on, but the NV interface is not available */ NV_READY; /* Radio is on and the NV interface is available */ @@ -49,32 +49,30 @@ public interface CommandsInterface { || this == NV_READY; } - boolean isAvailable() { + public boolean isAvailable() { return this != RADIO_UNAVAILABLE; } - boolean isSIMReady() { + public boolean isSIMReady() { return this == SIM_READY; } - - boolean isRUIMReady() { + + public boolean isRUIMReady() { return this == RUIM_READY; } - - boolean isNVReady() { + + public boolean isNVReady() { return this == NV_READY; } - boolean isGsm() { - return this == RADIO_OFF - || this == RADIO_UNAVAILABLE - || this == SIM_NOT_READY + + public boolean isGsm() { + return this == SIM_NOT_READY || this == SIM_LOCKED_OR_ABSENT || this == SIM_READY; } - boolean isCdma() { - return this == RADIO_OFF - || this == RADIO_UNAVAILABLE - || this == RUIM_NOT_READY + + public boolean isCdma() { + return this == RUIM_NOT_READY || this == RUIM_READY || this == RUIM_LOCKED_OR_ABSENT || this == NV_NOT_READY @@ -124,7 +122,7 @@ public interface CommandsInterface { static final String CB_FACILITY_BA_MT = "AC"; static final String CB_FACILITY_BA_SIM = "SC"; static final String CB_FACILITY_BA_FD = "FD"; - + // Used for various supp services apis // See 27.007 +CCFC or +CLCK @@ -133,7 +131,7 @@ public interface CommandsInterface { static final int SERVICE_CLASS_DATA = (1 << 1); //synoym for 16+32+64+128 static final int SERVICE_CLASS_FAX = (1 << 2); static final int SERVICE_CLASS_SMS = (1 << 3); - static final int SERVICE_CLASS_DATA_SYNC = (1 << 4); + static final int SERVICE_CLASS_DATA_SYNC = (1 << 4); static final int SERVICE_CLASS_DATA_ASYNC = (1 << 5); static final int SERVICE_CLASS_PACKET = (1 << 6); static final int SERVICE_CLASS_PAD = (1 << 7); @@ -153,8 +151,8 @@ public interface CommandsInterface { RadioState getRadioState(); - /** - * Fires on any RadioState transition + /** + * Fires on any RadioState transition * Always fires immediately as well * * do not attempt to calculate transitions by storing getRadioState() values @@ -162,68 +160,86 @@ public interface CommandsInterface { * registration methods */ void registerForRadioStateChanged(Handler h, int what, Object obj); + void unregisterForRadioStateChanged(Handler h); - /** - * Fires on any transition into RadioState.isOn() + /** + * Fires on any transition into RadioState.isOn() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForOn(Handler h, int what, Object obj); + void unregisterForOn(Handler h); - /** - * Fires on any transition out of RadioState.isAvailable() + /** + * Fires on any transition out of RadioState.isAvailable() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForAvailable(Handler h, int what, Object obj); - //void unregisterForAvailable(Handler h); - /** + void unregisterForAvailable(Handler h); + + /** * Fires on any transition into !RadioState.isAvailable() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForNotAvailable(Handler h, int what, Object obj); - //void unregisterForNotAvailable(Handler h); - /** + void unregisterForNotAvailable(Handler h); + + /** * Fires on any transition into RADIO_OFF or !RadioState.isAvailable() * Fires immediately if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForOffOrNotAvailable(Handler h, int what, Object obj); - //void unregisterForNotAvailable(Handler h); + void unregisterForOffOrNotAvailable(Handler h); - /** + /** * Fires on any transition into SIM_READY * Fires immediately if if currently in that state * In general, actions should be idempotent. State may change * before event is received. */ void registerForSIMReady(Handler h, int what, Object obj); - //void unregisterForSIMReady(Handler h); + void unregisterForSIMReady(Handler h); + /** Any transition into SIM_LOCKED_OR_ABSENT */ void registerForSIMLockedOrAbsent(Handler h, int what, Object obj); - //void unregisterForSIMLockedOrAbsent(Handler h); + void unregisterForSIMLockedOrAbsent(Handler h); void registerForCallStateChanged(Handler h, int what, Object obj); - //void unregisterForCallStateChanged(Handler h); + void unregisterForCallStateChanged(Handler h); void registerForNetworkStateChanged(Handler h, int what, Object obj); - //void unregisterForNetworkStateChanged(Handler h); - void registerForPDPStateChanged(Handler h, int what, Object obj); - //void unregisterForPDPStateChanged(Handler h); + void unregisterForNetworkStateChanged(Handler h); + void registerForDataStateChanged(Handler h, int what, Object obj); + void unregisterForDataStateChanged(Handler h); void registerForRadioTechnologyChanged(Handler h, int what, Object obj); - //void unregisterForRadioTechnologyChanged(Handler h); + void unregisterForRadioTechnologyChanged(Handler h); void registerForNVReady(Handler h, int what, Object obj); - //void unregisterForNVReady(Handler h, int what, Object obj); + void unregisterForNVReady(Handler h); void registerForRUIMLockedOrAbsent(Handler h, int what, Object obj); - //void unregisterForRUIMLockedOrAbsent(Handler h, int what, Object obj); + void unregisterForRUIMLockedOrAbsent(Handler h); + + /** InCall voice privacy notifications */ + void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj); + void unregisterForInCallVoicePrivacyOn(Handler h); + void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj); + void unregisterForInCallVoicePrivacyOff(Handler h); + + /** + * Fires on any transition into RUIM_READY + * Fires immediately if if currently in that state + * In general, actions should be idempotent. State may change + * before event is received. + */ void registerForRUIMReady(Handler h, int what, Object obj); - //void unregisterForRUIMReady(Handler h, int what, Object obj); - + void unregisterForRUIMReady(Handler h); + /** * unlike the register* methods, there's only one new SMS handler * if you need to unregister, you should also tell the radio to stop @@ -232,27 +248,30 @@ public interface CommandsInterface { * AsyncResult.result is a String containing the SMS PDU */ void setOnNewSMS(Handler h, int what, Object obj); + void unSetOnNewSMS(Handler h); /** - * Register for NEW_SMS_ON_SIM unsolicited message + * Register for NEW_SMS_ON_SIM unsolicited message * * AsyncResult.result is an int array containing the index of new SMS */ void setOnSmsOnSim(Handler h, int what, Object obj); + void unSetOnSmsOnSim(Handler h); /** - * Register for NEW_SMS_STATUS_REPORT unsolicited message + * Register for NEW_SMS_STATUS_REPORT unsolicited message * * AsyncResult.result is a String containing the status report PDU */ void setOnSmsStatus(Handler h, int what, Object obj); - + void unSetOnSmsStatus(Handler h); + /** * unlike the register* methods, there's only one NITZ time handler * * AsyncResult.result is an Object[] * ((Object[])AsyncResult.result)[0] is a String containing the NITZ time string - * ((Object[])AsyncResult.result)[0] is an Integer containing + * ((Object[])AsyncResult.result)[0] is an Integer containing * the UNIX time_t returned by time() when * this NITZ time was posted. * @@ -260,13 +279,14 @@ public interface CommandsInterface { * seconds on system startup */ void setOnNITZTime(Handler h, int what, Object obj); + void unSetOnNITZTime(Handler h); /** * unlike the register* methods, there's only one USSD notify handler * * Represents the arrival of a USSD "notify" message, which may * or may not have been triggered by a previous USSD send - * + * * AsyncResult.result is a String[] * ((String[])(AsyncResult.result))[0] contains status code * "0" USSD-Notify -- text in ((const char **)data)[1] @@ -281,26 +301,29 @@ public interface CommandsInterface { */ void setOnUSSD(Handler h, int what, Object obj); + void unSetOnUSSD(Handler h); /** * unlike the register* methods, there's only one signal strength handler - * AsyncResult.result is an int[2] - * response.obj.result[0] is received signal strength (0-31, 99) - * response.obj.result[1] is bit error rate (0-7, 99) + * AsyncResult.result is an int[2] + * response.obj.result[0] is received signal strength (0-31, 99) + * response.obj.result[1] is bit error rate (0-7, 99) * as defined in TS 27.007 8.5 */ void setOnSignalStrengthUpdate(Handler h, int what, Object obj); + void unSetOnSignalStrengthUpdate(Handler h); /** - * Sets the handler for SIM SMS storage full unsolicited message. + * Sets the handler for SIM/RUIM SMS storage full unsolicited message. * Unlike the register* methods, there's only one notification handler * * @param h Handler for notification message. * @param what User-defined message code. * @param obj User object. */ - void setOnSimSmsFull(Handler h, int what, Object obj); + void setOnIccSmsFull(Handler h, int what, Object obj); + void unSetOnIccSmsFull(Handler h); /** * Sets the handler for SIM Refresh notifications. @@ -311,7 +334,8 @@ public interface CommandsInterface { * @param obj User object. */ void setOnIccRefresh(Handler h, int what, Object obj); - + void unSetOnIccRefresh(Handler h); + /** * Sets the handler for RING notifications. * Unlike the register* methods, there's only one notification handler @@ -321,7 +345,8 @@ public interface CommandsInterface { * @param obj User object. */ void setOnCallRing(Handler h, int what, Object obj); - + void unSetOnCallRing(Handler h); + /** * Sets the handler for Supplementary Service Notifications. * Unlike the register* methods, there's only one notification handler @@ -331,6 +356,7 @@ public interface CommandsInterface { * @param obj User object. */ void setOnSuppServiceNotification(Handler h, int what, Object obj); + void unSetOnSuppServiceNotification(Handler h); /** * Sets the handler for Session End Notifications for STK. @@ -341,6 +367,7 @@ public interface CommandsInterface { * @param obj User object. */ void setOnStkSessionEnd(Handler h, int what, Object obj); + void unSetOnStkSessionEnd(Handler h); /** * Sets the handler for Proactive Commands for STK. @@ -351,6 +378,7 @@ public interface CommandsInterface { * @param obj User object. */ void setOnStkProactiveCmd(Handler h, int what, Object obj); + void unSetOnStkProactiveCmd(Handler h); /** * Sets the handler for Event Notifications for STK. @@ -361,6 +389,7 @@ public interface CommandsInterface { * @param obj User object. */ void setOnStkEvent(Handler h, int what, Object obj); + void unSetOnStkEvent(Handler h); /** * Sets the handler for Call Set Up Notifications for STK. @@ -371,6 +400,7 @@ public interface CommandsInterface { * @param obj User object. */ void setOnStkCallSetUp(Handler h, int what, Object obj); + void unSetOnStkCallSetUp(Handler h); /** * Enables/disbables supplementary service related notifications from @@ -380,19 +410,21 @@ public interface CommandsInterface { * @param result Message to be posted when command completes. */ void setSuppServiceNotifications(boolean enable, Message result); + //void unSetSuppServiceNotifications(Handler h); + /** * Returns current ICC status. * * AsyncResult.result is IccStatus - * + * */ - void getIccStatus(Message result); + void getIccStatus(Message result); /** * Supply the ICC PIN to the ICC card - * + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -406,7 +438,7 @@ public interface CommandsInterface { /** * Supply the ICC PUK to the ICC card - * + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -422,7 +454,7 @@ public interface CommandsInterface { * Supply the ICC PIN2 to the ICC card * Only called following operation where ICC_PIN2 was * returned as a a failure from a previous operation - * + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -438,7 +470,7 @@ public interface CommandsInterface { * Supply the SIM PUK2 to the SIM card * Only called following operation where SIM_PUK2 was * returned as a a failure from a previous operation - * + * * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -457,7 +489,7 @@ public interface CommandsInterface { void supplyNetworkDepersonalization(String netpin, Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -467,16 +499,26 @@ public interface CommandsInterface { */ void getCurrentCalls (Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result contains a List of PDPContextState + * @deprecated */ void getPDPContextList(Message result); - /** + /** + * returned message + * retMsg.obj = AsyncResult ar + * ar.exception carries exception on failure + * ar.userObject contains the orignal value of result.obj + * ar.result contains a List of PDPContextState + */ + void getDataCallList(Message result); + + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -489,7 +531,7 @@ public interface CommandsInterface { */ void dial (String address, int clirMode, Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -498,7 +540,7 @@ public interface CommandsInterface { */ void getIMSI(Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -507,7 +549,7 @@ public interface CommandsInterface { */ void getIMEI(Message result); - /** + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure @@ -516,7 +558,7 @@ public interface CommandsInterface { */ void getIMEISV(Message result); - /** + /** * Hang up one individual connection. * returned message * retMsg.obj = AsyncResult ar @@ -541,7 +583,7 @@ public interface CommandsInterface { /** * 3GPP 22.030 6.5.5 - * "Releases all active calls (if any exist) and accepts + * "Releases all active calls (if any exist) and accepts * the other (held or waiting) call." * * ar.exception carries exception on failure @@ -552,7 +594,7 @@ public interface CommandsInterface { /** * 3GPP 22.030 6.5.5 - * "Places all active calls (if any exist) on hold and accepts + * "Places all active calls (if any exist) on hold and accepts * the other (held or waiting) call." * * ar.exception carries exception on failure @@ -568,7 +610,7 @@ public interface CommandsInterface { * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void conference (Message result); /** @@ -578,7 +620,7 @@ public interface CommandsInterface { * @param result is a callback message */ void setPreferredVoicePrivacy(boolean enable, Message result); - + /** * Get currently set preferred Voice Privacy (VP) mode. * @@ -588,7 +630,7 @@ public interface CommandsInterface { /** * 3GPP 22.030 6.5.5 - * "Places all active calls on hold except call X with which + * "Places all active calls on hold except call X with which * communication shall be supported." */ void separateConnection (int gsmIndex, Message result); @@ -598,15 +640,15 @@ public interface CommandsInterface { * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void acceptCall (Message result); - /** + /** * also known as UDUB * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void rejectCall (Message result); /** @@ -630,14 +672,21 @@ public interface CommandsInterface { void getLastCallFailCause (Message result); - /** + /** * Reason for last PDP context deactivate or failure to activate * cause code returned as int[0] in Message.obj.response * returns an integer cause code defined in TS 24.008 * section 6.1.3.1.3 or close approximation + * @deprecated */ void getLastPdpFailCause (Message result); + /** + * The preferred new alternative to getLastPdpFailCause + * that is also CDMA-compatible. + */ + void getLastDataCallFailCause (Message result); + void setMute (boolean enableMute, Message response); void getMute (Message response); @@ -645,8 +694,8 @@ public interface CommandsInterface { /** * response.obj is an AsyncResult * response.obj.result is an int[2] - * response.obj.result[0] is received signal strength (0-31, 99) - * response.obj.result[1] is bit error rate (0-7, 99) + * response.obj.result[0] is received signal strength (0-31, 99) + * response.obj.result[1] is bit error rate (0-7, 99) * as defined in TS 27.007 8.5 */ void getSignalStrength (Message response); @@ -656,21 +705,21 @@ public interface CommandsInterface { * response.obj.result is an int[3] * response.obj.result[0] is registration state 0-5 from TS 27.007 7.2 * response.obj.result[1] is LAC if registered or -1 if not - * response.obj.result[2] is CID if registered or -1 if not + * response.obj.result[2] is CID if registered or -1 if not * valid LAC and CIDs are 0x0000 - 0xffff - * + * * Please note that registration state 4 ("unknown") is treated * as "out of service" above */ void getRegistrationState (Message response); - + /** * response.obj.result is an int[3] * response.obj.result[0] is registration state 0-5 from TS 27.007 7.2 * response.obj.result[1] is LAC if registered or -1 if not - * response.obj.result[2] is CID if registered or -1 if not + * response.obj.result[2] is CID if registered or -1 if not * valid LAC and CIDs are 0x0000 - 0xffff - * + * * Please note that registration state 4 ("unknown") is treated * as "out of service" above */ @@ -681,14 +730,14 @@ public interface CommandsInterface { * response.obj.result[0] is long alpha or null if unregistered * response.obj.result[1] is short alpha or null if unregistered * response.obj.result[2] is numeric or null if unregistered - */ + */ void getOperator(Message response); /** * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result is null on success and failure - */ + */ void sendDtmf(char c, Message result); @@ -711,26 +760,40 @@ public interface CommandsInterface { * smscPDU is smsc address in PDU form GSM BCD format prefixed * by a length byte (as expected by TS 27.005) or NULL for default SMSC * pdu is SMS in PDU format as an ASCII hex string - * less the SMSC address + * less the SMSC address */ void sendSMS (String smscPDU, String pdu, Message response); /** + * @param pdu is CDMA-SMS in internal pseudo-PDU format + * @param response sent when operation completes + */ + void sendCdmaSms(byte[] pdu, Message response); + + /** * Deletes the specified SMS record from SIM memory (EF_SMS). - * + * * @param index index of the SMS record to delete * @param response sent when operation completes */ void deleteSmsOnSim(int index, Message response); /** + * Deletes the specified SMS record from RUIM memory (EF_SMS in DF_CDMA). + * + * @param index index of the SMS record to delete + * @param response sent when operation completes + */ + void deleteSmsOnRuim(int index, Message response); + + /** * Writes an SMS message to SIM memory (EF_SMS). - * + * * @param status status of message on SIM. One of: - * SmsManger.STATUS_ON_SIM_READ - * SmsManger.STATUS_ON_SIM_UNREAD - * SmsManger.STATUS_ON_SIM_SENT - * SmsManger.STATUS_ON_SIM_UNSENT + * SmsManger.STATUS_ON_ICC_READ + * SmsManger.STATUS_ON_ICC_UNREAD + * SmsManger.STATUS_ON_ICC_SENT + * SmsManger.STATUS_ON_ICC_UNSENT * @param pdu message PDU, as hex string * @param response sent when operation completes. * response.obj will be an AsyncResult, and will indicate @@ -738,89 +801,105 @@ public interface CommandsInterface { */ void writeSmsToSim(int status, String smsc, String pdu, Message response); + void writeSmsToRuim(int status, String pdu, Message response); + + /** + * @deprecated + * @param apn + * @param user + * @param password + * @param response + */ void setupDefaultPDP(String apn, String user, String password, Message response); + /** + * @deprecated + * @param cid + * @param response + */ void deactivateDefaultPDP(int cid, Message response); void setRadioPower(boolean on, Message response); void acknowledgeLastIncomingSMS(boolean success, Message response); - /** - * parameters equivilient to 27.007 AT+CRSM command + void acknowledgeLastIncomingCdmaSms(boolean success, Message response); + + /** + * parameters equivilient to 27.007 AT+CRSM command * response.obj will be an AsyncResult * response.obj.userObj will be a IccIoResult on success */ - void iccIO (int command, int fileid, String path, int p1, int p2, int p3, + void iccIO (int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, Message response); /** * (AsyncResult)response.obj).result is an int[] with element [0] set to - * 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned". + * 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned". * * @param response is callback message */ - + void queryCLIP(Message response); /** * response.obj will be a an int[2] * * response.obj[0] will be TS 27.007 +CLIR parameter 'n' - * 0 presentation indicator is used according to the subscription of the CLIR service - * 1 CLIR invocation - * 2 CLIR suppression + * 0 presentation indicator is used according to the subscription of the CLIR service + * 1 CLIR invocation + * 2 CLIR suppression * * response.obj[1] will be TS 27.007 +CLIR parameter 'm' - * 0 CLIR not provisioned - * 1 CLIR provisioned in permanent mode - * 2 unknown (e.g. no network, etc.) - * 3 CLIR temporary mode presentation restricted - * 4 CLIR temporary mode presentation allowed + * 0 CLIR not provisioned + * 1 CLIR provisioned in permanent mode + * 2 unknown (e.g. no network, etc.) + * 3 CLIR temporary mode presentation restricted + * 4 CLIR temporary mode presentation allowed */ void getCLIR(Message response); - + /** * clirMode is one of the CLIR_* constants above * * response.obj is null */ - + void setCLIR(int clirMode, Message response); /** * (AsyncResult)response.obj).result is an int[] with element [0] set to - * 0 for disabled, 1 for enabled. + * 0 for disabled, 1 for enabled. * * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - + void queryCallWaiting(int serviceClass, Message response); - + /** * @param enable is true to enable, false to disable * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - + void setCallWaiting(boolean enable, int serviceClass, Message response); /** * @param action is one of CF_ACTION_* * @param cfReason is one of CF_REASON_* - * @param serviceClass is a sum of SERVICE_CLASSS_* + * @param serviceClass is a sum of SERVICE_CLASSS_* */ - void setCallForward(int action, int cfReason, int serviceClass, - String number, int timeSeconds, Message response); + void setCallForward(int action, int cfReason, int serviceClass, + String number, int timeSeconds, Message response); /** * cfReason is one of CF_REASON_* * * ((AsyncResult)response.obj).result will be an array of * CallForwardInfo's - * + * * An array of length 0 means "disabled for all codes" */ void queryCallForwardStatus(int cfReason, int serviceClass, @@ -859,7 +938,7 @@ public interface CommandsInterface { * @param serviceClass is a sum of SERVICE_CLASS_* * @param response is callback message */ - + void queryFacilityLock (String facility, String password, int serviceClass, Message response); @@ -872,7 +951,7 @@ public interface CommandsInterface { */ void setFacilityLock (String facility, boolean lockState, String password, int serviceClass, Message response); - + void sendUSSD (String ussdString, Message response); @@ -894,7 +973,7 @@ public interface CommandsInterface { /** * Query the list of band mode supported by RF. - * + * * @param response is callback message * ((AsyncResult)response.obj).result is an int[] with every * element representing one avialable BM_*_BAND @@ -969,15 +1048,15 @@ public interface CommandsInterface { public void handleCallSetupRequestFromSim(boolean accept, Message response); //***** new Methods for CDMA support - + /** * Request the device ESN / MEID / IMEI / IMEISV. * "response" is const char ** * [0] is IMEI if GSM subscription is available * [1] is IMEISV if GSM subscription is available * [2] is ESN if CDMA subscription is available - * [3] is MEID if CDMA subscription is available - */ + * [3] is MEID if CDMA subscription is available + */ public void getDeviceIdentity(Message response); /** @@ -988,16 +1067,15 @@ public interface CommandsInterface { * [2] is AH_SID (Analog Home SID) if CDMA subscription * [3] is H_SID (Home SID) if CDMA subscription is available * [4] is H_NID (Home SID) if CDMA subscription is available - */ + */ public void getCDMASubscription(Message response); - - /** - * Fires on any transition into RUIM_READY - * Fires immediately if if currently in that state - * In general, actions should be idempotent. State may change - * before event is received. + + /** + * Send Flash Code. + * "response" is is NULL + * [0] is a FLASH string */ - //void registerForRUIMReady(Handler h, int what, Object obj); //TODO check moved above + public void sendCDMAFeatureCode(String FeatureCode, Message response); /** Set the Phone type created */ void setPhoneType(int phoneType); @@ -1007,21 +1085,21 @@ public interface CommandsInterface { * @param response is callback message to report one of CDMA_RM_* */ void queryCdmaRoamingPreference(Message response); - + /** * Requests to set the CDMA roaming preference * @param cdmaRoamingType one of CDMA_RM_* * @param response is callback message */ void setCdmaRoamingPreference(int cdmaRoamingType, Message response); - + /** * Requests to set the CDMA subscription mode * @param cdmaSubscriptionType one of CDMA_SUBSCRIPTION_* * @param response is callback message */ void setCdmaSubscription(int cdmaSubscriptionType, Message response); - + /** * Set the TTY mode for the CDMA phone * @@ -1029,14 +1107,75 @@ public interface CommandsInterface { * @param response is callback message */ void setTTYModeEnabled(boolean enable, Message response); - + /** * Query the TTY mode for the CDMA phone * (AsyncResult)response.obj).result is an int[] with element [0] set to - * 0 for disabled, 1 for enabled. - * + * 0 for disabled, 1 for enabled. + * * @param response is callback message */ void queryTTYModeEnabled(Message response); + /** + * Setup a packet data connection On successful completion, the result + * message will return the following: [0] indicating PDP CID, which is + * generated by RIL. This Connection ID is used in both GSM/UMTS and CDMA + * modes [1] indicating the network interface name for GSM/UMTS or CDMA [2] + * indicating the IP address for this interface for GSM/UMTS and NULL in the + * case of CDMA + * + * @param radioTechnology + * indicates whether to setup connection on radio technology CDMA + * (0) or GSM/UMTS (1) + * @param profile + * Profile Number or NULL to indicate default profile + * @param apn + * the APN to connect to if radio technology is GSM/UMTS. + * Otherwise null for CDMA. + * @param user + * the username for APN, or NULL + * @param password + * the password for APN, or NULL + * @param result + * Callback message + */ + public void setupDataCall(String radioTechnology, String profile, String apn, + String user, String password, Message result); + + /** + * Deactivate packet data connection + * + * @param cid + * The connection ID + * @param result + * Callback message is empty on completion + */ + public void deactivateDataCall(int cid, Message result); + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param result + * Callback message is empty on completion + */ + public void activateCdmaBroadcastSms(int activate, Message result); + + /** + * Configure cdma cell broadcast SMS. + * + * @param result + * Callback message is empty on completion + */ + public void setCdmaBroadcastConfig(int[] configValuesArray, Message result); + + /** + * Query the current configuration of cdma cell broadcast SMS. + * + * @param result + * Callback message contains the configuration from the modem on completion + */ + public void getCdmaBroadcastConfig(Message result); } diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java index 2cc7ee2c17f6..d395a4ae71a6 100644 --- a/telephony/java/com/android/internal/telephony/Connection.java +++ b/telephony/java/com/android/internal/telephony/Connection.java @@ -34,7 +34,7 @@ public abstract class Connection { INCOMING_REJECTED, /* an incoming call that was rejected */ POWER_OFF, /* radio is turned off explicitly */ OUT_OF_SERVICE, /* out of service */ - SIM_ERROR, /* No SIM, SIM locked, or other SIM error */ + ICC_ERROR, /* No ICC, ICC locked, or other ICC error */ CALL_BARRED, /* call was blocked by call barrring */ FDN_BLOCKED /* call was blocked by fixed dial number */ } @@ -43,7 +43,7 @@ public abstract class Connection { /* Instance Methods */ - /** + /** * Gets address (e.g., phone number) associated with connection * TODO: distinguish reasons for unavailablity * @@ -81,7 +81,7 @@ public abstract class Connection { public abstract long getDisconnectTime(); /** - * returns the number of milliseconds the call has been connected, + * returns the number of milliseconds the call has been connected, * or 0 if the call has never connected. * If the call is still connected, then returns the elapsed * time since connect @@ -102,8 +102,8 @@ public abstract class Connection { public abstract DisconnectCause getDisconnectCause(); /** - * Returns true of this connection originated elsewhere - * ("MT" or mobile terminated; another party called this terminal) + * Returns true of this connection originated elsewhere + * ("MT" or mobile terminated; another party called this terminal) * or false if this call originated here (MO or mobile originated) */ public abstract boolean isIncoming(); @@ -111,7 +111,7 @@ public abstract class Connection { /** * If this Connection is connected, then it is associated with * a Call. - * + * * Returns getCall().getState() or Call.State.IDLE if not * connected */ @@ -120,16 +120,16 @@ public abstract class Connection { c = getCall(); - if (c == null) { + if (c == null) { return Call.State.IDLE; } else { return c.getState(); } } - + /** * isAlive() - * + * * @return true if the connection isn't disconnected * (could be active, holding, ringing, dialing, etc) */ @@ -147,7 +147,7 @@ public abstract class Connection { } /** - * + * * @return the userdata set in setUserData() */ public Object getUserData() { @@ -155,13 +155,13 @@ public abstract class Connection { } /** - * + * * @param userdata user can store an any userdata in the Connection object. */ public void setUserData(Object userdata) { this.userData = userdata; } - + /** * Hangup individual Connection */ @@ -175,16 +175,16 @@ public abstract class Connection { public abstract void separate() throws CallStateException; public enum PostDialState { - NOT_STARTED, /* The post dial string playback hasn't - been started, or this call is not yet + NOT_STARTED, /* The post dial string playback hasn't + been started, or this call is not yet connected, or this is an incoming call */ STARTED, /* The post dial string playback has begun */ - WAIT, /* The post dial string playback is waiting for a + WAIT, /* The post dial string playback is waiting for a call to proceedAfterWaitChar() */ - WILD, /* The post dial string playback is waiting for a + WILD, /* The post dial string playback is waiting for a call to proceedAfterWildChar() */ COMPLETE, /* The post dial string playback is complete */ - CANCELLED /* The post dial string playback was cancelled + CANCELLED /* The post dial string playback was cancelled with cancelPostDial() */ } @@ -199,7 +199,7 @@ public abstract class Connection { /** * See Phone.setOnPostDialWaitCharacter() */ - + public abstract void proceedAfterWaitChar(); /** @@ -210,6 +210,6 @@ public abstract class Connection { * Cancel any post */ public abstract void cancelPostDial(); - + } diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java new file mode 100644 index 000000000000..0b0dc7a3b744 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -0,0 +1,297 @@ +/* + * 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; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +/** + * {@hide} + */ +public abstract class DataConnection extends Handler { + + // the inherited class + + public enum State { + ACTIVE, /* has active data connection */ + ACTIVATING, /* during connecting process */ + INACTIVE; /* has empty data connection */ + + public String toString() { + switch (this) { + case ACTIVE: + return "active"; + case ACTIVATING: + return "setting up"; + default: + return "inactive"; + } + } + + public boolean isActive() { + return this == ACTIVE; + } + + public boolean isInactive() { + return this == INACTIVE; + } + } + + public enum FailCause { + NONE, + BAD_APN, + BAD_PAP_SECRET, + BARRED, + USER_AUTHENTICATION, + SERVICE_OPTION_NOT_SUPPORTED, + SERVICE_OPTION_NOT_SUBSCRIBED, + SIM_LOCKED, + RADIO_OFF, + NO_SIGNAL, + NO_DATA_PLAN, + RADIO_NOT_AVAILABLE, + SUSPENED_TEMPORARY, + RADIO_ERROR_RETRY, + UNKNOWN; + + public boolean isPermanentFail() { + return (this == RADIO_OFF); + } + + public String toString() { + switch (this) { + case NONE: + return "no error"; + case BAD_APN: + return "bad apn"; + case BAD_PAP_SECRET: + return "bad pap secret"; + case BARRED: + return "barred"; + case USER_AUTHENTICATION: + return "error user autentication"; + case SERVICE_OPTION_NOT_SUPPORTED: + return "data not supported"; + case SERVICE_OPTION_NOT_SUBSCRIBED: + return "datt not subcribed"; + case SIM_LOCKED: + return "sim locked"; + case RADIO_OFF: + return "radio is off"; + case NO_SIGNAL: + return "no signal"; + case NO_DATA_PLAN: + return "no data plan"; + case RADIO_NOT_AVAILABLE: + return "radio not available"; + case SUSPENED_TEMPORARY: + return "suspend temporary"; + case RADIO_ERROR_RETRY: + return "transient radio error"; + default: + return "unknown data error"; + } + } + } + + // ***** Event codes + protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 1; + protected static final int EVENT_GET_LAST_FAIL_DONE = 2; + protected static final int EVENT_LINK_STATE_CHANGED = 3; + protected static final int EVENT_DEACTIVATE_DONE = 4; + protected static final int EVENT_FORCE_RETRY = 5; + + //***** Tag IDs for EventLog + protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100; + + + //***** Member Variables + protected PhoneBase phone; + protected Message onConnectCompleted; + protected Message onDisconnect; + protected int cid; + protected String interfaceName; + protected String ipAddress; + protected String gatewayAddress; + protected String[] dnsServers; + protected State state; + protected long createTime; + protected long lastFailTime; + protected FailCause lastFailCause; + protected static final String NULL_IP = "0.0.0.0"; + Object userData; + + // receivedDisconnectReq is set when disconnect during activation + protected boolean receivedDisconnectReq; + + /* Instance Methods */ + protected abstract void onSetupConnectionCompleted(AsyncResult ar); + + protected abstract void onDeactivated(AsyncResult ar); + + protected abstract void disconnect(Message msg); + + protected abstract void notifyDisconnect(Message msg); + + protected abstract FailCause getFailCauseFromRequest(int rilCause); + + protected abstract void notifyFail(FailCause cause, Message onCompleted); + + protected abstract void onLinkStateChanged(DataLink.LinkState linkState); + + protected abstract void log(String s); + + + //***** Constructor + protected DataConnection(PhoneBase phone) { + super(); + this.phone = phone; + onConnectCompleted = null; + onDisconnect = null; + this.cid = -1; + receivedDisconnectReq = false; + this.dnsServers = new String[2]; + + clearSettings(); + } + + protected void setHttpProxy(String httpProxy, String httpPort) { + if (httpProxy == null || httpProxy.length() == 0) { + phone.setSystemProperty("net.gprs.http-proxy", null); + return; + } + + if (httpPort == null || httpPort.length() == 0) { + httpPort = "8080"; // Default to port 8080 + } + + phone.setSystemProperty("net.gprs.http-proxy", + "http://" + httpProxy + ":" + httpPort + "/"); + } + + public String getInterface() { + return interfaceName; + } + + public String getIpAddress() { + return ipAddress; + } + + public String getGatewayAddress() { + return gatewayAddress; + } + + public String[] getDnsServers() { + return dnsServers; + } + + public void clearSettings() { + log("DataConnection.clearSettings()"); + + this.state = State.INACTIVE; + this.createTime = -1; + this.lastFailTime = -1; + this.lastFailCause = FailCause.NONE; + + receivedDisconnectReq = false; + onConnectCompleted = null; + interfaceName = null; + ipAddress = null; + gatewayAddress = null; + dnsServers[0] = null; + dnsServers[1] = null; + } + + protected void onGetLastFailCompleted(AsyncResult ar) { + if (receivedDisconnectReq) { + // Don't bother reporting the error if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + notifyDisconnect(onDisconnect); + } else { + FailCause cause = FailCause.UNKNOWN; + + if (ar.exception == null) { + int rilFailCause = ((int[]) (ar.result))[0]; + cause = getFailCauseFromRequest(rilFailCause); + } + notifyFail(cause, onConnectCompleted); + } + } + + protected void onForceRetry() { + if (receivedDisconnectReq) { + notifyDisconnect(onDisconnect); + } else { + notifyFail(FailCause.RADIO_ERROR_RETRY, onConnectCompleted); + } + } + + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + log("DataConnection.handleMessage()"); + + switch (msg.what) { + + case EVENT_SETUP_DATA_CONNECTION_DONE: + onSetupConnectionCompleted((AsyncResult) msg.obj); + break; + + case EVENT_FORCE_RETRY: + onForceRetry(); + break; + + case EVENT_GET_LAST_FAIL_DONE: + onGetLastFailCompleted((AsyncResult) msg.obj); + break; + + case EVENT_LINK_STATE_CHANGED: + ar = (AsyncResult) msg.obj; + DataLink.LinkState ls = (DataLink.LinkState) ar.result; + onLinkStateChanged(ls); + break; + + case EVENT_DEACTIVATE_DONE: + onDeactivated((AsyncResult) msg.obj); + break; + } + } + + public State getState() { + log("DataConnection.getState()"); + return state; + } + + public long getConnectionTime() { + log("DataConnection.getConnectionTime()"); + return createTime; + } + + public long getLastFailTime() { + log("DataConnection.getLastFailTime()"); + return lastFailTime; + } + + public FailCause getLastFailCause() { + log("DataConnection.getLastFailCause()"); + return lastFailCause; + } +} diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java new file mode 100644 index 000000000000..f6469b107416 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -0,0 +1,334 @@ +/* + * 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; + +import android.os.AsyncResult; +import android.os.Handler; +import android.os.INetStatService; +import android.os.Message; +import android.os.RemoteException; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.util.Log; + +/** + * {@hide} + * + */ +public abstract class DataConnectionTracker extends Handler { + private static final boolean DBG = true; + + /** + * IDLE: ready to start data connection setup, default state + * INITING: state of issued setupDefaultPDP() but not finish yet + * CONNECTING: state of issued startPppd() but not finish yet + * SCANNING: data connection fails with one apn but other apns are available + * ready to start data connection on other apns (before INITING) + * CONNECTED: IP connection is setup + * FAILED: data connection fail for all apns settings + * + * getDataConnectionState() maps State to DataState + * FAILED or IDLE : DISCONNECTED + * INITING or CONNECTING or SCANNING: CONNECTING + * CONNECTED : CONNECTED + */ + public enum State { + IDLE, + INITING, + CONNECTING, + SCANNING, + CONNECTED, + FAILED + } + + public enum Activity { + NONE, + DATAIN, + DATAOUT, + DATAINANDOUT + } + + //***** Event Codes + protected static final int EVENT_DATA_SETUP_COMPLETE = 1; + protected static final int EVENT_RADIO_AVAILABLE = 3; + protected static final int EVENT_RECORDS_LOADED = 4; + protected static final int EVENT_TRY_SETUP_DATA = 5; + protected static final int EVENT_DATA_STATE_CHANGED = 6; + protected static final int EVENT_POLL_PDP = 7; + protected static final int EVENT_GET_PDP_LIST_COMPLETE = 11; + protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12; + protected static final int EVENT_VOICE_CALL_STARTED = 14; + protected static final int EVENT_VOICE_CALL_ENDED = 15; + protected static final int EVENT_GPRS_DETACHED = 19; + protected static final int EVENT_LINK_STATE_CHANGED = 20; + protected static final int EVENT_ROAMING_ON = 21; + protected static final int EVENT_ROAMING_OFF = 22; + protected static final int EVENT_ENABLE_NEW_APN = 23; + protected static final int EVENT_RESTORE_DEFAULT_APN = 24; + protected static final int EVENT_DISCONNECT_DONE = 25; + protected static final int EVENT_GPRS_ATTACHED = 26; + protected static final int EVENT_START_NETSTAT_POLL = 27; + protected static final int EVENT_START_RECOVERY = 28; + protected static final int EVENT_CDMA_DATA_DETACHED = 29; + protected static final int EVENT_NV_READY = 30; + + //***** Constants + protected static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000; + + /** Slow poll when attempting connection recovery. */ + protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000; + /** Default ping deadline, in seconds. */ + protected final int DEFAULT_PING_DEADLINE = 5; + /** Default max failure count before attempting to network re-registration. */ + protected final int DEFAULT_MAX_PDP_RESET_FAIL = 3; + + /** + * After detecting a potential connection problem, this is the max number + * of subsequent polls before attempting a radio reset. At this point, + * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to + * poll for about 2 more minutes. + */ + protected static final int NO_RECV_POLL_LIMIT = 24; + + // 1 sec. default polling interval when screen is on. + protected static final int POLL_NETSTAT_MILLIS = 1000; + // 10 min. default polling interval when screen is off. + protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; + // 2 min for round trip time + protected static final int POLL_LONGEST_RTT = 120 * 1000; + // 10 for packets without ack + protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10; + // how long to wait before switching back to default APN + protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000; + // system property that can override the above value + protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; + // represents an invalid IP address + protected static final String NULL_IP = "0.0.0.0"; + + + // member variables + protected PhoneBase phone; + protected Activity activity = Activity.NONE; + protected State state = State.IDLE; + protected Handler mDataConnectionTracker = null; + + + protected INetStatService netstat; + protected int txPkts, rxPkts, sentSinceLastRecv, netStatPollPeriod; + protected int mNoRecvPollCount = 0; + protected boolean netStatPollEnabled = false; + + /** + * Default constructor + */ + protected DataConnectionTracker(PhoneBase phone) { + super(); + this.phone = phone; + } + + public Activity getActivity() { + return activity; + } + + public State getState() { + return state; + } + + //The data roaming setting is now located in the shared preferences. + // See if the requested preference value is the same as that stored in + // the shared values. If it is not, then update it. + public void setDataOnRoamingEnabled(boolean enabled) { + if (getDataOnRoamingEnabled() != enabled) { + Settings.System.putInt(phone.getContext().getContentResolver(), + Settings.System.DATA_ROAMING, enabled ? 1 : 0); + } + Message roamingMsg = phone.getServiceState().getRoaming() ? + obtainMessage(EVENT_ROAMING_ON) : obtainMessage(EVENT_ROAMING_OFF); + sendMessage(roamingMsg); + } + + //Retrieve the data roaming setting from the shared preferences. + public boolean getDataOnRoamingEnabled() { + try { + return Settings.System.getInt(phone.getContext().getContentResolver(), + Settings.System.DATA_ROAMING) > 0; + } catch (SettingNotFoundException snfe) { + return false; + } + } + + // abstract handler methods + protected abstract void onTrySetupData(); + protected abstract void onRoamingOff(); + protected abstract void onRoamingOn(); + protected abstract void onRadioAvailable(); + protected abstract void onRadioOffOrNotAvailable(); + protected abstract void onDataSetupComplete(AsyncResult ar); + protected abstract void onDisconnectDone(); + protected abstract void onVoiceCallStarted(); + protected abstract void onVoiceCallEnded(); + + //***** Overridden from Handler + public void handleMessage (Message msg) { + switch (msg.what) { + + case EVENT_TRY_SETUP_DATA: + onTrySetupData(); + break; + + case EVENT_ROAMING_OFF: + onRoamingOff(); + break; + + case EVENT_ROAMING_ON: + onRoamingOn(); + break; + + case EVENT_RADIO_AVAILABLE: + onRadioAvailable(); + break; + + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + onRadioOffOrNotAvailable(); + break; + + case EVENT_DATA_SETUP_COMPLETE: + onDataSetupComplete((AsyncResult) msg.obj); + break; + + case EVENT_DISCONNECT_DONE: + onDisconnectDone(); + break; + + case EVENT_VOICE_CALL_STARTED: + onVoiceCallStarted(); + break; + + case EVENT_VOICE_CALL_ENDED: + onVoiceCallEnded(); + break; + + default: + Log.e("DATA", "Unidentified event = " + msg.what); + break; + } + } + + /** + * Report the current state of data connectivity (enabled or disabled) + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + public abstract boolean getDataEnabled(); + + /** + * Prevent mobile data connections from being established, + * or once again allow mobile data connections. If the state + * toggles, then either tear down or set up data, as + * appropriate to match the new state. + * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data + * @return {@code true} if the operation succeeded + */ + public abstract boolean setDataEnabled(boolean enable); + + protected Runnable mPollNetStat = new Runnable() { + + public void run() { + int sent, received; + int preTxPkts = -1, preRxPkts = -1; + + Activity newActivity; + + preTxPkts = txPkts; + preRxPkts = rxPkts; + + // check if netstat is still valid to avoid NullPointerException after NTC + if (netstat != null) { + try { + txPkts = netstat.getTxPackets(); + rxPkts = netstat.getRxPackets(); + } catch (RemoteException e) { + txPkts = 0; + rxPkts = 0; + } + + //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); + + if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { + sent = txPkts - preTxPkts; + received = rxPkts - preRxPkts; + + if ( sent > 0 && received > 0 ) { + sentSinceLastRecv = 0; + newActivity = Activity.DATAINANDOUT; + } else if (sent > 0 && received == 0) { + if (phone.getState() == Phone.State.IDLE) { + sentSinceLastRecv += sent; + } else { + sentSinceLastRecv = 0; + } + newActivity = Activity.DATAOUT; + } else if (sent == 0 && received > 0) { + sentSinceLastRecv = 0; + newActivity = Activity.DATAIN; + } else if (sent == 0 && received == 0) { + newActivity = Activity.NONE; + } else { + sentSinceLastRecv = 0; + newActivity = Activity.NONE; + } + + if (activity != newActivity) { + activity = newActivity; + phone.notifyDataActivity(); + } + } + + if (sentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) { + // we already have NUMBER_SENT_PACKETS sent without ack + if (mNoRecvPollCount < NO_RECV_POLL_LIMIT) { + mNoRecvPollCount++; + // Slow down the poll interval to let things happen + netStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS; + } else { + if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + + " pkts since last received"); + // We've exceeded the threshold. Restart the radio. + netStatPollEnabled = false; + stopNetStatPoll(); + restartRadio(); + } + } else { + mNoRecvPollCount = 0; + netStatPollPeriod = POLL_NETSTAT_MILLIS; + } + + if (netStatPollEnabled) { + mDataConnectionTracker.postDelayed(this, netStatPollPeriod); + } + } + } + }; + + protected abstract void startNetStatPoll(); + + protected abstract void stopNetStatPoll(); + + protected abstract void restartRadio(); + + protected abstract void log(String s); +} diff --git a/telephony/java/com/android/internal/telephony/gsm/DataLink.java b/telephony/java/com/android/internal/telephony/DataLink.java index b822ab45a5e4..8132d9170d06 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DataLink.java +++ b/telephony/java/com/android/internal/telephony/DataLink.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.os.Handler; import android.os.Registrant; @@ -24,14 +24,13 @@ import android.os.Registrant; * * {@hide} */ -abstract class DataLink extends Handler implements DataLinkInterface { +public abstract class DataLink extends Handler implements DataLinkInterface { /** Registrant for link status change notifications. */ - Registrant mLinkChangeRegistrant; - + protected Registrant mLinkChangeRegistrant; protected DataConnectionTracker dataConnection; - DataLink(DataConnectionTracker dc) { + protected DataLink(DataConnectionTracker dc) { dataConnection = dc; } diff --git a/telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java b/telephony/java/com/android/internal/telephony/DataLinkInterface.java index bca63f2c7f20..e8148a8945a8 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java +++ b/telephony/java/com/android/internal/telephony/DataLinkInterface.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.database.Cursor; import android.os.Handler; @@ -24,7 +24,7 @@ import android.os.Handler; * * {@hide} */ -interface DataLinkInterface { +public interface DataLinkInterface { /** * Link state enumeration. * @@ -35,21 +35,21 @@ interface DataLinkInterface { LINK_DOWN, LINK_EXITED } - + /** Normal exit */ final static int EXIT_OK = 0; /** Open failed */ final static int EXIT_OPEN_FAILED = 7; - + /** * Sets the handler for link state change events. - * + * * @param h Handler * @param what User-defined message code * @param obj User object */ void setOnLinkChange(Handler h, int what, Object obj); - + /** * Sets up the data link. */ @@ -59,14 +59,14 @@ interface DataLinkInterface { * Tears down the data link. */ void disconnect(); - + /** - * Returns the exit code for a data link failure. + * Returns the exit code for a data link failure. * * @return exit code */ int getLastLinkExitCode(); - + /** * Sets password information that may be required by the data link * (eg, PAP secrets). diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java index 81ef623d8f7d..79b4afe86984 100644 --- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -33,7 +33,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { private static final boolean DBG = true; private ITelephonyRegistry mRegistry; - /*package*/ + /*package*/ DefaultPhoneNotifier() { mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( "telephony.registry")); @@ -94,7 +94,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { public void notifyDataConnection(Phone sender, String reason) { try { - mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()), + mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()), sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), sender.getInterfaceName(null)); } catch (RemoteException ex) { @@ -119,7 +119,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier { // system process is dead } } - + private void log(String s) { Log.d(LOG_TAG, "[PhoneNotifier] " + s); } diff --git a/telephony/java/com/android/internal/telephony/DriverCall.java b/telephony/java/com/android/internal/telephony/DriverCall.java index 515693f5c5a4..00e7d800c83f 100644 --- a/telephony/java/com/android/internal/telephony/DriverCall.java +++ b/telephony/java/com/android/internal/telephony/DriverCall.java @@ -25,7 +25,7 @@ import android.telephony.PhoneNumberUtils; */ public class DriverCall implements Comparable { static final String LOG_TAG = "RILB"; - + public enum State { ACTIVE, HOLDING, @@ -45,7 +45,7 @@ public class DriverCall implements Comparable { public int TOA; public boolean isVoice; public int als; - + /** returns null on error */ static DriverCall fromCLCCLine(String line) { @@ -118,7 +118,7 @@ public class DriverCall implements Comparable { } } - //***** Comparable Implementation + //***** Comparable Implementation /** For sorting by index */ public int diff --git a/telephony/java/com/android/internal/telephony/gsm/EncodeException.java b/telephony/java/com/android/internal/telephony/EncodeException.java index d546cefd9491..0436ba0a070b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/EncodeException.java +++ b/telephony/java/com/android/internal/telephony/EncodeException.java @@ -14,25 +14,21 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * {@hide} */ -public class EncodeException extends Exception -{ - public EncodeException() - { +public class EncodeException extends Exception { + public EncodeException() { super(); } - - public EncodeException(String s) - { + + public EncodeException(String s) { super(s); } - public EncodeException(char c) - { + public EncodeException(char c) { super("Unencodable char: '" + c + "'"); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java index 7baaecaa434e..b814088a3201 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java +++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; -import android.telephony.gsm.SmsMessage; +import android.telephony.SmsMessage; import android.util.SparseIntArray; import android.util.Log; @@ -28,16 +28,15 @@ import android.util.Log; * * {@hide} */ -public class GsmAlphabet -{ +public class GsmAlphabet { static final String LOG_TAG = "GSM"; - + //***** Constants /** - * This escapes extended characters, and when present indicates that the + * This escapes extended characters, and when present indicates that the * following character should * be looked up in the "extended" table * @@ -55,8 +54,7 @@ public class GsmAlphabet * should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string */ public static int - charToGsm(char c) - { + charToGsm(char c) { try { return charToGsm(c, false); } catch (EncodeException ex) { @@ -67,7 +65,7 @@ public class GsmAlphabet /** * char to GSM alphabet char - * @param throwException If true, throws EncodeException on invalid char. + * @param throwException If true, throws EncodeException on invalid char. * If false, returns GSM alphabet ' ' char. * * Returns GSM_EXTENDED_ESCAPE if this character is in the extended table @@ -76,10 +74,9 @@ public class GsmAlphabet */ public static int - charToGsm(char c, boolean throwException) throws EncodeException - { + charToGsm(char c, boolean throwException) throws EncodeException { int ret; - + ret = charToGsm.get(c, -1); if (ret == -1) { @@ -99,7 +96,7 @@ public class GsmAlphabet return ret; } - + /** * char to extended GSM alphabet char @@ -110,10 +107,9 @@ public class GsmAlphabet * */ public static int - charToGsmExtended(char c) - { + charToGsmExtended(char c) { int ret; - + ret = charToGsmExtended.get(c, -1); if (ret == -1) { @@ -124,34 +120,32 @@ public class GsmAlphabet } /** - * Converts a character in the GSM alphabet into a char + * Converts a character in the GSM alphabet into a char * * if GSM_EXTENDED_ESCAPE is passed, 0xffff is returned. In this case, - * the following character in the stream should be decoded with + * the following character in the stream should be decoded with * gsmExtendedToChar() * * If an unmappable value is passed (one greater than 127), ' ' is returned */ public static char - gsmToChar(int gsmChar) - { + gsmToChar(int gsmChar) { return (char)gsmToChar.get(gsmChar, ' '); } - + /** - * Converts a character in the extended GSM alphabet into a char + * Converts a character in the extended GSM alphabet into a char * * if GSM_EXTENDED_ESCAPE is passed, ' ' is returned since no second * extension page has yet been defined (see Note 1 in table 6.2.1.1 of * TS 23.038 v7.00) - * + * * If an unmappable value is passed , ' ' is returned */ public static char - gsmExtendedToChar(int gsmChar) - { + gsmExtendedToChar(int gsmChar) { int ret; ret = gsmExtendedToChar.get(gsmChar, -1); @@ -205,7 +199,7 @@ public class GsmAlphabet } /** - * Converts a String into a byte array containing + * Converts a String into a byte array containing * the 7-bit packed GSM Alphabet representation of the string. * * Unencodable chars are encoded as spaces @@ -224,7 +218,7 @@ public class GsmAlphabet } /** - * Converts a String into a byte array containing + * Converts a String into a byte array containing * the 7-bit packed GSM Alphabet representation of the string. * * Byte 0 in the returned byte array is the count of septets used @@ -238,7 +232,7 @@ public class GsmAlphabet * enforced maximum. * @param startingBitOffset the number of padding bits to put before * the start of the first septet at the begining of the array - * @param throwException If true, throws EncodeException on invalid char. + * @param throwException If true, throws EncodeException on invalid char. * If false, replaces unencodable char with GSM alphabet space char. * * @throws EncodeException if String is too large to encode @@ -294,27 +288,26 @@ public class GsmAlphabet * @param bitOffset the bit offset that the septet should be packed at * (septet index * 7) */ - private static void - packSmsChar(byte[] packedChars, int bitOffset, int value) - { + private static void + packSmsChar(byte[] packedChars, int bitOffset, int value) { int byteOffset = bitOffset / 8; int shift = bitOffset % 8; packedChars[++byteOffset] |= value << shift; if (shift > 1) { - packedChars[++byteOffset] = (byte)(value >> (8 - shift)); - } + packedChars[++byteOffset] = (byte)(value >> (8 - shift)); + } } /** - * Convert a GSM alphabet 7 bit packed string (SMS string) into a + * Convert a GSM alphabet 7 bit packed string (SMS string) into a * {@link java.lang.String}. * * See TS 23.038 6.1.2.1 for SMS Character Packing * * @param pdu the raw data from the pdu - * @param offset the byte offset of + * @param offset the byte offset of * @param lengthSeptets string length in septets, not bytes * @return String representation or null on decoding exception */ @@ -324,27 +317,26 @@ public class GsmAlphabet } /** - * Convert a GSM alphabet 7 bit packed string (SMS string) into a + * Convert a GSM alphabet 7 bit packed string (SMS string) into a * {@link java.lang.String}. * * See TS 23.038 6.1.2.1 for SMS Character Packing * * @param pdu the raw data from the pdu - * @param offset the byte offset of + * @param offset the byte offset of * @param lengthSeptets string length in septets, not bytes * @param numPaddingBits the number of padding bits before the start of the * string in the first byte * @return String representation or null on decoding exception */ public static String gsm7BitPackedToString(byte[] pdu, int offset, - int lengthSeptets, int numPaddingBits) - { + int lengthSeptets, int numPaddingBits) { StringBuilder ret = new StringBuilder(lengthSeptets); boolean prevCharWasEscape; - + try { prevCharWasEscape = false; - + for (int i = 0 ; i < lengthSeptets ; i++) { int bitOffset = (7 * i) + numPaddingBits; @@ -381,15 +373,14 @@ public class GsmAlphabet /** - * Convert a GSM alphabet string that's stored in 8-bit unpacked + * Convert a GSM alphabet string that's stored in 8-bit unpacked * format (as it often appears in SIM records) into a String * * Field may be padded with trailing 0xff's. The decode stops * at the first 0xff encountered. */ public static String - gsm8BitUnpackedToString(byte[] data, int offset, int length) - { + gsm8BitUnpackedToString(byte[] data, int offset, int length) { boolean prevWasEscape; StringBuilder ret = new StringBuilder(length); @@ -420,8 +411,8 @@ public class GsmAlphabet prevWasEscape = false; } } - - return ret.toString(); + + return ret.toString(); } /** @@ -429,8 +420,7 @@ public class GsmAlphabet * array */ public static byte[] - stringToGsm8BitPacked(String s) - { + stringToGsm8BitPacked(String s) { byte[] ret; int septets = 0; @@ -452,15 +442,14 @@ public class GsmAlphabet * * Field is padded with 0xff's, string is truncated if necessary */ - + public static void - stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) - { + stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) { int outByteIndex = offset; // Septets are stored in byte-aligned octets for (int i = 0, sz = s.length() - ; i < sz && (outByteIndex - offset) < length + ; i < sz && (outByteIndex - offset) < length ; i++ ) { char c = s.charAt(i); @@ -475,7 +464,7 @@ public class GsmAlphabet dest[outByteIndex++] = GSM_EXTENDED_ESCAPE; - v = GsmAlphabet.charToGsmExtended(c); + v = GsmAlphabet.charToGsmExtended(c); } dest[outByteIndex++] = (byte)v; @@ -492,8 +481,7 @@ public class GsmAlphabet * needed to represent this character. Counts unencodable char as 1 septet. */ public static int - countGsmSeptets(char c) - { + countGsmSeptets(char c) { try { return countGsmSeptets(c, true); } catch (EncodeException ex) { @@ -509,21 +497,20 @@ public class GsmAlphabet * char. Otherwise, counts invalid char as 1 septet */ public static int - countGsmSeptets(char c, boolean throwsException) throws EncodeException - { - if (charToGsm.get(c, -1) != -1) { - return 1; - } - - if (charToGsmExtended.get(c, -1) != -1) { - return 2; - } + countGsmSeptets(char c, boolean throwsException) throws EncodeException { + if (charToGsm.get(c, -1) != -1) { + return 1; + } + + if (charToGsmExtended.get(c, -1) != -1) { + return 2; + } if (throwsException) { throw new EncodeException(c); - } else { - // count as a space char - return 1; + } else { + // count as a space char + return 1; } } @@ -532,8 +519,7 @@ public class GsmAlphabet * needed to represent this string. Counts unencodable char as 1 septet. */ public static int - countGsmSeptets(String s) - { + countGsmSeptets(String s) { try { return countGsmSeptets(s, true); } catch (EncodeException ex) { @@ -549,8 +535,7 @@ public class GsmAlphabet * char. Otherwise, counts invalid char as 1 septet */ public static int - countGsmSeptets(String s, boolean throwsException) throws EncodeException - { + countGsmSeptets(String s, boolean throwsException) throws EncodeException { int charIndex = 0; int sz = s.length(); int count = 0; @@ -559,9 +544,9 @@ public class GsmAlphabet count += countGsmSeptets(s.charAt(charIndex), throwsException); charIndex++; } - + return count; - } + } /** * Returns the index into <code>s</code> of the first character @@ -623,7 +608,7 @@ public class GsmAlphabet * @return index of first character that won't fit, or the length * of the entire string if everything fits */ - public static int + public static int findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException { if (encodingType == SmsMessage.ENCODING_7BIT) { return findGsmSeptetLimitIndex(s, start, limit); @@ -643,10 +628,10 @@ public class GsmAlphabet private static final SparseIntArray gsmToChar = new SparseIntArray(); private static final SparseIntArray charToGsmExtended = new SparseIntArray(); private static final SparseIntArray gsmExtendedToChar = new SparseIntArray(); - + static { int i = 0; - + charToGsm.put('@', i++); charToGsm.put('\u00a3', i++); charToGsm.put('$', i++); @@ -663,7 +648,7 @@ public class GsmAlphabet charToGsm.put('\r', i++); charToGsm.put('\u00c5', i++); charToGsm.put('\u00e5', i++); - + charToGsm.put('\u0394', i++); charToGsm.put('_', i++); charToGsm.put('\u03a6', i++); @@ -680,7 +665,7 @@ public class GsmAlphabet charToGsm.put('\u00e6', i++); charToGsm.put('\u00df', i++); charToGsm.put('\u00c9', i++); - + charToGsm.put(' ', i++); charToGsm.put('!', i++); charToGsm.put('"', i++); @@ -697,7 +682,7 @@ public class GsmAlphabet charToGsm.put('-', i++); charToGsm.put('.', i++); charToGsm.put('/', i++); - + charToGsm.put('0', i++); charToGsm.put('1', i++); charToGsm.put('2', i++); @@ -714,7 +699,7 @@ public class GsmAlphabet charToGsm.put('=', i++); charToGsm.put('>', i++); charToGsm.put('?', i++); - + charToGsm.put('\u00a1', i++); charToGsm.put('A', i++); charToGsm.put('B', i++); @@ -731,7 +716,7 @@ public class GsmAlphabet charToGsm.put('M', i++); charToGsm.put('N', i++); charToGsm.put('O', i++); - + charToGsm.put('P', i++); charToGsm.put('Q', i++); charToGsm.put('R', i++); @@ -748,7 +733,7 @@ public class GsmAlphabet charToGsm.put('\u0147', i++); charToGsm.put('\u00dc', i++); charToGsm.put('\u00a7', i++); - + charToGsm.put('\u00bf', i++); charToGsm.put('a', i++); charToGsm.put('b', i++); @@ -765,7 +750,7 @@ public class GsmAlphabet charToGsm.put('m', i++); charToGsm.put('n', i++); charToGsm.put('o', i++); - + charToGsm.put('p', i++); charToGsm.put('q', i++); charToGsm.put('r', i++); @@ -782,8 +767,8 @@ public class GsmAlphabet charToGsm.put('\u00f1', i++); charToGsm.put('\u00fc', i++); charToGsm.put('\u00e0', i++); - - + + charToGsmExtended.put('\f', 10); charToGsmExtended.put('^', 20); charToGsmExtended.put('{', 40); @@ -794,12 +779,12 @@ public class GsmAlphabet charToGsmExtended.put(']', 62); charToGsmExtended.put('|', 64); charToGsmExtended.put('\u20ac', 101); - + int size = charToGsm.size(); for (int j=0; j<size; j++) { gsmToChar.put(charToGsm.valueAt(j), charToGsm.keyAt(j)); } - + size = charToGsmExtended.size(); for (int j=0; j<size; j++) { gsmExtendedToChar.put(charToGsmExtended.valueAt(j), charToGsmExtended.keyAt(j)); @@ -808,6 +793,6 @@ public class GsmAlphabet sGsmSpaceChar = charToGsm.get(' '); } - + } diff --git a/telephony/java/com/android/internal/telephony/gsm/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl index 904a54e2f03e..257f1e62b9a7 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -14,20 +14,20 @@ ** limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.app.PendingIntent; -import com.android.internal.telephony.gsm.SmsRawData; +import com.android.internal.telephony.SmsRawData; -/** Interface for applications to access the SIM phone book. +/** Interface for applications to access the ICC phone book. * * <p>The following code snippet demonstrates a static method to - * retrieve the ISimSms interface from Android:</p> - * <pre>private static ISimSms getSimSmsInterface() + * retrieve the ISms interface from Android:</p> + * <pre>private static ISms getSmsInterface() throws DeadObjectException { IServiceManager sm = ServiceManagerNative.getDefault(); - ISimSms ss; - ss = ISimSms.Stub.asInterface(sm.getService("isms")); + ISms ss; + ss = ISms.Stub.asInterface(sm.getService("isms")); return ss; } * </pre> @@ -35,45 +35,45 @@ import com.android.internal.telephony.gsm.SmsRawData; interface ISms { /** - * Retrieves all messages currently stored on SIM. + * Retrieves all messages currently stored on ICC. * - * @return list of SmsRawData of all sms on SIM + * @return list of SmsRawData of all sms on ICC */ - List<SmsRawData> getAllMessagesFromSimEf(); + List<SmsRawData> getAllMessagesFromIccEf(); /** - * Update the specified message on the SIM. + * Update the specified message on the ICC. * * @param messageIndex record index of message to update - * @param newStatus new message status (STATUS_ON_SIM_READ, - * STATUS_ON_SIM_UNREAD, STATUS_ON_SIM_SENT, - * STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE) + * @param newStatus new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) * @param pdu the raw PDU to store * @return success or not * */ - boolean updateMessageOnSimEf(int messageIndex, int newStatus, + boolean updateMessageOnIccEf(int messageIndex, int newStatus, in byte[] pdu); /** - * Copy a raw SMS PDU to the SIM. + * Copy a raw SMS PDU to the ICC. * * @param pdu the raw PDU to store - * @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD, - * STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT) + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) * @return success or not * */ - boolean copyMessageToSimEf(int status, in byte[] pdu, in byte[] smsc); + boolean copyMessageToIccEf(int status, in byte[] pdu, in byte[] smsc); /** * Send a SMS * * @param smsc the SMSC to send the message through, or NULL for the - * defatult SMSC + * default SMSC * @param pdu the raw PDU to send * @param sentIntent if not NULL this <code>Intent</code> is - * broadcast when the message is sucessfully sent, or failed. + * broadcast when the message is successfully sent, or failed. * The result code will be <code>Activity.RESULT_OK<code> for success, * or one of these errors: * <code>RESULT_ERROR_GENERIC_FAILURE</code> @@ -88,13 +88,13 @@ interface ISms { /** * Send a multi-part text based SMS. - * + * * @param destinationAddress the address to send the message to * @param scAddress is the service center address or null to use * the current default SMSC * @param parts an <code>ArrayList</code> of strings that, in order, * comprise the original message - * @param sentIntents if not null, an <code>ArrayList</code> of + * @param sentIntents if not null, an <code>ArrayList</code> of * <code>PendingIntent</code>s (one for each message part) that is * broadcast when the corresponding message part has been sent. * The result code will be <code>Activity.RESULT_OK<code> for success, @@ -102,7 +102,7 @@ interface ISms { * <code>RESULT_ERROR_GENERIC_FAILURE</code> * <code>RESULT_ERROR_RADIO_OFF</code> * <code>RESULT_ERROR_NULL_PDU</code>. - * @param deliveryIntents if not null, an <code>ArrayList</code> of + * @param deliveryIntents if not null, an <code>ArrayList</code> of * <code>PendingIntent</code>s (one for each message part) that is * broadcast when the corresponding message part has been delivered * to the recipient. The raw pdu of the status report is in the diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 663fc0380430..83fb8bfc1d5c 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -19,7 +19,7 @@ package com.android.internal.telephony; import android.os.Bundle; /** - * Interface used to interact with the phone. Mostly this is used by the + * Interface used to interact with the phone. Mostly this is used by the * TelephonyManager class. A few places are still using this directly. * Please clean them up if possible and use TelephonyManager insteadl. * @@ -46,7 +46,7 @@ interface ITelephony { * Returns true if the call screen was shown. */ boolean showCallScreen(); - + /** * End call or go to the Home screen * @@ -87,7 +87,7 @@ interface ITelephony { /** * Cancels the missed calls notification. */ - void cancelMissedCallsNotification(); + void cancelMissedCallsNotification(); /** * Supply a pin to unlock the SIM. Blocks until a result is determined. @@ -99,7 +99,7 @@ interface ITelephony { /** * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated * without SEND (so <code>dial</code> is not appropriate). - * + * * @param dialString the MMI command to be executed. * @return true if MMI command is executed. */ @@ -160,4 +160,12 @@ interface ITelephony { int getCallState(); int getDataActivity(); int getDataState(); + + /** + * Returns the current active phone type as integer. + * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE + * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE + */ + int getActivePhoneType(); + } diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java index 614463e6eb29..d7ad492bdd4a 100644 --- a/telephony/java/com/android/internal/telephony/IccCard.java +++ b/telephony/java/com/android/internal/telephony/IccCard.java @@ -23,7 +23,6 @@ import android.os.Handler; * {@hide} */ public interface IccCard { - // TODO: check intent filters in apps /* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */ static public final String INTENT_KEY_ICC_STATE = "ss"; /* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */ @@ -73,7 +72,7 @@ public interface IccCard { * Notifies handler of any transition into State.ABSENT */ void registerForAbsent(Handler h, int what, Object obj); - void unregisterForAbsent(Handler h); + void unregisterForAbsent(Handler h); /** * Notifies handler of any transition into State.isPinLocked() @@ -100,11 +99,11 @@ public interface IccCard { * * If the supplied PIN is incorrect: * ((AsyncResult)onComplete.obj).exception != null - * && ((AsyncResult)onComplete.obj).exception + * && ((AsyncResult)onComplete.obj).exception * instanceof com.android.internal.telephony.gsm.CommandException) * && ((CommandException)(((AsyncResult)onComplete.obj).exception)) * .getCommandError() == CommandException.Error.PASSWORD_INCORRECT - * + * * */ diff --git a/telephony/java/com/android/internal/telephony/IccCardApplication.java b/telephony/java/com/android/internal/telephony/IccCardApplication.java index de7480c51582..9f60a6cffec8 100644 --- a/telephony/java/com/android/internal/telephony/IccCardApplication.java +++ b/telephony/java/com/android/internal/telephony/IccCardApplication.java @@ -29,7 +29,7 @@ public class IccCardApplication { APPTYPE_USIM, APPTYPE_RUIM, APPTYPE_CSIM - }; + }; public enum AppState{ APPSTATE_UNKNOWN, @@ -38,15 +38,15 @@ public class IccCardApplication { APPSTATE_PUK, APPSTATE_SUBSCRIPTION_PERSO, APPSTATE_READY; - + boolean isPinRequired() { return this == APPSTATE_PIN; } - + boolean isPukRequired() { return this == APPSTATE_PUK; } - + boolean isSubscriptionPersoEnabled() { return this == APPSTATE_SUBSCRIPTION_PERSO; } @@ -54,14 +54,14 @@ public class IccCardApplication { boolean isAppReady() { return this == APPSTATE_READY; } - + boolean isAppNotReady() { return this == APPSTATE_UNKNOWN || - this == APPSTATE_DETECTED; + this == APPSTATE_DETECTED; } }; - public enum PersoSubState{ + public enum PersoSubState{ PERSOSUBSTATE_UNKNOWN, PERSOSUBSTATE_IN_PROGRESS, PERSOSUBSTATE_READY, @@ -87,25 +87,25 @@ public class IccCardApplication { PERSOSUBSTATE_RUIM_CORPORATE_PUK, PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK, PERSOSUBSTATE_RUIM_RUIM_PUK; - + boolean isPersoSubStateUnknown() { return this == PERSOSUBSTATE_UNKNOWN; - } + } }; - - public AppType app_type; - public AppState app_state; + + public AppType app_type; + public AppState app_state; // applicable only if app_state == RIL_APPSTATE_SUBSCRIPTION_PERSO public PersoSubState perso_substate; - // null terminated string, e.g., from 0xA0, 0x00 -> 0x41, 0x30, 0x30, 0x30 */ + // null terminated string, e.g., from 0xA0, 0x00 -> 0x41, 0x30, 0x30, 0x30 */ public String aid; // null terminated string public String app_label; // applicable to USIM and CSIM public int pin1_replaced; - public int pin1; - public int pin2; - + public int pin1; + public int pin2; + AppType AppTypeFromRILInt(int type) { AppType newType; /* RIL_AppType ril.h */ @@ -115,13 +115,13 @@ public class IccCardApplication { case 2: newType = AppType.APPTYPE_USIM; break; case 3: newType = AppType.APPTYPE_RUIM; break; case 4: newType = AppType.APPTYPE_CSIM; break; - default: + default: throw new RuntimeException( "Unrecognized RIL_AppType: " +type); - } + } return newType; } - + AppState AppStateFromRILInt(int state) { AppState newState; /* RIL_AppState ril.h */ @@ -132,10 +132,10 @@ public class IccCardApplication { case 3: newState = AppState.APPSTATE_PUK; break; case 4: newState = AppState.APPSTATE_SUBSCRIPTION_PERSO; break; case 5: newState = AppState.APPSTATE_READY; break; - default: + default: throw new RuntimeException( "Unrecognized RIL_AppState: " +state); - } + } return newState; } @@ -160,7 +160,7 @@ public class IccCardApplication { case 14: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK2; break; case 15: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_HRPD; break; case 16: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_CORPORATE; break; - case 17: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER; break; + case 17: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER; break; case 18: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_RUIM; break; case 19: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK1_PUK; break; case 20: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK2_PUK; break; @@ -168,11 +168,11 @@ public class IccCardApplication { case 22: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_CORPORATE_PUK; break; case 23: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK; break; case 24: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_RUIM_PUK; break; - default: + default: throw new RuntimeException( "Unrecognized RIL_PersoSubstate: " +substate); - } + } return newSubState; } - + } diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java index 1ecf59fdb7b9..b602b1c68cc2 100644 --- a/telephony/java/com/android/internal/telephony/IccCardStatus.java +++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java @@ -30,7 +30,7 @@ public class IccCardStatus { CARDSTATE_ABSENT, CARDSTATE_PRESENT, CARDSTATE_ERROR; - + boolean isCardPresent() { return this == CARDSTATE_PRESENT; } @@ -44,13 +44,13 @@ public class IccCardStatus { PINSTATE_ENABLED_BLOCKED, PINSTATE_ENABLED_PERM_BLOCKED }; - - public CardState card_state; - public PinState universal_pin_state; - public int gsm_umts_subscription_app_index; - public int cdma_subscription_app_index; + + public CardState card_state; + public PinState universal_pin_state; + public int gsm_umts_subscription_app_index; + public int cdma_subscription_app_index; public int num_applications; - + ArrayList<IccCardApplication> application = new ArrayList<IccCardApplication>(CARD_MAX_APPS); CardState CardStateFromRILInt(int state) { @@ -60,10 +60,10 @@ public class IccCardStatus { case 0: newState = CardState.CARDSTATE_ABSENT; break; case 1: newState = CardState.CARDSTATE_PRESENT; break; case 2: newState = CardState.CARDSTATE_ERROR; break; - default: + default: throw new RuntimeException( "Unrecognized RIL_CardState: " +state); - } + } return newState; } @@ -77,10 +77,10 @@ public class IccCardStatus { case 3: newState = PinState.PINSTATE_DISABLED; break; case 4: newState = PinState.PINSTATE_ENABLED_BLOCKED; break; case 5: newState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; break; - default: + default: throw new RuntimeException( "Unrecognized RIL_PinState: " +state); - } + } return newState; } } diff --git a/telephony/java/com/android/internal/telephony/IccConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java index adf4e1e9c2b5..59ce5bbafeba 100644 --- a/telephony/java/com/android/internal/telephony/IccConstants.java +++ b/telephony/java/com/android/internal/telephony/IccConstants.java @@ -51,9 +51,9 @@ public interface IccConstants { public static final int EF_INFO_CPHS = 0x6f16; // CDMA RUIM file ids from 3GPP2 C.S0023-0 - // TODO: add necessary RUIM file ids here - public static final int EF_CST = 0x6f32; - + public static final int EF_CST = 0x6f32; + public static final int EF_RUIM_SPN =0x6F41; + // SMS record length from TS 51.011 10.5.3 static public final int SMS_RECORD_LENGTH = 176; } diff --git a/telephony/java/com/android/internal/telephony/IccFileHandler.java b/telephony/java/com/android/internal/telephony/IccFileHandler.java index e23b9265542a..e751c5eb1bc8 100644 --- a/telephony/java/com/android/internal/telephony/IccFileHandler.java +++ b/telephony/java/com/android/internal/telephony/IccFileHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2008 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. @@ -16,7 +16,6 @@ package com.android.internal.telephony; -//import com.android.internal.telephony.*; import android.os.*; import android.util.Log; import java.util.ArrayList; @@ -25,7 +24,7 @@ import java.util.ArrayList; * {@hide} */ public abstract class IccFileHandler extends Handler { - + //from TS 11.11 9.1 or elsewhere static protected final int COMMAND_READ_BINARY = 0xb0; static protected final int COMMAND_UPDATE_BINARY = 0xd6; @@ -72,7 +71,7 @@ public abstract class IccFileHandler extends Handler { static protected final int RESPONSE_DATA_STRUCTURE = 13; static protected final int RESPONSE_DATA_RECORD_LENGTH = 14; - + //***** Events /** Finished retrieving size of transparent EF; start loading. */ @@ -90,24 +89,425 @@ public abstract class IccFileHandler extends Handler { /** Finished retrieving icon data; post result. */ static protected final int EVENT_READ_ICON_DONE = 10; - + // member variables + protected PhoneBase phone; + + static class LoadLinearFixedContext { + + int efid; + int recordNum, recordSize, countRecords; + boolean loadAll; + + Message onLoaded; + + ArrayList<byte[]> results; + + LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) { + this.efid = efid; + this.recordNum = recordNum; + this.onLoaded = onLoaded; + this.loadAll = false; + } + + LoadLinearFixedContext(int efid, Message onLoaded) { + this.efid = efid; + this.recordNum = 1; + this.loadAll = true; + this.onLoaded = onLoaded; + } + } + + /** + * Default constructor + */ + protected IccFileHandler(PhoneBase phone) { + super(); + this.phone = phone; + } + + public void dispose() { + } + + //***** Public Methods + + /** + * Load a record from a SIM Linear Fixed EF + * + * @param fileid EF id + * @param recordNum 1-based (not 0-based) record number + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) { + Message response + = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, + new LoadLinearFixedContext(fileid, recordNum, onLoaded)); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load a image instance record from a SIM Linear Fixed EF-IMG + * + * @param recordNum 1-based (not 0-based) record number + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + public void loadEFImgLinearFixed(int recordNum, Message onLoaded) { + Message response = obtainMessage(EVENT_READ_IMG_DONE, + new LoadLinearFixedContext(IccConstants.EF_IMG, recordNum, + onLoaded)); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img", + recordNum, READ_RECORD_MODE_ABSOLUTE, + GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response); + } + + /** + * get record size for a linear fixed EF + * + * @param fileid EF id + * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[] + * int[0] is the record length int[1] is the total length of the EF + * file int[3] is the number of records in the EF file So int[0] * + * int[3] = int[1] + */ + public void getEFLinearRecordSize(int fileid, Message onLoaded) { + Message response + = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE, + new LoadLinearFixedContext(fileid, onLoaded)); + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load all records from a SIM Linear Fixed EF + * + * @param fileid EF id + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is an ArrayList<byte[]> + * + */ + public void loadEFLinearFixedAll(int fileid, Message onLoaded) { + Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, + new LoadLinearFixedContext(fileid,onLoaded)); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load a SIM Transparent EF + * + * @param fileid EF id + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + + public void loadEFTransparent(int fileid, Message onLoaded) { + Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE, + fileid, 0, onLoaded); + + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, + 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + } + + /** + * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to + * retrive STK's icon data. + * + * @param fileid EF id + * @param onLoaded + * + * ((AsyncResult)(onLoaded.obj)).result is the byte[] + * + */ + public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, + int length, Message onLoaded) { + Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0, + onLoaded); + + phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset, + length, null, null, response); + } + + /** + * Update a record in a linear fixed EF + * @param fileid EF id + * @param recordNum 1-based (not 0-based) record number + * @param data must be exactly as long as the record in the EF + * @param pin2 for CHV2 operations, otherwist must be null + * @param onComplete onComplete.obj will be an AsyncResult + * onComplete.obj.userObj will be a IccIoResult on success + */ + public void updateEFLinearFixed(int fileid, int recordNum, byte[] data, + String pin2, Message onComplete) { + phone.mCM.iccIO(COMMAND_UPDATE_RECORD, fileid, null, + recordNum, READ_RECORD_MODE_ABSOLUTE, data.length, + IccUtils.bytesToHexString(data), pin2, onComplete); + } + + /** + * Update a transparent EF + * @param fileid EF id + * @param data must be exactly as long as the EF + */ + public void updateEFTransparent(int fileid, byte[] data, Message onComplete) { + phone.mCM.iccIO(COMMAND_UPDATE_BINARY, fileid, null, + 0, 0, data.length, + IccUtils.bytesToHexString(data), null, onComplete); + } + + //***** Abstract Methods - - protected abstract void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded); - - protected abstract void loadEFImgLinearFixed(int recordNum, Message onLoaded); - - protected abstract void getEFLinearRecordSize(int fileid, Message onLoaded); - - protected abstract void loadEFLinearFixedAll(int fileid, Message onLoaded); - - protected abstract void loadEFTransparent(int fileid, Message onLoaded); - - protected abstract void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, - int length, Message onLoaded); - - protected abstract void updateEFLinearFixed(int fileid, int recordNum, byte[] data, - String pin2, Message onComplete); - - protected abstract void updateEFTransparent(int fileid, byte[] data, Message onComplete); + + + //***** Private Methods + + private void sendResult(Message response, Object result, Throwable ex) { + if (response == null) { + return; + } + + AsyncResult.forMessage(response, result, ex); + + response.sendToTarget(); + } + + //***** Overridden from Handler + + public void handleMessage(Message msg) { + AsyncResult ar; + IccIoResult result; + Message response = null; + String str; + LoadLinearFixedContext lc; + + IccException iccException; + byte data[]; + int size; + int fileid; + int recordNum; + int recordSize[]; + + try { + switch (msg.what) { + case EVENT_READ_IMG_DONE: + ar = (AsyncResult) msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + iccException = result.getException(); + if (iccException != null) { + sendResult(response, result.payload, ar.exception); + } + break; + case EVENT_READ_ICON_DONE: + ar = (AsyncResult) msg.obj; + response = (Message) ar.userObj; + result = (IccIoResult) ar.result; + + iccException = result.getException(); + if (iccException != null) { + sendResult(response, result.payload, ar.exception); + } + break; + case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE: + ar = (AsyncResult)msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + data = result.payload; + + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] || + EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + recordSize = new int[3]; + recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; + recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + recordSize[2] = recordSize[1] / recordSize[0]; + + sendResult(response, recordSize, null); + break; + case EVENT_GET_RECORD_SIZE_DONE: + ar = (AsyncResult)msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + data = result.payload; + fileid = lc.efid; + recordNum = lc.recordNum; + + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { + throw new IccFileTypeMismatch(); + } + + if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + lc.recordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; + + size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + + lc.countRecords = size / lc.recordSize; + + if (lc.loadAll) { + lc.results = new ArrayList<byte[]>(lc.countRecords); + } + + phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null, + lc.recordNum, + READ_RECORD_MODE_ABSOLUTE, + lc.recordSize, null, null, + obtainMessage(EVENT_READ_RECORD_DONE, lc)); + break; + case EVENT_GET_BINARY_SIZE_DONE: + ar = (AsyncResult)msg.obj; + response = (Message) ar.userObj; + result = (IccIoResult) ar.result; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + data = result.payload; + + fileid = msg.arg1; + + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { + throw new IccFileTypeMismatch(); + } + + if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) { + throw new IccFileTypeMismatch(); + } + + size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) + + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); + + phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, null, + 0, 0, size, null, null, + obtainMessage(EVENT_READ_BINARY_DONE, + fileid, 0, response)); + break; + + case EVENT_READ_RECORD_DONE: + + ar = (AsyncResult)msg.obj; + lc = (LoadLinearFixedContext) ar.userObj; + result = (IccIoResult) ar.result; + response = lc.onLoaded; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + if (!lc.loadAll) { + sendResult(response, result.payload, null); + } else { + lc.results.add(result.payload); + + lc.recordNum++; + + if (lc.recordNum > lc.countRecords) { + sendResult(response, lc.results, null); + } else { + phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null, + lc.recordNum, + READ_RECORD_MODE_ABSOLUTE, + lc.recordSize, null, null, + obtainMessage(EVENT_READ_RECORD_DONE, lc)); + } + } + + break; + + case EVENT_READ_BINARY_DONE: + ar = (AsyncResult)msg.obj; + response = (Message) ar.userObj; + result = (IccIoResult) ar.result; + + if (ar.exception != null) { + sendResult(response, null, ar.exception); + break; + } + + iccException = result.getException(); + + if (iccException != null) { + sendResult(response, null, iccException); + break; + } + + sendResult(response, result.payload, null); + break; + + }} catch (Exception exc) { + if (response != null) { + sendResult(response, null, exc); + } else { + loge("uncaught exception" + exc); + } + } + } + + protected abstract void logd(String s); + + protected abstract void loge(String s); + } diff --git a/telephony/java/com/android/internal/telephony/IccIoResult.java b/telephony/java/com/android/internal/telephony/IccIoResult.java index c57cc78fea13..a6e0ec365bb3 100644 --- a/telephony/java/com/android/internal/telephony/IccIoResult.java +++ b/telephony/java/com/android/internal/telephony/IccIoResult.java @@ -33,13 +33,11 @@ IccIoResult { } public IccIoResult(int sw1, int sw2, String hexString) { - //TODO T: IccUtils is linked to IccUtils which is stored in telephony package - //Maybe in a later version all function calls of IccUtils will be renamed to IccUtils. this(sw1, sw2, IccUtils.hexStringToBytes(hexString)); } public String toString() { - return "IccIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x" + return "IccIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x" + Integer.toHexString(sw2); } @@ -57,7 +55,7 @@ IccIoResult { */ public IccException getException() { if (success()) return null; - + switch (sw1) { case 0x94: if (sw2 == 0x08) { diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java index 4554aed1e741..0bcaaa684d9b 100644 --- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java @@ -33,4 +33,234 @@ import java.util.List; * access ADN-like SIM records. */ public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub { + protected static final boolean DBG = true; + + protected PhoneBase phone; + protected AdnRecordCache adnCache; + protected Object mLock = new Object(); + protected int recordSize[]; + protected boolean success; + protected List<AdnRecord> records; + + protected static final boolean ALLOW_SIM_OP_IN_UI_THREAD = false; + + protected static final int EVENT_GET_SIZE_DONE = 1; + protected static final int EVENT_LOAD_DONE = 2; + protected static final int EVENT_UPDATE_DONE = 3; + + protected Handler mBaseHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_GET_SIZE_DONE: + ar = (AsyncResult) msg.obj; + synchronized (mLock) { + if (ar.exception == null) { + recordSize = (int[])ar.result; + // recordSize[0] is the record length + // recordSize[1] is the total length of the EF file + // recordSize[2] is the number of records in the EF file + logd("GET_RECORD_SIZE Size " + recordSize[0] + + " total " + recordSize[1] + + " #record " + recordSize[2]); + mLock.notifyAll(); + } + } + break; + case EVENT_UPDATE_DONE: + ar = (AsyncResult) msg.obj; + synchronized (mLock) { + success = (ar.exception == null); + mLock.notifyAll(); + } + break; + case EVENT_LOAD_DONE: + ar = (AsyncResult)msg.obj; + synchronized (mLock) { + if (ar.exception == null) { + records = (List<AdnRecord>) + ((ArrayList<AdnRecord>) ar.result); + } else { + if(DBG) logd("Cannot load ADN records"); + if (records != null) { + records.clear(); + } + } + mLock.notifyAll(); + } + break; + } + } + }; + + public IccPhoneBookInterfaceManager(PhoneBase phone) { + this.phone = phone; + } + + public void dispose() { + } + + protected void publish() { + //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy + ServiceManager.addService("simphonebook", this); + } + + protected abstract void logd(String msg); + + protected abstract void loge(String msg); + + /** + * Replace oldAdn with newAdn in ADN-like record in EF + * + * getAdnRecordsInEf must be called at least once before this function, + * otherwise an error will be returned + * throws SecurityException if no WRITE_CONTACTS permission + * + * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN + * @param oldTag adn tag to be replaced + * @param oldPhoneNumber adn number to be replaced + * Set both oldTag and oldPhoneNubmer to "" means to replace an + * empty record, aka, insert new record + * @param newTag adn tag to be stored + * @param newPhoneNumber adn number ot be stored + * Set both newTag and newPhoneNubmer to "" means to replace the old + * record with empty one, aka, delete old record + * @param pin2 required to update EF_FDN, otherwise must be null + * @return true for success + */ + public boolean + updateAdnRecordsInEfBySearch (int efid, + String oldTag, String oldPhoneNumber, + String newTag, String newPhoneNumber, String pin2) { + + + if (phone.getContext().checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_CONTACTS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires android.permission.WRITE_CONTACTS permission"); + } + + + if (DBG) logd("updateAdnRecordsInEfBySearch: efid=" + efid + + " ("+ oldTag + "," + oldPhoneNumber + ")"+ "==>" + + " ("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); + synchronized(mLock) { + checkThread(); + success = false; + Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE); + AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber); + AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); + adnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to update by search"); + } + } + return success; + } + + /** + * Update an ADN-like EF record by record index + * + * This is useful for iteration the whole ADN file, such as write the whole + * phone book or erase/format the whole phonebook + * throws SecurityException if no WRITE_CONTACTS permission + * + * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN + * @param newTag adn tag to be stored + * @param newPhoneNumber adn number to be stored + * Set both newTag and newPhoneNubmer to "" means to replace the old + * record with empty one, aka, delete old record + * @param index is 1-based adn record index to be updated + * @param pin2 required to update EF_FDN, otherwise must be null + * @return true for success + */ + public boolean + updateAdnRecordsInEfByIndex(int efid, String newTag, + String newPhoneNumber, int index, String pin2) { + + if (phone.getContext().checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_CONTACTS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires android.permission.WRITE_CONTACTS permission"); + } + + if (DBG) logd("updateAdnRecordsInEfByIndex: efid=" + efid + + " Index=" + index + " ==> " + + "("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); + synchronized(mLock) { + checkThread(); + success = false; + Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE); + AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); + adnCache.updateAdnByIndex(efid, newAdn, index, pin2, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to update by index"); + } + } + return success; + } + + /** + * Get the capacity of records in efid + * + * @param efid the EF id of a ADN-like ICC + * @return int[3] array + * recordSizes[0] is the single record length + * recordSizes[1] is the total length of the EF file + * recordSizes[2] is the number of records in the EF file + */ + public abstract int[] getAdnRecordsSize(int efid); + + /** + * Loads the AdnRecords in efid and returns them as a + * List of AdnRecords + * + * throws SecurityException if no READ_CONTACTS permission + * + * @param efid the EF id of a ADN-like ICC + * @return List of AdnRecord + */ + public List<AdnRecord> getAdnRecordsInEf(int efid) { + + if (phone.getContext().checkCallingOrSelfPermission( + android.Manifest.permission.READ_CONTACTS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires android.permission.READ_CONTACTS permission"); + } + + if (DBG) logd("getAdnRecordsInEF: efid=" + efid); + + synchronized(mLock) { + checkThread(); + Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE); + adnCache.requestLoadAllAdnLike(efid, response); + try { + mLock.wait(); + } catch (InterruptedException e) { + logd("interrupted while trying to load from the SIM"); + } + } + return records; + } + + protected void checkThread() { + if (!ALLOW_SIM_OP_IN_UI_THREAD) { + // Make sure this isn't the UI thread, since it will block + if (mBaseHandler.getLooper().equals(Looper.myLooper())) { + loge("query() called on the main UI thread!"); + throw new IllegalStateException( + "You cannot call query on this provder from the main UI thread."); + } + } + } } + diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java index 959e6a33e0fc..1c0fc52e78eb 100644 --- a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java +++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2008 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. @@ -28,8 +28,6 @@ import android.util.Log; import java.util.ArrayList; import java.util.List; -//TODO T: remove if AdnRecord is moved to telephony package -//import com.android.internal.telephony.gsm.*; /** * SimPhoneBookInterfaceManager to provide an inter-process communication to @@ -38,14 +36,20 @@ import java.util.List; public class IccPhoneBookInterfaceManagerProxy extends IIccPhoneBook.Stub { private IccPhoneBookInterfaceManager mIccPhoneBookInterfaceManager; - public IccPhoneBookInterfaceManagerProxy(IccPhoneBookInterfaceManager + public IccPhoneBookInterfaceManagerProxy(IccPhoneBookInterfaceManager iccPhoneBookInterfaceManager) { mIccPhoneBookInterfaceManager = iccPhoneBookInterfaceManager; - ServiceManager.addService("simphonebook", this);; + if(ServiceManager.getService("simphonebook") == null) { + ServiceManager.addService("simphonebook", this); + } + } + + public void setmIccPhoneBookInterfaceManager( + IccPhoneBookInterfaceManager iccPhoneBookInterfaceManager) { + this.mIccPhoneBookInterfaceManager = iccPhoneBookInterfaceManager; } public boolean - //TODO Investigate updateAdnRecordsInEfBySearch (int efid, String oldTag, String oldPhoneNumber, String newTag, String newPhoneNumber, @@ -55,19 +59,16 @@ public class IccPhoneBookInterfaceManagerProxy extends IIccPhoneBook.Stub { } public boolean - //TODO Investigate updateAdnRecordsInEfByIndex(int efid, String newTag, String newPhoneNumber, int index, String pin2) throws android.os.RemoteException { - return mIccPhoneBookInterfaceManager.updateAdnRecordsInEfByIndex(efid, + return mIccPhoneBookInterfaceManager.updateAdnRecordsInEfByIndex(efid, newTag, newPhoneNumber, index, pin2); } - //TODO Investigate public int[] getAdnRecordsSize(int efid) throws android.os.RemoteException { return mIccPhoneBookInterfaceManager.getAdnRecordsSize(efid); } - //TODO Investigate public List<AdnRecord> getAdnRecordsInEf(int efid) throws android.os.RemoteException { return mIccPhoneBookInterfaceManager.getAdnRecordsInEf(efid); } diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java index fa1ed8b04d59..4cbd779722d4 100644 --- a/telephony/java/com/android/internal/telephony/IccProvider.java +++ b/telephony/java/com/android/internal/telephony/IccProvider.java @@ -42,7 +42,7 @@ import com.android.internal.telephony.IIccPhoneBook; public class IccProvider extends ContentProvider { private static final String TAG = "IccProvider"; private static final boolean DBG = false; - + private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] { "name", @@ -60,7 +60,6 @@ public class IccProvider extends ContentProvider { private static final UriMatcher URL_MATCHER = new UriMatcher(UriMatcher.NO_MATCH); - // TODO T: consider change from "sim" to "icc", also at other locations static { URL_MATCHER.addURI("icc", "adn", ADN); URL_MATCHER.addURI("icc", "fdn", FDN); @@ -87,21 +86,21 @@ public class IccProvider extends ContentProvider { public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sort) { ArrayList<ArrayList> results; - + if (!mSimulator) { switch (URL_MATCHER.match(url)) { case ADN: results = loadFromEf(IccConstants.EF_ADN); break; - + case FDN: results = loadFromEf(IccConstants.EF_FDN); break; - + case SDN: results = loadFromEf(IccConstants.EF_SDN); break; - + default: throw new IllegalArgumentException("Unknown URL " + url); } @@ -140,8 +139,6 @@ public class IccProvider extends ContentProvider { case ADN: case FDN: case SDN: - // TODO T: Do we have to change this "link" - // as well to "icc-contact"? return "vnd.android.cursor.dir/sim-contact"; default: @@ -191,7 +188,7 @@ public class IccProvider extends ContentProvider { buf.append("fdn/"); break; } - + // TODO: we need to find out the rowId for the newly added record buf.append(0); @@ -331,9 +328,6 @@ public class IccProvider extends ContentProvider { try { IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( - // TODO T: Do we have to change the service - // as well to "iccphonebook"? - // defined in: device/commands/binder/Service_info.c ServiceManager.getService("simphonebook")); if (iccIpb != null) { adnRecords = iccIpb.getAdnRecordsInEf(efType); @@ -374,9 +368,6 @@ public class IccProvider extends ContentProvider { try { IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( - // TODO T: Do we have to change the service - // as well to "iccphonebook"? - // defined in: device/commands/binder/Service_info.c ServiceManager.getService("simphonebook")); if (iccIpb != null) { success = iccIpb.updateAdnRecordsInEfBySearch(efType, "", "", @@ -401,9 +392,6 @@ public class IccProvider extends ContentProvider { try { IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( - // TODO T: Do we have to change the service - // as well to "iccphonebook"? - // defined in: device/commands/binder/Service_info.c ServiceManager.getService("simphonebook")); if (iccIpb != null) { success = iccIpb.updateAdnRecordsInEfBySearch(efType, @@ -419,9 +407,7 @@ public class IccProvider extends ContentProvider { } - private boolean deleteIccRecordFromEf(int efType, - String name, String number, - String pin2) { + private boolean deleteIccRecordFromEf(int efType, String name, String number, String pin2) { if (DBG) log("deleteIccRecordFromEf: efType=" + efType + ", name=" + name + ", number=" + number + ", pin2=" + pin2); @@ -429,13 +415,10 @@ public class IccProvider extends ContentProvider { try { IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface( - // TODO T: Do we have to change the service - // as well to "iccphonebook"? - // defined in: device/commands/binder/Service_info.c ServiceManager.getService("simphonebook")); if (iccIpb != null) { success = iccIpb.updateAdnRecordsInEfBySearch(efType, - name, number, "", "", pin2); + name, number, "", "", pin2); } } catch (RemoteException ex) { // ignore it diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java index 6849fad9d908..114094b74181 100644 --- a/telephony/java/com/android/internal/telephony/IccRecords.java +++ b/telephony/java/com/android/internal/telephony/IccRecords.java @@ -16,10 +16,6 @@ package com.android.internal.telephony; - - -import java.util.ArrayList; - import android.os.AsyncResult; import android.os.Handler; import android.os.Message; @@ -27,125 +23,66 @@ import android.os.Registrant; import android.os.RegistrantList; import android.util.Log; -import static com.android.internal.telephony.TelephonyProperties.*; - -// TODO: move abstract parts to here +import java.util.ArrayList; /** * {@hide} */ public abstract class IccRecords extends Handler implements IccConstants { - static String LOG_TAG = "IccRecords"; - - protected static final boolean DBG = true; + + protected static final boolean DBG = true; //***** Instance Variables - PhoneBase phone; - RegistrantList recordsLoadedRegistrants = new RegistrantList(); + protected PhoneBase phone; + protected RegistrantList recordsLoadedRegistrants = new RegistrantList(); - int recordsToLoad; // number of pending load requests + protected int recordsToLoad; // number of pending load requests - AdnRecordCache adnCache; + protected AdnRecordCache adnCache; //***** Cached SIM State; cleared on channel close - boolean recordsRequested = false; // true if we've made requests for the sim records - - String imsi; - String iccid; - String msisdn = null; // My mobile number - String msisdnTag = null; - String voiceMailNum = null; - String voiceMailTag = null; - String newVoiceMailNum = null; - String newVoiceMailTag = null; - boolean isVoiceMailFixed = false; - int countVoiceMessages = 0; - boolean callForwardingEnabled; - int mncLength = 0; // 0 is used to indicate that the value - // is not initialized - int mailboxIndex = 0; // 0 is no mailbox dailing number associated - - - byte[] efMWIS = null; - byte[] efCPHS_MWI =null; - byte[] mEfCff = null; - byte[] mEfCfis = null; + protected boolean recordsRequested = false; // true if we've made requests for the sim records + public String iccid; + protected String msisdn = null; // My mobile number + protected String msisdnTag = null; + protected String voiceMailNum = null; + protected String voiceMailTag = null; + protected String newVoiceMailNum = null; + protected String newVoiceMailTag = null; + protected boolean isVoiceMailFixed = false; + protected int countVoiceMessages = 0; - String spn; - int spnDisplayCondition; - // Numeric network codes listed in TS 51.011 EF[SPDI] - ArrayList<String> spdiNetworks = null; + protected int mncLength = 0; // 0 is used to indicate that the value + // is not initialized + protected int mailboxIndex = 0; // 0 is no mailbox dailing number associated - String pnnHomeName = null; + protected String spn; + protected int spnDisplayCondition; //***** Constants // Bitmasks for SPN display rules. - static final int SPN_RULE_SHOW_SPN = 0x01; - static final int SPN_RULE_SHOW_PLMN = 0x02; - - // From TS 51.011 EF[SPDI] section - static final int TAG_SPDI_PLMN_LIST = 0x80; - - // Full Name IEI from TS 24.008 - static final int TAG_FULL_NETWORK_NAME = 0x43; - - // Short Name IEI from TS 24.008 - static final int TAG_SHORT_NETWORK_NAME = 0x45; - - // active CFF from CPHS 4.2 B.4.5 - static final int CFF_UNCONDITIONAL_ACTIVE = 0x0a; - static final int CFF_UNCONDITIONAL_DEACTIVE = 0x05; - static final int CFF_LINE1_MASK = 0x0f; - static final int CFF_LINE1_RESET = 0xf0; + protected static final int SPN_RULE_SHOW_SPN = 0x01; + protected static final int SPN_RULE_SHOW_PLMN = 0x02; //***** Event Constants - private static final int EVENT_SET_MSISDN_DONE = 30; - + protected static final int EVENT_SET_MSISDN_DONE = 30; + //***** Constructor - public IccRecords(PhoneBase phone) { - this.phone = phone; + public IccRecords(PhoneBase p) { + this.phone = p; } -// TODO T: check if public can /should be avoided - protected AdnRecordCache getAdnCache() { - return adnCache; - } + protected abstract void onRadioOffOrNotAvailable(); - protected void onRadioOffOrNotAvailable() { - imsi = null; - msisdn = null; - voiceMailNum = null; - countVoiceMessages = 0; - mncLength = 0; - iccid = null; - spn = null; - // -1 means no EF_SPN found; treat accordingly. - spnDisplayCondition = -1; - efMWIS = null; - efCPHS_MWI = null; - spn = null; - spdiNetworks = null; - pnnHomeName = null; - - adnCache.reset(); - - phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, null); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, null); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, null); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY, null); - - // recordsRequested is set to false indicating that the SIM - // read requests made so far are not valid. This is set to - // true only when fresh set of read requests are made. - recordsRequested = false; + //***** Public Methods + public AdnRecordCache getAdnCache() { + return adnCache; } - - //***** Public Methods public void registerForRecordsLoaded(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); recordsLoadedRegistrants.add(r); @@ -155,9 +92,8 @@ public abstract class IccRecords extends Handler implements IccConstants { } } - /** Returns null if SIM is not yet ready */ - public String getIMSI() { - return imsi; + public void unregisterForRecordsLoaded(Handler h) { + recordsLoadedRegistrants.remove(h); } public String getMsisdnNumber() { @@ -203,10 +139,10 @@ public abstract class IccRecords extends Handler implements IccConstants { } /** - * Return Service Provider Name stored in SIM - * @return null if SIM is not yet ready + * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41) + * @return null if SIM is not yet ready or no RUIM entry */ - public String getServiceProvideName() { + public String getServiceProviderName() { return spn; } @@ -217,7 +153,7 @@ public abstract class IccRecords extends Handler implements IccConstants { * EF_MAILBOX_CPHS (CPHS 4.2) * * If EF_MBDN is available, store the voice mail number to EF_MBDN - * + * * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS * * So the voice mail number will be stored in both EFs if both are available @@ -245,7 +181,7 @@ public abstract class IccRecords extends Handler implements IccConstants { * Sets the SIM voice message waiting indicator records * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported * @param countWaiting The number of messages waiting, if known. Use - * -1 to indicate that an unknown number of + * -1 to indicate that an unknown number of * messages are waiting */ public abstract void setVoiceMessageWaiting(int line, int countWaiting); @@ -257,20 +193,13 @@ public abstract class IccRecords extends Handler implements IccConstants { /** * Returns number of voice messages waiting, if available - * If not available (eg, on an older CPHS SIM) -1 is returned if + * If not available (eg, on an older CPHS SIM) -1 is returned if * getVoiceMessageWaiting() is true */ public int getCountVoiceMessages() { return countVoiceMessages; } - public boolean getVoiceCallForwardingFlag() { - return callForwardingEnabled; - } - - public abstract void setVoiceCallForwardingFlag(int line, boolean enable); - - /** * Called by STK Service when REFRESH is received. * @param fileChanged indicates whether any files changed @@ -279,7 +208,6 @@ public abstract class IccRecords extends Handler implements IccConstants { public abstract void onRefresh(boolean fileChanged, int[] fileList); -// TODO T: check if public can /should be avoided public boolean getRecordsLoaded() { if (recordsToLoad == 0 && recordsRequested == true) { return true; @@ -292,10 +220,9 @@ public abstract class IccRecords extends Handler implements IccConstants { public abstract void handleMessage(Message msg); protected abstract void onRecordLoaded(); - + protected abstract void onAllRecordsLoaded(); - -// TODO T: check if public can /should be avoided + /** * Returns the SpnDisplayRule based on settings on the SIM and the * specified plmn (currently-registered PLMN). See TS 22.101 Annex A @@ -304,9 +231,7 @@ public abstract class IccRecords extends Handler implements IccConstants { * If the SPN is not found on the SIM, the rule is always PLMN_ONLY. */ protected abstract int getDisplayRule(String plmn); - - private void log(String s) { - Log.d(LOG_TAG, " " + s); - } - + + protected abstract void log(String s); } + diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java index b2c69b5e95af..620f2deae500 100644 --- a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2008 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. @@ -18,22 +18,149 @@ package com.android.internal.telephony; import android.app.PendingIntent; import android.content.Context; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.os.ServiceManager; -import android.telephony.gsm.SmsManager; import android.util.Log; import java.util.ArrayList; import java.util.List; -import com.android.internal.telephony.IccConstants; -import com.android.internal.telephony.gsm.*; //TO BE REMOVED when Isms goes to telephony +import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; /** - * SimSmsInterfaceManager to provide an inter-process communication to - * access Sms in Sim. + * IccSmsInterfaceManager to provide an inter-process communication to + * access Sms in Icc. */ public abstract class IccSmsInterfaceManager extends ISms.Stub { + static final boolean DBG = true; + + protected PhoneBase mPhone; + protected Context mContext; + protected SMSDispatcher mDispatcher; + + protected IccSmsInterfaceManager(PhoneBase phone){ + mPhone = phone; + mContext = phone.getContext(); + } + + protected void enforceReceiveAndSend(String message) { + mContext.enforceCallingPermission( + "android.permission.RECEIVE_SMS", message); + mContext.enforceCallingPermission( + "android.permission.SEND_SMS", message); + } + + /** + * Send a Raw PDU SMS + * + * @param smsc the SMSC to send the message through, or NULL for the + * defatult SMSC + * @param pdu the raw PDU to send + * @param sentIntent if not NULL this <code>Intent</code> is + * broadcast when the message is sucessfully sent, or failed. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors: + * <code>RESULT_ERROR_GENERIC_FAILURE</code> + * <code>RESULT_ERROR_RADIO_OFF</code> + * <code>RESULT_ERROR_NULL_PDU</code>. + * @param deliveryIntent if not NULL this <code>Intent</code> is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + */ + public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + Context context = mPhone.getContext(); + + context.enforceCallingPermission( + "android.permission.SEND_SMS", + "Sending SMS message"); + if (DBG) log("sendRawPdu: smsc=" + smsc + + " pdu="+ pdu + " sentIntent" + sentIntent + + " deliveryIntent" + deliveryIntent); + mDispatcher.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); + } + + /** + * Send a multi-part text based SMS. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param parts an <code>ArrayList</code> of strings that, in order, + * comprise the original message + * @param sentIntents if not null, an <code>ArrayList</code> of + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors: + * <code>RESULT_ERROR_GENERIC_FAILURE</code> + * <code>RESULT_ERROR_RADIO_OFF</code> + * <code>RESULT_ERROR_NULL_PDU</code>. + * @param deliveryIntents if not null, an <code>ArrayList</code> of + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). + */ + public void sendMultipartText(String destinationAddress, String scAddress, List<String> parts, + List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { + Context context = mPhone.getContext(); + + context.enforceCallingPermission( + "android.permission.SEND_SMS", + "Sending SMS message"); + if (DBG) log("sendMultipartText"); + mDispatcher.sendMultipartText(destinationAddress, scAddress, (ArrayList<String>) parts, + (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents); + } + + /** + * create SmsRawData lists from all sms record byte[] + * Use null to indicate "free" record + * + * @param messages List of message records from EF_SMS. + * @return SmsRawData list of all in-used records + */ + protected ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) { + int count = messages.size(); + ArrayList<SmsRawData> ret; + + ret = new ArrayList<SmsRawData>(count); + + for (int i = 0; i < count; i++) { + byte[] ba = messages.get(i); + if (ba[0] == STATUS_ON_ICC_FREE) { + ret.add(null); + } else { + ret.add(new SmsRawData(messages.get(i))); + } + } + + return ret; + } + + /** + * Generates an EF_SMS record from status and raw PDU. + * + * @param status Message status. See TS 51.011 10.5.3. + * @param pdu Raw message PDU. + * @return byte array for the record. + */ + protected byte[] makeSmsRecordData(int status, byte[] pdu) { + byte[] data = new byte[IccConstants.SMS_RECORD_LENGTH]; + + // Status bits for this record. See TS 51.011 10.5.3 + data[0] = (byte)(status & 7); + + System.arraycopy(pdu, 0, data, 1, pdu.length); + + // Pad out with 0xFF's. + for (int j = pdu.length+1; j < IccConstants.SMS_RECORD_LENGTH; j++) { + data[j] = -1; + } + + return data; + } + + protected abstract void log(String msg); + } + diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java index 90c0ec098da6..a51d074104c7 100644 --- a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java +++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2008 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. @@ -17,58 +17,49 @@ package com.android.internal.telephony; import android.app.PendingIntent; -import android.content.Context; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; import android.os.ServiceManager; -import android.telephony.gsm.SmsManager; -import android.util.Log; -import java.util.ArrayList; import java.util.List; -//TODO remove after moving SmsRawData and ISms.Stub to telephony -import com.android.internal.telephony.gsm.*; - public class IccSmsInterfaceManagerProxy extends ISms.Stub { private IccSmsInterfaceManager mIccSmsInterfaceManager; - public IccSmsInterfaceManagerProxy(IccSmsInterfaceManager + public IccSmsInterfaceManagerProxy(IccSmsInterfaceManager iccSmsInterfaceManager) { this.mIccSmsInterfaceManager = iccSmsInterfaceManager; - ServiceManager.addService("isms", this); + if(ServiceManager.getService("isms") == null) { + ServiceManager.addService("isms", this); + } + } + + public void setmIccSmsInterfaceManager(IccSmsInterfaceManager iccSmsInterfaceManager) { + this.mIccSmsInterfaceManager = iccSmsInterfaceManager; } public boolean - //TODO Investigate - updateMessageOnSimEf(int index, int status, byte[] pdu) throws android.os.RemoteException { - return mIccSmsInterfaceManager.updateMessageOnSimEf(index, status, pdu); + updateMessageOnIccEf(int index, int status, byte[] pdu) throws android.os.RemoteException { + return mIccSmsInterfaceManager.updateMessageOnIccEf(index, status, pdu); } - //TODO Investigate - public boolean copyMessageToSimEf(int status, byte[] pdu, + public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) throws android.os.RemoteException { - return mIccSmsInterfaceManager.copyMessageToSimEf(status, pdu, smsc); + return mIccSmsInterfaceManager.copyMessageToIccEf(status, pdu, smsc); } - //TODO Investigate - public List<SmsRawData> getAllMessagesFromSimEf() throws android.os.RemoteException { - return mIccSmsInterfaceManager.getAllMessagesFromSimEf(); + public List<SmsRawData> getAllMessagesFromIccEf() throws android.os.RemoteException { + return mIccSmsInterfaceManager.getAllMessagesFromIccEf(); } - //TODO Investigate public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, PendingIntent deliveryIntent) throws android.os.RemoteException { - mIccSmsInterfaceManager.sendRawPdu(smsc, pdu, sentIntent, + mIccSmsInterfaceManager.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); } - //TODO Investigate - public void sendMultipartText(String destinationAddress, String scAddress, - List<String> parts, List<PendingIntent> sentIntents, + public void sendMultipartText(String destinationAddress, String scAddress, + List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) throws android.os.RemoteException { - mIccSmsInterfaceManager.sendMultipartText(destinationAddress, scAddress, + mIccSmsInterfaceManager.sendMultipartText(destinationAddress, scAddress, parts, sentIntents, deliveryIntents); } diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java index ea544ab1eaa0..917be43989e7 100644 --- a/telephony/java/com/android/internal/telephony/IccUtils.java +++ b/telephony/java/com/android/internal/telephony/IccUtils.java @@ -16,12 +16,13 @@ package com.android.internal.telephony; -import java.io.UnsupportedEncodingException; - import android.graphics.Bitmap; import android.graphics.Color; import android.util.Log; -import com.android.internal.telephony.gsm.GsmAlphabet; + +import com.android.internal.telephony.GsmAlphabet; + +import java.io.UnsupportedEncodingException; /** * Various methods, useful for dealing with SIM data. @@ -32,7 +33,7 @@ public class IccUtils { /** * Many fields in GSM SIM's are stored as nibble-swizzled BCD * - * Assumes left-justified field that may be padded right with 0xf + * Assumes left-justified field that may be padded right with 0xf * values. * * Stops on invalid BCD value, returning string so far @@ -40,21 +41,21 @@ public class IccUtils { public static String bcdToString(byte[] data, int offset, int length) { StringBuilder ret = new StringBuilder(length*2); - + for (int i = offset ; i < offset + length ; i++) { byte b; int v; - + v = data[i] & 0xf; if (v > 9) break; ret.append((char)('0' + v)); v = (data[i] >> 4) & 0xf; if (v > 9) break; - ret.append((char)('0' + v)); + ret.append((char)('0' + v)); } - - return ret.toString(); + + return ret.toString(); } @@ -65,7 +66,7 @@ public class IccUtils { * significant nibble. * * Out-of-range digits are treated as 0 for the sake of the time stamp, - * because of this: + * because of this: * * TS 23.040 section 9.2.3.11 * "if the MS receives a non-integer value in the SCTS, it shall @@ -78,7 +79,7 @@ public class IccUtils { // treat out-of-range BCD values as 0 if ((b & 0xf0) <= 0x90) { - ret = (b >> 4) & 0xf; + ret = (b >> 4) & 0xf; } if ((b & 0x0f) <= 0x09) { @@ -88,6 +89,24 @@ public class IccUtils { return ret; } + /** Decodes BCD byte like {@link bcdByteToInt}, but the most significant BCD + * digit is expected in the most significant nibble. + */ + public static int + beBcdByteToInt(byte b) { + int ret = 0; + + // treat out-of-range BCD values as 0 + if ((b & 0xf0) <= 0x90) { + ret = ((b >> 4) & 0xf) * 10; + } + + if ((b & 0x0f) <= 0x09) { + ret += (b & 0xf); + } + + return ret; + } /** * Decodes a string field that's formatted like the EF[ADN] alpha @@ -96,8 +115,8 @@ public class IccUtils { * From TS 51.011 10.5.1: * Coding: * this alpha tagging shall use either - * - the SMS default 7 bit coded alphabet as defined in - * TS 23.038 [12] with bit 8 set to 0. The alpha identifier + * - the SMS default 7 bit coded alphabet as defined in + * TS 23.038 [12] with bit 8 set to 0. The alpha identifier * shall be left justified. Unused bytes shall be set to 'FF'; or * - one of the UCS2 coded options as defined in annex B. * @@ -107,7 +126,7 @@ public class IccUtils { * 2) if the first octet in the alpha string is '81', then the * second octet contains a value indicating the number of * characters in the string, and the third octet contains an - * 8 bit number which defines bits 15 to 8 of a 16 bit + * 8 bit number which defines bits 15 to 8 of a 16 bit * base pointer, where bit 16 is set to zero and bits 7 to 1 * are also set to zero. These sixteen bits constitute a * base pointer to a "half page" in the UCS2 code space, to be @@ -215,12 +234,12 @@ public class IccUtils { /** * Converts a hex String to a byte array. - * + * * @param s A string of hexadecimal characters, must be an even number of * chars long * * @return byte array representation - * + * * @throws RuntimeException on invalid format */ public static byte[] @@ -234,10 +253,10 @@ public class IccUtils { ret = new byte[sz/2]; for (int i=0 ; i <sz ; i+=2) { - ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4) + ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4) | hexCharToInt(s.charAt(i+1))); } - + return ret; } @@ -250,7 +269,7 @@ public class IccUtils { public static String bytesToHexString(byte[] bytes) { if (bytes == null) return null; - + StringBuilder ret = new StringBuilder(2*bytes.length); for (int i = 0 ; i < bytes.length ; i++) { @@ -277,7 +296,7 @@ public class IccUtils { public static String networkNameToString(byte[] data, int offset, int length) { String ret; - + if ((data[offset] & 0x80) != 0x80 || length < 1) { return ""; } @@ -288,13 +307,12 @@ public class IccUtils { int countSeptets; int unusedBits = data[offset] & 7; countSeptets = (((length - 1) * 8) - unusedBits) / 7 ; - ret = GsmAlphabet.gsm7BitPackedToString( - data, offset + 1, countSeptets); + ret = GsmAlphabet.gsm7BitPackedToString(data, offset + 1, countSeptets); break; case 1: // UCS2 try { - ret = new String(data, + ret = new String(data, offset + 1, length - 1, "utf-16"); } catch (UnsupportedEncodingException ex) { ret = ""; @@ -325,7 +343,7 @@ public class IccUtils { * @param data The raw data * @param length The length of image body * @return The bitmap - */ + */ public static Bitmap parseToBnW(byte[] data, int length){ int valueIndex = 0; int width = data[valueIndex++] & 0xFF; @@ -362,7 +380,7 @@ public class IccUtils { /** * a TS 131.102 image instance of code scheme '11' into color Bitmap - * + * * @param data The raw data * @param length the length of image body * @param transparency with or without transparency diff --git a/telephony/java/com/android/internal/telephony/MmiCode.java b/telephony/java/com/android/internal/telephony/MmiCode.java index 925b06fb926c..c71ff778d859 100644 --- a/telephony/java/com/android/internal/telephony/MmiCode.java +++ b/telephony/java/com/android/internal/telephony/MmiCode.java @@ -41,14 +41,14 @@ public interface MmiCode * @return Localized message for UI display, valid only in COMPLETE * or FAILED states. null otherwise */ - + public CharSequence getMessage(); /** * Cancels pending MMI request. * State becomes CANCELLED unless already COMPLETE or FAILED */ - public void cancel(); + public void cancel(); /** * @return true if the network response is a REQUEST for more user input. diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index d178c37309a3..398f9d316f8a 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -21,6 +21,8 @@ import android.os.Handler; import android.os.Message; import android.telephony.CellLocation; import android.telephony.ServiceState; + +import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.gsm.NetworkInfo; import com.android.internal.telephony.gsm.PdpConnection; import com.android.internal.telephony.test.SimulatedRadioControl; @@ -38,13 +40,13 @@ public interface Phone { /** used to enable additional debug messages */ static final boolean DEBUG_PHONE = true; - - /** + + /** * The phone state. One of the following:<p> * <ul> * <li>IDLE = no phone activity</li> - * <li>RINGING = a phone call is ringing or call waiting. + * <li>RINGING = a phone call is ringing or call waiting. * In the latter case, another call is active as well</li> * <li>OFFHOOK = The phone is off hook. At least one call * exists that is dialing, active or holding and no calls are @@ -70,7 +72,7 @@ public interface Phone { CONNECTED, CONNECTING, DISCONNECTED, SUSPENDED; }; - enum DataActivityState { + public enum DataActivityState { /** * The state of a data activity. * <ul> @@ -131,6 +133,7 @@ public interface Phone { static final String REASON_DATA_ENABLED = "dataEnabled"; static final String REASON_GPRS_ATTACHED = "gprsAttached"; static final String REASON_GPRS_DETACHED = "gprsDetached"; + static final String REASON_CDMA_DATA_DETACHED = "cdmaDataDetached"; static final String REASON_APN_CHANGED = "apnChanged"; static final String REASON_APN_SWITCHED = "apnSwitched"; static final String REASON_RESTORE_DEFAULT_APN = "restoreDefaultApn"; @@ -149,26 +152,32 @@ public interface Phone { static final int BM_BOUNDARY = 6; // upper band boundary // Used for preferred network type - static final int NT_AUTO_TYPE = 0; // GSM/WCDMA (WCDMA preferred) - static final int NT_GSM_TYPE = 1; // GSM only - static final int NT_WCDMA_TYPE = 2; // WCDMA only - static final int NT_GSM_UMTS_AUTO_TYPE = 3; // GSM/WCDMA (auto mode) - static final int NT_CDMA_EVDO_AUTO_TYPE = 4; // CDMA and EvDo (auto mode, according to PRL) - static final int NT_CDMA_TYPE = 5; // CDMA only - static final int NT_EVDO_TYPE = 6; // EvDo only - static final int NT_GLOBAL_AUTO_TYPE = 7; // GSM/WCDMA, CDMA, EvDo (auto mode, according to PRL) + // Note NT_* substitute RILConstants.NETWORK_MODE_* above the Phone + int NT_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */ + int NT_MODE_GSM_ONLY = 1; /* GSM only */ + int NT_MODE_WCDMA_ONLY = 2; /* WCDMA only */ + int NT_MODE_GSM_UMTS = 3; /* GSM/WCDMA (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int NT_MODE_CDMA = 4; /* CDMA and EvDo (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int NT_MODE_CDMA_NO_EVDO = 5; /* CDMA only */ + int NT_MODE_EVDO_NO_CDMA = 6; /* EvDo only */ + int NT_MODE_GLOBAL = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int PREFERRED_NT_MODE = NT_MODE_GLOBAL; + // Used for CDMA roaming mode static final int CDMA_RM_HOME = 0; //Home Networks only, as defined in PRL static final int CDMA_RM_AFFILIATED = 1; //Roaming an Affiliated networks, as defined in PRL static final int CDMA_RM_ANY = 2; //Roaming on Any Network, as defined in PRL - + // Used for CDMA subscription mode static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; //RUIM/SIM (default) static final int CDMA_SUBSCRIPTION_NV = 1; //NV -> non-volatile memory /** - * Get the current ServiceState. Use + * Get the current ServiceState. Use * <code>registerForServiceStateChanged</code> to be informed of * updates. */ @@ -178,11 +187,12 @@ public interface Phone { * Get the current CellLocation. */ CellLocation getCellLocation(); - + /** * Get the current DataState. No change notification exists at this - * interface -- use - * {@link com.android.internal.telephony.PhoneStateIntentReceiver PhoneStateIntentReceiver} instead. + * interface -- use + * {@link com.android.internal.telephony.PhoneStateIntentReceiver PhoneStateIntentReceiver} + * instead. */ DataState getDataConnectionState(); @@ -192,58 +202,58 @@ public interface Phone { * {@link TelephonyManager} instead. */ DataActivityState getDataActivityState(); - + /** * Gets the context for the phone, as set at initialization time. */ Context getContext(); - /** + /** * Get current coarse-grained voice call state. - * Use {@link #registerForPhoneStateChanged(Handler, int, Object) + * Use {@link #registerForPhoneStateChanged(Handler, int, Object) * registerForPhoneStateChanged()} for change notification. <p> * If the phone has an active call and call waiting occurs, * then the phone state is RINGING not OFFHOOK - * <strong>Note:</strong> + * <strong>Note:</strong> * This registration point provides notification of finer-grained * changes.<p> * */ State getState(); - /** + /** * Returns a string identifier for this phone interface for parties * outside the phone app process. * @return The string name. */ String getPhoneName(); - /** + /** * Returns an array of string identifiers for the APN types serviced by the * currently active or last connected APN. * @return The string array. */ String[] getActiveApnTypes(); - - /** + + /** * Returns a string identifier for currently active or last connected APN. * @return The string name. */ String getActiveApn(); - - /** + + /** * Get current signal strength. No change notification available on this * interface. Use <code>PhoneStateNotifier</code> or an equivalent. - * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu). + * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu). * The following special values are defined:</p> * <ul><li>0 means "-113 dBm or less".</li> * <li>31 means "-51 dBm or greater".</li></ul> - * + * * @return Current signal strength in ASU's. */ int getSignalStrengthASU(); - - /** + + /** * Notifies when a previously untracked non-ringing/waiting connection has appeared. * This is likely due to some other entity (eg, SIM card application) initiating a call. */ @@ -254,7 +264,7 @@ public interface Phone { */ void unregisterForUnknownConnection(Handler h); - /** + /** * Notifies when any aspect of the voice call state changes. * Resulting events will have an AsyncResult in <code>Message.obj</code>. * AsyncResult.userData will be set to the obj argument here. @@ -263,13 +273,13 @@ public interface Phone { void registerForPhoneStateChanged(Handler h, int what, Object obj); /** - * Unregisters for voice call state change notifications. + * Unregisters for voice call state change notifications. * Extraneous calls are tolerated silently. */ void unregisterForPhoneStateChanged(Handler h); - /** + /** * Notifies when a new ringing or waiting connection has appeared.<p> * * Messages received from this: @@ -278,19 +288,19 @@ public interface Phone { * AsyncResult.result = a Connection. <p> * Please check Connection.isRinging() to make sure the Connection * has not dropped since this message was posted. - * If Connection.isRinging() is true, then + * If Connection.isRinging() is true, then * Connection.getCall() == Phone.getRingingCall() */ void registerForNewRingingConnection(Handler h, int what, Object obj); /** - * Unregisters for new ringing connection notification. + * Unregisters for new ringing connection notification. * Extraneous calls are tolerated silently */ void unregisterForNewRingingConnection(Handler h); - /** + /** * Notifies when an incoming call rings.<p> * * Messages received from this: @@ -299,29 +309,29 @@ public interface Phone { * AsyncResult.result = a Connection. <p> */ void registerForIncomingRing(Handler h, int what, Object obj); - + /** - * Unregisters for ring notification. + * Unregisters for ring notification. * Extraneous calls are tolerated silently */ - + void unregisterForIncomingRing(Handler h); - - - /** + + + /** * Notifies when a voice connection has disconnected, either due to local * or remote hangup or error. - * + * * Messages received from this will have the following members:<p> * <ul><li>Message.obj will be an AsyncResult</li> * <li>AsyncResult.userObj = obj</li> - * <li>AsyncResult.result = a Connection object that is + * <li>AsyncResult.result = a Connection object that is * no longer connected.</li></ul> */ void registerForDisconnect(Handler h, int what, Object obj); /** - * Unregisters for voice disconnection notification. + * Unregisters for voice disconnection notification. * Extraneous calls are tolerated silently */ void unregisterForDisconnect(Handler h); @@ -341,7 +351,7 @@ public interface Phone { void registerForMmiInitiate(Handler h, int what, Object obj); /** - * Unregisters for new MMI initiate notification. + * Unregisters for new MMI initiate notification. * Extraneous calls are tolerated silently */ void unregisterForMmiInitiate(Handler h); @@ -357,7 +367,7 @@ public interface Phone { void registerForMmiComplete(Handler h, int what, Object obj); /** - * Unregisters for MMI complete notification. + * Unregisters for MMI complete notification. * Extraneous calls are tolerated silently */ void unregisterForMmiComplete(Handler h); @@ -366,7 +376,7 @@ public interface Phone { * Returns a list of MMI codes that are pending. (They have initiated * but have not yet completed). * Presently there is only ever one. - * Use <code>registerForMmiInitiate</code> + * Use <code>registerForMmiInitiate</code> * and <code>registerForMmiComplete</code> for change notification. */ public List<? extends MmiCode> getPendingMmiCodes(); @@ -381,14 +391,14 @@ public interface Phone { public void sendUssdResponse(String ussdMessge); /** - * Register for ServiceState changed. + * Register for ServiceState changed. * Message.obj will contain an AsyncResult. * AsyncResult.result will be a ServiceState instance */ void registerForServiceStateChanged(Handler h, int what, Object obj); /** - * Unregisters for ServiceStateChange notification. + * Unregisters for ServiceStateChange notification. * Extraneous calls are tolerated silently */ void unregisterForServiceStateChanged(Handler h); @@ -405,9 +415,9 @@ public interface Phone { void registerForSuppServiceNotification(Handler h, int what, Object obj); /** - * Unregisters for Supplementary Service notifications. + * Unregisters for Supplementary Service notifications. * Extraneous calls are tolerated silently - * + * * @param h Handler to be removed from the registrant list. */ void unregisterForSuppServiceNotification(Handler h); @@ -425,20 +435,52 @@ public interface Phone { /** * Unregister for notifications when a supplementary service attempt fails. * Extraneous calls are tolerated silently - * + * * @param h Handler to be removed from the registrant list. */ void unregisterForSuppServiceFailed(Handler h); - /** - * Returns SIM record load state. Use + /** + * Register for notifications when a sInCall VoicePrivacy is enabled + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj); + + /** + * Unegister for notifications when a sInCall VoicePrivacy is enabled + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForInCallVoicePrivacyOn(Handler h); + + /** + * Register for notifications when a sInCall VoicePrivacy is disabled + * + * @param h Handler that receives the notification message. + * @param what User-defined message code. + * @param obj User object. + */ + void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj); + + /** + * Unegister for notifications when a sInCall VoicePrivacy is disabled + * + * @param h Handler to be removed from the registrant list. + */ + void unregisterForInCallVoicePrivacyOff(Handler h); + + /** + * Returns SIM record load state. Use * <code>getSimCard().registerForReady()</code> for change notification. * - * @return true if records from the SIM have been loaded and are + * @return true if records from the SIM have been loaded and are * available (if applicable). If not applicable to the underlying * technology, returns true as well. */ - boolean getSimRecordsLoaded(); + boolean getIccRecordsLoaded(); /** * Returns the ICC card interface for this phone, or null @@ -447,31 +489,31 @@ public interface Phone { IccCard getIccCard(); /** - * Answers a ringing or waiting call. Active calls, if any, go on hold. + * Answers a ringing or waiting call. Active calls, if any, go on hold. * Answering occurs asynchronously, and final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ void acceptCall() throws CallStateException; - /** - * Reject (ignore) a ringing call. In GSM, this means UDUB - * (User Determined User Busy). Reject occurs asynchronously, - * and final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + /** + * Reject (ignore) a ringing call. In GSM, this means UDUB + * (User Determined User Busy). Reject occurs asynchronously, + * and final notification occurs via + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ void rejectCall() throws CallStateException; - /** + /** * Places any active calls on hold, and makes any held calls * active. Switch occurs asynchronously and may fail. - * Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * Final notification occurs via + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. * * @exception CallStateException if a call is ringing, waiting, or @@ -480,18 +522,18 @@ public interface Phone { void switchHoldingAndActive() throws CallStateException; /** - * Whether or not the phone can conference in the current phone + * Whether or not the phone can conference in the current phone * state--that is, one call holding and one call active. - * @return true if the phone can conference; false otherwise. + * @return true if the phone can conference; false otherwise. */ boolean canConference(); /** - * Conferences holding and active. Conference occurs asynchronously - * and may fail. Final notification occurs via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, - * java.lang.Object) registerForPhoneStateChanged()}. - * + * Conferences holding and active. Conference occurs asynchronously + * and may fail. Final notification occurs via + * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * java.lang.Object) registerForPhoneStateChanged()}. + * * @exception CallStateException if canConference() would return false. * In these cases, this operation may not be performed. */ @@ -500,15 +542,15 @@ public interface Phone { /** * Enable or disable enhanced Voice Privacy (VP). If enhanced VP is * disabled, normal VP is enabled. - * + * * @param enable whether true or false to enable or disable. * @param onComplete a callback message when the action is completed. */ void enableEnhancedVoicePrivacy(boolean enable, Message onComplete); - + /** * Get the currently set Voice Privacy (VP) mode. - * + * * @param onComplete a callback message when the action is completed. */ void getEnhancedVoicePrivacy(Message onComplete); @@ -540,65 +582,65 @@ public interface Phone { void clearDisconnected(); - /** - * Gets the foreground call object, which represents all connections that - * are dialing or active (all connections + /** + * Gets the foreground call object, which represents all connections that + * are dialing or active (all connections * that have their audio path connected).<p> * * The foreground call is a singleton object. It is constant for the life * of this phone. It is never null.<p> - * + * * The foreground call will only ever be in one of these states: - * IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED. + * IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. */ Call getForegroundCall(); - /** + /** * Gets the background call object, which represents all connections that * are holding (all connections that have been accepted or connected, but * do not have their audio path connected). <p> * * The background call is a singleton object. It is constant for the life * of this phone object . It is never null.<p> - * + * * The background call will only ever be in one of these states: * IDLE, HOLDING or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. */ Call getBackgroundCall(); - /** - * Gets the ringing call object, which represents an incoming + /** + * Gets the ringing call object, which represents an incoming * connection (if present) that is pending answer/accept. (This connection * may be RINGING or WAITING, and there may be only one.)<p> * The ringing call is a singleton object. It is constant for the life * of this phone. It is never null.<p> - * + * * The ringing call will only ever be in one of these states: * IDLE, INCOMING, WAITING or DISCONNECTED. * * State change notification is available via - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()}. */ Call getRingingCall(); - /** + /** * Initiate a new voice connection. This happens asynchronously, so you * cannot assume the audio path is connected (or a call index has been * assigned) until PhoneStateChanged notification has occurred. * * @exception CallStateException if a new outgoing call is not currently - * possible because no more call slots exist or a call exists that is - * dialing, alerting, ringing, or waiting. Other errors are + * possible because no more call slots exist or a call exists that is + * dialing, alerting, ringing, or waiting. Other errors are * handled asynchronously. */ Connection dial(String dialString) throws CallStateException; @@ -606,7 +648,7 @@ public interface Phone { /** * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated * without SEND (so <code>dial</code> is not appropriate). - * + * * @param dialString the MMI command to be executed. * @return true if MMI command is executed. */ @@ -624,7 +666,7 @@ public interface Phone { boolean handleInCallMmiCommands(String command) throws CallStateException; /** - * Play a DTMF tone on the active call. Ignored if there is no active call. + * Play a DTMF tone on the active call. Ignored if there is no active call. * @param c should be one of 0-9, '*' or '#'. Other values will be * silently ignored. */ @@ -646,20 +688,20 @@ public interface Phone { /** - * Sets the radio power on/off state (off is sometimes - * called "airplane mode"). Current state can be gotten via - * {@link #getServiceState()}.{@link + * Sets the radio power on/off state (off is sometimes + * called "airplane mode"). Current state can be gotten via + * {@link #getServiceState()}.{@link * android.telephony.ServiceState#getState() getState()}. - * <strong>Note: </strong>This request is asynchronous. + * <strong>Note: </strong>This request is asynchronous. * getServiceState().getState() will not change immediately after this call. - * registerForServiceStateChanged() to find out when the + * registerForServiceStateChanged() to find out when the * request is complete. * - * @param power true means "on", false means "off". + * @param power true means "on", false means "off". */ void setRadioPower(boolean power); - /** + /** * Get voice message waiting indicator status. No change notification * available on this interface. Use PhoneStateNotifier or similar instead. * @@ -701,8 +743,8 @@ public interface Phone { void setLine1Number(String alphaTag, String number, Message onComplete); /** - * Get the voice mail access phone number. Typically dialed when the - * user holds the "1" key in the phone app. May return null if not + * Get the voice mail access phone number. Typically dialed when the + * user holds the "1" key in the phone app. May return null if not * available or the SIM is not ready.<p> */ String getVoiceMailNumber(); @@ -711,8 +753,8 @@ public interface Phone { * Returns the alpha tag associated with the voice mail number. * If there is no alpha tag associated or the record is not yet available, * returns a default localized string. <p> - * - * Please use this value instead of some other localized string when + * + * Please use this value instead of some other localized string when * showing a name for this number in the UI. For example, call log * entries should show this alpha tag. <p> * @@ -735,29 +777,29 @@ public interface Phone { /** * getCallForwardingOptions - * gets a call forwarding option. The return value of - * ((AsyncResult)onComplete.obj) is an array of CallForwardInfo. - * - * @param commandInterfaceCFReason is one of the valid call forwarding - * CF_REASONS, as defined in - * <code>com.android.internal.telephony.gsm.CommandsInterface</code> + * gets a call forwarding option. The return value of + * ((AsyncResult)onComplete.obj) is an array of CallForwardInfo. + * + * @param commandInterfaceCFReason is one of the valid call forwarding + * CF_REASONS, as defined in + * <code>com.android.internal.telephony.CommandsInterface./code> * @param onComplete a callback message when the action is completed. * @see com.android.internal.telephony.CallForwardInfo for details. */ void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete); - + /** * setCallForwardingOptions * sets a call forwarding option. - * - * @param commandInterfaceCFReason is one of the valid call forwarding - * CF_REASONS, as defined in - * <code>com.android.internal.telephony.gsm.CommandsInterface</code> - * @param commandInterfaceCFAction is one of the valid call forwarding - * CF_ACTIONS, as defined in - * <code>com.android.internal.telephony.gsm.CommandsInterface</code> - * @param dialingNumber is the target phone number to forward calls to + * + * @param commandInterfaceCFReason is one of the valid call forwarding + * CF_REASONS, as defined in + * <code>com.android.internal.telephony.CommandsInterface./code> + * @param commandInterfaceCFAction is one of the valid call forwarding + * CF_ACTIONS, as defined in + * <code>com.android.internal.telephony.CommandsInterface./code> + * @param dialingNumber is the target phone number to forward calls to * @param timerSeconds is used by CFNRy to indicate the timeout before * forwarding is attempted. * @param onComplete a callback message when the action is completed. @@ -767,83 +809,83 @@ public interface Phone { String dialingNumber, int timerSeconds, Message onComplete); - + /** * getOutgoingCallerIdDisplay - * gets outgoing caller id display. The return value of + * gets outgoing caller id display. The return value of * ((AsyncResult)onComplete.obj) is an array of int, with a length of 2. - * + * * @param onComplete a callback message when the action is completed. - * @see com.android.internal.telephony.gsm.CommandsInterface.getCLIR for details. + * @see com.android.internal.telephony.CommandsInterface.getCLIR for details. */ void getOutgoingCallerIdDisplay(Message onComplete); - + /** * setOutgoingCallerIdDisplay - * sets a call forwarding option. - * - * @param commandInterfaceCLIRMode is one of the valid call CLIR - * modes, as defined in - * <code>com.android.internal.telephony.gsm.CommandsInterface</code> + * sets a call forwarding option. + * + * @param commandInterfaceCLIRMode is one of the valid call CLIR + * modes, as defined in + * <code>com.android.internal.telephony.CommandsInterface./code> * @param onComplete a callback message when the action is completed. */ void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete); - + /** * getCallWaiting - * gets call waiting activation state. The return value of + * gets call waiting activation state. The return value of * ((AsyncResult)onComplete.obj) is an array of int, with a length of 1. - * + * * @param onComplete a callback message when the action is completed. - * @see com.android.internal.telephony.gsm.CommandsInterface.queryCallWaiting for details. + * @see com.android.internal.telephony.CommandsInterface.queryCallWaiting for details. */ void getCallWaiting(Message onComplete); - + /** * setCallWaiting - * sets a call forwarding option. - * - * @param enable is a boolean representing the state that you are + * sets a call forwarding option. + * + * @param enable is a boolean representing the state that you are * requesting, true for enabled, false for disabled. * @param onComplete a callback message when the action is completed. */ void setCallWaiting(boolean enable, Message onComplete); - + /** * Scan available networks. This method is asynchronous; . * On completion, <code>response.obj</code> is set to an AsyncResult with * one of the following members:.<p> *<ul> - * <li><code>response.obj.result</code> will be a <code>List</code> of - * <code>com.android.internal.telephony.gsm.NetworkInfo</code> objects, or</li> - * <li><code>response.obj.exception</code> will be set with an exception + * <li><code>response.obj.result</code> will be a <code>List</code> of + * <code>com.android.internal.telephony.gsm.NetworkInfo</code> objects, or</li> + * <li><code>response.obj.exception</code> will be set with an exception * on failure.</li> * </ul> */ - void getAvailableNetworks(Message response); + void getAvailableNetworks(Message response); /** * Switches network selection mode to "automatic", re-scanning and * re-selecting a network if appropriate. - * - * @param response The message to dispatch when the network selection + * + * @param response The message to dispatch when the network selection * is complete. - * - * @see #selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo, + * + * @see #selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo, * android.os.Message ) */ void setNetworkSelectionModeAutomatic(Message response); /** - * Manually selects a network. <code>response</code> is + * Manually selects a network. <code>response</code> is * dispatched when this is complete. <code>response.obj</code> will be * an AsyncResult, and <code>response.obj.exception</code> will be non-null * on failure. - * + * * @see #setNetworkSelectionModeAutomatic(Message) */ - void selectNetworkManually(NetworkInfo network, + void selectNetworkManually(NetworkInfo network, Message response); /** @@ -870,7 +912,7 @@ public interface Phone { * of available cell IDs. Cell IDs are in hexadecimal format. * * @param response callback message that is dispatched when the query - * completes. + * completes. */ void getNeighboringCids(Message response); @@ -883,28 +925,28 @@ public interface Phone { * <code>AsyncResult</code>. <code>Message.obj.result</code> will be * a Connection object.<p> * - * Message.arg1 will be the post dial character being processed, + * Message.arg1 will be the post dial character being processed, * or 0 ('\0') if end of string.<p> * - * If Connection.getPostDialState() == WAIT, - * the application must call - * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar() - * Connection.proceedAfterWaitChar()} or - * {@link com.android.internal.telephony.Connection#cancelPostDial() + * If Connection.getPostDialState() == WAIT, + * the application must call + * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar() + * Connection.proceedAfterWaitChar()} or + * {@link com.android.internal.telephony.Connection#cancelPostDial() * Connection.cancelPostDial()} - * for the telephony system to continue playing the post-dial + * for the telephony system to continue playing the post-dial * DTMF sequence.<p> * - * If Connection.getPostDialState() == WILD, - * the application must call + * If Connection.getPostDialState() == WILD, + * the application must call * {@link com.android.internal.telephony.Connection#proceedAfterWildChar * Connection.proceedAfterWildChar()} - * or - * {@link com.android.internal.telephony.Connection#cancelPostDial() + * or + * {@link com.android.internal.telephony.Connection#cancelPostDial() * Connection.cancelPostDial()} - * for the telephony system to continue playing the + * for the telephony system to continue playing the * post-dial DTMF sequence.<p> - * + * * Only one post dial character handler may be set. <p> * Calling this method with "h" equal to null unsets this handler.<p> */ @@ -912,19 +954,19 @@ public interface Phone { /** - * Mutes or unmutes the microphone for the active call. The microphone - * is automatically unmuted if a call is answered, dialed, or resumed + * Mutes or unmutes the microphone for the active call. The microphone + * is automatically unmuted if a call is answered, dialed, or resumed * from a holding state. - * - * @param muted true to mute the microphone, + * + * @param muted true to mute the microphone, * false to activate the microphone. */ void setMute(boolean muted); /** - * Gets current mute status. Use - * {@link #registerForPhoneStateChanged(android.os.Handler, int, + * Gets current mute status. Use + * {@link #registerForPhoneStateChanged(android.os.Handler, int, * java.lang.Object) registerForPhoneStateChanged()} * as a change notifcation, although presently phone state changed is not * fired when setMute() is called. @@ -935,12 +977,12 @@ public interface Phone { /** * Invokes RIL_REQUEST_OEM_HOOK_RAW on RIL implementation. - * + * * @param data The data for the request. - * @param response <strong>On success</strong>, + * @param response <strong>On success</strong>, * (byte[])(((AsyncResult)response.obj).result) - * <strong>On failure</strong>, - * (((AsyncResult)response.obj).result) == null and + * <strong>On failure</strong>, + * (((AsyncResult)response.obj).result) == null and * (((AsyncResult)response.obj).exception) being an instance of * com.android.internal.telephony.gsm.CommandException * @@ -950,13 +992,13 @@ public interface Phone { /** * Invokes RIL_REQUEST_OEM_HOOK_Strings on RIL implementation. - * + * * @param strings The strings to make available as the request data. - * @param response <strong>On success</strong>, "response" bytes is + * @param response <strong>On success</strong>, "response" bytes is * made available as: * (String[])(((AsyncResult)response.obj).result). - * <strong>On failure</strong>, - * (((AsyncResult)response.obj).result) == null and + * <strong>On failure</strong>, + * (((AsyncResult)response.obj).result) == null and * (((AsyncResult)response.obj).exception) being an instance of * com.android.internal.telephony.gsm.CommandException * @@ -967,6 +1009,7 @@ public interface Phone { /** * Get the current active PDP context list * + * @deprecated * @param response <strong>On success</strong>, "response" bytes is * made available as: * (String[])(((AsyncResult)response.obj).result). @@ -978,13 +1021,34 @@ public interface Phone { void getPdpContextList(Message response); /** + * Get the current active Data Call list, substitutes getPdpContextList + * + * @param response <strong>On success</strong>, "response" bytes is + * made available as: + * (String[])(((AsyncResult)response.obj).result). + * <strong>On failure</strong>, + * (((AsyncResult)response.obj).result) == null and + * (((AsyncResult)response.obj).exception) being an instance of + * com.android.internal.telephony.gsm.CommandException + */ + void getDataCallList(Message response); + + /** * Get current mutiple PDP link status - * + * + * @deprecated * @return list of pdp link connections */ List<PdpConnection> getCurrentPdpList (); /** + * Get current mutiple data connection status + * + * @return list of data connections + */ + List<DataConnection> getCurrentDataConnectionList (); + + /** * Udpate LAC and CID in service state for currnet GSM netowrk registration * * If get different LAC and/or CID, notifyServiceState will be sent @@ -1008,11 +1072,11 @@ public interface Phone { void disableLocationUpdates(); /** - * For unit tests; don't send notifications to "Phone" + * For unit tests; don't send notifications to "Phone" * mailbox registrants if true. */ void setUnitTestMode(boolean f); - + /** * @return true If unit test mode is enabled */ @@ -1051,7 +1115,7 @@ public interface Phone { * @param response is callback message to report one of CDMA_RM_* */ void queryCdmaRoamingPreference(Message response); - + /** * Requests to set the CDMA roaming preference * @param cdmaRoamingType one of CDMA_RM_* @@ -1065,10 +1129,10 @@ public interface Phone { * @param response is callback message */ void setCdmaSubscription(int cdmaSubscriptionType, Message response); - + /** * If this is a simulated phone interface, returns a SimulatedRadioControl. - * @ return A SimulatedRadioControl if this is a simulated interface; + * @ return A SimulatedRadioControl if this is a simulated interface; * otherwise, null. */ SimulatedRadioControl getSimulatedRadioControl(); @@ -1157,7 +1221,7 @@ public interface Phone { public String[] getDnsServers(String apnType); /** - * Retrieves the unique device ID, e.g., IMEI for GSM phones. + * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones. */ String getDeviceId(); @@ -1176,9 +1240,9 @@ public interface Phone { * Retrieves the serial number of the ICC, if applicable. */ String getIccSerialNumber(); - + //***** CDMA support methods - + /** * Retrieves the ESN for CDMA phones. @@ -1189,11 +1253,11 @@ public interface Phone { * Retrieves MEID for CDMA phones. */ String getMeid(); - + /** * Retrieves the PhoneSubInfo of the Phone */ - public PhoneSubInfo getPhoneSubInfo(); + public PhoneSubInfo getPhoneSubInfo(); /** * Retrieves the IccSmsInterfaceManager of the Phone @@ -1208,19 +1272,46 @@ public interface Phone { /** * setTTYModeEnabled * sets a TTY mode option. - * - * @param enable is a boolean representing the state that you are + * + * @param enable is a boolean representing the state that you are * requesting, true for enabled, false for disabled. * @param onComplete a callback message when the action is completed */ - void setTTYModeEnabled(boolean enable, Message onComplete); - + void setTTYModeEnabled(boolean enable, Message onComplete); + /** * queryTTYModeEnabled - * query the status of the TTY mode - * + * query the status of the TTY mode + * * @param onComplete a callback message when the action is completed. */ void queryTTYModeEnabled(Message onComplete); - + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param response + * Callback message is empty on completion + */ + void activateCellBroadcastSms(int activate, Message response); + + /** + * Query the current configuration of cdma cell broadcast SMS. + * + * @param response + * Callback message is empty on completion + */ + void getCellBroadcastSmsConfig(Message response); + + /** + * Configure cell broadcast SMS. + * + * @param response + * Callback message is empty on completion + */ + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response); + + public void notifyDataActivity(); } diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java index 2693e3a946bb..446053ae4de7 100644 --- a/telephony/java/com/android/internal/telephony/PhoneBase.java +++ b/telephony/java/com/android/internal/telephony/PhoneBase.java @@ -16,16 +16,6 @@ package com.android.internal.telephony; -import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE; -import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; -import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE; -import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; import android.content.Context; import android.content.SharedPreferences; import android.os.AsyncResult; @@ -39,12 +29,16 @@ import android.telephony.ServiceState; import android.text.TextUtils; import android.util.Log; +import com.android.internal.telephony.gsm.PdpConnection; import com.android.internal.telephony.test.SimulatedRadioControl; +import java.util.List; + + /** - * (<em>Not for SDK use</em>) + * (<em>Not for SDK use</em>) * A base implementation for the com.android.internal.telephony.Phone interface. - * + * * Note that implementations of Phone.java are expected to be used * from a single application thread. This should be the same thread that * originally called PhoneFactory to obtain the interface. @@ -54,13 +48,15 @@ import com.android.internal.telephony.test.SimulatedRadioControl; */ public abstract class PhoneBase implements Phone { - private static final String LOG_TAG = "PhoneBase"; - private static final boolean LOCAL_DEBUG = false; - + private static final String LOG_TAG = "PHONE"; + private static final boolean LOCAL_DEBUG = true; + // Key used to read and write the saved network selection value public static final String NETWORK_SELECTION_KEY = "network_selection_key"; - + // Key used to read/write "disable data connection on boot" pref (used for testing) + public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key"; + //***** Event Constants protected static final int EVENT_RADIO_AVAILABLE = 1; /** Supplementary Service Notification received. */ @@ -77,74 +73,72 @@ public abstract class PhoneBase implements Phone { protected static final int EVENT_SET_CALL_FORWARD_DONE = 12; protected static final int EVENT_GET_CALL_FORWARD_DONE = 13; protected static final int EVENT_CALL_RING = 14; - // Used to intercept the carrier selection calls so that + // Used to intercept the carrier selection calls so that // we can save the values. protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 15; protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 16; protected static final int EVENT_SET_CLIR_COMPLETE = 17; protected static final int EVENT_REGISTERED_TO_NETWORK = 18; // Events for CDMA support - protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 19; - protected static final int EVENT_RUIM_RECORDS_LOADED = 3; - protected static final int EVENT_NV_READY = 20; + protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 19; + protected static final int EVENT_RUIM_RECORDS_LOADED = 3; + protected static final int EVENT_NV_READY = 20; protected static final int EVENT_SET_ENHANCED_VP = 21; - + // Key used to read/write current CLIR setting public static final String CLIR_KEY = "clir_key"; - - //***** Instance Variables + + //***** Instance Variables public CommandsInterface mCM; protected IccFileHandler mIccFileHandler; - // TODO T: should be protected but GsmMmiCode and DataConnectionTracker still refer to it directly - public Handler h; - + /** * Set a system property, unless we're in unit test mode */ - protected void + public void setSystemProperty(String property, String value) { if(getUnitTestMode()) { return; } SystemProperties.set(property, value); } - - protected final RegistrantList mPhoneStateRegistrants + + protected final RegistrantList mPhoneStateRegistrants = new RegistrantList(); - protected final RegistrantList mNewRingingConnectionRegistrants + protected final RegistrantList mNewRingingConnectionRegistrants = new RegistrantList(); - protected final RegistrantList mIncomingRingRegistrants + protected final RegistrantList mIncomingRingRegistrants = new RegistrantList(); - - protected final RegistrantList mDisconnectRegistrants + + protected final RegistrantList mDisconnectRegistrants = new RegistrantList(); - protected final RegistrantList mServiceStateRegistrants + protected final RegistrantList mServiceStateRegistrants = new RegistrantList(); - - protected final RegistrantList mMmiCompleteRegistrants + + protected final RegistrantList mMmiCompleteRegistrants = new RegistrantList(); - protected final RegistrantList mMmiRegistrants + protected final RegistrantList mMmiRegistrants = new RegistrantList(); - protected final RegistrantList mUnknownConnectionRegistrants + protected final RegistrantList mUnknownConnectionRegistrants = new RegistrantList(); - - protected final RegistrantList mSuppServiceFailedRegistrants + + protected final RegistrantList mSuppServiceFailedRegistrants = new RegistrantList(); - + protected Looper mLooper; /* to insure registrants are in correct thread*/ protected Context mContext; - /** - * PhoneNotifier is an abstraction for all system-wide - * state change notification. DefaultPhoneNotifier is + /** + * PhoneNotifier is an abstraction for all system-wide + * state change notification. DefaultPhoneNotifier is * used here unless running we're inside a unit test. */ protected PhoneNotifier mNotifier; @@ -157,7 +151,7 @@ public abstract class PhoneBase implements Phone { * Constructs a PhoneBase in normal (non-unit test) mode. * * @param context Context object from hosting application - * @param notifier An instance of DefaultPhoneNotifier, + * @param notifier An instance of DefaultPhoneNotifier, * unless unit testing. */ protected PhoneBase(PhoneNotifier notifier, Context context) { @@ -168,13 +162,13 @@ public abstract class PhoneBase implements Phone { * Constructs a PhoneBase in normal (non-unit test) mode. * * @param context Context object from hosting application - * @param notifier An instance of DefaultPhoneNotifier, + * @param notifier An instance of DefaultPhoneNotifier, * unless unit testing. - * @param unitTestMode when true, prevents notifications + * @param unitTestMode when true, prevents notifications * of state change events */ - protected PhoneBase(PhoneNotifier notifier, Context context, - boolean unitTestMode) { + protected PhoneBase(PhoneNotifier notifier, Context context, + boolean unitTestMode) { this.mNotifier = notifier; this.mContext = context; mLooper = Looper.myLooper(); @@ -198,29 +192,29 @@ public abstract class PhoneBase implements Phone { public void unregisterForPhoneStateChanged(Handler h) { mPhoneStateRegistrants.remove(h); } - + /** * Notify registrants of a PhoneStateChanged. - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ protected void notifyCallStateChangedP() { AsyncResult ar = new AsyncResult(null, this, null); mPhoneStateRegistrants.notifyRegistrants(ar); } - + // Inherited documentation suffices. public void registerForUnknownConnection(Handler h, int what, Object obj) { checkCorrectThread(h); - + mUnknownConnectionRegistrants.addUnique(h, what, obj); } - + // Inherited documentation suffices. public void unregisterForUnknownConnection(Handler h) { mUnknownConnectionRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForNewRingingConnection( Handler h, int what, Object obj) { @@ -234,12 +228,33 @@ public abstract class PhoneBase implements Phone { mNewRingingConnectionRegistrants.remove(h); } + // Inherited documentation suffices. + public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){ + mCM.registerForInCallVoicePrivacyOn(h,what,obj); + } + + // Inherited documentation suffices. + public void unregisterForInCallVoicePrivacyOn(Handler h){ + mCM.unregisterForInCallVoicePrivacyOn(h); + } + + // Inherited documentation suffices. + public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){ + mCM.registerForInCallVoicePrivacyOff(h,what,obj); + } + + // Inherited documentation suffices. + public void unregisterForInCallVoicePrivacyOff(Handler h){ + mCM.unregisterForInCallVoicePrivacyOff(h); + } + + /** * Notifiy registrants of a new ringing Connection. - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ - protected void notifyNewRingingConnectionP(Connection cn) { + protected void notifyNewRingingConnectionP(Connection cn) { AsyncResult ar = new AsyncResult(null, cn, null); mNewRingingConnectionRegistrants.notifyRegistrants(ar); } @@ -248,15 +263,15 @@ public abstract class PhoneBase implements Phone { public void registerForIncomingRing( Handler h, int what, Object obj) { checkCorrectThread(h); - + mIncomingRingRegistrants.addUnique(h, what, obj); } - + // Inherited documentation suffices. public void unregisterForIncomingRing(Handler h) { mIncomingRingRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForDisconnect(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -272,15 +287,15 @@ public abstract class PhoneBase implements Phone { // Inherited documentation suffices. public void registerForSuppServiceFailed(Handler h, int what, Object obj) { checkCorrectThread(h); - + mSuppServiceFailedRegistrants.addUnique(h, what, obj); } - + // Inherited documentation suffices. public void unregisterForSuppServiceFailed(Handler h) { mSuppServiceFailedRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForMmiInitiate(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -292,7 +307,7 @@ public abstract class PhoneBase implements Phone { public void unregisterForMmiInitiate(Handler h) { mMmiRegistrants.remove(h); } - + // Inherited documentation suffices. public void registerForMmiComplete(Handler h, int what, Object obj) { checkCorrectThread(h); @@ -311,7 +326,7 @@ public abstract class PhoneBase implements Phone { * Method to retrieve the saved operator id from the Shared Preferences */ private String getSavedNetworkSelection() { - // open the shared preferences and search with our key. + // open the shared preferences and search with our key. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); return sp.getString(NETWORK_SELECTION_KEY, ""); } @@ -324,7 +339,7 @@ public abstract class PhoneBase implements Phone { public void restoreSavedNetworkSelection(Message response) { // retrieve the operator id String networkSelection = getSavedNetworkSelection(); - + // set to auto if the id is empty, otherwise select the network. if (TextUtils.isEmpty(networkSelection)) { mCM.setNetworkSelectionModeAutomatic(response); @@ -333,10 +348,6 @@ public abstract class PhoneBase implements Phone { } } - - /** - * Subclasses should override this. See documentation in superclass. - */ // Inherited documentation suffices. public void setUnitTestMode(boolean f) { mUnitTestMode = f; @@ -346,11 +357,11 @@ public abstract class PhoneBase implements Phone { public boolean getUnitTestMode() { return mUnitTestMode; } - + /** * To be invoked when a voice call Connection disconnects. * - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ protected void notifyDisconnectP(Connection cn) { @@ -372,7 +383,7 @@ public abstract class PhoneBase implements Phone { } /** - * Subclasses of Phone probably want to replace this with a + * Subclasses of Phone probably want to replace this with a * version scoped to their packages */ protected void notifyServiceStateChangedP(ServiceState ss) { @@ -398,42 +409,42 @@ public abstract class PhoneBase implements Phone { private void checkCorrectThread(Handler h) { if (h.getLooper() != mLooper) { throw new RuntimeException( - "com.android.internal.telephony.Phone must be used from within one thread"); + "com.android.internal.telephony.Phone must be used from within one thread"); } } /** * Retrieves the Handler of the Phone instance - */ - protected abstract Handler getHandler(); + */ + public abstract Handler getHandler(); /** * Retrieves the IccFileHandler of the Phone instance - */ - protected abstract IccFileHandler getIccFileHandler(); + */ + public abstract IccFileHandler getIccFileHandler(); + - /** * Query the status of the CDMA roaming preference */ public void queryCdmaRoamingPreference(Message response) { mCM.queryCdmaRoamingPreference(response); } - + /** * Set the status of the CDMA roaming preference */ public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { mCM.setCdmaRoamingPreference(cdmaRoamingType, response); } - + /** * Set the status of the CDMA subscription mode */ public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { mCM.setCdmaSubscription(cdmaSubscriptionType, response); } - + /** * Set the preferred Network Type: Global, CDMA only or GSM/UMTS only */ @@ -447,134 +458,61 @@ public abstract class PhoneBase implements Phone { public void getPreferredNetworkType(Message response) { mCM.getPreferredNetworkType(response); } - + public void setTTYModeEnabled(boolean enable, Message onComplete) { - // This function should be overridden by the class CDMAPhone. - // It is not implemented in the class GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, because we have an " + - "inactive CDMAPhone then."); + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); } - + public void queryTTYModeEnabled(Message onComplete) { - // This function should be overridden by the class CDMAPhone. - // It is not implemented in the class GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, because we have an " + - "inactive CDMAPhone then."); - } - - // TODO: might not be used in CDMA any longer, move this to GSMPhone - protected boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { - switch (commandInterfaceCFReason) { - case CF_REASON_UNCONDITIONAL: - case CF_REASON_BUSY: - case CF_REASON_NO_REPLY: - case CF_REASON_NOT_REACHABLE: - case CF_REASON_ALL: - case CF_REASON_ALL_CONDITIONAL: - return true; - default: - return false; - } + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); } - // TODO: might not be used in CDMA any longer, move this to GSMPhone - protected boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { - switch (commandInterfaceCFAction) { - case CF_ACTION_DISABLE: - case CF_ACTION_ENABLE: - case CF_ACTION_REGISTRATION: - case CF_ACTION_ERASURE: - return true; - default: - return false; - } + /** + * This should only be called in GSM mode. + * Only here for some backward compatibility + * issues concerning the GSMPhone class. + * @deprecated + */ + public List<PdpConnection> getCurrentPdpList() { + return null; } - // TODO: might not be used in CDMA any longer, move this to GSMPhone - protected boolean isCfEnable(int action) { - return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); + public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); } - - /** - * Make sure the network knows our preferred setting. - */ - // TODO: might not be used in CDMA any longer, move this to GSMPhone - protected void syncClirSetting() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - int clirSetting = sp.getInt(CLIR_KEY, -1); - if (clirSetting >= 0) { - mCM.setCLIR(clirSetting, null); - } + + public void getEnhancedVoicePrivacy(Message onComplete) { + // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone. + Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone."); } - // TODO: might not be used in CDMA any longer, move this to GSMPhone - public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { - if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { - if (LOCAL_DEBUG) Log.d(LOG_TAG, "requesting call forwarding query."); - Message resp; - if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) { - resp = h.obtainMessage(EVENT_GET_CALL_FORWARD_DONE, onComplete); - } else { - resp = onComplete; - } - mCM.queryCallForwardStatus(commandInterfaceCFReason,0,null,resp); - } + public void setBandMode(int bandMode, Message response) { + mCM.setBandMode(bandMode, response); } - - /** - * Saves CLIR setting so that we can re-apply it as necessary - * (in case the RIL resets it across reboots). - */ - // TODO: might not be used in CDMA any longer, move this to GSMPhone - public void saveClirSetting(int commandInterfaceCLIRMode) { - // open the shared preferences editor, and write the value. - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - SharedPreferences.Editor editor = sp.edit(); - editor.putInt(CLIR_KEY, commandInterfaceCLIRMode); - - // commit and log the result. - if (! editor.commit()) { - Log.e(LOG_TAG, "failed to commit CLIR preference"); - } + + public void queryAvailableBandMode(Message response) { + mCM.queryAvailableBandMode(response); } - - // TODO: might not be used in CDMA any longer, move this to GSMPhone - public void setCallForwardingOption(int commandInterfaceCFAction, - int commandInterfaceCFReason, - String dialingNumber, - int timerSeconds, - Message onComplete) { - if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && - (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { - - Message resp; - if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) { - resp = h.obtainMessage(EVENT_SET_CALL_FORWARD_DONE, - isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, onComplete); - } else { - resp = onComplete; - } - mCM.setCallForward(commandInterfaceCFAction, - commandInterfaceCFReason, - CommandsInterface.SERVICE_CLASS_VOICE, - dialingNumber, - timerSeconds, - resp); - } - } - - public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { - // This function should be overridden by the class CDMAPhone. - // It is not implemented in the class GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, because we have an" + - "inactive CDMAPhone then."); + + public void invokeOemRilRequestRaw(byte[] data, Message response) { + mCM.invokeOemRilRequestRaw(data, response); } - public void getEnhancedVoicePrivacy(Message onComplete) { - // This function should be overridden by the class CDMAPhone. - // It is not implemented in the class GSMPhone. - Log.e(LOG_TAG, "Error! This function should never be executed, because we have an " + - "inactive CDMAPhone then."); + public void invokeOemRilRequestStrings(String[] strings, Message response) { + mCM.invokeOemRilRequestStrings(strings, response); } + public void notifyDataActivity() { + mNotifier.notifyDataActivity(this); + } + + public void notifyDataConnection(String reason) { + mNotifier.notifyDataConnection(this, reason); + } + + public abstract String getPhoneName(); + } diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java index 9a123a41f734..b094478fb57c 100644 --- a/telephony/java/com/android/internal/telephony/PhoneFactory.java +++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java @@ -16,27 +16,14 @@ package com.android.internal.telephony; -import java.util.ArrayList; -import java.util.List; -import java.io.IOException; -import java.net.InetSocketAddress; - -import java.util.Collections; - -import android.util.Log; -import com.android.internal.telephony.gsm.GSMPhone; -import com.android.internal.telephony.cdma.CDMAPhone; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.test.SimulatedCommands; - -import android.os.Looper; -import android.os.SystemProperties; import android.content.Context; -import android.content.Intent; import android.net.LocalServerSocket; -import android.app.ActivityManagerNative; +import android.os.Looper; import android.provider.Settings; -import android.telephony.cdma.TtyIntent; +import android.util.Log; + +import com.android.internal.telephony.cdma.CDMAPhone; +import com.android.internal.telephony.gsm.GSMPhone; /** * {@hide} @@ -45,35 +32,19 @@ public class PhoneFactory { static final String LOG_TAG = "PhoneFactory"; static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000; static final int SOCKET_OPEN_MAX_RETRY = 3; - //***** Class Variables + //***** Class Variables - static private Phone sPhone = null; + static private Phone sProxyPhone = null; static private CommandsInterface sCommandsInterface = null; static private boolean sMadeDefaults = false; static private PhoneNotifier sPhoneNotifier; static private Looper sLooper; + static private Context sContext; -/* public static final int NETWORK_MODE_GLOBAL = 0; - public static final int NETWORK_MODE_CDMA = 1; - public static final int NETWORK_MODE_GSM_UMTS = 2; - - public static final int SUBSCRIPTION_FROM_RUIM = 0; - public static final int SUBSCRIPTION_FROM_NV = 1;*/ //TODO Remove, moved to RILConstants + static final int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE; - //preferredNetworkMode 7 - Global, CDMA Preferred - // 4 - CDMA only - // 3 - GSM/UMTS only - static final int preferredNetworkMode = RILConstants.NETWORK_MODE_GLOBAL; - - //cdmaSubscription 0 - Subscription from RUIM, when available - // 1 - Subscription from NV - static final int preferredCdmaSubscription = RILConstants.SUBSCRIPTION_FROM_RUIM; - - // preferred TTY mode - // 0 = disabled - // 1 = enabled - static final int preferredTTYMode = RILConstants.CDM_TTY_MODE_DISABLED; + static final int preferredCdmaSubscription = RILConstants.PREFERRED_CDMA_SUBSCRIPTION; //***** Class Methods @@ -86,9 +57,10 @@ public class PhoneFactory { * instances */ public static void makeDefaultPhone(Context context) { - synchronized(Phone.class) { - if (!sMadeDefaults) { + synchronized(Phone.class) { + if (!sMadeDefaults) { sLooper = Looper.myLooper(); + sContext = context; if (sLooper == null) { throw new RuntimeException( @@ -112,7 +84,7 @@ public class PhoneFactory { break; } else if (retryCount > SOCKET_OPEN_MAX_RETRY) { throw new RuntimeException("PhoneFactory probably already running"); - }else { + } else { try { Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); } catch (InterruptedException er) { @@ -129,28 +101,32 @@ public class PhoneFactory { //Get preferredNetworkMode from Settings.System int cdmaSubscription = Settings.System.getInt(context.getContentResolver(), - Settings.System.PREFERRED_CDMA_SUBSCRIPTION, preferredCdmaSubscription); + Settings.System.PREFERRED_CDMA_SUBSCRIPTION, preferredCdmaSubscription); Log.i(LOG_TAG, "Cdma Subscription set to " + Integer.toString(cdmaSubscription)); - //reads the system proprieties and makes commandsinterface - sCommandsInterface = new RIL(context, networkMode, cdmaSubscription); + //reads the system properties and makes commandsinterface + sCommandsInterface = new RIL(context, networkMode, cdmaSubscription); switch(networkMode) { + case RILConstants.NETWORK_MODE_WCDMA_PREF: + case RILConstants.NETWORK_MODE_GSM_ONLY: + case RILConstants.NETWORK_MODE_WCDMA_ONLY: case RILConstants.NETWORK_MODE_GSM_UMTS: - sPhone = new PhoneProxy(new GSMPhone(context, + sProxyPhone = new PhoneProxy(new GSMPhone(context, sCommandsInterface, sPhoneNotifier)); Log.i(LOG_TAG, "Creating GSMPhone"); break; - case RILConstants.NETWORK_MODE_GLOBAL: case RILConstants.NETWORK_MODE_CDMA: + case RILConstants.NETWORK_MODE_CDMA_NO_EVDO: + case RILConstants.NETWORK_MODE_EVDO_NO_CDMA: + sProxyPhone = new PhoneProxy(new CDMAPhone(context, + sCommandsInterface, sPhoneNotifier)); + Log.i(LOG_TAG, "Creating CDMAPhone"); + break; + case RILConstants.NETWORK_MODE_GLOBAL: default: - sPhone = new PhoneProxy(new CDMAPhone(context, + sProxyPhone = new PhoneProxy(new CDMAPhone(context, sCommandsInterface, sPhoneNotifier)); - // Check if the TTY mode is enabled, and enable/disable the icon - int enabled = - android.provider.Settings.System.getInt(context.getContentResolver(), - android.provider.Settings.System.TTY_MODE_ENABLED, preferredTTYMode); - setTTYStatusBarIcon(context, ((enabled != 0) ? true : false)); Log.i(LOG_TAG, "Creating CDMAPhone"); } sMadeDefaults = true; @@ -163,22 +139,26 @@ public class PhoneFactory { throw new RuntimeException( "PhoneFactory.getDefaultPhone must be called from Looper thread"); } - + if (!sMadeDefaults) { throw new IllegalStateException("Default phones haven't been made yet!"); } - return sPhone; + return sProxyPhone; } - /** - * Tells the StatusBar whether the TTY mode is enabled or disabled - */ - private static void setTTYStatusBarIcon(Context context, boolean enabled) { - Intent ttyModeChanged = new Intent(TtyIntent.TTY_ENABLED_CHANGE_ACTION); - ttyModeChanged.putExtra("ttyEnabled", enabled); - context.sendBroadcast(ttyModeChanged); + public static Phone getCdmaPhone() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + Phone phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier); + return phone; + } + } + + public static Phone getGsmPhone() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + Phone phone = new GSMPhone(sContext, sCommandsInterface, sPhoneNotifier); + return phone; + } } - } diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java index e86294b44e60..9ddedddeb6e7 100644 --- a/telephony/java/com/android/internal/telephony/PhoneProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2008 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. @@ -13,58 +13,145 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + package com.android.internal.telephony; -/* -import android.util.Log; -import com.android.internal.telephony.test.ModelInterpreter; -import com.android.internal.telephony.test.SimulatedCommands; -import android.os.Looper; -import android.os.SystemProperties; + +import android.app.ActivityManagerNative; import android.content.Context; import android.content.Intent; -import android.net.LocalServerSocket; -import android.app.ActivityManagerNative; -*/ -import android.content.*; -import android.os.*; +import android.os.Handler; +import android.os.Message; +import android.telephony.CellLocation; +import android.telephony.ServiceState; +import android.util.Log; -import com.android.internal.telephony.*; -import com.android.internal.telephony.test.SimulatedRadioControl; +import com.android.internal.telephony.cdma.CDMAPhone; +import com.android.internal.telephony.gsm.GSMPhone; import com.android.internal.telephony.gsm.NetworkInfo; import com.android.internal.telephony.gsm.PdpConnection; -import com.android.internal.telephony.gsm.GSMPhone; -import com.android.internal.telephony.cdma.CDMAPhone; -import android.telephony.CellLocation; -import android.telephony.ServiceState; +import com.android.internal.telephony.test.SimulatedRadioControl; -/* -import java.util.ArrayList; import java.util.List; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.Collections; -*/ -import java.util.*; -public class PhoneProxy implements Phone { +public class PhoneProxy extends Handler implements Phone{ + public final static Object lockForRadioTechnologyChange = new Object(); +// private static boolean radioTechnologyChangeGsmToCdma = false; +// private static boolean radioTechnologyChangeCdmaToGsm = false; + private Phone mActivePhone; - private Phone mCdmaPhone; - private Phone mGsmPhone; + private String mOutgoingPhone; + private CommandsInterface mCommandsInterface; private IccSmsInterfaceManagerProxy mIccSmsInterfaceManagerProxy; private IccPhoneBookInterfaceManagerProxy mIccPhoneBookInterfaceManagerProxy; private PhoneSubInfoProxy mPhoneSubInfoProxy; + private static final int EVENT_RADIO_TECHNOLOGY_CHANGED = 1; + private static final String LOG_TAG = "PHONE"; + //***** Class Methods public PhoneProxy(Phone phone) { mActivePhone = phone; - mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy(phone.getIccSmsInterfaceManager()); - mIccPhoneBookInterfaceManagerProxy = - new IccPhoneBookInterfaceManagerProxy(phone.getIccPhoneBookInterfaceManager()); + mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy( + phone.getIccSmsInterfaceManager()); + mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy( + phone.getIccPhoneBookInterfaceManager()); mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo()); + mCommandsInterface = ((PhoneBase)mActivePhone).mCM; + mCommandsInterface.registerForRadioTechnologyChanged( + this, EVENT_RADIO_TECHNOLOGY_CHANGED, null); + } + + @Override + public void handleMessage(Message msg) { + switch(msg.what) { + case EVENT_RADIO_TECHNOLOGY_CHANGED: + //switch Phone from CDMA to GSM or vice versa + mOutgoingPhone = ((PhoneBase)mActivePhone).getPhoneName(); + logd("Switching phone from " + mOutgoingPhone + "Phone to " + + (mOutgoingPhone.equals("GSM") ? "CDMAPhone" : "GSMPhone") ); + boolean oldPowerState = false; //old power state to off + if (mCommandsInterface.getRadioState().isOn()) { + oldPowerState = true; + logd("Setting Radio Power to Off"); + mCommandsInterface.setRadioPower(false, null); + } + if(mOutgoingPhone.equals("GSM")) { + logd("Make a new CDMAPhone and destroy the old GSMPhone."); + + ((GSMPhone)mActivePhone).dispose(); + Phone oldPhone = mActivePhone; + + //Give the garbage collector a hint to start the garbage collection asap + // NOTE this has been disabled since radio technology change could happen during + // e.g. a multimedia playing and could slow the system. Tests needs to be done + // to see the effects of the GC call here when system is busy. + //System.gc(); + + mActivePhone = PhoneFactory.getCdmaPhone(); + logd("Resetting Radio"); + mCommandsInterface.setRadioPower(oldPowerState, null); + ((GSMPhone)oldPhone).removeReferences(); + oldPhone = null; + } else { + logd("Make a new GSMPhone and destroy the old CDMAPhone."); + + ((CDMAPhone)mActivePhone).dispose(); + //mActivePhone = null; + Phone oldPhone = mActivePhone; + + // Give the GC a hint to start the garbage collection asap + // NOTE this has been disabled since radio technology change could happen during + // e.g. a multimedia playing and could slow the system. Tests needs to be done + // to see the effects of the GC call here when system is busy. + //System.gc(); + + mActivePhone = PhoneFactory.getGsmPhone(); + logd("Resetting Radio:"); + mCommandsInterface.setRadioPower(oldPowerState, null); + ((CDMAPhone)oldPhone).removeReferences(); + oldPhone = null; + } + + //Set the new interfaces in the proxy's + mIccSmsInterfaceManagerProxy.setmIccSmsInterfaceManager( + mActivePhone.getIccSmsInterfaceManager()); + mIccPhoneBookInterfaceManagerProxy.setmIccPhoneBookInterfaceManager( + mActivePhone.getIccPhoneBookInterfaceManager()); + mPhoneSubInfoProxy.setmPhoneSubInfo(this.mActivePhone.getPhoneSubInfo()); + mCommandsInterface = ((PhoneBase)mActivePhone).mCM; + + //Send an Intent to the PhoneApp that we had a radio technology change + Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); + intent.putExtra(Phone.PHONE_NAME_KEY, mActivePhone.getPhoneName()); + ActivityManagerNative.broadcastStickyIntent(intent, null); + + break; + default: + Log.e(LOG_TAG, "Error! This handler was not registered for this message type. Message: " + + msg.what); + break; + } + super.handleMessage(msg); + } + + private void logv(String msg) { + Log.v(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void logd(String msg) { + Log.d(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void logw(String msg) { + Log.w(LOG_TAG, "[PhoneProxy] " + msg); + } + + private void loge(String msg) { + Log.e(LOG_TAG, "[PhoneProxy] " + msg); } + public ServiceState getServiceState() { return mActivePhone.getServiceState(); } @@ -74,18 +161,18 @@ public class PhoneProxy implements Phone { } public DataState getDataConnectionState() { - return mActivePhone.getDataConnectionState(); + return mActivePhone.getDataConnectionState(); } - public DataActivityState getDataActivityState() { - return mActivePhone.getDataActivityState(); + public DataActivityState getDataActivityState() { + return mActivePhone.getDataActivityState(); } public Context getContext() { - return mActivePhone.getContext(); + return mActivePhone.getContext(); } - public State getState() { + public State getState() { return mActivePhone.getState(); } @@ -93,55 +180,55 @@ public class PhoneProxy implements Phone { return mActivePhone.getPhoneName(); } - public String[] getActiveApnTypes() { - return mActivePhone.getActiveApnTypes(); + public String[] getActiveApnTypes() { + return mActivePhone.getActiveApnTypes(); } - public String getActiveApn() { - return mActivePhone.getActiveApn(); + public String getActiveApn() { + return mActivePhone.getActiveApn(); } - public int getSignalStrengthASU() { + public int getSignalStrengthASU() { return mActivePhone.getSignalStrengthASU(); } - public void registerForUnknownConnection(Handler h, int what, Object obj) { + public void registerForUnknownConnection(Handler h, int what, Object obj) { mActivePhone.registerForUnknownConnection(h, what, obj); } - public void unregisterForUnknownConnection(Handler h) { + public void unregisterForUnknownConnection(Handler h) { mActivePhone.unregisterForUnknownConnection(h); } - public void registerForPhoneStateChanged(Handler h, int what, Object obj) { + public void registerForPhoneStateChanged(Handler h, int what, Object obj) { mActivePhone.registerForPhoneStateChanged(h, what, obj); } - public void unregisterForPhoneStateChanged(Handler h) { + public void unregisterForPhoneStateChanged(Handler h) { mActivePhone.unregisterForPhoneStateChanged(h); } - public void registerForNewRingingConnection(Handler h, int what, Object obj) { + public void registerForNewRingingConnection(Handler h, int what, Object obj) { mActivePhone.registerForNewRingingConnection(h, what, obj); } - public void unregisterForNewRingingConnection(Handler h) { + public void unregisterForNewRingingConnection(Handler h) { mActivePhone.unregisterForNewRingingConnection(h); } - public void registerForIncomingRing(Handler h, int what, Object obj) { + public void registerForIncomingRing(Handler h, int what, Object obj) { mActivePhone.registerForIncomingRing(h, what, obj); } - public void unregisterForIncomingRing(Handler h) { + public void unregisterForIncomingRing(Handler h) { mActivePhone.unregisterForIncomingRing(h); } - public void registerForDisconnect(Handler h, int what, Object obj) { + public void registerForDisconnect(Handler h, int what, Object obj) { mActivePhone.registerForDisconnect(h, what, obj); } - public void unregisterForDisconnect(Handler h) { + public void unregisterForDisconnect(Handler h) { mActivePhone.unregisterForDisconnect(h); } @@ -193,23 +280,39 @@ public class PhoneProxy implements Phone { mActivePhone.unregisterForSuppServiceFailed(h); } - public boolean getSimRecordsLoaded() { - return mActivePhone.getSimRecordsLoaded(); + public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){ + mActivePhone.registerForInCallVoicePrivacyOn(h,what,obj); + } + + public void unregisterForInCallVoicePrivacyOn(Handler h){ + mActivePhone.unregisterForInCallVoicePrivacyOn(h); + } + + public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){ + mActivePhone.registerForInCallVoicePrivacyOff(h,what,obj); + } + + public void unregisterForInCallVoicePrivacyOff(Handler h){ + mActivePhone.unregisterForInCallVoicePrivacyOff(h); + } + + public boolean getIccRecordsLoaded() { + return mActivePhone.getIccRecordsLoaded(); } public IccCard getIccCard() { return mActivePhone.getIccCard(); } - public void acceptCall() throws CallStateException { + public void acceptCall() throws CallStateException { mActivePhone.acceptCall(); } - public void rejectCall() throws CallStateException { + public void rejectCall() throws CallStateException { mActivePhone.rejectCall(); } - public void switchHoldingAndActive() throws CallStateException { + public void switchHoldingAndActive() throws CallStateException { mActivePhone.switchHoldingAndActive(); } @@ -217,7 +320,7 @@ public class PhoneProxy implements Phone { return mActivePhone.canConference(); } - public void conference() throws CallStateException { + public void conference() throws CallStateException { mActivePhone.conference(); } @@ -233,7 +336,7 @@ public class PhoneProxy implements Phone { return mActivePhone.canTransfer(); } - public void explicitCallTransfer() throws CallStateException { + public void explicitCallTransfer() throws CallStateException { mActivePhone.explicitCallTransfer(); } @@ -253,7 +356,7 @@ public class PhoneProxy implements Phone { return mActivePhone.getRingingCall(); } - public Connection dial(String dialString) throws CallStateException { + public Connection dial(String dialString) throws CallStateException { return mActivePhone.dial(dialString); } @@ -261,7 +364,7 @@ public class PhoneProxy implements Phone { return mActivePhone.handlePinMmi(dialString); } - public boolean handleInCallMmiCommands(String command) throws CallStateException { + public boolean handleInCallMmiCommands(String command) throws CallStateException { return mActivePhone.handleInCallMmiCommands(command); } @@ -297,7 +400,7 @@ public class PhoneProxy implements Phone { return mActivePhone.getLine1AlphaTag(); } - public void setLine1Number(String alphaTag, String number, Message onComplete) { + public void setLine1Number(String alphaTag, String number, Message onComplete) { mActivePhone.setLine1Number(alphaTag, number, onComplete); } @@ -316,7 +419,7 @@ public class PhoneProxy implements Phone { public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { - mActivePhone.getCallForwardingOption(commandInterfaceCFReason, + mActivePhone.getCallForwardingOption(commandInterfaceCFReason, onComplete); } @@ -331,7 +434,7 @@ public class PhoneProxy implements Phone { mActivePhone.getOutgoingCallerIdDisplay(onComplete); } - public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { mActivePhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode, onComplete); @@ -347,7 +450,7 @@ public class PhoneProxy implements Phone { public void getAvailableNetworks(Message response) { mActivePhone.getAvailableNetworks(response); - } + } public void setNetworkSelectionModeAutomatic(Message response) { mActivePhone.setNetworkSelectionModeAutomatic(response); @@ -362,7 +465,7 @@ public class PhoneProxy implements Phone { } public void getPreferredNetworkType(Message response) { - mActivePhone.getPreferredNetworkType(response) ; + mActivePhone.getPreferredNetworkType(response); } public void getNeighboringCids(Message response) { @@ -389,12 +492,26 @@ public class PhoneProxy implements Phone { mActivePhone.invokeOemRilRequestStrings(strings, response); } + /** + * @deprecated + */ public void getPdpContextList(Message response) { mActivePhone.getPdpContextList(response); } - public List<PdpConnection> getCurrentPdpList () { - return mActivePhone.getCurrentPdpList (); + public void getDataCallList(Message response) { + mActivePhone.getDataCallList(response); + } + + /** + * @deprecated + */ + public List<PdpConnection> getCurrentPdpList() { + return mActivePhone.getCurrentPdpList(); + } + + public List<DataConnection> getCurrentDataConnectionList() { + return mActivePhone.getCurrentDataConnectionList(); } public void updateServiceLocation(Message response) { @@ -436,11 +553,11 @@ public class PhoneProxy implements Phone { public void queryCdmaRoamingPreference(Message response) { mActivePhone.queryCdmaRoamingPreference(response); } - + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { mActivePhone.setCdmaRoamingPreference(cdmaRoamingType, response); } - + public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { mActivePhone.setCdmaSubscription(cdmaSubscriptionType, response); } @@ -510,25 +627,39 @@ public class PhoneProxy implements Phone { } public PhoneSubInfo getPhoneSubInfo(){ - return null; //mActivePhone.getPhoneSubInfo(); + return mActivePhone.getPhoneSubInfo(); } - public IccSmsInterfaceManager getIccSmsInterfaceManager(){ - return null; //mActivePhone.getIccSmsInterfaceManager(); + return mActivePhone.getIccSmsInterfaceManager(); } - public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){ - return null; //mActivePhone.getIccPhoneBookInterfaceManager(); + return mActivePhone.getIccPhoneBookInterfaceManager(); } public void setTTYModeEnabled(boolean enable, Message onComplete) { mActivePhone.setTTYModeEnabled(enable, onComplete); } - + public void queryTTYModeEnabled(Message onComplete) { mActivePhone.queryTTYModeEnabled(onComplete); } + + public void activateCellBroadcastSms(int activate, Message response) { + mActivePhone.activateCellBroadcastSms(activate, response); + } + + public void getCellBroadcastSmsConfig(Message response) { + mActivePhone.getCellBroadcastSmsConfig(response); + } + + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) { + mActivePhone.setCellBroadcastSmsConfig(configValuesArray, response); + } + + public void notifyDataActivity() { + mActivePhone.notifyDataActivity(); + } } diff --git a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java index c558cd15f1d1..468a1f67e2f5 100644 --- a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java +++ b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java @@ -32,7 +32,7 @@ import android.telephony.ServiceState; * * Use android.telephony.TelephonyManager and PhoneStateListener instead. * - * + * */ @Deprecated public final class PhoneStateIntentReceiver extends BroadcastReceiver { @@ -184,7 +184,7 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver { if (TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED.equals(action)) { mAsu = intent.getIntExtra(INTENT_KEY_ASU, mAsu); if (DBG) Log.d(LOG_TAG, "onReceiveIntent: set asu=" + mAsu); - + if (mTarget != null && getNotifySignalStrength()) { Message message = Message.obtain(mTarget, mAsuEventWhat); mTarget.sendMessage(message); diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java index 01f34426e747..4d1f7e5f1331 100644 --- a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java +++ b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java @@ -16,9 +16,10 @@ package com.android.internal.telephony; import android.content.Context; - +import android.util.Log; public class PhoneSubInfo extends IPhoneSubInfo.Stub { + static final String LOG_TAG = "PHONE"; private Phone mPhone; private Context mContext; private static final String READ_PHONE_STATE = @@ -28,8 +29,16 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub { mPhone = phone; mContext = phone.getContext(); } + + public void dispose() { + } + + protected void finalize() { + Log.d(LOG_TAG, "PhoneSubInfo finalized"); + } + /** - * Retrieves the unique device ID, e.g., IMEI for GSM phones. + * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones. */ public String getDeviceId() { mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE"); diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java index 87102a92d740..450b3a70d88b 100644 --- a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java +++ b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java @@ -16,16 +16,21 @@ package com.android.internal.telephony; -import android.content.Context; import android.os.ServiceManager; -import com.android.internal.telephony.*; + public class PhoneSubInfoProxy extends IPhoneSubInfo.Stub { private PhoneSubInfo mPhoneSubInfo; public PhoneSubInfoProxy(PhoneSubInfo phoneSubInfo) { mPhoneSubInfo = phoneSubInfo; - ServiceManager.addService("iphonesubinfo", this); + if(ServiceManager.getService("iphonesubinfo") == null) { + ServiceManager.addService("iphonesubinfo", this); + } + } + + public void setmPhoneSubInfo(PhoneSubInfo phoneSubInfo) { + this.mPhoneSubInfo = phoneSubInfo; } public String getDeviceId() { diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index 568c86c5fc56..d995075d555e 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -16,43 +16,45 @@ package com.android.internal.telephony; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.BroadcastReceiver; -import com.android.internal.telephony.CallForwardInfo; -import com.android.internal.telephony.RILConstants; -import com.android.internal.telephony.gsm.CommandException; -import com.android.internal.telephony.gsm.NetworkInfo; -import com.android.internal.telephony.gsm.PDPContextState; -import com.android.internal.telephony.IccUtils; -import com.android.internal.telephony.gsm.SmsResponse; -import com.android.internal.telephony.gsm.SuppServiceNotification; - -import android.os.Parcel; -import java.io.IOException; -import android.os.Message; -import android.os.Handler; -import android.net.LocalSocketAddress; import android.net.LocalSocket; -import com.android.internal.os.HandlerThread; +import android.net.LocalSocketAddress; +import android.os.AsyncResult; +import android.os.Handler; import android.os.HandlerInterface; -import java.util.ArrayList; -import java.util.Collections; -import java.io.InputStream; +import android.os.Message; +import android.os.Parcel; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; import android.telephony.PhoneNumberUtils; -import android.telephony.gsm.SmsManager; -import android.telephony.gsm.SmsMessage; +import android.telephony.SmsManager; +import android.telephony.SmsMessage; import android.util.Log; import android.util.Config; -import android.os.AsyncResult; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; -import com.android.internal.telephony.IccCardStatus; +import static com.android.internal.telephony.RILConstants.*; + +import com.android.internal.os.HandlerThread; +import com.android.internal.telephony.CallForwardInfo; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.gsm.NetworkInfo; +import com.android.internal.telephony.gsm.PDPContextState; +import com.android.internal.telephony.gsm.SuppServiceNotification; import com.android.internal.telephony.IccCardApplication; +import com.android.internal.telephony.IccCardStatus; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.RILConstants; +import com.android.internal.telephony.SmsResponse; -import static com.android.internal.telephony.RILConstants.*; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; /** * {@hide} @@ -77,14 +79,14 @@ class RILRequest { /** * Retrieves a new RILRequest instance from the pool. - * + * * @param request RIL_REQUEST_* * @param result sent when operation completes * @return a RILRequest instance from the pool. */ static RILRequest obtain(int request, Message result) { RILRequest rr = null; - + synchronized(sPoolSync) { if (sPool != null) { rr = sPool; @@ -93,7 +95,7 @@ class RILRequest { sPoolSize--; } } - + if (rr == null) { rr = new RILRequest(); } @@ -118,7 +120,7 @@ class RILRequest { /** * Returns a RILRequest instance to the pool. - * + * * Note: This should only be called once per use. */ void release() { @@ -167,7 +169,7 @@ class RILRequest { ex = CommandException.fromRilErrno(error); if (RIL.RILJ_LOG) Log.d(LOG_TAG, serialString() + "< " - + RIL.requestToString(mRequest) + + RIL.requestToString(mRequest) + " error: " + ex); if (mResult != null) { @@ -186,7 +188,7 @@ class RILRequest { /** * RIL implementation of the CommandsInterface. * FIXME public only for testing - * + * * {@hide} */ public final class RIL extends BaseCommands implements CommandsInterface { @@ -212,7 +214,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { //I'd rather this be LinkedList or something ArrayList<RILRequest> mRequestsList = new ArrayList<RILRequest>(); - + Object mLastNITZTimeInfo; //***** Events @@ -243,7 +245,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { } } }; - + class RILSender implements HandlerInterface,Runnable { // Only allocated once byte[] dataLength = new byte[4]; @@ -261,7 +263,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { handleMessage(Message msg) { RILRequest rr = (RILRequest)(msg.obj); RILRequest req = null; - + switch (msg.what) { case EVENT_SEND: /** @@ -298,7 +300,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { if (data.length > RIL_MAX_COMMAND_BYTES) { throw new RuntimeException( - "Parcel larger than max bytes allowed! " + "Parcel larger than max bytes allowed! " + data.length); } @@ -309,7 +311,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { //Log.v(LOG_TAG, "writing packet: " + data.length + " bytes"); - s.getOutputStream().write(dataLength); + s.getOutputStream().write(dataLength); s.getOutputStream().write(data); } catch (IOException ex) { Log.e(LOG_TAG, "IOException", ex); @@ -349,12 +351,12 @@ public final class RIL extends BaseCommands implements CommandsInterface { Log.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " + " mReqPending=" + mRequestMessagesPending + " mRequestList=" + count); - + for (int i = 0; i < count; i++) { rr = mRequestsList.get(i); Log.d(LOG_TAG, i + ": [" + rr.mSerial + "] " + requestToString(rr.mRequest)); - + } } } @@ -436,7 +438,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void run() { int retryCount = 0; - + try {for (;;) { LocalSocket s = null; LocalSocketAddress l; @@ -454,23 +456,23 @@ public final class RIL extends BaseCommands implements CommandsInterface { } catch (IOException ex2) { //ignore failure to close after failure to connect } - + // don't print an error message after the the first time // or after the 8th time if (retryCount == 8) { - Log.e (LOG_TAG, + Log.e (LOG_TAG, "Couldn't find '" + SOCKET_NAME_RIL + "' socket after " + retryCount + " times, continuing to retry silently"); } else if (retryCount > 0 && retryCount < 8) { - Log.i (LOG_TAG, + Log.i (LOG_TAG, "Couldn't find '" + SOCKET_NAME_RIL + "' socket; retrying after timeout"); } try { - Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); + Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); } catch (InterruptedException er) { } @@ -486,7 +488,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { int length = 0; try { InputStream is = mSocket.getInputStream(); - + for (;;) { Parcel p; @@ -517,9 +519,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { + "' socket"); setRadioState (RadioState.RADIO_UNAVAILABLE); - + try { - mSocket.close(); + mSocket.close(); } catch (IOException ex) { } @@ -545,8 +547,10 @@ public final class RIL extends BaseCommands implements CommandsInterface { //***** Constructors - public RIL(Context context) { - this(context, RILConstants.NETWORK_MODE_GLOBAL, RILConstants.SUBSCRIPTION_FROM_RUIM); + public + RIL(Context context) { + this(context, RILConstants.PREFERRED_NETWORK_MODE, + RILConstants.PREFERRED_CDMA_SUBSCRIPTION); } public RIL(Context context, int networkMode, int cdmaSubscription) { @@ -554,14 +558,27 @@ public final class RIL extends BaseCommands implements CommandsInterface { mCdmaSubscription = cdmaSubscription; mNetworkMode = networkMode; //At startup mPhoneType is first set from networkMode - if(networkMode == RILConstants.NETWORK_MODE_GSM_UMTS) { - mPhoneType = RILConstants.GSM_PHONE; - } else { - mPhoneType = RILConstants.CDMA_PHONE; + switch(networkMode) { + case RILConstants.NETWORK_MODE_WCDMA_PREF: + case RILConstants.NETWORK_MODE_GSM_ONLY: + case RILConstants.NETWORK_MODE_WCDMA_ONLY: + case RILConstants.NETWORK_MODE_GSM_UMTS: + mPhoneType = RILConstants.GSM_PHONE; + break; + case RILConstants.NETWORK_MODE_CDMA: + case RILConstants.NETWORK_MODE_CDMA_NO_EVDO: + case RILConstants.NETWORK_MODE_EVDO_NO_CDMA: + mPhoneType = RILConstants.CDMA_PHONE; + break; + case RILConstants.NETWORK_MODE_GLOBAL: + mPhoneType = RILConstants.CDMA_PHONE; + break; + default: + mPhoneType = RILConstants.CDMA_PHONE; } PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); mWakeLock.setReferenceCounted(false); mRequestMessagesPending = 0; @@ -581,7 +598,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { //***** CommandsInterface implementation - @Override public void + @Override public void setOnNITZTime(Handler h, int what, Object obj) { super.setOnNITZTime(h, what, obj); @@ -594,10 +611,10 @@ public final class RIL extends BaseCommands implements CommandsInterface { } } - public void + public void getIccStatus(Message result) { - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -605,10 +622,10 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void supplyIccPin(String pin, Message result) { - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -619,10 +636,10 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void supplyIccPuk(String puk, String newPin, Message result) { - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -634,10 +651,10 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void supplyIccPin2(String pin, Message result) { - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN2, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -648,10 +665,10 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void supplyIccPuk2(String puk, String newPin2, Message result) { - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK2, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -665,8 +682,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void changeIccPin(String oldPin, String newPin, Message result) { - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -680,8 +697,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void changeIccPin2(String oldPin2, String newPin2, Message result) { - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN2, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -707,7 +724,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void supplyNetworkDepersonalization(String netpin, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result); @@ -718,8 +735,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - - public void + + public void getCurrentCalls (Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result); @@ -728,16 +745,21 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void getPDPContextList(Message result) { - RILRequest rr = RILRequest.obtain(RIL_REQUEST_PDP_CONTEXT_LIST, result); + getDataCallList(result); + } + + public void + getDataCallList(Message result) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DATA_CALL_LIST, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); } - public void + public void dial (String address, int clirMode, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result); @@ -749,7 +771,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void getIMSI(Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result); @@ -780,13 +802,14 @@ public final class RIL extends BaseCommands implements CommandsInterface { } - public void + public void hangupConnection (int gsmIndex, Message result) { if (RILJ_LOG) riljLog("hangupConnection: gsmIndex=" + gsmIndex); RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP, result); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + gsmIndex); + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + + gsmIndex); rr.mp.writeInt(1); rr.mp.writeInt(gsmIndex); @@ -794,9 +817,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void hangupWaitingOrBackground (Message result) { - RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, + RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -806,9 +829,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void hangupForegroundResumeBackground (Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain( - RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, + RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -817,9 +840,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void switchWaitingOrHoldingAndActive (Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain( - RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, + RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -828,7 +851,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void conference (Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CONFERENCE, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -840,13 +863,13 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void setPreferredVoicePrivacy(boolean enable, Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, result); - + rr.mp.writeInt(1); rr.mp.writeInt(enable ? 1:0); - + send(rr); } - + public void getPreferredVoicePrivacy(Message result) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, result); @@ -855,7 +878,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void separateConnection (int gsmIndex, Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEPARATE_CONNECTION, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -869,7 +892,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void acceptCall (Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_ANSWER, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -877,9 +900,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void rejectCall (Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_UDUB, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -899,7 +922,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void getLastCallFailCause (Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -907,10 +930,21 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + /** + * @deprecated + */ + public void getLastPdpFailCause (Message result) { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_LAST_PDP_FAIL_CAUSE, result); + getLastDataCallFailCause (result); + } + + /** + * The preferred new alternative to getLastPdpFailCause + */ + public void + getLastDataCallFailCause (Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -919,7 +953,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void setMute (boolean enableMute, Message response) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_MUTE, response); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -933,7 +967,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void getMute (Message response) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_MUTE, response); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -943,7 +977,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void getSignalStrength (Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SIGNAL_STRENGTH, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -951,9 +985,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void getRegistrationState (Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_REGISTRATION_STATE, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -961,9 +995,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void getGPRSRegistrationState (Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GPRS_REGISTRATION_STATE, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -971,9 +1005,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void getOperator(Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_OPERATOR, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -981,13 +1015,13 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void sendDtmf(char c, Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_DTMF, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + rr.mp.writeString(Character.toString(c)); send(rr); @@ -1018,7 +1052,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void sendSMS (String smscPDU, String pdu, Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result); rr.mp.writeInt(2); @@ -1026,20 +1060,83 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr.mp.writeString(pdu); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + + send(rr); + } + + public void + sendCdmaSms(byte[] pdu, Message result) { + int address_nbr_of_digits; + int subaddr_nbr_of_digits; + int bearerDataLength; + ByteArrayInputStream bais = new ByteArrayInputStream(pdu); + DataInputStream dis = new DataInputStream(bais); + + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_CDMA_SEND_SMS, result); + + try { + rr.mp.writeInt(dis.readInt()); //teleServiceId + rr.mp.writeInt(dis.readInt()); //servicePresent + rr.mp.writeInt(dis.readInt()); //serviceCategory + rr.mp.writeInt(dis.read()); //address_digit_mode + rr.mp.writeInt(dis.read()); //address_nbr_mode + rr.mp.writeInt(dis.read()); //address_ton + rr.mp.writeInt(dis.read()); //address_nbr_plan + address_nbr_of_digits = (byte) dis.read(); + rr.mp.writeInt(address_nbr_of_digits); + for(int i=0; i < address_nbr_of_digits; i++){ + rr.mp.writeInt(dis.readByte()); // address_orig_bytes[i] + } + rr.mp.writeInt(dis.read()); //subaddressType + rr.mp.writeInt(dis.read()); //subaddr_odd + subaddr_nbr_of_digits = (byte) dis.read(); + rr.mp.writeInt(subaddr_nbr_of_digits); + for(int i=0; i < subaddr_nbr_of_digits; i++){ + rr.mp.writeInt(dis.readByte()); //subaddr_orig_bytes[i] + } + + bearerDataLength = dis.read(); + rr.mp.writeInt(bearerDataLength); + for(int i=0; i < bearerDataLength; i++){ + rr.mp.writeInt(dis.readByte()); //bearerData[i] + } + }catch (IOException ex){ + if (RILJ_LOG) riljLog("sendSmsCdma: conversion from input stream to object failed: " + + ex); + } + + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + send(rr); } public void deleteSmsOnSim(int index, Message response) { RILRequest rr = RILRequest.obtain(RIL_REQUEST_DELETE_SMS_ON_SIM, response); - + rr.mp.writeInt(1); rr.mp.writeInt(index); - if (Config.LOGD) { + if (Config.LOGD) { if (RILJ_LOG) riljLog(rr.serialString() + "> " - + requestToString(rr.mRequest) + + requestToString(rr.mRequest) + + " " + index); + } + + send(rr); + } + + public void deleteSmsOnRuim(int index, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM, + response); + + rr.mp.writeInt(1); + rr.mp.writeInt(index); + + if (Config.LOGD) { + if (RILJ_LOG) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + index); } @@ -1048,17 +1145,35 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void writeSmsToSim(int status, String smsc, String pdu, Message response) { status = translateStatus(status); - + RILRequest rr = RILRequest.obtain(RIL_REQUEST_WRITE_SMS_TO_SIM, response); - + rr.mp.writeInt(status); rr.mp.writeString(pdu); rr.mp.writeString(smsc); - - if (Config.LOGD) { + + if (Config.LOGD) { if (RILJ_LOG) riljLog(rr.serialString() + "> " - + requestToString(rr.mRequest) + + requestToString(rr.mRequest) + + " " + status); + } + + send(rr); + } + + public void writeSmsToRuim(int status, String pdu, Message response) { + status = translateStatus(status); + + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM, + response); + + rr.mp.writeInt(status); + rr.mp.writeString(pdu); + + if (Config.LOGD) { + if (RILJ_LOG) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + status); } @@ -1071,46 +1186,76 @@ public final class RIL extends BaseCommands implements CommandsInterface { */ private int translateStatus(int status) { switch(status & 0x7) { - case SmsManager.STATUS_ON_SIM_READ: + case SmsManager.STATUS_ON_ICC_READ: return 1; - case SmsManager.STATUS_ON_SIM_UNREAD: + case SmsManager.STATUS_ON_ICC_UNREAD: return 0; - case SmsManager.STATUS_ON_SIM_SENT: + case SmsManager.STATUS_ON_ICC_SENT: return 3; - case SmsManager.STATUS_ON_SIM_UNSENT: + case SmsManager.STATUS_ON_ICC_UNSENT: return 2; } - + // Default to READ. return 1; } - public void + /** + * @deprecated + */ + public void setupDefaultPDP(String apn, String user, String password, Message result) { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_SETUP_DEFAULT_PDP, result); + String radioTechnology = "1"; //0 for CDMA, 1 for GSM/UMTS + String profile = ""; //profile number, NULL for GSM/UMTS + setupDataCall(radioTechnology, profile, apn, user, + password, result); - rr.mp.writeInt(3); + } + + /** + * @deprecated + */ + public void + deactivateDefaultPDP(int cid, Message result) { + deactivateDataCall(cid, result); + } + + /** + * The preferred new alternative to setupDefaultPDP that is + * CDMA-compatible. + * + */ + public void + setupDataCall(String radioTechnology, String profile, String apn, + String user, String password, Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result); + + rr.mp.writeInt(5); + + rr.mp.writeString(radioTechnology); + rr.mp.writeString(profile); rr.mp.writeString(apn); rr.mp.writeString(user); rr.mp.writeString(password); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + apn); - + send(rr); } public void - deactivateDefaultPDP(int cid, Message result) { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_DEACTIVATE_DEFAULT_PDP, result); + deactivateDataCall(int cid, Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_DEACTIVATE_DATA_CALL, result); rr.mp.writeInt(1); rr.mp.writeString(Integer.toString(cid)); - if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + cid); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + + requestToString(rr.mRequest) + " " + cid); + send(rr); } @@ -1120,25 +1265,13 @@ public final class RIL extends BaseCommands implements CommandsInterface { if(mInitialRadioStateChange) { synchronized (mStateMonitor) { if (!mState.isOn()) { - int modemNetworkMode; - switch(mNetworkMode) { - case RILConstants.NETWORK_MODE_GSM_UMTS: - modemNetworkMode = Phone.NT_GSM_UMTS_AUTO_TYPE; - break; - case RILConstants.NETWORK_MODE_CDMA: - modemNetworkMode = Phone.NT_CDMA_EVDO_AUTO_TYPE; - break; - case RILConstants.NETWORK_MODE_GLOBAL: - default: - modemNetworkMode = Phone.NT_GLOBAL_AUTO_TYPE; - } RILRequest rrPnt = RILRequest.obtain( RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, null); rrPnt.mp.writeInt(1); - rrPnt.mp.writeInt(modemNetworkMode); - if (RILJ_LOG) riljLog(rrPnt.serialString() + "> " - + requestToString(rrPnt.mRequest) + " : " + modemNetworkMode); + rrPnt.mp.writeInt(mNetworkMode); + if (RILJ_LOG) riljLog(rrPnt.serialString() + "> " + + requestToString(rrPnt.mRequest) + " : " + mNetworkMode); send(rrPnt); @@ -1146,31 +1279,31 @@ public final class RIL extends BaseCommands implements CommandsInterface { RIL_REQUEST_CDMA_SET_SUBSCRIPTION, null); rrCs.mp.writeInt(1); rrCs.mp.writeInt(mCdmaSubscription); - if (RILJ_LOG) riljLog(rrCs.serialString() + "> " - + requestToString(rrCs.mRequest) + " : " + mCdmaSubscription); - send(rrCs); + if (RILJ_LOG) riljLog(rrCs.serialString() + "> " + + requestToString(rrCs.mRequest) + " : " + mCdmaSubscription); + send(rrCs); } } } - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result); rr.mp.writeInt(1); rr.mp.writeInt(on ? 1 : 0); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } public void setSuppServiceNotifications(boolean enable, Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, result); rr.mp.writeInt(1); rr.mp.writeInt(enable ? 1 : 0); - + if (Config.LOGD) { if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -1179,27 +1312,42 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - public void + public void acknowledgeLastIncomingSMS(boolean success, Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SMS_ACKNOWLEDGE, result); rr.mp.writeInt(1); rr.mp.writeInt(success ? 1 : 0); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } - + public void - iccIO (int command, int fileid, String path, int p1, int p2, int p3, + acknowledgeLastIncomingCdmaSms(boolean success, Message result) { + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, result); + + rr.mp.writeInt(success ? 0 : 1); //RIL_CDMA_SMS_ErrorClass + // cause code according to X.S004-550E + rr.mp.writeInt(39); //39 means other terminal problem; is not interpreted for success. + + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); + + send(rr); + } + + + public void + iccIO (int command, int fileid, String path, int p1, int p2, int p3, String data, String pin2, Message result) { - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM - RILRequest rr + //Note: This RIL request has not been renamed to ICC, + // but this request is also valid for SIM and RUIM + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SIM_IO, result); - + rr.mp.writeInt(command); rr.mp.writeInt(fileid); rr.mp.writeString(path); @@ -1210,47 +1358,47 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr.mp.writeString(pin2); if (RILJ_LOG) riljLog(rr.serialString() + "> iccIO: " + requestToString(rr.mRequest) - + " 0x" + Integer.toHexString(command) - + " 0x" + Integer.toHexString(fileid) + " " + + " 0x" + Integer.toHexString(command) + + " 0x" + Integer.toHexString(fileid) + " " + p1 + "," + p2 + "," + p3); - + send(rr); } - + public void getCLIR(Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CLIR, result); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } public void setCLIR(int clirMode, Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CLIR, result); // count ints rr.mp.writeInt(1); rr.mp.writeInt(clirMode); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + clirMode); - + send(rr); } public void queryCallWaiting(int serviceClass, Message response) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_CALL_WAITING, response); rr.mp.writeInt(1); rr.mp.writeInt(serviceClass); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + serviceClass); @@ -1259,70 +1407,70 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void setCallWaiting(boolean enable, int serviceClass, Message response) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CALL_WAITING, response); - + rr.mp.writeInt(2); rr.mp.writeInt(enable ? 1 : 0); rr.mp.writeInt(serviceClass); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + enable + ", " + serviceClass); - + send(rr); } public void setNetworkSelectionModeAutomatic(Message response) { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, response); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } - public void + public void setNetworkSelectionModeManual(String operatorNumeric, Message response) { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL, response); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + operatorNumeric); rr.mp.writeString(operatorNumeric); - + send(rr); } - public void + public void getNetworkSelectionMode(Message response) { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE, response); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } - public void + public void getAvailableNetworks(Message response) { - RILRequest rr - = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, + RILRequest rr + = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS, response); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); - + send(rr); } public void - setCallForward(int action, int cfReason, int serviceClass, + setCallForward(int action, int cfReason, int serviceClass, String number, int timeSeconds, Message response) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_CALL_FORWARD, response); rr.mp.writeInt(action); @@ -1331,18 +1479,18 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr.mp.writeInt(PhoneNumberUtils.toaFromString(number)); rr.mp.writeString(number); rr.mp.writeInt (timeSeconds); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) - + " " + action + " " + cfReason + " " + serviceClass + + " " + action + " " + cfReason + " " + serviceClass + timeSeconds); - + send(rr); } public void queryCallForwardStatus(int cfReason, int serviceClass, String number, Message response) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, response); rr.mp.writeInt(2); // 2 is for query action, not in used anyway @@ -1351,7 +1499,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr.mp.writeInt(PhoneNumberUtils.toaFromString(number)); rr.mp.writeString(number); rr.mp.writeInt (0); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + cfReason + " " + serviceClass); @@ -1371,9 +1519,9 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void getBasebandVersion (Message response) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_BASEBAND_VERSION, response); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); send(rr); @@ -1387,7 +1535,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); // count strings - rr.mp.writeInt(3); + rr.mp.writeInt(3); rr.mp.writeString(facility); rr.mp.writeString(password); @@ -1418,10 +1566,10 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - + public void sendUSSD (String ussdString, Message response) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_SEND_USSD, response); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -1445,7 +1593,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void resetRadio(Message result) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_RESET_RADIO, result); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -1454,7 +1602,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { } public void invokeOemRilRequestRaw(byte[] data, Message response) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_RAW, response); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) @@ -1467,7 +1615,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { } public void invokeOemRilRequestStrings(String[] strings, Message response) { - RILRequest rr + RILRequest rr = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_STRINGS, response); if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)); @@ -1604,10 +1752,10 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_LOCATION_UPDATES, response); rr.mp.writeInt(1); rr.mp.writeInt(enable ? 1 : 0); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + enable); - + send(rr); } @@ -1617,12 +1765,12 @@ public final class RIL extends BaseCommands implements CommandsInterface { RILRequest rr = RILRequest.obtain(RIL_REQUEST_SCREEN_STATE, null); rr.mp.writeInt(1); rr.mp.writeInt(on ? 1 : 0); - + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + on); - + send(rr); } - + protected void onRadioAvailable() { // In case screen state was lost (due to process crash), @@ -1649,7 +1797,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { case 8: newState = RadioState.NV_NOT_READY; break; case 9: newState = RadioState.NV_READY; break; - default: + default: throw new RuntimeException( "Unrecognized RIL_RadioState: " +state); } @@ -1666,7 +1814,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { setRadioPower(false, null); } else { if (DBG) Log.d(LOG_TAG, "Radio OFF @ init"); - setRadioState(newState); + setRadioState(newState); } mInitialRadioStateChange = false; } else { @@ -1679,7 +1827,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { * a) There is outstanding RIL request sent to RIL deamon and no replied * b) There is a request waiting to be sent out. * - * There is a WAKE_LOCK_TIMEOUT to release the lock, though it shouldn't + * There is a WAKE_LOCK_TIMEOUT to release the lock, though it shouldn't * happen often. */ @@ -1728,13 +1876,11 @@ public final class RIL extends BaseCommands implements CommandsInterface { processUnsolicited (p); } else if (type == RESPONSE_SOLICITED) { processSolicited (p); - } + } releaseWakeLockIfDone(); } - - private RILRequest findAndRemoveRequestFromList(int serial) { synchronized (mRequestsList) { for (int i = 0, s = mRequestsList.size() ; i < s ; i++) { @@ -1763,7 +1909,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr = findAndRemoveRequestFromList(serial); if (rr == null) { - Log.w(LOG_TAG, "Unexpected solicited response! sn: " + Log.w(LOG_TAG, "Unexpected solicited response! sn: " + serial + " error: " + error); return; } @@ -1775,16 +1921,13 @@ public final class RIL extends BaseCommands implements CommandsInterface { } Object ret; - + try {switch (rr.mRequest) { /* cat libs/telephony/ril_commands.h \ | egrep "^ *{RIL_" \ | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/' */ - //TODO T: start - // These RIL requests will not be renamed to ICC, - // but these requests are also valid for SIM and RUIM case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break; case RIL_REQUEST_ENTER_SIM_PIN: ret = responseVoid(p); break; case RIL_REQUEST_ENTER_SIM_PUK: ret = responseVoid(p); break; @@ -1792,7 +1935,6 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseVoid(p); break; case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseVoid(p); break; case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseVoid(p); break; - //TODO T: end case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseVoid(p); break; case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break; case RIL_REQUEST_DIAL: ret = responseVoid(p); break; @@ -1812,9 +1954,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_DTMF: ret = responseVoid(p); break; case RIL_REQUEST_SEND_SMS: ret = responseSMS(p); break; case RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret = responseSMS(p); break; - case RIL_REQUEST_SETUP_DEFAULT_PDP: ret = responseStrings(p); break; - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM + case RIL_REQUEST_SETUP_DATA_CALL: ret = responseStrings(p); break; case RIL_REQUEST_SIM_IO: ret = responseICC_IO(p); break; case RIL_REQUEST_SEND_USSD: ret = responseVoid(p); break; case RIL_REQUEST_CANCEL_USSD: ret = responseVoid(p); break; @@ -1828,7 +1968,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_GET_IMEI: ret = responseString(p); break; case RIL_REQUEST_GET_IMEISV: ret = responseString(p); break; case RIL_REQUEST_ANSWER: ret = responseVoid(p); break; - case RIL_REQUEST_DEACTIVATE_DEFAULT_PDP: ret = responseVoid(p); break; + case RIL_REQUEST_DEACTIVATE_DATA_CALL: ret = responseVoid(p); break; case RIL_REQUEST_QUERY_FACILITY_LOCK: ret = responseInts(p); break; case RIL_REQUEST_SET_FACILITY_LOCK: ret = responseVoid(p); break; case RIL_REQUEST_CHANGE_BARRING_PASSWORD: ret = responseVoid(p); break; @@ -1840,30 +1980,30 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_DTMF_STOP: ret = responseVoid(p); break; case RIL_REQUEST_BASEBAND_VERSION: ret = responseString(p); break; case RIL_REQUEST_SEPARATE_CONNECTION: ret = responseVoid(p); break; - case RIL_REQUEST_SET_MUTE: ret =responseVoid(p); break; - case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break; - case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break; - case RIL_REQUEST_LAST_PDP_FAIL_CAUSE: ret = responseInts(p); break; - case RIL_REQUEST_PDP_CONTEXT_LIST: ret = responseContextList(p); break; - case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break; - case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break; - case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break; + case RIL_REQUEST_SET_MUTE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break; + case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break; + case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: ret = responseInts(p); break; + case RIL_REQUEST_DATA_CALL_LIST: ret = responseDataCallList(p); break; + case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break; + case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break; + case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break; case RIL_REQUEST_SCREEN_STATE: ret = responseVoid(p); break; - case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break; - case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break; - case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break; - case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break; - case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break; - case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break; - case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break; - case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break; - case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break; - case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break; - case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break; - case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break; - case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseInts(p); break; - case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseStrings(p); break; - case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break; + case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break; + case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break; + case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break; + case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break; + case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break; + case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break; + case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break; + case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break; + case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break; + case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break; + case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break; + case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseInts(p); break; + case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseStrings(p); break; + case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break; case RIL_REQUEST_CDMA_SET_SUBSCRIPTION: ret = responseVoid(p); break; case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: ret = responseVoid(p); break; case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: ret = responseInts(p); break; @@ -1880,24 +2020,21 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: ret = responseCDMA_BR_CNF(p); break; case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: ret = responseVoid(p); break; case RIL_REQUEST_BROADCAST_ACTIVATION: ret = responseVoid(p); break; - case RIL_REQUEST_SETUP_DATA_CALL: ret = responseStrings(p); break; - case RIL_REQUEST_DEACTIVATE_DATA_CALL: ret = responseVoid(p); break; case RIL_REQUEST_CDMA_VALIDATE_AKEY: ret = responseVoid(p); break; case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: ret = responseVoid(p); break; - case RIL_REQUEST_CDMA_ENCODE_SMS: ret = responseRIL_CDMA_Encoded_SMS(p); break; - case RIL_REQUEST_CDMA_DECODE_SMS: ret = responseRIL_CDMA_SMS_ClientBd(p); break; case RIL_REQUEST_CDMA_SUBSCRIPTION: ret = responseStrings(p); break; case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret = responseInts(p); break; case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret = responseVoid(p); break; - case RIL_REQUEST_DEVICE_IDENTITY: ret = responseStrings(p); break; + case RIL_REQUEST_DEVICE_IDENTITY: ret = responseStrings(p); break; default: - throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); + throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest); //break; }} catch (Throwable tr) { // Exceptions here usually mean invalid RIL responses - - Log.w(LOG_TAG, rr.serialString() + "< " - + requestToString(rr.mRequest) + " exception, possible invalid RIL response", tr); + + Log.w(LOG_TAG, rr.serialString() + "< " + + requestToString(rr.mRequest) + + " exception, possible invalid RIL response", tr); if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, null, tr); @@ -1909,12 +2046,12 @@ public final class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOG) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest) + " " + retToString(rr.mRequest, ret)); - + if (rr.mResult != null) { AsyncResult.forMessage(rr.mResult, ret, null); rr.mResult.sendToTarget(); } - + rr.release(); } @@ -1994,26 +2131,24 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_UNSOL_ON_USSD: ret = responseStrings(p); break; case RIL_UNSOL_NITZ_TIME_RECEIVED: ret = responseString(p); break; case RIL_UNSOL_SIGNAL_STRENGTH: ret = responseInts(p); break; - case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED: ret = responseContextList(p);break; + case RIL_UNSOL_DATA_CALL_LIST_CHANGED: ret = responseDataCallList(p);break; case RIL_UNSOL_SUPP_SVC_NOTIFICATION: ret = responseSuppServiceNotification(p); break; case RIL_UNSOL_STK_SESSION_END: ret = responseVoid(p); break; case RIL_UNSOL_STK_PROACTIVE_COMMAND: ret = responseString(p); break; case RIL_UNSOL_STK_EVENT_NOTIFY: ret = responseString(p); break; case RIL_UNSOL_STK_CALL_SETUP: ret = responseInts(p); break; case RIL_UNSOL_SIM_SMS_STORAGE_FULL: ret = responseVoid(p); break; - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM case RIL_UNSOL_SIM_REFRESH: ret = responseInts(p); break; case RIL_UNSOL_CALL_RING: ret = responseVoid(p); break; case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: ret = responseVoid(p); break; - case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: ret = responseCDMA_SMS(p); break; + case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: ret = responseCdmaSms(p); break; case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: ret = responseString(p); break; case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: ret = responseVoid(p); break; - default: - throw new RuntimeException("Unrecognized unsol response: " + response); + default: + throw new RuntimeException("Unrecognized unsol response: " + response); //break; (implied) }} catch (Throwable tr) { - Log.e(LOG_TAG, "Exception processing unsol response: " + Log.e(LOG_TAG, "Exception processing unsol response: " + response, tr); return; } @@ -2022,7 +2157,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: /* has bonus radio state int */ setRadioStateFromRILInt(p.readInt()); - + if (RILJ_LOG) riljLog("[UNSL]< RADIO_STATE_CHANGED " +mState); break; case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: @@ -2047,7 +2182,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { SmsMessage sms; - sms = SmsMessage.newFromCMT(a); + sms = SmsMessage.newFromCMT(a); if (mSMSRegistrant != null) { mSMSRegistrant .notifyRegistrant(new AsyncResult(null, sms, null)); @@ -2081,7 +2216,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { break; case RIL_UNSOL_ON_USSD: String[] resp = (String[])ret; - + if (resp.length < 2) { resp = new String[2]; resp[0] = ((String[])ret)[0]; @@ -2093,7 +2228,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { new AsyncResult (null, resp, null)); } break; - case RIL_UNSOL_NITZ_TIME_RECEIVED: + case RIL_UNSOL_NITZ_TIME_RECEIVED: if (RILJ_LOG) riljLog("[UNSL]< NITZ_TIME_RECEIVED " + retToString(response, ret)); // has bonus int containing time_t that the NITZ @@ -2106,7 +2241,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { result[1] = Integer.valueOf(nitzReceiveTime); if (mNITZTimeRegistrant != null) { - + mNITZTimeRegistrant .notifyRegistrant(new AsyncResult (null, result, null)); } else { @@ -2114,23 +2249,23 @@ public final class RIL extends BaseCommands implements CommandsInterface { mLastNITZTimeInfo = result; } break; - + case RIL_UNSOL_SIGNAL_STRENGTH: // Note this is set to "verbose" because it happens // frequently if (Config.LOGV) Log.v(LOG_TAG, "[UNSL]< SIGNAL_STRENGTH " + retToString(response, ret)); - + if (mSignalStrengthRegistrant != null) { mSignalStrengthRegistrant.notifyRegistrant( new AsyncResult (null, ret, null)); } break; - case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED: - if (RILJ_LOG) riljLog("[UNSL]< PDP_CONTEXT_CHANGED " + retToString(response, ret)); + case RIL_UNSOL_DATA_CALL_LIST_CHANGED: + if (RILJ_LOG) riljLog("[UNSL]< DATA_CALL_LIST_CHANGED " + + retToString(response, ret)); - mPDPRegistrants - .notifyRegistrants(new AsyncResult(null, ret, null)); + mDataConnectionRegistrants.notifyRegistrants(new AsyncResult(null, ret, null)); break; case RIL_UNSOL_SUPP_SVC_NOTIFICATION: @@ -2197,14 +2332,12 @@ public final class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOG) riljLog("[UNSL]< SIM_SMS_STORAGE_FULL"); } - if (mSimSmsFullRegistrant != null) { - mSimSmsFullRegistrant.notifyRegistrant(); + if (mIccSmsFullRegistrant != null) { + mIccSmsFullRegistrant.notifyRegistrant(); } break; - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM - case RIL_UNSOL_SIM_REFRESH: + case RIL_UNSOL_SIM_REFRESH: if (Config.LOGD) { if (RILJ_LOG) riljLog("[UNSL]< SIM_REFRESH " + retToString(response, ret)); } @@ -2214,31 +2347,44 @@ public final class RIL extends BaseCommands implements CommandsInterface { new AsyncResult (null, ret, null)); } break; - - case RIL_UNSOL_CALL_RING: + + case RIL_UNSOL_CALL_RING: if (Config.LOGD) { if (RILJ_LOG) riljLog("[UNSL]< CALL_RING "); } - + if (mRingRegistrant != null) { mRingRegistrant.notifyRegistrant(); } break; - case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: - // TODO + case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: + if (mIccStatusChangedRegistrants != null) { + mIccStatusChangedRegistrants.notifyRegistrants(); + } break; - + case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: - // TODO + SmsMessage sms = (SmsMessage) ret; + + if (mSMSRegistrant != null) { + mSMSRegistrant + .notifyRegistrant(new AsyncResult(null, sms, null)); + } break; - + case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: - // TODO + // TODO T: waiting for SMS BC feature break; - + case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: - // TODO + if (Config.LOGD) { + if (RILJ_LOG) riljLog("[UNSL]< RUIM_SMS_STORAGE_FULL"); + } + + if (mIccSmsFullRegistrant != null) { + mIccSmsFullRegistrant.notifyRegistrant(); + } break; } } @@ -2291,22 +2437,24 @@ public final class RIL extends BaseCommands implements CommandsInterface { private Object responseSuppServiceNotification(Parcel p) { SuppServiceNotification notification = new SuppServiceNotification(); - + notification.notificationType = p.readInt(); notification.code = p.readInt(); notification.index = p.readInt(); notification.type = p.readInt(); notification.number = p.readString(); - + return notification; } - + private Object - responseCDMA_SMS(Parcel p) { - // TODO - return null; + responseCdmaSms(Parcel p) { + SmsMessage sms; + sms = SmsMessage.newFromParcel(p); + + return sms; } - + private Object responseString(Parcel p) { String response; @@ -2331,7 +2479,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { response[i] = p.readString(); } } - + return response; } @@ -2364,7 +2512,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { int sw1, sw2; byte data[] = null; Message ret; - + sw1 = p.readInt(); sw2 = p.readInt(); @@ -2377,16 +2525,16 @@ public final class RIL extends BaseCommands implements CommandsInterface { responseIccCardStatus(Parcel p) { RadioState currentRadioState; IccCardApplication ca; - + currentRadioState = getRadioState(); - + IccCardStatus status = new IccCardStatus(); status.card_state = status.CardStateFromRILInt(p.readInt()); status.universal_pin_state = status.PinStateFromRILInt(p.readInt()); status.gsm_umts_subscription_app_index = p.readInt(); status.cdma_subscription_app_index = p.readInt(); status.num_applications = p.readInt(); - + // limit to maximum allowed applications if (status.num_applications > IccCardStatus.CARD_MAX_APPS) { status.num_applications = IccCardStatus.CARD_MAX_APPS; @@ -2398,13 +2546,13 @@ public final class RIL extends BaseCommands implements CommandsInterface { ca.app_state = ca.AppStateFromRILInt(p.readInt()); ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt()); ca.aid = p.readString(); - ca.app_label = p.readString(); + ca.app_label = p.readString(); ca.pin1_replaced = p.readInt(); ca.pin1 = p.readInt(); ca.pin2 = p.readInt(); status.application.add(ca); } - + // this is common for all radio technologies if (!status.card_state.isCardPresent()) { return IccStatus.ICC_ABSENT; @@ -2412,25 +2560,25 @@ public final class RIL extends BaseCommands implements CommandsInterface { // check radio technology if( currentRadioState == RadioState.RADIO_OFF || - currentRadioState == RadioState.RADIO_UNAVAILABLE || + currentRadioState == RadioState.RADIO_UNAVAILABLE || currentRadioState == RadioState.SIM_NOT_READY || currentRadioState == RadioState.RUIM_NOT_READY || currentRadioState == RadioState.NV_NOT_READY || currentRadioState == RadioState.NV_READY ) { return IccStatus.ICC_NOT_READY; } - + if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT || currentRadioState == RadioState.SIM_READY || currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || currentRadioState == RadioState.RUIM_READY) { - + int index; - + // check for CDMA radio technology if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT || currentRadioState == RadioState.RUIM_READY) { - index = status.cdma_subscription_app_index; + index = status.cdma_subscription_app_index; } else { index = status.gsm_umts_subscription_app_index; @@ -2442,7 +2590,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { } if (status.application.get(index).app_state.isPukRequired()) { return IccStatus.ICC_PUK; - } + } if (status.application.get(index).app_state.isSubscriptionPersoEnabled()) { return IccStatus.ICC_NETWORK_PERSONALIZATION; } @@ -2454,11 +2602,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { } return IccStatus.ICC_NOT_READY; } - - // we should never reach this point - //TODO T: start - // These RIL requests will not be renamed to ICC, - // but these requests are also valid for SIM and RUIM + throw new RuntimeException ("Invalid RIL_REQUEST_GET_SIM_STATUS result"); } @@ -2466,6 +2610,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { private Object responseCallList(Parcel p) { int num; + byte voiceSettings; ArrayList<DriverCall> response; DriverCall dc; @@ -2474,14 +2619,15 @@ public final class RIL extends BaseCommands implements CommandsInterface { for (int i = 0 ; i < num ; i++) { dc = new DriverCall(); - + dc.state = DriverCall.stateFromCLCC(p.readInt()); dc.index = p.readInt(); dc.TOA = p.readInt(); dc.isMpty = (0 != p.readInt()); dc.isMT = (0 != p.readInt()); dc.als = p.readInt(); - dc.isVoice = (0 == p.readInt()) ? false : true; + voiceSettings = p.readByte(); + dc.isVoice = (0 == voiceSettings) ? false : true; dc.number = p.readString(); // Make sure there's a leading + on addresses with a TOA @@ -2491,6 +2637,16 @@ public final class RIL extends BaseCommands implements CommandsInterface { dc.number, dc.TOA); response.add(dc); + + if ( RILConstants.CDMA_VOICE_PRIVACY == voiceSettings ) { + mVoicePrivacyOnRegistrants.notifyRegistrants(); + Log.d(LOG_TAG, "InCall VoicePrivacy is enabled: " + + Integer.toString(voiceSettings)); + } else { + mVoicePrivacyOffRegistrants.notifyRegistrants(); + Log.d(LOG_TAG, "InCall VoicePrivacy is disabled: " + + Integer.toString(voiceSettings)); + } } Collections.sort(response); @@ -2499,7 +2655,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { } private Object - responseContextList(Parcel p) { + responseDataCallList(Parcel p) { int num; ArrayList<PDPContextState> response; @@ -2528,7 +2684,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { if (strings.length % 4 != 0) { throw new RuntimeException( - "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got " + strings.length + " strings, expected multible of 4"); } @@ -2542,7 +2698,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { strings[i+2], strings[i+3])); } - + return ret; } @@ -2554,20 +2710,19 @@ public final class RIL extends BaseCommands implements CommandsInterface { private Object responseCDMA_BR_CNF(Parcel p) { - // TODO - return null; - } - - private Object - responseRIL_CDMA_Encoded_SMS(Parcel p) { - // TODO - return null; - } + int numInts; + int response[]; - private Object - responseRIL_CDMA_SMS_ClientBd(Parcel p) { - // TODO - return null; + numInts = p.readInt(); + + response = new int[numInts]; + + response[0] = numInts; + for (int i = 1 ; i < numInts; i++) { + response[i] = p.readInt(); + } + + return response; } static String @@ -2578,9 +2733,6 @@ public final class RIL extends BaseCommands implements CommandsInterface { | sed -re 's/\{RIL_([^,]+),[^,]+,([^}]+).+/case RIL_\1: return "\1";/' */ switch(request) { - //TODO T: start - // These RIL requests will not be renamed to ICC, - // but these requests are also valid for SIM and RUIM case RIL_REQUEST_GET_SIM_STATUS: return "GET_SIM_STATUS"; case RIL_REQUEST_ENTER_SIM_PIN: return "ENTER_SIM_PIN"; case RIL_REQUEST_ENTER_SIM_PUK: return "ENTER_SIM_PUK"; @@ -2588,7 +2740,6 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_ENTER_SIM_PUK2: return "ENTER_SIM_PUK2"; case RIL_REQUEST_CHANGE_SIM_PIN: return "CHANGE_SIM_PIN"; case RIL_REQUEST_CHANGE_SIM_PIN2: return "CHANGE_SIM_PIN2"; - //TODO T: end case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: return "ENTER_NETWORK_DEPERSONALIZATION"; case RIL_REQUEST_GET_CURRENT_CALLS: return "GET_CURRENT_CALLS"; case RIL_REQUEST_DIAL: return "DIAL"; @@ -2608,9 +2759,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_DTMF: return "DTMF"; case RIL_REQUEST_SEND_SMS: return "SEND_SMS"; case RIL_REQUEST_SEND_SMS_EXPECT_MORE: return "SEND_SMS_EXPECT_MORE"; - case RIL_REQUEST_SETUP_DEFAULT_PDP: return "SETUP_DEFAULT_PDP"; - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM + case RIL_REQUEST_SETUP_DATA_CALL: return "SETUP_DATA_CALL"; case RIL_REQUEST_SIM_IO: return "SIM_IO"; case RIL_REQUEST_SEND_USSD: return "SEND_USSD"; case RIL_REQUEST_CANCEL_USSD: return "CANCEL_USSD"; @@ -2624,7 +2773,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_GET_IMEI: return "GET_IMEI"; case RIL_REQUEST_GET_IMEISV: return "GET_IMEISV"; case RIL_REQUEST_ANSWER: return "ANSWER"; - case RIL_REQUEST_DEACTIVATE_DEFAULT_PDP: return "DEACTIVATE_DEFAULT_PDP"; + case RIL_REQUEST_DEACTIVATE_DATA_CALL: return "DEACTIVATE_DATA_CALL"; case RIL_REQUEST_QUERY_FACILITY_LOCK: return "QUERY_FACILITY_LOCK"; case RIL_REQUEST_SET_FACILITY_LOCK: return "SET_FACILITY_LOCK"; case RIL_REQUEST_CHANGE_BARRING_PASSWORD: return "CHANGE_BARRING_PASSWORD"; @@ -2639,8 +2788,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_SET_MUTE: return "SET_MUTE"; case RIL_REQUEST_GET_MUTE: return "GET_MUTE"; case RIL_REQUEST_QUERY_CLIP: return "QUERY_CLIP"; - case RIL_REQUEST_LAST_PDP_FAIL_CAUSE: return "LAST_PDP_FAIL_CAUSE"; - case RIL_REQUEST_PDP_CONTEXT_LIST: return "PDP_CONTEXT_LIST"; + case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: return "LAST_DATA_CALL_FAIL_CAUSE"; + case RIL_REQUEST_DATA_CALL_LIST: return "DATA_CALL_LIST"; case RIL_REQUEST_RESET_RADIO: return "RESET_RADIO"; case RIL_REQUEST_OEM_HOOK_RAW: return "OEM_HOOK_RAW"; case RIL_REQUEST_OEM_HOOK_STRINGS: return "OEM_HOOK_STRINGS"; @@ -2676,12 +2825,8 @@ public final class RIL extends BaseCommands implements CommandsInterface { case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: return "RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG"; case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: return "RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG"; case RIL_REQUEST_BROADCAST_ACTIVATION: return "RIL_REQUEST_BROADCAST_ACTIVATION"; - case RIL_REQUEST_SETUP_DATA_CALL: return "RIL_REQUEST_SETUP_DATA_CALL"; - case RIL_REQUEST_DEACTIVATE_DATA_CALL: return "RIL_REQUEST_DEACTIVATE_DATA_CALL"; case RIL_REQUEST_CDMA_VALIDATE_AKEY: return "RIL_REQUEST_CDMA_VALIDATE_AKEY"; case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: return "RIL_REQUEST_CDMA_BROADCAST_ACTIVATION"; - case RIL_REQUEST_CDMA_ENCODE_SMS: return "RIL_REQUEST_CDMA_ENCODE_SMS"; - case RIL_REQUEST_CDMA_DECODE_SMS: return "RIL_REQUEST_CDMA_DECODE_SMS"; case RIL_REQUEST_CDMA_SUBSCRIPTION: return "RIL_REQUEST_CDMA_SUBSCRIPTION"; case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: return "RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM"; case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: return "RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM"; @@ -2693,7 +2838,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { private void riljLog(String msg) { Log.d(LOG_TAG, msg); } - + // ***** Methods for CDMA support public void getDeviceIdentity(Message response) { @@ -2728,7 +2873,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - + /** * {@inheritDoc} */ @@ -2744,7 +2889,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { send(rr); } - + /** * {@inheritDoc} */ @@ -2767,10 +2912,10 @@ public final class RIL extends BaseCommands implements CommandsInterface { public void queryTTYModeEnabled(Message response) { RILRequest rr = RILRequest.obtain( RILConstants.RIL_REQUEST_QUERY_TTY_MODE, response); - + send(rr); - } - + } + /** * {@inheritDoc} */ @@ -2780,7 +2925,48 @@ public final class RIL extends BaseCommands implements CommandsInterface { rr.mp.writeInt(1); rr.mp.writeInt(enable ? 1 : 0); - + + send(rr); + } + + /** + * {@inheritDoc} + */ + public void + sendCDMAFeatureCode(String FeatureCode, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_FLASH, response); + + rr.mp.writeInt(1); + rr.mp.writeString(FeatureCode); + + if (RILJ_LOG) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + + " : " + FeatureCode); + + send(rr); + } + + public void getCdmaBroadcastConfig(Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG, response); + + send(rr); + } + + public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG, response); + + for(int i = 0; i < configValuesArray.length; i++) { + rr.mp.writeInt(configValuesArray[i]); + } + + send(rr); + } + + public void activateCdmaBroadcastSms(int activate, Message response) { + RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_BROADCAST_ACTIVATION, response); + + rr.mp.writeInt(1); + rr.mp.writeInt(activate); + send(rr); } } diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 3e5818815f81..43fc3b620600 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -26,23 +26,40 @@ public interface RILConstants { // from RIL_Errno int SUCCESS = 0; - int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */ + int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */ int GENERIC_FAILURE = 2; - int PASSWORD_INCORRECT = 3; /* for PIN/PIN2 methods only! */ - int SIM_PIN2 = 4; /* Operation requires SIM PIN2 to be entered */ - int SIM_PUK2 = 5; /* Operation requires SIM PIN2 to be entered */ + int PASSWORD_INCORRECT = 3; /* for PIN/PIN2 methods only! */ + int SIM_PIN2 = 4; /* Operation requires SIM PIN2 to be entered */ + int SIM_PUK2 = 5; /* Operation requires SIM PIN2 to be entered */ int REQUEST_NOT_SUPPORTED = 6; int REQUEST_CANCELLED = 7; - int OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; /* data operation is not allowed during voice call in class C */ - int OP_NOT_ALLOWED_BEFORE_REG_NW = 9; /* request is not allowed before device registers to network */ - int SMS_SEND_FAIL_RETRY = 10; /* send sms fail and need retry */ + int OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; /* data operation is not allowed during voice call in + class C */ + int OP_NOT_ALLOWED_BEFORE_REG_NW = 9; /* request is not allowed before device registers to + network */ + int SMS_SEND_FAIL_RETRY = 10; /* send sms fail and need retry */ - int NETWORK_MODE_GSM_UMTS = 3; - int NETWORK_MODE_CDMA = 4; - int NETWORK_MODE_GLOBAL = 7; + /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */ + int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */ + int NETWORK_MODE_GSM_ONLY = 1; /* GSM only */ + int NETWORK_MODE_WCDMA_ONLY = 2; /* WCDMA only */ + int NETWORK_MODE_GSM_UMTS = 3; /* GSM/WCDMA (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int NETWORK_MODE_CDMA = 4; /* CDMA and EvDo (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int NETWORK_MODE_CDMA_NO_EVDO = 5; /* CDMA only */ + int NETWORK_MODE_EVDO_NO_CDMA = 6; /* EvDo only */ + int NETWORK_MODE_GLOBAL = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL) + AVAILABLE Application Settings menu*/ + int PREFERRED_NETWORK_MODE = NETWORK_MODE_GLOBAL; - int SUBSCRIPTION_FROM_RUIM = 0; - int SUBSCRIPTION_FROM_NV = 1; + /* CDMA subscription source. See ril.h RIL_REQUEST_CDMA_SET_SUBSCRIPTION */ + int SUBSCRIPTION_FROM_RUIM = 0; /* CDMA subscription from RUIM when available */ + int SUBSCRIPTION_FROM_NV = 1; /* CDMA subscription from NV */ + int PREFERRED_CDMA_SUBSCRIPTION = SUBSCRIPTION_FROM_NV; + + int CDMA_CELL_BROADCAST_SMS_DISABLED = 1; + int CDMA_CELL_BROADCAST_SMS_ENABLED = 0; int CDMA_PHONE = 0; int GSM_PHONE = 1; @@ -50,6 +67,9 @@ public interface RILConstants { int CDM_TTY_MODE_DISABLED = 0; int CDM_TTY_MODE_ENABLED = 1; + byte CDMA_VOICE_PRIVACY = 0x70; /* "p" value used in Ril_Call.isVoice if Privacy + is active */ + /* cat include/telephony/ril.h | \ egrep '^#define' | \ @@ -64,9 +84,6 @@ cat include/telephony/ril.h | \ int RIL_SIM_PIN = 3; int RIL_SIM_PUK = 4; int RIL_SIM_NETWORK_PERSONALIZATION = 5; - //TODO T: start - // These RIL requests will not be renamed to ICC, - // but these requests are also valid for SIM and RUIM int RIL_REQUEST_GET_SIM_STATUS = 1; int RIL_REQUEST_ENTER_SIM_PIN = 2; int RIL_REQUEST_ENTER_SIM_PUK = 3; @@ -74,7 +91,6 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_ENTER_SIM_PUK2 = 5; int RIL_REQUEST_CHANGE_SIM_PIN = 6; int RIL_REQUEST_CHANGE_SIM_PIN2 = 7; - //TODO T: end int RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION = 8; int RIL_REQUEST_GET_CURRENT_CALLS = 9; int RIL_REQUEST_DIAL = 10; @@ -94,9 +110,7 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_DTMF = 24; int RIL_REQUEST_SEND_SMS = 25; int RIL_REQUEST_SEND_SMS_EXPECT_MORE = 26; - int RIL_REQUEST_SETUP_DEFAULT_PDP = 27; - //TODO T: This RIL request will not be renamed to ICC, - // but this request is also valid for SIM and RUIM + int RIL_REQUEST_SETUP_DATA_CALL = 27; int RIL_REQUEST_SIM_IO = 28; int RIL_REQUEST_SEND_USSD = 29; int RIL_REQUEST_CANCEL_USSD = 30; @@ -110,7 +124,7 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_GET_IMEI = 38; int RIL_REQUEST_GET_IMEISV = 39; int RIL_REQUEST_ANSWER = 40; - int RIL_REQUEST_DEACTIVATE_DEFAULT_PDP = 41; + int RIL_REQUEST_DEACTIVATE_DATA_CALL = 41; int RIL_REQUEST_QUERY_FACILITY_LOCK = 42; int RIL_REQUEST_SET_FACILITY_LOCK = 43; int RIL_REQUEST_CHANGE_BARRING_PASSWORD = 44; @@ -125,8 +139,8 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_SET_MUTE = 53; int RIL_REQUEST_GET_MUTE = 54; int RIL_REQUEST_QUERY_CLIP = 55; - int RIL_REQUEST_LAST_PDP_FAIL_CAUSE = 56; - int RIL_REQUEST_PDP_CONTEXT_LIST = 57; + int RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE = 56; + int RIL_REQUEST_DATA_CALL_LIST = 57; int RIL_REQUEST_RESET_RADIO = 58; int RIL_REQUEST_OEM_HOOK_RAW = 59; int RIL_REQUEST_OEM_HOOK_STRINGS = 60; @@ -164,14 +178,10 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG = 92; int RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG = 93; int RIL_REQUEST_CDMA_BROADCAST_ACTIVATION = 94; - int RIL_REQUEST_SETUP_DATA_CALL = 95; - int RIL_REQUEST_DEACTIVATE_DATA_CALL = 96; - int RIL_REQUEST_CDMA_ENCODE_SMS = 97; - int RIL_REQUEST_CDMA_DECODE_SMS = 98; int RIL_REQUEST_CDMA_SUBSCRIPTION = 99; int RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM = 100; int RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM = 101; - int RIL_REQUEST_DEVICE_IDENTITY = 102; + int RIL_REQUEST_DEVICE_IDENTITY = 102; int RIL_UNSOL_RESPONSE_BASE = 1000; int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000; int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001; @@ -183,7 +193,7 @@ cat include/telephony/ril.h | \ int RIL_UNSOL_ON_USSD_REQUEST = 1007; int RIL_UNSOL_NITZ_TIME_RECEIVED = 1008; int RIL_UNSOL_SIGNAL_STRENGTH = 1009; - int RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED = 1010; + int RIL_UNSOL_DATA_CALL_LIST_CHANGED = 1010; int RIL_UNSOL_SUPP_SVC_NOTIFICATION = 1011; int RIL_UNSOL_STK_SESSION_END = 1012; int RIL_UNSOL_STK_PROACTIVE_COMMAND = 1013; diff --git a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java index 9341709c4ee0..9947dc046015 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java +++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import android.app.Activity; import android.app.PendingIntent; @@ -34,16 +34,16 @@ import android.os.Handler; import android.os.Message; import android.provider.Telephony; import android.provider.Telephony.Sms.Intents; -import android.telephony.gsm.SmsMessage; -import android.telephony.gsm.SmsManager; +import android.telephony.SmsMessage; import android.telephony.ServiceState; import android.util.Config; +import android.util.Log; +import android.view.WindowManager; -import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SmsResponse; import com.android.internal.util.HexDump; -import android.util.Log; -import android.view.WindowManager; import java.io.ByteArrayOutputStream; import java.util.ArrayList; @@ -52,87 +52,90 @@ import java.util.Random; import com.android.internal.R; -final class SMSDispatcher extends Handler { - private static final String TAG = "GSM"; +import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE; +import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE; +import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU; +import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF; + + +public abstract class SMSDispatcher extends Handler { + private static final String TAG = "SMS"; - /** Default checking period for SMS sent without uesr permit */ + /** Default checking period for SMS sent without user permit */ private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000; - /** Default number of SMS sent in checking period without uesr permit */ + /** Default number of SMS sent in checking period without user permit */ private static final int DEFAULT_SMS_MAX_ALLOWED = 100; /** Default timeout for SMS sent query */ private static final int DEFAULT_SMS_TIMOUEOUT = 6000; - private static final int WAP_PDU_TYPE_PUSH = 0x06; + protected static final int WAP_PDU_TYPE_PUSH = 0x06; - private static final int WAP_PDU_TYPE_CONFIRMED_PUSH = 0x07; + protected static final int WAP_PDU_TYPE_CONFIRMED_PUSH = 0x07; - private static final byte DRM_RIGHTS_XML = (byte)0xca; + protected static final byte DRM_RIGHTS_XML = (byte)0xca; - private static final String DRM_RIGHTS_XML_MIME_TYPE = "application/vnd.oma.drm.rights+xml"; + protected static final String DRM_RIGHTS_XML_MIME_TYPE = "application/vnd.oma.drm.rights+xml"; - private static final byte DRM_RIGHTS_WBXML = (byte)0xcb; + protected static final byte DRM_RIGHTS_WBXML = (byte)0xcb; - private static final String DRM_RIGHTS_WBXML_MIME_TYPE = + protected static final String DRM_RIGHTS_WBXML_MIME_TYPE = "application/vnd.oma.drm.rights+wbxml"; - private static final byte WAP_SI_MIME_PORT = (byte)0xae; + protected static final byte WAP_SI_MIME_PORT = (byte)0xae; - private static final String WAP_SI_MIME_TYPE = "application/vnd.wap.sic"; + protected static final String WAP_SI_MIME_TYPE = "application/vnd.wap.sic"; - private static final byte WAP_SL_MIME_PORT = (byte)0xb0; + protected static final byte WAP_SL_MIME_PORT = (byte)0xb0; - private static final String WAP_SL_MIME_TYPE = "application/vnd.wap.slc"; + protected static final String WAP_SL_MIME_TYPE = "application/vnd.wap.slc"; - private static final byte WAP_CO_MIME_PORT = (byte)0xb2; + protected static final byte WAP_CO_MIME_PORT = (byte)0xb2; - private static final String WAP_CO_MIME_TYPE = "application/vnd.wap.coc"; + protected static final String WAP_CO_MIME_TYPE = "application/vnd.wap.coc"; - private static final int WAP_PDU_SHORT_LENGTH_MAX = 30; + protected static final int WAP_PDU_SHORT_LENGTH_MAX = 30; - private static final int WAP_PDU_LENGTH_QUOTE = 31; + protected static final int WAP_PDU_LENGTH_QUOTE = 31; - private static final String MMS_MIME_TYPE = "application/vnd.wap.mms-message"; + protected static final String MMS_MIME_TYPE = "application/vnd.wap.mms-message"; - private static final String[] RAW_PROJECTION = new String[] { + protected static final String[] RAW_PROJECTION = new String[] { "pdu", "sequence", }; static final int MAIL_SEND_SMS = 1; - static final int EVENT_NEW_SMS = 1; + static final protected int EVENT_NEW_SMS = 1; - static final int EVENT_SEND_SMS_COMPLETE = 2; + static final protected int EVENT_SEND_SMS_COMPLETE = 2; /** Retry sending a previously failed SMS message */ - static final int EVENT_SEND_RETRY = 3; + static final protected int EVENT_SEND_RETRY = 3; /** Status report received */ - static final int EVENT_NEW_SMS_STATUS_REPORT = 5; + static final protected int EVENT_NEW_SMS_STATUS_REPORT = 5; - /** SIM storage is full */ - static final int EVENT_SIM_FULL = 6; + /** SIM/RUIM storage is full */ + static final protected int EVENT_ICC_FULL = 6; /** SMS confirm required */ - static final int EVENT_POST_ALERT = 7; + static final protected int EVENT_POST_ALERT = 7; /** Send the user confirmed SMS */ - static final int EVENT_SEND_CONFIRMED_SMS = 8; + static final protected int EVENT_SEND_CONFIRMED_SMS = 8; /** Alert is timeout */ - static final int EVENT_ALERT_TIMEOUT = 9; + static final protected int EVENT_ALERT_TIMEOUT = 9; - private final GSMPhone mPhone; + protected Phone mPhone; + protected Context mContext; + protected ContentResolver mResolver; + protected CommandsInterface mCm; - private final Context mContext; - - private final ContentResolver mResolver; - - private final CommandsInterface mCm; - - private final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); + protected final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); /** Maximum number of times to retry sending a failed SMS. */ private static final int MAX_SEND_RETRIES = 3; @@ -144,12 +147,16 @@ final class SMSDispatcher extends Handler { * CONCATENATED_16_BIT_REFERENCE message set. Should be * incremented for each set of concatenated messages. */ - private static int sConcatenatedRef; + protected static int sConcatenatedRef; private SmsCounter mCounter; private SmsTracker mSTracker; + private static SmsMessage mSmsMessage; + private static SmsMessageBase mSmsMessageBase; + private SmsMessageBase.SubmitPduBase mSubmitPduBase; + /** * Implement the per-application based SMS control, which only allows * a limit on the number of SMS/MMS messages an app can send in checking @@ -196,7 +203,7 @@ final class SMSDispatcher extends Handler { } } - SMSDispatcher(GSMPhone phone) { + protected SMSDispatcher(PhoneBase phone) { mPhone = phone; mContext = phone.getContext(); mResolver = mContext.getContentResolver(); @@ -207,19 +214,30 @@ final class SMSDispatcher extends Handler { mCm.setOnNewSMS(this, EVENT_NEW_SMS, null); mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null); - mCm.setOnSimSmsFull(this, EVENT_SIM_FULL, null); + mCm.setOnIccSmsFull(this, EVENT_ICC_FULL, null); // Don't always start message ref at 0. sConcatenatedRef = new Random().nextInt(256); } + public void dispose() { + mCm.unSetOnNewSMS(this); + mCm.unSetOnSmsStatus(this); + mCm.unSetOnIccSmsFull(this); + } + + protected void finalize() { + Log.d(TAG, "SMSDispatcher finalized"); + } + + /* TODO: Need to figure out how to keep track of status report routing in a * persistent manner. If the phone process restarts (reboot or crash), * we will lose this list and any status reports that come in after * will be dropped. */ /** Sent messages awaiting a delivery status report. */ - private final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>(); + protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>(); /** * Handles events coming from the phone stack. Overridden from handler. @@ -241,11 +259,8 @@ final class SMSDispatcher extends Handler { ar = (AsyncResult) msg.obj; - // FIXME unit test leaves cm == null. this should change - if (mCm != null) { // FIXME only acknowledge on store - mCm.acknowledgeLastIncomingSMS(true, null); - } + acknowledgeLastIncomingSms(true, null); if (ar.exception != null) { Log.e(TAG, "Exception processing incoming SMS", @@ -254,12 +269,12 @@ final class SMSDispatcher extends Handler { } sms = (SmsMessage) ar.result; - dispatchMessage(sms); + dispatchMessage(sms.mWrappedSmsMessage); break; case EVENT_SEND_SMS_COMPLETE: - // An outbound SMS has been sucessfully transferred, or failed. + // An outbound SMS has been successfully transferred, or failed. handleSendComplete((AsyncResult) msg.obj); break; @@ -271,8 +286,8 @@ final class SMSDispatcher extends Handler { handleStatusReport((AsyncResult)msg.obj); break; - case EVENT_SIM_FULL: - handleSimFull(); + case EVENT_ICC_FULL: + handleIccFull(); break; case EVENT_POST_ALERT: @@ -299,7 +314,7 @@ final class SMSDispatcher extends Handler { * Called when SIM_FULL message is received from the RIL. Notifies interested * parties that SIM storage for SMS messages is full. */ - private void handleSimFull() { + private void handleIccFull(){ // broadcast SIM_FULL intent Intent intent = new Intent(Intents.SIM_FULL_ACTION); mPhone.getContext().sendBroadcast(intent, "android.permission.RECEIVE_SMS"); @@ -312,34 +327,7 @@ final class SMSDispatcher extends Handler { * @param ar AsyncResult passed into the message handler. ar.result should * be a String representing the status report PDU, as ASCII hex. */ - private void handleStatusReport(AsyncResult ar) { - String pduString = (String) ar.result; - SmsMessage sms = SmsMessage.newFromCDS(pduString); - - if (sms != null) { - int messageRef = sms.messageRef; - for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { - SmsTracker tracker = deliveryPendingList.get(i); - if (tracker.mMessageRef == messageRef) { - // Found it. Remove from list and broadcast. - deliveryPendingList.remove(i); - PendingIntent intent = tracker.mDeliveryIntent; - Intent fillIn = new Intent(); - fillIn.putExtra("pdu", IccUtils.hexStringToBytes(pduString)); - try { - intent.send(mContext, Activity.RESULT_OK, fillIn); - } catch (CanceledException ex) {} - - // Only expect to see one tracker matching this messageref - break; - } - } - } - - if (mCm != null) { - mCm.acknowledgeLastIncomingSMS(true, null); - } - } + protected abstract void handleStatusReport(AsyncResult ar); /** * Called when SMS send completes. Broadcasts a sentIntent on success. @@ -350,7 +338,7 @@ final class SMSDispatcher extends Handler { * an SmsResponse instance if send was successful. ar.userObj * should be an SmsTracker instance. */ - private void handleSendComplete(AsyncResult ar) { + protected void handleSendComplete(AsyncResult ar) { SmsTracker tracker = (SmsTracker) ar.userObj; PendingIntent sentIntent = tracker.mSentIntent; @@ -398,7 +386,7 @@ final class SMSDispatcher extends Handler { } else if (tracker.mSentIntent != null) { // Done retrying; return an error to the app. try { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE); + tracker.mSentIntent.send(RESULT_ERROR_GENERIC_FAILURE); } catch (CanceledException ex) {} } } @@ -413,13 +401,13 @@ final class SMSDispatcher extends Handler { * POWER_OFF * @param tracker An SmsTracker for the current message. */ - private void handleNotInService(int ss, SmsTracker tracker) { + protected void handleNotInService(int ss, SmsTracker tracker) { if (tracker.mSentIntent != null) { try { if (ss == ServiceState.STATE_POWER_OFF) { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_RADIO_OFF); + tracker.mSentIntent.send(RESULT_ERROR_RADIO_OFF); } else { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE); + tracker.mSentIntent.send(RESULT_ERROR_NO_SERVICE); } } catch (CanceledException ex) {} } @@ -430,108 +418,14 @@ final class SMSDispatcher extends Handler { * * @param sms the incoming message from the phone */ - /* package */ void dispatchMessage(SmsMessage sms) { - boolean handled = false; - - // Special case the message waiting indicator messages - if (sms.isMWISetMessage()) { - mPhone.updateMessageWaitingIndicator(true); - - if (sms.isMwiDontStore()) { - handled = true; - } - - if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator set SMS shouldStore=" - + !handled); - } - } else if (sms.isMWIClearMessage()) { - mPhone.updateMessageWaitingIndicator(false); - - if (sms.isMwiDontStore()) { - handled = true; - } - - if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator clear SMS shouldStore=" - + !handled); - } - } - - if (handled) { - return; - } - - // Parse the headers to see if this is partial, or port addressed - int referenceNumber = -1; - int count = 0; - int sequence = 0; - int destPort = -1; - - SmsHeader header = sms.getUserDataHeader(); - if (header != null) { - for (SmsHeader.Element element : header.getElements()) { - switch (element.getID()) { - case SmsHeader.CONCATENATED_8_BIT_REFERENCE: { - byte[] data = element.getData(); - - referenceNumber = data[0] & 0xff; - count = data[1] & 0xff; - sequence = data[2] & 0xff; - - break; - } + protected abstract void dispatchMessage(SmsMessageBase sms); - case SmsHeader.CONCATENATED_16_BIT_REFERENCE: { - byte[] data = element.getData(); - - referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff); - count = data[2] & 0xff; - sequence = data[3] & 0xff; - - break; - } - - case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: { - byte[] data = element.getData(); - - destPort = (data[0] & 0xff) << 8; - destPort |= (data[1] & 0xff); - - break; - } - } - } - } - - if (referenceNumber == -1) { - // notify everyone of the message if it isn't partial - byte[][] pdus = new byte[1][]; - pdus[0] = sms.getPdu(); - - if (destPort != -1) { - if (destPort == SmsHeader.PORT_WAP_PUSH) { - dispatchWapPdu(sms.getUserData()); - } - // The message was sent to a port, so concoct a URI for it - dispatchPortAddressedPdus(pdus, destPort); - } else { - // It's a normal message, dispatch it - dispatchPdus(pdus); - } - } else { - // Process the message part - processMessagePart(sms, referenceNumber, sequence, count, destPort); - } - } /** * If this is the last part send the parts out to the application, otherwise * the part is stored for later processing. */ - private void processMessagePart(SmsMessage sms, int referenceNumber, + protected void processMessagePart(SmsMessageBase sms, int referenceNumber, int sequence, int count, int destinationPort) { // Lookup all other related parts StringBuilder where = new StringBuilder("reference_number ="); @@ -617,7 +511,7 @@ final class SMSDispatcher extends Handler { * * @param pdus The raw PDUs making up the message */ - private void dispatchPdus(byte[][] pdus) { + protected void dispatchPdus(byte[][] pdus) { Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION); intent.putExtra("pdus", pdus); mPhone.getContext().sendBroadcast( @@ -630,7 +524,7 @@ final class SMSDispatcher extends Handler { * @param pdus The raw PDUs making up the message * @param port The destination port of the messages */ - private void dispatchPortAddressedPdus(byte[][] pdus, int port) { + protected void dispatchPortAddressedPdus(byte[][] pdus, int port) { Uri uri = Uri.parse("sms://localhost:" + port); Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri); intent.putExtra("pdus", pdus); @@ -644,7 +538,7 @@ final class SMSDispatcher extends Handler { * * @param pdu The WAP PDU, made up of one or more SMS PDUs */ - private void dispatchWapPdu(byte[] pdu) { + protected void dispatchWapPdu(byte[] pdu) { int index = 0; int transactionId = pdu[index++] & 0xFF; int pduType = pdu[index++] & 0xFF; @@ -728,7 +622,7 @@ final class SMSDispatcher extends Handler { int dataIndex = headerStartIndex + headerLength; byte[] data; if (pdu[headerStartIndex] == WAP_CO_MIME_PORT) { - // because SMSDispatcher can't parse push headers "Content-Location" and + // because GsmSMSDispatcher can't parse push headers "Content-Location" and // X-Wap-Content-URI, so pass the whole push to CO application. data = pdu; } else { @@ -777,35 +671,9 @@ final class SMSDispatcher extends Handler { * to the recipient. The raw pdu of the status report is in the * extended data ("pdu"). */ - void sendMultipartText(String destinationAddress, String scAddress, ArrayList<String> parts, - ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { - - int ref = ++sConcatenatedRef & 0xff; - - for (int i = 0, count = parts.size(); i < count; i++) { - // build SmsHeader - byte[] data = new byte[3]; - data[0] = (byte) ref; // reference #, unique per message - data[1] = (byte) count; // total part count - data[2] = (byte) (i + 1); // 1-based sequence - SmsHeader header = new SmsHeader(); - header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data)); - PendingIntent sentIntent = null; - PendingIntent deliveryIntent = null; - - if (sentIntents != null && sentIntents.size() > i) { - sentIntent = sentIntents.get(i); - } - if (deliveryIntents != null && deliveryIntents.size() > i) { - deliveryIntent = deliveryIntents.get(i); - } - - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - parts.get(i), deliveryIntent != null, header.toByteArray()); - - sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); - } - } + protected abstract void sendMultipartText(String destinationAddress, String scAddress, + ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, + ArrayList<PendingIntent> deliveryIntents); /** * Send a SMS @@ -827,12 +695,12 @@ final class SMSDispatcher extends Handler { * broadcast when the message is delivered to the recipient. The * raw pdu of the status report is in the extended data ("pdu"). */ - void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, PendingIntent deliveryIntent) { if (pdu == null) { if (sentIntent != null) { try { - sentIntent.send(SmsManager.RESULT_ERROR_NULL_PDU); + sentIntent.send(RESULT_ERROR_NULL_PDU); } catch (CanceledException ex) {} } return; @@ -863,7 +731,7 @@ final class SMSDispatcher extends Handler { * * An SmsTracker for the current message. */ - private void handleReachSentLimit(SmsTracker tracker) { + protected void handleReachSentLimit(SmsTracker tracker) { Resources r = Resources.getSystem(); @@ -884,7 +752,7 @@ final class SMSDispatcher extends Handler { DEFAULT_SMS_TIMOUEOUT); } - private String getAppNameByIntent(PendingIntent intent) { + protected String getAppNameByIntent(PendingIntent intent) { Resources r = Resources.getSystem(); return (intent != null) ? intent.getTargetPackage() : r.getString(R.string.sms_control_default_app_name); @@ -895,29 +763,59 @@ final class SMSDispatcher extends Handler { * * @param tracker holds the SMS message to send */ - private void sendSms(SmsTracker tracker) { - HashMap map = tracker.mData; + protected abstract void sendSms(SmsTracker tracker); - byte smsc[] = (byte[]) map.get("smsc"); - byte pdu[] = (byte[]) map.get("pdu"); + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param response + * Callback message is empty on completion + */ + protected abstract void activateCellBroadcastSms(int activate, Message response); - Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); - mCm.sendSMS(IccUtils.bytesToHexString(smsc), - IccUtils.bytesToHexString(pdu), reply); - } + /** + * Query the current configuration of cell broadcast SMS. + * + * @param response + * Callback message contains the configuration from the modem on completion + * @see #setCellBroadcastConfig + */ + protected abstract void getCellBroadcastSmsConfig(Message response); + + /** + * Configure cell broadcast SMS. + * + * @param configValuesArray + * The first element defines the number of triples that follow. + * A triple is made up of the service category, the language identifier + * and a boolean that specifies whether the category is set active. + * @param response + * Callback message is empty on completion + */ + protected abstract void setCellBroadcastConfig(int[] configValuesArray, Message response); + + /** + * Send an acknowledge message. + * @param success indicates that last message was successfully received. + * @param response callback message sent when operation completes. + */ + protected abstract void acknowledgeLastIncomingSms(boolean success, Message response); /** * Keeps track of an SMS that has been sent to the RIL, until it it has * successfully been sent, or we're done trying. * */ - static class SmsTracker { - HashMap mData; - int mRetryCount; - int mMessageRef; + static protected class SmsTracker { + // fields need to be public for derived SmsDispatchers + public HashMap mData; + public int mRetryCount; + public int mMessageRef; - PendingIntent mSentIntent; - PendingIntent mDeliveryIntent; + public PendingIntent mSentIntent; + public PendingIntent mDeliveryIntent; SmsTracker(HashMap data, PendingIntent sentIntent, PendingIntent deliveryIntent) { @@ -926,17 +824,17 @@ final class SMSDispatcher extends Handler { mDeliveryIntent = deliveryIntent; mRetryCount = 0; } - } private DialogInterface.OnClickListener mListener = - new DialogInterface.OnClickListener() { + new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON1) { - Log.d(TAG, "click YES to send out sms"); - sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS)); - } + public void onClick(DialogInterface dialog, int which) { + if (which == DialogInterface.BUTTON1) { + Log.d(TAG, "click YES to send out sms"); + sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS)); } - }; + } + }; } + diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java index 1d3a44acd100..b71c23134686 100644 --- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java @@ -71,10 +71,7 @@ public abstract class ServiceStateTracker extends Handler { // signal strength poll rate protected static final int POLL_PERIOD_MILLIS = 20 * 1000; - //*****GSM events - //TODO Have to be extended with CDMA events - protected static final int EVENT_RADIO_STATE_CHANGED = 1; protected static final int EVENT_NETWORK_STATE_CHANGED = 2; protected static final int EVENT_GET_SIGNAL_STRENGTH = 3; @@ -94,20 +91,18 @@ public abstract class ServiceStateTracker extends Handler { protected static final int EVENT_SET_PREFERRED_NETWORK_TYPE = 20; protected static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21; - //*****CDMA events: - protected static final int EVENT_POLL_STATE_REGISTRATION_CDMA = 22; - protected static final int EVENT_POLL_STATE_OPERATOR_CDMA = 23; - protected static final int EVENT_RUIM_READY = 24; - protected static final int EVENT_RUIM_RECORDS_LOADED = 25; + protected static final int EVENT_POLL_STATE_REGISTRATION_CDMA = 22; + protected static final int EVENT_POLL_STATE_OPERATOR_CDMA = 23; + protected static final int EVENT_RUIM_READY = 24; + protected static final int EVENT_RUIM_RECORDS_LOADED = 25; protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA = 26; - protected static final int EVENT_POLL_SIGNAL_STRENGTH_CDMA = 27; - protected static final int EVENT_GET_SIGNAL_STRENGTH_CDMA = 28; - protected static final int EVENT_NETWORK_STATE_CHANGED_CDMA = 29; - protected static final int EVENT_GET_LOC_DONE_CDMA = 30; - protected static final int EVENT_SIGNAL_STRENGTH_UPDATE_CDMA = 31; - - protected static final int EVENT_NV_LOADED = 32; + protected static final int EVENT_POLL_SIGNAL_STRENGTH_CDMA = 27; + protected static final int EVENT_GET_SIGNAL_STRENGTH_CDMA = 28; + protected static final int EVENT_NETWORK_STATE_CHANGED_CDMA = 29; + protected static final int EVENT_GET_LOC_DONE_CDMA = 30; + protected static final int EVENT_SIGNAL_STRENGTH_UPDATE_CDMA = 31; + protected static final int EVENT_NV_LOADED = 32; //***** Time Zones protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone"; @@ -143,7 +138,6 @@ public abstract class ServiceStateTracker extends Handler { //***** Constructors public ServiceStateTracker() { - } @@ -164,6 +158,10 @@ public abstract class ServiceStateTracker extends Handler { } } + public void unregisterForRoamingOn(Handler h) { + roamingOnRegistrants.remove(h); + } + /** * Registration point for combined roaming off * combined roaming is true when roaming is true and ONS differs SPN @@ -180,7 +178,11 @@ public abstract class ServiceStateTracker extends Handler { r.notifyRegistrant(); } } - + + public void unregisterForRoamingOff(Handler h) { + roamingOffRegistrants.remove(h); + } + /** * Reregister network through toggle perferred network type * This is a work aorund to deregister and register network since there is @@ -219,7 +221,7 @@ public abstract class ServiceStateTracker extends Handler { //***** Protected abstract Methods protected abstract void handlePollStateResult(int what, AsyncResult ar); protected abstract void updateSpnDisplay(); - + // ***** Private Instance Methods protected void setPowerStateToDesired() { diff --git a/telephony/java/com/android/internal/telephony/SmsAddress.java b/telephony/java/com/android/internal/telephony/SmsAddress.java new file mode 100644 index 000000000000..b3892cb0b342 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SmsAddress.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2008 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; + +public abstract class SmsAddress { + // From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118 + // and C.S0005-D table 2.7.1.3.2.4-2 + public static final int TON_UNKNOWN = 0; + public static final int TON_INTERNATIONAL = 1; + public static final int TON_NATIONAL = 2; + public static final int TON_NETWORK = 3; + public static final int TON_SUBSCRIBER = 4; + public static final int TON_ALPHANUMERIC = 5; + public static final int TON_ABBREVIATED = 6; + + public int ton; + public String address; + public byte[] origBytes; + + /** + * Returns the address of the SMS message in String form or null if unavailable + */ + public String getAddressString() { + return address; + } + + /** + * Returns true if this is an alphanumeric address + */ + public boolean isAlphanumeric() { + return ton == TON_ALPHANUMERIC; + } + + /** + * Returns true if this is a network address + */ + public boolean isNetworkSpecific() { + return ton == TON_NETWORK; + } + + public boolean couldBeEmailGateway() { + // Some carriers seems to send email gateway messages in this form: + // from: an UNKNOWN TON, 3 or 4 digits long, beginning with a 5 + // PID: 0x00, Data coding scheme 0x03 + // So we just attempt to treat any message from an address length <= 4 + // as an email gateway + + return address.length() <= 4; + } + +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java index 22366ecdb030..64b884efa0c5 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsHeader.java +++ b/telephony/java/com/android/internal/telephony/SmsHeader.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; import com.android.internal.util.HexDump; @@ -24,8 +24,7 @@ import java.util.ArrayList; * This class represents a SMS user data header. * */ -public class SmsHeader -{ +public class SmsHeader { /** See TS 23.040 9.2.3.24 for description of this element ID. */ public static final int CONCATENATED_8_BIT_REFERENCE = 0x00; /** See TS 23.040 9.2.3.24 for description of this element ID. */ @@ -42,6 +41,7 @@ public class SmsHeader private byte[] m_data; private ArrayList<Element> m_elements = new ArrayList<Element>(); + public int nbrOfHeaders; /** * Creates an SmsHeader object from raw user data header bytes. @@ -49,36 +49,33 @@ public class SmsHeader * @param data is user data header bytes * @return an SmsHeader object */ - public static SmsHeader parse(byte[] data) - { + public static SmsHeader parse(byte[] data) { SmsHeader header = new SmsHeader(); header.m_data = data; int index = 0; - while (index < data.length) - { + header.nbrOfHeaders = 0; + while (index < data.length) { int id = data[index++] & 0xff; int length = data[index++] & 0xff; byte[] elementData = new byte[length]; System.arraycopy(data, index, elementData, 0, length); header.add(new Element(id, elementData)); index += length; + header.nbrOfHeaders++; } return header; } - public SmsHeader() - { - } + public SmsHeader() { } /** * Returns the list of SmsHeader Elements that make up the header. * * @return the list of SmsHeader Elements. */ - public ArrayList<Element> getElements() - { + public ArrayList<Element> getElements() { return m_elements; } @@ -87,14 +84,12 @@ public class SmsHeader * * @param element to add. */ - public void add(Element element) - { + public void add(Element element) { m_elements.add(element); } @Override - public String toString() - { + public String toString() { StringBuilder builder = new StringBuilder(); builder.append("UDH LENGTH: " + m_data.length + " octets"); @@ -104,40 +99,56 @@ public class SmsHeader for (Element e : getElements()) { builder.append(" 0x" + HexDump.toHexString((byte)e.getID()) + " - "); - switch (e.getID()) - { - case CONCATENATED_8_BIT_REFERENCE: - { + switch (e.getID()) { + case CONCATENATED_8_BIT_REFERENCE: { builder.append("Concatenated Short Message 8bit ref\n"); byte[] data = e.getData(); builder.append(" " + data.length + " (0x"); - builder.append(HexDump.toHexString((byte)data.length)+") Bytes - Information Element\n"); + builder.append(HexDump.toHexString((byte)data.length) + + ") Bytes - Information Element\n"); builder.append(" " + data[0] + " : SM reference number\n"); builder.append(" " + data[1] + " : number of messages\n"); builder.append(" " + data[2] + " : this SM sequence number\n"); break; } - case CONCATENATED_16_BIT_REFERENCE: - { + case CONCATENATED_16_BIT_REFERENCE: { builder.append("Concatenated Short Message 16bit ref\n"); byte[] data = e.getData(); builder.append(" " + data.length + " (0x"); - builder.append(HexDump.toHexString((byte)data.length)+") Bytes - Information Element\n"); - builder.append(" " + (data[0] & 0xff) * 256 + (data[1] & 0xff) + - " : SM reference number\n"); + builder.append(HexDump.toHexString((byte)data.length) + + ") Bytes - Information Element\n"); + builder.append(" " + (data[0] & 0xff) * 256 + (data[1] & 0xff) + + " : SM reference number\n"); builder.append(" " + data[2] + " : number of messages\n"); builder.append(" " + data[3] + " : this SM sequence number\n"); break; } - case APPLICATION_PORT_ADDRESSING_16_BIT: + case APPLICATION_PORT_ADDRESSING_8_BIT: { + builder.append("Application port addressing 8bit\n"); + byte[] data = e.getData(); + + builder.append(" " + data.length + " (0x"); + builder.append(HexDump.toHexString( + (byte)data.length) + ") Bytes - Information Element\n"); + + int source = (data[0] & 0xff); + builder.append(" " + source + " : DESTINATION port\n"); + + int dest = (data[1] & 0xff); + builder.append(" " + dest + " : SOURCE port\n"); + break; + } + + case APPLICATION_PORT_ADDRESSING_16_BIT: { builder.append("Application port addressing 16bit\n"); byte[] data = e.getData(); builder.append(" " + data.length + " (0x"); - builder.append(HexDump.toHexString((byte)data.length)+") Bytes - Information Element\n"); + builder.append(HexDump.toHexString((byte)data.length) + + ") Bytes - Information Element\n"); int source = (data[0] & 0xff) << 8; source |= (data[1] & 0xff); @@ -149,8 +160,7 @@ public class SmsHeader break; } - default: - { + default: { builder.append("Unknown element\n"); break; } @@ -202,13 +212,11 @@ public class SmsHeader * See TS 23.040 9.2.3.24. * */ - public static class Element - { + public static class Element { private byte[] m_data; private int m_id; - public Element(int id, byte[] data) - { + public Element(int id, byte[] data) { m_id = id; m_data = data; } @@ -218,8 +226,7 @@ public class SmsHeader * * @return the IE identifier. */ - public int getID() - { + public int getID() { return m_id; } @@ -228,8 +235,7 @@ public class SmsHeader * * @return element data. */ - public byte[] getData() - { + public byte[] getData() { return m_data; } } diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java new file mode 100644 index 000000000000..7c324511b2b9 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -0,0 +1,388 @@ +/* + * Copyright (C) 2008 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.util.Log; +import com.android.internal.telephony.SmsHeader; +import java.util.Arrays; + +import static android.telephony.SmsMessage.ENCODING_7BIT; +import static android.telephony.SmsMessage.ENCODING_16BIT; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER; +import static android.telephony.SmsMessage.MessageClass; +import static com.android.internal.telephony.SmsAddress.TON_ABBREVIATED; +import static com.android.internal.telephony.SmsAddress.TON_ALPHANUMERIC; +import static com.android.internal.telephony.SmsAddress.TON_INTERNATIONAL; +import static com.android.internal.telephony.SmsAddress.TON_NATIONAL; +import static com.android.internal.telephony.SmsAddress.TON_NETWORK; +import static com.android.internal.telephony.SmsAddress.TON_SUBSCRIBER; +import static com.android.internal.telephony.SmsAddress.TON_UNKNOWN; + +/** + * Base class declaring the specific methods and members for SmsMessage. + * {@hide} + */ +public abstract class SmsMessageBase { + private static final String LOG_TAG = "SMS"; + + /** {@hide} The address of the SMSC. May be null */ + protected String scAddress; + + /** {@hide} The address of the sender */ + protected SmsAddress originatingAddress; + + /** {@hide} The message body as a string. May be null if the message isn't text */ + protected String messageBody; + + /** {@hide} */ + protected String pseudoSubject; + + /** {@hide} Non-null if this is an email gateway message */ + protected String emailFrom; + + /** {@hide} Non-null if this is an email gateway message */ + protected String emailBody; + + /** {@hide} */ + protected boolean isEmail; + + /** {@hide} */ + protected long scTimeMillis; + + /** {@hide} The raw PDU of the message */ + protected byte[] mPdu; + + /** {@hide} The raw bytes for the user data section of the message */ + protected byte[] userData; + + /** {@hide} */ + protected SmsHeader userDataHeader; + + // "Message Waiting Indication Group" + // 23.038 Section 4 + /** {@hide} */ + protected boolean isMwi; + + /** {@hide} */ + protected boolean mwiSense; + + /** {@hide} */ + protected boolean mwiDontStore; + + /** + * Indicates status for messages stored on the ICC. + */ + protected int statusOnIcc = -1; + + /** + * Record index of message in the EF. + */ + protected int indexOnIcc = -1; + + /** TP-Message-Reference - Message Reference of sent message. @hide */ + public int messageRef; + + public static abstract class SubmitPduBase { + public byte[] encodedScAddress; // Null if not applicable. + public byte[] encodedMessage; + + public String toString() { + return "SubmitPdu: encodedScAddress = " + + Arrays.toString(encodedScAddress) + + ", encodedMessage = " + + Arrays.toString(encodedMessage); + } + } + + /** + * Returns the address of the SMS service center that relayed this message + * or null if there is none. + */ + public String getServiceCenterAddress() { + return scAddress; + } + + /** + * Returns the originating address (sender) of this SMS message in String + * form or null if unavailable + */ + public String getOriginatingAddress() { + if (originatingAddress == null) { + return null; + } + + return originatingAddress.getAddressString(); + } + + /** + * Returns the originating address, or email from address if this message + * was from an email gateway. Returns null if originating address + * unavailable. + */ + public String getDisplayOriginatingAddress() { + if (isEmail) { + return emailFrom; + } else { + return getOriginatingAddress(); + } + } + + /** + * Returns the message body as a String, if it exists and is text based. + * @return message body is there is one, otherwise null + */ + public String getMessageBody() { + return messageBody; + } + + /** + * Returns the class of this message. + */ + public abstract MessageClass getMessageClass(); + + /** + * Returns the message body, or email message body if this message was from + * an email gateway. Returns null if message body unavailable. + */ + public String getDisplayMessageBody() { + if (isEmail) { + return emailBody; + } else { + return getMessageBody(); + } + } + + /** + * Unofficial convention of a subject line enclosed in parens empty string + * if not present + */ + public String getPseudoSubject() { + return pseudoSubject == null ? "" : pseudoSubject; + } + + /** + * Returns the service centre timestamp in currentTimeMillis() format + */ + public long getTimestampMillis() { + return scTimeMillis; + } + + /** + * Returns true if message is an email. + * + * @return true if this message came through an email gateway and email + * sender / subject / parsed body are available + */ + public boolean isEmail() { + return isEmail; + } + + /** + * @return if isEmail() is true, body of the email sent through the gateway. + * null otherwise + */ + public String getEmailBody() { + return emailBody; + } + + /** + * @return if isEmail() is true, email from address of email sent through + * the gateway. null otherwise + */ + public String getEmailFrom() { + return emailFrom; + } + + /** + * Get protocol identifier. + */ + public abstract int getProtocolIdentifier(); + + /** + * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" + * SMS + */ + public abstract boolean isReplace(); + + /** + * Returns true for CPHS MWI toggle message. + * + * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section + * B.4.2 + */ + public abstract boolean isCphsMwiMessage(); + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) clear message + */ + public abstract boolean isMWIClearMessage(); + + /** + * returns true if this message is a CPHS voicemail / message waiting + * indicator (MWI) set message + */ + public abstract boolean isMWISetMessage(); + + /** + * returns true if this message is a "Message Waiting Indication Group: + * Discard Message" notification and should not be stored. + */ + public abstract boolean isMwiDontStore(); + + /** + * returns the user data section minus the user data header if one was + * present. + */ + public byte[] getUserData() { + return userData; + } + + /** + * Returns an object representing the user data header + * + * @return an object representing the user data header + * + * {@hide} + */ + public SmsHeader getUserDataHeader() { + return userDataHeader; + } + + /** + * Returns the raw PDU for the message. + * + * @return the raw PDU for the message. + */ + public byte[] getPdu() { + return mPdu; + } + + /** + * For an SMS-STATUS-REPORT message, this returns the status field from + * the status report. This field indicates the status of a previously + * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a + * description of values. + * + * @return 0 indicates the previously sent message was received. + * See TS 23.040, 9.9.2.3.15 for a description of other possible + * values. + */ + public abstract int getStatus(); + + /** + * Return true iff the message is a SMS-STATUS-REPORT message. + */ + public abstract boolean isStatusReportMessage(); + + /** + * Returns true iff the <code>TP-Reply-Path</code> bit is set in + * this message. + */ + public abstract boolean isReplyPathPresent(); + + /** + * Returns the status of the message on the ICC (read, unread, sent, unsent). + * + * @return the status of the message on the ICC. These are: + * SmsManager.STATUS_ON_ICC_FREE + * SmsManager.STATUS_ON_ICC_READ + * SmsManager.STATUS_ON_ICC_UNREAD + * SmsManager.STATUS_ON_ICC_SEND + * SmsManager.STATUS_ON_ICC_UNSENT + */ + public int getStatusOnIcc() { + return statusOnIcc; + } + + /** + * Returns the record index of the message on the ICC (1-based index). + * @return the record index of the message on the ICC, or -1 if this + * SmsMessage was not created from a ICC SMS EF record. + */ + public int getIndexOnIcc() { + return indexOnIcc; + } + + protected void parseMessageBody() { + if (originatingAddress.couldBeEmailGateway()) { + extractEmailAddressFromMessageBody(); + } + } + + /** + * Try to parse this message as an email gateway message -> Neither + * of the standard ways are currently supported: There are two ways + * specified in TS 23.040 Section 3.8 (not supported via this mechanism) - + * SMS message "may have its TP-PID set for internet electronic mail - MT + * SMS format: [<from-address><space>]<message> - "Depending on the + * nature of the gateway, the destination/origination address is either + * derived from the content of the SMS TP-OA or TP-DA field, or the + * TP-OA/TP-DA field contains a generic gateway address and the to/from + * address is added at the beginning as shown above." - multiple addreses + * separated by commas, no spaces - subject field delimited by '()' or '##' + * and '#' Section 9.2.3.24.11 + */ + protected void extractEmailAddressFromMessageBody() { + + /* + * a little guesswork here. I haven't found doc for this. + * the format could be either + * + * 1. [x@y][ ]/[subject][ ]/[body] + * -or- + * 2. [x@y][ ]/[body] + */ + int slash = 0, slash2 = 0, atSymbol = 0; + + try { + slash = messageBody.indexOf(" /"); + if (slash == -1) { + return; + } + + atSymbol = messageBody.indexOf('@'); + if (atSymbol == -1 || atSymbol > slash) { + return; + } + + emailFrom = messageBody.substring(0, slash); + + slash2 = messageBody.indexOf(" /", slash + 2); + + if (slash2 == -1) { + pseudoSubject = null; + emailBody = messageBody.substring(slash + 2); + } else { + pseudoSubject = messageBody.substring(slash + 2, slash2); + emailBody = messageBody.substring(slash2 + 2); + } + + isEmail = true; + } catch (Exception ex) { + Log.w(LOG_TAG, + "extractEmailAddressFromMessageBody: exception slash=" + + slash + ", atSymbol=" + atSymbol + ", slash2=" + + slash2, ex); + } + } + +} + diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.aidl b/telephony/java/com/android/internal/telephony/SmsRawData.aidl index 6f1a46dc9203..b0b3e4f93f57 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.aidl +++ b/telephony/java/com/android/internal/telephony/SmsRawData.aidl @@ -14,6 +14,6 @@ ** limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; parcelable SmsRawData; diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.java b/telephony/java/com/android/internal/telephony/SmsRawData.java index a029d5ce59f8..891d942b9a13 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsRawData.java +++ b/telephony/java/com/android/internal/telephony/SmsRawData.java @@ -15,10 +15,10 @@ */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; -import android.os.Parcelable; import android.os.Parcel; +import android.os.Parcelable; /** * A parcelable holder class of byte[] for ISms aidl implementation @@ -50,7 +50,7 @@ public class SmsRawData implements Parcelable { public byte[] getBytes() { return data; } - + public int describeContents() { return 0; } diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsResponse.java b/telephony/java/com/android/internal/telephony/SmsResponse.java index 9742b22a974f..3c4df563000e 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SmsResponse.java +++ b/telephony/java/com/android/internal/telephony/SmsResponse.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.telephony.gsm; +package com.android.internal.telephony; /** * Object returned by the RIL upon successful completion of sendSMS. diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 8519796c223f..6b1a5c3a243f 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -16,7 +16,7 @@ public class TelephonyIntents { * <li><em>phoneName</em> - A string version of the phone name.</li> * <li><em>state</em> - A string version of the new phone state.</li> * </ul> - * + * * <p class="note"> * You can <em>not</em> receive this through components declared * in manifests, only by exlicitly registering for it with @@ -28,6 +28,24 @@ public class TelephonyIntents { */ public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE"; + /** + * <p>Broadcast Action: The radio technology has changed. The intent will have the following + * extra values:</p> + * <ul> + * <li><em>phoneName</em> - A string version of the new phone name.</li> + * </ul> + * + * <p class="note"> + * You can <em>not</em> receive this through components declared + * in manifests, only by explicitly registering for it with + * {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver, + * android.content.IntentFilter) Context.registerReceiver()}. + * + * <p class="note"> + * Requires no permission. + */ + public static final String ACTION_RADIO_TECHNOLOGY_CHANGED + = "android.intent.action.RADIO_TECHNOLOGY"; /** * Broadcast Action: The phone service state has changed. The intent will have the following @@ -67,7 +85,7 @@ public class TelephonyIntents { * <ul><li>0 means "-113 dBm or less".</li><li>31 means "-51 dBm or greater".</li></ul> * </li> * </ul> - * + * * <p class="note"> * You can <em>not</em> receive this through components declared * in manifests, only by exlicitly registering for it with diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index c19773433aa7..037dd77c3ddb 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -26,8 +26,11 @@ public interface TelephonyProperties { //****** Baseband and Radio Interface version - /** - * Baseband version + //TODO T: property strings do not have to be gsm specific + // change gsm.*operator.*" properties to "operator.*" properties + + /** + * Baseband version * Availability: property is available any time radio is on */ static final String PROPERTY_BASEBAND_VERSION = "gsm.version.baseband"; @@ -64,7 +67,7 @@ public interface TelephonyProperties static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country"; //****** SIM Card - /** + /** * One of <code>"UNKNOWN"</code> <code>"ABSENT"</code> <code>"PIN_REQUIRED"</code> * <code>"PUK_REQUIRED"</code> <code>"NETWORK_LOCKED"</code> or <code>"READY"</code> */ @@ -82,15 +85,15 @@ public interface TelephonyProperties * provider of the SIM. 5 or 6 decimal digits. * Availablity: SIM state must be "READY" */ - static String PROPERTY_SIM_OPERATOR_NUMERIC = "gsm.sim.operator.numeric"; + static String PROPERTY_ICC_OPERATOR_NUMERIC = "gsm.sim.operator.numeric"; - /** PROPERTY_SIM_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name. + /** PROPERTY_ICC_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name. * Availablity: SIM state must be "READY" */ - static String PROPERTY_SIM_OPERATOR_ALPHA = "gsm.sim.operator.alpha"; + static String PROPERTY_ICC_OPERATOR_ALPHA = "gsm.sim.operator.alpha"; /** ISO country code equivalent for the SIM provider's country code*/ - static String PROPERTY_SIM_OPERATOR_ISO_COUNTRY = "gsm.sim.operator.iso-country"; + static String PROPERTY_ICC_OPERATOR_ISO_COUNTRY = "gsm.sim.operator.iso-country"; /** * Indicates the available radio technology. Values include: <code>"unknown"</code>, diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java index 53ff9d4254c3..7ceba3aa7d7b 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java @@ -13,13 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - + package com.android.internal.telephony.cdma; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; import android.content.Context; -import android.content.SharedPreferences; import android.os.AsyncResult; import android.os.Handler; import android.os.Looper; @@ -27,15 +24,19 @@ import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemProperties; -import android.preference.PreferenceManager; +import android.provider.Settings; import android.telephony.CellLocation; +import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; +import android.text.TextUtils; import android.util.Log; -import com.android.internal.telephony.CallForwardInfo; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; + import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DataConnection; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccPhoneBookInterfaceManager; @@ -44,13 +45,10 @@ import com.android.internal.telephony.MmiCode; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneBase; import com.android.internal.telephony.PhoneNotifier; +import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.PhoneSubInfo; -import com.android.internal.telephony.gsm.GsmMmiCode; -import com.android.internal.telephony.gsm.PdpConnection; import com.android.internal.telephony.RILConstants; -import android.telephony.PhoneNumberUtils; - import java.util.ArrayList; import java.util.List; @@ -59,16 +57,18 @@ import java.util.List; */ public class CDMAPhone extends PhoneBase { static final String LOG_TAG = "CDMA"; - private static final boolean LOCAL_DEBUG = false; - + private static final boolean LOCAL_DEBUG = true; + //***** Instance Variables CdmaCallTracker mCT; - SMSDispatcher mSMS; + CdmaSMSDispatcher mSMS; CdmaServiceStateTracker mSST; -// DataConnectionTracker mDataConnection; //TODO + CdmaDataConnectionTracker mDataConnection; + RuimFileHandler mRuimFileHandler; RuimRecords mRuimRecords; RuimCard mRuimCard; - //MyHandler h; + MyHandler h; + ArrayList <FeatureCode> mPendingMMIs = new ArrayList<FeatureCode>(); RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager; RuimSmsInterfaceManager mRuimSmsInterfaceManager; PhoneSubInfo mSubInfo; @@ -79,27 +79,26 @@ public class CDMAPhone extends PhoneBase { Registrant mPostDialHandler; - + //***** Constructors public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) { this(context,ci,notifier, false); - //TODO: to be checked if really needed } - - public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { + + public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier, + boolean unitTestMode) { super(notifier, context, unitTestMode); - //TODO: to be checked if really needed - + h = new MyHandler(); mCM = ci; - - mCM.setPhoneType(RILConstants.CDMA_PHONE); - mCT = new CdmaCallTracker(this); + + mCM.setPhoneType(RILConstants.CDMA_PHONE); + mCT = new CdmaCallTracker(this); mSST = new CdmaServiceStateTracker (this); - mSMS = new SMSDispatcher(this); + mSMS = new CdmaSMSDispatcher(this); mIccFileHandler = new RuimFileHandler(this); mRuimRecords = new RuimRecords(this); -// mDataConnection = new DataConnectionTracker (this); //TODO + mDataConnection = new CdmaDataConnectionTracker (this); mRuimCard = new RuimCard(this); mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this); mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this); @@ -107,58 +106,105 @@ public class CDMAPhone extends PhoneBase { mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null); mRuimRecords.registerForRecordsLoaded(h, EVENT_RUIM_RECORDS_LOADED, null); - mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, - null); + mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); mCM.registerForOn(h, EVENT_RADIO_ON, null); mCM.setOnSuppServiceNotification(h, EVENT_SSN, null); mCM.setOnCallRing(h, EVENT_CALL_RING, null); mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null); mCM.registerForNVReady(h, EVENT_NV_READY, null); + + //Change the system setting + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.CURRENT_ACTIVE_PHONE, RILConstants.CDMA_PHONE); + } + + public void dispose() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + + //Unregister from all former registered events + mRuimRecords.unregisterForRecordsLoaded(h); //EVENT_RUIM_RECORDS_LOADED + mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE + mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE + mCM.unregisterForOn(h); //EVENT_RADIO_ON + mCM.unregisterForNVReady(h); //EVENT_NV_READY + mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK + mCM.unSetOnSuppServiceNotification(h); + mCM.unSetOnCallRing(h); + + //Force all referenced classes to unregister their former registered events + mCT.dispose(); + mDataConnection.dispose(); + mSST.dispose(); + mSMS.dispose(); + mIccFileHandler.dispose(); // instance of RuimFileHandler + mRuimRecords.dispose(); + mRuimCard.dispose(); + mRuimPhoneBookInterfaceManager.dispose(); + mRuimSmsInterfaceManager.dispose(); + mSubInfo.dispose(); + } + } + + public void removeReferences() { + this.mRuimPhoneBookInterfaceManager = null; + this.mRuimSmsInterfaceManager = null; + this.mSMS = null; + this.mSubInfo = null; + this.mRuimRecords = null; + this.mIccFileHandler = null; + this.mRuimCard = null; + this.mDataConnection = null; + this.mCT = null; + this.mSST = null; } - - + + protected void finalize() { + if(LOCAL_DEBUG) Log.d(LOG_TAG, "CDMAPhone finalized"); + } + + //***** Overridden from Phone public ServiceState getServiceState() { return mSST.ss; - } - - public Phone.State + } + + public Phone.State getState() { return mCT.state; } - + public String getPhoneName() { return "CDMA"; } - + public boolean canTransfer() { - // TODO: to be implemented - //return mCT.canTransfer(); + Log.e(LOG_TAG, "canTransfer: not possible in CDMA"); return false; } - - public CdmaCall + + public CdmaCall getRingingCall() { return mCT.ringingCall; } - + public void setMute(boolean muted) { mCT.setMute(muted); } + public boolean getMute() { return mCT.getMute(); } - - public void conference() { //throws CallStateException - //TODO: ... - + + public void conference() throws CallStateException { + // three way calls in CDMA will be handled by feature codes + Log.e(LOG_TAG, "conference: not possible in CDMA"); } - + public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) { this.mCM.setPreferredVoicePrivacy(enable, onComplete); } - + public void getEnhancedVoicePrivacy(Message onComplete) { this.mCM.getPreferredVoicePrivacy(onComplete); } @@ -166,36 +212,29 @@ public class CDMAPhone extends PhoneBase { public void clearDisconnected() { mCT.clearDisconnected(); } - + public DataActivityState getDataActivityState() { DataActivityState ret = DataActivityState.NONE; if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.RADIO_TECHNOLOGY_UNKNOWN) { - // TODO This "switch" has to be implemented, when the CDMAPhone is able to generate a cdma.DataConnectionTracker - // Until this will happen, we return DataActivityState.DATAIN!!! - - ret = DataActivityState.DATAIN; // Remove this, when "switch" is implemented! - - /*switch (mDataConnection.activity) { - - case DATAIN: - ret = DataActivityState.DATAIN; - break; + switch (mDataConnection.getActivity()) { + case DATAIN: + ret = DataActivityState.DATAIN; + break; - case DATAOUT: - ret = DataActivityState.DATAOUT; - break; + case DATAOUT: + ret = DataActivityState.DATAOUT; + break; - case DATAINANDOUT: - ret = DataActivityState.DATAINANDOUT; - break; - }*/ + case DATAINANDOUT: + ret = DataActivityState.DATAINANDOUT; + break; + } } - return ret; } - + /*package*/ void notifySignalStrength() { mNotifier.notifySignalStrength(this); @@ -206,75 +245,109 @@ public class CDMAPhone extends PhoneBase { // Need to make sure dialString gets parsed properly String newDialString = PhoneNumberUtils.stripSeparators(dialString); - return mCT.dial(newDialString); + FeatureCode fc = FeatureCode.newFromDialString(newDialString, this); + if (LOCAL_DEBUG) Log.d(LOG_TAG, + "dialing w/ fc '" + fc + "'..."); + // check for feature code + if (fc == null) { + // check if call in progress + if (!mCT.foregroundCall.isIdle()) { + FeatureCode digits = new FeatureCode(this); + // use dial number as poundString + digits.poundString = newDialString; + mPendingMMIs.add(fc); + mMmiRegistrants.notifyRegistrants(new AsyncResult(null, fc, null)); + digits.processCode(); + return null; + } else { + return mCT.dial(newDialString); + } + } else { + mPendingMMIs.add(fc); + mMmiRegistrants.notifyRegistrants(new AsyncResult(null, fc, null)); + fc.processCode(); + + // FIXME should this return null or something else? + return null; + } } - + public int getSignalStrengthASU() { return mSST.rssi == 99 ? -1 : mSST.rssi; } public boolean getMessageWaitingIndicator() { - //TODO: ... -// throw new RuntimeException(); - return false; + Log.e(LOG_TAG, "method getMessageWaitingIndicator is NOT supported in CDMA!"); + return false; } + public List<? extends MmiCode> getPendingMmiCodes() { - ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>(); Log.e(LOG_TAG, "method getPendingMmiCodes is NOT supported in CDMA!"); - return mPendingMMIs; + return null; } + public void registerForSuppServiceNotification( Handler h, int what, Object obj) { - //TODO: .... + Log.e(LOG_TAG, "method registerForSuppServiceNotification is NOT supported in CDMA!"); } - + public CdmaCall getBackgroundCall() { return mCT.backgroundCall; } - + public String getGateway(String apnType) { - //TODO: .... -// throw new RuntimeException(); - return null; + return mDataConnection.getGateway(); } - + public boolean handleInCallMmiCommands(String dialString) { Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!"); return false; } - + public int enableApnType(String type) { - //TODO: .... - return 42; + // This request is mainly used to enable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to enableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_ALREADY_ACTIVE; + } else { + return Phone.APN_REQUEST_FAILED; + } } + public int disableApnType(String type) { - //TODO: to be implemented - return 42; + // This request is mainly used to disable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to disableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_REQUEST_STARTED; + } else { + return Phone.APN_REQUEST_FAILED; + } } - + public String getActiveApn() { - //TODO: ... -// throw new RuntimeException(); - return null; + Log.d(LOG_TAG, "Request to getActiveApn()"); + return null; } - - public void + + public void setNetworkSelectionModeAutomatic(Message response) { - //TODO: ... + Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!"); } - + public void unregisterForSuppServiceNotification(Handler h) { - //TODO: ... + Log.e(LOG_TAG, "method unregisterForSuppServiceNotification is NOT supported in CDMA!"); } - - public void + + public void acceptCall() throws CallStateException { mCT.acceptCall(); } - public void + public void rejectCall() throws CallStateException { mCT.rejectCall(); } @@ -283,155 +356,124 @@ public class CDMAPhone extends PhoneBase { switchHoldingAndActive() throws CallStateException { mCT.switchWaitingOrHoldingAndActive(); } - + public String getLine1Number() { return mRuimRecords.getMdnNumber(); } - public void stopDtmf() { - //TODO: ... - } - - // TODO: might not be used any longer in CDMA public void getCallWaiting(Message onComplete) { mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete); } - + public void setRadioPower(boolean power) { mSST.setRadioPower(power); } - + public String getEsn() { return mEsn; } - + public String getMeid() { return mMeid; } - + //returns MEID in CDMA public String getDeviceId() { - Log.d(LOG_TAG, "getDeviceId(): return 0"); - return "0"; + return getMeid(); } - + public String getDeviceSvn() { Log.d(LOG_TAG, "getDeviceSvn(): return 0"); return "0"; } - + public String getSubscriberId() { - //TODO: ... -// throw new RuntimeException(); - return null; + Log.e(LOG_TAG, "method getSubscriberId for IMSI is NOT supported in CDMA!"); + return null; } - + public boolean canConference() { - // TODO: to be implemented + Log.e(LOG_TAG, "canConference: not possible in CDMA"); return false; } - + public String getInterfaceName(String apnType) { - //TODO: .... -// throw new RuntimeException(); - return null; + return mDataConnection.getInterfaceName(); } - + public CellLocation getCellLocation() { return mSST.cellLoc; } - + public boolean disableDataConnectivity() { - //TODO: -// throw new RuntimeException(); - return true; - } - public void setBandMode(int bandMode, Message response) { - //TODO: ... + return mDataConnection.setDataEnabled(false); } - + public CdmaCall getForegroundCall() { return mCT.foregroundCall; } - - public void + + public void selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network, Message response) { - //TODO: ... + Log.e(LOG_TAG, "selectNetworkManually: not possible in CDMA"); } - + public void setOnPostDialCharacter(Handler h, int what, Object obj) { - //TODO: ... + Log.e(LOG_TAG, "setOnPostDialCharacter: not possible in CDMA"); } - + public boolean handlePinMmi(String dialString) { Log.e(LOG_TAG, "method handlePinMmi is NOT supported in CDMA!"); - return false; + return false; } - - public boolean isDataConnectivityPossible() { - // TODO: Currently checks if any GPRS connection is active. Should it only - // check for "default"? - - // TODO This function has to be implemented, when the CDMAPhone is able to generate a cdma.DataConnectionTracker - // Until this will happen, we return TRUE!!! - return true; - /*boolean noData = mDataConnection.getDataEnabled() && - getDataConnectionState() == DataState.DISCONNECTED; - return !noData && getSimCard().getState() == SimCard.State.READY && - getServiceState().getState() == ServiceState.STATE_IN_SERVICE && - (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming());*/ + public boolean isDataConnectivityPossible() { + boolean noData = mDataConnection.getDataEnabled() && + getDataConnectionState() == DataState.DISCONNECTED; + return !noData && getIccCard().getState() == IccCard.State.READY && + getServiceState().getState() == ServiceState.STATE_IN_SERVICE && + (mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming()); } - + public void setLine1Number(String alphaTag, String number, Message onComplete) { - //TODO: ... + Log.e(LOG_TAG, "setLine1Number: not possible in CDMA"); } - + public String[] getDnsServers(String apnType) { - //TODO: .... -// throw new RuntimeException(); - return null; + return mDataConnection.getDnsServers(); } - + public IccCard getIccCard() { return mRuimCard; } - + public String getIccSerialNumber() { return mRuimRecords.iccid; } - - public void queryAvailableBandMode(Message response) { - //TODO: .... - } - - // TODO: might not be used any longer in CDMA + public void setCallWaiting(boolean enable, Message onComplete) { - mCM.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete); + Log.e(LOG_TAG, "method setCallWaiting is NOT supported in CDMA!"); } - + public void updateServiceLocation(Message response) { mSST.getLacAndCid(response); } public void setDataRoamingEnabled(boolean enable) { - //TODO: .... + mDataConnection.setDataOnRoamingEnabled(enable); } - + public String getIpAddress(String apnType) { - //TODO: .... -// throw new RuntimeException(); - return null; + return mDataConnection.getIpAddress(); } - + public void getNeighboringCids(Message response) { - //TODO: .... -// throw new RuntimeException(); + //TODO T: implement after Cupcake merge } - + public DataState getDataConnectionState() { DataState ret = DataState.DISCONNECTED; @@ -443,88 +485,102 @@ public class CDMAPhone extends PhoneBase { // we report data connected ret = DataState.CONNECTED; - } else if (mSST.getCurrentCdmaDataConnectionState() == ServiceState.RADIO_TECHNOLOGY_UNKNOWN) { + } else if (mSST.getCurrentCdmaDataConnectionState() + == ServiceState.RADIO_TECHNOLOGY_UNKNOWN) { // If we're out of service, open TCP sockets may still work // but no data will flow ret = DataState.DISCONNECTED; - } else { /* mSST.getCurrentCdmaDataConnectionState() is ServiceState.RADIO_TECHNOLOGY_1xRTT or EVDO */ - - - // TODO This "switch" has to be implemented, when the CDMAPhone is able to generate a cdma.DataConnectionTracker - // Until this will happen, we return DataState.CONNECTED!!! - - ret = DataState.CONNECTED; //TODO Remove this, when "switch" iis implemented - - /* switch (mDataConnection.state) { - case FAILED: - case IDLE: - ret = DataState.DISCONNECTED; - break; - - case CONNECTED: - if ( mCT.state != Phone.State.IDLE - && !mSST.isConcurrentVoiceAndData()) - ret = DataState.SUSPENDED; - else - ret = DataState.CONNECTED; - break; - - case INITING: - case CONNECTING: - case SCANNING: - ret = DataState.CONNECTING; - break; - }*/ + } else { + switch (mDataConnection.getState()) { + case FAILED: + case IDLE: + ret = DataState.DISCONNECTED; + break; + + case CONNECTED: + if ( mCT.state != Phone.State.IDLE + && !mSST.isConcurrentVoiceAndData()) + ret = DataState.SUSPENDED; + else + ret = DataState.CONNECTED; + break; + + case INITING: + case CONNECTING: + case SCANNING: + ret = DataState.CONNECTING; + break; + } } return ret; } public void sendUssdResponse(String ussdMessge) { - //TODO: ... + Log.e(LOG_TAG, "sendUssdResponse: not possible in CDMA"); } + public void sendDtmf(char c) { - //TODO: .... + if (!PhoneNumberUtils.is12Key(c)) { + Log.e(LOG_TAG, + "sendDtmf called with invalid character '" + c + "'"); + } else { + if (mCT.state == Phone.State.OFFHOOK) { + mCM.sendDtmf(c, null); + } + } } - + public void startDtmf(char c) { - //TODO: .... + if (!PhoneNumberUtils.is12Key(c)) { + Log.e(LOG_TAG, + "startDtmf called with invalid character '" + c + "'"); + } else { + mCM.startDtmf(c, null); + } } - - public void - getAvailableNetworks(Message response) { - //TODO: .... + + public void stopDtmf() { + mCM.stopDtmf(null); + } + + public void getAvailableNetworks(Message response) { + Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA"); } - + public String[] getActiveApnTypes() { - //TODO: ..... -// throw new RuntimeException(); - return null; + String[] result; + Log.d(LOG_TAG, "Request to getActiveApn()"); + result = new String[1]; + result[0] = Phone.APN_TYPE_DEFAULT; + return result; } - + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { - // TODO: might not be used any longer in CDMA -// mCM.setCLIR(commandInterfaceCLIRMode, h.obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete)); + Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA"); } - + public void enableLocationUpdates() { mSST.enableLocationUpdates(); } - + + /** + * @deprecated + */ public void getPdpContextList(Message response) { - //TODO: to be implemented + getDataCallList(response); + } + + public void getDataCallList(Message response) { + mCM.getDataCallList(response); } - + public boolean getDataRoamingEnabled() { - //TODO: .... - return false; //mDataConnection.getDataOnRoamingEnabled(); + return mDataConnection.getDataOnRoamingEnabled(); } - - public List<PdpConnection> getCurrentPdpList () { - //TODO: to be implemented and import pdpConcecntion from - // GSM to be removed/replaced - return null; + public List<DataConnection> getCurrentDataConnectionList () { + return mDataConnection.getAllDataConnections(); } public void setVoiceMailNumber(String alphaTag, @@ -533,14 +589,14 @@ public class CDMAPhone extends PhoneBase { //mSIMRecords.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete); //TODO: Where do we have to store this value has to be clarified with QC } - + public String getVoiceMailNumber() { //TODO: Where can we get this value has to be clarified with QC //return mSIMRecords.getVoiceMailNumber(); -// throw new RuntimeException(); +// throw new RuntimeException(); return "12345"; } - + public String getVoiceMailAlphaTag() { // TODO: Where can we get this value has to be clarified with QC. String ret = "";//TODO: Remove = "", if we know where to get this value. @@ -552,56 +608,52 @@ public class CDMAPhone extends PhoneBase { com.android.internal.R.string.defaultVoiceMailAlphaTag).toString(); } - return ret; + return ret; } - public boolean enableDataConnectivity() { - //TODO: to be implemented - return false; + return mDataConnection.setDataEnabled(true); } public void disableLocationUpdates() { mSST.disableLocationUpdates(); } - public boolean - getSimRecordsLoaded() { - // TODO: this method is expected to be renamed - // and implemented in PhoneBase!!! + public boolean getIccRecordsLoaded() { return mRuimRecords.getRecordsLoaded(); } - - public void invokeOemRilRequestRaw(byte[] data, Message response) { - //TODO: ..... + + public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { + Log.e(LOG_TAG, "getCallForwardingOption: not possible in CDMA"); } - public void invokeOemRilRequestStrings(String[] strings, Message response) { - // TODO: to be implemented + + public void setCallForwardingOption(int commandInterfaceCFAction, + int commandInterfaceCFReason, + String dialingNumber, + int timerSeconds, + Message onComplete) { + Log.e(LOG_TAG, "setCallForwardingOption: not possible in CDMA"); } - // TODO: might not be used any longer in CDMA - public void + public void getOutgoingCallerIdDisplay(Message onComplete) { - // TODO: might not be used any longer in CDMA -// mCM.getCLIR(onComplete); + Log.e(LOG_TAG, "getOutgoingCallerIdDisplay: not possible in CDMA"); } - + public boolean getCallForwardingIndicator() { - // TODO: to be implemented + Log.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA"); return false; } public void explicitCallTransfer() { - //TODO: to be implemented like GSM - } - + Log.e(LOG_TAG, "explicitCallTransfer: not possible in CDMA"); + } + public String getLine1AlphaTag() { - // TODO: to be implemented - String ret = "to be implemented"; - return ret; + Log.e(LOG_TAG, "getLine1AlphaTag: not possible in CDMA"); + return null; } - /** * Notify any interested party of a Phone state change. @@ -609,17 +661,16 @@ public class CDMAPhone extends PhoneBase { /*package*/ void notifyPhoneStateChanged() { mNotifier.notifyPhoneState(this); } - + /** * Notifies registrants (ie, activities in the Phone app) about * changes to call state (including Phone and Connection changes). */ - /*package*/ void - notifyCallStateChanged() { + /*package*/ void notifyCallStateChanged() { /* we'd love it if this was package-scoped*/ super.notifyCallStateChangedP(); } - + void notifyServiceStateChanged(ServiceState ss) { super.notifyServiceStateChangedP(ss); } @@ -627,13 +678,8 @@ public class CDMAPhone extends PhoneBase { void notifyLocationChanged() { mNotifier.notifyCellLocation(this); } - - void notifyDataConnection(String reason) { - mNotifier.notifyDataConnection(this, reason); - } - - /*package*/ void - notifyNewRingingConnection(Connection c) { + + /*package*/ void notifyNewRingingConnection(Connection c) { /* we'd love it if this was package-scoped*/ super.notifyNewRingingConnectionP(c); } @@ -641,20 +687,43 @@ public class CDMAPhone extends PhoneBase { /** * Notifiy registrants of a RING event. */ - void notifyIncomingRing() { + void notifyIncomingRing() { AsyncResult ar = new AsyncResult(null, this, null); mIncomingRingRegistrants.notifyRegistrants(ar); } - - /*package*/ void - notifyDisconnect(Connection cn) { + + /*package*/ void notifyDisconnect(Connection cn) { mDisconnectRegistrants.notifyResult(cn); } void notifyUnknownConnection() { mUnknownConnectionRegistrants.notifyResult(this); } - + + /*package*/ void + updateMessageWaitingIndicator(boolean mwi) { + // this also calls notifyMessageWaitingIndicator() + mRuimRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0); + } + + + /** + * Removes the given FC from the pending list and notifies + * registrants that it is complete. + * @param fc FC that is done + */ + /*package*/ void onMMIDone(FeatureCode fc) { + /* Only notify complete if it's on the pending list. + * Otherwise, it's already been handled (eg, previously canceled). + * The exception is cancellation of an incoming USSD-REQUEST, which is + * not on the list. + */ + if (mPendingMMIs.remove(fc)) { + mMmiCompleteRegistrants.notifyRegistrants( + new AsyncResult(null, fc, null)); + } + } + //***** Inner Classes class MyHandler extends Handler { MyHandler() { @@ -664,14 +733,12 @@ public class CDMAPhone extends PhoneBase { super(l); } - public void - handleMessage(Message msg) { + public void handleMessage(Message msg) { AsyncResult ar; Message onComplete; switch(msg.what) { case EVENT_RADIO_AVAILABLE: { - Log.d(LOG_TAG, "Event EVENT_RADIO_AVAILABLE Received"); //TODO Remove mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE)); mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE)); @@ -679,7 +746,6 @@ public class CDMAPhone extends PhoneBase { break; case EVENT_GET_BASEBAND_VERSION_DONE:{ - Log.d(LOG_TAG, "Event EVENT_GET_BASEBAND_VERSION_DONE Received"); //TODO Remove ar = (AsyncResult)msg.obj; if (ar.exception != null) { @@ -690,132 +756,61 @@ public class CDMAPhone extends PhoneBase { setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result); } break; - + case EVENT_GET_DEVICE_IDENTITY_DONE:{ - Log.d(LOG_TAG, "Event EVENT_GET_DEVICE_IDENTITY_DONE Received"); //TODO Remove ar = (AsyncResult)msg.obj; if (ar.exception != null) { break; } - String[] localTemp = (String[])ar.result; - mEsn = localTemp[2]; - mMeid = localTemp[3]; - Log.d(LOG_TAG, "ESN: " + mEsn); //TODO Remove - Log.d(LOG_TAG, "MEID: " + mMeid); //TODO Remove + String[] respId = (String[])ar.result; + mEsn = respId[2]; + mMeid = respId[3]; } break; case EVENT_RUIM_RECORDS_LOADED:{ - Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received"); //TODO Remove - //TODO + Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received"); } break; case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{ - Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); //TODO Remove - //TODO + Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); } break; case EVENT_RADIO_ON:{ - Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received"); //TODO Remove + Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received"); } break; case EVENT_SSN:{ - Log.d(LOG_TAG, "Event EVENT_SSN Received"); //TODO Remove + Log.d(LOG_TAG, "Event EVENT_SSN Received"); } break; case EVENT_CALL_RING:{ - Log.d(LOG_TAG, "Event EVENT_CALL_RING Received"); //TODO Remove - } + Log.d(LOG_TAG, "Event EVENT_CALL_RING Received"); + } break; case EVENT_REGISTERED_TO_NETWORK:{ - Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received"); //TODO Remove - // TODO: might not be used any longer in CDMA - // syncClirSetting(); - } + Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received"); + } break; case EVENT_NV_READY:{ - Log.d(LOG_TAG, "Event EVENT_NV_READY Received"); //TODO Remove - //Get the records from NV - //TODO + Log.d(LOG_TAG, "Event EVENT_NV_READY Received"); //Inform the Service State Tracker mNvLoadedRegistrants.notifyRegistrants(); - } + } break; - // TODO: might not be used any longer in CDMA -// case EVENT_GET_CALL_FORWARD_DONE: -// ar = (AsyncResult)msg.obj; -// if (ar.exception == null) { -// handleCfuQueryResult((CallForwardInfo[])ar.result); -// } -// onComplete = (Message) ar.userObj; -// if (onComplete != null) { -// AsyncResult.forMessage(onComplete, ar.result, ar.exception); -// onComplete.sendToTarget(); -// } -// break; - - // TODO: might not be used any longer in CDMA -// case EVENT_SET_CALL_FORWARD_DONE: -// ar = (AsyncResult)msg.obj; -// -// // TODO: Normally, we don't have to set this flag at the RUIM card too. But check it again before deleting this code. -// /*if (ar.exception == null) { -// mSIMRecords.setVoiceCallForwardingFlag(1, msg.arg1 == 1); -// }*/ -// -// onComplete = (Message) ar.userObj; -// if (onComplete != null) { -// AsyncResult.forMessage(onComplete, ar.result, ar.exception); -// onComplete.sendToTarget(); -// } -// break; - - // TODO: might not be used any longer in CDMA -// case EVENT_SET_CLIR_COMPLETE: -// ar = (AsyncResult)msg.obj; -// if (ar.exception == null) { -// saveClirSetting(msg.arg1); -// } -// onComplete = (Message) ar.userObj; -// if (onComplete != null) { -// AsyncResult.forMessage(onComplete, ar.result, ar.exception); -// onComplete.sendToTarget(); -// } -// break; - default:{ throw new RuntimeException("unexpected event not handled"); } } - } - } - - private void handleCfuQueryResult(CallForwardInfo[] infos) { - - // TODO: Normally, we don't need to set this flag at the RUIM card too. But this has to be checked. - // Remove this function, if we don't need it in CDMA. - - /*if (infos == null || infos.length == 0) { - // Assume the default is not active - // Set unconditional CFF in SIM to false - mSIMRecords.setVoiceCallForwardingFlag(1, false); - } else { - for (int i = 0, s = infos.length; i < s; i++) { - if ((infos[i].serviceClass & SERVICE_CLASS_VOICE) != 0) { - mSIMRecords.setVoiceCallForwardingFlag(1, (infos[i].status == 1)); - // should only have the one - break; - } - } - }*/ + } } /** @@ -829,8 +824,7 @@ public class CDMAPhone extends PhoneBase { * Retrieves the IccSmsInterfaceManager of the CDMAPhone */ public IccSmsInterfaceManager getIccSmsInterfaceManager(){ - //TODO - return null; + return mRuimSmsInterfaceManager; } /** @@ -844,30 +838,33 @@ public class CDMAPhone extends PhoneBase { Registrant r = new Registrant (h, what, obj); mNvLoadedRegistrants.add(r); } - + + public void unregisterForNvLoaded(Handler h) { + mNvLoadedRegistrants.remove(h); + } + // override for allowing access from other classes of this package /** * {@inheritDoc} */ - protected final void - setSystemProperty(String property, String value) { + public final void setSystemProperty(String property, String value) { super.setSystemProperty(property, value); - } - + } + /** * {@inheritDoc} - */ - protected Handler getHandler(){ + */ + public Handler getHandler(){ return h; } - + /** * {@inheritDoc} - */ - protected IccFileHandler getIccFileHandler(){ - return this.mIccFileHandler; + */ + public IccFileHandler getIccFileHandler(){ + return this.mIccFileHandler; } - + /** * Set the TTY mode of the CDMAPhone */ @@ -881,4 +878,36 @@ public class CDMAPhone extends PhoneBase { public void queryTTYModeEnabled(Message onComplete) { this.mCM.queryTTYModeEnabled(onComplete); } + + /** + * Activate or deactivate cell broadcast SMS. + * + * @param activate + * 0 = activate, 1 = deactivate + * @param response + * Callback message is empty on completion + */ + public void activateCellBroadcastSms(int activate, Message response) { + mSMS.activateCellBroadcastSms(activate, response); + } + + /** + * Query the current configuration of cdma cell broadcast SMS. + * + * @param response + * Callback message is empty on completion + */ + public void getCellBroadcastSmsConfig(Message response){ + mSMS.getCellBroadcastSmsConfig(response); + } + + /** + * Configure cdma cell broadcast SMS. + * + * @param response + * Callback message is empty on completion + */ + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){ + mSMS.setCellBroadcastConfig(configValuesArray, response); + } } diff --git a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java index 9fcc37a661d3..ea557b2068e1 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java +++ b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java @@ -15,7 +15,7 @@ */ package com.android.internal.telephony.cdma; - + /** * Call fail causes from TS 24.008 . * These are mostly the cause codes we need to distinguish for the UI. diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java index 9982d1422bea..9ccb310c211b 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java @@ -22,9 +22,8 @@ import java.util.List; import com.android.internal.telephony.Call; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.Connection; -import com.android.internal.telephony.Phone; import com.android.internal.telephony.DriverCall; - +import com.android.internal.telephony.Phone; /** * {@hide} @@ -35,7 +34,7 @@ public final class CdmaCall extends Call { /*package*/ ArrayList<Connection> connections = new ArrayList<Connection>(); /*package*/ State state = State.IDLE; /*package*/ CdmaCallTracker owner; - + /***************************** Class Methods *****************************/ static State @@ -50,34 +49,35 @@ public final class CdmaCall extends Call { default: throw new RuntimeException ("illegal call state:" + dcState); } } - + /****************************** Constructors *****************************/ /*package*/ CdmaCall (CdmaCallTracker owner) { this.owner = owner; } - + + public void dispose() { + } + /************************** Overridden from Call *************************/ - // TODO is currently a copy of GSM to build - // has to be implemented public List<Connection> getConnections() { // FIXME should return Collections.unmodifiableList(); return connections; } - - public State + + public State getState() { return state; } - - public Phone + + public Phone getPhone() { - //TODO + //TODO, see GsmCall return null; } - + public boolean isMultiparty() { return connections.size() > 1; } @@ -86,11 +86,11 @@ public final class CdmaCall extends Call { * background call exists, the background call will be resumed * because an AT+CHLD=1 will be sent */ - public void + public void hangup() throws CallStateException { owner.hangup(this); - } - + } + public String toString() { return state.toString(); @@ -121,20 +121,20 @@ public final class CdmaCall extends Call { /* If only disconnected connections remain, we are disconnected*/ boolean hasOnlyDisconnectedConnections = true; - + for (int i = 0, s = connections.size() ; i < s; i ++) { - if (connections.get(i).getState() + if (connections.get(i).getState() != State.DISCONNECTED ) { hasOnlyDisconnectedConnections = false; break; - } + } } if (hasOnlyDisconnectedConnections) { - state = State.DISCONNECTED; + state = State.DISCONNECTED; } - } + } } @@ -151,9 +151,9 @@ public final class CdmaCall extends Call { update (CdmaConnection conn, DriverCall dc) { State newState; boolean changed = false; - + newState = stateFromDCState(dc.state); - + if (newState != state) { state = newState; changed = true; @@ -174,7 +174,7 @@ public final class CdmaCall extends Call { //***** Called from CdmaCallTracker - /** + /** * Called when this Call is being hung up locally (eg, user pressed "end") * Note that at this point, the hangup request has been dispatched to the radio * but no response has yet been received so update() has not yet been called @@ -189,18 +189,18 @@ public final class CdmaCall extends Call { cn.onHangupLocal(); } } - + /** * Called when it's time to clean up disconnected Connection objects */ void clearDisconnected() { for (int i = connections.size() - 1 ; i >= 0 ; i--) { CdmaConnection cn = (CdmaConnection)connections.get(i); - + if (cn.getState() == State.DISCONNECTED) { connections.remove(i); } - } + } if (connections.size() == 0) { state = State.IDLE; diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java index d813ecaf9f5b..2485dcb4e5b0 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java @@ -37,42 +37,42 @@ import com.android.internal.telephony.*; * {@hide} */ public final class CdmaCallTracker extends CallTracker { - static final String LOG_TAG = "CDMA"; - + static final String LOG_TAG = "CDMA"; + private static final boolean REPEAT_POLLING = false; private static final boolean DBG_POLL = false; //***** Constants - static final int MAX_CONNECTIONS = 7; // only 7 connections allowed in GSM - static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call + static final int MAX_CONNECTIONS = 1; // only 1 connection allowed in CDMA + static final int MAX_CONNECTIONS_PER_CALL = 1; // only 1 connection allowed per call //***** Instance Variables - + CdmaConnection connections[] = new CdmaConnection[MAX_CONNECTIONS]; RegistrantList voiceCallEndedRegistrants = new RegistrantList(); RegistrantList voiceCallStartedRegistrants = new RegistrantList(); // connections dropped durin last poll - ArrayList<CdmaConnection> droppedDuringPoll - = new ArrayList<CdmaConnection>(MAX_CONNECTIONS); + ArrayList<CdmaConnection> droppedDuringPoll + = new ArrayList<CdmaConnection>(MAX_CONNECTIONS); - CdmaCall ringingCall = new CdmaCall(this); + CdmaCall ringingCall = new CdmaCall(this); // A call that is ringing or (call) waiting CdmaCall foregroundCall = new CdmaCall(this); CdmaCall backgroundCall = new CdmaCall(this); CdmaConnection pendingMO; boolean hangupPendingMO; - + CDMAPhone phone; - + boolean desiredMute = false; // false = mute off Phone.State state = Phone.State.IDLE; - + // boolean needsPoll; @@ -88,7 +88,34 @@ public final class CdmaCallTracker extends CallTracker { cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null); cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null); } - + + public void dispose() { + cm.unregisterForCallStateChanged(this); + cm.unregisterForOn(this); + cm.unregisterForNotAvailable(this); + + for(CdmaConnection c : connections) { + try { + if(c != null) hangup(c); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + } + + try { + if(pendingMO != null) hangup(pendingMO); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + + clearDisconnected(); + + } + + protected void finalize() { + Log.d(LOG_TAG, "CdmaCallTracker finalized"); + } + //***** Instance Methods //***** Public Methods @@ -96,12 +123,19 @@ public final class CdmaCallTracker extends CallTracker { Registrant r = new Registrant(h, what, obj); voiceCallStartedRegistrants.add(r); } + public void unregisterForVoiceCallStarted(Handler h) { + voiceCallStartedRegistrants.remove(h); + } public void registerForVoiceCallEnded(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); voiceCallEndedRegistrants.add(r); } + public void unregisterForVoiceCallEnded(Handler h) { + voiceCallEndedRegistrants.remove(h); + } + private void fakeHoldForegroundBeforeDial() { List<Connection> connCopy; @@ -116,7 +150,7 @@ public final class CdmaCallTracker extends CallTracker { conn.fakeHoldBeforeDial(); } } - + /** * clirMode is one of the CLIR_ constants */ @@ -139,13 +173,13 @@ public final class CdmaCallTracker extends CallTracker { // for the newly dialed connection switchWaitingOrHoldingAndActive(); - // Fake local state so that + // Fake local state so that // a) foregroundCall is empty for the newly dialed connection // b) hasNonHangupStateChanged remains false in the // next poll, so that we don't clear a failed dialing call fakeHoldForegroundBeforeDial(); - } - + } + if (foregroundCall.getState() != CdmaCall.State.IDLE) { //we should have failed in !canDial() above before we get here throw new CallStateException("cannot dial in current state"); @@ -161,33 +195,33 @@ public final class CdmaCallTracker extends CallTracker { pendingMO.cause = Connection.DisconnectCause.INVALID_NUMBER; // handlePollCalls() will notice this call not present - // and will mark it as dropped. + // and will mark it as dropped. pollCallsWhenSafe(); } else { // Always unmute when initiating a new call setMute(false); - cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); + cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); } updatePhoneState(); phone.notifyCallStateChanged(); - + return pendingMO; } - + Connection dial (String dialString) throws CallStateException { return dial(dialString, CommandsInterface.CLIR_DEFAULT); } - + void acceptCall () throws CallStateException { // FIXME if SWITCH fails, should retry with ANSWER // in case the active/holding call disappeared and this // is no longer call waiting - + if (ringingCall.getState() == CdmaCall.State.INCOMING) { Log.i("phone", "acceptCall: incoming..."); // Always unmute when answering a new call @@ -218,21 +252,21 @@ public final class CdmaCallTracker extends CallTracker { if (ringingCall.getState() == CdmaCall.State.INCOMING) { throw new CallStateException("cannot be in the incoming state"); } else { - cm.switchWaitingOrHoldingAndActive( - obtainCompleteMessage(EVENT_SWITCH_RESULT)); + cm.sendCDMAFeatureCode("", obtainCompleteMessage(EVENT_SWITCH_RESULT)); } } void conference() throws CallStateException { - cm.conference(obtainCompleteMessage(EVENT_CONFERENCE_RESULT)); + // three way calls in CDMA will be handled by feature codes + Log.e(LOG_TAG, "conference: not possible in CDMA"); } void explicitCallTransfer() throws CallStateException { cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT)); } - + void clearDisconnected() { internalClearDisconnected(); @@ -241,7 +275,7 @@ public final class CdmaCallTracker extends CallTracker { phone.notifyCallStateChanged(); } - boolean + boolean canConference() { return foregroundCall.getState() == CdmaCall.State.ACTIVE && backgroundCall.getState() == CdmaCall.State.HOLDING @@ -265,21 +299,19 @@ public final class CdmaCallTracker extends CallTracker { boolean canTransfer() { - return foregroundCall.getState() == CdmaCall.State.ACTIVE - && backgroundCall.getState() == CdmaCall.State.HOLDING; + Log.e(LOG_TAG, "canTransfer: not possible in CDMA"); + return false; } - + //***** Private Instance Methods - + private void internalClearDisconnected() { ringingCall.clearDisconnected(); foregroundCall.clearDisconnected(); - backgroundCall.clearDisconnected(); + backgroundCall.clearDisconnected(); } - - - + /** * Obtain a message to use for signalling "invoke getCurrentCalls() when * this operation and all other pending operations are complete @@ -288,7 +320,7 @@ public final class CdmaCallTracker extends CallTracker { obtainCompleteMessage() { return obtainCompleteMessage(EVENT_OPERATION_COMPLETE); } - + /** * Obtain a message to use for signalling "invoke getCurrentCalls() when * this operation and all other pending operations are complete @@ -308,26 +340,26 @@ public final class CdmaCallTracker extends CallTracker { private void operationComplete() { pendingOperations--; - + if (DBG_POLL) log("operationComplete: pendingOperations=" + pendingOperations + ", needsPoll=" + needsPoll); if (pendingOperations == 0 && needsPoll) { lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); - cm.getCurrentCalls(lastRelevantPoll); + cm.getCurrentCalls(lastRelevantPoll); } else if (pendingOperations < 0) { // this should never happen Log.e(LOG_TAG,"CdmaCallTracker.pendingOperations < 0"); pendingOperations = 0; } } - + private void updatePhoneState() { Phone.State oldState = state; - + if (ringingCall.isRinging()) { state = Phone.State.RINGING; } else if (pendingMO != null || @@ -335,7 +367,7 @@ public final class CdmaCallTracker extends CallTracker { state = Phone.State.OFFHOOK; } else { state = Phone.State.IDLE; - } + } if (state == Phone.State.IDLE && oldState != state) { voiceCallEndedRegistrants.notifyRegistrants( @@ -349,13 +381,13 @@ public final class CdmaCallTracker extends CallTracker { phone.notifyPhoneStateChanged(); } } - + // ***** Overwritten from CallTracker - + protected void handlePollCalls(AsyncResult ar) { List polledCalls; - + if (ar.exception == null) { polledCalls = (List)ar.result; } else if (isCommandExceptionRadioNotAvailable(ar.exception)) { @@ -375,7 +407,7 @@ public final class CdmaCallTracker extends CallTracker { boolean needsPollDelay = false; boolean unknownConnectionAppeared = false; - for (int i = 0, curDC = 0, dcSize = polledCalls.size() + for (int i = 0, curDC = 0, dcSize = polledCalls.size() ; i < connections.length; i++) { CdmaConnection conn = connections[i]; DriverCall dc = null; @@ -432,7 +464,7 @@ public final class CdmaCallTracker extends CallTracker { // which is neither a ringing call or one we created. // Either we've crashed and re-attached to an existing // call, or something else (eg, SIM) initiated the call. - + Log.i(LOG_TAG,"Phantom call appeared " + dc); // If it's a connected call, set the connect time so that @@ -449,8 +481,8 @@ public final class CdmaCallTracker extends CallTracker { hasNonHangupStateChanged = true; } else if (conn != null && dc == null) { // Connection missing in CLCC response that we were - // tracking. - droppedDuringPoll.add(conn); + // tracking. + droppedDuringPoll.add(conn); // Dropped connections are removed from the CallTracker // list but kept in the Call list connections[i] = null; @@ -458,7 +490,7 @@ public final class CdmaCallTracker extends CallTracker { // Connection in CLCC response does not match what // we were tracking. Assume dropped call and new call - droppedDuringPoll.add(conn); + droppedDuringPoll.add(conn); connections[i] = new CdmaConnection (dc, this, i); if (connections[i].getCall() == ringingCall) { @@ -494,11 +526,11 @@ public final class CdmaCallTracker extends CallTracker { // This is the first poll after an ATD. // We expect the pending call to appear in the list // If it does not, we land here - if (pendingMO != null) { - Log.d(LOG_TAG,"Pending MO dropped before poll fg state:" + if (pendingMO != null) { + Log.d(LOG_TAG,"Pending MO dropped before poll fg state:" + foregroundCall.getState()); - droppedDuringPoll.add(pendingMO); + droppedDuringPoll.add(pendingMO); pendingMO = null; hangupPendingMO = false; } @@ -519,7 +551,7 @@ public final class CdmaCallTracker extends CallTracker { if (conn.cause == Connection.DisconnectCause.LOCAL) { cause = Connection.DisconnectCause.INCOMING_REJECTED; } else { - cause = Connection.DisconnectCause.INCOMING_MISSED; + cause = Connection.DisconnectCause.INCOMING_MISSED; } if (Phone.DEBUG_PHONE) { @@ -532,8 +564,7 @@ public final class CdmaCallTracker extends CallTracker { // Local hangup droppedDuringPoll.remove(i); conn.onDisconnect(Connection.DisconnectCause.LOCAL); - } else if (conn.cause == - Connection.DisconnectCause.INVALID_NUMBER) { + } else if (conn.cause == Connection.DisconnectCause.INVALID_NUMBER) { droppedDuringPoll.remove(i); conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER); } @@ -575,7 +606,7 @@ public final class CdmaCallTracker extends CallTracker { /*package*/ void hangup (CdmaConnection conn) throws CallStateException { if (conn.owner != this) { - throw new CallStateException ("CdmaConnection " + conn + throw new CallStateException ("CdmaConnection " + conn + "does not belong to CdmaCallTracker " + this); } @@ -584,14 +615,14 @@ public final class CdmaCallTracker extends CallTracker { // GSM index assigned yet if (Phone.DEBUG_PHONE) log("hangup: set hangupPendingMO to true"); - hangupPendingMO = true; + hangupPendingMO = true; } else { - try { - cm.hangupConnection (conn.getGSMIndex(), obtainCompleteMessage()); + try { + cm.hangupConnection (conn.getCDMAIndex(), obtainCompleteMessage()); } catch (CallStateException ex) { // Ignore "connection not found" // Call may have hung up already - Log.w(LOG_TAG,"CdmaCallTracker WARN: hangup() on absent connection " + Log.w(LOG_TAG,"CdmaCallTracker WARN: hangup() on absent connection " + conn); } } @@ -602,20 +633,20 @@ public final class CdmaCallTracker extends CallTracker { /*package*/ void separate (CdmaConnection conn) throws CallStateException { if (conn.owner != this) { - throw new CallStateException ("CdmaConnection " + conn + throw new CallStateException ("CdmaConnection " + conn + "does not belong to CdmaCallTracker " + this); } try { - cm.separateConnection (conn.getGSMIndex(), + cm.separateConnection (conn.getCDMAIndex(), obtainCompleteMessage(EVENT_SEPARATE_RESULT)); } catch (CallStateException ex) { // Ignore "connection not found" // Call may have hung up already - Log.w(LOG_TAG,"CdmaCallTracker WARN: separate() on absent connection " + Log.w(LOG_TAG,"CdmaCallTracker WARN: separate() on absent connection " + conn); } - } - + } + //***** Called from CDMAPhone /*package*/ void @@ -623,13 +654,13 @@ public final class CdmaCallTracker extends CallTracker { desiredMute = mute; cm.setMute(desiredMute, null); } - + /*package*/ boolean getMute() { return desiredMute; - } + } + - //***** Called from CdmaCall /* package */ void @@ -684,7 +715,7 @@ public final class CdmaCallTracker extends CallTracker { int count = call.connections.size(); for (int i = 0; i < count; i++) { CdmaConnection cn = (CdmaConnection)call.connections.get(i); - if (cn.getGSMIndex() == index) { + if (cn.getCDMAIndex() == index) { cm.hangupConnection(index, obtainCompleteMessage()); return; } @@ -698,27 +729,27 @@ public final class CdmaCallTracker extends CallTracker { int count = call.connections.size(); for (int i = 0; i < count; i++) { CdmaConnection cn = (CdmaConnection)call.connections.get(i); - cm.hangupConnection(cn.getGSMIndex(), obtainCompleteMessage()); + cm.hangupConnection(cn.getCDMAIndex(), obtainCompleteMessage()); } } catch (CallStateException ex) { Log.e(LOG_TAG, "hangupConnectionByIndex caught " + ex); } } - + /* package */ CdmaConnection getConnectionByIndex(CdmaCall call, int index) throws CallStateException { int count = call.connections.size(); for (int i = 0; i < count; i++) { CdmaConnection cn = (CdmaConnection)call.connections.get(i); - if (cn.getGSMIndex() == index) { + if (cn.getCDMAIndex() == index) { return cn; } } return null; } - + private Phone.SuppService getFailedService(int what) { switch (what) { case EVENT_SWITCH_RESULT: @@ -733,16 +764,22 @@ public final class CdmaCallTracker extends CallTracker { return Phone.SuppService.UNKNOWN; } + private void handleRadioNotAvailable() { + // handlePollCalls will clear out its + // call list when it gets the CommandException + // error result from this + pollCallsWhenSafe(); + } + //****** Overridden from Handler - public void + public void handleMessage (Message msg) { AsyncResult ar; - + switch (msg.what) { case EVENT_POLL_CALLS_RESULT:{ - //TODO Remove - Log.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received"); + Log.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received"); ar = (AsyncResult)msg.obj; if(msg == lastRelevantPoll) { @@ -759,25 +796,17 @@ public final class CdmaCallTracker extends CallTracker { ar = (AsyncResult)msg.obj; operationComplete(); break; - -// TODO + case EVENT_SWITCH_RESULT: -// case EVENT_CONFERENCE_RESULT: -// case EVENT_SEPARATE_RESULT: -// case EVENT_ECT_RESULT: - ar = (AsyncResult)msg.obj; - if (ar.exception != null) { - // TODO: will be handles by InCall Supp. Service use case - //phone.notifySuppServiceFailed(getFailedService(msg.what)); - } - operationComplete(); + ar = (AsyncResult)msg.obj; + operationComplete(); break; case EVENT_GET_LAST_CALL_FAIL_CAUSE: int causeCode; ar = (AsyncResult)msg.obj; - operationComplete(); + operationComplete(); if (ar.exception != null) { // An exception occurred...just treat the disconnect @@ -788,7 +817,7 @@ public final class CdmaCallTracker extends CallTracker { } else { causeCode = ((int[])ar.result)[0]; } - + for (int i = 0, s = droppedDuringPoll.size() ; i < s ; i++ ) { @@ -802,31 +831,26 @@ public final class CdmaCallTracker extends CallTracker { phone.notifyCallStateChanged(); droppedDuringPoll.clear(); break; - -// TODO: check if needed -// case EVENT_REPOLL_AFTER_DELAY: + case EVENT_CALL_STATE_CHANGE: - Log.d(LOG_TAG, "Event EVENT_CALL_STATE_CHANGE Received"); //TODO Remove pollCallsWhenSafe(); break; - case EVENT_RADIO_AVAILABLE:{ - Log.d(LOG_TAG, "Event EVENT_RADIO_AVAILABLE Received"); //TODO Remove + case EVENT_RADIO_AVAILABLE: handleRadioAvailable(); - } break; - + case EVENT_RADIO_NOT_AVAILABLE: - Log.d(LOG_TAG, "Event EVENT_RADIO_NOT_AVAILABLE Received"); //TODO Remove - //handleRadioNotAvailable(); //TODO + handleRadioNotAvailable(); break; + default:{ - throw new RuntimeException("unexpected event not handled"); + throw new RuntimeException("unexpected event not handled"); } } } - - private void log(String msg) { + + protected void log(String msg) { Log.d(LOG_TAG, "[CdmaCallTracker] " + msg); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java index 495bf3b66d89..019685b9cb79 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java @@ -18,17 +18,17 @@ package com.android.internal.telephony.cdma; import com.android.internal.telephony.*; +import android.os.AsyncResult; import android.os.Handler; -import android.os.Registrant; import android.os.Looper; import android.os.Message; -import android.os.AsyncResult; +import android.os.Registrant; import android.os.SystemClock; -import android.util.Log; import android.util.Config; +import android.util.Log; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; - + /** * {@hide} @@ -41,13 +41,13 @@ public class CdmaConnection extends Connection { CdmaCallTracker owner; CdmaCall parent; - - String address; // MAY BE NULL!!! + + String address; // MAY BE NULL!!! String dialString; // outgoing calls only - String postDialString; // outgoing calls only + String postDialString; // outgoing calls only boolean isIncoming; - boolean disconnected; - + boolean disconnected; + int index; // index in CdmaCallTracker.connections[], -1 if unassigned /* @@ -65,14 +65,14 @@ public class CdmaConnection extends Connection { */ long connectTimeReal; long duration; - long holdingStartTime; // The time when the Connection last transitioned + long holdingStartTime; // The time when the Connection last transitioned // into HOLDING int nextPostDialChar; // index into postDialString - + DisconnectCause cause = DisconnectCause.NOT_DISCONNECTED; PostDialState postDialState = PostDialState.NOT_STARTED; - + Handler h; //***** Event Constants @@ -93,6 +93,7 @@ public class CdmaConnection extends Connection { public void handleMessage(Message msg) { + switch (msg.what) { case EVENT_NEXT_POST_DIAL: case EVENT_DTMF_DONE: @@ -143,6 +144,9 @@ public class CdmaConnection extends Connection { parent.attachFake(this, CdmaCall.State.DIALING); } + public void dispose() { + } + static boolean equalsHandlesNulls (Object a, Object b) { return (a == null) ? (b == null) : a.equals (b); @@ -161,19 +165,18 @@ public class CdmaConnection extends Connection { // no control over when they begin, so we might as well String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA); - return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); - } - + return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); + } + public String toString() { return (isIncoming ? "incoming" : "outgoing"); } public String getAddress() { - return address; + return address; } - public CdmaCall getCall() { return parent; } @@ -220,13 +223,13 @@ public class CdmaConnection extends Connection { public CdmaCall.State getState() { if (disconnected) { return CdmaCall.State.DISCONNECTED; - } else { + } else { return super.getState(); } } public void hangup() throws CallStateException { - if (!disconnected) { + if (!disconnected) { owner.hangup(this); } else { throw new CallStateException ("disconnected"); @@ -234,7 +237,7 @@ public class CdmaConnection extends Connection { } public void separate() throws CallStateException { - if (!disconnected) { + if (!disconnected) { owner.separate(this); } else { throw new CallStateException ("disconnected"); @@ -247,7 +250,7 @@ public class CdmaConnection extends Connection { public void proceedAfterWaitChar() { if (postDialState != PostDialState.WAIT) { - Log.w(LOG_TAG, "CdmaConnection.proceedAfterWaitChar(): Expected " + Log.w(LOG_TAG, "CdmaConnection.proceedAfterWaitChar(): Expected " + "getPostDialState() to be WAIT but was " + postDialState); return; } @@ -256,10 +259,10 @@ public class CdmaConnection extends Connection { processNextPostDialChar(); } - + public void proceedAfterWildChar(String str) { if (postDialState != PostDialState.WILD) { - Log.w(LOG_TAG, "CdmaConnection.proceedAfterWaitChar(): Expected " + Log.w(LOG_TAG, "CdmaConnection.proceedAfterWaitChar(): Expected " + "getPostDialState() to be WILD but was " + postDialState); return; } @@ -296,22 +299,22 @@ public class CdmaConnection extends Connection { postDialString = buf.toString(); nextPostDialChar = 0; if (Phone.DEBUG_PHONE) { - log("proceedAfterWildChar: new postDialString is " + + log("proceedAfterWildChar: new postDialString is " + postDialString); } processNextPostDialChar(); } } - + public void cancelPostDial() { postDialState = PostDialState.CANCELLED; } - /** + /** * Called when this Connection is being hung up locally (eg, user pressed "end") * Note that at this point, the hangup request has been dispatched to the radio - * but no response has yet been received so update() has not yet been called + * but no response has yet been received so update() has not yet been called */ void onHangupLocal() { @@ -324,31 +327,12 @@ public class CdmaConnection extends Connection { * See 22.001 Annex F.4 for mapping of cause codes * to local tones */ - + switch (causeCode) { case CallFailCause.USER_BUSY: return DisconnectCause.BUSY; - - // TODO: check if cases are needed for CDMA -// case CallFailCause.NO_CIRCUIT_AVAIL: -// case CallFailCause.TEMPORARY_FAILURE: -// case CallFailCause.SWITCHING_CONGESTION: -// case CallFailCause.CHANNEL_NOT_AVAIL: -// case CallFailCause.QOS_NOT_AVAIL: -// case CallFailCause.BEARER_NOT_AVAIL: -// return DisconnectCause.CONGESTION; -// -// case CallFailCause.ACM_LIMIT_EXCEEDED: -// return DisconnectCause.LIMIT_EXCEEDED; -// -// case CallFailCause.CALL_BARRED: -// return DisconnectCause.CALL_BARRED; -// -// case CallFailCause.FDN_BLOCKED: -// return DisconnectCause.FDN_BLOCKED; - case CallFailCause.ERROR_UNSPECIFIED: - case CallFailCause.NORMAL_CLEARING: + case CallFailCause.NORMAL_CLEARING: default: CDMAPhone phone = owner.phone; int serviceState = phone.getServiceState().getState(); @@ -357,8 +341,9 @@ public class CdmaConnection extends Connection { } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE || serviceState == ServiceState.STATE_EMERGENCY_ONLY ) { return DisconnectCause.OUT_OF_SERVICE; - } else if (phone.getIccCard().getState() != RuimCard.State.READY) { - return DisconnectCause.SIM_ERROR; + } else if (phone.mCM.getRadioState() != CommandsInterface.RadioState.NV_READY + && phone.getIccCard().getState() != RuimCard.State.READY) { + return DisconnectCause.ICC_ERROR; } else { return DisconnectCause.NORMAL; } @@ -374,10 +359,10 @@ public class CdmaConnection extends Connection { /*package*/ void onDisconnect(DisconnectCause cause) { this.cause = cause; - - if (!disconnected) { + + if (!disconnected) { index = -1; - + disconnectTime = System.currentTimeMillis(); duration = SystemClock.elapsedRealtime() - connectTimeReal; disconnected = true; @@ -388,7 +373,7 @@ public class CdmaConnection extends Connection { owner.phone.notifyDisconnect(this); if (parent != null) { - parent.connectionDisconnected(this); + parent.connectionDisconnected(this); } } } @@ -463,13 +448,12 @@ public class CdmaConnection extends Connection { onStartedHolding(); } - // TODO: find another name for this function /*package*/ int - getGSMIndex() throws CallStateException { + getCDMAIndex() throws CallStateException { if (index >= 0) { return index + 1; } else { - throw new CallStateException ("GSM index not yet assigned"); + throw new CallStateException ("CDMA connection index not assigned"); } } @@ -510,21 +494,21 @@ public class CdmaConnection extends Connection { } else if (c == PhoneNumberUtils.PAUSE) { // From TS 22.101: - // "The first occurrence of the "DTMF Control Digits Separator" - // shall be used by the ME to distinguish between the addressing + // "The first occurrence of the "DTMF Control Digits Separator" + // shall be used by the ME to distinguish between the addressing // digits (i.e. the phone number) and the DTMF digits...." if (nextPostDialChar == 1) { // The first occurrence. // We don't need to pause here, but wait for just a bit anyway - h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), + h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), PAUSE_DELAY_FIRST_MILLIS); } else { // It continues... - // "Upon subsequent occurrences of the separator, the UE shall - // pause again for 3 seconds (\u00B1 20 %) before sending any + // "Upon subsequent occurrences of the separator, the UE shall + // pause again for 3 seconds (\u00B1 20 %) before sending any // further DTMF digits." - h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), + h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), PAUSE_DELAY_MILLIS); } } else if (c == PhoneNumberUtils.WAIT) { @@ -540,7 +524,7 @@ public class CdmaConnection extends Connection { public String getRemainingPostDialString() { - if (postDialState == PostDialState.CANCELLED + if (postDialState == PostDialState.CANCELLED || postDialState == PostDialState.COMPLETE || postDialString == null || postDialString.length() <= nextPostDialChar @@ -550,7 +534,7 @@ public class CdmaConnection extends Connection { return postDialString.substring(nextPostDialChar); } - + private void processNextPostDialChar() { char c = 0; @@ -569,7 +553,7 @@ public class CdmaConnection extends Connection { c = 0; } else { boolean isValid; - + postDialState = PostDialState.STARTED; c = postDialString.charAt(nextPostDialChar++); @@ -589,7 +573,8 @@ public class CdmaConnection extends Connection { Message notifyMessage; - if (postDialHandler != null && (notifyMessage = postDialHandler.messageForRegistrant()) != null) { + if (postDialHandler != null && + (notifyMessage = postDialHandler.messageForRegistrant()) != null) { // The AsyncResult.result is the Connection object PostDialState state = postDialState; AsyncResult ar = AsyncResult.forMessage(notifyMessage); @@ -599,17 +584,8 @@ public class CdmaConnection extends Connection { // arg1 is the character that was/is being processed notifyMessage.arg1 = c; - //Log.v("CDMA", "##### processNextPostDialChar: send msg to postDialHandler, arg1=" + c); notifyMessage.sendToTarget(); } -/* Reviewer Comment: moved due to Line length more than 100 - else { - if (postDialHandler == null) - Log.v("CDMA", "##### processNextPostDialChar: postDialHandler is NULL!"); - else - Log.v("CDMA", "##### processNextPostDialChar: postDialHandler.messageForRegistrant() returned NULL!"); - } -*/ } @@ -618,11 +594,11 @@ public class CdmaConnection extends Connection { */ private boolean isConnectingInOrOut() { - return parent == null || parent == owner.ringingCall - || parent.state == CdmaCall.State.DIALING + return parent == null || parent == owner.ringingCall + || parent.state == CdmaCall.State.DIALING || parent.state == CdmaCall.State.ALERTING; } - + private CdmaCall parentFromDCState (DriverCall.State state) { switch (state) { diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java new file mode 100644 index 000000000000..1b431c9f1fea --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java @@ -0,0 +1,315 @@ +/* + * 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.cdma; + +import android.os.*; +import android.util.EventLog; +import android.util.Log; + +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataLink; +import com.android.internal.telephony.RILConstants; + +/** + * {@hide} + * + */ +public class CdmaDataConnection extends DataConnection { + + private static final String LOG_TAG = "CDMA"; + private static final boolean DBG = true; + + /** Fail cause of last Data Call activate from RIL_LastDataCallActivateFailCause */ + private final static int PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING = 8; + private final static int PS_NET_DOWN_REASON_UNKNOWN_APN = 27; + private final static int PS_NET_DOWN_REASON_AUTH_FAILED = 29; + private final static int PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED = 32; + private final static int PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED = 33; + +/** It is likely that the number of error codes listed below will be removed + * in the foreseeable future. They have been added, but not agreed upon. + * + */ + private final static int PS_NET_DOWN_REASON_NOT_SPECIFIED = 0; + private final static int PS_NET_DOWN_REASON_CLOSE_IN_PROGRESS = 1; + private final static int PS_NET_DOWN_REASON_NW_INITIATED_TERMINATION = 2; + private final static int PS_NET_DOWN_REASON_APP_PREEMPTED = 3; + private final static int PS_NET_DOWN_REASON_LLC_SNDCP_FAILURE = 25; + private final static int PS_NET_DOWN_REASON_INSUFFICIENT_RESOURCES = 26; + private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP = 28; + private final static int PS_NET_DOWN_REASON_GGSN_REJECT = 30; + private final static int PS_NET_DOWN_REASON_ACTIVATION_REJECT = 31; + private final static int PS_NET_DOWN_REASON_OPTION_TEMP_OOO = 34; + private final static int PS_NET_DOWN_REASON_NSAPI_ALREADY_USED = 35; + private final static int PS_NET_DOWN_REASON_REGULAR_DEACTIVATION = 36; + private final static int PS_NET_DOWN_REASON_QOS_NOT_ACCEPTED = 37; + private final static int PS_NET_DOWN_REASON_NETWORK_FAILURE = 38; + private final static int PS_NET_DOWN_REASON_UMTS_REATTACH_REQ = 39; + private final static int PS_NET_DOWN_REASON_TFT_SEMANTIC_ERROR = 41; + private final static int PS_NET_DOWN_REASON_TFT_SYNTAX_ERROR = 42; + private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP_CONTEXT = 43; + private final static int PS_NET_DOWN_REASON_FILTER_SEMANTIC_ERROR = 44; + private final static int PS_NET_DOWN_REASON_FILTER_SYNTAX_ERROR = 45; + private final static int PS_NET_DOWN_REASON_PDP_WITHOUT_ACTIVE_TFT = 46; + private final static int PS_NET_DOWN_REASON_INVALID_TRANSACTION_ID = 81; + private final static int PS_NET_DOWN_REASON_MESSAGE_INCORRECT_SEMANTIC = 95; + private final static int PS_NET_DOWN_REASON_INVALID_MANDATORY_INFO = 96; + private final static int PS_NET_DOWN_REASON_MESSAGE_TYPE_UNSUPPORTED = 97; + private final static int PS_NET_DOWN_REASON_MSG_TYPE_NONCOMPATIBLE_STATE = 98; + private final static int PS_NET_DOWN_REASON_UNKNOWN_INFO_ELEMENT = 99; + private final static int PS_NET_DOWN_REASON_CONDITIONAL_IE_ERROR = 100; + private final static int PS_NET_DOWN_REASON_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101; + private final static int PS_NET_DOWN_REASON_PROTOCOL_ERROR = 111; + private final static int PS_NET_DOWN_REASON_APN_TYPE_CONFLICT = 112; + private final static int PS_NET_DOWN_REASON_UNKNOWN_CAUSE_CODE = 113; + private final static int PS_NET_DOWN_REASON_INTERNAL_MIN = 200; + private final static int PS_NET_DOWN_REASON_INTERNAL_ERROR = 201; + private final static int PS_NET_DOWN_REASON_INTERNAL_CALL_ENDED = 202; + private final static int PS_NET_DOWN_REASON_INTERNAL_UNKNOWN_CAUSE_CODE = 203; + private final static int PS_NET_DOWN_REASON_INTERNAL_MAX = 204; + private final static int PS_NET_DOWN_REASON_CDMA_LOCK = 500; + private final static int PS_NET_DOWN_REASON_INTERCEPT = 501; + private final static int PS_NET_DOWN_REASON_REORDER = 502; + private final static int PS_NET_DOWN_REASON_REL_SO_REJ = 503; + private final static int PS_NET_DOWN_REASON_INCOM_CALL = 504; + private final static int PS_NET_DOWN_REASON_ALERT_STOP = 505; + private final static int PS_NET_DOWN_REASON_ACTIVATION = 506; + private final static int PS_NET_DOWN_REASON_MAX_ACCESS_PROBE = 507; + private final static int PS_NET_DOWN_REASON_CCS_NOT_SUPPORTED_BY_BS = 508; + private final static int PS_NET_DOWN_REASON_NO_RESPONSE_FROM_BS = 509; + private final static int PS_NET_DOWN_REASON_REJECTED_BY_BS = 510; + private final static int PS_NET_DOWN_REASON_INCOMPATIBLE = 511; + private final static int PS_NET_DOWN_REASON_ALREADY_IN_TC = 512; + private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_GPS = 513; + private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_SMS = 514; + private final static int PS_NET_DOWN_REASON_NO_CDMA_SRV = 515; + private final static int PS_NET_DOWN_REASON_CONF_FAILED = 1000; + private final static int PS_NET_DOWN_REASON_INCOM_REJ = 1001; + private final static int PS_NET_DOWN_REASON_NO_GW_SRV = 1002; + private final static int PS_NET_DOWN_REASON_CD_GEN_OR_BUSY = 1500; + private final static int PS_NET_DOWN_REASON_CD_BILL_OR_AUTH = 1501; + private final static int PS_NET_DOWN_REASON_CHG_HDR = 1502; + private final static int PS_NET_DOWN_REASON_EXIT_HDR = 1503; + private final static int PS_NET_DOWN_REASON_HDR_NO_SESSION = 1504; + private final static int PS_NET_DOWN_REASON_HDR_ORIG_DURING_GPS_FIX = 1505; + private final static int PS_NET_DOWN_REASON_HDR_CS_TIMEOUT = 1506; + private final static int PS_NET_DOWN_REASON_HDR_RELEASED_BY_CM = 1507; + private final static int PS_NET_DOWN_REASON_CLIENT_END = 2000; + private final static int PS_NET_DOWN_REASON_NO_SRV = 2001; + private final static int PS_NET_DOWN_REASON_FADE = 2002; + private final static int PS_NET_DOWN_REASON_REL_NORMAL = 2003; + private final static int PS_NET_DOWN_REASON_ACC_IN_PROG = 2004; + private final static int PS_NET_DOWN_REASON_ACC_FAIL = 2005; + private final static int PS_NET_DOWN_REASON_REDIR_OR_HANDOFF = 2006; + + // ***** Instance Variables + + // ***** Constructor + CdmaDataConnection(CDMAPhone phone) { + super(phone); + + if (DBG) log("CdmaDataConnection <constructor>"); + } + + /** + * Setup a data connection + * + * @param onCompleted + * notify success or not after down + */ + void connect(Message onCompleted) { + if (DBG) log("CdmaDataConnection Connecting..."); + + //setHttpProxy (apn.proxy, apn.port); + + state = State.ACTIVATING; + onConnectCompleted = onCompleted; + createTime = -1; + lastFailTime = -1; + lastFailCause = FailCause.NONE; + receivedDisconnectReq = false; + phone.mCM.setupDataCall(Integer.toString(RILConstants.CDMA_PHONE), null, null, null, + null, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); + } + + protected void disconnect(Message msg) { + onDisconnect = msg; + if (state == State.ACTIVE) { + if (phone.mCM.getRadioState().isOn()) { + phone.mCM.deactivateDataCall(cid, obtainMessage( + EVENT_DEACTIVATE_DONE, msg)); + } + } else if (state == State.ACTIVATING) { + receivedDisconnectReq = true; + } + } + + + public String toString() { + return "State=" + state + " create=" + createTime + " lastFail=" + + lastFailTime + " lastFailCause=" + lastFailCause; + } + + + protected void notifyFail(FailCause cause, Message onCompleted) { + if (onCompleted == null) { + return; + } + state = State.INACTIVE; + lastFailCause = cause; + lastFailTime = System.currentTimeMillis(); + onConnectCompleted = null; + + if(DBG) { + log("Notify data connection fail at " + lastFailTime + + " due to " + lastFailCause); + } + + AsyncResult.forMessage(onCompleted, cause, new Exception()); + onCompleted.sendToTarget(); + } + + protected void notifySuccess(Message onCompleted) { + if (onCompleted == null) { + return; + } + + state = State.ACTIVE; + createTime = System.currentTimeMillis(); + onConnectCompleted = null; + onCompleted.arg1 = cid; + + if (DBG) log("Notify data connection success at " + createTime); + + AsyncResult.forMessage(onCompleted); + onCompleted.sendToTarget(); + } + + protected void notifyDisconnect(Message msg) { + if (DBG) log("Notify data connection disconnect"); + + if (msg != null) { + AsyncResult.forMessage(msg); + msg.sendToTarget(); + } + clearSettings(); + } + + protected void onLinkStateChanged(DataLink.LinkState linkState) { + switch (linkState) { + case LINK_UP: + notifySuccess(onConnectCompleted); + break; + + case LINK_DOWN: + case LINK_EXITED: + phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE)); + break; + } + } + + protected FailCause getFailCauseFromRequest(int rilCause) { + FailCause cause; + + switch (rilCause) { + case PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING: + cause = FailCause.BARRED; + break; + case PS_NET_DOWN_REASON_AUTH_FAILED: + cause = FailCause.USER_AUTHENTICATION; + break; + case PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED: + cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED; + break; + case PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED: + cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED; + break; + default: + cause = FailCause.UNKNOWN; + } + return cause; + } + + protected void log(String s) { + Log.d(LOG_TAG, "[CdmaDataConnection] " + s); + } + + @Override + protected void onDeactivated(AsyncResult ar) { + notifyDisconnect((Message) ar.userObj); + if (DBG) log("CDMA Connection Deactivated"); + } + + @Override + protected void onSetupConnectionCompleted(AsyncResult ar) { + if (ar.exception != null) { + Log.e(LOG_TAG, "CdmaDataConnection Init failed " + ar.exception); + + if (receivedDisconnectReq) { + // Don't bother reporting the error if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + notifyDisconnect(onDisconnect); + } else { + if (ar.exception instanceof CommandException + && ((CommandException) (ar.exception)).getCommandError() + == CommandException.Error.RADIO_NOT_AVAILABLE) { + notifyFail(FailCause.RADIO_NOT_AVAILABLE, onConnectCompleted); + } else { + phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE)); + } + } + } else { + if (receivedDisconnectReq) { + // Don't bother reporting success if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + disconnect(onDisconnect); + } else { + String[] response = ((String[]) ar.result); + cid = Integer.parseInt(response[0]); + + if (response.length > 2) { + interfaceName = response[1]; + ipAddress = response[2]; + String prefix = "net." + interfaceName + "."; + gatewayAddress = SystemProperties.get(prefix + "gw"); + dnsServers[0] = SystemProperties.get(prefix + "dns1"); + dnsServers[1] = SystemProperties.get(prefix + "dns2"); + if (DBG) { + log("interface=" + interfaceName + " ipAddress=" + ipAddress + + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0] + + " DNS2=" + dnsServers[1]); + } + + if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])) { + // Work around a race condition where QMI does not fill in DNS: + // Deactivate PDP and let DataConnectionTracker retry. + EventLog.writeEvent(EVENT_LOG_BAD_DNS_ADDRESS, dnsServers[0]); + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY)); + return; + } + } + + onLinkStateChanged(DataLink.LinkState.LINK_UP); + + if (DBG) log("CdmaDataConnection setup on cid = " + cid); + } + } + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java new file mode 100644 index 000000000000..bc9f0d3a7003 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -0,0 +1,738 @@ +/* + * 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.cdma; + +import android.app.AlarmManager; +import android.app.IAlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.os.AsyncResult; +import android.os.Handler; +import android.os.INetStatService; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.preference.PreferenceManager; +import android.provider.Checkin; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; +import android.telephony.ServiceState; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataConnection.FailCause; +import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; + +import java.util.ArrayList; + +/** + * {@hide} + * + */ +public final class CdmaDataConnectionTracker extends DataConnectionTracker { + private static final String LOG_TAG = "CDMA"; + private static final boolean DBG = true; + + //***** Instance Variables + + // Indicates baseband will not auto-attach + private boolean noAutoAttach = false; + long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + private IntentFilter filterS; + private IntentFilter filter; + + //useful for debugging + boolean failNextConnect = false; + + /** + * dataConnectionList holds all the Data connection + */ + private ArrayList<DataConnection> dataConnectionList; + + /** Currently active CdmaDataConnection */ + private CdmaDataConnection mActiveDataConnection; + + /** Defined cdma connection profiles */ + private static int EXTERNAL_NETWORK_DEFAULT_ID = 0; + private static int EXTERNAL_NETWORK_NUM_TYPES = 1; + + private boolean[] dataEnabled = new boolean[EXTERNAL_NETWORK_NUM_TYPES]; + + //***** Constants + + /** + * Pool size of CdmaDataConnection objects. + */ + private static final int DATA_CONNECTION_POOL_SIZE = 1; + + private static final int POLL_CONNECTION_MILLIS = 5 * 1000; + static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.cdma-reconnect"; + + BroadcastReceiver screenOnOffReceiver = new BroadcastReceiver () { + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_SCREEN_ON) && + phone.getState() == Phone.State.IDLE) { + stopNetStatPoll(); + startNetStatPoll(); + } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { + stopNetStatPoll(); + startNetStatPoll(); + } else { + Log.w(LOG_TAG, "DataConnectionTracker received unexpected Intent: " + + intent.getAction()); + } + } + }; + + BroadcastReceiver alarmReceiver = new BroadcastReceiver () { + + public void onReceive(Context context, Intent intent) { + Log.d(LOG_TAG, "Data reconnect alarm. Previous state was " + state); + + if (state == State.FAILED) { + cleanUpConnection(false, null); + } + + trySetupData(null); + } + }; + + + //***** Constructor + + CdmaDataConnectionTracker(CDMAPhone p) { + super(p); + + p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); + p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + p.mRuimRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); + p.mCM.registerForNVReady(this, EVENT_NV_READY, null); + p.mCM.registerForDataStateChanged (this, EVENT_DATA_STATE_CHANGED, null); + p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); + p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); + p.mSST.registerForCdmaDataConnectionAttached(this, EVENT_TRY_SETUP_DATA, null); + p.mSST.registerForCdmaDataConnectionDetached(this, EVENT_CDMA_DATA_DETACHED, null); + p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); + p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); + + this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); + + filter = new IntentFilter(); + filter.addAction(INTENT_RECONNECT_ALARM); + phone.getContext().registerReceiver( + alarmReceiver, filter, null, phone.getHandler()); + + filterS = new IntentFilter(); + filterS.addAction(Intent.ACTION_SCREEN_ON); + filterS.addAction(Intent.ACTION_SCREEN_OFF); + p.getContext().registerReceiver(screenOnOffReceiver, filterS); + + mDataConnectionTracker = this; + + createAllDataConnectionList(); + + // This preference tells us 1) initial condition for "dataEnabled", + // and 2) whether the RIL will setup the baseband to auto-PS attach. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); + + dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID] = + !sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false); + noAutoAttach = !dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]; + } + + public void dispose() { + //Unregister from all events + phone.mCM.unregisterForAvailable(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + ((CDMAPhone) phone).mRuimRecords.unregisterForRecordsLoaded(this); + phone.mCM.unregisterForNVReady(this); + phone.mCM.unregisterForDataStateChanged(this); + ((CDMAPhone) phone).mCT.unregisterForVoiceCallEnded(this); + ((CDMAPhone) phone).mCT.unregisterForVoiceCallStarted(this); + ((CDMAPhone) phone).mSST.unregisterForCdmaDataConnectionAttached(this); + ((CDMAPhone) phone).mSST.unregisterForCdmaDataConnectionDetached(this); + ((CDMAPhone) phone).mSST.unregisterForRoamingOn(this); + ((CDMAPhone) phone).mSST.unregisterForRoamingOff(this); + + phone.getContext().unregisterReceiver(this.alarmReceiver); + phone.getContext().unregisterReceiver(this.screenOnOffReceiver); + destroyAllDataConnectionList(); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "CdmaDataConnectionTracker finalized"); + } + + void setState(State s) { + if (state != s) { + if (s == State.INITING) { // request Data connection context + Checkin.updateStats(phone.getContext().getContentResolver(), + Checkin.Stats.Tag.PHONE_CDMA_DATA_ATTEMPTED, 1, 0.0); + } + + if (s == State.CONNECTED) { // pppd is up + Checkin.updateStats(phone.getContext().getContentResolver(), + Checkin.Stats.Tag.PHONE_CDMA_DATA_CONNECTED, 1, 0.0); + } + } + + state = s; + } + + public int enableApnType(String type) { + // This request is mainly used to enable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to enableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_ALREADY_ACTIVE; + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + public int disableApnType(String type) { + // This request is mainly used to disable MMS APN + // In CDMA there is no need to enable/disable a different APN for MMS + Log.d(LOG_TAG, "Request to disableApnType("+type+")"); + if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return Phone.APN_REQUEST_STARTED; + } else { + return Phone.APN_REQUEST_FAILED; + } + } + + private boolean isEnabled(int cdmaDataProfile) { + return dataEnabled[cdmaDataProfile]; + } + + private void setEnabled(int cdmaDataProfile, boolean enable) { + Log.d(LOG_TAG, "setEnabled(" + cdmaDataProfile + ", " + enable + ')'); + dataEnabled[cdmaDataProfile] = enable; + Log.d(LOG_TAG, "dataEnabled[DEFAULT_PROFILE]=" + dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]); + } + + /** + * Prevent mobile data connections from being established, + * or once again allow mobile data connections. If the state + * toggles, then either tear down or set up data, as + * appropriate to match the new state. + * <p>This operation only affects the default connection + * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data + * @return {@code true} if the operation succeeded + */ + public boolean setDataEnabled(boolean enable) { + + boolean isEnabled = isEnabled(EXTERNAL_NETWORK_DEFAULT_ID); + + Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled); + if (!isEnabled && enable) { + setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, true); + return trySetupData(Phone.REASON_DATA_ENABLED); + } else if (!enable) { + setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, false); + return false; + } else // isEnabled && enable + + return true; + } + + /** + * Report the current state of data connectivity (enabled or disabled) + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + public boolean getDataEnabled() { + return dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]; + } + + /** + * Report on whether data connectivity is enabled + * @return {@code false} if data connectivity has been explicitly disabled, + * {@code true} otherwise. + */ + public boolean getAnyDataEnabled() { + for (int i=0; i < EXTERNAL_NETWORK_NUM_TYPES; i++) { + if (isEnabled(i)) return true; + } + return false; + } + + //Retrieve the data roaming setting from the shared preferences. + public boolean getDataOnRoamingEnabled() { + try { + return Settings.System.getInt(phone.getContext().getContentResolver(), + Settings.System.DATA_ROAMING) > 0; + } catch (SettingNotFoundException snfe) { + return false; + } + } + + private boolean isDataAllowed() { + boolean roaming = phone.getServiceState().getRoaming(); + return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled()); + } + + private boolean trySetupData(String reason) { + if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); + + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + setState(State.CONNECTED); + phone.notifyDataConnection(reason); + + Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected"); + return true; + } + + int psState = ((CDMAPhone) phone).mSST.getCurrentCdmaDataConnectionState(); + boolean roaming = phone.getServiceState().getRoaming(); + + if ((state == State.IDLE || state == State.SCANNING) + && (psState == ServiceState.RADIO_TECHNOLOGY_1xRTT || + psState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 || + psState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) + && ((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) || + ((CDMAPhone) phone).mRuimRecords.getRecordsLoaded()) + && ( ((CDMAPhone) phone).mSST.isConcurrentVoiceAndData() || + phone.getState() == Phone.State.IDLE ) + && isDataAllowed()) { + + return setupData(reason); + + } else { + if (DBG) { + log("trySetupData: Not ready for data: " + + " dataState=" + state + + " PS state=" + psState + + " radio state=" + phone.mCM.getRadioState() + + " ruim=" + ((CDMAPhone) phone).mRuimRecords.getRecordsLoaded() + + " concurrentVoice&Data=" + ((CDMAPhone) phone).mSST.isConcurrentVoiceAndData() + + " phoneState=" + phone.getState() + + " dataEnabled=" + getAnyDataEnabled() + + " roaming=" + roaming + + " dataOnRoamingEnable=" + getDataOnRoamingEnabled()); + } + return false; + } + } + + /** + * If tearDown is true, this only tears down a CONNECTED session. Presently, + * there is no mechanism for abandoning an INITING/CONNECTING session, + * but would likely involve cancelling pending async requests or + * setting a flag or new state to ignore them when they came in + * @param tearDown true if the underlying DataConnection should be + * disconnected. + * @param reason reason for the clean up. + */ + private void cleanUpConnection(boolean tearDown, String reason) { + if (DBG) log("Clean up connection due to " + reason); + + for (DataConnection connBase : dataConnectionList) { + CdmaDataConnection conn = (CdmaDataConnection) connBase; + + if(conn != null) { + if (tearDown) { + Message msg = obtainMessage(EVENT_DISCONNECT_DONE); + conn.disconnect(msg); + } else { + conn.clearSettings(); + } + } + } + + stopNetStatPoll(); + setState(State.IDLE); + phone.notifyDataConnection(reason); + } + + private CdmaDataConnection findFreeDataConnection() { + for (DataConnection connBase : dataConnectionList) { + CdmaDataConnection conn = (CdmaDataConnection) connBase; + if (conn.getState() == DataConnection.State.INACTIVE) { + return conn; + } + } + return null; + } + + private boolean setupData(String reason) { + + CdmaDataConnection conn = findFreeDataConnection(); + + if (conn == null) { + if (DBG) log("setupData: No free CdmaDataConnectionfound!"); + return false; + } + + mActiveDataConnection = conn; + + Message msg = obtainMessage(); + msg.what = EVENT_DATA_SETUP_COMPLETE; + + conn.connect(msg); + + setState(State.INITING); + phone.notifyDataConnection(reason); + return true; + } + + private void notifyDefaultData() { + setState(State.CONNECTED); + phone.notifyDataConnection(null); + startNetStatPoll(); + // reset reconnect timer + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + } + + private void resetPollStats() { + txPkts = -1; + rxPkts = -1; + sentSinceLastRecv = 0; + netStatPollPeriod = POLL_NETSTAT_MILLIS; + mNoRecvPollCount = 0; + } + + protected void startNetStatPoll() { + if (state == State.CONNECTED) { + Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); + resetPollStats(); + netStatPollEnabled = true; + mPollNetStat.run(); + } + } + + protected void stopNetStatPoll() { + netStatPollEnabled = false; + removeCallbacks(mPollNetStat); + Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); + } + + protected void restartRadio() { + Log.d(LOG_TAG, "************TURN OFF RADIO**************"); + cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); + phone.mCM.setRadioPower(false, null); + /* Note: no need to call setRadioPower(true). Assuming the desired + * radio power state is still ON (as tracked by ServiceStateTracker), + * ServiceStateTracker will call setRadioPower when it receives the + * RADIO_STATE_CHANGED notification for the power off. And if the + * desired power state has changed in the interim, we don't want to + * override it with an unconditional power on. + */ + } + + /** + * Returns true if the last fail cause is something that + * seems like it deserves an error notification. + * Transient errors are ignored + */ + private boolean + shouldPostNotification(FailCause cause) { + return (cause != FailCause.UNKNOWN); + } + + private void + reconnectAfterFail(FailCause lastFailCauseCode) { + if (state == State.FAILED) { + Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for " + + (nextReconnectDelay / 1000) + "s"); + + try { + IAlarmManager am = IAlarmManager.Stub.asInterface( + ServiceManager.getService(Context.ALARM_SERVICE)); + PendingIntent sender = PendingIntent.getBroadcast( + phone.getContext(), 0, + new Intent(INTENT_RECONNECT_ALARM), 0); + am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + nextReconnectDelay, + sender); + } catch (RemoteException ex) { + } + + // double it for next time + nextReconnectDelay *= 2; + + if (!shouldPostNotification(lastFailCauseCode)) { + Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification " + + "-- likely transient error"); + } else { + notifyNoData(lastFailCauseCode); + } + } + } + + private void notifyNoData(FailCause lastFailCauseCode) { + setState(State.FAILED); + } + + protected void onRecordsLoaded() { + if (state == State.FAILED) { + cleanUpConnection(false, null); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + } + + protected void onNVReady() { + if (state == State.FAILED) { + cleanUpConnection(false, null); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onTrySetupData() { + trySetupData(null); + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRoamingOff() { + trySetupData(Phone.REASON_ROAMING_OFF); + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRoamingOn() { + if (getDataOnRoamingEnabled()) { + trySetupData(Phone.REASON_ROAMING_ON); + } else { + if (DBG) log("Tear down data connection on roaming."); + cleanUpConnection(true, Phone.REASON_ROAMING_ON); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRadioAvailable() { + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + setState(State.CONNECTED); + phone.notifyDataConnection(null); + + Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); + } + + if (state != State.IDLE) { + cleanUpConnection(true, null); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onRadioOffOrNotAvailable() { + // Make sure our reconnect delay starts at the initial value + // next time the radio comes on + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); + } else { + if (DBG) log("Radio is off and clean up all connection"); + cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onDataSetupComplete(AsyncResult ar) { + + if (ar.exception == null) { + // everything is setup + notifyDefaultData(); + + } else { + FailCause cause = (FailCause) (ar.result); + if(DBG) log("Data Connection setup failed " + cause); + + // No try for permanent failure + if (cause.isPermanentFail()) { + notifyNoData(cause); + } + + if (tryAgain(cause)) { + trySetupData(null); + } else { + notifyNoData(cause); + reconnectAfterFail(cause); + } + } + + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onDisconnectDone() { + if(DBG) log("EVENT_DISCONNECT_DONE"); + trySetupData(null); + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onVoiceCallStarted() { + if (state == State.CONNECTED && !((CDMAPhone) phone).mSST.isConcurrentVoiceAndData()) { + stopNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); + } + } + + /** + * @override com.android.internal.telephony.DataConnectionTracker + */ + protected void onVoiceCallEnded() { + // in case data setup was attempted when we were on a voice call + trySetupData(Phone.REASON_VOICE_CALL_ENDED); + if (state == State.CONNECTED && + !((CDMAPhone) phone).mSST.isConcurrentVoiceAndData()) { + startNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); + } else { + // clean slate after call end. + resetPollStats(); + } + } + + private boolean tryAgain(FailCause cause) { + return (cause != FailCause.RADIO_NOT_AVAILABLE) + && (cause != FailCause.RADIO_OFF) + && (cause != FailCause.RADIO_ERROR_RETRY) + && (cause != FailCause.NO_SIGNAL) + && (cause != FailCause.SIM_LOCKED); + } + + private void createAllDataConnectionList() { + dataConnectionList = new ArrayList<DataConnection>(); + CdmaDataConnection dataConn; + + for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) { + dataConn = new CdmaDataConnection((CDMAPhone) phone); + dataConnectionList.add(dataConn); + } + } + + private void destroyAllDataConnectionList() { + if(dataConnectionList != null) { + CdmaDataConnection pdp; + dataConnectionList.removeAll(dataConnectionList); + } + } + + private void onCdmaDataAttached() { + if (state == State.CONNECTED) { + startNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED); + } else { + trySetupData(Phone.REASON_CDMA_DATA_DETACHED); + } + } + + protected void onDataStateChanged (AsyncResult ar) { + + if (ar.exception != null) { + // This is probably "radio not available" or something + // of that sort. If so, the whole connection is going + // to come down soon anyway + return; + } + + Log.i(LOG_TAG, "Data connection has changed."); + } + + String getInterfaceName() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getInterface(); + } + return null; + } + + protected String getIpAddress() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getIpAddress(); + } + return null; + } + + String getGateway() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getGatewayAddress(); + } + return null; + } + + protected String[] getDnsServers() { + if (mActiveDataConnection != null) { + return mActiveDataConnection.getDnsServers(); + } + return null; + } + + public ArrayList<DataConnection> getAllDataConnections() { + return dataConnectionList; + } + + public void handleMessage (Message msg) { + + switch (msg.what) { + case EVENT_RECORDS_LOADED: + onRecordsLoaded(); + break; + + case EVENT_NV_READY: + onNVReady(); + break; + + case EVENT_CDMA_DATA_DETACHED: + onCdmaDataAttached(); + break; + + case EVENT_DATA_STATE_CHANGED: + onDataStateChanged((AsyncResult) msg.obj); + break; + + default: + // handle the message in the super class DataConnectionTracker + super.handleMessage(msg); + break; + } + } + + protected void log(String s) { + Log.d(LOG_TAG, "[CdmaDataConnectionTracker] " + s); + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java new file mode 100644 index 000000000000..b96366b6f976 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java @@ -0,0 +1,375 @@ +/* + * Copyright (C) 2008 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.cdma; + + +import android.app.PendingIntent; +import android.content.ContentValues; +import android.database.Cursor; +import android.database.SQLException; +import android.os.AsyncResult; +import android.os.Message; +import android.util.Config; +import android.util.Log; + +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.SMSDispatcher; +import com.android.internal.telephony.cdma.SmsMessage; +import com.android.internal.telephony.cdma.sms.SmsEnvelope; +import com.android.internal.util.HexDump; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; +import java.util.HashMap; + + +final class CdmaSMSDispatcher extends SMSDispatcher { + private static final String TAG = "CDMA"; + + CdmaSMSDispatcher(CDMAPhone phone) { + super(phone); + } + + /** + * Called when a status report is received. This should correspond to + * a previously successful SEND. + * Is a special GSM function, should never be called in CDMA!! + * + * @param ar AsyncResult passed into the message handler. ar.result should + * be a String representing the status report PDU, as ASCII hex. + */ + protected void handleStatusReport(AsyncResult ar) { + Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!"); + } + + /** + * Dispatches an incoming SMS messages. + * + * @param smsb the incoming message from the phone + */ + protected void dispatchMessage(SmsMessageBase smsb) { + SmsMessage sms = (SmsMessage) smsb; + int teleService; + boolean handled = false; + + // Decode BD stream and set sms variables. + sms.parseSms(); + teleService = sms.getTeleService(); + + // Teleservices W(E)MT and VMN are handled together: + if ((SmsEnvelope.TELESERVICE_WMT == teleService) + ||(SmsEnvelope.TELESERVICE_WEMT == teleService) + ||(SmsEnvelope.TELESERVICE_VMN == teleService)){ + // From here on we need decoded BD. + // Special case the message waiting indicator messages + if (sms.isMWISetMessage()) { + ((CDMAPhone) mPhone).updateMessageWaitingIndicator(true); + + if (sms.isMwiDontStore()) { + handled = true; + } + + if (Config.LOGD) { + Log.d(TAG, + "Received voice mail indicator set SMS shouldStore=" + !handled); + } + } else if (sms.isMWIClearMessage()) { + ((CDMAPhone) mPhone).updateMessageWaitingIndicator(false); + + if (sms.isMwiDontStore()) { + handled = true; + } + + if (Config.LOGD) { + Log.d(TAG, + "Received voice mail indicator clear SMS shouldStore=" + !handled); + } + } + } + + if (null == sms.getUserData()){ + handled = true; + if (Config.LOGD) { + Log.d(TAG, "Received SMS without user data"); + } + } + + if (handled) return; + + if (SmsEnvelope.TELESERVICE_WAP == teleService){ + processCdmaWapPdu(sms.getUserData(), sms.messageRef, sms.getOriginatingAddress()); + return; + } + + // Parse the headers to see if this is partial, or port addressed + int referenceNumber = -1; + int count = 0; + int sequence = 0; + int destPort = -1; + // From here on we need BD distributed to SMS member variables. + + SmsHeader header = sms.getUserDataHeader(); + if (header != null) { + for (SmsHeader.Element element : header.getElements()) { + switch (element.getID()) { + case SmsHeader.CONCATENATED_8_BIT_REFERENCE: { + byte[] data = element.getData(); + + referenceNumber = data[0] & 0xff; + count = data[1] & 0xff; + sequence = data[2] & 0xff; + + break; + } + + case SmsHeader.CONCATENATED_16_BIT_REFERENCE: { + byte[] data = element.getData(); + + referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff); + count = data[2] & 0xff; + sequence = data[3] & 0xff; + + break; + } + + case SmsHeader.APPLICATION_PORT_ADDRESSING_8_BIT: { + byte[] data = element.getData(); + + destPort = data[0] & 0xff; + + break; + } + + case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: { + byte[] data = element.getData(); + + destPort = (data[0] & 0xff) << 8; + destPort |= (data[1] & 0xff); + + break; + } + } + } + } + + if (referenceNumber == -1) { + // notify everyone of the message if it isn't partial + byte[][] pdus = new byte[1][]; + pdus[0] = sms.getPdu(); + + if (destPort != -1) {// GSM-style WAP indication + if (destPort == SmsHeader.PORT_WAP_PUSH) { + dispatchWapPdu(sms.getUserData()); + } + // The message was sent to a port, so concoct a URI for it + dispatchPortAddressedPdus(pdus, destPort); + } else { + // It's a normal message, dispatch it + dispatchPdus(pdus); + } + } else { + // Process the message part + processMessagePart(sms, referenceNumber, sequence, count, destPort); + } + } + + /** + * Processes inbound messages that are in the WAP-WDP PDU format. See + * wap-259-wdp-20010614-a section 6.5 for details on the WAP-WDP PDU format. + * WDP segments are gathered until a datagram completes and gets dispatched. + * + * @param pdu The WAP-WDP PDU segment + */ + protected void processCdmaWapPdu(byte[] pdu, int referenceNumber, String address){ + int segment; + int totalSegments; + int index = 0; + int msgType; + + int sourcePort; + int destinationPort; + + msgType = pdu[index++]; + if (msgType != 0){ + Log.w(TAG, "Received a WAP SMS which is not WDP. Discard."); + return; + } + totalSegments = pdu[index++]; // >=1 + segment = pdu[index++]; // >=0 + + //process WDP segment + sourcePort = (0xFF & pdu[index++]) << 8; + sourcePort |= 0xFF & pdu[index++]; + destinationPort = (0xFF & pdu[index++]) << 8; + destinationPort |= 0xFF & pdu[index++]; + + // Lookup all other related parts + StringBuilder where = new StringBuilder("reference_number ="); + where.append(referenceNumber); + where.append(" AND address = ?"); + String[] whereArgs = new String[] {address}; + + Log.i(TAG, "Received WAP PDU. Type = " + msgType + ", originator = " + address + + ", src-port = " + sourcePort + ", dst-port = " + destinationPort + + ", ID = " + referenceNumber + ", segment# = " + segment + "/" + totalSegments); + + byte[][] pdus = null; + Cursor cursor = null; + try { + cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null); + int cursorCount = cursor.getCount(); + if (cursorCount != totalSegments - 1) { + // We don't have all the parts yet, store this one away + ContentValues values = new ContentValues(); + values.put("date", new Long(0)); + values.put("pdu", HexDump.toHexString(pdu, index, pdu.length - index)); + values.put("address", address); + values.put("reference_number", referenceNumber); + values.put("count", totalSegments); + values.put("sequence", segment); + values.put("destination_port", destinationPort); + + mResolver.insert(mRawUri, values); + + return; + } + + // All the parts are in place, deal with them + int pduColumn = cursor.getColumnIndex("pdu"); + int sequenceColumn = cursor.getColumnIndex("sequence"); + + pdus = new byte[totalSegments][]; + for (int i = 0; i < cursorCount; i++) { + cursor.moveToNext(); + int cursorSequence = (int)cursor.getLong(sequenceColumn); + pdus[cursorSequence - 1] = HexDump.hexStringToByteArray( + cursor.getString(pduColumn)); + } + // The last part will be added later + + // Remove the parts from the database + mResolver.delete(mRawUri, where.toString(), whereArgs); + } catch (SQLException e) { + Log.e(TAG, "Can't access multipart SMS database", e); + return; // TODO: NACK the message or something, don't just discard. + } finally { + if (cursor != null) cursor.close(); + } + + // Build up the data stream + ByteArrayOutputStream output = new ByteArrayOutputStream(); + for (int i = 0; i < totalSegments-1; i++) { + // reassemble the (WSP-)pdu + output.write(pdus[i], 0, pdus[i].length); + } + + // This one isn't in the DB, so add it + output.write(pdu, index, pdu.length - index); + + byte[] datagram = output.toByteArray(); + // Dispatch the PDU to applications + switch (destinationPort) { + case SmsHeader.PORT_WAP_PUSH: + // Handle the PUSH + dispatchWapPdu(datagram); + break; + + default:{ + pdus = new byte[1][]; + pdus[0] = datagram; + // The messages were sent to any other WAP port + dispatchPortAddressedPdus(pdus, destinationPort); + break; + } + } + } + + /** {@inheritDoc} */ + protected void sendMultipartText(String destinationAddress, String scAddress, + ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, + ArrayList<PendingIntent> deliveryIntents) { + + int ref = ++sConcatenatedRef & 0xff; + + for (int i = 0, count = parts.size(); i < count; i++) { + // build SmsHeader data + byte[] data = new byte[5]; + data[0] = (byte) SmsHeader.CONCATENATED_8_BIT_REFERENCE; + data[1] = (byte) 3; // 3 bytes follow + data[2] = (byte) ref; // reference #, unique per message + data[3] = (byte) count; // total part count + data[4] = (byte) (i + 1); // 1-based sequence + + PendingIntent sentIntent = null; + PendingIntent deliveryIntent = null; + + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + if (deliveryIntents != null && deliveryIntents.size() > i) { + deliveryIntent = deliveryIntents.get(i); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, + parts.get(i), deliveryIntent != null, data); + + sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + } + } + + protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, + PendingIntent deliveryIntent) { + super.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); + } + + /** {@inheritDoc} */ + protected void sendSms(SmsTracker tracker) { + HashMap map = tracker.mData; + + byte smsc[] = (byte[]) map.get("smsc"); + byte pdu[] = (byte[]) map.get("pdu"); + + Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); + + mCm.sendCdmaSms(pdu, reply); + } + + /** {@inheritDoc} */ + protected void acknowledgeLastIncomingSms(boolean success, Message response){ + // FIXME unit test leaves cm == null. this should change + if (mCm != null) { + mCm.acknowledgeLastIncomingCdmaSms(success, response); + } + } + + /** {@inheritDoc} */ + protected void activateCellBroadcastSms(int activate, Message response) { + mCm.activateCdmaBroadcastSms(activate, response); + } + + /** {@inheritDoc} */ + protected void getCellBroadcastSmsConfig(Message response) { + mCm.getCdmaBroadcastConfig(response); + } + + /** {@inheritDoc} */ + protected void setCellBroadcastConfig(int[] configValuesArray, Message response) { + mCm.setCdmaBroadcastConfig(configValuesArray, response); + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java index f6a4b62c6d3f..22ba8f46a1b5 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java @@ -22,7 +22,7 @@ import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERAT import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_ALPHA; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; import android.app.AlarmManager; import android.content.ContentResolver; import android.content.Context; @@ -45,13 +45,13 @@ import android.text.TextUtils; import android.util.Log; import android.util.TimeUtils; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.gsm.MccTable; +import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.telephony.gsm.CommandException; -import com.android.internal.telephony.gsm.MccTable; import java.util.Arrays; -import java.util.Calendar; import java.util.Date; import java.util.TimeZone; @@ -81,19 +81,8 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList(); private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList(); - // Sometimes we get the NITZ time before we know what country we are in. - // Keep the time zone information from the NITZ string so we can fix - // the time zone once know the country. - private boolean mNeedFixZone = false; - private int mZoneOffset; - private boolean mZoneDst; - private long mZoneTime; private boolean mGotCountryCode = false; - String mSavedTimeZone; - long mSavedTime; - long mSavedAtTime; - // We can't register for SIM_RECORDS_LOADED immediately because the // SIMRecords object may not be instantiated yet. private boolean mNeedToRegForRuimLoaded; @@ -107,12 +96,13 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { static final String LOG_TAG = "CDMA"; static final String TMUK = "23430"; + private ContentResolver cr; private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { - Log.i("CdmaServiceStateTracker", "Auto time state changed"); - revertToNitz(); + Log.i("CdmaServiceStateTracker", "Auto time state called ..."); + //NOTE in CDMA NITZ is not used } }; @@ -129,11 +119,11 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { cellLoc = new CdmaCellLocation(); newCellLoc = new CdmaCellLocation(); - cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); + cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED_CDMA, null); - cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE_CDMA, null); + cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); cm.registerForRUIMReady(this, EVENT_RUIM_READY, null); @@ -143,17 +133,33 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { int airplaneMode = Settings.System.getInt( phone.getContext().getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0); - mDesiredPowerState = ! (airplaneMode > 0); + mDesiredPowerState = ! (airplaneMode > 0); - ContentResolver cr = phone.getContext().getContentResolver(); + cr = phone.getContext().getContentResolver(); cr.registerContentObserver( - Settings.System.getUriFor(Settings.System.AUTO_TIME), true, + Settings.System.getUriFor(Settings.System.AUTO_TIME), true, mAutoTimeObserver); setRssiDefaultValues(); mNeedToRegForRuimLoaded = true; } + public void dispose() { + //Unregister for all events + cm.unregisterForAvailable(this); + cm.unregisterForRadioStateChanged(this); + cm.unregisterForNetworkStateChanged(this); + cm.unregisterForRUIMReady(this); + phone.unregisterForNvLoaded(this); + phone.mRuimRecords.unregisterForRecordsLoaded(this); + cm.unSetOnSignalStrengthUpdate(this); + cr.unregisterContentObserver(this.mAutoTimeObserver); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "CdmaServiceStateTracker finalized"); + } + void registerForNetworkAttach(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); networkAttachedRegistrants.add(r); @@ -163,8 +169,12 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } } + void unregisterForNetworkAttach(Handler h) { + networkAttachedRegistrants.remove(h); + } + /** - * Registration point for transition into GPRS attached. + * Registration point for transition into Data attached. * @param h handler to notify * @param what what code of message when delivered * @param obj placed in Message.obj @@ -174,15 +184,18 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { Registrant r = new Registrant(h, what, obj); cdmaDataConnectionAttachedRegistrants.add(r); - if (cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT - || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 + if (cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT + || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) { r.notifyRegistrant(); } } + void unregisterForCdmaDataConnectionAttached(Handler h) { + cdmaDataConnectionAttachedRegistrants.remove(h); + } /** - * Registration point for transition into GPRS detached. + * Registration point for transition into Data detached. * @param h handler to notify * @param what what code of message when delivered * @param obj placed in Message.obj @@ -192,12 +205,15 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { Registrant r = new Registrant(h, what, obj); cdmaDataConnectionDetachedRegistrants.add(r); - if (cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT - && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 + if (cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT + && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A) { r.notifyRegistrant(); } - } + } + void unregisterForCdmaDataConnectionDetached(Handler h) { + cdmaDataConnectionDetachedRegistrants.remove(h); + } //***** Called from CDMAPhone public void @@ -247,11 +263,11 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { pollState(); break; - case EVENT_GET_SIGNAL_STRENGTH_CDMA: + case EVENT_GET_SIGNAL_STRENGTH: // This callback is called when signal strength is polled // all by itself - if (!(cm.getRadioState().isOn())) { + if (!(cm.getRadioState().isOn()) || (cm.getRadioState().isGsm())) { // Polling will continue when radio turns back on return; } @@ -289,10 +305,10 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } // only update if cell location really changed - if (cellLoc.getBaseStationId() != baseStationData[0] - || cellLoc.getBaseStationLatitude() != baseStationData[1] + if (cellLoc.getBaseStationId() != baseStationData[0] + || cellLoc.getBaseStationLatitude() != baseStationData[1] || cellLoc.getBaseStationLongitude() != baseStationData[2]) { - cellLoc.setCellLocationData(baseStationData[0], + cellLoc.setCellLocationData(baseStationData[0], baseStationData[1], baseStationData[2]); phone.notifyLocationChanged(); @@ -313,23 +329,13 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { handlePollStateResult(msg.what, ar); break; - case EVENT_POLL_SIGNAL_STRENGTH_CDMA: + case EVENT_POLL_SIGNAL_STRENGTH: // Just poll signal strength...not part of pollState() - cm.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH_CDMA)); + cm.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH)); break; - //TODO Implement this case for CDMA or remove it, if it is not necessary... - /*case EVENT_NITZ_TIME: - ar = (AsyncResult) msg.obj; - - String nitzString = (String)((Object[])ar.result)[0]; - int nitzReceiveTime = ((Integer)((Object[])ar.result)[1]).intValue(); - - setTimeFromNITZString(nitzString, nitzReceiveTime); - break;*/ - - case EVENT_SIGNAL_STRENGTH_UPDATE_CDMA: + case EVENT_SIGNAL_STRENGTH_UPDATE: // This is a notification from // CommandsInterface.setOnSignalStrengthUpdate @@ -343,6 +349,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { break; case EVENT_RUIM_RECORDS_LOADED: + case EVENT_NV_LOADED: updateSpnDisplay(); break; @@ -354,9 +361,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } break; - case EVENT_NV_LOADED: - updateSpnDisplay(); //TODO same as EVENT_RUIM_RECORDS_LOADED - break; default: Log.e(LOG_TAG, "Unhandled message with number: " + msg.what); break; @@ -367,17 +371,18 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { protected void updateSpnDisplay() { - // TODO Check this method again, because it is not sure at the moment how + // TODO Check this method again, because it is not sure at the moment how // the RUIM handles the SIM stuff //int rule = phone.mRuimRecords.getDisplayRule(ss.getOperatorNumeric()); - String spn = null; //phone.mRuimRecords.getServiceProvideName(); + String spn = null; //phone.mRuimRecords.getServiceProviderName(); String plmn = ss.getOperatorAlphaLong(); - //if (rule != curSpnRule || !TextUtils.equals(spn, curSpn) || !TextUtils.equals(plmn, curPlmn)) { if (!TextUtils.equals(this.curPlmn, plmn)) { - boolean showSpn = false;//TODO (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN; - boolean showPlmn = true;//TODO (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN; + //TODO (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN; + boolean showSpn = false; + //TODO (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN; + boolean showPlmn = true; Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION); intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn); intent.putExtra(Intents.EXTRA_SPN, spn); @@ -432,7 +437,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { switch (what) { case EVENT_POLL_STATE_REGISTRATION_CDMA: //offset, because we don't want the first 3 values in the int-array - final int offset = 3; + final int offset = 3; states = (String[])ar.result; int responseValuesRegistrationState[] = { @@ -440,7 +445,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { -1, //[1] baseStationId -1, //[2] baseStationLatitude -1, //[3] baseStationLongitude - 0, //[4] cssIndicator; init with 0, because it is treated as a boolean + 0, //[4] cssIndicator; init with 0, because it is treated as a boolean -1, //[5] systemId -1 //[6] networkId }; @@ -448,23 +453,24 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { if (states.length > 0) { try { this.mRegistrationState = Integer.parseInt(states[0]); - if (states.length == 10) { + if (states.length == 10) { for(int i = 0; i < states.length - offset; i++) { - if (states[i + offset] != null + if (states[i + offset] != null && states[i + offset].length() > 0) { try { - responseValuesRegistrationState[i] = + responseValuesRegistrationState[i] = Integer.parseInt(states[i + offset], 16); } catch(NumberFormatException ex) { - Log.w(LOG_TAG, "Warning! There is an unexpected value returned" - + " as response from RIL_REQUEST_REGISTRATION_STATE."); + Log.w(LOG_TAG, "Warning! There is an unexpected value" + + "returned as response from " + + "RIL_REQUEST_REGISTRATION_STATE."); } } } } else { - Log.e(LOG_TAG, "Too less parameters returned from" + Log.e(LOG_TAG, "Too less parameters returned from" + " RIL_REQUEST_REGISTRATION_STATE"); } } catch (NumberFormatException ex) { @@ -473,12 +479,12 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } mCdmaRoaming = regCodeIsRoaming(this.mRegistrationState); - this.newCdmaDataConnectionState = + this.newCdmaDataConnectionState = radioTechnologyToServiceState(responseValuesRegistrationState[0]); newSS.setState (regCodeToServiceState(this.mRegistrationState)); newSS.setRadioTechnology(responseValuesRegistrationState[0]); newSS.setCssIndicator(responseValuesRegistrationState[4]); - newSS.setSystemAndNetworkId(responseValuesRegistrationState[5], + newSS.setSystemAndNetworkId(responseValuesRegistrationState[5], responseValuesRegistrationState[6]); newNetworkType = responseValuesRegistrationState[0]; @@ -502,7 +508,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { newSS.setIsManualSelection(ints[0] == 1); break; default: - Log.e(LOG_TAG, "RIL response handle in wrong phone!" + Log.e(LOG_TAG, "RIL response handle in wrong phone!" + " Expected CDMA RIL request and get GSM RIL request."); break; } @@ -528,7 +534,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { newSS.setExtendedCdmaRoaming(ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE); break; default: - Log.w(LOG_TAG, "Received a different registration state, " + Log.w(LOG_TAG, "Received a different registration state, " + "but don't changed the extended cdma roaming mode."); } pollStateDone(); @@ -564,7 +570,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { pollStateDone(); break; - case RADIO_OFF: newSS.setStateOff(); newCellLoc.setStateInvalid(); @@ -574,25 +579,37 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { pollStateDone(); break; + case SIM_NOT_READY: + case SIM_LOCKED_OR_ABSENT: + case SIM_READY: + log("Radio Technology Change ongoing, setting SS to off"); + newSS.setStateOff(); + newCellLoc.setStateInvalid(); + setRssiDefaultValues(); + mGotCountryCode = false; + + pollStateDone(); + break; + default: // Issue all poll-related commands at once // then count down the responses, which // are allowed to arrive out-of-order pollingContext[0]++; - //RIL_REQUEST_OPERATOR is necessary for CDMA + //RIL_REQUEST_OPERATOR is necessary for CDMA cm.getOperator( obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext)); pollingContext[0]++; //RIL_REQUEST_REGISTRATION_STATE is necessary for CDMA cm.getRegistrationState( - obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, pollingContext)); + obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, pollingContext)); pollingContext[0]++; //RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE necessary for CDMA cm.getNetworkSelectionMode( - obtainMessage(EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA, pollingContext)); + obtainMessage(EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA, pollingContext)); break; } } @@ -642,25 +659,25 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { && newSS.getState() != ServiceState.STATE_IN_SERVICE; boolean hasCdmaDataConnectionAttached = - (this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT - && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 - && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A) - && (this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT - || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 - || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A); + (this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT + && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 + && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A) + && (this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT + || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 + || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A); boolean hasCdmaDataConnectionDetached = - ( this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT - || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 - || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) - && (this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT - && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 - && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A); - - boolean hasCdmaDataConnectionChanged = + (this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT + || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 + || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) + && (this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT + && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0 + && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A); + + boolean hasCdmaDataConnectionChanged = cdmaDataConnectionState != newCdmaDataConnectionState; - boolean hasNetworkTypeChanged = networkType != newNetworkType; + boolean hasNetworkTypeChanged = networkType != newNetworkType; boolean hasChanged = !newSS.equals(ss); @@ -721,44 +738,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, iso); mGotCountryCode = true; - - if (mNeedFixZone) { - TimeZone zone = null; - // If the offset is (0, false) and the timezone property - // is set, use the timezone property rather than - // GMT. - String zoneName = SystemProperties.get(TIMEZONE_PROPERTY); - if ((mZoneOffset == 0) && (mZoneDst == false) && - (zoneName != null) && (zoneName.length() > 0) && - (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) { - zone = TimeZone.getDefault(); - // For NITZ string without timezone, - // need adjust time to reflect default timezone setting - long tzOffset; - tzOffset = zone.getOffset(System.currentTimeMillis()); - SystemClock.setCurrentTimeMillis( - System.currentTimeMillis() - tzOffset); - } else if (iso.equals("")){ - // Country code not found. This is likely a test network. - // Get a TimeZone based only on the NITZ parameters (best guess). - zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime); - } else { - zone = TimeUtils.getTimeZone(mZoneOffset, - mZoneDst, mZoneTime, iso); - } - - mNeedFixZone = false; - - if (zone != null) { - Context context = phone.getContext(); - if (getAutoTime()) { - AlarmManager alarm = - (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - alarm.setTimeZone(zone.getID()); - } - saveNitzTimeZone(zone.getID()); - } - } } phone.setSystemProperty(PROPERTY_OPERATOR_ISROAMING, @@ -833,7 +812,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { private void queueNextSignalStrengthPoll() { - if (dontPollSignalStrength) { + if (dontPollSignalStrength || (cm.getRadioState().isGsm())) { // The radio is telling us about signal strength changes // we don't have to ask it return; @@ -842,7 +821,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { Message msg; msg = obtainMessage(); - msg.what = EVENT_POLL_SIGNAL_STRENGTH_CDMA; + msg.what = EVENT_POLL_SIGNAL_STRENGTH; // TODO Done't poll signal strength if screen is off sendMessageDelayed(msg, POLL_PERIOD_MILLIS); @@ -873,7 +852,13 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } if (rssi != oldRSSI) { - phone.notifySignalStrength(); + try { // This takes care of delayed EVENT_POLL_SIGNAL_STRENGTH (scheduled after + // POLL_PERIOD_MILLIS) during Radio Technology Change) + phone.notifySignalStrength(); + } catch (NullPointerException ex) { + log("onSignalStrengthResult() Phone already destroyed: " + ex + + "Signal Stranth not notified"); + } } } @@ -929,42 +914,13 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { /** * @return The current CDMA data connection state. ServiceState.RADIO_TECHNOLOGY_1xRTT or - * ServiceState.RADIO_TECHNOLOGY_EVDO is the same as "attached" and + * ServiceState.RADIO_TECHNOLOGY_EVDO is the same as "attached" and * ServiceState.RADIO_TECHNOLOGY_UNKNOWN is the same as detached. */ /*package*/ int getCurrentCdmaDataConnectionState() { return cdmaDataConnectionState; } - //TODO Maybe this is not necessary for CDMA part... - /** - * In the case a TMUK SIM/USIM is used, there is no indication on the - * MMI that emergency calls can be made during emergency camping in - * the United Kingdom on a non T-Mobile UK PLMN. - * TMUK MCC/MNC + non-TMUK PLMN = no EC allowed. - * @return true if TMUK MCC/MNC SIM in non-TMUK PLMN - */ - private boolean isTmobileUkRoamingEmergency() { - String spn = null; - String ons = null; - boolean isTmobileUk = false; - /* - if ( phone != null && phone.mSIMRecords != null) - spn = phone.mSIMRecords.getSIMOperatorNumeric(); - if ( ss != null ) - ons = ss.getOperatorNumeric(); - */ - if ( spn != null && spn.equals(TMUK) && - ! (ons!= null && ons.equals(TMUK)) ) { - isTmobileUk = true; - } - - if(DBG) - Log.d(LOG_TAG, - "SPN=" + spn + " ONS=" + ons + " TMUK Emg=" + isTmobileUk); - return isTmobileUk; - } - /** * code is registration state 0-5 from TS 27.007 7.2 * returns true if registered roam, false otherwise @@ -983,7 +939,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { */ private boolean isRoamingBetweenOperators(boolean cdmaRoaming, ServiceState s) { - String spn = SystemProperties.get(PROPERTY_SIM_OPERATOR_ALPHA, "empty"); + String spn = SystemProperties.get(PROPERTY_ICC_OPERATOR_ALPHA, "empty"); String onsl = s.getOperatorAlphaLong(); String onss = s.getOperatorAlphaShort(); @@ -994,209 +950,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { return cdmaRoaming && !(equalsOnsl || equalsOnss); } - //TODO Never used. Check it! - private static - int twoDigitsAt(String s, int offset) { - int a, b; - - a = Character.digit(s.charAt(offset), 10); - b = Character.digit(s.charAt(offset+1), 10); - - if (a < 0 || b < 0) { - - throw new RuntimeException("invalid format"); - } - - return a*10 + b; - } - - //TODO Never used. Check it! - /** - * Provides the name of the algorithmic time zone for the specified - * offset. Taken from TimeZone.java. - */ - private static String displayNameFor(int off) { - off = off / 1000 / 60; - - char[] buf = new char[9]; - buf[0] = 'G'; - buf[1] = 'M'; - buf[2] = 'T'; - - if (off < 0) { - buf[3] = '-'; - off = -off; - } else { - buf[3] = '+'; - } - - int hours = off / 60; - int minutes = off % 60; - - buf[4] = (char) ('0' + hours / 10); - buf[5] = (char) ('0' + hours % 10); - - buf[6] = ':'; - - buf[7] = (char) ('0' + minutes / 10); - buf[8] = (char) ('0' + minutes % 10); - - return new String(buf); - } - - //TODO Never used. Check it! - /** - * nitzReceiveTime is time_t that the NITZ time was posted - */ - private - void setTimeFromNITZString (String nitz, int nitzReceiveTime) { - // "yy/mm/dd,hh:mm:ss(+/-)tz" - // tz is in number of quarter-hours - - Log.i(LOG_TAG, "setTimeFromNITZString: " + - nitz + "," + nitzReceiveTime); - - try { - /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone - * offset as well (which we won't worry about until later) */ - Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT")); - - c.clear(); - c.set(Calendar.DST_OFFSET, 0); - - String[] nitzSubs = nitz.split("[/:,+-]"); - - int year = 2000 + Integer.parseInt(nitzSubs[0]); - c.set(Calendar.YEAR, year); - - // month is 0 based! - int month = Integer.parseInt(nitzSubs[1]) - 1; - c.set(Calendar.MONTH, month); - - int date = Integer.parseInt(nitzSubs[2]); - c.set(Calendar.DATE, date); - - int hour = Integer.parseInt(nitzSubs[3]); - c.set(Calendar.HOUR, hour); - - int minute = Integer.parseInt(nitzSubs[4]); - c.set(Calendar.MINUTE, minute); - - int second = Integer.parseInt(nitzSubs[5]); - c.set(Calendar.SECOND, second); - - boolean sign = (nitz.indexOf('-') == -1); - - int tzOffset = Integer.parseInt(nitzSubs[6]); - - int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7]) - : 0; - - // The zone offset received from NITZ is for current local time, - // so DST correction is already applied. Don't add it again. - // - // tzOffset += dst * 4; - // - // We could unapply it if we wanted the raw offset. - - tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000; - - TimeZone zone = null; - - // As a special extension, the Android emulator appends the name of - // the host computer's timezone to the nitz string. this is zoneinfo - // timezone name of the form Area!Location or Area!Location!SubLocation - // so we need to convert the ! into / - if (nitzSubs.length >= 9) { - String tzname = nitzSubs[8].replace('!','/'); - zone = TimeZone.getTimeZone( tzname ); - } - - String iso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY); - - if (zone == null) { - - if (mGotCountryCode) { - if (iso != null && iso.length() > 0) { - zone = TimeUtils.getTimeZone(tzOffset, dst != 0, - c.getTimeInMillis(), - iso); - } else { - // We don't have a valid iso country code. This is - // most likely because we're on a test network that's - // using a bogus MCC (eg, "001"), so get a TimeZone - // based only on the NITZ parameters. - zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis()); - } - } - } - - if (zone == null) { - // We got the time before the country, so we don't know - // how to identify the DST rules yet. Save the information - // and hope to fix it up later. - - mNeedFixZone = true; - mZoneOffset = tzOffset; - mZoneDst = dst != 0; - mZoneTime = c.getTimeInMillis(); - } - - if (zone != null) { - Context context = phone.getContext(); - if (getAutoTime()) { - AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - alarm.setTimeZone(zone.getID()); - } - saveNitzTimeZone(zone.getID()); - } - - long millisSinceNitzReceived - = System.currentTimeMillis() - (nitzReceiveTime * 1000L); - - if (millisSinceNitzReceived < 0) { - // Sanity check: something is wrong - Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled " - + "backwards since NITZ time received, " - + nitz); - return; - } - - if (millisSinceNitzReceived > (1000L * 1000L)) { - // If the time is this far off, something is wrong - Log.i(LOG_TAG, "NITZ: not setting time, more than 1000 seconds " - + " have elapsed since time received, " - + nitz); - - return; - } - - // Note: with range checks above, cast to int is safe - c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived); - - String ignore = SystemProperties.get("cdma.ignore-nitz"); - if (ignore != null && ignore.equals("yes")) { - Log.i(LOG_TAG, - "Not setting clock because cdma.ignore-nitz is set"); - return; - } - - if (getAutoTime()) { - Log.i(LOG_TAG, "Setting time of day to " + c.getTime() - + " NITZ receive delay(ms): " + millisSinceNitzReceived - + " gained(ms): " - + (c.getTimeInMillis() - System.currentTimeMillis()) - + " from " + nitz); - - SystemClock.setCurrentTimeMillis(c.getTimeInMillis()); - } - SystemProperties.set("cdma.nitz.time", String.valueOf(c.getTimeInMillis())); - saveNitzTime(c.getTimeInMillis()); - } catch (RuntimeException ex) { - Log.e(LOG_TAG, "Parsing NITZ time " + nitz, ex); - } - } - private boolean getAutoTime() { try { return Settings.System.getInt(phone.getContext().getContentResolver(), @@ -1206,39 +959,20 @@ final class CdmaServiceStateTracker extends ServiceStateTracker { } } - private void saveNitzTimeZone(String zoneId) { - mSavedTimeZone = zoneId; - // Send out a sticky broadcast so the system can determine if - // the timezone was set by the carrier... - Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); - intent.putExtra("time-zone", zoneId); - phone.getContext().sendStickyBroadcast(intent); - } + /** + * @return true if phone is camping on a technology + * that could support voice and data simultaneously. + */ + boolean isConcurrentVoiceAndData() { - private void saveNitzTime(long time) { - mSavedTime = time; - mSavedAtTime = SystemClock.elapsedRealtime(); - // Send out a sticky broadcast so the system can determine if - // the time was set by the carrier... - Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); - intent.putExtra("time", time); - phone.getContext().sendStickyBroadcast(intent); + // Note: it needs to be confirmed which CDMA network types + // can support voice and data calls concurrently. + // For the time-being, the return value will be false. + return false; } - private void revertToNitz() { - if (Settings.System.getInt(phone.getContext().getContentResolver(), - Settings.System.AUTO_TIME, 0) == 0) { - return; - } - Log.d(LOG_TAG, "Reverting to NITZ: tz='" + mSavedTimeZone - + "' mSavedTime=" + mSavedTime - + " mSavedAtTime=" + mSavedAtTime); - if (mSavedTimeZone != null && mSavedTime != 0 && mSavedAtTime != 0) { - AlarmManager alarm = - (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); - alarm.setTimeZone(mSavedTimeZone); - SystemClock.setCurrentTimeMillis(mSavedTime - + (SystemClock.elapsedRealtime() - mSavedAtTime)); - } + protected void log(String s) { + Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s); } + } diff --git a/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java new file mode 100644 index 000000000000..65b733645358 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java @@ -0,0 +1,312 @@ +/* + * 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.cdma; + +import android.content.Context; +import android.os.*; +import android.util.Log; + +import com.android.internal.telephony.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * {@hide} + * + */ +public final class FeatureCode extends Handler implements MmiCode { + static final String LOG_TAG = "CDMA"; + + //***** Constants + + // Call Forwarding + static final String FC_CF_ACTIVATE = "72"; + static final String FC_CF_DEACTIVATE = "73"; + static final String FC_CF_FORWARD_TO_NUMBER = "56"; + + // Call Forwarding Busy Line + static final String FC_CFBL_ACTIVATE = "90"; + static final String FC_CFBL_DEACTIVATE = "91"; + static final String FC_CFBL_FORWARD_TO_NUMBER = "40"; + + // Call Forwarding Don't Answer + static final String FC_CFDA_ACTIVATE = "92"; + static final String FC_CFDA_DEACTIVATE = "93"; + static final String FC_CFDA_FORWARD_TO_NUMBER = "42"; + + // Cancel Call Waiting + static final String FC_CCW = "70"; + + // Usage Sensitive Three-way Calling + static final String FC_3WC = "71"; + + // Do Not Disturb + static final String FC_DND_ACTIVATE = "78"; + static final String FC_DND_DEACTIVATE = "79"; + + // Who Called Me? + static final String FC_WHO = "51"; + + // Rejection of Undesired Annoying Calls + static final String FC_RUAC_ACTIVATE = "60"; + static final String FC_RUAC_DEACTIVATE = "80"; + + // Calling Number Delivery + // Calling Number Identification Presentation + static final String FC_CNIP = "65"; + // Calling Number Identification Restriction + static final String FC_CNIR = "85"; + + + //***** Event Constants + + static final int EVENT_SET_COMPLETE = 1; + static final int EVENT_CDMA_FLASH_COMPLETED = 2; + + + //***** Instance Variables + + CDMAPhone phone; + Context context; + + String action; // '*' in CDMA + String sc; // Service Code + String poundString; // Entire Flash string + String dialingNumber; + + /** Set to true in processCode, not at newFromDialString time */ + + State state = State.PENDING; + CharSequence message; + + //***** Class Variables + + + // Flash Code Pattern + + static Pattern sPatternSuppService = Pattern.compile( + "((\\*)(\\d{2,3})(#?)([^*#]*)?)(.*)"); +/* 1 2 3 4 5 6 + + 1 = Full string up to and including # + 2 = action + 3 = service code + 4 = separator + 5 = dialing number +*/ + + static final int MATCH_GROUP_POUND_STRING = 1; + static final int MATCH_GROUP_ACTION_STRING = 2; + static final int MATCH_GROUP_SERVICE_CODE = 3; + static final int MATCH_GROUP_DIALING_NUMBER = 5; + + + //***** Public Class methods + + /** + * Some dial strings in CDMA are defined to do non-call setup + * things, such as set supplementary service settings (eg, call + * forwarding). These are generally referred to as "Feature Codes". + * We look to see if the dial string contains a valid Feature code (potentially + * with a dial string at the end as well) and return info here. + * + * If the dial string contains no Feature code, we return an instance with + * only "dialingNumber" set + * + * Please see also S.R0006-000-A v2.0 "Wireless Features Description" + */ + + static FeatureCode newFromDialString(String dialString, CDMAPhone phone) { + Matcher m; + FeatureCode ret = null; + + m = sPatternSuppService.matcher(dialString); + + // Is this formatted like a standard supplementary service code? + if (m.matches()) { + ret = new FeatureCode(phone); + ret.poundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING)); + ret.action = makeEmptyNull(m.group(MATCH_GROUP_ACTION_STRING)); + ret.sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE)); + ret.dialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER)); + } + + return ret; + } + + //***** Private Class methods + + /** make empty strings be null. + * Java regexp returns empty strings for empty groups + */ + private static String makeEmptyNull (String s) { + if (s != null && s.length() == 0) return null; + + return s; + } + + /** returns true of the string is empty or null */ + private static boolean isEmptyOrNull(CharSequence s) { + return s == null || (s.length() == 0); + } + + static boolean isServiceCodeCallForwarding(String sc) { + return sc != null && + (sc.equals(FC_CF_ACTIVATE) + || sc.equals(FC_CF_DEACTIVATE) || sc.equals(FC_CF_FORWARD_TO_NUMBER) + || sc.equals(FC_CFBL_ACTIVATE) || sc.equals(FC_CFBL_DEACTIVATE) + || sc.equals(FC_CFBL_FORWARD_TO_NUMBER) || sc.equals(FC_CFDA_ACTIVATE) + || sc.equals(FC_CFDA_DEACTIVATE) || sc.equals(FC_CFDA_FORWARD_TO_NUMBER)); + } + + static boolean isServiceCodeCallWaiting(String sc) { + return sc != null && sc.equals(FC_CCW); + } + + static boolean isServiceCodeThreeWayCalling(String sc) { + return sc != null && sc.equals(FC_3WC); + } + + static boolean isServiceCodeAnnoyingCalls(String sc) { + return sc != null && + (sc.equals(FC_RUAC_ACTIVATE) + || sc.equals(FC_RUAC_DEACTIVATE)); + } + + static boolean isServiceCodeCallingNumberDelivery(String sc) { + return sc != null && + (sc.equals(FC_CNIP) + || sc.equals(FC_CNIR)); + } + + static boolean isServiceCodeDoNotDisturb(String sc) { + return sc != null && + (sc.equals(FC_DND_ACTIVATE) + || sc.equals(FC_DND_DEACTIVATE)); + } + + + //***** Constructor + + FeatureCode (CDMAPhone phone) { + super(phone.getHandler().getLooper()); + this.phone = phone; + this.context = phone.getContext(); + } + + + //***** MmiCode implementation + + public State getState() { + return state; + } + + public CharSequence getMessage() { + return message; + } + + // inherited javadoc suffices + public void cancel() { + //Not used here + } + + public boolean isCancelable() { + Log.e(LOG_TAG, "isCancelable: not used in CDMA"); + return false; + } + + public boolean isUssdRequest() { + Log.e(LOG_TAG, "isUssdRequest: not used in CDMA"); + return false; + } + + /** Process a Flash Code...anything that isn't a dialing number */ + void processCode () { + Log.d(LOG_TAG, "send feature code..."); + phone.mCM.sendCDMAFeatureCode(this.poundString, + obtainMessage(EVENT_CDMA_FLASH_COMPLETED)); + } + + /** Called from CDMAPhone.handleMessage; not a Handler subclass */ + public void handleMessage (Message msg) { + AsyncResult ar; + + switch (msg.what) { + case EVENT_SET_COMPLETE: + ar = (AsyncResult) (msg.obj); + onSetComplete(ar); + break; + case EVENT_CDMA_FLASH_COMPLETED: + ar = (AsyncResult) (msg.obj); + + if (ar.exception != null) { + state = State.FAILED; + message = context.getText(com.android.internal.R.string.mmiError); + } else { + state = State.COMPLETE; + message = context.getText(com.android.internal.R.string.mmiComplete); + } + phone.onMMIDone(this); + break; + } + } + + + //***** Private instance methods + + private CharSequence getScString() { + if (sc != null) { + if (isServiceCodeCallForwarding(sc)) { + return context.getText(com.android.internal.R.string.CfMmi); + } else if (isServiceCodeCallWaiting(sc)) { + return context.getText(com.android.internal.R.string.CwMmi); + } else if (sc.equals(FC_CNIP)) { + return context.getText(com.android.internal.R.string.CnipMmi); + } else if (sc.equals(FC_CNIR)) { + return context.getText(com.android.internal.R.string.CnirMmi); + } else if (isServiceCodeThreeWayCalling(sc)) { + return context.getText(com.android.internal.R.string.ThreeWCMmi); + } else if (isServiceCodeAnnoyingCalls(sc)) { + return context.getText(com.android.internal.R.string.RuacMmi); + } else if (isServiceCodeCallingNumberDelivery(sc)) { + return context.getText(com.android.internal.R.string.CndMmi); + } else if (isServiceCodeDoNotDisturb(sc)) { + return context.getText(com.android.internal.R.string.DndMmi); + } + } + + return ""; + } + + private void onSetComplete(AsyncResult ar){ + StringBuilder sb = new StringBuilder(getScString()); + sb.append("\n"); + + if (ar.exception != null) { + state = State.FAILED; + sb.append(context.getText(com.android.internal.R.string.mmiError)); + } else { + state = State.FAILED; + sb.append(context.getText(com.android.internal.R.string.mmiError)); + } + + message = sb; + phone.onMMIDone(this); + } +} diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java index b52504dbf6a0..9d9f47958e29 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java @@ -17,40 +17,42 @@ package com.android.internal.telephony.cdma; import android.os.AsyncResult; -import android.os.RemoteException; import android.os.Handler; import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; +import android.os.RemoteException; import android.util.Log; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.telephony.TelephonyProperties; +import android.app.ActivityManagerNative; import android.content.Intent; import android.content.res.Configuration; -import android.app.ActivityManagerNative; import static android.Manifest.permission.READ_PHONE_STATE; /** + * Note: this class shares common code with SimCard, consider a base class to minimize code + * duplication. * {@hide} */ -// TODO to be implemented public final class RuimCard extends Handler implements IccCard { static final String LOG_TAG="CDMA"; - + //***** Instance Variables private static final boolean DBG = true; private CDMAPhone phone; - + private CommandsInterface.IccStatus status = null; private boolean mDesiredPinLocked; - private boolean mDesiredFdnEnabled; + private boolean mDesiredFdnEnabled; private boolean mRuimPinLocked = true; // default to locked private boolean mRuimFdnEnabled = false; // Default to disabled. // Will be updated when RUIM_READY. @@ -91,7 +93,7 @@ public final class RuimCard extends Handler implements IccCard { updateStateProperty(); } - + //***** RuimCard implementation public State @@ -111,6 +113,9 @@ public final class RuimCard extends Handler implements IccCard { return State.UNKNOWN; case RUIM_READY: return State.READY; + case NV_READY: + case NV_NOT_READY: + return State.ABSENT; } } else { switch (status) { @@ -127,7 +132,17 @@ public final class RuimCard extends Handler implements IccCard { return State.UNKNOWN; } -//********* TODO BEGIN: this is something for the base class + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForRUIMLockedOrAbsent(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + phone.mCM.unregisterForRUIMReady(this); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimCard finalized"); + } + private RegistrantList absentRegistrants = new RegistrantList(); private RegistrantList pinLockedRegistrants = new RegistrantList(); private RegistrantList networkLockedRegistrants = new RegistrantList(); @@ -142,7 +157,7 @@ public final class RuimCard extends Handler implements IccCard { r.notifyRegistrant(); } } - + public void unregisterForAbsent(Handler h) { absentRegistrants.remove(h); } @@ -160,7 +175,7 @@ public final class RuimCard extends Handler implements IccCard { public void unregisterForNetworkLocked(Handler h) { networkLockedRegistrants.remove(h); } - + public void registerForLocked(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); @@ -174,30 +189,27 @@ public final class RuimCard extends Handler implements IccCard { public void unregisterForLocked(Handler h) { pinLockedRegistrants.remove(h); } -//********* TODO END: this is something for the base class public void supplyPin (String pin, Message onComplete) { - phone.mCM.supplyIccPin(pin, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); + phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } public void supplyPuk (String puk, String newPin, Message onComplete) { - phone.mCM.supplyIccPuk(puk, newPin, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); + phone.mCM.supplyIccPuk(puk, newPin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } + public void supplyPin2 (String pin2, Message onComplete) { - phone.mCM.supplyIccPin2(pin2, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); + phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } + public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { - phone.mCM.supplyIccPuk2(puk2, newPin2, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); + phone.mCM.supplyIccPuk2(puk2, newPin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } public void supplyNetworkDepersonalization (String pin, Message onComplete) { if(DBG) log("Network Despersonalization: " + pin); phone.mCM.supplyNetworkDepersonalization(pin, - obtainMessage(EVENT_PINPUK_DONE, onComplete)); + obtainMessage(EVENT_PINPUK_DONE, onComplete)); } public boolean getIccLockEnabled() { @@ -242,7 +254,6 @@ public final class RuimCard extends Handler implements IccCard { if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword); phone.mCM.changeIccPin(oldPassword, newPassword, obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete)); - } public void changeIccFdnPassword(String oldPassword, String newPassword, @@ -250,13 +261,10 @@ public final class RuimCard extends Handler implements IccCard { if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword); phone.mCM.changeIccPin2(oldPassword, newPassword, obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete)); - } - public String getServiceProviderName () { - // TODO: SIMRecords getServiceProvideName is not implemented yet - return "CDMA Test Provider"; - //return phone.mSIMRecords.getServiceProvideName(); + public String getServiceProviderName() { + return phone.mRuimRecords.getServiceProviderName(); } //***** Handler implementation @@ -271,13 +279,13 @@ public final class RuimCard extends Handler implements IccCard { switch (msg.what) { case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: - Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); status = null; updateStateProperty(); - broadcastSimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_NOT_READY, null); - break; + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_NOT_READY, null); + break; case EVENT_RUIM_READY: - Log.d(LOG_TAG, "Event EVENT_RUIM_READY Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_RUIM_READY Received"); //TODO: put facility read in SIM_READY now, maybe in REG_NW phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE)); phone.mCM.queryFacilityLock ( @@ -288,20 +296,20 @@ public final class RuimCard extends Handler implements IccCard { obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE)); break; case EVENT_RUIM_LOCKED_OR_ABSENT: - Log.d(LOG_TAG, "Event EVENT_RUIM_LOCKED_OR_ABSENT Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_RUIM_LOCKED_OR_ABSENT Received"); phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE)); phone.mCM.queryFacilityLock ( CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX, obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE)); break; case EVENT_GET_RUIM_STATUS_DONE: - Log.d(LOG_TAG, "Event EVENT_GET_RUIM_STATUS_DONE Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_GET_RUIM_STATUS_DONE Received"); ar = (AsyncResult)msg.obj; getRuimStatusDone(ar); break; case EVENT_PINPUK_DONE: - Log.d(LOG_TAG, "Event EVENT_PINPUK_DONE Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_PINPUK_DONE Received"); // a PIN/PUK/PIN2/PUK2/Network Personalization // request has completed. ar.userObj is the response Message // Repoll before returning @@ -313,7 +321,7 @@ public final class RuimCard extends Handler implements IccCard { obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj)); break; case EVENT_REPOLL_STATUS_DONE: - Log.d(LOG_TAG, "Event EVENT_REPOLL_STATUS_DONE Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_REPOLL_STATUS_DONE Received"); // Finished repolling status after PIN operation // ar.userObj is the response messaeg // ar.userObj.obj is already an AsyncResult with an @@ -324,17 +332,17 @@ public final class RuimCard extends Handler implements IccCard { ((Message)ar.userObj).sendToTarget(); break; case EVENT_QUERY_FACILITY_LOCK_DONE: - Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_LOCK_DONE Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_LOCK_DONE Received"); ar = (AsyncResult)msg.obj; onQueryFacilityLock(ar); break; case EVENT_QUERY_FACILITY_FDN_DONE: - Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_FDN_DONE Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_FDN_DONE Received"); ar = (AsyncResult)msg.obj; onQueryFdnEnabled(ar); break; case EVENT_CHANGE_FACILITY_LOCK_DONE: - Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_LOCK_DONE Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_LOCK_DONE Received"); ar = (AsyncResult)msg.obj; if (ar.exception == null) { mRuimPinLocked = mDesiredPinLocked; @@ -349,7 +357,7 @@ public final class RuimCard extends Handler implements IccCard { ((Message)ar.userObj).sendToTarget(); break; case EVENT_CHANGE_FACILITY_FDN_DONE: - Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_FDN_DONE Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_FDN_DONE Received"); ar = (AsyncResult)msg.obj; if (ar.exception == null) { @@ -365,7 +373,7 @@ public final class RuimCard extends Handler implements IccCard { ((Message)ar.userObj).sendToTarget(); break; case EVENT_CHANGE_RUIM_PASSWORD_DONE: - Log.d(LOG_TAG, "Event EVENT_CHANGE_RUIM_PASSWORD_DONE Received"); //TODO + Log.d(LOG_TAG, "Event EVENT_CHANGE_RUIM_PASSWORD_DONE Received"); ar = (AsyncResult)msg.obj; if(ar.exception != null) { Log.e(LOG_TAG, "Error in change sim password with exception" @@ -382,9 +390,8 @@ public final class RuimCard extends Handler implements IccCard { //***** Private methods -//********* TODO BEGIN: this is something for the base class /** - * Interperate EVENT_QUERY_FACILITY_LOCK_DONE + * Interpret EVENT_QUERY_FACILITY_LOCK_DONE * @param ar is asyncResult of Query_Facility_Locked */ private void onQueryFacilityLock(AsyncResult ar) { @@ -403,7 +410,7 @@ public final class RuimCard extends Handler implements IccCard { } /** - * Interperate EVENT_QUERY_FACILITY_LOCK_DONE + * Interpret EVENT_QUERY_FACILITY_LOCK_DONE * @param ar is asyncResult of Query_Facility_Locked */ private void onQueryFdnEnabled(AsyncResult ar) { @@ -420,8 +427,7 @@ public final class RuimCard extends Handler implements IccCard { Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response"); } } -//********* TODO END: this is something for the base class - + private void getRuimStatusDone(AsyncResult ar) { if (ar.exception != null) { @@ -431,7 +437,7 @@ public final class RuimCard extends Handler implements IccCard { return; } - CommandsInterface.IccStatus newStatus + CommandsInterface.IccStatus newStatus = (CommandsInterface.IccStatus) ar.result; handleRuimStatus(newStatus); @@ -442,7 +448,7 @@ public final class RuimCard extends Handler implements IccCard { boolean transitionedIntoPinLocked; boolean transitionedIntoAbsent; boolean transitionedIntoNetworkLocked; - + RuimCard.State oldState, newState; oldState = getState(); @@ -461,24 +467,22 @@ public final class RuimCard extends Handler implements IccCard { if (transitionedIntoPinLocked) { if(DBG) log("Notify RUIM pin or puk locked."); pinLockedRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED, + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED, (newState == State.PIN_REQUIRED) ? INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); } else if (transitionedIntoAbsent) { if(DBG) log("Notify RUIM missing."); absentRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_ABSENT, null); + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_ABSENT, null); } else if (transitionedIntoNetworkLocked) { if(DBG) log("Notify RUIM network locked."); networkLockedRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED, + broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED, INTENT_VALUE_LOCKED_NETWORK); } } - // TODO: should probably be renamed to broadcastIccStateChangedIntent in SIMRecords.java - public void broadcastSimStateChangedIntent(String value, String reason) { - // TODO: check if intent has to be renamed + public void broadcastRuimStateChangedIntent(String value, String reason) { Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName()); intent.putExtra(RuimCard.INTENT_KEY_ICC_STATE, value); @@ -488,7 +492,6 @@ public final class RuimCard extends Handler implements IccCard { ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE); } - // TODO: check if this is valid for CDMA public void updateImsiConfiguration(String imsi) { if (imsi.length() >= 6) { Configuration config = new Configuration(); diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java index 0724b23b4963..7d392f0b0fdc 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java @@ -16,16 +16,18 @@ package com.android.internal.telephony.cdma; -import com.android.internal.telephony.*; // TODO: Remove * -import com.android.internal.telephony.IccException; -import com.android.internal.telephony.IccIoResult; -import com.android.internal.telephony.IccFileTypeMismatch; - import android.os.*; import android.os.AsyncResult; -import android.os.RegistrantList; -import android.os.Registrant; import android.util.Log; + +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccException; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccFileTypeMismatch; +import com.android.internal.telephony.IccIoResult; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; + import java.util.ArrayList; /** @@ -34,424 +36,44 @@ import java.util.ArrayList; public final class RuimFileHandler extends IccFileHandler { static final String LOG_TAG = "CDMA"; - //***** Instance Variables - CDMAPhone phone; - - - //***** Inner Classes - - static class LoadLinearFixedContext { - - int efid; - int recordNum, recordSize, countRecords; - boolean loadAll; - - Message onLoaded; - - ArrayList<byte[]> results; - - LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) { - this.efid = efid; - this.recordNum = recordNum; - this.onLoaded = onLoaded; - this.loadAll = false; - } - - LoadLinearFixedContext(int efid, Message onLoaded) { - this.efid = efid; - this.recordNum = 1; - this.loadAll = true; - this.onLoaded = onLoaded; - } - - } - + //***** Instance Variables //***** Constructor RuimFileHandler(CDMAPhone phone) { - this.phone = phone; - } - - //***** Public Methods - - /** - * Load a record from a SIM Linear Fixed EF - * - * @param fileid EF id - * @param recordNum 1-based (not 0-based) record number - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - protected void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) { - Message response - = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid, recordNum, onLoaded)); - - phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); - } - - /** - * Load a image instance record from a SIM Linear Fixed EF-IMG - * - * @param recordNum 1-based (not 0-based) record number - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - public void loadEFImgLinearFixed(int recordNum, Message onLoaded) { - Message response = obtainMessage(EVENT_READ_IMG_DONE, - new LoadLinearFixedContext(IccConstants.EF_IMG, recordNum, - onLoaded)); - - phone.mCM.iccIO(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img", - recordNum, READ_RECORD_MODE_ABSOLUTE, - GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response); + super(phone); } - /** - * get record size for a linear fixed EF - * - * @param fileid EF id - * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[] - * int[0] is the record length int[1] is the total length of the EF - * file int[3] is the number of records in the EF file So int[0] * - * int[3] = int[1] - */ - protected void getEFLinearRecordSize(int fileid, Message onLoaded) { - Message response - = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid, onLoaded)); - - phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + public void dispose() { } - /** - * Load all records from a SIM Linear Fixed EF - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is an ArrayList<byte[]> - * - */ - protected void loadEFLinearFixedAll(int fileid, Message onLoaded) { - Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid,onLoaded)); - - phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + protected void finalize() { + Log.d(LOG_TAG, "RuimFileHandler finalized"); } - /** - * Load a SIM Transparent EF - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ + //***** Overridden from IccFileHandler - protected void loadEFTransparent(int fileid, Message onLoaded) { - Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE, - fileid, 0, onLoaded); - - phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); - } - - /** - * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to - * retrive STK's icon data. - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - protected void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, + @Override + public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, int length, Message onLoaded) { Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0, onLoaded); - + phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, "img", 0, 0, GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response); } - /** - * Update a record in a linear fixed EF - * @param fileid EF id - * @param recordNum 1-based (not 0-based) record number - * @param data must be exactly as long as the record in the EF - * @param pin2 for CHV2 operations, otherwist must be null - * @param onComplete onComplete.obj will be an AsyncResult - * onComplete.obj.userObj will be a IccIoResult on success - */ - protected void updateEFLinearFixed(int fileid, int recordNum, byte[] data, - String pin2, Message onComplete) { - phone.mCM.iccIO(COMMAND_UPDATE_RECORD, fileid, null, - recordNum, READ_RECORD_MODE_ABSOLUTE, data.length, - IccUtils.bytesToHexString(data), pin2, onComplete); - } - - /** - * Update a transparent EF - * @param fileid EF id - * @param data must be exactly as long as the EF - */ - protected void updateEFTransparent(int fileid, byte[] data, Message onComplete) { - phone.mCM.iccIO(COMMAND_UPDATE_BINARY, fileid, null, - 0, 0, data.length, - IccUtils.bytesToHexString(data), null, onComplete); - } - - //***** Overridden from Handler - + @Override public void handleMessage(Message msg) { - AsyncResult ar; - IccIoResult result; - Message response = null; - String str; - LoadLinearFixedContext lc; - - IccException iccException; - byte data[]; - int size; - int fileid; - int recordNum; - int recordSize[]; - - try { - switch (msg.what) { - case EVENT_READ_IMG_DONE: - Log.d(LOG_TAG, "Event EVENT_READ_IMG_DONE Received"); //TODO - ar = (AsyncResult) msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (IccIoResult) ar.result; - response = lc.onLoaded; - - iccException = result.getException(); - if (iccException != null) { - sendResult(response, result.payload, ar.exception); - } - break; - case EVENT_READ_ICON_DONE: - Log.d(LOG_TAG, "Event EVENT_READ_ICON_DONE Received"); //TODO - ar = (AsyncResult) msg.obj; - response = (Message) ar.userObj; - result = (IccIoResult) ar.result; - - iccException = result.getException(); - if (iccException != null) { - sendResult(response, result.payload, ar.exception); - } - break; - case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE: - Log.d(LOG_TAG, "Event EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE Received"); //TODO - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (IccIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - iccException = result.getException(); - if (iccException != null) { - sendResult(response, null, iccException); - break; - } - data = result.payload; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] || - EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { - throw new IccFileTypeMismatch(); - } - - recordSize = new int[3]; - recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; - recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - recordSize[2] = recordSize[1] / recordSize[0]; - - sendResult(response, recordSize, null); - break; - case EVENT_GET_RECORD_SIZE_DONE: - Log.d(LOG_TAG, "Event EVENT_GET_RECORD_SIZE_DONE Received"); //TODO - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (IccIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - iccException = result.getException(); - - if (iccException != null) { - sendResult(response, null, iccException); - break; - } - - data = result.payload; - fileid = lc.efid; - recordNum = lc.recordNum; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { - throw new IccFileTypeMismatch(); - } - - if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { - throw new IccFileTypeMismatch(); - } - - lc.recordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; - - size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - - lc.countRecords = size / lc.recordSize; - - if (lc.loadAll) { - lc.results = new ArrayList<byte[]>(lc.countRecords); - } - - phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null, - lc.recordNum, - READ_RECORD_MODE_ABSOLUTE, - lc.recordSize, null, null, - obtainMessage(EVENT_READ_RECORD_DONE, lc)); - break; - case EVENT_GET_BINARY_SIZE_DONE: - Log.d(LOG_TAG, "Event EVENT_GET_BINARY_SIZE_DONE Received"); //TODO - ar = (AsyncResult)msg.obj; - response = (Message) ar.userObj; - result = (IccIoResult) ar.result; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - iccException = result.getException(); - - if (iccException != null) { - sendResult(response, null, iccException); - break; - } - - data = result.payload; - - fileid = msg.arg1; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { - throw new IccFileTypeMismatch(); - } - - if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) { - throw new IccFileTypeMismatch(); - } - - size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - - phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, null, - 0, 0, size, null, null, - obtainMessage(EVENT_READ_BINARY_DONE, - fileid, 0, response)); - break; - - case EVENT_READ_RECORD_DONE: - Log.d(LOG_TAG, "Event EVENT_READ_RECORD_DONE Received"); //TODO - - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (IccIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - iccException = result.getException(); - - if (iccException != null) { - sendResult(response, null, iccException); - break; - } - - if (!lc.loadAll) { - sendResult(response, result.payload, null); - } else { - lc.results.add(result.payload); - - lc.recordNum++; - - if (lc.recordNum > lc.countRecords) { - sendResult(response, lc.results, null); - } else { - phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null, - lc.recordNum, - READ_RECORD_MODE_ABSOLUTE, - lc.recordSize, null, null, - obtainMessage(EVENT_READ_RECORD_DONE, lc)); - } - } - - break; - - case EVENT_READ_BINARY_DONE: - Log.d(LOG_TAG, "Event EVENT_READ_BINARY_DONE Received"); //TODO - ar = (AsyncResult)msg.obj; - response = (Message) ar.userObj; - result = (IccIoResult) ar.result; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - iccException = result.getException(); - - if (iccException != null) { - sendResult(response, null, iccException); - break; - } - - sendResult(response, result.payload, null); - break; - - }} catch (Exception exc) { - if (response != null) { - sendResult(response, null, exc); - } else { - Log.e(LOG_TAG, "uncaught exception", exc); - } - } + super.handleMessage(msg); } - //***** Private Methods - - // TODO: check if this is something for the base class - private void sendResult(Message response, Object result, Throwable ex) { - if (response == null) { - return; - } + protected void logd(String msg) { + Log.d(LOG_TAG, "[RuimFileHandler] " + msg); + } - AsyncResult.forMessage(response, result, ex); + protected void loge(String msg) { + Log.e(LOG_TAG, "[RuimFileHandler] " + msg); + } - response.sendToTarget(); - } } diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java index 02d9695e5e31..78e89d56cb92 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java @@ -1,19 +1,18 @@ /* - * 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. - */ - +** Copyright 2007, 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.cdma; @@ -26,242 +25,77 @@ import android.os.ServiceManager; import android.telephony.PhoneNumberUtils; import android.util.Log; +import com.android.internal.telephony.AdnRecord; +import com.android.internal.telephony.AdnRecordCache; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.PhoneProxy; + import java.util.ArrayList; import java.util.List; -import com.android.internal.telephony.IccPhoneBookInterfaceManager; -import com.android.internal.telephony.AdnRecordCache; -import com.android.internal.telephony.AdnRecord; /** * RuimPhoneBookInterfaceManager to provide an inter-process communication to * access ADN-like SIM records. */ -// -//TODO Check if a common IccPhoneBookInterfaceManager is enough!!!! -// + public class RuimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { static final String LOG_TAG = "CDMA"; - static final boolean DBG = false; - - private CDMAPhone phone; - private AdnRecordCache adnCache; - private final Object mLock = new Object(); - private int recordSize[]; - private boolean success; - private List<AdnRecord> records; - private static final boolean ALLOW_SIM_OP_IN_UI_THREAD = false; - - private static final int EVENT_GET_SIZE_DONE = 1; - private static final int EVENT_LOAD_DONE = 2; - private static final int EVENT_UPDATE_DONE = 3; Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { AsyncResult ar; - switch (msg.what) { - case EVENT_GET_SIZE_DONE: - Log.d(LOG_TAG, "Event EVENT_GET_SIZE_DONE Received"); //TODO - ar = (AsyncResult) msg.obj; - synchronized (mLock) { - if (ar.exception == null) { - recordSize = (int[])ar.result; - // recordSize[0] is the record length - // recordSize[1] is the total length of the EF file - // recordSize[2] is the number of records in the EF file - log("GET_RECORD_SIZE Size " + recordSize[0] + - " total " + recordSize[1] + - " #record " + recordSize[2]); - mLock.notifyAll(); - } - } - break; - case EVENT_UPDATE_DONE: - Log.d(LOG_TAG, "Event EVENT_UPDATE_DONE Received"); //TODO - ar = (AsyncResult) msg.obj; - synchronized (mLock) { - success = (ar.exception == null); - mLock.notifyAll(); - } - break; - case EVENT_LOAD_DONE: - Log.d(LOG_TAG, "Event EVENT_LOAD_DONE Received"); //TODO - ar = (AsyncResult)msg.obj; - synchronized (mLock) { - if (ar.exception == null) { - records = (List<AdnRecord>) - ((ArrayList<AdnRecord>) ar.result); - } else { - if(DBG) log("Cannot load ADN records"); - if (records != null) { - records.clear(); - } - } - mLock.notifyAll(); - } + switch(msg.what) { + default: + mBaseHandler.handleMessage(msg); break; } } }; public RuimPhoneBookInterfaceManager(CDMAPhone phone) { - this.phone = phone; - adnCache = phone.mRuimRecords.getAdnCache(); - //publish(); //TODO REMOVE + super(phone); + adnCache = phone.mRuimRecords.getAdnCache(); + //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy } - private void publish() { - // TODO T: Do we have to change the service - // as well to "iccphonebook"? - // defined in: device/commands/binder/Service_info.c - ServiceManager.addService("simphonebook", this); + public void dispose() { + super.dispose(); } - /** - * Replace oldAdn with newAdn in ADN-like record in EF - * - * getAdnRecordsInEf must be called at least once before this function, - * otherwise an error will be returned - * throws SecurityException if no WRITE_CONTACTS permission - * - * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN - * @param oldTag adn tag to be replaced - * @param oldPhoneNumber adn number to be replaced - * Set both oldTag and oldPhoneNubmer to "" means to replace an - * empty record, aka, insert new record - * @param newTag adn tag to be stored - * @param newPhoneNumber adn number ot be stored - * Set both newTag and newPhoneNubmer to "" means to replace the old - * record with empty one, aka, delete old record - * @param pin2 required to update EF_FDN, otherwise must be null - * @return true for success - */ - public boolean - updateAdnRecordsInEfBySearch (int efid, - String oldTag, String oldPhoneNumber, - String newTag, String newPhoneNumber, String pin2) { - success = false; - return success; + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimPhoneBookInterfaceManager finalized"); } - /** - * Update an ADN-like EF record by record index - * - * This is useful for iteration the whole ADN file, such as write the whole - * phone book or erase/format the whole phonebook - * throws SecurityException if no WRITE_CONTACTS permission - * - * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN - * @param newTag adn tag to be stored - * @param newPhoneNumber adn number to be stored - * Set both newTag and newPhoneNubmer to "" means to replace the old - * record with empty one, aka, delete old record - * @param index is 1-based adn record index to be updated - * @param pin2 required to update EF_FDN, otherwise must be null - * @return true for success - */ - public boolean - updateAdnRecordsInEfByIndex(int efid, String newTag, - String newPhoneNumber, int index, String pin2) { - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.WRITE_CONTACTS permission"); - } - - if (DBG) log("updateAdnRecordsInEfByIndex: efid=" + efid + - " Index=" + index + " ==> " + - "("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); - synchronized(mLock) { - checkThread(); - success = false; - Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); - adnCache.updateAdnByIndex(efid, newAdn, index, pin2, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to update by index"); - } - } - return success; - } - - /** - * Get the capacity of records in efid - * - * @param efid the EF id of a ADN-like SIM - * @return int[3] array - * recordSizes[0] is the single record length - * recordSizes[1] is the total length of the EF file - * recordSizes[2] is the number of records in the EF file - */ public int[] getAdnRecordsSize(int efid) { - if (DBG) log("getAdnRecordsSize: efid=" + efid); + if (DBG) logd("getAdnRecordsSize: efid=" + efid); synchronized(mLock) { checkThread(); recordSize = new int[3]; - Message response = mHandler.obtainMessage(EVENT_GET_SIZE_DONE); - ((RuimFileHandler)phone.getIccFileHandler()).getEFLinearRecordSize(efid, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to load from the SIM"); - } - } - - return recordSize; - } - /** - * Loads the AdnRecords in efid and returns them as a - * List of AdnRecords - * - * throws SecurityException if no READ_CONTACTS permission - * - * @param efid the EF id of a ADN-like SIM - * @return List of AdnRecord - */ - public List<AdnRecord> getAdnRecordsInEf(int efid) { - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.READ_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.READ_CONTACTS permission"); - } - - if (DBG) log("getAdnRecordsInEF: efid=" + efid); + //Using mBaseHandler, no difference in EVENT_GET_SIZE_DONE handling + Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE); - synchronized(mLock) { - checkThread(); - Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); - adnCache.requestLoadAllAdnLike(efid, response); + phone.getIccFileHandler().getEFLinearRecordSize(efid, response); try { mLock.wait(); } catch (InterruptedException e) { - log("interrupted while trying to load from the SIM"); + logd("interrupted while trying to load from the RUIM"); } } - return records; - } - private void checkThread() { - if (!ALLOW_SIM_OP_IN_UI_THREAD) { - // Make sure this isn't the UI thread, since it will block - if (mHandler.getLooper().equals(Looper.myLooper())) { - Log.e(LOG_TAG, "query() called on the main UI thread!"); - throw new IllegalStateException( - "You cannot call query on this provder from the main UI thread."); - } - } + return recordSize; } - private void log(String msg) { + protected void logd(String msg) { Log.d(LOG_TAG, "[RuimPbInterfaceManager] " + msg); } + + protected void loge(String msg) { + Log.e(LOG_TAG, "[RuimPbInterfaceManager] " + msg); + } } diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java index af8f6436dd45..c23363f713de 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java @@ -16,32 +16,29 @@ package com.android.internal.telephony.cdma; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_ISO_COUNTRY; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; import android.os.AsyncResult; -import android.os.RegistrantList; -import android.os.Registrant; import android.os.Handler; import android.os.Message; -import android.telephony.gsm.SmsMessage; +import android.os.Registrant; import android.util.Log; -import java.util.ArrayList; -import com.android.internal.telephony.cdma.RuimCard; - -import com.android.internal.telephony.IccUtils; +import static com.android.internal.telephony.TelephonyProperties.*; import com.android.internal.telephony.AdnRecord; import com.android.internal.telephony.AdnRecordCache; import com.android.internal.telephony.AdnRecordLoader; +import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.cdma.RuimCard; import com.android.internal.telephony.gsm.MccTable; -import com.android.internal.telephony.gsm.SimCard; -import com.android.internal.telephony.gsm.SimTlv; - // can't be used since VoiceMailConstants is not public //import com.android.internal.telephony.gsm.VoiceMailConstants; +import com.android.internal.telephony.IccException; import com.android.internal.telephony.IccRecords; -import com.android.internal.telephony.PhoneBase; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; + /** * {@hide} @@ -49,68 +46,38 @@ import com.android.internal.telephony.PhoneBase; public final class RuimRecords extends IccRecords { static final String LOG_TAG = "CDMA"; - private static final boolean CRASH_RIL = false; - private static final boolean DBG = true; //***** Instance Variables - - CDMAPhone phone; - RegistrantList recordsLoadedRegistrants = new RegistrantList(); - - int recordsToLoad; // number of pending load requests - - AdnRecordCache adnCache; - - boolean recordsRequested = false; // true if we've made requests for the sim records - String imsi_m; String mdn = null; // My mobile number String h_sid; String h_nid; - String iccid; - - int mncLength = 0; // 0 is used to indicate that the value // is not initialized - + //***** Event Constants private static final int EVENT_RUIM_READY = 1; private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2; - // TODO: check if needed for CDMA - //private static final int EVENT_GET_IMSI_DONE = 3; - private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4; private static final int EVENT_GET_ICCID_DONE = 5; - - // TODO: find synonyms for CDMA -// private static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM -// private static final int EVENT_GET_MSISDN_DONE = 10; private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10; - private static final int EVENT_UPDATE_DONE = 14; - - // TODO: check if EF_CST should be used instead in CDMA - //private static final int EVENT_GET_SST_DONE = 17; - - // TODO: probably needed in CDMA as well + private 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; - - // TODO: check for CDMA - private static final int EVENT_SMS_ON_SIM = 21; + + private static final int EVENT_SMS_ON_RUIM = 21; private static final int EVENT_GET_SMS_DONE = 22; - + private static final int EVENT_RUIM_REFRESH = 31; - + //***** Constructor - RuimRecords(CDMAPhone phone) { - super(phone); - this.phone = phone; + RuimRecords(CDMAPhone p) { + super(p); - // TODO: additional constructor and implementation needed in AdnRecordCache adnCache = new AdnRecordCache(phone); recordsRequested = false; // No load request is made till SIM ready @@ -119,47 +86,44 @@ public final class RuimRecords extends IccRecords { recordsToLoad = 0; - phone.mCM.registerForRUIMReady(this, EVENT_RUIM_READY, null); - phone.mCM.registerForOffOrNotAvailable( - this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - // TODO: check if needed - //phone.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); - phone.mCM.setOnIccRefresh(this, EVENT_RUIM_REFRESH, null); + p.mCM.registerForRUIMReady(this, EVENT_RUIM_READY, null); + p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + // NOTE the EVENT_SMS_ON_RUIM is not registered + p.mCM.setOnIccRefresh(this, EVENT_RUIM_REFRESH, null); // Start off by setting empty state - onRadioOffOrNotAvailable(); + onRadioOffOrNotAvailable(); } - - public AdnRecordCache getAdnCache() { - return adnCache; + + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForRUIMReady(this); + phone.mCM.unregisterForOffOrNotAvailable( this); + phone.mCM.unSetOnIccRefresh(this); } - + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimRecords finalized"); + } + protected void onRadioOffOrNotAvailable() { -// TODO: missing implementation, maybe some parts will be moved to a super class -// Example: -// super.onRadioOffOrNotAvailable(); -// -// phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, null); -// phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, null); -// phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, null); -// phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY, null); -// -// // recordsRequested is set to false indicating that the SIM -// // read requests made so far are not valid. This is set to -// // true only when fresh set of read requests are made. -// recordsRequested = false; + countVoiceMessages = 0; + mncLength = 0; + iccid = null; + + adnCache.reset(); + + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null); + + // recordsRequested is set to false indicating that the SIM + // read requests made so far are not valid. This is set to + // true only when fresh set of read requests are made. + recordsRequested = false; } //***** Public Methods - public void registerForRecordsLoaded(Handler h, int what, Object obj) { - Registrant r = new Registrant(h, what, obj); - recordsLoadedRegistrants.add(r); - - if (recordsToLoad == 0 && recordsRequested == true) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } /** Returns null if RUIM is not yet ready */ public String getIMSI_M() { @@ -170,9 +134,16 @@ public final class RuimRecords extends IccRecords { return mdn; } - // TODO: change STK to CDMA specific term + public void setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete){ + // In CDMA this is Operator/OEM dependent + AsyncResult.forMessage((onComplete)).exception = + new IccException("setVoiceMailNumber not implemented"); + onComplete.sendToTarget(); + Log.e(LOG_TAG, "method setVoiceMailNumber is not implemented"); + } + /** - * Called by STK Service when REFRESH is received. + * Called by CCAT Service when REFRESH is received. * @param fileChanged indicates whether any files changed * @param fileList if non-null, a list of EF files that changed */ @@ -183,9 +154,8 @@ public final class RuimRecords extends IccRecords { // just re-fetch all RUIM records that we cache. fetchRuimRecords(); } - } + } - // TODO: this is something for the base class, change function name to getICCOperatorNumeric /** Returns the 5 or 6 digit MCC/MNC of the operator that * provided the RUIM card. Returns null of RUIM is not yet ready */ @@ -197,7 +167,7 @@ public final class RuimRecords extends IccRecords { if (mncLength != 0) { // Length = length of MCC + length of MNC // TODO: change spec name - // length of mcc = 3 (TS 23.003 Section 2.2) + // length of mcc = 3 (3GPP2 C.S0005 - Section 2.3) return imsi_m.substring(0, 3 + mncLength); } @@ -211,15 +181,6 @@ public final class RuimRecords extends IccRecords { return imsi_m.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc)); } - public void setVoiceCallForwardingFlag(int line, boolean enable) { - // TODO T: implement or use abstract method - } - - public void setVoiceMailNumber(String alphaTag, String voiceNumber, - Message onComplete){ - // TODO T: implement or use abstract method - } - //***** Overridden from Handler public void handleMessage(Message msg) { AsyncResult ar; @@ -230,158 +191,87 @@ public final class RuimRecords extends IccRecords { try { switch (msg.what) { case EVENT_RUIM_READY: - Log.d(LOG_TAG, "Event EVENT_RUIM_READY Received"); //TODO onRuimReady(); break; case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: - Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received"); //TODO onRadioOffOrNotAvailable(); - break; - + break; + case EVENT_GET_DEVICE_IDENTITY_DONE: - Log.d(LOG_TAG, "Event EVENT_GET_DEVICE_IDENTITY_DONE Received"); //TODO - // TODO: might be deleted + Log.d(LOG_TAG, "Event EVENT_GET_DEVICE_IDENTITY_DONE Received"); break; /* IO events */ - - // TODO: maybe substituted by RIL_REQUEST_CDMA_SUBSCRIPTION (MDN) -// case EVENT_GET_MSISDN_DONE: -// isRecordLoadResponse = true; -// -// ar = (AsyncResult)msg.obj; -// -// if (ar.exception != null) { -// Log.d(LOG_TAG, "Invalid or missing EF[MSISDN]"); -// break; -// } -// -// adn = (AdnRecord)ar.result; -// -// msisdn = adn.getNumber(); -// msisdnTag = adn.getAlphaTag(); -// -// Log.d(LOG_TAG, "MSISDN: " + msisdn); -// break; - + case EVENT_GET_CDMA_SUBSCRIPTION_DONE: - Log.d(LOG_TAG, "Event EVENT_GET_CDMA_SUBSCRIPTION_DONE Received"); //TODO ar = (AsyncResult)msg.obj; String localTemp[] = (String[])ar.result; if (ar.exception != null) { break; } - + mdn = localTemp[0]; h_sid = localTemp[1]; h_nid = localTemp[2]; - + Log.d(LOG_TAG, "MDN: " + mdn); - + break; case EVENT_GET_ICCID_DONE: - Log.d(LOG_TAG, "Event EVENT_GET_ICCID_DONE Received"); //TODO isRecordLoadResponse = true; ar = (AsyncResult)msg.obj; data = (byte[])ar.result; - + if (ar.exception != null) { break; - } + } iccid = IccUtils.bcdToString(data, 0, data.length); - + Log.d(LOG_TAG, "iccid: " + iccid); break; case EVENT_UPDATE_DONE: - Log.d(LOG_TAG, "Event EVENT_UPDATE_DONE Received"); //TODO ar = (AsyncResult)msg.obj; if (ar.exception != null) { Log.i(LOG_TAG, "RuimRecords update failed", ar.exception); } break; - // TODO: handled by SMS use cases -// case EVENT_GET_ALL_SMS_DONE: -// isRecordLoadResponse = true; -// -// ar = (AsyncResult)msg.obj; -// if (ar.exception != null) -// break; -// -// handleSmses((ArrayList) ar.result); -// break; -// -// case EVENT_MARK_SMS_READ_DONE: -// Log.i("ENF", "marked read: sms " + msg.arg1); -// break; -// -// -// case EVENT_SMS_ON_SIM: -// isRecordLoadResponse = false; -// -// ar = (AsyncResult)msg.obj; -// -// int[] index = (int[])ar.result; -// -// if (ar.exception != null || index.length != 1) { -// Log.e(LOG_TAG, "[SIMRecords] Error on SMS_ON_SIM with exp " -// + ar.exception + " length " + index.length); -// } else { -// Log.d(LOG_TAG, "READ EF_SMS RECORD index=" + index[0]); -// phone.mSIMFileHandler.loadEFLinearFixed(EF_SMS,index[0],obtainMessage(EVENT_GET_SMS_DONE)); -// } -// break; -// -// case EVENT_GET_SMS_DONE: -// isRecordLoadResponse = false; -// ar = (AsyncResult)msg.obj; -// if (ar.exception == null) { -// handleSms((byte[])ar.result); -// } else { -// Log.e(LOG_TAG, "[SIMRecords] Error on GET_SMS with exp " -// + ar.exception); -// } -// break; + case EVENT_GET_ALL_SMS_DONE: + case EVENT_MARK_SMS_READ_DONE: + case EVENT_SMS_ON_RUIM: + case EVENT_GET_SMS_DONE: + Log.w(LOG_TAG, "Event not supported: " + msg.what); + break; // TODO: probably EF_CST should be read instead -// case EVENT_GET_SST_DONE: -// isRecordLoadResponse = true; -// -// ar = (AsyncResult)msg.obj; -// data = (byte[])ar.result; -// -// if (ar.exception != null) { -// break; -// } -// -// //Log.d(LOG_TAG, "SST: " + IccUtils.bytesToHexString(data)); -// break; + case EVENT_GET_SST_DONE: + Log.d(LOG_TAG, "Event EVENT_GET_SST_DONE Received"); + break; case EVENT_RUIM_REFRESH: - Log.d(LOG_TAG, "Event EVENT_RUIM_REFRESH Received"); //TODO isRecordLoadResponse = false; ar = (AsyncResult)msg.obj; if (ar.exception == null) { - //TODO: handleRuimRefresh((int[])(ar.result)); + handleRuimRefresh((int[])(ar.result)); } break; }}catch (RuntimeException exc) { // I don't want these exceptions to be fatal - Log.w(LOG_TAG, "Exception parsing SIM record", exc); - } finally { + Log.w(LOG_TAG, "Exception parsing RUIM record", exc); + } finally { // Count up record load responses even if they are fails if (isRecordLoadResponse) { - //TODO: onRecordLoaded(); + onRecordLoaded(); } } - } + } protected void onRecordLoaded() { // One record loaded successfully or failed, In either case @@ -395,93 +285,91 @@ public final class RuimRecords extends IccRecords { recordsToLoad = 0; } } - + protected void onAllRecordsLoaded() { - // TODO: implementation is missing + Log.d(LOG_TAG, "RuimRecords: record load complete"); + + // Further records that can be inserted are Operator/OEM dependent + + recordsLoadedRegistrants.notifyRegistrants( + new AsyncResult(null, null, null)); + ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent( + RuimCard.INTENT_VALUE_ICC_LOADED, null); } - - + + //***** Private Methods - + private void onRuimReady() { /* broadcast intent ICC_READY here so that we can make sure READY is sent before IMSI ready */ - - // TODO: broadcastSimStateChangedIntent will probably be renamed - phone.mRuimCard.broadcastSimStateChangedIntent( + + ((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent( RuimCard.INTENT_VALUE_ICC_READY, null); fetchRuimRecords(); - - // TODO: add a function here + phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); - + } - + private void fetchRuimRecords() { recordsRequested = true; Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad); - - // TODO: IMSI needed to get mcc and mnc -// phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE)); -// recordsToLoad++; - ((RuimFileHandler)phone.getIccFileHandler()).loadEFTransparent(EF_ICCID, - obtainMessage(EVENT_GET_ICCID_DONE)); + phone.getIccFileHandler().loadEFTransparent(EF_ICCID, + obtainMessage(EVENT_GET_ICCID_DONE)); recordsToLoad++; - // TODO: IMSI_M(MIN)/MDN, RIL_REQUEST_DEVICE_IDENTITY - // FIXME should examine EF[MSISDN]'s capability configuration - // to determine which is the voice/data/fax line -// new AdnRecordLoader(phone).loadFromEF(EF_MSISDN, EF_EXT1, 1, -// obtainMessage(EVENT_GET_MSISDN_DONE)); -// recordsToLoad++; - - // TODO: probably done by RIL_REQUEST_DEVICE_IDENTITY -// phone.mSIMFileHandler.loadEFTransparent(EF_AD, -// obtainMessage(EVENT_GET_AD_DONE)); -// recordsToLoad++; - - // TODO: check if if CDMA Service Table 0x6F32 should be read instead -// phone.mSIMFileHandler.loadEFTransparent(EF_SST, -// obtainMessage(EVENT_GET_SST_DONE)); -// recordsToLoad++; - - // TODO: SMS handling in CDMA - // XXX should seek instead of examining them all -// if (false) { // XXX -// phone.mSIMFileHandler.loadEFLinearFixedAll(EF_SMS, -// obtainMessage(EVENT_GET_ALL_SMS_DONE)); -// recordsToLoad++; -// } - - // TODO: check later in SMS use case -// if (CRASH_RIL) { -// String sms = "0107912160130310f20404d0110041007030208054832b0120ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; -// byte[] ba = IccUtils.hexStringToBytes(sms); -// -// phone.mSIMFileHandler.updateEFLinearFixed(EF_SMS, 1, ba, null, -// obtainMessage(EVENT_MARK_SMS_READ_DONE, 1)); -// } + // Further records that can be inserted are Operator/OEM dependent } - - private void log(String s) { - Log.d(LOG_TAG, "[RuimRecords] " + s); - } - @Override protected int getDisplayRule(String plmn) { - // TODO Auto-generated method stub + // TODO together with spn return 0; } @Override public void setVoiceMessageWaiting(int line, int countWaiting) { - // TODO Auto-generated method stub - + Log.i(LOG_TAG, "RuimRecords: setVoiceMessageWaiting not supported."); + } + + private void handleRuimRefresh(int[] result) { + if (result == null || result.length == 0) { + return; + } + + switch ((result[0])) { + case CommandsInterface.SIM_REFRESH_FILE_UPDATED: + adnCache.reset(); + fetchRuimRecords(); + break; + case CommandsInterface.SIM_REFRESH_INIT: + // need to reload all files (that we care about) + fetchRuimRecords(); + break; + case CommandsInterface.SIM_REFRESH_RESET: + phone.mCM.setRadioPower(false, null); + /* Note: no need to call setRadioPower(true). Assuming the desired + * radio power state is still ON (as tracked by ServiceStateTracker), + * ServiceStateTracker will call setRadioPower when it receives the + * RADIO_STATE_CHANGED notification for the power off. And if the + * desired power state has changed in the interim, we don't want to + * override it with an unconditional power on. + */ + break; + default: + // unknown refresh operation + break; + } } + + protected void log(String s) { + Log.d(LOG_TAG, "[RuimRecords] " + s); + } + } diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java index 2be41edd2b67..9439359fe735 100644 --- a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright (C) 2008 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. @@ -17,31 +17,31 @@ package com.android.internal.telephony.cdma; -import android.app.PendingIntent; import android.content.Context; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; -import android.os.ServiceManager; -import android.telephony.gsm.SmsManager; import android.util.Log; +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccSmsInterfaceManager; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.SmsRawData; + import java.util.ArrayList; import java.util.List; -import com.android.internal.telephony.IccConstants; -import com.android.internal.telephony.IccSmsInterfaceManager; -import com.android.internal.telephony.gsm.SmsRawData; //TODO remove after moving to telephony +import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; /** - * SimSmsInterfaceManager to provide an inter-process communication to - * access Sms in Sim. + * RuimSmsInterfaceManager to provide an inter-process communication to + * access Sms in Ruim. */ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager { static final String LOG_TAG = "CDMA"; - static final boolean DBG = false; + static final boolean DBG = true; - private CDMAPhone mPhone; private final Object mLock = new Object(); private boolean mSuccess; private List<SmsRawData> mSms; @@ -56,7 +56,6 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager { switch (msg.what) { case EVENT_UPDATE_DONE: - Log.d(LOG_TAG, "Event EVENT_UPDATE_DONE Received"); //TODO ar = (AsyncResult) msg.obj; synchronized (mLock) { mSuccess = (ar.exception == null); @@ -64,7 +63,6 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager { } break; case EVENT_LOAD_DONE: - Log.d(LOG_TAG, "Event EVENT_LOAD_DONE Received"); //TODO ar = (AsyncResult)msg.obj; synchronized (mLock) { if (ar.exception == null) { @@ -83,79 +81,112 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager { }; public RuimSmsInterfaceManager(CDMAPhone phone) { - this.mPhone = phone; - //ServiceManager.addService("isms", this); + super(phone); + mDispatcher = new CdmaSMSDispatcher(phone); } - private void enforceReceiveAndSend(String message) { - Context context = mPhone.getContext(); + public void dispose() { + } - context.enforceCallingPermission( - "android.permission.RECEIVE_SMS", message); - context.enforceCallingPermission( - "android.permission.SEND_SMS", message); + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "RuimSmsInterfaceManager finalized"); } /** * Update the specified message on the RUIM. + * + * @param index record index of message to update + * @param status new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) + * @param pdu the raw PDU to store + * @return success or not + * */ public boolean - updateMessageOnSimEf(int index, int status, byte[] pdu) { - //TODO - mSuccess = false; + updateMessageOnIccEf(int index, int status, byte[] pdu) { + if (DBG) log("updateMessageOnIccEf: index=" + index + + " status=" + status + " ==> " + + "("+ pdu + ")"); + enforceReceiveAndSend("Updating message on RUIM"); + synchronized(mLock) { + mSuccess = false; + Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); + + if (status == STATUS_ON_ICC_FREE) { + // Special case FREE: call deleteSmsOnRuim instead of + // manipulating the RUIM record + mPhone.mCM.deleteSmsOnRuim(index, response); + } else { + byte[] record = makeSmsRecordData(status, pdu); + mPhone.getIccFileHandler().updateEFLinearFixed( + IccConstants.EF_SMS, index, record, null, response); + } + try { + mLock.wait(); + } catch (InterruptedException e) { + log("interrupted while trying to update by index"); + } + } return mSuccess; } /** * Copy a raw SMS PDU to the RUIM. + * + * @param pdu the raw PDU to store + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) + * @return success or not + * */ - public boolean copyMessageToSimEf(int status, byte[] pdu, byte[] smsc) { - //TODO - mSuccess = false; + public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) { + //NOTE smsc not used in RUIM + if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " + + "pdu=("+ pdu + ")"); + enforceReceiveAndSend("Copying message to RUIM"); + synchronized(mLock) { + mSuccess = false; + Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); + + mPhone.mCM.writeSmsToRuim(status, IccUtils.bytesToHexString(pdu), + response); + + try { + mLock.wait(); + } catch (InterruptedException e) { + log("interrupted while trying to update by index"); + } + } return mSuccess; } /** * Retrieves all messages currently stored on RUIM. */ - public List<SmsRawData> getAllMessagesFromSimEf() { - //TODO - return null; - } + public List<SmsRawData> getAllMessagesFromIccEf() { + if (DBG) log("getAllMessagesFromEF"); - /** - * Send a Raw PDU SMS - */ - public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, - PendingIntent deliveryIntent) { - //TODO - } - - /** - * Send a multi-part text based SMS. - */ - public void sendMultipartText(String destinationAddress, String scAddress, List<String> parts, - List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { - //TODO - } - - /** - * Generates an EF_SMS record from status and raw PDU. - */ - private byte[] makeSmsRecordData(int status, byte[] pdu) { - //TODO - return null; - } + Context context = mPhone.getContext(); - /** - * create SmsRawData lists from all sms record byte[] - */ - private ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) { - //TODO - return null; + context.enforceCallingPermission( + "android.permission.RECEIVE_SMS", + "Reading messages from RUIM"); + synchronized(mLock) { + Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); + mPhone.getIccFileHandler().loadEFLinearFixedAll(IccConstants.EF_SMS, response); + + try { + mLock.wait(); + } catch (InterruptedException e) { + log("interrupted while trying to load from the RUIM"); + } + } + return mSms; } - private void log(String msg) { + protected void log(String msg) { Log.d(LOG_TAG, "[RuimSmsInterfaceManager] " + msg); } } + diff --git a/telephony/java/com/android/internal/telephony/cdma/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/SMSDispatcher.java deleted file mode 100644 index 21546d89ddfd..000000000000 --- a/telephony/java/com/android/internal/telephony/cdma/SMSDispatcher.java +++ /dev/null @@ -1,833 +0,0 @@ -/* - * Copyright (C) 2008 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.cdma; - -import android.app.Activity; -import android.app.PendingIntent; -import android.app.AlertDialog; -import android.app.PendingIntent.CanceledException; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.DialogInterface; -import android.content.res.Resources; -import android.database.Cursor; -import android.database.SQLException; -import android.net.Uri; -import android.os.AsyncResult; -import android.os.Handler; -import android.os.Message; -import android.provider.Telephony; -import android.provider.Telephony.Sms.Intents; -import android.telephony.gsm.SmsMessage; -import android.telephony.gsm.SmsManager; -import android.telephony.ServiceState; -import android.util.Config; - -import com.android.internal.telephony.IccUtils; -import com.android.internal.telephony.CommandsInterface; -import com.android.internal.util.HexDump; -import android.util.Log; -import android.view.WindowManager; - -import java.io.ByteArrayOutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Random; - -import com.android.internal.R; - -final class SMSDispatcher extends Handler { - private static final String TAG = "CDMA"; - - /** Default checking period for SMS sent without uesr permit */ - private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000; - - /** Default number of SMS sent in checking period without uesr permit */ - private static final int DEFAULT_SMS_MAX_ALLOWED = 100; - - /** Default timeout for SMS sent query */ - private static final int DEFAULT_SMS_TIMOUEOUT = 6000; - - private static final String MMS_MIME_TYPE = "application/vnd.wap.mms-message"; - - private static final String[] RAW_PROJECTION = new String[] { - "pdu", - "sequence", - }; - -//TODO static final int MAIL_SEND_SMS = 1; - - static final int EVENT_NEW_SMS = 1; - - static final int EVENT_SEND_SMS_COMPLETE = 2; - - /** Retry sending a previously failed SMS message */ - static final int EVENT_SEND_RETRY = 3; - - /** Status report received */ - static final int EVENT_NEW_SMS_STATUS_REPORT = 5; - - /** SIM storage is full */ - static final int EVENT_RUIM_FULL = 6; - - /** SMS confirm required */ - static final int EVENT_POST_ALERT = 7; - - /** Send the user confirmed SMS */ - static final int EVENT_SEND_CONFIRMED_SMS = 8; - - /** Alert is timeout */ - static final int EVENT_ALERT_TIMEOUT = 9; - - private final CDMAPhone mPhone; - - private final Context mContext; - - private final ContentResolver mResolver; - - private final CommandsInterface mCm; - - private final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw"); - - /** Maximum number of times to retry sending a failed SMS. */ - private static final int MAX_SEND_RETRIES = 3; - /** Delay before next send attempt on a failed SMS, in milliseconds. */ - private static final int SEND_RETRY_DELAY = 2000; // ms - - /** - * Message reference for a CONCATENATED_8_BIT_REFERENCE or - * CONCATENATED_16_BIT_REFERENCE message set. Should be - * incremented for each set of concatenated messages. - */ - private static int sConcatenatedRef; - - private SmsCounter mCounter; - - private SmsTracker mSTracker; - - /** - * Implement the per-application based SMS control, which only allows - * a limit on the number of SMS/MMS messages an app can send in checking - * period. - */ - private class SmsCounter { - private int mCheckPeriod; - private int mMaxAllowed; - private HashMap<String, ArrayList<Long>> mSmsStamp; - - /** - * Create SmsCounter - * @param mMax is the number of SMS allowed without user permit - * @param mPeriod is the checking period - */ - SmsCounter(int mMax, int mPeriod) { - mMaxAllowed = mMax; - mCheckPeriod = mPeriod; - mSmsStamp = new HashMap<String, ArrayList<Long>> (); - } - - boolean check(String appName) { - if (!mSmsStamp.containsKey(appName)) { - mSmsStamp.put(appName, new ArrayList<Long>()); - } - - return isUnderLimit(mSmsStamp.get(appName)); - } - - private boolean isUnderLimit(ArrayList<Long> sent) { - Long ct = System.currentTimeMillis(); - - Log.d(TAG, "SMS send size=" + sent.size() + "time=" + ct); - - while (sent.size() > 0 && (ct - sent.get(0)) > mCheckPeriod ) { - sent.remove(0); - } - - if (sent.size() < mMaxAllowed) { - sent.add(ct); - return true; - } - return false; - } - } - - SMSDispatcher(CDMAPhone phone) { - mPhone = phone; - mContext = phone.getContext(); - mResolver = mContext.getContentResolver(); - mCm = phone.mCM; - mSTracker = null; - mCounter = new SmsCounter(DEFAULT_SMS_MAX_ALLOWED, - DEFAULT_SMS_CHECK_PERIOD); - - //mCm.setOnNewSMS(this, EVENT_NEW_SMS, null); - //mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null); - //mCm.setOnSimSmsFull(this, EVENT_SIM_FULL, null); - //TODO CommandsInterface method for setOnRuimSmsFull - - // Don't always start message ref at 0. - sConcatenatedRef = new Random().nextInt(256); - } - - /* TODO: Need to figure out how to keep track of status report routing in a - * persistent manner. If the phone process restarts (reboot or crash), - * we will lose this list and any status reports that come in after - * will be dropped. - */ - /** Sent messages awaiting a delivery status report. */ - private final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>(); - - /** - * Handles events coming from the phone stack. Overridden from handler. - * - * @param msg the message to handle - */ - @Override - public void handleMessage(Message msg) { - AsyncResult ar; - - switch (msg.what) { - case EVENT_NEW_SMS: - // A new SMS has been received by the device -// if (Config.LOGD) { - Log.d(TAG, "New SMS Message Received"); //TODO -// } - -/* SmsMessage sms; - - ar = (AsyncResult) msg.obj; - - // FIXME unit test leaves cm == null. this should change - if (mCm != null) { - // FIXME only acknowledge on store - mCm.acknowledgeLastIncomingSMS(true, null); - } - - if (ar.exception != null) { - Log.e(TAG, "Exception processing incoming SMS", - ar.exception); - return; - } - - sms = (SmsMessage) ar.result; - dispatchMessage(sms); */ - - break; - - case EVENT_SEND_SMS_COMPLETE: - // An outbound SMS has been sucessfully transferred, or failed. -// handleSendComplete((AsyncResult) msg.obj); - Log.d(TAG, "Event EVENT_SEND_SMS_COMPLETE Received"); //TODO - break; - - case EVENT_SEND_RETRY: -// sendSms((SmsTracker) msg.obj); - Log.d(TAG, "Event EVENT_SEND_RETRY Received"); //TODO - break; - - case EVENT_NEW_SMS_STATUS_REPORT: -// handleStatusReport((AsyncResult)msg.obj); - Log.d(TAG, "Event EVENT_NEW_SMS_STATUS_REPORT Received"); //TODO - break; - - case EVENT_RUIM_FULL: -// handleSimFull(); - Log.d(TAG, "Event EVENT_SIM_FULL Received"); //TODO - break; - - case EVENT_POST_ALERT: -// handleReachSentLimit((SmsTracker)(msg.obj)); - Log.d(TAG, "Event EVENT_POST_ALERT Received"); //TODO - break; - - case EVENT_ALERT_TIMEOUT: -/* ((AlertDialog)(msg.obj)).dismiss(); - msg.obj = null; - mSTracker = null; */ - Log.d(TAG, "Event EVENT_ALERT_TIMEOUT Received"); //TODO - break; - - case EVENT_SEND_CONFIRMED_SMS: -/* if (mSTracker!=null) { - Log.d(TAG, "Ready to send SMS again."); - sendSms(mSTracker); - mSTracker = null; - } */ - Log.d(TAG, "Event EVENT_SEND_CONFIRMED_SMS Received"); //TODO - break; - } - } - - /** - * Called when SIM_FULL message is received from the RIL. Notifies interested - * parties that SIM storage for SMS messages is full. - */ - private void handleSimFull() { - //TODO -// // broadcast SIM_FULL intent -// Intent intent = new Intent(Intents.SIM_FULL_ACTION); -// mPhone.getContext().sendBroadcast(intent, "android.permission.RECEIVE_SMS"); - } - - /** - * Called when a status report is received. This should correspond to - * a previously successful SEND. - * - * @param ar AsyncResult passed into the message handler. ar.result should - * be a String representing the status report PDU, as ASCII hex. - */ - private void handleStatusReport(AsyncResult ar) { - //TODO -/* String pduString = (String) ar.result; - SmsMessage sms = SmsMessage.newFromCDS(pduString); - - if (sms != null) { - int messageRef = sms.messageRef; - for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { - SmsTracker tracker = deliveryPendingList.get(i); - if (tracker.mMessageRef == messageRef) { - // Found it. Remove from list and broadcast. - deliveryPendingList.remove(i); - PendingIntent intent = tracker.mDeliveryIntent; - Intent fillIn = new Intent(); - fillIn.putExtra("pdu", IccUtils.hexStringToBytes(pduString)); - try { - intent.send(mContext, Activity.RESULT_OK, fillIn); - } catch (CanceledException ex) {} - - // Only expect to see one tracker matching this messageref - break; - } - } - } - - if (mCm != null) { - mCm.acknowledgeLastIncomingSMS(true, null); - } */ - } - - /** - * Called when SMS send completes. Broadcasts a sentIntent on success. - * On failure, either sets up retries or broadcasts a sentIntent with - * the failure in the result code. - * - * @param ar AsyncResult passed into the message handler. ar.result should - * an SmsResponse instance if send was successful. ar.userObj - * should be an SmsTracker instance. - */ - private void handleSendComplete(AsyncResult ar) { - //TODO -/* SmsTracker tracker = (SmsTracker) ar.userObj; - PendingIntent sentIntent = tracker.mSentIntent; - - if (ar.exception == null) { - if (Config.LOGD) { - Log.d(TAG, "SMS send complete. Broadcasting " - + "intent: " + sentIntent); - } - - if (tracker.mDeliveryIntent != null) { - // Expecting a status report. Add it to the list. - int messageRef = ((SmsResponse)ar.result).messageRef; - tracker.mMessageRef = messageRef; - deliveryPendingList.add(tracker); - } - - if (sentIntent != null) { - try { - sentIntent.send(Activity.RESULT_OK); - } catch (CanceledException ex) {} - } - } else { - if (Config.LOGD) { - Log.d(TAG, "SMS send failed"); - } - - int ss = mPhone.getServiceState().getState(); - - if (ss != ServiceState.STATE_IN_SERVICE) { - handleNotInService(ss, tracker); - } else if ((((CommandException)(ar.exception)).getCommandError() - == CommandException.Error.SMS_FAIL_RETRY) && - tracker.mRetryCount < MAX_SEND_RETRIES) { - // Retry after a delay if needed. - // TODO: According to TS 23.040, 9.2.3.6, we should resend - // with the same TP-MR as the failed message, and - // TP-RD set to 1. However, we don't have a means of - // knowing the MR for the failed message (EF_SMSstatus - // may or may not have the MR corresponding to this - // message, depending on the failure). Also, in some - // implementations this retry is handled by the baseband. - tracker.mRetryCount++; - Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker); - sendMessageDelayed(retryMsg, SEND_RETRY_DELAY); - } else if (tracker.mSentIntent != null) { - // Done retrying; return an error to the app. - try { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE); - } catch (CanceledException ex) {} - } - } */ - } - - /** - * Handles outbound message when the phone is not in service. - * - * @param ss Current service state. Valid values are: - * OUT_OF_SERVICE - * EMERGENCY_ONLY - * POWER_OFF - * @param tracker An SmsTracker for the current message. - */ - private void handleNotInService(int ss, SmsTracker tracker) { - //TODO -/* if (tracker.mSentIntent != null) { - try { - if (ss == ServiceState.STATE_POWER_OFF) { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_RADIO_OFF); - } else { - tracker.mSentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE); - } - } catch (CanceledException ex) {} - } */ - } - - /** - * Dispatches an incoming SMS messages. - * - * @param sms the incoming message from the phone - */ - /* package */ void dispatchMessage(SmsMessage sms) { - //TODO -/* boolean handled = false; - - // Special case the message waiting indicator messages - if (sms.isMWISetMessage()) { - mPhone.updateMessageWaitingIndicator(true); - - if (sms.isMwiDontStore()) { - handled = true; - } - - if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator set SMS shouldStore=" - + !handled); - } - } else if (sms.isMWIClearMessage()) { - mPhone.updateMessageWaitingIndicator(false); - - if (sms.isMwiDontStore()) { - handled = true; - } - - if (Config.LOGD) { - Log.d(TAG, - "Received voice mail indicator clear SMS shouldStore=" - + !handled); - } - } - - if (handled) { - return; - } - - // Parse the headers to see if this is partial, or port addressed - int referenceNumber = -1; - int count = 0; - int sequence = 0; - int destPort = -1; - - SmsHeader header = sms.getUserDataHeader(); - if (header != null) { - for (SmsHeader.Element element : header.getElements()) { - switch (element.getID()) { - case SmsHeader.CONCATENATED_8_BIT_REFERENCE: { - byte[] data = element.getData(); - - referenceNumber = data[0] & 0xff; - count = data[1] & 0xff; - sequence = data[2] & 0xff; - - break; - } - - case SmsHeader.CONCATENATED_16_BIT_REFERENCE: { - byte[] data = element.getData(); - - referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff); - count = data[2] & 0xff; - sequence = data[3] & 0xff; - - break; - } - - case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: { - byte[] data = element.getData(); - - destPort = (data[0] & 0xff) << 8; - destPort |= (data[1] & 0xff); - - break; - } - } - } - } - - if (referenceNumber == -1) { - // notify everyone of the message if it isn't partial - byte[][] pdus = new byte[1][]; - pdus[0] = sms.getPdu(); - - if (destPort != -1) { - if (destPort == SmsHeader.PORT_WAP_PUSH) { - dispatchWapPdu(sms.getUserData()); - } - // The message was sent to a port, so concoct a URI for it - dispatchPortAddressedPdus(pdus, destPort); - } else { - // It's a normal message, dispatch it - dispatchPdus(pdus); - } - } else { - // Process the message part - processMessagePart(sms, referenceNumber, sequence, count, destPort); - } */ - } - - /** - * If this is the last part send the parts out to the application, otherwise - * the part is stored for later processing. - */ - private void processMessagePart(SmsMessage sms, int referenceNumber, - int sequence, int count, int destinationPort) { - //TODO -/* // Lookup all other related parts - StringBuilder where = new StringBuilder("reference_number ="); - where.append(referenceNumber); - where.append(" AND address = ?"); - String[] whereArgs = new String[] {sms.getOriginatingAddress()}; - - byte[][] pdus = null; - Cursor cursor = null; - try { - cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null); - int cursorCount = cursor.getCount(); - if (cursorCount != count - 1) { - // We don't have all the parts yet, store this one away - ContentValues values = new ContentValues(); - values.put("date", new Long(sms.getTimestampMillis())); - values.put("pdu", HexDump.toHexString(sms.getPdu())); - values.put("address", sms.getOriginatingAddress()); - values.put("reference_number", referenceNumber); - values.put("count", count); - values.put("sequence", sequence); - if (destinationPort != -1) { - values.put("destination_port", destinationPort); - } - mResolver.insert(mRawUri, values); - - return; - } - - // All the parts are in place, deal with them - int pduColumn = cursor.getColumnIndex("pdu"); - int sequenceColumn = cursor.getColumnIndex("sequence"); - - pdus = new byte[count][]; - for (int i = 0; i < cursorCount; i++) { - cursor.moveToNext(); - int cursorSequence = (int)cursor.getLong(sequenceColumn); - pdus[cursorSequence - 1] = HexDump.hexStringToByteArray( - cursor.getString(pduColumn)); - } - // This one isn't in the DB, so add it - pdus[sequence - 1] = sms.getPdu(); - - // Remove the parts from the database - mResolver.delete(mRawUri, where.toString(), whereArgs); - } catch (SQLException e) { - Log.e(TAG, "Can't access multipart SMS database", e); - return; // TODO: NACK the message or something, don't just discard. - } finally { - if (cursor != null) cursor.close(); - } - - // Dispatch the PDUs to applications - switch (destinationPort) { - case SmsHeader.PORT_WAP_PUSH: { - // Build up the data stream - ByteArrayOutputStream output = new ByteArrayOutputStream(); - for (int i = 0; i < count; i++) { - SmsMessage msg = SmsMessage.createFromPdu(pdus[i]); - byte[] data = msg.getUserData(); - output.write(data, 0, data.length); - } - - // Handle the PUSH - dispatchWapPdu(output.toByteArray()); - break; - } - - case -1: - // The messages were not sent to a port - dispatchPdus(pdus); - break; - - default: - // The messages were sent to a port, so concoct a URI for it - dispatchPortAddressedPdus(pdus, destinationPort); - break; - } */ - } - - /** - * Dispatches standard PDUs to interested applications - * - * @param pdus The raw PDUs making up the message - */ - private void dispatchPdus(byte[][] pdus) { - //TODO -/* Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION); - intent.putExtra("pdus", pdus); - mPhone.getContext().sendBroadcast( - intent, "android.permission.RECEIVE_SMS"); */ - } - - /** - * Dispatches port addressed PDUs to interested applications - * - * @param pdus The raw PDUs making up the message - * @param port The destination port of the messages - */ - private void dispatchPortAddressedPdus(byte[][] pdus, int port) { - //TODO -/* Uri uri = Uri.parse("sms://localhost:" + port); - Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri); - intent.putExtra("pdus", pdus); - mPhone.getContext().sendBroadcast( - intent, "android.permission.RECEIVE_SMS"); */ - } - - /** - * Dispatches inbound messages that are in the WAP PDU format. See - * wap-230-wsp-20010705-a section 8 for details on the WAP PDU format. - * - * @param pdu The WAP PDU, made up of one or more SMS PDUs - */ - private void dispatchWapPdu(byte[] pdu) { - //TODO - } - - /** - * Send a multi-part text based SMS. - * - * @param destinationAddress the address to send the message to - * @param scAddress is the service center address or null to use - * the current default SMSC - * @param parts an <code>ArrayList</code> of strings that, in order, - * comprise the original message - * @param sentIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been sent. - * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. - * The per-application based SMS control checks sentIntent. If sentIntent - * is NULL the caller will be checked against all unknown applicaitons, - * which cause smaller number of SMS to be sent in checking period. - * @param deliveryIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been delivered - * to the recipient. The raw pdu of the status report is in the - * extended data ("pdu"). - */ - void sendMultipartText(String destinationAddress, String scAddress, ArrayList<String> parts, - ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { - //TODO -/* - int ref = ++sConcatenatedRef & 0xff; - - for (int i = 0, count = parts.size(); i < count; i++) { - // build SmsHeader - byte[] data = new byte[3]; - data[0] = (byte) ref; // reference #, unique per message - data[1] = (byte) count; // total part count - data[2] = (byte) (i + 1); // 1-based sequence - SmsHeader header = new SmsHeader(); - header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data)); - PendingIntent sentIntent = null; - PendingIntent deliveryIntent = null; - - if (sentIntents != null && sentIntents.size() > i) { - sentIntent = sentIntents.get(i); - } - if (deliveryIntents != null && deliveryIntents.size() > i) { - deliveryIntent = deliveryIntents.get(i); - } - - SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, - parts.get(i), deliveryIntent != null, header.toByteArray()); - - sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); - } */ - } - - /** - * Send a SMS - * - * @param smsc the SMSC to send the message through, or NULL for the - * defatult SMSC - * @param pdu the raw PDU to send - * @param sentIntent if not NULL this <code>Intent</code> is - * broadcast when the message is sucessfully sent, or failed. - * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. - * The per-application based SMS control checks sentIntent. If sentIntent - * is NULL the caller will be checked against all unknown applicaitons, - * which cause smaller number of SMS to be sent in checking period. - * @param deliveryIntent if not NULL this <code>Intent</code> is - * broadcast when the message is delivered to the recipient. The - * raw pdu of the status report is in the extended data ("pdu"). - */ - void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, - PendingIntent deliveryIntent) { - //TODO -/* if (pdu == null) { - if (sentIntent != null) { - try { - sentIntent.send(SmsManager.RESULT_ERROR_NULL_PDU); - } catch (CanceledException ex) {} - } - return; - } - - HashMap<String, Object> map = new HashMap<String, Object>(); - map.put("smsc", smsc); - map.put("pdu", pdu); - - SmsTracker tracker = new SmsTracker(map, sentIntent, - deliveryIntent); - int ss = mPhone.getServiceState().getState(); - - if (ss != ServiceState.STATE_IN_SERVICE) { - handleNotInService(ss, tracker); - } else { - String appName = getAppNameByIntent(sentIntent); - if (mCounter.check(appName)) { - sendSms(tracker); - } else { - sendMessage(obtainMessage(EVENT_POST_ALERT, tracker)); - } - } */ - } - - /** - * Post an alert while SMS needs user confirm. - * - * An SmsTracker for the current message. - */ - private void handleReachSentLimit(SmsTracker tracker) { - //TODO -/* - Resources r = Resources.getSystem(); - - String appName = getAppNameByIntent(tracker.mSentIntent); - - AlertDialog d = new AlertDialog.Builder(mContext) - .setTitle(r.getString(R.string.sms_control_title)) - .setMessage(appName + " " + r.getString(R.string.sms_control_message)) - .setPositiveButton(r.getString(R.string.sms_control_yes), mListener) - .setNegativeButton(r.getString(R.string.sms_control_no), null) - .create(); - - d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - d.show(); - - mSTracker = tracker; - sendMessageDelayed ( obtainMessage(EVENT_ALERT_TIMEOUT, d), - DEFAULT_SMS_TIMOUEOUT); */ - } - - private String getAppNameByIntent(PendingIntent intent) { - //TODO -/* Resources r = Resources.getSystem(); - return (intent != null) ? intent.getTargetPackage() - : r.getString(R.string.sms_control_default_app_name); */ - String ret = "to be implemented"; - return ret; - } - - /** - * Send the message along to the radio. - * - * @param tracker holds the SMS message to send - */ - private void sendSms(SmsTracker tracker) { - //TODO -/* HashMap map = tracker.mData; - - byte smsc[] = (byte[]) map.get("smsc"); - byte pdu[] = (byte[]) map.get("pdu"); - - Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); - mCm.sendSMS(IccUtils.bytesToHexString(smsc), - IccUtils.bytesToHexString(pdu), reply); */ - } - - /** - * Keeps track of an SMS that has been sent to the RIL, until it it has - * successfully been sent, or we're done trying. - * - */ - static class SmsTracker { - //TODO - HashMap mData; - int mRetryCount; - int mMessageRef; - - PendingIntent mSentIntent; - PendingIntent mDeliveryIntent; - - SmsTracker(HashMap data, PendingIntent sentIntent, - PendingIntent deliveryIntent) { - mData = data; - mSentIntent = sentIntent; - mDeliveryIntent = deliveryIntent; - mRetryCount = 0; - } - - } - - private DialogInterface.OnClickListener mListener = - new DialogInterface.OnClickListener() { - - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON1) { - Log.d(TAG, "click YES to send out sms"); - //sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS)); //TODO - } - } - }; -} diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java new file mode 100644 index 000000000000..921b6633c6d3 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java @@ -0,0 +1,905 @@ +/* + * Copyright (C) 2008 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.cdma; + +import android.pim.Time; +import android.os.Parcel; +import android.util.Config; +import android.util.Log; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; +import com.android.internal.telephony.cdma.sms.BearerData; +import com.android.internal.telephony.cdma.sms.CdmaSmsAddress; +import com.android.internal.telephony.cdma.sms.SmsDataCoding; +import com.android.internal.telephony.cdma.sms.SmsEnvelope; +import com.android.internal.telephony.cdma.sms.UserData; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.Random; + +import static android.telephony.SmsMessage.ENCODING_7BIT; +import static android.telephony.SmsMessage.ENCODING_8BIT; +import static android.telephony.SmsMessage.ENCODING_16BIT; +import static android.telephony.SmsMessage.ENCODING_UNKNOWN; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER; +import static android.telephony.SmsMessage.MessageClass; +import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_NONE; +import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_TEMPORARY; +import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_PERMANENT; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_DELIVER; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_SUBMIT; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_CANCELLATION; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_DELIVERY_ACK; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_USER_ACK; +import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_READ_ACK; +import static com.android.internal.telephony.cdma.sms.CdmaSmsAddress.SMS_ADDRESS_MAX; +import static com.android.internal.telephony.cdma.sms.CdmaSmsAddress.SMS_SUBADDRESS_MAX; +import static com.android.internal.telephony.cdma.sms.SmsEnvelope.SMS_BEARER_DATA_MAX; +import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_7BIT_ASCII; +import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_GSM_7BIT_ALPHABET; +import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_IA5; +import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_OCTET; +import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_UNICODE_16; + +/** + * A Short Message Service message. + * + */ +public class SmsMessage extends SmsMessageBase { + static final String LOG_TAG = "CDMA"; + + /** + * Status of a previously submitted SMS. + * This field applies to SMS Delivery Acknowledge messages. 0 indicates success; + * Here, the error class is defined by the bits from 9-8, the status code by the bits from 7-0. + * See C.S0015-B, v2.0, 4.5.21 for a detailed description of possible values. + */ + private int status; + + /** The next message ID for the BearerData. Shall be a random value on first use. + * (See C.S0015-B, v2.0, 4.3.1.5) + */ + private static int nextMessageId = 0; + + /** Specifies if this is the first SMS message submit */ + private static boolean firstSMS = true; + + /** Specifies if a return of an acknowledgment is requested for send SMS */ + private static final int RETURN_NO_ACK = 0; + private static final int RETURN_ACK = 1; + + private SmsEnvelope mEnvelope; + private BearerData mBearerData; + + public static class SubmitPdu extends SubmitPduBase { + } + + /** + * Create an SmsMessage from a raw PDU. + * Note: In CDMA the PDU is just a byte representation of the received Sms. + */ + public static SmsMessage createFromPdu(byte[] pdu) { + SmsMessage msg = new SmsMessage(); + + try { + msg.parsePdu(pdu); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static SmsMessage newFromCMT(String[] lines) { + Log.w(LOG_TAG, "newFromCMT: is not supported in CDMA mode."); + return null; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static SmsMessage newFromCMTI(String line) { + Log.w(LOG_TAG, "newFromCMTI: is not supported in CDMA mode."); + return null; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static SmsMessage newFromCDS(String line) { + Log.w(LOG_TAG, "newFromCDS: is not supported in CDMA mode."); + return null; + } + + /** + * Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp. + * Note: Only primitive fields are set. + */ + public static SmsMessage newFromParcel(Parcel p) { + // Note: Parcel.readByte actually reads one Int and masks to byte + SmsMessage msg = new SmsMessage(); + SmsEnvelope env = new SmsEnvelope(); + CdmaSmsAddress addr = new CdmaSmsAddress(); + byte[] data; + byte count; + int countInt; + + //currently not supported by the modem-lib: env.mMessageType + env.teleService = p.readInt(); //p_cur->uTeleserviceID + + if (0 != p.readByte()) { //p_cur->bIsServicePresent + env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST; + } + else { + if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) { + // assume type ACK + env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE; + } else { + env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT; + } + } + env.serviceCategory = p.readInt(); //p_cur->uServicecategory + + // address + addr.digitMode = (byte) (0xFF & p.readInt()); //p_cur->sAddress.digit_mode + addr.numberMode = (byte) (0xFF & p.readInt()); //p_cur->sAddress.number_mode + addr.ton = p.readInt(); //p_cur->sAddress.number_type + addr.numberPlan = (byte) (0xFF & p.readInt()); //p_cur->sAddress.number_plan + count = p.readByte(); //p_cur->sAddress.number_of_digits + addr.numberOfDigits = count; + data = new byte[count]; + //p_cur->sAddress.digits[digitCount] + for (int index=0; index < count; index++) { + data[index] = p.readByte(); + } + addr.origBytes = data; + + // ignore subaddress + p.readInt(); //p_cur->sSubAddress.subaddressType + p.readInt(); //p_cur->sSubAddress.odd + count = p.readByte(); //p_cur->sSubAddress.number_of_digits + //p_cur->sSubAddress.digits[digitCount] : + for (int index=0; index < count; index++) { + p.readByte(); + } + + /* currently not supported by the modem-lib: + env.bearerReply + env.replySeqNo + env.errorClass + env.causeCode + */ + + // bearer data + countInt = p.readInt(); //p_cur->uBearerDataLen + if (countInt >0) { + data = new byte[countInt]; + //p_cur->aBearerData[digitCount] : + for (int index=0; index < countInt; index++) { + data[index] = p.readByte(); + } + env.bearerData = data; + // BD gets further decoded when accessed in SMSDispatcher + } + + // link the the filled objects to the SMS + env.origAddress = addr; + msg.originatingAddress = addr; + msg.mEnvelope = env; + + // create byte stream representation for transportation through the layers. + msg.createPdu(); + + return msg; + } + + /** + * Create an SmsMessage from an SMS EF record. + * + * @param index Index of SMS record. This should be index in ArrayList + * returned by RuimSmsInterfaceManager.getAllMessagesFromIcc + 1. + * @param data Record data. + * @return An SmsMessage representing the record. + * + * @hide + */ + public static SmsMessage createFromEfRecord(int index, byte[] data) { + try { + SmsMessage msg = new SmsMessage(); + + msg.indexOnIcc = index; + + // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, + // or STORED_UNSENT + // See 3GPP2 C.S0023 3.4.27 + if ((data[0] & 1) == 0) { + Log.w(LOG_TAG, "SMS parsing failed: Trying to parse a free record"); + return null; + } else { + msg.statusOnIcc = data[0] & 0x07; + } + + // Second byte is the MSG_LEN, length of the message + // See 3GPP2 C.S0023 3.4.27 + int size = data[1]; + + // Note: Data may include trailing FF's. That's OK; message + // should still parse correctly. + byte[] pdu = new byte[size]; + System.arraycopy(data, 2, pdu, 0, size); + // the message has to be parsed before it can be displayed + // see gsm.SmsMessage + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public static int getTPLayerLengthForPDU(String pdu) { + Log.w(LOG_TAG, "getTPLayerLengthForPDU: is not supported in CDMA mode."); + return 0; + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @param destinationAddress Address of the recipient. + * @param message String representation of the message payload. + * @param statusReportRequested Indicates whether a report is requested for this message. + * @param headerData Array containing the data for the User Data Header, preceded + * by the Element Identifiers. + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @hide + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested, byte[] headerData) { + + SmsMessage sms = new SmsMessage(); + SubmitPdu ret = new SubmitPdu(); + UserData uData = new UserData(); + SmsHeader smsHeader; + + // Perform null parameter checks. + if (message == null || destinationAddress == null) { + return null; + } + + // ** Set UserData + SmsHeader ** + try { + // First, try encoding it with the GSM alphabet + int septetCount = GsmAlphabet.countGsmSeptets(message, true); + // User Data (and length) + + uData.userData = message.getBytes(); + + if (uData.userData.length > MAX_USER_DATA_SEPTETS) { + // Message too long + return null; + } + + // desired TP-Data-Coding-Scheme + uData.userDataEncoding = UserData.UD_ENCODING_GSM_7BIT_ALPHABET; + + // paddingBits not needed for UD_ENCODING_GSM_7BIT_ALPHABET + + // sms header + if(headerData != null) { + smsHeader = SmsHeader.parse(headerData); + uData.userDataHeader = smsHeader; + } else { + // no user data header available! + } + + } catch (EncodeException ex) { + byte[] textPart; + // Encoding to the 7-bit alphabet failed. Let's see if we can + // send it as a UCS-2 encoded message + + try { + textPart = message.getBytes("utf-16be"); + } catch (UnsupportedEncodingException uex) { + Log.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex); + return null; + } + + uData.userData = textPart; + + if (uData.userData.length > MAX_USER_DATA_BYTES) { + // Message too long + return null; + } + + // TP-Data-Coding-Scheme + uData.userDataEncoding = UserData.UD_ENCODING_UNICODE_16; + + // sms header + if(headerData != null) { + smsHeader = SmsHeader.parse(headerData); + uData.userDataHeader = smsHeader; + } else { + // no user data header available! + } + } + + byte[] data = sms.getEnvelope(destinationAddress, statusReportRequested, uData, + (headerData != null), (null == headerData)); + + if (null == data) return null; + + ret.encodedMessage = data; + ret.encodedScAddress = null; + return ret; + } + + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested) { + return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); + } + + /** + * Get an SMS-SUBMIT PDU for a data message to a destination address & port + * + * @param scAddress Service Centre address. null == use default + * @param destinationAddress the address of the destination for the message + * @param destinationPort the port to deliver the message to at the + * destination + * @param data the data for the message + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, short destinationPort, byte[] data, + boolean statusReportRequested) { + + SmsMessage sms = new SmsMessage(); + SubmitPdu ret = new SubmitPdu(); + UserData uData = new UserData(); + SmsHeader smsHeader = new SmsHeader(); + + if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) { + Log.e(LOG_TAG, "SMS data message may only contain " + + (MAX_USER_DATA_BYTES - 7) + " bytes"); + return null; + } + + byte[] destPort = new byte[4]; + destPort[0] = (byte) ((destinationPort >> 8) & 0xFF); // MSB of destination port + destPort[1] = (byte) (destinationPort & 0xFF); // LSB of destination port + destPort[2] = 0x00; // MSB of originating port + destPort[3] = 0x00; // LSB of originating port + smsHeader.add( + new SmsHeader.Element(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT, destPort)); + + smsHeader.nbrOfHeaders = smsHeader.getElements().size(); + uData.userDataHeader = smsHeader; + + // TP-Data-Coding-Scheme + // No class, 8 bit data + uData.userDataEncoding = UserData.UD_ENCODING_OCTET; + uData.userData = data; + + byte[] msgData = sms.getEnvelope(destinationAddress, statusReportRequested, uData, + true, true); + + ret.encodedMessage = msgData; + ret.encodedScAddress = null; + return ret; + } + + static class PduParser { + + PduParser() { + } + + /** + * Parses an SC timestamp and returns a currentTimeMillis()-style + * timestamp + */ + static long getSCTimestampMillis(byte[] timestamp) { + // TP-Service-Centre-Time-Stamp + int year = IccUtils.beBcdByteToInt(timestamp[0]); + int month = IccUtils.beBcdByteToInt(timestamp[1]); + int day = IccUtils.beBcdByteToInt(timestamp[2]); + int hour = IccUtils.beBcdByteToInt(timestamp[3]); + int minute = IccUtils.beBcdByteToInt(timestamp[4]); + int second = IccUtils.beBcdByteToInt(timestamp[5]); + + Time time = new Time(Time.TIMEZONE_UTC); + + // C.S0015-B v2.0, 4.5.4: range is 1996-2095 + time.year = year >= 96 ? year + 1900 : year + 2000; + time.month = month - 1; + time.monthDay = day; + time.hour = hour; + time.minute = minute; + time.second = second; + + return time.toMillis(true); + } + + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public int getProtocolIdentifier() { + Log.w(LOG_TAG, "getProtocolIdentifier: is not supported in CDMA mode."); + // (3GPP TS 23.040): "no interworking, but SME to SME protocol": + return 0; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isReplace() { + Log.w(LOG_TAG, "isReplace: is not supported in CDMA mode."); + return false; + } + + /** + * {@inheritDoc} + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isCphsMwiMessage() { + Log.w(LOG_TAG, "isCphsMwiMessage: is not supported in CDMA mode."); + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isMWIClearMessage() { + if ((mBearerData != null) && (0 == mBearerData.numberOfMessages)) { + return true; + } + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isMWISetMessage() { + if ((mBearerData != null) && (mBearerData.numberOfMessages >0)) { + return true; + } + return false; + } + + /** + * {@inheritDoc} + */ + public boolean isMwiDontStore() { + if ((mBearerData != null) && (mBearerData.numberOfMessages >0) + && (null == mBearerData.userData)) { + return true; + } + return false; + } + + /** + * Returns the status for a previously submitted message. + * For not interfering with status codes from GSM, this status code is + * shifted to the bits 31-16. + */ + public int getStatus() { + return(status<<16); + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isStatusReportMessage() { + Log.w(LOG_TAG, "isStatusReportMessage: is not supported in CDMA mode."); + return false; + } + + /** + * Note: This function is a GSM specific functionality which is not supported in CDMA mode. + */ + public boolean isReplyPathPresent() { + Log.w(LOG_TAG, "isReplyPathPresent: is not supported in CDMA mode."); + return false; + } + + /** + * Returns the teleservice type of the message. + * @return the teleservice: + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WMT}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WEMT}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN}, + * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP} + */ + public int getTeleService() { + return mEnvelope.teleService; + } + + /** + * Decodes pdu to an empty SMS object. + * In the CDMA case the pdu is just an internal byte stream representation + * of the SMS Java-object. + * @see #createPdu() + */ + private void parsePdu(byte[] pdu) { + ByteArrayInputStream bais = new ByteArrayInputStream(pdu); + DataInputStream dis = new DataInputStream(new BufferedInputStream(bais)); + byte length; + SmsEnvelope env = new SmsEnvelope(); + CdmaSmsAddress addr = new CdmaSmsAddress(); + + try { + env.messageType = dis.readInt(); + env.teleService = dis.readInt(); + env.serviceCategory = dis.readInt(); + + addr.digitMode = dis.readByte(); + addr.numberMode = dis.readByte(); + addr.ton = dis.readByte(); + addr.numberPlan = dis.readByte(); + + length = dis.readByte(); + addr.numberOfDigits = length; + addr.origBytes = new byte[length]; + dis.read(addr.origBytes, 0, length); // digits + + env.bearerReply = dis.readInt(); + // CauseCode values: + env.replySeqNo = dis.readByte(); + env.errorClass = dis.readByte(); + env.causeCode = dis.readByte(); + + //encoded BearerData: + length = dis.readByte(); + env.bearerData = new byte[length]; + dis.read(env.bearerData, 0, length); + dis.close(); + } catch (Exception ex) { + Log.e(LOG_TAG, "createFromPdu: conversion from byte array to object failed: " + ex); + } + + // link the filled objects to this SMS + originatingAddress = addr; + env.origAddress = addr; + mEnvelope = env; + + parseSms(); + } + + /** + * Parses a SMS message from its BearerData stream. (mobile-terminated only) + */ + protected void parseSms() { + mBearerData = SmsDataCoding.decodeCdmaSms(mEnvelope.bearerData); + messageRef = mBearerData.messageID; + + // TP-Message-Type-Indicator + // (See 3GPP2 C.S0015-B, v2, 4.5.1) + int messageType = mBearerData.messageType; + + switch (messageType) { + case MESSAGE_TYPE_USER_ACK: + case MESSAGE_TYPE_READ_ACK: + case MESSAGE_TYPE_DELIVER: + // Deliver (mobile-terminated only) + parseSmsDeliver(); + break; + case MESSAGE_TYPE_DELIVERY_ACK: + parseSmsDeliveryAck(); + break; + + default: + // the rest of these + throw new RuntimeException("Unsupported message type: " + messageType); + } + } + + /** + * Parses a SMS-DELIVER message. (mobile-terminated only) + * See 3GPP2 C.S0015-B, v2, 4.4.1 + */ + private void parseSmsDeliver() { + if (originatingAddress != null) { + originatingAddress.address = new String(originatingAddress.origBytes); + if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " + + originatingAddress.address); + } + + if (mBearerData.timeStamp != null) { + scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp); + } + + if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); + + parseUserData(mBearerData.userData); + } + + /** + * Parses a SMS-DELIVER message. (mobile-terminated only) + * See 3GPP2 C.S0015-B, v2, 4.4.1 + */ + private void parseSmsDeliveryAck() { + if (originatingAddress != null) { + originatingAddress.address = new String(originatingAddress.origBytes); + if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " + + originatingAddress.address); + } + + if (mBearerData.timeStamp != null) { + scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp); + } + + if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); + + if (mBearerData.errorClass != BearerData.ERROR_UNDEFINED) { + status = mBearerData.errorClass << 8; + status |= mBearerData.messageStatus; + } + + parseUserData(mBearerData.userData); + + } + + /** + * Parses the User Data of an SMS. + */ + private void parseUserData(UserData uData) { + int encodingType; + + if (null == uData) { + return; + } + + encodingType = uData.userDataEncoding; + + // insert DCS-decoding here when type is supported by ril-library + + userData = uData.userData; + userDataHeader = uData.userDataHeader; + + switch (encodingType) { + case UD_ENCODING_GSM_7BIT_ALPHABET: + case UD_ENCODING_UNICODE_16: + // user data was already decoded by wmsts-library + messageBody = new String(userData); + break; + + // data and unsupported encodings: + case UD_ENCODING_OCTET: + default: + messageBody = null; + break; + } + + if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'"); + + if (messageBody != null) { + parseMessageBody(); + } + } + + /** + * {@inheritDoc} + */ + public MessageClass getMessageClass() { + if (BearerData.DISPLAY_IMMEDIATE == mBearerData.displayMode ) { + return MessageClass.CLASS_0; + } else { + return MessageClass.UNKNOWN; + } + } + + /** + * Creates BearerData and Envelope from parameters for a Submit SMS. + * @return byte stream for SubmitPdu. + */ + private byte[] getEnvelope(String destinationAddress, boolean statusReportRequested, + UserData userData, boolean hasHeaders, boolean useNewId) { + + BearerData mBearerData = new BearerData(); + SmsEnvelope env = new SmsEnvelope(); + CdmaSmsAddress mSmsAddress = new CdmaSmsAddress(); + + // ** set SmsAddress ** + mSmsAddress.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR; + try { + mSmsAddress.origBytes = destinationAddress.getBytes("UTF-8"); + } catch (Exception e) { + Log.e(LOG_TAG, "doGetSubmitPdu: conversion of destinationAddress from string to byte[]" + + " failed: " + e.getMessage()); + return null; + } + mSmsAddress.numberOfDigits = (byte)mSmsAddress.origBytes.length; + mSmsAddress.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK; + // see C.S0015-B, v2.0, 3.4.3.3 + mSmsAddress.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY; + mSmsAddress.ton = CdmaSmsAddress.TON_INTERNATIONAL_OR_IP; + + // ** set BearerData ** + mBearerData.userData = userData; + mBearerData.messageType = BearerData.MESSAGE_TYPE_SUBMIT; + + if (useNewId) { + setNextMessageId(); + } + mBearerData.messageID = nextMessageId; + + // Set the reply options (See C.S0015-B, v2.0, 4.5.11) + if(statusReportRequested) { + mBearerData.deliveryAckReq = true; + } else { + mBearerData.deliveryAckReq = false; + } + // Currently settings applications do not support this + mBearerData.userAckReq = false; + mBearerData.readAckReq = false; + mBearerData.reportReq = false; + + // Set the display mode (See C.S0015-B, v2.0, 4.5.16) + mBearerData.displayMode = BearerData.DISPLAY_DEFAULT; + + // number of messages: not needed for encoding! + + // indicate whether a user data header is available + mBearerData.hasUserDataHeader = hasHeaders; + + // ** encode BearerData ** + byte[] encodedBearerData = null; + try { + encodedBearerData = SmsDataCoding.encodeCdmaSms(mBearerData); + } catch (Exception e) { + Log.e(LOG_TAG, "doGetSubmitPdu: EncodeCdmaSMS function in JNI interface failed: " + + e.getMessage()); + return null; + } + + // ** SmsEnvelope ** + env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT; + env.teleService = SmsEnvelope.TELESERVICE_WEMT; + env.destAddress = mSmsAddress; + env.bearerReply = RETURN_ACK; + env.bearerData = encodedBearerData; + mEnvelope = env; + + // get byte array output stream from SmsAddress object and SmsEnvelope member. + return serialize(mSmsAddress); + } + + /** + * Set the nextMessageId to a random value between 0 and 65536 + * See C.S0015-B, v2.0, 4.3.1.5 + */ + private void setNextMessageId() { + // Message ID, modulo 65536 + if(firstSMS) { + Random generator = new Random(); + nextMessageId = generator.nextInt(65536); + firstSMS = false; + } else { + nextMessageId = ++nextMessageId & 0xFFFF; + } + } + + /** + * Creates ByteArrayOutputStream from CdmaSmsAddress and SmsEnvelope objects + * + * @param address CdmaSmsAddress object + * @return ByteArrayOutputStream + */ + private byte[] serialize(CdmaSmsAddress destAddress) { + SmsEnvelope env = mEnvelope; + ByteArrayOutputStream baos = new ByteArrayOutputStream(100); + DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos)); + + try { + dos.writeInt(env.teleService); + dos.writeInt(0); //servicePresent + dos.writeInt(0); //serviceCategory + dos.write(destAddress.digitMode); + dos.write(destAddress.numberMode); + dos.write(destAddress.ton); // number_type + dos.write(destAddress.numberPlan); + dos.write(destAddress.numberOfDigits); + dos.write(destAddress.origBytes, 0, destAddress.origBytes.length); // digits + // Subaddress is not supported. + dos.write(0); //subaddressType + dos.write(0); //subaddr_odd + dos.write(0); //subaddr_nbr_of_digits + dos.write(env.bearerData.length); + dos.write(env.bearerData, 0, env.bearerData.length); + dos.close(); + return baos.toByteArray(); + } catch(IOException ex) { + Log.e(LOG_TAG, "serialize: conversion from object to data output stream failed: " + ex); + return null; + } + } + + /** + * Creates byte array (pseudo pdu) from SMS object. + * Note: Do not call this method more than once per object! + */ + private void createPdu() { + SmsEnvelope env = mEnvelope; + CdmaSmsAddress addr = env.origAddress; + ByteArrayOutputStream baos = new ByteArrayOutputStream(100); + DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos)); + + try { + dos.writeInt(env.messageType); + dos.writeInt(env.teleService); + dos.writeInt(env.serviceCategory); + + dos.writeByte(addr.digitMode); + dos.writeByte(addr.numberMode); + dos.writeByte(addr.ton); + dos.writeByte(addr.numberPlan); + dos.writeByte(addr.numberOfDigits); + dos.write(addr.origBytes, 0, addr.origBytes.length); // digits + + dos.writeInt(env.bearerReply); + // CauseCode values: + dos.writeByte(env.replySeqNo); + dos.writeByte(env.errorClass); + dos.writeByte(env.causeCode); + //encoded BearerData: + dos.writeByte(env.bearerData.length); + dos.write(env.bearerData, 0, env.bearerData.length); + dos.close(); + + mPdu = baos.toByteArray(); + } catch (IOException ex) { + Log.e(LOG_TAG, "createPdu: conversion from object to byte array failed: " + ex); + } + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java b/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java new file mode 100644 index 000000000000..f27f79cd9ebe --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java @@ -0,0 +1,46 @@ +/* + * 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.cdma; + +public class TtyIntent { + + private static final String TAG = "TtyIntent"; + + + /** Event for TTY mode change */ + + /** + * Broadcast intent action indicating that the TTY has either been + * enabled or disabled. An intent extra provides this state as a boolean, + * where {@code true} means enabled. + * @see #TTY_ENABLED + * + * {@hide} + */ + public static final String TTY_ENABLED_CHANGE_ACTION = + "com.android.internal.telephony.cdma.intent.action.TTY_ENABLED_CHANGE"; + + /** + * The lookup key for a boolean that indicates whether TTY mode is enabled or + * disabled. {@code true} means TTY mode is enabled. Retrieve it with + * {@link android.content.Intent#getBooleanExtra(String,boolean)}. + * + * {@hide} + */ + public static final String TTY_ENABLED = "ttyEnabled"; + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/package.html b/telephony/java/com/android/internal/telephony/cdma/package.html new file mode 100644 index 000000000000..cf1ad4a046bf --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/package.html @@ -0,0 +1,6 @@ +<HTML> +<BODY> +Provides classes to control or read data from CDMA phones. +@hide +</BODY> +</HTML> diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java new file mode 100644 index 000000000000..fec95297f76d --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2008 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.cdma.sms; + +public final class BearerData{ + + // For completeness the following fields are listed, though not used yet. + /** + * Supported priority modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1) + */ + //public static final int PRIORITY_NORMAL = 0x0; + //public static final int PRIORITY_INTERACTIVE = 0x1; + //public static final int PRIORITY_URGENT = 0x2; + //public static final int PRIORITY_EMERGENCY = 0x3; + + /** + * Supported privacy modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.10-1) + */ + //public static final int PRIVACY_NOT_RESTRICTED = 0x0; + //public static final int PRIVACY_RESTRICTED = 0x1; + //public static final int PRIVACY_CONFIDENTIAL = 0x2; + //public static final int PRIVACY_SECRET = 0x3; + + /** + * Supported alert modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.13-1) + */ + //public static final int ALERT_DEFAULT = 0x0; + //public static final int ALERT_LOW_PRIO = 0x1; + //public static final int ALERT_MEDIUM_PRIO = 0x2; + //public static final int ALERT_HIGH_PRIO = 0x3; + + /** + * Supported display modes for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.16-1) + */ + public static final int DISPLAY_IMMEDIATE = 0x0; + public static final int DISPLAY_DEFAULT = 0x1; + public static final int DISPLAY_USER = 0x2; + + /** + * Supported message types for CDMA SMS messages + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1) + */ + public static final int MESSAGE_TYPE_DELIVER = 0x01; + public static final int MESSAGE_TYPE_SUBMIT = 0x02; + public static final int MESSAGE_TYPE_CANCELLATION = 0x03; + public static final int MESSAGE_TYPE_DELIVERY_ACK = 0x04; + public static final int MESSAGE_TYPE_USER_ACK = 0x05; + public static final int MESSAGE_TYPE_READ_ACK = 0x06; + public static final int MESSAGE_TYPE_DELIVER_REPORT = 0x07; + public static final int MESSAGE_TYPE_SUBMIT_REPORT = 0x08; + + /** + * SMS Message Status Codes + * (See 3GPP2 C.S0015-B, v2.0, table 4.5.21-1) + */ + /* no-error codes */ + public static final int ERROR_NONE = 0x00; + public static final int STATUS_ACCEPTED = 0x00; + public static final int STATUS_DEPOSITED_TO_INTERNET = 0x01; + public static final int STATUS_DELIVERED = 0x02; + public static final int STATUS_CANCELLED = 0x03; + /* temporary-error and permanent-error codes */ + public static final int ERROR_TEMPORARY = 0x02; + public static final int STATUS_NETWORK_CONGESTION = 0x04; + public static final int STATUS_NETWORK_ERROR = 0x05; + public static final int STATUS_UNKNOWN_ERROR = 0x1F; + /* permanent-error codes */ + public static final int ERROR_PERMANENT = 0x03; + public static final int STATUS_CANCEL_FAILED = 0x06; + public static final int STATUS_BLOCKED_DESTINATION = 0x07; + public static final int STATUS_TEXT_TOO_LONG = 0x08; + public static final int STATUS_DUPLICATE_MESSAGE = 0x09; + public static final int STATUS_INVALID_DESTINATION = 0x0A; + public static final int STATUS_MESSAGE_EXPIRED = 0x0D; + /* undefined-status codes */ + public static final int ERROR_UNDEFINED = 0xFF; + public static final int STATUS_UNDEFINED = 0xFF; + + /** Bit-mask indicating used fields for SmsDataCoding */ + public int mask; + + /** + * 4-bit value indicating the message type in accordance to + * table 4.5.1-1 + * (See 3GPP2 C.S0015-B, v2, 4.5.1) + */ + public byte messageType; + + /** + * 16-bit value indicating the message ID, which increments modulo 65536. + * (Special rules apply for WAP-messages.) + * (See 3GPP2 C.S0015-B, v2, 4.5.1) + */ + public int messageID; + + /** + * 1-bit value that indicates whether a User Data Header is present. + * (See 3GPP2 C.S0015-B, v2, 4.5.1) + */ + public boolean hasUserDataHeader; + + /** + * provides the information for the user data + * (e.g. padding bits, user data, user data header, etc) + * (See 3GPP2 C.S.0015-B, v2, 4.5.2) + */ + public UserData userData; + + //public UserResponseCode userResponseCode; + + /** + * 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4 + * year, month, day, hours, minutes, seconds; + */ + public byte[] timeStamp; + + //public SmsTime validityPeriodAbsolute; + //public SmsRelTime validityPeriodRelative; + //public SmsTime deferredDeliveryTimeAbsolute; + //public SmsRelTime deferredDeliveryTimeRelative; + //public byte priority; + //public byte privacy; + + /** + * Reply Option + * 1-bit values which indicate whether SMS acknowledgment is requested or not. + * (See 3GPP2 C.S0015-B, v2, 4.5.11) + */ + public boolean userAckReq; + public boolean deliveryAckReq; + public boolean readAckReq; + public boolean reportReq; + + /** + * The number of Messages element (8-bit value) is a decimal number in the 0 to 99 range + * representing the number of messages stored at the Voice Mail System. This element is + * used by the Voice Mail Notification service. + * (See 3GPP2 C.S0015-B, v2, 4.5.12) + */ + public int numberOfMessages; + + //public int alert; + //public int language; + + /** + * 4-bit or 8-bit value that indicates the number to be dialed in reply to a + * received SMS message. + * (See 3GPP2 C.S0015-B, v2, 4.5.15) + */ + public CdmaSmsAddress callbackNumber; + + /** + * 2-bit value that is used to indicate to the mobile station when to display + * the received message. + * (See 3GPP2 C.S0015-B, v2, 4.5.16) + */ + public byte displayMode = DISPLAY_DEFAULT; + + /** + * First component of the Message status, that indicates if an error has occurred + * and whether the error is considered permanent or temporary. + * (See 3GPP2 C.S0015-B, v2, 4.5.21) + */ + public int errorClass = ERROR_UNDEFINED; + + /** + * Second component of the Message status, that indicates if an error has occurred + * and the cause of the error. + * (See 3GPP2 C.S0015-B, v2, 4.5.21) + */ + public int messageStatus = STATUS_UNDEFINED; + +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java new file mode 100644 index 000000000000..1643cab46b01 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2008 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.cdma.sms; + +import com.android.internal.telephony.SmsAddress; + +public class CdmaSmsAddress extends SmsAddress { + /** + * digit mode indicators + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + static public final int DIGIT_MODE_4BIT_DTMF = 0x00; + static public final int DIGIT_MODE_8BIT_CHAR = 0x01; + + /** + * number mode indicators + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + static public final int NUMBER_MODE_NOT_DATA_NETWORK = 0x00; + static public final int NUMBER_MODE_DATA_NETWORK = 0x01; + + /** + * number types for data networks + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + static public final int TON_UNKNOWN = 0x00; + static public final int TON_INTERNATIONAL_OR_IP = 0x01; + static public final int TON_NATIONAL_OR_EMAIL = 0x02; + static public final int TON_NETWORK = 0x03; + static public final int TON_SUBSCRIBER = 0x04; + static public final int TON_ALPHANUMERIC = 0x05; + static public final int TON_ABBREVIATED = 0x06; + static public final int TON_RESERVED = 0x07; + + /** + * maximum lengths for fields as defined in ril_cdma_sms.h + */ + static public final int SMS_ADDRESS_MAX = 36; + static public final int SMS_SUBADDRESS_MAX = 36; + + /** + * Supported numbering plan identification + * (See C.S005-D, v1.0, table 2.7.1.3.2.4-3) + */ + static public final int NUMBERING_PLAN_UNKNOWN = 0x0; + static public final int NUMBERING_PLAN_ISDN_TELEPHONY = 0x1; + //static protected final int NUMBERING_PLAN_DATA = 0x3; + //static protected final int NUMBERING_PLAN_TELEX = 0x4; + //static protected final int NUMBERING_PLAN_PRIVATE = 0x9; + + /** + * 1-bit value that indicates whether the address digits are 4-bit DTMF codes + * or 8-bit codes. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + public byte digitMode; + + /** + * 1-bit value that indicates whether the address type is a data network address or not. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + public byte numberMode; + + // use parent class member ton instead public byte numberType; + + /** + * 0 or 4-bit value that indicates which numbering plan identification is set. + * (See 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3) + */ + public byte numberPlan; + + /** + * This field shall be set to the number of address digits + * (See 3GPP2 C.S0015-B, v2, 3.4.3.3) + */ + public byte numberOfDigits; + + // use parent class member orig_bytes instead of public byte[] digits; + + // Constructor + public CdmaSmsAddress(){ + } + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java new file mode 100644 index 000000000000..6ba7463a3047 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java @@ -0,0 +1,371 @@ +/* + * Copyright (C) 2007 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.cdma.sms; + +import com.android.internal.telephony.SmsHeader; + +/* + * The SMSDataCoding class encodes and decodes CDMA SMS messages. + */ +public class SmsDataCoding { + private final static String TAG = "CDMA_SMS_JNI"; + + private final static int CDMA_SMS_WMS_MASK_BD_NULL = 0x00000000; + private final static int CDMA_SMS_WMS_MASK_BD_MSG_ID = 0x00000001; + private final static int CDMA_SMS_WMS_MASK_BD_USER_DATA = 0x00000002; +// private final static int CDMA_SMS_WMS_MASK_BD_USER_RESP = 0x00000004; + private final static int CDMA_SMS_WMS_MASK_BD_MC_TIME = 0x00000008; +// private final static int CDMA_SMS_WMS_MASK_BD_VALID_ABS = 0x00000010; +// private final static int CDMA_SMS_WMS_MASK_BD_VALID_REL = 0x00000020; +// private final static int CDMA_SMS_WMS_MASK_BD_DEFER_ABS = 0x00000040; +// private final static int CDMA_SMS_WMS_MASK_BD_DEFER_REL = 0x00000080; +// private final static int CDMA_SMS_WMS_MASK_BD_PRIORITY = 0x00000100; +// private final static int CDMA_SMS_WMS_MASK_BD_PRIVACY = 0x00000200; +// private final static int CDMA_SMS_WMS_MASK_BD_REPLY_OPTION = 0x00000400; + private final static int CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS = 0x00000800; +// private final static int CDMA_SMS_WMS_MASK_BD_ALERT = 0x00001000; +// private final static int CDMA_SMS_WMS_MASK_BD_LANGUAGE = 0x00002000; + private final static int CDMA_SMS_WMS_MASK_BD_CALLBACK = 0x00004000; + private final static int CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE = 0x00008000; +// private final static int CDMA_SMS_WMS_MASK_BD_SCPT_DATA = 0x00010000; +// private final static int CDMA_SMS_WMS_MASK_BD_SCPT_RESULT = 0x00020000; +// private final static int CDMA_SMS_WMS_MASK_BD_DEPOSIT_INDEX = 0x00040000; +// private final static int CDMA_SMS_WMS_MASK_BD_DELIVERY_STATUS = 0x00080000; +// private final static int CDMA_SMS_WMS_MASK_BD_IP_ADDRESS = 0x10000000; +// private final static int CDMA_SMS_WMS_MASK_BD_RSN_NO_NOTIFY = 0x20000000; +// private final static int CDMA_SMS_WMS_MASK_BD_OTHER = 0x40000000; + + /** + * Successful operation. + */ + private static final int JNI_CDMA_SMS_SUCCESS = 0; + + /** + * General failure. + */ + private static final int JNI_CDMA_SMS_FAILURE = 1; + + /** + * Data length is out of length. + */ + private static final int JNI_CDMA_SMS_DATA_LEN_OUT_OF_RANGE = 2; + + /** + * Class name unknown. + */ + private static final int JNI_CDMA_SMS_CLASS_UNKNOWN = 3; + + /** + * Field ID unknown. + */ + private static final int JNI_CDMA_SMS_FIELD_ID_UNKNOWN = 4; + + /** + * Memory allocation failed. + */ + private static final int JNI_CDMA_SMS_OUT_OF_MEMORY = 5; + + /** + * Encode SMS. + * + * @param bearerData an instance of BearerData. + * + * @return the encoded SMS as byte[]. + */ + public static byte[] encodeCdmaSms(BearerData bearerData) { + byte[] encodedSms; + + if( nativeCdmaSmsConstructClientBD() == JNI_CDMA_SMS_FAILURE){ + return null; + } + + // check bearer data and generate bit mask + generateBearerDataBitMask(bearerData); + encodedSms = startEncoding(bearerData); + + if( nativeCdmaSmsDestructClientBD() == JNI_CDMA_SMS_FAILURE){ + return null; + } + return encodedSms; + } + + /** + * Decode SMS. + * + * @param SmsData the encoded SMS. + * + * @return an instance of BearerData. + */ + public static BearerData decodeCdmaSms(byte[] SmsData) { + BearerData bearerData; + + if( nativeCdmaSmsConstructClientBD() == JNI_CDMA_SMS_FAILURE){ + return null; + } + + bearerData = startDecoding(SmsData); + + if( nativeCdmaSmsDestructClientBD() == JNI_CDMA_SMS_FAILURE){ + return null; + } + return bearerData; + } + + private static void generateBearerDataBitMask(BearerData bearerData) { + // initial + bearerData.mask = CDMA_SMS_WMS_MASK_BD_NULL; + + // check message type + if (bearerData.messageType != 0){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_MSG_ID; + } + + // check mUserData + if (bearerData.userData != null){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_USER_DATA; + } + + // check mTimeStamp + if (bearerData.timeStamp != null){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_MC_TIME; + } + + // check mNumberOfMessages + if (bearerData.numberOfMessages > 0){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS; + } + + // check mCallbackNumber + if(bearerData.callbackNumber != null){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_CALLBACK; + } + + // check DisplayMode + if(bearerData.displayMode == BearerData.DISPLAY_DEFAULT || + bearerData.displayMode == BearerData.DISPLAY_IMMEDIATE || + bearerData.displayMode == BearerData.DISPLAY_USER){ + bearerData.mask |= CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE; + } + } + + private static byte[] startEncoding(BearerData bearerData) { + int m_id; + byte[] m_data; + int dataLength; + byte[] encodedSms; + int nbrOfHeaders = 0; + + if( nativeCdmaSmsSetBearerDataPrimitives(bearerData) == JNI_CDMA_SMS_FAILURE){ + return null; + } + + if ((bearerData.mask & CDMA_SMS_WMS_MASK_BD_USER_DATA) == CDMA_SMS_WMS_MASK_BD_USER_DATA){ + if( nativeCdmaSmsSetUserData(bearerData.userData) == JNI_CDMA_SMS_FAILURE){ + return null; + } + + if (bearerData.userData.userDataHeader != null){ + nbrOfHeaders = bearerData.userData.userDataHeader.nbrOfHeaders; + } + + for (int i = 0; i < nbrOfHeaders; i++) { + m_id = bearerData.userData.userDataHeader.getElements().get(i).getID(); + m_data = bearerData.userData.userDataHeader.getElements().get(i).getData(); + dataLength = m_data.length; + if( nativeCdmaSmsSetUserDataHeader(m_id, m_data, dataLength, i) + == JNI_CDMA_SMS_FAILURE){ + return null; + } + } + } + + if ((bearerData.mask & CDMA_SMS_WMS_MASK_BD_CALLBACK) == CDMA_SMS_WMS_MASK_BD_CALLBACK) { + if( nativeCdmaSmsSetSmsAddress(bearerData.callbackNumber) == JNI_CDMA_SMS_FAILURE){ + return null; + } + } + + /* call native method to encode SMS */ + encodedSms = nativeCdmaSmsEncodeSms(); + + return encodedSms; + } + + private static BearerData startDecoding(byte[] SmsData) { + BearerData bData = new BearerData(); + byte[] udhData; + + /* call native method to decode SMS */ + if( nativeCdmaSmsDecodeSms(SmsData) == JNI_CDMA_SMS_FAILURE){ + return null; + } + + if( nativeCdmaSmsGetBearerDataPrimitives(bData) == JNI_CDMA_SMS_FAILURE){ + return null; + } + + if ((bData.mask & CDMA_SMS_WMS_MASK_BD_USER_DATA) == CDMA_SMS_WMS_MASK_BD_USER_DATA) { + bData.userData = new UserData(); + if( nativeCdmaSmsGetUserData(bData.userData) == JNI_CDMA_SMS_FAILURE){ + return null; + } + + udhData = nativeCdmaSmsGetUserDataHeader(); + if (udhData != null) { + bData.userData.userDataHeader = SmsHeader.parse(udhData); + } + } + + if ((bData.mask & CDMA_SMS_WMS_MASK_BD_CALLBACK) == CDMA_SMS_WMS_MASK_BD_CALLBACK) { + bData.callbackNumber = new CdmaSmsAddress(); + if( nativeCdmaSmsGetSmsAddress(bData.callbackNumber) == JNI_CDMA_SMS_FAILURE){ + return null; + } + } + + return bData; + } + + // native methods + + /** + * native method: Allocate memory for clientBD structure + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsConstructClientBD(); + + /** + * native method: Free memory used for clientBD structure + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsDestructClientBD(); + + /** + * native method: fill clientBD structure with bearerData primitives + * + * @param bearerData an instance of BearerData. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsSetBearerDataPrimitives(BearerData bearerData); + + /** + * native method: fill bearerData primitives with clientBD variables + * + * @param bearerData an instance of BearerData. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsGetBearerDataPrimitives(BearerData bearerData); + + /** + * native method: fill clientBD.user_data with UserData primitives + * + * @param userData an instance of UserData. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsSetUserData(UserData userData); + + /** + * native method: fill UserData primitives with clientBD.user_data + * + * @param userData an instance of UserData. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsGetUserData(UserData userData); + + /** + * native method: fill clientBD.user_data.headers with UserDataHeader primitives + * + * @param ID ID of element. + * @param data element data. + * @param dataLength data length + * @param index index of element + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsSetUserDataHeader( + int ID, byte[] data, int dataLength, int index); + + /** + * native method: fill UserDataHeader primitives with clientBD.user_data.headers + * + * @return user data headers + */ + private static native byte[] nativeCdmaSmsGetUserDataHeader(); + + /** + * native method: fill clientBD.callback with SmsAddress primitives + * + * @param smsAddr an instance of SmsAddress. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsSetSmsAddress(CdmaSmsAddress smsAddr); + + /** + * native method: fill SmsAddress primitives with clientBD.callback + * + * @param smsAddr an instance of SmsAddress. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsGetSmsAddress(CdmaSmsAddress smsAddr); + + /** + * native method: call encoding functions and get encoded SMS + * + * @return the encoded SMS + */ + private static native byte[] nativeCdmaSmsEncodeSms(); + + /** + * native method: call decode functions + * + * @param encodedSMS encoded SMS. + * + * @return #JNI_CDMA_SMS_SUCCESS if succeed. + * #JNI_CDMA_SMS_FAILURE if fail. + */ + private static native int nativeCdmaSmsDecodeSms(byte[] encodedSMS); + + /** + * Load the shared library to link the native methods. + */ + static { + try { + System.loadLibrary("cdma_sms_jni"); + } + catch (UnsatisfiedLinkError ule) { + System.err.println("WARNING: Could not load cdma_sms_jni.so"); + } + } +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java new file mode 100644 index 000000000000..f80e8c091b7d --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2008 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.cdma.sms; + + +public final class SmsEnvelope{ + /** + * Message Types + * (See 3GPP2 C.S0015-B 3.4.1) + */ + static public final int MESSAGE_TYPE_POINT_TO_POINT = 0x00; + static public final int MESSAGE_TYPE_BROADCAST = 0x01; + static public final int MESSAGE_TYPE_ACKNOWLEDGE = 0x02; + + /** + * Supported Teleservices + * (See 3GPP2 N.S0005 and TIA-41) + */ + static public final int TELESERVICE_NOT_SET = 0x0000; + static public final int TELESERVICE_WMT = 0x1002; + static public final int TELESERVICE_VMN = 0x1003; + static public final int TELESERVICE_WAP = 0x1004; + static public final int TELESERVICE_WEMT = 0x1005; + + // ServiceCategories for Cell Broadcast, see 3GPP2 C.R1001 table 9.3.1-1 + //static public final int SERVICECATEGORY_EMERGENCY = 0x0010; + //... + + /** + * maximum lengths for fields as defined in ril_cdma_sms.h + */ + static public final int SMS_BEARER_DATA_MAX = 255; + + /** + * Provides the type of a SMS message like point to point, broadcast or acknowledge + */ + public int messageType; + + /** + * The 16-bit Teleservice parameter identifies which upper layer service access point is sending + * or receiving the message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.1) + */ + public int teleService = TELESERVICE_NOT_SET; + + /** + * The 16-bit service category parameter identifies the type of service provided + * by the SMS message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.2) + */ + public int serviceCategory; + + /** + * The origination address identifies the originator of the SMS message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.4) + */ + public CdmaSmsAddress origAddress; + + /** + * The destination address identifies the target of the SMS message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.4) + */ + public CdmaSmsAddress destAddress; + + /** + * The 6-bit bearer reply parameter is used to request the return of a + * SMS Acknowledge Message. + * (See 3GPP2 C.S0015-B, v2, 3.4.3.5) + */ + public int bearerReply; + + /** + * Cause Code values: + * The cause code parameters are an indication whether an SMS error has occurred and if so, + * whether the condition is considered temporary or permanent. + * ReplySeqNo 6-bit value, + * ErrorClass 2-bit value, + * CauseCode 0-bit or 8-bit value + * (See 3GPP2 C.S0015-B, v2, 3.4.3.6) + */ + public byte replySeqNo; + public byte errorClass; + public byte causeCode; + + /** + * encoded bearer data + * (See 3GPP2 C.S0015-B, v2, 3.4.3.7) + */ + public byte[] bearerData; + + public SmsEnvelope() { + // nothing to see here + } + +} + diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java new file mode 100644 index 000000000000..e7614694eae7 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2008 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.cdma.sms; + +import com.android.internal.telephony.SmsHeader; + +public class UserData{ + + /** + * Supported user data encoding types + * (See 3GPP2 C.R1001-F, v1.0, table 9.1-1) + */ + public static final int UD_ENCODING_OCTET = 0x00; + //public static final int UD_ENCODING_EXTENDED_PROTOCOL = 0x01; + public static final int UD_ENCODING_7BIT_ASCII = 0x02; + public static final int UD_ENCODING_IA5 = 0x03; + public static final int UD_ENCODING_UNICODE_16 = 0x04; + //public static final int UD_ENCODING_SHIFT_JIS = 0x05; + //public static final int UD_ENCODING_KOREAN = 0x06; + //public static final int UD_ENCODING_LATIN_HEBREW = 0x07; + //public static final int UD_ENCODING_LATIN = 0x08; + public static final int UD_ENCODING_GSM_7BIT_ALPHABET = 0x09; + //public static final int UD_ENCODING_GSM_DCS = 0x0A; + + /** + * Contains the data header of the user data + */ + public SmsHeader userDataHeader; + + /** + * Contains the data encoding type for the SMS message + */ + public int userDataEncoding; + + // needed when encoding is IS91 or DCS (not supported yet): + //public int messageType; + + /** + * Number of invalid bits in the last byte of data. + */ + public int paddingBits; + + /** + * Contains the user data of a SMS message + * (See 3GPP2 C.S0015-B, v2, 4.5.2) + */ + public byte[] userData; + +} diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/package.html b/telephony/java/com/android/internal/telephony/cdma/sms/package.html new file mode 100644 index 000000000000..48e10340cb86 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/cdma/sms/package.html @@ -0,0 +1,6 @@ +<HTML> +<BODY> +Provides CDMA-specific features for text/data/PDU SMS messages +@hide +</BODY> +</HTML> diff --git a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java index 2f9141191f0e..4b1c1e4c143a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java +++ b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java @@ -16,7 +16,8 @@ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; +import com.android.internal.telephony.Phone; + /** * This class represents a apn setting for create PDP link */ diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java index fe2739265b59..c9e3496bb738 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java +++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java @@ -16,9 +16,6 @@ package com.android.internal.telephony.gsm; -import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; -import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; @@ -32,27 +29,33 @@ import android.os.Registrant; import android.os.RegistrantList; import android.os.SystemProperties; import android.preference.PreferenceManager; +import android.provider.Settings; import android.provider.Telephony; -import com.android.internal.telephony.*; -import com.android.internal.telephony.gsm.stk.Service; - -import com.android.internal.telephony.test.SimulatedRadioControl; -import android.text.TextUtils; -import android.util.Log; -import static com.android.internal.telephony.CommandsInterface.*; -import static com.android.internal.telephony.TelephonyProperties.*; -import android.net.Uri; -import android.telephony.PhoneNumberUtils; import android.telephony.CellLocation; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; import android.text.TextUtils; import android.util.Log; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE; +import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY; +import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL; +import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION; + import com.android.internal.telephony.CallForwardInfo; import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataConnectionTracker; import com.android.internal.telephony.IccCard; import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccPhoneBookInterfaceManager; @@ -61,6 +64,7 @@ import com.android.internal.telephony.MmiCode; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneBase; import com.android.internal.telephony.PhoneNotifier; +import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.PhoneSubInfo; import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.gsm.stk.Service; @@ -81,10 +85,8 @@ public class GSMPhone extends PhoneBase { // from this file will go into the radio log rather than the main // log. (Use "adb logcat -b radio" to see them.) static final String LOG_TAG = "GSM"; - private static final boolean LOCAL_DEBUG = false; + private static final boolean LOCAL_DEBUG = true; - // Key used to read/write "disable data connection on boot" pref (used for testing) - public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key"; // Key used to read/write current ciphering state public static final String CIPHERING_KEY = "ciphering_key"; @@ -92,12 +94,12 @@ public class GSMPhone extends PhoneBase { GsmCallTracker mCT; GsmServiceStateTracker mSST; - SMSDispatcher mSMS; - DataConnectionTracker mDataConnection; + GsmSMSDispatcher mSMS; + GsmDataConnectionTracker mDataConnection; SIMRecords mSIMRecords; SimCard mSimCard; Service mStkService; - //MyHandler h; + MyHandler h; ArrayList <GsmMmiCode> mPendingMMIs = new ArrayList<GsmMmiCode>(); SimPhoneBookInterfaceManager mSimPhoneBookIntManager; SimSmsInterfaceManager mSimSmsIntManager; @@ -129,7 +131,6 @@ public class GSMPhone extends PhoneBase { public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) { super(notifier, context, unitTestMode); - h = new MyHandler(); mCM = ci; @@ -140,10 +141,10 @@ public class GSMPhone extends PhoneBase { mCM.setPhoneType(RILConstants.GSM_PHONE); mCT = new GsmCallTracker(this); mSST = new GsmServiceStateTracker (this); - mSMS = new SMSDispatcher(this); + mSMS = new GsmSMSDispatcher(this); mIccFileHandler = new SIMFileHandler(this); mSIMRecords = new SIMRecords(this); - mDataConnection = new DataConnectionTracker (this); + mDataConnection = new GsmDataConnectionTracker (this); mSimCard = new SimCard(this); if (!unitTestMode) { mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this); @@ -152,11 +153,10 @@ public class GSMPhone extends PhoneBase { } mStkService = Service.getInstance(mCM, mSIMRecords, mContext, (SIMFileHandler)mIccFileHandler, mSimCard); - + mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null); mSIMRecords.registerForRecordsLoaded(h, EVENT_SIM_RECORDS_LOADED, null); - mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, - null); + mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); mCM.registerForOn(h, EVENT_RADIO_ON, null); mCM.setOnUSSD(h, EVENT_USSD, null); mCM.setOnSuppServiceNotification(h, EVENT_SSN, null); @@ -182,7 +182,7 @@ public class GSMPhone extends PhoneBase { mCM.resetRadio(null); sock.close(); } catch (IOException ex) { - Log.w(LOG_TAG, + Log.w(LOG_TAG, "Exception accepting socket", ex); } } @@ -196,11 +196,63 @@ public class GSMPhone extends PhoneBase { Log.w(LOG_TAG, "Failure to open com.android.internal.telephony.debug socket", ex); } } + + //Change the system setting + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.CURRENT_ACTIVE_PHONE, RILConstants.GSM_PHONE); + } + + public void dispose() { + synchronized(PhoneProxy.lockForRadioTechnologyChange) { + //Unregister from all former registered events + mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE + mSIMRecords.unregisterForRecordsLoaded(h); //EVENT_SIM_RECORDS_LOADED + mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE + mCM.unregisterForOn(h); //EVENT_RADIO_ON + mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK + mCM.unSetOnUSSD(h); + mCM.unSetOnSuppServiceNotification(h); + mCM.unSetOnCallRing(h); + + mPendingMMIs.clear(); + + //Force all referenced classes to unregister their former registered events + mStkService.dispose(); + mCT.dispose(); + mDataConnection.dispose(); + mSST.dispose(); + mIccFileHandler.dispose(); // instance of SimFileHandler + mSIMRecords.dispose(); + mSimCard.dispose(); + mSimPhoneBookIntManager.dispose(); + mSimSmsIntManager.dispose(); + mSubInfo.dispose(); + } + } + + public void removeReferences() { + this.mSimulatedRadioControl = null; + this.mStkService = null; + this.mSimPhoneBookIntManager = null; + this.mSimSmsIntManager = null; + this.mSMS = null; + this.mSubInfo = null; + this.mSIMRecords = null; + this.mIccFileHandler = null; + this.mSimCard = null; + this.mDataConnection = null; + this.mCT = null; + this.mSST = null; + } + + protected void finalize() { + if(LOCAL_DEBUG) Log.d(LOG_TAG, "GSMPhone finalized"); } - + + //***** Overridden from Phone - public ServiceState + public ServiceState getServiceState() { return mSST.ss; } @@ -209,7 +261,7 @@ public class GSMPhone extends PhoneBase { return mSST.cellLoc; } - public Phone.State + public Phone.State getState() { return mCT.state; } @@ -264,25 +316,25 @@ public class GSMPhone extends PhoneBase { // but no data will flow ret = DataState.DISCONNECTED; } else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */ - switch (mDataConnection.state) { - case FAILED: - case IDLE: - ret = DataState.DISCONNECTED; - break; + switch (mDataConnection.getState()) { + case FAILED: + case IDLE: + ret = DataState.DISCONNECTED; + break; - case CONNECTED: - if ( mCT.state != Phone.State.IDLE - && !mSST.isConcurrentVoiceAndData()) - ret = DataState.SUSPENDED; - else - ret = DataState.CONNECTED; - break; - - case INITING: - case CONNECTING: - case SCANNING: - ret = DataState.CONNECTING; - break; + case CONNECTED: + if ( mCT.state != Phone.State.IDLE + && !mSST.isConcurrentVoiceAndData()) + ret = DataState.SUSPENDED; + else + ret = DataState.CONNECTED; + break; + + case INITING: + case CONNECTING: + case SCANNING: + ret = DataState.CONNECTING; + break; } } @@ -293,19 +345,18 @@ public class GSMPhone extends PhoneBase { DataActivityState ret = DataActivityState.NONE; if (mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE) { - switch (mDataConnection.activity) { - - case DATAIN: - ret = DataActivityState.DATAIN; - break; + switch (mDataConnection.getActivity()) { + case DATAIN: + ret = DataActivityState.DATAIN; + break; - case DATAOUT: - ret = DataActivityState.DATAOUT; - break; + case DATAOUT: + ret = DataActivityState.DATAOUT; + break; - case DATAINANDOUT: - ret = DataActivityState.DATAINANDOUT; - break; + case DATAINANDOUT: + ret = DataActivityState.DATAINANDOUT; + break; } } @@ -338,11 +389,11 @@ public class GSMPhone extends PhoneBase { /** * Notifiy registrants of a RING event. */ - void notifyIncomingRing() { + void notifyIncomingRing() { AsyncResult ar = new AsyncResult(null, this, null); mIncomingRingRegistrants.notifyRegistrants(ar); } - + /*package*/ void notifyDisconnect(Connection cn) { mDisconnectRegistrants.notifyResult(cn); @@ -351,7 +402,7 @@ public class GSMPhone extends PhoneBase { void notifyUnknownConnection() { mUnknownConnectionRegistrants.notifyResult(this); } - + void notifySuppServiceFailed(SuppService code) { mSuppServiceFailedRegistrants.notifyResult(code); } @@ -372,32 +423,22 @@ public class GSMPhone extends PhoneBase { } /*package*/ void - notifyDataConnection(String reason) { - mNotifier.notifyDataConnection(this, reason); - } - - /*package*/ void notifyDataConnectionFailed(String reason) { mNotifier.notifyDataConnectionFailed(this, reason); } /*package*/ void - notifyDataActivity() { - mNotifier.notifyDataActivity(this); - } - - /*package*/ void updateMessageWaitingIndicator(boolean mwi) { // this also calls notifyMessageWaitingIndicator() mSIMRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0); } - /*package*/ void + public void notifyMessageWaitingIndicator() { mNotifier.notifyMessageWaitingChanged(this); } - /*package*/ void + public void notifyCallForwardingIndicator() { mNotifier.notifyCallForwardingChanged(this); } @@ -406,7 +447,7 @@ public class GSMPhone extends PhoneBase { /** * {@inheritDoc} */ - protected final void + public final void setSystemProperty(String property, String value) { super.setSystemProperty(property, value); } @@ -422,12 +463,12 @@ public class GSMPhone extends PhoneBase { if (mSsnRegistrants.size() == 0) mCM.setSuppServiceNotifications(false, null); } - public void + public void acceptCall() throws CallStateException { mCT.acceptCall(); } - public void + public void rejectCall() throws CallStateException { mCT.rejectCall(); } @@ -437,7 +478,6 @@ public class GSMPhone extends PhoneBase { mCT.switchWaitingOrHoldingAndActive(); } - public boolean canConference() { return mCT.canConference(); } @@ -451,7 +491,6 @@ public class GSMPhone extends PhoneBase { } public void clearDisconnected() { - mCT.clearDisconnected(); } @@ -468,12 +507,12 @@ public class GSMPhone extends PhoneBase { return mCT.foregroundCall; } - public GsmCall + public GsmCall getBackgroundCall() { return mCT.backgroundCall; } - public GsmCall + public GsmCall getRingingCall() { return mCT.ringingCall; } @@ -559,7 +598,7 @@ public class GSMPhone extends PhoneBase { char ch = dialString.charAt(1); int callIndex = ch - '0'; GsmConnection conn = mCT.getConnectionByIndex(call, callIndex); - + // gsm index starts at 1, up to 5 connections in a call, if (conn != null && callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 2: separate call "+ @@ -704,7 +743,7 @@ public class GSMPhone extends PhoneBase { if (handleInCallMmiCommands(newDialString)) { return null; } - + GsmMmiCode mmi = GsmMmiCode.newFromDialString(newDialString, this); if (LOCAL_DEBUG) Log.d(LOG_TAG, "dialing w/ mmi '" + mmi + "'..."); @@ -725,15 +764,15 @@ public class GSMPhone extends PhoneBase { public boolean handlePinMmi(String dialString) { GsmMmiCode mmi = GsmMmiCode.newFromDialString(dialString, this); - + if (mmi != null && mmi.isPinCommand()) { mPendingMMIs.add(mmi); mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); mmi.processCode(); return true; } - - return false; + + return false; } public void sendUssdResponse(String ussdMessge) { @@ -742,11 +781,11 @@ public class GSMPhone extends PhoneBase { mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null)); mmi.sendUssd(ussdMessge); } - + public void sendDtmf(char c) { if (!PhoneNumberUtils.is12Key(c)) { - Log.e(LOG_TAG, + Log.e(LOG_TAG, "sendDtmf called with invalid character '" + c + "'"); } else { if (mCT.state == Phone.State.OFFHOOK) { @@ -790,7 +829,7 @@ public class GSMPhone extends PhoneBase { com.android.internal.R.string.defaultVoiceMailAlphaTag).toString(); } - return ret; + return ret; } public String getDeviceId() { @@ -805,7 +844,7 @@ public class GSMPhone extends PhoneBase { Log.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method"); return "0"; } - + public String getMeid() { Log.e(LOG_TAG, "[GSMPhone] getMeid() is a CDMA method"); return "0"; @@ -845,7 +884,37 @@ public class GSMPhone extends PhoneBase { Message onComplete) { mSIMRecords.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete); } - + + private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) { + switch (commandInterfaceCFReason) { + case CF_REASON_UNCONDITIONAL: + case CF_REASON_BUSY: + case CF_REASON_NO_REPLY: + case CF_REASON_NOT_REACHABLE: + case CF_REASON_ALL: + case CF_REASON_ALL_CONDITIONAL: + return true; + default: + return false; + } + } + + private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) { + switch (commandInterfaceCFAction) { + case CF_ACTION_DISABLE: + case CF_ACTION_ENABLE: + case CF_ACTION_REGISTRATION: + case CF_ACTION_ERASURE: + return true; + default: + return false; + } + } + + protected boolean isCfEnable(int action) { + return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION); + } + public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) { if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "requesting call forwarding query."); @@ -859,11 +928,35 @@ public class GSMPhone extends PhoneBase { } } + public void setCallForwardingOption(int commandInterfaceCFAction, + int commandInterfaceCFReason, + String dialingNumber, + int timerSeconds, + Message onComplete) { + if ( (isValidCommandInterfaceCFAction(commandInterfaceCFAction)) && + (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) { + + Message resp; + if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) { + resp = h.obtainMessage(EVENT_SET_CALL_FORWARD_DONE, + isCfEnable(commandInterfaceCFAction) ? 1 : 0, 0, onComplete); + } else { + resp = onComplete; + } + mCM.setCallForward(commandInterfaceCFAction, + commandInterfaceCFReason, + CommandsInterface.SERVICE_CLASS_VOICE, + dialingNumber, + timerSeconds, + resp); + } + } + public void getOutgoingCallerIdDisplay(Message onComplete) { mCM.getCLIR(onComplete); } - - public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, + + public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) { mCM.setCLIR(commandInterfaceCLIRMode, h.obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete)); @@ -872,13 +965,13 @@ public class GSMPhone extends PhoneBase { public void getCallWaiting(Message onComplete) { mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete); } - + public void setCallWaiting(boolean enable, Message onComplete) { mCM.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete); } - + public boolean - getSimRecordsLoaded() { + getIccRecordsLoaded() { return mSIMRecords.getRecordsLoaded(); } @@ -886,86 +979,97 @@ public class GSMPhone extends PhoneBase { return mSimCard; } - public void + public void getAvailableNetworks(Message response) { mCM.getAvailableNetworks(response); } /** - * Small container class used to hold information relevant to + * Small container class used to hold information relevant to * the carrier selection process. operatorNumeric can be "" - * if we are looking for automatic selection. + * if we are looking for automatic selection. */ private static class NetworkSelectMessage { public Message message; public String operatorNumeric; } - - public void + + public void setNetworkSelectionModeAutomatic(Message response) { // wrap the response message in our own message along with - // an empty string (to indicate automatic selection) for the + // an empty string (to indicate automatic selection) for the // operator's id. NetworkSelectMessage nsm = new NetworkSelectMessage(); nsm.message = response; nsm.operatorNumeric = ""; - + // get the message Message msg = h.obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm); - if (LOCAL_DEBUG) + if (LOCAL_DEBUG) Log.d(LOG_TAG, "wrapping and sending message to connect automatically"); mCM.setNetworkSelectionModeAutomatic(msg); } - public void + public void selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network, - Message response) { + Message response) { // wrap the response message in our own message along with // the operator's id. NetworkSelectMessage nsm = new NetworkSelectMessage(); nsm.message = response; nsm.operatorNumeric = network.operatorNumeric; - + // get the message Message msg = h.obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm); mCM.setNetworkSelectionModeManual(network.operatorNumeric, msg); } - + public void getNeighboringCids(Message response) { mCM.getNeighboringCids(response); } - + public void setOnPostDialCharacter(Handler h, int what, Object obj) { mPostDialHandler = new Registrant(h, what, obj); } - public void setMute(boolean muted) { mCT.setMute(muted); } - + public boolean getMute() { return mCT.getMute(); } - - public void invokeOemRilRequestRaw(byte[] data, Message response) { - mCM.invokeOemRilRequestRaw(data, response); + /** + * @deprecated + */ + public void getPdpContextList(Message response) { + getDataCallList(response); } - public void invokeOemRilRequestStrings(String[] strings, Message response) { - mCM.invokeOemRilRequestStrings(strings, response); + public void getDataCallList(Message response) { + mCM.getDataCallList(response); } - public void getPdpContextList(Message response) { - mCM.getPDPContextList(response); + /** + * @deprecated + */ + public List<PdpConnection> getCurrentPdpList() { + ArrayList<DataConnection> connections = new ArrayList<DataConnection>(); + ArrayList<PdpConnection> pdp_list = new ArrayList<PdpConnection>(); + + for(int n = 0; n < connections.size(); n++) { + pdp_list.add((PdpConnection) connections.get(n)); + } + + return pdp_list; } - public List<PdpConnection> getCurrentPdpList () { - return mDataConnection.getAllPdps(); + public List<DataConnection> getCurrentDataConnectionList () { + return mDataConnection.getAllDataConnections(); } public void updateServiceLocation(Message response) { @@ -980,14 +1084,6 @@ public class GSMPhone extends PhoneBase { mSST.disableLocationUpdates(); } - public void setBandMode(int bandMode, Message response) { - mCM.setBandMode(bandMode, response); - } - - public void queryAvailableBandMode(Message response) { - mCM.queryAvailableBandMode(response); - } - public boolean getDataRoamingEnabled() { return mDataConnection.getDataOnRoamingEnabled(); } @@ -1056,7 +1152,7 @@ public class GSMPhone extends PhoneBase { */ /*package*/ void onMMIDone(GsmMmiCode mmi) { - /* Only notify complete if it's on the pending list. + /* Only notify complete if it's on the pending list. * Otherwise, it's already been handled (eg, previously canceled). * The exception is cancellation of an incoming USSD-REQUEST, which is * not on the list. @@ -1068,7 +1164,7 @@ public class GSMPhone extends PhoneBase { } - private void + private void onNetworkInitiatedUssd(GsmMmiCode mmi) { mMmiCompleteRegistrants.notifyRegistrants( new AsyncResult(null, mmi, null)); @@ -1080,14 +1176,14 @@ public class GSMPhone extends PhoneBase { onIncomingUSSD (int ussdMode, String ussdMessage) { boolean isUssdError; boolean isUssdRequest; - - isUssdRequest + + isUssdRequest = (ussdMode == CommandsInterface.USSD_MODE_REQUEST); - isUssdError + isUssdError = (ussdMode != CommandsInterface.USSD_MODE_NOTIFY && ussdMode != CommandsInterface.USSD_MODE_REQUEST); - + // See comments in GsmMmiCode.java // USSD requests aren't finished until one // of these two events happen @@ -1114,7 +1210,7 @@ public class GSMPhone extends PhoneBase { // also, discard if there is no message to present if (!isUssdError && ussdMessage != null) { GsmMmiCode mmi; - mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage, + mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage, isUssdRequest, GSMPhone.this); onNetworkInitiatedUssd(mmi); @@ -1122,6 +1218,17 @@ public class GSMPhone extends PhoneBase { } } + /** + * Make sure the network knows our preferred setting. + */ + protected void syncClirSetting() { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + int clirSetting = sp.getInt(CLIR_KEY, -1); + if (clirSetting >= 0) { + mCM.setCLIR(clirSetting, null); + } + } + //***** Inner Classes class MyHandler extends Handler { @@ -1197,11 +1304,10 @@ public class GSMPhone extends PhoneBase { if (ar.exception != null) { break; } - + mImeiSv = (String)ar.result; break; - case EVENT_USSD: ar = (AsyncResult)msg.obj; @@ -1216,7 +1322,7 @@ public class GSMPhone extends PhoneBase { } break; - case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: + case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: // Some MMI requests (eg USSD) are not completed // within the course of a CommandsInterface request // If the radio shuts off or resets while one of these @@ -1225,10 +1331,10 @@ public class GSMPhone extends PhoneBase { for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) { if (mPendingMMIs.get(i).isPendingUSSD()) { mPendingMMIs.get(i).onUssdFinishedError(); - } + } } break; - + case EVENT_SSN: ar = (AsyncResult)msg.obj; SuppServiceNotification not = (SuppServiceNotification) ar.result; @@ -1258,15 +1364,15 @@ public class GSMPhone extends PhoneBase { onComplete.sendToTarget(); } break; - + case EVENT_CALL_RING: ar = (AsyncResult)msg.obj; if (ar.exception == null) { notifyIncomingRing(); } break; - - // handle the select network completion callbacks. + + // handle the select network completion callbacks. case EVENT_SET_NETWORK_MANUAL_COMPLETE: case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE: handleSetSelectNetwork((AsyncResult) msg.obj); @@ -1286,34 +1392,34 @@ public class GSMPhone extends PhoneBase { } } } - + /** * Used to track the settings upon completion of the network change. */ private void handleSetSelectNetwork(AsyncResult ar) { - // look for our wrapper within the asyncresult, skip the rest if it - // is null. + // look for our wrapper within the asyncresult, skip the rest if it + // is null. if (!(ar.userObj instanceof NetworkSelectMessage)) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "unexpected result from user object."); return; } - + NetworkSelectMessage nsm = (NetworkSelectMessage) ar.userObj; - + // found the object, now we send off the message we had originally - // attached to the request. + // attached to the request. if (nsm.message != null) { if (LOCAL_DEBUG) Log.d(LOG_TAG, "sending original message to recipient"); AsyncResult.forMessage(nsm.message, ar.result, ar.exception); nsm.message.sendToTarget(); } - + // open the shared preferences editor, and write the value. // nsm.operatorNumeric is "" if we're in automatic.selection. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); SharedPreferences.Editor editor = sp.edit(); editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric); - + // commit and log the result. if (! editor.commit()) { Log.e(LOG_TAG, "failed to commit network selection preference"); @@ -1321,6 +1427,22 @@ public class GSMPhone extends PhoneBase { } + /** + * Saves CLIR setting so that we can re-apply it as necessary + * (in case the RIL resets it across reboots). + */ + public void saveClirSetting(int commandInterfaceCLIRMode) { + // open the shared preferences editor, and write the value. + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); + SharedPreferences.Editor editor = sp.edit(); + editor.putInt(CLIR_KEY, commandInterfaceCLIRMode); + + // commit and log the result. + if (! editor.commit()) { + Log.e(LOG_TAG, "failed to commit CLIR preference"); + } + } + private void handleCfuQueryResult(CallForwardInfo[] infos) { if (infos == null || infos.length == 0) { // Assume the default is not active @@ -1342,7 +1464,7 @@ public class GSMPhone extends PhoneBase { * simulates various data connection states. This messes with * DataConnectionTracker's internal states, but doesn't actually change * the underlying radio connection states. - * + * * @param state Phone.DataState enum. */ public void simulateDataConnection(Phone.DataState state) { @@ -1390,16 +1512,29 @@ public class GSMPhone extends PhoneBase { /** * {@inheritDoc} - */ - protected Handler getHandler(){ + */ + public Handler getHandler(){ return h; } - + /** * {@inheritDoc} - */ - protected IccFileHandler getIccFileHandler(){ - return this.mIccFileHandler; + */ + public IccFileHandler getIccFileHandler(){ + return this.mIccFileHandler; } + + public void activateCellBroadcastSms(int activate, Message response) { + Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + } + + public void getCellBroadcastSmsConfig(Message response) { + Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + } + + public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){ + Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM."); + } + } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCall.java b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java index 85529f581d12..1fe22bb06c43 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmCall.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java @@ -16,7 +16,12 @@ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; +import com.android.internal.telephony.Call; +import com.android.internal.telephony.CallStateException; +import com.android.internal.telephony.Connection; +import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.Phone; + import java.util.ArrayList; import java.util.List; @@ -29,7 +34,7 @@ class GsmCall extends Call { /*package*/ ArrayList<Connection> connections = new ArrayList<Connection>(); /*package*/ GsmCallTracker owner; - + /***************************** Class Methods *****************************/ static State @@ -44,7 +49,7 @@ class GsmCall extends Call { default: throw new RuntimeException ("illegal call state:" + dcState); } } - + /****************************** Constructors *****************************/ /*package*/ @@ -52,6 +57,9 @@ class GsmCall extends Call { this.owner = owner; } + public void dispose() { + } + /************************** Overridden from Call *************************/ public List<Connection> @@ -60,7 +68,7 @@ class GsmCall extends Call { return connections; } - public Phone + public Phone getPhone() { //TODO return null; @@ -75,7 +83,7 @@ class GsmCall extends Call { * background call exists, the background call will be resumed * because an AT+CHLD=1 will be sent */ - public void + public void hangup() throws CallStateException { owner.hangup(this); } @@ -110,20 +118,20 @@ class GsmCall extends Call { /* If only disconnected connections remain, we are disconnected*/ boolean hasOnlyDisconnectedConnections = true; - + for (int i = 0, s = connections.size() ; i < s; i ++) { - if (connections.get(i).getState() + if (connections.get(i).getState() != State.DISCONNECTED ) { hasOnlyDisconnectedConnections = false; break; - } + } } if (hasOnlyDisconnectedConnections) { - state = State.DISCONNECTED; + state = State.DISCONNECTED; } - } + } } @@ -140,9 +148,9 @@ class GsmCall extends Call { update (GsmConnection conn, DriverCall dc) { State newState; boolean changed = false; - + newState = stateFromDCState(dc.state); - + if (newState != state) { state = newState; changed = true; @@ -163,7 +171,7 @@ class GsmCall extends Call { //***** Called from GsmCallTracker - /** + /** * Called when this Call is being hung up locally (eg, user pressed "end") * Note that at this point, the hangup request has been dispatched to the radio * but no response has yet been received so update() has not yet been called @@ -178,7 +186,7 @@ class GsmCall extends Call { cn.onHangupLocal(); } } - + /** * Called when it's time to clean up disconnected Connection objects */ @@ -186,11 +194,11 @@ class GsmCall extends Call { clearDisconnected() { for (int i = connections.size() - 1 ; i >= 0 ; i--) { GsmConnection cn = (GsmConnection)connections.get(i); - + if (cn.getState() == State.DISCONNECTED) { connections.remove(i); } - } + } if (connections.size() == 0) { state = State.IDLE; diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java index 4a8e88a050bc..9f018ad0a6ea 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java @@ -16,24 +16,23 @@ package com.android.internal.telephony.gsm; +import android.os.*; +import android.telephony.PhoneNumberUtils; +import android.telephony.ServiceState; +import android.util.Log; + import com.android.internal.telephony.CallStateException; import com.android.internal.telephony.CallTracker; import com.android.internal.telephony.Connection; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.gsm.CallFailCause; -import com.android.internal.telephony.gsm.CommandException; import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.gsm.CallFailCause; import com.android.internal.telephony.gsm.GsmCall; import com.android.internal.telephony.gsm.GsmConnection; import com.android.internal.telephony.gsm.GSMPhone; +import com.android.internal.telephony.Phone; import com.android.internal.telephony.*; -import android.os.*; -import android.util.Log; -import android.telephony.PhoneNumberUtils; -import android.telephony.ServiceState; - import java.util.List; import java.util.ArrayList; @@ -45,24 +44,23 @@ public final class GsmCallTracker extends CallTracker { private static final boolean REPEAT_POLLING = false; private static final boolean DBG_POLL = false; - + //***** Constants static final int MAX_CONNECTIONS = 7; // only 7 connections allowed in GSM static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call //***** Instance Variables - GsmConnection connections[] = new GsmConnection[MAX_CONNECTIONS]; RegistrantList voiceCallEndedRegistrants = new RegistrantList(); RegistrantList voiceCallStartedRegistrants = new RegistrantList(); // connections dropped durin last poll - ArrayList<GsmConnection> droppedDuringPoll - = new ArrayList<GsmConnection>(MAX_CONNECTIONS); + ArrayList<GsmConnection> droppedDuringPoll + = new ArrayList<GsmConnection>(MAX_CONNECTIONS); - GsmCall ringingCall = new GsmCall(this); + GsmCall ringingCall = new GsmCall(this); // A call that is ringing or (call) waiting GsmCall foregroundCall = new GsmCall(this); GsmCall backgroundCall = new GsmCall(this); @@ -93,6 +91,33 @@ public final class GsmCallTracker extends CallTracker { cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null); } + public void dispose() { + //Unregister for all events + cm.unregisterForCallStateChanged(this); + cm.unregisterForOn(this); + cm.unregisterForNotAvailable(this); + + for(GsmConnection c : connections) { + try { + if(c != null) hangup(c); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + } + + try { + if(pendingMO != null) hangup(pendingMO); + } catch (CallStateException ex) { + Log.e(LOG_TAG, "unexpected error on hangup during dispose"); + } + + clearDisconnected(); + } + + protected void finalize() { + Log.d(LOG_TAG, "GsmCallTracker finalized"); + } + //***** Instance Methods //***** Public Methods @@ -101,11 +126,19 @@ public final class GsmCallTracker extends CallTracker { voiceCallStartedRegistrants.add(r); } + public void unregisterForVoiceCallStarted(Handler h) { + voiceCallStartedRegistrants.remove(h); + } + public void registerForVoiceCallEnded(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); voiceCallEndedRegistrants.add(r); } + public void unregisterForVoiceCallEnded(Handler h) { + voiceCallEndedRegistrants.remove(h); + } + private void fakeHoldForegroundBeforeDial() { List<Connection> connCopy; @@ -143,13 +176,13 @@ public final class GsmCallTracker extends CallTracker { // for the newly dialed connection switchWaitingOrHoldingAndActive(); - // Fake local state so that + // Fake local state so that // a) foregroundCall is empty for the newly dialed connection // b) hasNonHangupStateChanged remains false in the // next poll, so that we don't clear a failed dialing call fakeHoldForegroundBeforeDial(); - } - + } + if (foregroundCall.getState() != GsmCall.State.IDLE) { //we should have failed in !canDial() above before we get here throw new CallStateException("cannot dial in current state"); @@ -165,22 +198,22 @@ public final class GsmCallTracker extends CallTracker { pendingMO.cause = Connection.DisconnectCause.INVALID_NUMBER; // handlePollCalls() will notice this call not present - // and will mark it as dropped. + // and will mark it as dropped. pollCallsWhenSafe(); } else { // Always unmute when initiating a new call setMute(false); - cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); + cm.dial(pendingMO.address, clirMode, obtainCompleteMessage()); } updatePhoneState(); phone.notifyCallStateChanged(); - + return pendingMO; } - + Connection dial (String dialString) throws CallStateException { return dial(dialString, CommandsInterface.CLIR_DEFAULT); @@ -191,7 +224,7 @@ public final class GsmCallTracker extends CallTracker { // FIXME if SWITCH fails, should retry with ANSWER // in case the active/holding call disappeared and this // is no longer call waiting - + if (ringingCall.getState() == GsmCall.State.INCOMING) { Log.i("phone", "acceptCall: incoming..."); // Always unmute when answering a new call @@ -236,7 +269,7 @@ public final class GsmCallTracker extends CallTracker { explicitCallTransfer() throws CallStateException { cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT)); } - + void clearDisconnected() { internalClearDisconnected(); @@ -245,7 +278,7 @@ public final class GsmCallTracker extends CallTracker { phone.notifyCallStateChanged(); } - boolean + boolean canConference() { return foregroundCall.getState() == GsmCall.State.ACTIVE && backgroundCall.getState() == GsmCall.State.HOLDING @@ -274,16 +307,14 @@ public final class GsmCallTracker extends CallTracker { } //***** Private Instance Methods - + private void internalClearDisconnected() { ringingCall.clearDisconnected(); foregroundCall.clearDisconnected(); - backgroundCall.clearDisconnected(); + backgroundCall.clearDisconnected(); } - - /** * Obtain a message to use for signalling "invoke getCurrentCalls() when * this operation and all other pending operations are complete @@ -312,26 +343,24 @@ public final class GsmCallTracker extends CallTracker { private void operationComplete() { pendingOperations--; - + if (DBG_POLL) log("operationComplete: pendingOperations=" + pendingOperations + ", needsPoll=" + needsPoll); if (pendingOperations == 0 && needsPoll) { lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT); - cm.getCurrentCalls(lastRelevantPoll); + cm.getCurrentCalls(lastRelevantPoll); } else if (pendingOperations < 0) { // this should never happen Log.e(LOG_TAG,"GsmCallTracker.pendingOperations < 0"); pendingOperations = 0; } } - - private void updatePhoneState() { Phone.State oldState = state; - + if (ringingCall.isRinging()) { state = Phone.State.RINGING; } else if (pendingMO != null || @@ -339,7 +368,7 @@ public final class GsmCallTracker extends CallTracker { state = Phone.State.OFFHOOK; } else { state = Phone.State.IDLE; - } + } if (state == Phone.State.IDLE && oldState != state) { voiceCallEndedRegistrants.notifyRegistrants( @@ -377,7 +406,7 @@ public final class GsmCallTracker extends CallTracker { boolean needsPollDelay = false; boolean unknownConnectionAppeared = false; - for (int i = 0, curDC = 0, dcSize = polledCalls.size() + for (int i = 0, curDC = 0, dcSize = polledCalls.size() ; i < connections.length; i++) { GsmConnection conn = connections[i]; DriverCall dc = null; @@ -434,7 +463,7 @@ public final class GsmCallTracker extends CallTracker { // which is neither a ringing call or one we created. // Either we've crashed and re-attached to an existing // call, or something else (eg, SIM) initiated the call. - + Log.i(LOG_TAG,"Phantom call appeared " + dc); // If it's a connected call, set the connect time so that @@ -451,8 +480,8 @@ public final class GsmCallTracker extends CallTracker { hasNonHangupStateChanged = true; } else if (conn != null && dc == null) { // Connection missing in CLCC response that we were - // tracking. - droppedDuringPoll.add(conn); + // tracking. + droppedDuringPoll.add(conn); // Dropped connections are removed from the CallTracker // list but kept in the GsmCall list connections[i] = null; @@ -460,7 +489,7 @@ public final class GsmCallTracker extends CallTracker { // Connection in CLCC response does not match what // we were tracking. Assume dropped call and new call - droppedDuringPoll.add(conn); + droppedDuringPoll.add(conn); connections[i] = new GsmConnection (dc, this, i); if (connections[i].getCall() == ringingCall) { @@ -496,11 +525,11 @@ public final class GsmCallTracker extends CallTracker { // This is the first poll after an ATD. // We expect the pending call to appear in the list // If it does not, we land here - if (pendingMO != null) { - Log.d(LOG_TAG,"Pending MO dropped before poll fg state:" + if (pendingMO != null) { + Log.d(LOG_TAG,"Pending MO dropped before poll fg state:" + foregroundCall.getState()); - droppedDuringPoll.add(pendingMO); + droppedDuringPoll.add(pendingMO); pendingMO = null; hangupPendingMO = false; } @@ -521,7 +550,7 @@ public final class GsmCallTracker extends CallTracker { if (conn.cause == Connection.DisconnectCause.LOCAL) { cause = Connection.DisconnectCause.INCOMING_REJECTED; } else { - cause = Connection.DisconnectCause.INCOMING_MISSED; + cause = Connection.DisconnectCause.INCOMING_MISSED; } if (Phone.DEBUG_PHONE) { @@ -584,7 +613,7 @@ public final class GsmCallTracker extends CallTracker { private void dumpState() { List l; - + Log.i(LOG_TAG,"Phone State:" + state); Log.i(LOG_TAG,"Ringing call: " + ringingCall.toString()); @@ -615,7 +644,7 @@ public final class GsmCallTracker extends CallTracker { /*package*/ void hangup (GsmConnection conn) throws CallStateException { if (conn.owner != this) { - throw new CallStateException ("GsmConnection " + conn + throw new CallStateException ("GsmConnection " + conn + "does not belong to GsmCallTracker " + this); } @@ -624,14 +653,14 @@ public final class GsmCallTracker extends CallTracker { // GSM index assigned yet if (Phone.DEBUG_PHONE) log("hangup: set hangupPendingMO to true"); - hangupPendingMO = true; + hangupPendingMO = true; } else { - try { + try { cm.hangupConnection (conn.getGSMIndex(), obtainCompleteMessage()); } catch (CallStateException ex) { // Ignore "connection not found" // Call may have hung up already - Log.w(LOG_TAG,"GsmCallTracker WARN: hangup() on absent connection " + Log.w(LOG_TAG,"GsmCallTracker WARN: hangup() on absent connection " + conn); } } @@ -642,16 +671,16 @@ public final class GsmCallTracker extends CallTracker { /*package*/ void separate (GsmConnection conn) throws CallStateException { if (conn.owner != this) { - throw new CallStateException ("GsmConnection " + conn + throw new CallStateException ("GsmConnection " + conn + "does not belong to GsmCallTracker " + this); } try { - cm.separateConnection (conn.getGSMIndex(), + cm.separateConnection (conn.getGSMIndex(), obtainCompleteMessage(EVENT_SEPARATE_RESULT)); } catch (CallStateException ex) { // Ignore "connection not found" // Call may have hung up already - Log.w(LOG_TAG,"GsmCallTracker WARN: separate() on absent connection " + Log.w(LOG_TAG,"GsmCallTracker WARN: separate() on absent connection " + conn); } } @@ -663,13 +692,13 @@ public final class GsmCallTracker extends CallTracker { desiredMute = mute; cm.setMute(desiredMute, null); } - + /*package*/ boolean getMute() { return desiredMute; } - + //***** Called from GsmCall /* package */ void @@ -775,10 +804,10 @@ public final class GsmCallTracker extends CallTracker { //****** Overridden from Handler - public void + public void handleMessage (Message msg) { AsyncResult ar; - + switch (msg.what) { case EVENT_POLL_CALLS_RESULT: ar = (AsyncResult)msg.obj; @@ -812,7 +841,7 @@ public final class GsmCallTracker extends CallTracker { int causeCode; ar = (AsyncResult)msg.obj; - operationComplete(); + operationComplete(); if (ar.exception != null) { // An exception occurred...just treat the disconnect @@ -823,7 +852,7 @@ public final class GsmCallTracker extends CallTracker { } else { causeCode = ((int[])ar.result)[0]; } - + for (int i = 0, s = droppedDuringPoll.size() ; i < s ; i++ ) { @@ -853,7 +882,7 @@ public final class GsmCallTracker extends CallTracker { } } - private void log(String msg) { + protected void log(String msg) { Log.d(LOG_TAG, "[GsmCallTracker] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java index 2a46f77e616d..997777e6f370 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java @@ -16,18 +16,19 @@ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; +import android.os.AsyncResult; import android.os.Handler; -import android.os.Registrant; import android.os.Looper; import android.os.Message; -import android.os.AsyncResult; +import android.os.Registrant; import android.os.SystemClock; -import android.util.Log; import android.util.Config; +import android.util.Log; import android.telephony.PhoneNumberUtils; import android.telephony.ServiceState; +import com.android.internal.telephony.*; + /** * {@hide} */ @@ -41,9 +42,9 @@ public class GsmConnection extends Connection { String address; // MAY BE NULL!!! String dialString; // outgoing calls only - String postDialString; // outgoing calls only + String postDialString; // outgoing calls only boolean isIncoming; - boolean disconnected; + boolean disconnected; int index; // index in GsmCallTracker.connections[], -1 if unassigned // The GSM index is 1 + this @@ -63,7 +64,7 @@ public class GsmConnection extends Connection { */ long connectTimeReal; long duration; - long holdingStartTime; // The time when the Connection last transitioned + long holdingStartTime; // The time when the Connection last transitioned // into HOLDING int nextPostDialChar; // index into postDialString @@ -91,6 +92,7 @@ public class GsmConnection extends Connection { public void handleMessage(Message msg) { + switch (msg.what) { case EVENT_NEXT_POST_DIAL: case EVENT_DTMF_DONE: @@ -140,7 +142,10 @@ public class GsmConnection extends Connection { this.parent = parent; parent.attachFake(this, GsmCall.State.DIALING); } - + + public void dispose() { + } + static boolean equalsHandlesNulls (Object a, Object b) { return (a == null) ? (b == null) : a.equals (b); @@ -159,7 +164,7 @@ public class GsmConnection extends Connection { // no control over when they begin, so we might as well String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA); - return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); + return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress); } public String @@ -168,10 +173,9 @@ public class GsmConnection extends Connection { } public String getAddress() { - return address; + return address; } - public GsmCall getCall() { return parent; } @@ -218,13 +222,13 @@ public class GsmConnection extends Connection { public GsmCall.State getState() { if (disconnected) { return GsmCall.State.DISCONNECTED; - } else { + } else { return super.getState(); } } public void hangup() throws CallStateException { - if (!disconnected) { + if (!disconnected) { owner.hangup(this); } else { throw new CallStateException ("disconnected"); @@ -232,7 +236,7 @@ public class GsmConnection extends Connection { } public void separate() throws CallStateException { - if (!disconnected) { + if (!disconnected) { owner.separate(this); } else { throw new CallStateException ("disconnected"); @@ -245,7 +249,7 @@ public class GsmConnection extends Connection { public void proceedAfterWaitChar() { if (postDialState != PostDialState.WAIT) { - Log.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected " + Log.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected " + "getPostDialState() to be WAIT but was " + postDialState); return; } @@ -254,10 +258,10 @@ public class GsmConnection extends Connection { processNextPostDialChar(); } - + public void proceedAfterWildChar(String str) { if (postDialState != PostDialState.WILD) { - Log.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected " + Log.w(LOG_TAG, "GsmConnection.proceedAfterWaitChar(): Expected " + "getPostDialState() to be WILD but was " + postDialState); return; } @@ -294,22 +298,22 @@ public class GsmConnection extends Connection { postDialString = buf.toString(); nextPostDialChar = 0; if (Phone.DEBUG_PHONE) { - log("proceedAfterWildChar: new postDialString is " + + log("proceedAfterWildChar: new postDialString is " + postDialString); } processNextPostDialChar(); } } - + public void cancelPostDial() { postDialState = PostDialState.CANCELLED; } - /** + /** * Called when this Connection is being hung up locally (eg, user pressed "end") * Note that at this point, the hangup request has been dispatched to the radio - * but no response has yet been received so update() has not yet been called + * but no response has yet been received so update() has not yet been called */ void onHangupLocal() { @@ -322,7 +326,7 @@ public class GsmConnection extends Connection { * See 22.001 Annex F.4 for mapping of cause codes * to local tones */ - + switch (causeCode) { case CallFailCause.USER_BUSY: return DisconnectCause.BUSY; @@ -345,7 +349,7 @@ public class GsmConnection extends Connection { return DisconnectCause.FDN_BLOCKED; case CallFailCause.ERROR_UNSPECIFIED: - case CallFailCause.NORMAL_CLEARING: + case CallFailCause.NORMAL_CLEARING: default: GSMPhone phone = owner.phone; int serviceState = phone.getServiceState().getState(); @@ -355,7 +359,7 @@ public class GsmConnection extends Connection { || serviceState == ServiceState.STATE_EMERGENCY_ONLY ) { return DisconnectCause.OUT_OF_SERVICE; } else if (phone.getIccCard().getState() != SimCard.State.READY) { - return DisconnectCause.SIM_ERROR; + return DisconnectCause.ICC_ERROR; } else { return DisconnectCause.NORMAL; } @@ -371,10 +375,10 @@ public class GsmConnection extends Connection { /*package*/ void onDisconnect(DisconnectCause cause) { this.cause = cause; - - if (!disconnected) { + + if (!disconnected) { index = -1; - + disconnectTime = System.currentTimeMillis(); duration = SystemClock.elapsedRealtime() - connectTimeReal; disconnected = true; @@ -385,7 +389,7 @@ public class GsmConnection extends Connection { owner.phone.notifyDisconnect(this); if (parent != null) { - parent.connectionDisconnected(this); + parent.connectionDisconnected(this); } } } @@ -506,21 +510,21 @@ public class GsmConnection extends Connection { } else if (c == PhoneNumberUtils.PAUSE) { // From TS 22.101: - // "The first occurrence of the "DTMF Control Digits Separator" - // shall be used by the ME to distinguish between the addressing + // "The first occurrence of the "DTMF Control Digits Separator" + // shall be used by the ME to distinguish between the addressing // digits (i.e. the phone number) and the DTMF digits...." if (nextPostDialChar == 1) { // The first occurrence. // We don't need to pause here, but wait for just a bit anyway - h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), + h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), PAUSE_DELAY_FIRST_MILLIS); } else { // It continues... - // "Upon subsequent occurrences of the separator, the UE shall - // pause again for 3 seconds (\u00B1 20 %) before sending any + // "Upon subsequent occurrences of the separator, the UE shall + // pause again for 3 seconds (\u00B1 20 %) before sending any // further DTMF digits." - h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), + h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE), PAUSE_DELAY_MILLIS); } } else if (c == PhoneNumberUtils.WAIT) { @@ -536,7 +540,7 @@ public class GsmConnection extends Connection { public String getRemainingPostDialString() { - if (postDialState == PostDialState.CANCELLED + if (postDialState == PostDialState.CANCELLED || postDialState == PostDialState.COMPLETE || postDialString == null || postDialString.length() <= nextPostDialChar @@ -546,7 +550,7 @@ public class GsmConnection extends Connection { return postDialString.substring(nextPostDialChar); } - + private void processNextPostDialChar() { char c = 0; @@ -565,7 +569,7 @@ public class GsmConnection extends Connection { c = 0; } else { boolean isValid; - + postDialState = PostDialState.STARTED; c = postDialString.charAt(nextPostDialChar++); @@ -585,7 +589,8 @@ public class GsmConnection extends Connection { Message notifyMessage; - if (postDialHandler != null && (notifyMessage = postDialHandler.messageForRegistrant()) != null) { + if (postDialHandler != null + && (notifyMessage = postDialHandler.messageForRegistrant()) != null) { // The AsyncResult.result is the Connection object PostDialState state = postDialState; AsyncResult ar = AsyncResult.forMessage(notifyMessage); @@ -598,15 +603,6 @@ public class GsmConnection extends Connection { //Log.v("GSM", "##### processNextPostDialChar: send msg to postDialHandler, arg1=" + c); notifyMessage.sendToTarget(); } -//moved indent due to maximum character length -/* -else { -if (postDialHandler == null) -Log.v("GSM", "##### processNextPostDialChar: postDialHandler is NULL!"); -else -Log.v("GSM", "##### processNextPostDialChar: postDialHandler.messageForRegistrant() returned NULL!"); -} -*/ } @@ -615,8 +611,8 @@ Log.v("GSM", "##### processNextPostDialChar: postDialHandler.messageForRegistran */ private boolean isConnectingInOrOut() { - return parent == null || parent == owner.ringingCall - || parent.state == GsmCall.State.DIALING + return parent == null || parent == owner.ringingCall + || parent.state == GsmCall.State.DIALING || parent.state == GsmCall.State.ALERTING; } diff --git a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 63d145edabf4..e9d1eb3b7026 100644 --- a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -39,57 +39,28 @@ import android.preference.PreferenceManager; import android.provider.Checkin; import android.provider.Settings; import android.provider.Telephony; -import android.provider.Settings.SettingNotFoundException; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.gsm.PdpConnection.PdpFailCause; - import android.telephony.ServiceState; import android.util.EventLog; import android.util.Log; import android.text.TextUtils; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataConnection.FailCause; +import com.android.internal.telephony.DataConnectionTracker; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; + import java.io.IOException; import java.util.ArrayList; /** * {@hide} */ -final class DataConnectionTracker extends Handler -{ +public final class GsmDataConnectionTracker extends DataConnectionTracker { private static final String LOG_TAG = "GSM"; private static final boolean DBG = true; /** - * IDLE: ready to start data connection setup, default state - * INITING: state of issued setupDefaultPDP() but not finish yet - * CONNECTING: state of issued startPppd() but not finish yet - * SCANNING: data connection fails with one apn but other apns are available - * ready to start data connection on other apns (before INITING) - * CONNECTED: IP connection is setup - * FAILED: data connection fail for all apns settings - * - * getDataConnectionState() maps State to DataState - * FAILED or IDLE : DISCONNECTED - * INITING or CONNECTING or SCANNING: CONNECTING - * CONNECTED : CONNECTED - */ - enum State { - IDLE, - INITING, - CONNECTING, - SCANNING, - CONNECTED, - FAILED - } - - enum Activity { - NONE, - DATAIN, - DATAOUT, - DATAINANDOUT - } - - /** * Handles changes to the APN db. */ private class ApnChangeObserver extends ContentObserver { @@ -112,19 +83,14 @@ final class DataConnectionTracker extends Handler //***** Instance Variables - GSMPhone phone; INetStatService netstat; - State state = State.IDLE; - Activity activity = Activity.NONE; - boolean netStatPollEnabled = false; // Indicates baseband will not auto-attach private boolean noAutoAttach = false; long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - Handler mDataConnectionTracker = null; private ContentResolver mResolver; + private IntentFilter filterS; + private IntentFilter filter; - int txPkts, rxPkts, sentSinceLastRecv, netStatPollPeriod; - private int mNoRecvPollCount = 0; private boolean mPingTestActive = false; // Count of PDP reset attempts; reset when we see incoming, // call reRegisterNetwork, or pingTest succeeds. @@ -152,11 +118,11 @@ final class DataConnectionTracker extends Handler /** * pdpList holds all the PDP connection, i.e. IP Link in GPRS */ - private ArrayList<PdpConnection> pdpList; + private ArrayList<DataConnection> pdpList; /** CID of active PDP */ int cidActive; - + /** Currently requested APN type */ private String mRequestedApnType = Phone.APN_TYPE_DEFAULT; @@ -182,39 +148,6 @@ final class DataConnectionTracker extends Handler private static final int PDP_CONNECTION_POOL_SIZE = 1; private static final int POLL_PDP_MILLIS = 5 * 1000; - private static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000; - - /** Slow poll when attempting connection recovery. */ - private static final int POLL_NETSTAT_SLOW_MILLIS = 5000; - - /** Default ping deadline, in seconds. */ - private final int DEFAULT_PING_DEADLINE = 5; - /** Default max failure count before attempting to network re-registration. */ - private final int DEFAULT_MAX_PDP_RESET_FAIL = 3; - - /** - * After detecting a potential connection problem, this is the max number - * of subsequent polls before attempting a radio reset. At this point, - * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to - * poll for about 2 more minutes. - */ - private static final int NO_RECV_POLL_LIMIT = 24; - - // 1 sec. default polling interval when screen is on. - private static final int POLL_NETSTAT_MILLIS = 1000; - // 10 min. default polling interval when screen is off. - private static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10; - // 2 min for round trip time - private static final int POLL_LONGEST_RTT = 120 * 1000; - // 10 for packets without ack - private static final int NUMBER_SENT_PACKETS_OF_HANG = 10; - // how long to wait before switching back to default APN - private static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000; - // system property that can override the above value - private static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; - // represents an invalid IP address - private static final String NULL_IP = "0.0.0.0"; - static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect"; //***** Tag IDs for EventLog @@ -223,32 +156,8 @@ final class DataConnectionTracker extends Handler private static final int EVENT_LOG_PDP_RESET = 50103; private static final int EVENT_LOG_REREGISTER_NETWORK = 50104; - //***** Event Codes - static final int EVENT_DATA_SETUP_COMPLETE = 1; - static final int EVENT_RADIO_AVAILABLE = 3; - static final int EVENT_RECORDS_LOADED = 4; - static final int EVENT_TRY_SETUP_DATA = 5; - static final int EVENT_PDP_STATE_CHANGED = 6; - static final int EVENT_POLL_PDP = 7; - static final int EVENT_GET_PDP_LIST_COMPLETE = 11; - static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12; - static final int EVENT_VOICE_CALL_STARTED = 14; - static final int EVENT_VOICE_CALL_ENDED = 15; - static final int EVENT_GPRS_DETACHED = 19; - static final int EVENT_LINK_STATE_CHANGED = 20; - static final int EVENT_ROAMING_ON = 21; - static final int EVENT_ROAMING_OFF = 22; - static final int EVENT_ENABLE_NEW_APN = 23; - static final int EVENT_RESTORE_DEFAULT_APN = 24; - static final int EVENT_DISCONNECT_DONE = 25; - static final int EVENT_GPRS_ATTACHED = 26; - static final int EVENT_START_NETSTAT_POLL = 27; - static final int EVENT_START_RECOVERY = 28; - - BroadcastReceiver screenOnOffReceiver = new BroadcastReceiver () - { - public void onReceive(Context context, Intent intent) - { + BroadcastReceiver screenOnOffReceiver = new BroadcastReceiver () { + public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { mIsScreenOn = true; stopNetStatPoll(); @@ -258,7 +167,8 @@ final class DataConnectionTracker extends Handler stopNetStatPoll(); startNetStatPoll(); } else { - Log.w(LOG_TAG, "DataConnectionTracker received unexpected Intent: " + intent.getAction()); + Log.w(LOG_TAG, "DataConnectionTracker received unexpected Intent: " + + intent.getAction()); } } }; @@ -266,8 +176,7 @@ final class DataConnectionTracker extends Handler BroadcastReceiver alarmReceiver = new BroadcastReceiver () { - public void onReceive(Context context, Intent intent) - { + public void onReceive(Context context, Intent intent) { Log.d(LOG_TAG, "GPRS reconnect alarm. Previous state was " + state); if (state == State.FAILED) { @@ -283,37 +192,37 @@ final class DataConnectionTracker extends Handler //***** Constructor - DataConnectionTracker(GSMPhone phone) - { - this.phone = phone; - phone.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); - phone.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - phone.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); - phone.mCM.registerForPDPStateChanged (this, EVENT_PDP_STATE_CHANGED, null); - phone.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); - phone.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); - phone.mSST.registerForGprsAttached(this, EVENT_GPRS_ATTACHED, null); - phone.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null); - phone.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); - phone.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); + GsmDataConnectionTracker(GSMPhone p) { + super(p); + + p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); + p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); + p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); + p.mCM.registerForDataStateChanged (this, EVENT_DATA_STATE_CHANGED, null); + p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null); + p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null); + p.mSST.registerForGprsAttached(this, EVENT_GPRS_ATTACHED, null); + p.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null); + p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null); + p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null); this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat")); - IntentFilter filter = new IntentFilter(); + this.filter = new IntentFilter(); filter.addAction(INTENT_RECONNECT_ALARM); - phone.getContext().registerReceiver( - alarmReceiver, filter, null, phone.h); + p.getContext().registerReceiver( + alarmReceiver, filter, null, phone.getHandler()); - IntentFilter filterS = new IntentFilter(); + this.filterS = new IntentFilter(); filterS.addAction(Intent.ACTION_SCREEN_ON); filterS.addAction(Intent.ACTION_SCREEN_OFF); - phone.getContext().registerReceiver(screenOnOffReceiver, filterS); + p.getContext().registerReceiver(screenOnOffReceiver, filterS); mDataConnectionTracker = this; mResolver = phone.getContext().getContentResolver(); apnObserver = new ApnChangeObserver(); - phone.getContext().getContentResolver().registerContentObserver( + p.getContext().getContentResolver().registerContentObserver( Telephony.Carriers.CONTENT_URI, true, apnObserver); createAllPdpList(); @@ -325,6 +234,30 @@ final class DataConnectionTracker extends Handler noAutoAttach = !dataEnabled[APN_DEFAULT_ID]; } + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForAvailable(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + ((GSMPhone) phone).mSIMRecords.unregisterForRecordsLoaded(this); + phone.mCM.unregisterForDataStateChanged(this); + ((GSMPhone) phone).mCT.unregisterForVoiceCallEnded(this); + ((GSMPhone) phone).mCT.unregisterForVoiceCallStarted(this); + ((GSMPhone) phone).mSST.unregisterForGprsAttached(this); + ((GSMPhone) phone).mSST.unregisterForGprsDetached(this); + ((GSMPhone) phone).mSST.unregisterForRoamingOn(this); + ((GSMPhone) phone).mSST.unregisterForRoamingOff(this); + + phone.getContext().unregisterReceiver(this.alarmReceiver); + phone.getContext().unregisterReceiver(this.screenOnOffReceiver); + phone.getContext().getContentResolver().unregisterContentObserver(this.apnObserver); + + destroyAllPdpList(); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized"); + } + void setState(State s) { if (state != s) { if (s == State.INITING) { // request PDP context @@ -347,7 +280,7 @@ final class DataConnectionTracker extends Handler waitingApns.clear(); // when teardown the connection and set to IDLE } } - String[] getActiveApnTypes() { + protected String[] getActiveApnTypes() { String[] result; if (mActiveApn != null) { result = mActiveApn.types; @@ -358,7 +291,7 @@ final class DataConnectionTracker extends Handler return result; } - String getActiveApnString() { + protected String getActiveApnString() { String result = null; if (mActiveApn != null) { result = mActiveApn.apn; @@ -376,7 +309,7 @@ final class DataConnectionTracker extends Handler * will be sent by the ConnectivityManager when a connection to * the APN has been established. */ - int enableApnType(String type) { + protected int enableApnType(String type) { if (!TextUtils.equals(type, Phone.APN_TYPE_MMS)) { return Phone.APN_REQUEST_FAILED; } @@ -414,7 +347,7 @@ final class DataConnectionTracker extends Handler * @param type the APN type. The only valid value currently is {@link Phone#APN_TYPE_MMS}. * @return */ - int disableApnType(String type) { + protected int disableApnType(String type) { Log.d(LOG_TAG, "disableApnType("+type+")"); if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { removeMessages(EVENT_RESTORE_DEFAULT_APN); @@ -440,7 +373,7 @@ final class DataConnectionTracker extends Handler return Phone.APN_REQUEST_FAILED; } } - + private boolean isApnTypeActive(String type) { // TODO: to support simultaneous, mActiveApn can be a List instead. return mActiveApn != null && mActiveApn.canHandleType(type); @@ -477,7 +410,7 @@ final class DataConnectionTracker extends Handler Log.d(LOG_TAG, "dataEnabled[DEFAULT_APN]=" + dataEnabled[APN_DEFAULT_ID] + " dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID]); } - + /** * Prevent mobile data connections from being established, * or once again allow mobile data connections. If the state @@ -506,8 +439,10 @@ final class DataConnectionTracker extends Handler return true; } return false; - } else // isEnabled && enable + } else { + // isEnabled && enable return true; + } } /** @@ -529,31 +464,11 @@ final class DataConnectionTracker extends Handler return dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID]; } - //The data roaming setting is now located in the shared preferences. - // See if the requested preference value is the same as that stored in - // the shared values. If it is not, then update it. - public void setDataOnRoamingEnabled(boolean enabled) { - if (getDataOnRoamingEnabled() != enabled) { - Settings.System.putInt(phone.getContext().getContentResolver(), - Settings.System.DATA_ROAMING, enabled ? 1 : 0); - } - Message roamingMsg = phone.getServiceState().getRoaming() ? - obtainMessage(EVENT_ROAMING_ON) : obtainMessage(EVENT_ROAMING_OFF); - sendMessage(roamingMsg); - } - - //Retrieve the data roaming setting from the shared preferences. - public boolean getDataOnRoamingEnabled() { - try { - return Settings.System.getInt(phone.getContext().getContentResolver(), - Settings.System.DATA_ROAMING) > 0; - } catch (SettingNotFoundException snfe) { - return false; - } - } - - public ArrayList<PdpConnection> getAllPdps() { - ArrayList<PdpConnection> pdps = (ArrayList<PdpConnection>)pdpList.clone(); + /** + * Formerly this method was ArrayList<PdpConnection> getAllPdps() + */ + public ArrayList<DataConnection> getAllDataConnections() { + ArrayList<DataConnection> pdps = (ArrayList<DataConnection>)pdpList.clone(); return pdps; } @@ -567,8 +482,7 @@ final class DataConnectionTracker extends Handler * Invoked when ServiceStateTracker observes a transition from GPRS * attach to detach. */ - private void onGprsDetached() - { + protected void onGprsDetached() { /* * We presently believe it is unnecessary to tear down the PDP context * when GPRS detaches, but we should stop the network polling. @@ -576,7 +490,7 @@ final class DataConnectionTracker extends Handler stopNetStatPoll(); phone.notifyDataConnection(Phone.REASON_GPRS_DETACHED); } - + private void onGprsAttached() { if (state == State.CONNECTED) { startNetStatPoll(); @@ -586,8 +500,7 @@ final class DataConnectionTracker extends Handler } } - private boolean trySetupData(String reason) - { + private boolean trySetupData(String reason) { if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason)); if (phone.getSimulatedRadioControl() != null) { @@ -600,13 +513,13 @@ final class DataConnectionTracker extends Handler return true; } - int gprsState = phone.mSST.getCurrentGprsState(); + int gprsState = ((GSMPhone) phone).mSST.getCurrentGprsState(); boolean roaming = phone.getServiceState().getRoaming(); if ((state == State.IDLE || state == State.SCANNING) && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach) - && phone.mSIMRecords.getRecordsLoaded() - && ( phone.mSST.isConcurrentVoiceAndData() || + && ((GSMPhone) phone).mSIMRecords.getRecordsLoaded() + && ( ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() || phone.getState() == Phone.State.IDLE ) && isDataAllowed()) { @@ -614,7 +527,7 @@ final class DataConnectionTracker extends Handler waitingApns = buildWaitingApns(); if (waitingApns.isEmpty()) { if (DBG) log("No APN found"); - notifyNoData(PdpConnection.PdpFailCause.BAD_APN); + notifyNoData(PdpConnection.FailCause.BAD_APN); return false; } else { log ("Create from allApns : " + apnListToString(allApns)); @@ -630,8 +543,8 @@ final class DataConnectionTracker extends Handler log("trySetupData: Not ready for data: " + " dataState=" + state + " gprsState=" + gprsState + - " sim=" + phone.mSIMRecords.getRecordsLoaded() + - " UMTS=" + phone.mSST.isConcurrentVoiceAndData() + + " sim=" + ((GSMPhone) phone).mSIMRecords.getRecordsLoaded() + + " UMTS=" + ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() + " phoneState=" + phone.getState() + " dataEnabled=" + getAnyDataEnabled() + " roaming=" + roaming + @@ -651,7 +564,8 @@ final class DataConnectionTracker extends Handler */ private void cleanUpConnection(boolean tearDown, String reason) { if (DBG) log("Clean up connection due to " + reason); - for (PdpConnection pdp : pdpList) { + for (DataConnection conn : pdpList) { + PdpConnection pdp = (PdpConnection) conn; if (tearDown) { Message msg = obtainMessage(EVENT_DISCONNECT_DONE); pdp.disconnect(msg); @@ -705,8 +619,9 @@ final class DataConnectionTracker extends Handler } private PdpConnection findFreePdp() { - for (PdpConnection pdp : pdpList) { - if (pdp.getState() == PdpConnection.PdpState.INACTIVE) { + for (DataConnection conn : pdpList) { + PdpConnection pdp = (PdpConnection) conn; + if (pdp.getState() == DataConnection.State.INACTIVE) { return pdp; } } @@ -744,7 +659,7 @@ final class DataConnectionTracker extends Handler return null; } - String getIpAddress(String apnType) { + protected String getIpAddress(String apnType) { if (mActivePdp != null && (apnType == null || mActiveApn.canHandleType(apnType))) { return mActivePdp.getIpAddress(); @@ -760,7 +675,7 @@ final class DataConnectionTracker extends Handler return null; } - String[] getDnsServers(String apnType) { + protected String[] getDnsServers(String apnType) { if (mActivePdp != null && (apnType == null || mActiveApn.canHandleType(apnType))) { return mActivePdp.getDnsServers(); @@ -769,8 +684,7 @@ final class DataConnectionTracker extends Handler } private boolean - pdpStatesHasCID (ArrayList<PDPContextState> states, int cid) - { + pdpStatesHasCID (ArrayList<PDPContextState> states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { if (states.get(i).cid == cid) return true; } @@ -779,8 +693,7 @@ final class DataConnectionTracker extends Handler } private boolean - pdpStatesHasActiveCID (ArrayList<PDPContextState> states, int cid) - { + pdpStatesHasActiveCID (ArrayList<PDPContextState> states, int cid) { for (int i = 0, s = states.size() ; i < s ; i++) { if (states.get(i).cid == cid) return states.get(i).active; } @@ -794,9 +707,7 @@ final class DataConnectionTracker extends Handler * via an unsolicited response (which could have happened at any * previous state */ - private void - onPdpStateChanged (AsyncResult ar, boolean explicitPoll) - { + protected void onPdpStateChanged (AsyncResult ar, boolean explicitPoll) { ArrayList<PDPContextState> pdpStates; pdpStates = (ArrayList<PDPContextState>)(ar.result); @@ -852,7 +763,7 @@ final class DataConnectionTracker extends Handler this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); } else { Log.i(LOG_TAG, "PDP connection has dropped (active=false case). " - + " Reconnecting"); + + " Reconnecting"); cleanUpConnection(true, null); trySetupData(null); @@ -912,9 +823,7 @@ final class DataConnectionTracker extends Handler * with certain RIL impl's/basebands * */ - private void - startPeriodicPdpPoll() - { + private void startPeriodicPdpPoll() { removeMessages(EVENT_POLL_PDP); sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); @@ -924,6 +833,7 @@ final class DataConnectionTracker extends Handler txPkts = -1; rxPkts = -1; sentSinceLastRecv = 0; + netStatPollPeriod = POLL_NETSTAT_MILLIS; mNoRecvPollCount = 0; } @@ -931,7 +841,7 @@ final class DataConnectionTracker extends Handler if (state == State.CONNECTED) { int maxPdpReset = Settings.Gservices.getInt(mResolver, Settings.Gservices.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT, - DEFAULT_MAX_PDP_RESET_FAIL); + DEFAULT_MAX_PDP_RESET_FAIL); if (mPdpResetCount < maxPdpReset) { mPdpResetCount++; EventLog.writeEvent(EVENT_LOG_PDP_RESET, sentSinceLastRecv); @@ -939,16 +849,14 @@ final class DataConnectionTracker extends Handler } else { mPdpResetCount = 0; EventLog.writeEvent(EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv); - phone.mSST.reRegisterNetwork(null); + ((GSMPhone) phone).mSST.reRegisterNetwork(null); } // TODO: Add increasingly drastic recovery steps, eg, // reset the radio, reset the device. } } - private void - startNetStatPoll() - { + protected void startNetStatPoll() { if (state == State.CONNECTED && mPingTestActive == false) { Log.d(LOG_TAG, "[DataConnection] Start poll NetStat"); resetPollStats(); @@ -957,17 +865,13 @@ final class DataConnectionTracker extends Handler } } - private void - stopNetStatPoll() - { + protected void stopNetStatPoll() { netStatPollEnabled = false; removeCallbacks(mPollNetStat); Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat"); } - private void - restartRadio() - { + protected void restartRadio() { Log.d(LOG_TAG, "************TURN OFF RADIO**************"); cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF); phone.mCM.setRadioPower(false, null); @@ -983,117 +887,6 @@ final class DataConnectionTracker extends Handler SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1)); } - Runnable mPollNetStat = new Runnable() - { - - public void run() { - int sent, received; - int preTxPkts = -1, preRxPkts = -1; - - Activity newActivity; - - preTxPkts = txPkts; - preRxPkts = rxPkts; - - try { - txPkts = netstat.getTxPackets(); - rxPkts = netstat.getRxPackets(); - } catch (RemoteException e) { - txPkts = 0; - rxPkts = 0; - } - - //Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts)); - - if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) { - sent = txPkts - preTxPkts; - received = rxPkts - preRxPkts; - - if ( sent > 0 && received > 0 ) { - sentSinceLastRecv = 0; - newActivity = Activity.DATAINANDOUT; - mPdpResetCount = 0; - } else if (sent > 0 && received == 0) { - if (phone.mCT.state == Phone.State.IDLE) { - sentSinceLastRecv += sent; - } else { - sentSinceLastRecv = 0; - } - newActivity = Activity.DATAOUT; - } else if (sent == 0 && received > 0) { - sentSinceLastRecv = 0; - newActivity = Activity.DATAIN; - mPdpResetCount = 0; - } else if (sent == 0 && received == 0) { - newActivity = Activity.NONE; - } else { - sentSinceLastRecv = 0; - newActivity = Activity.NONE; - } - - if (activity != newActivity && mIsScreenOn) { - activity = newActivity; - phone.notifyDataActivity(); - } - } - - int watchdogTrigger = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, NUMBER_SENT_PACKETS_OF_HANG); - - if (sentSinceLastRecv >= watchdogTrigger) { - // we already have NUMBER_SENT_PACKETS sent without ack - if (mNoRecvPollCount == 0) { - EventLog.writeEvent(EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED, - sentSinceLastRecv); - } - - int noRecvPollLimit = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_COUNT, NO_RECV_POLL_LIMIT); - - if (mNoRecvPollCount < noRecvPollLimit) { - // It's possible the PDP context went down and we weren't notified. - // Start polling the context list in an attempt to recover. - if (DBG) log("no DATAIN in a while; polling PDP"); - phone.mCM.getPDPContextList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); - - mNoRecvPollCount++; - - // Slow down the poll interval to let things happen - netStatPollPeriod = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, POLL_NETSTAT_SLOW_MILLIS); - } else { - if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) + - " pkts since last received"); - // We've exceeded the threshold. Run ping test as a final check; - // it will proceed with recovery if ping fails. - netStatPollEnabled = false; - stopNetStatPoll(); - Thread pingTest = new Thread() { - public void run() { - mPingTestActive = true; - runPingTest(); - } - }; - pingTest.start(); - } - } else { - mNoRecvPollCount = 0; - if (mIsScreenOn) { - netStatPollPeriod = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS); - } else { - netStatPollPeriod = Settings.Gservices.getInt(mResolver, - Settings.Gservices.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS, - POLL_NETSTAT_SCREEN_OFF_MILLIS); - } - } - - if (netStatPollEnabled) { - mDataConnectionTracker.postDelayed(this, netStatPollPeriod); - } - } - }; - private void runPingTest () { int status = -1; try { @@ -1112,7 +905,7 @@ final class DataConnectionTracker extends Handler } catch (Exception e) { Log.w(LOG_TAG, "exception trying to ping"); } - + if (status == 0) { // ping succeeded. False alarm. Reset netStatPoll. // ("-1" for this event indicates a false alarm) @@ -1130,20 +923,16 @@ final class DataConnectionTracker extends Handler * seems like it deserves an error notification. * Transient errors are ignored */ - private boolean - shouldPostNotification(PdpConnection.PdpFailCause cause) - { + private boolean shouldPostNotification(PdpConnection.FailCause cause) { boolean shouldPost = true; // TODO CHECK // if (dataLink != null) { // shouldPost = dataLink.getLastLinkExitCode() != DataLink.EXIT_OPEN_FAILED; //} - return (shouldPost && cause != PdpConnection.PdpFailCause.UNKNOWN); + return (shouldPost && cause != PdpConnection.FailCause.UNKNOWN); } - private void - reconnectAfterFail(PdpConnection.PdpFailCause lastFailCauseCode) - { + private void reconnectAfterFail(PdpConnection.FailCause lastFailCauseCode) { if (state == State.FAILED) { Log.d(LOG_TAG, "PDP activate failed. Scheduling next attempt for " + (nextReconnectDelay / 1000) + "s"); @@ -1172,239 +961,180 @@ final class DataConnectionTracker extends Handler } } - private void notifyNoData(PdpConnection.PdpFailCause lastFailCauseCode) { + private void notifyNoData(PdpConnection.FailCause lastFailCauseCode) { setState(State.FAILED); } - - private void log(String s) { - Log.d(LOG_TAG, "[DataConnectionTracker] " + s); + protected void onRecordsLoaded() { + createAllApnList(); + if (state == State.FAILED) { + cleanUpConnection(false, null); + } + sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); } - //***** Overridden from Handler - public void - handleMessage (Message msg) - { - AsyncResult ar; - String reason = null; - - switch (msg.what) { - case EVENT_RECORDS_LOADED: - createAllApnList(); - if (state == State.FAILED) { - cleanUpConnection(false, null); - } - sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); - break; - - case EVENT_ENABLE_NEW_APN: - // TODO: To support simultaneous PDP contexts, this should really only call - // cleanUpConnection if it needs to free up a PdpConnection. - reason = Phone.REASON_APN_SWITCHED; - cleanUpConnection(true, reason); - // Fall through to EVENT_TRY_SETUP_DATA. - case EVENT_TRY_SETUP_DATA: - trySetupData(reason); - break; - - case EVENT_RESTORE_DEFAULT_APN: - if (DBG) Log.d(LOG_TAG, "Restore default APN"); - setEnabled(Phone.APN_TYPE_MMS, false); - if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { - cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN); - mRequestedApnType = Phone.APN_TYPE_DEFAULT; - trySetupData(Phone.REASON_RESTORE_DEFAULT_APN ); - } - break; - - case EVENT_ROAMING_OFF: - trySetupData(Phone.REASON_ROAMING_OFF); - break; - - case EVENT_GPRS_DETACHED: - onGprsDetached(); - break; + protected void onEnableNewApn() { + // TODO: To support simultaneous PDP contexts, this should really only call + // cleanUpConnection if it needs to free up a PdpConnection. + cleanUpConnection(true, Phone.REASON_APN_SWITCHED); + trySetupData(Phone.REASON_APN_SWITCHED); + } - case EVENT_GPRS_ATTACHED: - onGprsAttached(); - break; - - case EVENT_ROAMING_ON: - if (getDataOnRoamingEnabled()) { - trySetupData(Phone.REASON_ROAMING_ON); - } else { - if (DBG) log("Tear down data connection on roaming."); - cleanUpConnection(true, Phone.REASON_ROAMING_ON); - } - break; + protected void onTrySetupData() { + trySetupData(null); + } - case EVENT_RADIO_AVAILABLE: - if (phone.getSimulatedRadioControl() != null) { - // Assume data is connected on the simulator - // FIXME this can be improved - setState(State.CONNECTED); - phone.notifyDataConnection(null); + protected void onRestoreDefaultApn() { + if (DBG) Log.d(LOG_TAG, "Restore default APN"); + setEnabled(Phone.APN_TYPE_MMS, false); + if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { + cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN); + mRequestedApnType = Phone.APN_TYPE_DEFAULT; + trySetupData(Phone.REASON_RESTORE_DEFAULT_APN ); + } + } - Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); - } + protected void onRoamingOff() { + trySetupData(Phone.REASON_ROAMING_OFF); + } - if (state != State.IDLE) { - cleanUpConnection(true, null); - } - break; + protected void onRoamingOn() { + if (getDataOnRoamingEnabled()) { + trySetupData(Phone.REASON_ROAMING_ON); + } else { + if (DBG) log("Tear down data connection on roaming."); + cleanUpConnection(true, Phone.REASON_ROAMING_ON); + } + } - case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: - // Make sure our reconnect delay starts at the initial value - // next time the radio comes on - nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; + protected void onRadioAvailable() { + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + setState(State.CONNECTED); + phone.notifyDataConnection(null); - if (phone.getSimulatedRadioControl() != null) { - // Assume data is connected on the simulator - // FIXME this can be improved - Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); - } else { - if (DBG) log("Radio is off and clean up all connection"); - // TODO: Should we reset mRequestedApnType to "default"? - cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); - } - break; - - case EVENT_DATA_SETUP_COMPLETE: - ar = (AsyncResult) msg.obj; - - if (ar.exception == null) { - // everything is setup - - // arg1 contains CID for this PDP context - cidActive = msg.arg1; - /* - * We may have switched away from the default PDP context - * in order to enable a "special" APN (e.g., for MMS - * traffic). Set a timer to switch back and/or disable the - * special APN, so that a negligient application doesn't - * permanently prevent data connectivity. What we are - * protecting against here is not malicious apps, but - * rather an app that inadvertantly fails to reset to the - * default APN, or that dies before doing so. - */ - if (dataEnabled[APN_MMS_ID]) { - removeMessages(EVENT_RESTORE_DEFAULT_APN); - sendMessageDelayed( - obtainMessage(EVENT_RESTORE_DEFAULT_APN), - getRestoreDefaultApnDelay()); - } - if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { - SystemProperties.set("gsm.defaultpdpcontext.active", "true"); - } else { - SystemProperties.set("gsm.defaultpdpcontext.active", "false"); - } - notifyDefaultData(); - - // TODO: For simultaneous PDP support, we need to build another - // trigger another TRY_SETUP_DATA for the next APN type. (Note - // that the existing connection may service that type, in which - // case we should try the next type, etc. - } else { - PdpConnection.PdpFailCause cause; - cause = (PdpConnection.PdpFailCause) (ar.result); - if(DBG) - log("PDP setup failed " + cause); - - // No try for permanent failure - if (cause.isPermanentFail()) { - notifyNoData(cause); - } - - if (tryNextApn(cause)) { - waitingApns.remove(0); - if (waitingApns.isEmpty()) { - // No more to try, start delayed retry - notifyNoData(cause); - reconnectAfterFail(cause); - } else { - // we still have more apns to try - setState(State.SCANNING); - trySetupData(null); - } - } else { - notifyNoData(cause); - reconnectAfterFail(cause); - } - } - break; + Log.i(LOG_TAG, "We're on the simulator; assuming data is connected"); + } - case EVENT_DISCONNECT_DONE: - if(DBG) log("EVENT_DISCONNECT_DONE"); - trySetupData(null); - break; + if (state != State.IDLE) { + cleanUpConnection(true, null); + } + } - case EVENT_PDP_STATE_CHANGED: - ar = (AsyncResult) msg.obj; + protected void onRadioOffOrNotAvailable() { + // Make sure our reconnect delay starts at the initial value + // next time the radio comes on + nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS; - onPdpStateChanged(ar, false); - break; + if (phone.getSimulatedRadioControl() != null) { + // Assume data is connected on the simulator + // FIXME this can be improved + Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless"); + } else { + if (DBG) log("Radio is off and clean up all connection"); + // TODO: Should we reset mRequestedApnType to "default"? + cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF); + } + } - case EVENT_GET_PDP_LIST_COMPLETE: - ar = (AsyncResult) msg.obj; + protected void onDataSetupComplete(AsyncResult ar) { + if (ar.exception == null) { + // everything is setup + + /* + * We may have switched away from the default PDP context + * in order to enable a "special" APN (e.g., for MMS + * traffic). Set a timer to switch back and/or disable the + * special APN, so that a negligient application doesn't + * permanently prevent data connectivity. What we are + * protecting against here is not malicious apps, but + * rather an app that inadvertantly fails to reset to the + * default APN, or that dies before doing so. + */ + if (dataEnabled[APN_MMS_ID]) { + removeMessages(EVENT_RESTORE_DEFAULT_APN); + sendMessageDelayed(obtainMessage(EVENT_RESTORE_DEFAULT_APN), + getRestoreDefaultApnDelay()); + } + if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { + SystemProperties.set("gsm.defaultpdpcontext.active", "true"); + } else { + SystemProperties.set("gsm.defaultpdpcontext.active", "false"); + } + notifyDefaultData(); - onPdpStateChanged(ar, true); - break; + // TODO: For simultaneous PDP support, we need to build another + // trigger another TRY_SETUP_DATA for the next APN type. (Note + // that the existing connection may service that type, in which + // case we should try the next type, etc. + } else { + PdpConnection.FailCause cause; + cause = (PdpConnection.FailCause) (ar.result); + if(DBG) log("PDP setup failed " + cause); - case EVENT_POLL_PDP: - /* See comment in startPeriodicPdpPoll */ - ar = (AsyncResult) msg.obj; + // No try for permanent failure + if (cause.isPermanentFail()) { + notifyNoData(cause); + } - if (!(state == State.CONNECTED)) { - // not connected; don't poll anymore - break; + if (tryNextApn(cause)) { + waitingApns.remove(0); + if (waitingApns.isEmpty()) { + // No more to try, start delayed retry + notifyNoData(cause); + reconnectAfterFail(cause); + } else { + // we still have more apns to try + setState(State.SCANNING); + trySetupData(null); } + } else { + notifyNoData(cause); + reconnectAfterFail(cause); + } + } + } - phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); - - sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), - POLL_PDP_MILLIS); - break; + protected void onDisconnectDone() { + if(DBG) log("EVENT_DISCONNECT_DONE"); + trySetupData(null); + } - case EVENT_VOICE_CALL_STARTED: - if (state == State.CONNECTED && - !phone.mSST.isConcurrentVoiceAndData()) { - stopNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); - } - break; - - case EVENT_VOICE_CALL_ENDED: - // in case data setup was attempted when we were on a voice call - trySetupData(Phone.REASON_VOICE_CALL_ENDED); - if (state == State.CONNECTED && - !phone.mSST.isConcurrentVoiceAndData()) { - startNetStatPoll(); - phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); - } else { - // clean slate after call end. - resetPollStats(); - } - break; + protected void onPollPdp() { + if (state == State.CONNECTED) { + // only poll when connected + phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE)); + sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS); + } + } - case EVENT_START_NETSTAT_POLL: - mPingTestActive = false; - startNetStatPoll(); - break; + protected void onVoiceCallStarted() { + if (state == State.CONNECTED && !((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) { + stopNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED); + } + } - case EVENT_START_RECOVERY: - mPingTestActive = false; - doRecovery(); - break; + protected void onVoiceCallEnded() { + // in case data setup was attempted when we were on a voice call + trySetupData(Phone.REASON_VOICE_CALL_ENDED); + if (state == State.CONNECTED && !((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) { + startNetStatPoll(); + phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED); + } else { + // clean slate after call end. + resetPollStats(); } } - private boolean tryNextApn(PdpFailCause cause) { - return (cause != PdpFailCause.RADIO_NOT_AVIALABLE) - && (cause != PdpFailCause.RADIO_OFF) - && (cause != PdpFailCause.RADIO_ERROR_RETRY) - && (cause != PdpFailCause.NO_SIGNAL) - && (cause != PdpFailCause.SIM_LOCKED); + private boolean tryNextApn(FailCause cause) { + return (cause != FailCause.RADIO_NOT_AVAILABLE) + && (cause != FailCause.RADIO_OFF) + && (cause != FailCause.RADIO_ERROR_RETRY) + && (cause != FailCause.NO_SIGNAL) + && (cause != FailCause.SIM_LOCKED); } private int getRestoreDefaultApnDelay() { @@ -1427,7 +1157,7 @@ final class DataConnectionTracker extends Handler */ private void createAllApnList() { allApns = new ArrayList<ApnSetting>(); - String operator = phone.mSIMRecords.getSIMOperatorNumeric(); + String operator = ((GSMPhone) phone).mSIMRecords.getSIMOperatorNumeric(); if (operator != null) { String selection = "numeric = '" + operator + "'"; @@ -1438,7 +1168,7 @@ final class DataConnectionTracker extends Handler if (cursor != null) { if (cursor.getCount() > 0) { allApns = createApnList(cursor); - // TODO: Figure out where this fits in. This basically just + // TODO: Figure out where this fits in. This basically just // writes the pap-secrets file. No longer tied to PdpConnection // object. Not used on current platform (no ppp). //PdpConnection pdp = pdpList.get(pdp_name); @@ -1452,20 +1182,27 @@ final class DataConnectionTracker extends Handler if (allApns.isEmpty()) { if (DBG) log("No APN found for carrier: " + operator); - notifyNoData(PdpConnection.PdpFailCause.BAD_APN); + notifyNoData(PdpConnection.FailCause.BAD_APN); } } private void createAllPdpList() { - pdpList = new ArrayList<PdpConnection>(); - PdpConnection pdp; + pdpList = new ArrayList<DataConnection>(); + DataConnection pdp; for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) { - pdp = new PdpConnection(phone); + pdp = new PdpConnection((GSMPhone) phone); pdpList.add(pdp); } } + private void destroyAllPdpList() { + if(pdpList != null) { + PdpConnection pdp; + pdpList.removeAll(pdpList); + } + } + /** * * @return waitingApns list to be used to create PDP @@ -1485,7 +1222,7 @@ final class DataConnectionTracker extends Handler } /** - * Get next apn in waitingApns + * Get next apn in waitingApns * @return the first apn found in waitingApns, null if none */ private ApnSetting getNextApn() { @@ -1509,4 +1246,61 @@ final class DataConnectionTracker extends Handler } return result.toString(); } + + public void handleMessage (Message msg) { + + switch (msg.what) { + case EVENT_RECORDS_LOADED: + onRecordsLoaded(); + break; + + case EVENT_ENABLE_NEW_APN: + onEnableNewApn(); + break; + + case EVENT_RESTORE_DEFAULT_APN: + onRestoreDefaultApn(); + break; + + case EVENT_GPRS_DETACHED: + onGprsDetached(); + break; + + case EVENT_GPRS_ATTACHED: + onGprsAttached(); + break; + + case EVENT_DATA_STATE_CHANGED: + onPdpStateChanged((AsyncResult) msg.obj, false); + break; + + case EVENT_GET_PDP_LIST_COMPLETE: + onPdpStateChanged((AsyncResult) msg.obj, true); + break; + + case EVENT_POLL_PDP: + onPollPdp(); + break; + + case EVENT_START_NETSTAT_POLL: + mPingTestActive = false; + startNetStatPoll(); + break; + + case EVENT_START_RECOVERY: + mPingTestActive = false; + doRecovery(); + break; + + default: + // handle the message in the super class DataConnectionTracker + super.handleMessage(msg); + break; + } + } + + protected void log(String s) { + Log.d(LOG_TAG, "[GsmtaConnectionTracker] " + s); + } + } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java index 2ac0ef5dea19..9fb1ce9b4128 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java @@ -20,14 +20,16 @@ import android.content.Context; import com.android.internal.telephony.*; import android.os.*; -import android.util.Log; -import java.util.regex.Pattern; -import java.util.regex.Matcher; +import android.telephony.PhoneNumberUtils; import android.text.SpannableStringBuilder; import android.text.TextUtils; -import android.telephony.PhoneNumberUtils; +import android.util.Log; + import static com.android.internal.telephony.CommandsInterface.*; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + /** * The motto for this file is: * @@ -41,15 +43,15 @@ public final class GsmMmiCode extends Handler implements MmiCode { static final String LOG_TAG = "GSM"; //***** Constants - + // From TS 22.030 6.5.2 static final String ACTION_ACTIVATE = "*"; static final String ACTION_DEACTIVATE = "#"; static final String ACTION_INTERROGATE = "*#"; static final String ACTION_REGISTER = "**"; static final String ACTION_ERASURE = "##"; - - // Supp Service cocdes from TS 22.030 Annex B + + // Supp Service cocdes from TS 22.030 Annex B //Called line presentation static final String SC_CLIP = "30"; @@ -101,25 +103,24 @@ public final class GsmMmiCode extends Handler implements MmiCode { GSMPhone phone; Context context; - + String action; // One of ACTION_* String sc; // Service Code String sia, sib, sic; // Service Info a,b,c String poundString; // Entire MMI string up to and including # String dialingNumber; String pwd; // For password registration - - /** Set to true in processCode, not at newFromDialString time */ + /** Set to true in processCode, not at newFromDialString time */ private boolean isPendingUSSD; private boolean isUssdRequest; - State state = State.PENDING; + State state = State.PENDING; CharSequence message; - + //***** Class Variables - + // See TS 22.030 6.5.2 "Structure of the MMI" @@ -136,9 +137,9 @@ public final class GsmMmiCode extends Handler implements MmiCode { 10 = dialing number */ - static final int MATCH_GROUP_POUND_STRING = 1; + static final int MATCH_GROUP_POUND_STRING = 1; - static final int MATCH_GROUP_ACTION = 2; + static final int MATCH_GROUP_ACTION = 2; //(activation/interrogation/registration/erasure) static final int MATCH_GROUP_SERVICE_CODE = 3; @@ -150,7 +151,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { //***** Public Class methods - + /** * Some dial strings in GSM are defined to do non-call setup * things, such as modify or query supplementry service settings (eg, call @@ -164,7 +165,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { * Please see flow chart in TS 22.030 6.5.3.2 */ - static GsmMmiCode + static GsmMmiCode newFromDialString(String dialString, GSMPhone phone) { Matcher m; GsmMmiCode ret = null; @@ -185,7 +186,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { } else if (dialString.endsWith("#")) { // TS 22.030 sec 6.5.3.2 - // "Entry of any characters defined in the 3GPP TS 23.038 [8] Default Alphabet + // "Entry of any characters defined in the 3GPP TS 23.038 [8] Default Alphabet // (up to the maximum defined in 3GPP TS 24.080 [10]), followed by #SEND". ret = new GsmMmiCode(phone); @@ -195,12 +196,12 @@ public final class GsmMmiCode extends Handler implements MmiCode { ret = new GsmMmiCode(phone); ret.dialingNumber = dialString; } - + return ret; } static GsmMmiCode - newNetworkInitiatedUssd (String ussdMessage, + newNetworkInitiatedUssd (String ussdMessage, boolean isUssdRequest, GSMPhone phone) { GsmMmiCode ret; @@ -208,7 +209,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { ret.message = ussdMessage; ret.isUssdRequest = isUssdRequest; - + // If it's a request, set to PENDING so that it's cancelable. if (isUssdRequest) { ret.isPendingUSSD = true; @@ -222,18 +223,18 @@ public final class GsmMmiCode extends Handler implements MmiCode { static GsmMmiCode newFromUssdUserInput(String ussdMessge, GSMPhone phone) { GsmMmiCode ret = new GsmMmiCode(phone); - + ret.message = ussdMessge; ret.state = State.PENDING; ret.isPendingUSSD = true; - + return ret; } //***** Private Class methods - /** make empty strings be null. - * Regexp returns empty strings for empty groups + /** make empty strings be null. + * Regexp returns empty strings for empty groups */ private static String makeEmptyNull (String s) { @@ -243,7 +244,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { } /** returns true of the string is empty or null */ - private static boolean + private static boolean isEmptyOrNull(CharSequence s) { return s == null || (s.length() == 0); } @@ -251,10 +252,10 @@ public final class GsmMmiCode extends Handler implements MmiCode { private static int scToCallForwardReason(String sc) { - if (sc == null) { + if (sc == null) { throw new RuntimeException ("invalid call forward sc"); } - + if (sc.equals(SC_CF_All)) { return CommandsInterface.CF_REASON_ALL; } else if (sc.equals(SC_CFU)) { @@ -292,7 +293,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { /* Note for code 20: From TS 22.030 Annex C: - "All GPRS bearer services" are not included in "All tele and bearer services" + "All GPRS bearer services" are not included in "All tele and bearer services" and "All bearer services"." ....so SERVICE_CLASS_DATA, which (according to 27.007) includes GPRS */ @@ -323,29 +324,29 @@ public final class GsmMmiCode extends Handler implements MmiCode { static boolean isServiceCodeCallForwarding(String sc) { - return sc != null && - (sc.equals(SC_CFU) - || sc.equals(SC_CFB) || sc.equals(SC_CFNRy) - || sc.equals(SC_CFNR) || sc.equals(SC_CF_All) + return sc != null && + (sc.equals(SC_CFU) + || sc.equals(SC_CFB) || sc.equals(SC_CFNRy) + || sc.equals(SC_CFNR) || sc.equals(SC_CF_All) || sc.equals(SC_CF_All_Conditional)); } static boolean isServiceCodeCallBarring(String sc) { return sc != null && - (sc.equals(SC_BAOC) + (sc.equals(SC_BAOC) || sc.equals(SC_BAOIC) || sc.equals(SC_BAOICxH) || sc.equals(SC_BAIC) || sc.equals(SC_BAICr) || sc.equals(SC_BA_ALL) || sc.equals(SC_BA_MO) - || sc.equals(SC_BA_MT)); + || sc.equals(SC_BA_MT)); } static String scToBarringFacility(String sc) { - if (sc == null) { + if (sc == null) { throw new RuntimeException ("invalid call barring sc"); } @@ -375,7 +376,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { GsmMmiCode (GSMPhone phone) { // The telephony unit-test cases may create GsmMmiCode's // in secondary threads - super(phone.h.getLooper()); + super(phone.getHandler().getLooper()); this.phone = phone; this.context = phone.getContext(); } @@ -408,7 +409,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { * cancel it. */ phone.mCM.cancelPendingUssd(obtainMessage(EVENT_USSD_CANCEL_COMPLETE, this)); - + /* * Don't call phone.onMMIDone here; wait for CANCEL_COMPLETE notice * from RIL. @@ -421,7 +422,6 @@ public final class GsmMmiCode extends Handler implements MmiCode { phone.onMMIDone (this); } - } public boolean isCancelable() { @@ -430,7 +430,6 @@ public final class GsmMmiCode extends Handler implements MmiCode { } //***** Instance Methods - /** Does this dial string contain a structured or unstructured MMI code? */ boolean @@ -441,7 +440,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { /* Is this a 1 or 2 digit "short code" as defined in TS 22.030 sec 6.5.3.2? */ boolean isShortCode() { - return poundString == null + return poundString == null && dialingNumber != null && dialingNumber.length() <= 2; } @@ -462,7 +461,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { * for treating "0" and "00" as call setup strings. */ || dialString.equals("0") - || dialString.equals("00")))); + || dialString.equals("00")))); } /** * @return true if the Service Code is PIN/PIN2/PUK/PUK2-related @@ -472,15 +471,15 @@ public final class GsmMmiCode extends Handler implements MmiCode { || sc.equals(SC_PUK) || sc.equals(SC_PUK2)); } - /** + /** * *See TS 22.030 Annex B - * In temporary mode, to suppress CLIR for a single call, enter: + * In temporary mode, to suppress CLIR for a single call, enter: * " * 31 # <called number> SEND " - * In temporary mode, to invoke CLIR for a single call enter: + * In temporary mode, to invoke CLIR for a single call enter: * " # 31 # <called number> SEND " */ - - boolean + + boolean isTemporaryModeCLIR() { return sc != null && sc.equals(SC_CLIR) && dialingNumber != null && (isActivate() || isDeactivate()); @@ -496,13 +495,13 @@ public final class GsmMmiCode extends Handler implements MmiCode { if (isActivate()) { return CommandsInterface.CLIR_SUPPRESSION; } else if (isDeactivate()) { - return CommandsInterface.CLIR_INVOCATION; + return CommandsInterface.CLIR_INVOCATION; } } - + return CommandsInterface.CLIR_DEFAULT; } - + boolean isActivate() { return action != null && action.equals(ACTION_ACTIVATE); } @@ -510,7 +509,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { boolean isDeactivate() { return action != null && action.equals(ACTION_DEACTIVATE); } - + boolean isInterrogate() { return action != null && action.equals(ACTION_INTERROGATE); } @@ -523,7 +522,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { return action != null && action.equals(ACTION_ERASURE); } - /** + /** * Returns true if this is a USSD code that's been submitted to the * network...eg, after processCode() is called */ @@ -547,7 +546,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { // We should have no dialing numbers here throw new RuntimeException ("Invalid or Unsupported MMI Code"); } else if (sc != null && sc.equals(SC_CLIP)) { - Log.d(LOG_TAG, "is CLIP"); + Log.d(LOG_TAG, "is CLIP"); if (isInterrogate()) { phone.mCM.queryCLIP( obtainMessage(EVENT_QUERY_COMPLETE, this)); @@ -555,7 +554,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { throw new RuntimeException ("Invalid or Unsupported MMI Code"); } } else if (sc != null && sc.equals(SC_CLIR)) { - Log.d(LOG_TAG, "is CLIR"); + Log.d(LOG_TAG, "is CLIR"); if (isActivate()) { phone.mCM.setCLIR(CommandsInterface.CLIR_INVOCATION, obtainMessage(EVENT_SET_COMPLETE, this)); @@ -605,7 +604,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { || (cfAction == CommandsInterface.CF_ACTION_REGISTRATION)) ? 1 : 0; phone.mCM.setCallForward(cfAction, reason, - serviceClass, dialingNumber, time, + serviceClass, dialingNumber, time, obtainMessage(EVENT_SET_CFF_COMPLETE, isSettingUnconditionalVoice, isEnableDesired, @@ -622,7 +621,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { if (isInterrogate()) { phone.mCM.queryFacilityLock(facility, password, serviceClass, obtainMessage(EVENT_QUERY_COMPLETE, this)); - } else if (isActivate() || isDeactivate()) { + } else if (isActivate() || isDeactivate()) { phone.mCM.setFacilityLock(facility, isActivate(), password, serviceClass, obtainMessage(EVENT_SET_COMPLETE, this)); } else { @@ -713,7 +712,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { state = State.FAILED; message = context.getText(com.android.internal.R.string.mmiError); phone.onMMIDone(this); - } + } } private void handlePasswordError(int res) { @@ -725,8 +724,8 @@ public final class GsmMmiCode extends Handler implements MmiCode { phone.onMMIDone(this); } - /** - * Called from GSMPhone + /** + * Called from GSMPhone * * An unsolicited USSD NOTIFY or REQUEST has come in matching * up with this pending USSD request @@ -752,8 +751,8 @@ public final class GsmMmiCode extends Handler implements MmiCode { } } - /** - * Called from GSMPhone + /** + * Called from GSMPhone * * The radio has reset, and this is still pending */ @@ -776,8 +775,8 @@ public final class GsmMmiCode extends Handler implements MmiCode { // response does not complete this MMI code...we wait for // an unsolicited USSD "Notify" or "Request". // The matching up of this is doene in GSMPhone. - - phone.mCM.sendUSSD(ussdMessage, + + phone.mCM.sendUSSD(ussdMessage, obtainMessage(EVENT_USSD_COMPLETE, this)); } @@ -832,13 +831,13 @@ public final class GsmMmiCode extends Handler implements MmiCode { com.android.internal.R.string.mmiError); phone.onMMIDone(this); - } + } // Note that unlike most everything else, the USSD complete // response does not complete this MMI code...we wait for // an unsolicited USSD "Notify" or "Request". // The matching up of this is done in GSMPhone. - + break; case EVENT_USSD_CANCEL_COMPLETE: @@ -962,35 +961,35 @@ public final class GsmMmiCode extends Handler implements MmiCode { com.android.internal.R.string.serviceNotProvisioned)); state = State.COMPLETE; break; - + case 1: // CLIR provisioned in permanent mode sb.append(context.getText( com.android.internal.R.string.CLIRPermanent)); state = State.COMPLETE; break; - case 2: // unknown (e.g. no network, etc.) + case 2: // unknown (e.g. no network, etc.) sb.append(context.getText( com.android.internal.R.string.mmiError)); state = State.FAILED; break; - case 3: // CLIR temporary mode presentation restricted + case 3: // CLIR temporary mode presentation restricted // the 'n' parameter from TS 27.007 7.7 switch (clirArgs[0]) { default: case 0: // Default sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOnNextCallOn)); + com.android.internal.R.string.CLIRDefaultOnNextCallOn)); break; case 1: // CLIR invocation sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOnNextCallOn)); + com.android.internal.R.string.CLIRDefaultOnNextCallOn)); break; case 2: // CLIR suppression sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOnNextCallOff)); + com.android.internal.R.string.CLIRDefaultOnNextCallOff)); break; } state = State.COMPLETE; @@ -1002,21 +1001,21 @@ public final class GsmMmiCode extends Handler implements MmiCode { default: case 0: // Default sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOffNextCallOff)); + com.android.internal.R.string.CLIRDefaultOffNextCallOff)); break; case 1: // CLIR invocation sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOffNextCallOn)); + com.android.internal.R.string.CLIRDefaultOffNextCallOn)); break; case 2: // CLIR suppression sb.append(context.getText( - com.android.internal.R.string.CLIRDefaultOffNextCallOff)); + com.android.internal.R.string.CLIRDefaultOffNextCallOff)); break; } state = State.COMPLETE; break; - } + } } message = sb; @@ -1025,7 +1024,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { /** * @param serviceClass 1 bit of the service class bit vectory - * @return String to be used for call forward query MMI response text. + * @return String to be used for call forward query MMI response text. * Returns null if unrecognized */ @@ -1065,7 +1064,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { // CF_REASON_NO_REPLY also has a time value associated with // it. All others don't. - needTimeTemplate = + needTimeTemplate = (info.reason == CommandsInterface.CF_REASON_NO_REPLY); if (info.status == 1) { @@ -1093,8 +1092,8 @@ public final class GsmMmiCode extends Handler implements MmiCode { } // In the template (from strings.xmls) - // {0} is one of "bearerServiceCode*" - // {1} is dialing number + // {0} is one of "bearerServiceCode*" + // {1} is dialing number // {2} is time in seconds destinations[0] = serviceClassToCFString(info.serviceClass & serviceClassMask); @@ -1122,7 +1121,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { sb.append(context.getText(com.android.internal.R.string.mmiError)); } else { CallForwardInfo infos[]; - + infos = (CallForwardInfo[]) ar.result; if (infos.length == 0) { @@ -1136,18 +1135,18 @@ public final class GsmMmiCode extends Handler implements MmiCode { SpannableStringBuilder tb = new SpannableStringBuilder(); // Each bit in the service class gets its own result line - // The service classes may be split up over multiple + // The service classes may be split up over multiple // CallForwardInfos. So, for each service classs, find out // which CallForwardInfo represents it and then build // the response text based on that - for (int serviceClassMask = 1 + for (int serviceClassMask = 1 ; serviceClassMask <= SERVICE_CLASS_MAX - ; serviceClassMask <<= 1 + ; serviceClassMask <<= 1 ) { for (int i = 0, s = infos.length; i < s ; i++) { if ((serviceClassMask & infos[i].serviceClass) != 0) { - tb.append(makeCFQueryResultMessage(infos[i], + tb.append(makeCFQueryResultMessage(infos[i], serviceClassMask)); tb.append("\n"); } @@ -1161,7 +1160,7 @@ public final class GsmMmiCode extends Handler implements MmiCode { message = sb; phone.onMMIDone(this); - + } private void @@ -1197,15 +1196,15 @@ public final class GsmMmiCode extends Handler implements MmiCode { message = sb; phone.onMMIDone(this); } - + private CharSequence createQueryCallWaitingResultMessage(int serviceClass) { - StringBuilder sb = + StringBuilder sb = new StringBuilder(context.getText(com.android.internal.R.string.serviceEnabledFor)); - for (int classMask = 1 + for (int classMask = 1 ; classMask <= SERVICE_CLASS_MAX - ; classMask <<= 1 + ; classMask <<= 1 ) { if ((classMask & serviceClass) != 0) { sb.append("\n"); @@ -1214,12 +1213,12 @@ public final class GsmMmiCode extends Handler implements MmiCode { } return sb; } - + /*** * TODO: It would be nice to have a method here that can take in a dialstring and * figure out if there is an MMI code embedded within it. This code would replace - * some of the string parsing functionality in the Phone App's - * SpecialCharSequenceMgr class. + * some of the string parsing functionality in the Phone App's + * SpecialCharSequenceMgr class. */ } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java new file mode 100644 index 000000000000..e8b9fdcc6ef5 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java @@ -0,0 +1,259 @@ +/* + * 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.gsm; + +import android.app.Activity; +import android.app.PendingIntent; +import android.app.PendingIntent.CanceledException; +import android.content.Intent; +import android.os.AsyncResult; +import android.os.Message; +import android.util.Config; +import android.util.Log; + +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.gsm.SmsMessage; +import com.android.internal.telephony.SMSDispatcher; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; + +import java.util.ArrayList; +import java.util.HashMap; + + +final class GsmSMSDispatcher extends SMSDispatcher { + private static final String TAG = "GSM"; + + GsmSMSDispatcher(GSMPhone phone) { + super(phone); + } + + /** + * Called when a status report is received. This should correspond to + * a previously successful SEND. + * + * @param ar AsyncResult passed into the message handler. ar.result should + * be a String representing the status report PDU, as ASCII hex. + */ + protected void handleStatusReport(AsyncResult ar) { + String pduString = (String) ar.result; + SmsMessage sms = SmsMessage.newFromCDS(pduString); + + if (sms != null) { + int messageRef = sms.messageRef; + for (int i = 0, count = deliveryPendingList.size(); i < count; i++) { + SmsTracker tracker = deliveryPendingList.get(i); + if (tracker.mMessageRef == messageRef) { + // Found it. Remove from list and broadcast. + deliveryPendingList.remove(i); + PendingIntent intent = tracker.mDeliveryIntent; + Intent fillIn = new Intent(); + fillIn.putExtra("pdu", IccUtils.hexStringToBytes(pduString)); + try { + intent.send(mContext, Activity.RESULT_OK, fillIn); + } catch (CanceledException ex) {} + + // Only expect to see one tracker matching this messageref + break; + } + } + } + + if (mCm != null) { + mCm.acknowledgeLastIncomingSMS(true, null); + } + } + + + /** + * Dispatches an incoming SMS messages. + * + * @param sms the incoming message from the phone + */ + protected void dispatchMessage(SmsMessageBase smsb) { + SmsMessage sms = (SmsMessage) smsb; + boolean handled = false; + + // Special case the message waiting indicator messages + if (sms.isMWISetMessage()) { + ((GSMPhone) mPhone).updateMessageWaitingIndicator(true); + + if (sms.isMwiDontStore()) { + handled = true; + } + + if (Config.LOGD) { + Log.d(TAG, + "Received voice mail indicator set SMS shouldStore=" + + !handled); + } + } else if (sms.isMWIClearMessage()) { + ((GSMPhone) mPhone).updateMessageWaitingIndicator(false); + + if (sms.isMwiDontStore()) { + handled = true; + } + + if (Config.LOGD) { + Log.d(TAG, + "Received voice mail indicator clear SMS shouldStore=" + + !handled); + } + } + + if (handled) { + return; + } + + // Parse the headers to see if this is partial, or port addressed + int referenceNumber = -1; + int count = 0; + int sequence = 0; + int destPort = -1; + + SmsHeader header = sms.getUserDataHeader(); + if (header != null) { + for (SmsHeader.Element element : header.getElements()) { + switch (element.getID()) { + case SmsHeader.CONCATENATED_8_BIT_REFERENCE: { + byte[] data = element.getData(); + + referenceNumber = data[0] & 0xff; + count = data[1] & 0xff; + sequence = data[2] & 0xff; + + break; + } + + case SmsHeader.CONCATENATED_16_BIT_REFERENCE: { + byte[] data = element.getData(); + + referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff); + count = data[2] & 0xff; + sequence = data[3] & 0xff; + + break; + } + + case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: { + byte[] data = element.getData(); + + destPort = (data[0] & 0xff) << 8; + destPort |= (data[1] & 0xff); + + break; + } + } + } + } + + if (referenceNumber == -1) { + // notify everyone of the message if it isn't partial + byte[][] pdus = new byte[1][]; + pdus[0] = sms.getPdu(); + + if (destPort != -1) { + if (destPort == SmsHeader.PORT_WAP_PUSH) { + dispatchWapPdu(sms.getUserData()); + } + // The message was sent to a port, so concoct a URI for it + dispatchPortAddressedPdus(pdus, destPort); + } else { + // It's a normal message, dispatch it + dispatchPdus(pdus); + } + } else { + // Process the message part + processMessagePart(sms, referenceNumber, sequence, count, destPort); + } + } + + /** {@inheritDoc} */ + protected void sendMultipartText(String destinationAddress, String scAddress, + ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, + ArrayList<PendingIntent> deliveryIntents) { + + int ref = ++sConcatenatedRef & 0xff; + + for (int i = 0, count = parts.size(); i < count; i++) { + // build SmsHeader + byte[] data = new byte[3]; + data[0] = (byte) ref; // reference #, unique per message + data[1] = (byte) count; // total part count + data[2] = (byte) (i + 1); // 1-based sequence + SmsHeader header = new SmsHeader(); + header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data)); + PendingIntent sentIntent = null; + PendingIntent deliveryIntent = null; + + if (sentIntents != null && sentIntents.size() > i) { + sentIntent = sentIntents.get(i); + } + if (deliveryIntents != null && deliveryIntents.size() > i) { + deliveryIntent = deliveryIntents.get(i); + } + + SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress, + parts.get(i), deliveryIntent != null, header.toByteArray()); + + sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); + } + } + + /** {@inheritDoc} */ + protected void sendSms(SmsTracker tracker) { + HashMap map = tracker.mData; + + byte smsc[] = (byte[]) map.get("smsc"); + byte pdu[] = (byte[]) map.get("pdu"); + + Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker); + mCm.sendSMS(IccUtils.bytesToHexString(smsc), + IccUtils.bytesToHexString(pdu), reply); + } + + /** {@inheritDoc} */ + protected void acknowledgeLastIncomingSms(boolean success, Message response){ + // FIXME unit test leaves cm == null. this should change + if (mCm != null) { + mCm.acknowledgeLastIncomingSMS(success, response); + } + } + + /** {@inheritDoc} */ + protected void activateCellBroadcastSms(int activate, Message response) { + // Unless CBS is implemented for GSM, this point should be unreachable. + Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); + response.recycle(); + } + + /** {@inheritDoc} */ + protected void getCellBroadcastSmsConfig(Message response){ + // Unless CBS is implemented for GSM, this point should be unreachable. + Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); + response.recycle(); + } + + /** {@inheritDoc} */ + protected void setCellBroadcastConfig(int[] configValuesArray, Message response) { + // Unless CBS is implemented for GSM, this point should be unreachable. + Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM."); + response.recycle(); + } + +} + diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java index 2080df18e182..7c3c5598eab7 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java @@ -17,13 +17,13 @@ package com.android.internal.telephony.gsm; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA; +import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ALPHA; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISMANUAL; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_ALPHA; -import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC; import com.android.internal.telephony.Phone; import android.app.AlarmManager; import android.content.ContentResolver; @@ -47,6 +47,9 @@ import android.text.TextUtils; import android.util.Log; import android.util.TimeUtils; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.ServiceStateTracker; import com.android.internal.telephony.TelephonyIntents; @@ -90,7 +93,8 @@ final class GsmServiceStateTracker extends ServiceStateTracker { private boolean mZoneDst; private long mZoneTime; private boolean mGotCountryCode = false; - + private ContentResolver cr; + String mSavedTimeZone; long mSavedTime; long mSavedAtTime; @@ -107,9 +111,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker { //***** Constants static final boolean DBG = true; - static final String LOG_TAG = "GsmServiceStateTracker"; + static final String LOG_TAG = "GSM"; + - private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { @@ -131,7 +135,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { cellLoc = new GsmCellLocation(); newCellLoc = new GsmCellLocation(); - cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); + cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null); cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null); cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null); @@ -139,21 +143,37 @@ final class GsmServiceStateTracker extends ServiceStateTracker { cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null); cm.registerForSIMReady(this, EVENT_SIM_READY, null); - + // system setting property AIRPLANE_MODE_ON is set in Settings. int airplaneMode = Settings.System.getInt( phone.getContext().getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0); - mDesiredPowerState = ! (airplaneMode > 0); + mDesiredPowerState = ! (airplaneMode > 0); - ContentResolver cr = phone.getContext().getContentResolver(); + cr = phone.getContext().getContentResolver(); cr.registerContentObserver( - Settings.System.getUriFor(Settings.System.AUTO_TIME), true, + Settings.System.getUriFor(Settings.System.AUTO_TIME), true, mAutoTimeObserver); setRssiDefaultValues(); mNeedToRegForSimLoaded = true; } + public void dispose() { + //Unregister for all events + cm.unregisterForAvailable(this); + cm.unregisterForRadioStateChanged(this); + cm.unregisterForNetworkStateChanged(this); + cm.unregisterForSIMReady(this); + phone.mSIMRecords.unregisterForRecordsLoaded(this); + cm.unSetOnSignalStrengthUpdate(this); + cm.unSetOnNITZTime(this); + cr.unregisterContentObserver(this.mAutoTimeObserver); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "GsmServiceStateTracker finalized"); + } + /** * Registration point for transition into GPRS attached. * @param h handler to notify @@ -170,14 +190,21 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } } + /*protected*/ void unregisterForGprsAttached(Handler h) { + gprsAttachedRegistrants.remove(h); + } + void registerForNetworkAttach(Handler h, int what, Object obj) { Registrant r = new Registrant(h, what, obj); networkAttachedRegistrants.add(r); - + if (ss.getState() == ServiceState.STATE_IN_SERVICE) { r.notifyRegistrant(); } } + void unregisterForNetworkAttach(Handler h) { + networkAttachedRegistrants.remove(h); + } /** * Registration point for transition into GPRS detached. * @param h handler to notify @@ -193,7 +220,11 @@ final class GsmServiceStateTracker extends ServiceStateTracker { r.notifyRegistrant(); } } - + + /*protected*/ void unregisterForGprsDetached(Handler h) { + gprsDetachedRegistrants.remove(h); + } + //***** Called from GSMPhone public void getLacAndCid(Message onComplete) { @@ -243,18 +274,18 @@ final class GsmServiceStateTracker extends ServiceStateTracker { pollState(); break; - case EVENT_GET_SIGNAL_STRENGTH: + case EVENT_GET_SIGNAL_STRENGTH: // This callback is called when signal strength is polled // all by itself - if (!(cm.getRadioState().isOn())) { - // Polling will continue when radio turns back on + if (!(cm.getRadioState().isOn()) || (cm.getRadioState().isCdma())) { + // Polling will continue when radio turns back on and not CDMA return; } ar = (AsyncResult) msg.obj; onSignalStrengthResult(ar); queueNextSignalStrengthPoll(); - + break; case EVENT_GET_LOC_DONE: @@ -339,7 +370,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { getLacAndCid(null); } break; - + case EVENT_SET_PREFERRED_NETWORK_TYPE: ar = (AsyncResult) msg.obj; // Don't care the result, only use for dereg network (COPS=2) @@ -349,7 +380,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { case EVENT_RESET_PREFERRED_NETWORK_TYPE: ar = (AsyncResult) msg.obj; - if (ar.userObj != null) { //TODO check in Data Connectivity + if (ar.userObj != null) { AsyncResult.forMessage(((Message) ar.userObj)).exception = ar.exception; ((Message) ar.userObj).sendToTarget(); @@ -362,13 +393,11 @@ final class GsmServiceStateTracker extends ServiceStateTracker { if (ar.exception == null) { mPreferredNetworkType = ((int[])ar.result)[0]; } else { - mPreferredNetworkType = Phone.NT_GLOBAL_AUTO_TYPE; + mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL; } message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj); - int toggledNetworkType = Phone.NT_GLOBAL_AUTO_TYPE; - /*(mPreferredNetworkType == Phone.NT_AUTO_TYPE) ? - Phone.NT_GSM_TYPE : Phone.NT_AUTO_TYPE;*/ //TODO check in Data Connectivity + int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL; cm.setPreferredNetworkType(toggledNetworkType, message); break; @@ -382,7 +411,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { protected void updateSpnDisplay() { int rule = phone.mSIMRecords.getDisplayRule(ss.getOperatorNumeric()); - String spn = phone.mSIMRecords.getServiceProvideName(); + String spn = phone.mSIMRecords.getServiceProviderName(); String plmn = ss.getOperatorAlphaLong(); if (rule != curSpnRule @@ -479,7 +508,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { if (states.length > 0) { try { regState = Integer.parseInt(states[0]); - + // states[3] (if present) is the current radio technology if (states.length >= 4 && states[3] != null) { type = Integer.parseInt(states[3]); @@ -550,7 +579,6 @@ final class GsmServiceStateTracker extends ServiceStateTracker { pollStateDone(); break; - case RADIO_OFF: newSS.setStateOff(); newCellLoc.setStateInvalid(); @@ -560,6 +588,20 @@ final class GsmServiceStateTracker extends ServiceStateTracker { pollStateDone(); break; + case RUIM_NOT_READY: + case RUIM_READY: + case RUIM_LOCKED_OR_ABSENT: + case NV_NOT_READY: + case NV_READY: + log("Radio Technology Change ongoing, setting SS to off"); + newSS.setStateOff(); + newCellLoc.setStateInvalid(); + setRssiDefaultValues(); + mGotCountryCode = false; + + pollStateDone(); + break; + default: // Issue all poll-related commands at once // then count down the responses, which @@ -588,7 +630,8 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } } - private static String networkTypeToString(int type) { //Network Type from GPRS_REGISTRATION_STATE + private static String networkTypeToString(int type) { + //Network Type from GPRS_REGISTRATION_STATE String ret = "unknown"; switch (type) { @@ -603,7 +646,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { break; default: Log.e(LOG_TAG, "Wrong network type: " + Integer.toString(type)); - break; + break; } return ret; @@ -727,7 +770,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { if (zone != null) { Context context = phone.getContext(); if (getAutoTime()) { - AlarmManager alarm = + AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarm.setTimeZone(zone.getID()); } @@ -769,7 +812,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { phone.notifyLocationChanged(); } } - + /** * Returns a TimeZone object based only on parameters from the NITZ string. */ @@ -802,13 +845,13 @@ final class GsmServiceStateTracker extends ServiceStateTracker { break; } } - + return guess; } private void queueNextSignalStrengthPoll() { - if (dontPollSignalStrength) { + if (dontPollSignalStrength || (cm.getRadioState().isCdma())) { // The radio is telling us about signal strength changes // we don't have to ask it return; @@ -850,7 +893,13 @@ final class GsmServiceStateTracker extends ServiceStateTracker { } if (rssi != oldRSSI) { - phone.notifySignalStrength(); + try { // This takes care of delayed EVENT_POLL_SIGNAL_STRENGTH (scheduled after + // POLL_PERIOD_MILLIS) during Radio Technology Change) + phone.notifySignalStrength(); + } catch (NullPointerException ex) { + log("onSignalStrengthResult() Phone already destroyed: " + ex + + "Signal Stranth not notified"); + } } } @@ -897,7 +946,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { */ private boolean isRoamingBetweenOperators(boolean gsmRoaming, ServiceState s) { - String spn = SystemProperties.get(PROPERTY_SIM_OPERATOR_ALPHA, "empty"); + String spn = SystemProperties.get(PROPERTY_ICC_OPERATOR_ALPHA, "empty"); String onsl = s.getOperatorAlphaLong(); String onss = s.getOperatorAlphaShort(); @@ -905,9 +954,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker { boolean equalsOnsl = onsl != null && spn.equals(onsl); boolean equalsOnss = onss != null && spn.equals(onss); - String simNumeric = SystemProperties.get(PROPERTY_SIM_OPERATOR_NUMERIC, ""); + String simNumeric = SystemProperties.get(PROPERTY_ICC_OPERATOR_NUMERIC, ""); String operatorNumeric = s.getOperatorNumeric(); - + boolean equalsMcc = true; try { equalsMcc = simNumeric.substring(0, 3). @@ -1083,7 +1132,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker { if (zone != null) { Context context = phone.getContext(); if (getAutoTime()) { - AlarmManager alarm = + AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); alarm.setTimeZone(zone.getID()); } @@ -1144,26 +1193,26 @@ final class GsmServiceStateTracker extends ServiceStateTracker { return true; } } - + private void saveNitzTimeZone(String zoneId) { mSavedTimeZone = zoneId; - // Send out a sticky broadcast so the system can determine if + // Send out a sticky broadcast so the system can determine if // the timezone was set by the carrier... Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE); intent.putExtra("time-zone", zoneId); phone.getContext().sendStickyBroadcast(intent); } - + private void saveNitzTime(long time) { mSavedTime = time; mSavedAtTime = SystemClock.elapsedRealtime(); - // Send out a sticky broadcast so the system can determine if + // Send out a sticky broadcast so the system can determine if // the time was set by the carrier... Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME); intent.putExtra("time", time); phone.getContext().sendStickyBroadcast(intent); } - + private void revertToNitz() { if (Settings.System.getInt(phone.getContext().getContentResolver(), Settings.System.AUTO_TIME, 0) == 0) { @@ -1173,11 +1222,15 @@ final class GsmServiceStateTracker extends ServiceStateTracker { + "' mSavedTime=" + mSavedTime + " mSavedAtTime=" + mSavedAtTime); if (mSavedTimeZone != null && mSavedTime != 0 && mSavedAtTime != 0) { - AlarmManager alarm = + AlarmManager alarm = (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE); alarm.setTimeZone(mSavedTimeZone); - SystemClock.setCurrentTimeMillis(mSavedTime + SystemClock.setCurrentTimeMillis(mSavedTime + (SystemClock.elapsedRealtime() - mSavedAtTime)); } } + + protected void log(String s) { + Log.d(LOG_TAG, "[GsmServiceStateTracker] " + s); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java new file mode 100644 index 000000000000..c163803a6ff0 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java @@ -0,0 +1,148 @@ +/* + * 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.gsm; + +import android.telephony.PhoneNumberUtils; + +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsAddress; + +public class GsmSmsAddress extends SmsAddress { + + static final int OFFSET_ADDRESS_LENGTH = 0; + + static final int OFFSET_TOA = 1; + + static final int OFFSET_ADDRESS_VALUE = 2; + + /** + * New GsmSmsAddress from TS 23.040 9.1.2.5 Address Field + * + * @param offset the offset of the Address-Length byte + * @param length the length in bytes rounded up, e.g. "2 + + * (addressLength + 1) / 2" + */ + + public GsmSmsAddress(byte[] data, int offset, int length) { + origBytes = new byte[length]; + System.arraycopy(data, offset, origBytes, 0, length); + + // addressLength is the count of semi-octets, not bytes + int addressLength = origBytes[OFFSET_ADDRESS_LENGTH] & 0xff; + + int toa = origBytes[OFFSET_TOA] & 0xff; + ton = 0x7 & (toa >> 4); + + // TOA must have its high bit set + if ((toa & 0x80) != 0x80) { + throw new RuntimeException("Invalid TOA - high bit must be set"); + } + + if (isAlphanumeric()) { + // An alphanumeric address + int countSeptets = addressLength * 4 / 7; + + address = GsmAlphabet.gsm7BitPackedToString(origBytes, + OFFSET_ADDRESS_VALUE, countSeptets); + } else { + // TS 23.040 9.1.2.5 says + // that "the MS shall interpret reserved values as 'Unknown' + // but shall store them exactly as received" + + byte lastByte = origBytes[length - 1]; + + if ((addressLength & 1) == 1) { + // Make sure the final unused BCD digit is 0xf + origBytes[length - 1] |= 0xf0; + } + address = PhoneNumberUtils.calledPartyBCDToString(origBytes, + OFFSET_TOA, length - OFFSET_TOA); + + // And restore origBytes + origBytes[length - 1] = lastByte; + } + } + + public String getAddressString() { + return address; + } + + /** + * Returns true if this is an alphanumeric address + */ + public boolean isAlphanumeric() { + return ton == TON_ALPHANUMERIC; + } + + public boolean isNetworkSpecific() { + return ton == TON_NETWORK; + } + + /** + * Returns true of this is a valid CPHS voice message waiting indicator + * address + */ + public boolean isCphsVoiceMessageIndicatorAddress() { + // CPHS-style MWI message + // See CPHS 4.7 B.4.2.1 + // + // Basically: + // + // - Originating address should be 4 bytes long and alphanumeric + // - Decode will result with two chars: + // - Char 1 + // 76543210 + // ^ set/clear indicator (0 = clear) + // ^^^ type of indicator (000 = voice) + // ^^^^ must be equal to 0001 + // - Char 2: + // 76543210 + // ^ line number (0 = line 1) + // ^^^^^^^ set to 0 + // + // Remember, since the alpha address is stored in 7-bit compact form, + // the "line number" is really the top bit of the first address value + // byte + + return (origBytes[OFFSET_ADDRESS_LENGTH] & 0xff) == 4 + && isAlphanumeric() && (origBytes[OFFSET_TOA] & 0x0f) == 0; + } + + /** + * Returns true if this is a valid CPHS voice message waiting indicator + * address indicating a "set" of "indicator 1" of type "voice message + * waiting" + */ + public boolean isCphsVoiceMessageSet() { + // 0x11 means "set" "voice message waiting" "indicator 1" + return isCphsVoiceMessageIndicatorAddress() + && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x11; + + } + + /** + * Returns true if this is a valid CPHS voice message waiting indicator + * address indicating a "clear" of "indicator 1" of type "voice message + * waiting" + */ + public boolean isCphsVoiceMessageClear() { + // 0x10 means "clear" "voice message waiting" "indicator 1" + return isCphsVoiceMessageIndicatorAddress() + && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x10; + + } +} diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java index 57aa01261ff8..07420e599892 100644 --- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java +++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java @@ -51,11 +51,11 @@ public final class MccTable entryForMcc(int mcc) { int index; - + MccEntry m; m = new MccEntry(mcc, null, 0); - + index = Collections.binarySearch(table, m); if (index < 0) { @@ -110,7 +110,7 @@ public final class MccTable /* * The table below is built from two resources: - * + * * 1) ITU "Mobile Network Code (MNC) for the international * identification plan for mobile terminals and mobile users" * which is available as an annex to the ITU operational bulletin @@ -123,238 +123,238 @@ public final class MccTable * * FIXME(mkf) this should be stored in a more efficient representation */ - - table.add(new MccEntry(202,"gr",2)); //Greece - table.add(new MccEntry(204,"nl",2)); //Netherlands (Kingdom of the) - table.add(new MccEntry(206,"be",2)); //Belgium - table.add(new MccEntry(208,"fr",2)); //France - table.add(new MccEntry(212,"mc",2)); //Monaco (Principality of) - table.add(new MccEntry(213,"ad",2)); //Andorra (Principality of) - table.add(new MccEntry(214,"es",2)); //Spain - table.add(new MccEntry(216,"hu",2)); //Hungary (Republic of) - table.add(new MccEntry(218,"ba",2)); //Bosnia and Herzegovina - table.add(new MccEntry(219,"hr",2)); //Croatia (Republic of) - table.add(new MccEntry(220,"rs",2)); //Serbia and Montenegro - table.add(new MccEntry(222,"it",2)); //Italy - table.add(new MccEntry(225,"va",2)); //Vatican City State - table.add(new MccEntry(226,"ro",2)); //Romania - table.add(new MccEntry(228,"ch",2)); //Switzerland (Confederation of) - table.add(new MccEntry(230,"cz",2)); //Czech Republic - table.add(new MccEntry(231,"sk",2)); //Slovak Republic - table.add(new MccEntry(232,"at",2)); //Austria - table.add(new MccEntry(234,"gb",2)); //United Kingdom of Great Britain and Northern Ireland - table.add(new MccEntry(235,"gb",2)); //United Kingdom of Great Britain and Northern Ireland - table.add(new MccEntry(238,"dk",2)); //Denmark - table.add(new MccEntry(240,"se",2)); //Sweden - table.add(new MccEntry(242,"no",2)); //Norway - table.add(new MccEntry(244,"fi",2)); //Finland - table.add(new MccEntry(246,"lt",2)); //Lithuania (Republic of) - table.add(new MccEntry(247,"lv",2)); //Latvia (Republic of) - table.add(new MccEntry(248,"ee",2)); //Estonia (Republic of) - table.add(new MccEntry(250,"ru",2)); //Russian Federation - table.add(new MccEntry(255,"ua",2)); //Ukraine - table.add(new MccEntry(257,"by",2)); //Belarus (Republic of) - table.add(new MccEntry(259,"md",2)); //Moldova (Republic of) - table.add(new MccEntry(260,"pl",2)); //Poland (Republic of) - table.add(new MccEntry(262,"de",2)); //Germany (Federal Republic of) - table.add(new MccEntry(266,"gi",2)); //Gibraltar - table.add(new MccEntry(268,"pt",2)); //Portugal - table.add(new MccEntry(270,"lu",2)); //Luxembourg - table.add(new MccEntry(272,"ie",2)); //Ireland - table.add(new MccEntry(274,"is",2)); //Iceland - table.add(new MccEntry(276,"al",2)); //Albania (Republic of) - table.add(new MccEntry(278,"mt",2)); //Malta - table.add(new MccEntry(280,"cy",2)); //Cyprus (Republic of) - table.add(new MccEntry(282,"ge",2)); //Georgia - table.add(new MccEntry(283,"am",2)); //Armenia (Republic of) - table.add(new MccEntry(284,"bg",2)); //Bulgaria (Republic of) - table.add(new MccEntry(286,"tr",2)); //Turkey - table.add(new MccEntry(288,"fo",2)); //Faroe Islands - table.add(new MccEntry(290,"gl",2)); //Greenland (Denmark) - table.add(new MccEntry(292,"sm",2)); //San Marino (Republic of) - table.add(new MccEntry(293,"sl",2)); //Slovenia (Republic of) + + table.add(new MccEntry(202,"gr",2)); //Greece + table.add(new MccEntry(204,"nl",2)); //Netherlands (Kingdom of the) + table.add(new MccEntry(206,"be",2)); //Belgium + table.add(new MccEntry(208,"fr",2)); //France + table.add(new MccEntry(212,"mc",2)); //Monaco (Principality of) + table.add(new MccEntry(213,"ad",2)); //Andorra (Principality of) + table.add(new MccEntry(214,"es",2)); //Spain + table.add(new MccEntry(216,"hu",2)); //Hungary (Republic of) + table.add(new MccEntry(218,"ba",2)); //Bosnia and Herzegovina + table.add(new MccEntry(219,"hr",2)); //Croatia (Republic of) + table.add(new MccEntry(220,"rs",2)); //Serbia and Montenegro + table.add(new MccEntry(222,"it",2)); //Italy + table.add(new MccEntry(225,"va",2)); //Vatican City State + table.add(new MccEntry(226,"ro",2)); //Romania + table.add(new MccEntry(228,"ch",2)); //Switzerland (Confederation of) + table.add(new MccEntry(230,"cz",2)); //Czech Republic + table.add(new MccEntry(231,"sk",2)); //Slovak Republic + table.add(new MccEntry(232,"at",2)); //Austria + table.add(new MccEntry(234,"gb",2)); //United Kingdom of Great Britain and Northern Ireland + table.add(new MccEntry(235,"gb",2)); //United Kingdom of Great Britain and Northern Ireland + table.add(new MccEntry(238,"dk",2)); //Denmark + table.add(new MccEntry(240,"se",2)); //Sweden + table.add(new MccEntry(242,"no",2)); //Norway + table.add(new MccEntry(244,"fi",2)); //Finland + table.add(new MccEntry(246,"lt",2)); //Lithuania (Republic of) + table.add(new MccEntry(247,"lv",2)); //Latvia (Republic of) + table.add(new MccEntry(248,"ee",2)); //Estonia (Republic of) + table.add(new MccEntry(250,"ru",2)); //Russian Federation + table.add(new MccEntry(255,"ua",2)); //Ukraine + table.add(new MccEntry(257,"by",2)); //Belarus (Republic of) + table.add(new MccEntry(259,"md",2)); //Moldova (Republic of) + table.add(new MccEntry(260,"pl",2)); //Poland (Republic of) + table.add(new MccEntry(262,"de",2)); //Germany (Federal Republic of) + table.add(new MccEntry(266,"gi",2)); //Gibraltar + table.add(new MccEntry(268,"pt",2)); //Portugal + table.add(new MccEntry(270,"lu",2)); //Luxembourg + table.add(new MccEntry(272,"ie",2)); //Ireland + table.add(new MccEntry(274,"is",2)); //Iceland + table.add(new MccEntry(276,"al",2)); //Albania (Republic of) + table.add(new MccEntry(278,"mt",2)); //Malta + table.add(new MccEntry(280,"cy",2)); //Cyprus (Republic of) + table.add(new MccEntry(282,"ge",2)); //Georgia + table.add(new MccEntry(283,"am",2)); //Armenia (Republic of) + table.add(new MccEntry(284,"bg",2)); //Bulgaria (Republic of) + table.add(new MccEntry(286,"tr",2)); //Turkey + table.add(new MccEntry(288,"fo",2)); //Faroe Islands + table.add(new MccEntry(290,"gl",2)); //Greenland (Denmark) + table.add(new MccEntry(292,"sm",2)); //San Marino (Republic of) + table.add(new MccEntry(293,"sl",2)); //Slovenia (Republic of) table.add(new MccEntry(294,"mk",2)); //The Former Yugoslav Republic of Macedonia - table.add(new MccEntry(295,"li",2)); //Liechtenstein (Principality of) - table.add(new MccEntry(302,"ca",2)); //Canada - table.add(new MccEntry(308,"pm",2)); //Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise) - table.add(new MccEntry(310,"us",3)); //United States of America - table.add(new MccEntry(311,"us",3)); //United States of America - table.add(new MccEntry(312,"us",3)); //United States of America - table.add(new MccEntry(313,"us",3)); //United States of America - table.add(new MccEntry(314,"us",3)); //United States of America - table.add(new MccEntry(315,"us",3)); //United States of America - table.add(new MccEntry(316,"us",3)); //United States of America - table.add(new MccEntry(330,"pr",2)); //Puerto Rico - table.add(new MccEntry(332,"vi",2)); //United States Virgin Islands - table.add(new MccEntry(334,"mx",3)); //Mexico - table.add(new MccEntry(338,"jm",3)); //Jamaica - table.add(new MccEntry(340,"gp",2)); //Guadeloupe (French Department of) - table.add(new MccEntry(342,"bb",3)); //Barbados - table.add(new MccEntry(344,"ag",3)); //Antigua and Barbuda - table.add(new MccEntry(346,"ky",3)); //Cayman Islands - table.add(new MccEntry(348,"vg",3)); //British Virgin Islands - table.add(new MccEntry(350,"bm",2)); //Bermuda - table.add(new MccEntry(352,"gd",2)); //Grenada - table.add(new MccEntry(354,"ms",2)); //Montserrat - table.add(new MccEntry(356,"kn",2)); //Saint Kitts and Nevis - table.add(new MccEntry(358,"lc",2)); //Saint Lucia - table.add(new MccEntry(360,"vc",2)); //Saint Vincent and the Grenadines - table.add(new MccEntry(362,"nl",2)); //Netherlands Antilles - table.add(new MccEntry(363,"aw",2)); //Aruba - table.add(new MccEntry(364,"bs",2)); //Bahamas (Commonwealth of the) - table.add(new MccEntry(365,"ai",3)); //Anguilla - table.add(new MccEntry(366,"dm",2)); //Dominica (Commonwealth of) - table.add(new MccEntry(368,"cu",2)); //Cuba - table.add(new MccEntry(370,"do",2)); //Dominican Republic - table.add(new MccEntry(372,"ht",2)); //Haiti (Republic of) - table.add(new MccEntry(374,"tt",2)); //Trinidad and Tobago - table.add(new MccEntry(376,"tc",2)); //Turks and Caicos Islands - table.add(new MccEntry(400,"az",2)); //Azerbaijani Republic - table.add(new MccEntry(401,"kz",2)); //Kazakhstan (Republic of) - table.add(new MccEntry(402,"bt",2)); //Bhutan (Kingdom of) - table.add(new MccEntry(404,"in",2)); //India (Republic of) - table.add(new MccEntry(405,"in",2)); //India (Republic of) - table.add(new MccEntry(410,"pk",2)); //Pakistan (Islamic Republic of) - table.add(new MccEntry(412,"af",2)); //Afghanistan - table.add(new MccEntry(413,"lk",2)); //Sri Lanka (Democratic Socialist Republic of) - table.add(new MccEntry(414,"mm",2)); //Myanmar (Union of) - table.add(new MccEntry(415,"lb",2)); //Lebanon - table.add(new MccEntry(416,"jo",2)); //Jordan (Hashemite Kingdom of) - table.add(new MccEntry(417,"sy",2)); //Syrian Arab Republic - table.add(new MccEntry(418,"iq",2)); //Iraq (Republic of) - table.add(new MccEntry(419,"kw",2)); //Kuwait (State of) - table.add(new MccEntry(420,"sa",2)); //Saudi Arabia (Kingdom of) - table.add(new MccEntry(421,"ye",2)); //Yemen (Republic of) - table.add(new MccEntry(422,"om",2)); //Oman (Sultanate of) - table.add(new MccEntry(424,"ae",2)); //United Arab Emirates - table.add(new MccEntry(425,"il",2)); //Israel (State of) - table.add(new MccEntry(426,"bh",2)); //Bahrain (Kingdom of) - table.add(new MccEntry(427,"qa",2)); //Qatar (State of) - table.add(new MccEntry(428,"mn",2)); //Mongolia - table.add(new MccEntry(429,"np",2)); //Nepal - table.add(new MccEntry(430,"ae",2)); //United Arab Emirates - table.add(new MccEntry(431,"ae",2)); //United Arab Emirates - table.add(new MccEntry(432,"ir",2)); //Iran (Islamic Republic of) - table.add(new MccEntry(434,"uz",2)); //Uzbekistan (Republic of) - table.add(new MccEntry(436,"tj",2)); //Tajikistan (Republic of) - table.add(new MccEntry(437,"kg",2)); //Kyrgyz Republic - table.add(new MccEntry(438,"tm",2)); //Turkmenistan - table.add(new MccEntry(440,"jp",2)); //Japan - table.add(new MccEntry(441,"jp",2)); //Japan - table.add(new MccEntry(450,"kr",2)); //Korea (Republic of) - table.add(new MccEntry(452,"vn",2)); //Viet Nam (Socialist Republic of) - table.add(new MccEntry(454,"hk",2)); //"Hong Kong, China" - table.add(new MccEntry(455,"mo",2)); //"Macao, China" - table.add(new MccEntry(456,"kh",2)); //Cambodia (Kingdom of) - table.add(new MccEntry(457,"la",2)); //Lao People's Democratic Republic - table.add(new MccEntry(460,"cn",2)); //China (People's Republic of) - table.add(new MccEntry(461,"cn",2)); //China (People's Republic of) - table.add(new MccEntry(466,"tw",2)); //"Taiwan, China" - table.add(new MccEntry(467,"kp",2)); //Democratic People's Republic of Korea - table.add(new MccEntry(470,"bd",2)); //Bangladesh (People's Republic of) - table.add(new MccEntry(472,"mv",2)); //Maldives (Republic of) - table.add(new MccEntry(502,"my",2)); //Malaysia - table.add(new MccEntry(505,"au",2)); //Australia - table.add(new MccEntry(510,"id",2)); //Indonesia (Republic of) - table.add(new MccEntry(514,"tl",2)); //Democratic Republic of Timor-Leste - table.add(new MccEntry(515,"ph",2)); //Philippines (Republic of the) - table.add(new MccEntry(520,"th",2)); //Thailand - table.add(new MccEntry(525,"sg",2)); //Singapore (Republic of) - table.add(new MccEntry(528,"bn",2)); //Brunei Darussalam - table.add(new MccEntry(530,"nz",2)); //New Zealand - table.add(new MccEntry(534,"mp",2)); //Northern Mariana Islands (Commonwealth of the) - table.add(new MccEntry(535,"gu",2)); //Guam - table.add(new MccEntry(536,"nr",2)); //Nauru (Republic of) - table.add(new MccEntry(537,"pg",2)); //Papua New Guinea - table.add(new MccEntry(539,"to",2)); //Tonga (Kingdom of) - table.add(new MccEntry(540,"sb",2)); //Solomon Islands - table.add(new MccEntry(541,"vu",2)); //Vanuatu (Republic of) - table.add(new MccEntry(542,"fj",2)); //Fiji (Republic of) - table.add(new MccEntry(543,"wf",2)); //Wallis and Futuna (Territoire franais d'outre-mer) - table.add(new MccEntry(544,"as",2)); //American Samoa - table.add(new MccEntry(545,"ki",2)); //Kiribati (Republic of) - table.add(new MccEntry(546,"nc",2)); //New Caledonia (Territoire franais d'outre-mer) - table.add(new MccEntry(547,"pf",2)); //French Polynesia (Territoire franais d'outre-mer) - table.add(new MccEntry(548,"ck",2)); //Cook Islands - table.add(new MccEntry(549,"ws",2)); //Samoa (Independent State of) - table.add(new MccEntry(550,"fm",2)); //Micronesia (Federated States of) - table.add(new MccEntry(551,"mh",2)); //Marshall Islands (Republic of the) - table.add(new MccEntry(552,"pw",2)); //Palau (Republic of) - table.add(new MccEntry(602,"eg",2)); //Egypt (Arab Republic of) - table.add(new MccEntry(603,"dz",2)); //Algeria (People's Democratic Republic of) - table.add(new MccEntry(604,"ma",2)); //Morocco (Kingdom of) - table.add(new MccEntry(605,"tn",2)); //Tunisia - table.add(new MccEntry(606,"ly",2)); //Libya (Socialist People's Libyan Arab Jamahiriya) - table.add(new MccEntry(607,"gm",2)); //Gambia (Republic of the) - table.add(new MccEntry(608,"sn",2)); //Senegal (Republic of) - table.add(new MccEntry(609,"mr",2)); //Mauritania (Islamic Republic of) - table.add(new MccEntry(610,"ml",2)); //Mali (Republic of) - table.add(new MccEntry(611,"gn",2)); //Guinea (Republic of) - table.add(new MccEntry(612,"ci",2)); //Cte d'Ivoire (Republic of) - table.add(new MccEntry(613,"bf",2)); //Burkina Faso - table.add(new MccEntry(614,"ne",2)); //Niger (Republic of the) - table.add(new MccEntry(615,"tg",2)); //Togolese Republic - table.add(new MccEntry(616,"bj",2)); //Benin (Republic of) - table.add(new MccEntry(617,"mu",2)); //Mauritius (Republic of) - table.add(new MccEntry(618,"lr",2)); //Liberia (Republic of) - table.add(new MccEntry(619,"sl",2)); //Sierra Leone - table.add(new MccEntry(620,"gh",2)); //Ghana - table.add(new MccEntry(621,"ng",2)); //Nigeria (Federal Republic of) - table.add(new MccEntry(622,"td",2)); //Chad (Republic of) - table.add(new MccEntry(623,"cf",2)); //Central African Republic - table.add(new MccEntry(624,"cm",2)); //Cameroon (Republic of) - table.add(new MccEntry(625,"cv",2)); //Cape Verde (Republic of) - table.add(new MccEntry(626,"st",2)); //Sao Tome and Principe (Democratic Republic of) - table.add(new MccEntry(627,"gq",2)); //Equatorial Guinea (Republic of) - table.add(new MccEntry(628,"ga",2)); //Gabonese Republic - table.add(new MccEntry(629,"cg",2)); //Congo (Republic of the) - table.add(new MccEntry(630,"cg",2)); //Democratic Republic of the Congo - table.add(new MccEntry(631,"ao",2)); //Angola (Republic of) - table.add(new MccEntry(632,"gw",2)); //Guinea-Bissau (Republic of) - table.add(new MccEntry(633,"sc",2)); //Seychelles (Republic of) - table.add(new MccEntry(634,"sd",2)); //Sudan (Republic of the) - table.add(new MccEntry(635,"rw",2)); //Rwanda (Republic of) - table.add(new MccEntry(636,"et",2)); //Ethiopia (Federal Democratic Republic of) - table.add(new MccEntry(637,"so",2)); //Somali Democratic Republic - table.add(new MccEntry(638,"dj",2)); //Djibouti (Republic of) - table.add(new MccEntry(639,"ke",2)); //Kenya (Republic of) - table.add(new MccEntry(640,"tz",2)); //Tanzania (United Republic of) - table.add(new MccEntry(641,"ug",2)); //Uganda (Republic of) - table.add(new MccEntry(642,"bi",2)); //Burundi (Republic of) - table.add(new MccEntry(643,"mz",2)); //Mozambique (Republic of) - table.add(new MccEntry(645,"zm",2)); //Zambia (Republic of) - table.add(new MccEntry(646,"mg",2)); //Madagascar (Republic of) - table.add(new MccEntry(647,"re",2)); //Reunion (French Department of) - table.add(new MccEntry(648,"zw",2)); //Zimbabwe (Republic of) - table.add(new MccEntry(649,"na",2)); //Namibia (Republic of) - table.add(new MccEntry(650,"mw",2)); //Malawi - table.add(new MccEntry(651,"ls",2)); //Lesotho (Kingdom of) - table.add(new MccEntry(652,"bw",2)); //Botswana (Republic of) - table.add(new MccEntry(653,"sz",2)); //Swaziland (Kingdom of) - table.add(new MccEntry(654,"km",2)); //Comoros (Union of the) - table.add(new MccEntry(655,"za",2)); //South Africa (Republic of) - table.add(new MccEntry(657,"er",2)); //Eritrea - table.add(new MccEntry(702,"bz",2)); //Belize - table.add(new MccEntry(704,"gt",2)); //Guatemala (Republic of) - table.add(new MccEntry(706,"sv",2)); //El Salvador (Republic of) - table.add(new MccEntry(708,"hn",3)); //Honduras (Republic of) - table.add(new MccEntry(710,"ni",2)); //Nicaragua - table.add(new MccEntry(712,"cr",2)); //Costa Rica - table.add(new MccEntry(714,"pa",2)); //Panama (Republic of) - table.add(new MccEntry(716,"pe",2)); //Peru - table.add(new MccEntry(722,"ar",3)); //Argentine Republic - table.add(new MccEntry(724,"br",2)); //Brazil (Federative Republic of) - table.add(new MccEntry(730,"cl",2)); //Chile - table.add(new MccEntry(732,"co",3)); //Colombia (Republic of) - table.add(new MccEntry(734,"ve",2)); //Venezuela (Bolivarian Republic of) - table.add(new MccEntry(736,"bo",2)); //Bolivia (Republic of) - table.add(new MccEntry(738,"gy",2)); //Guyana - table.add(new MccEntry(740,"ec",2)); //Ecuador - table.add(new MccEntry(742,"gf",2)); //French Guiana (French Department of) - table.add(new MccEntry(744,"py",2)); //Paraguay (Republic of) - table.add(new MccEntry(746,"sr",2)); //Suriname (Republic of) - table.add(new MccEntry(748,"uy",2)); //Uruguay (Eastern Republic of) - table.add(new MccEntry(750,"fk",2)); //Falkland Islands (Malvinas) + table.add(new MccEntry(295,"li",2)); //Liechtenstein (Principality of) + table.add(new MccEntry(302,"ca",2)); //Canada + table.add(new MccEntry(308,"pm",2)); //Saint Pierre and Miquelon (Collectivit territoriale de la Rpublique franaise) + table.add(new MccEntry(310,"us",3)); //United States of America + table.add(new MccEntry(311,"us",3)); //United States of America + table.add(new MccEntry(312,"us",3)); //United States of America + table.add(new MccEntry(313,"us",3)); //United States of America + table.add(new MccEntry(314,"us",3)); //United States of America + table.add(new MccEntry(315,"us",3)); //United States of America + table.add(new MccEntry(316,"us",3)); //United States of America + table.add(new MccEntry(330,"pr",2)); //Puerto Rico + table.add(new MccEntry(332,"vi",2)); //United States Virgin Islands + table.add(new MccEntry(334,"mx",3)); //Mexico + table.add(new MccEntry(338,"jm",3)); //Jamaica + table.add(new MccEntry(340,"gp",2)); //Guadeloupe (French Department of) + table.add(new MccEntry(342,"bb",3)); //Barbados + table.add(new MccEntry(344,"ag",3)); //Antigua and Barbuda + table.add(new MccEntry(346,"ky",3)); //Cayman Islands + table.add(new MccEntry(348,"vg",3)); //British Virgin Islands + table.add(new MccEntry(350,"bm",2)); //Bermuda + table.add(new MccEntry(352,"gd",2)); //Grenada + table.add(new MccEntry(354,"ms",2)); //Montserrat + table.add(new MccEntry(356,"kn",2)); //Saint Kitts and Nevis + table.add(new MccEntry(358,"lc",2)); //Saint Lucia + table.add(new MccEntry(360,"vc",2)); //Saint Vincent and the Grenadines + table.add(new MccEntry(362,"nl",2)); //Netherlands Antilles + table.add(new MccEntry(363,"aw",2)); //Aruba + table.add(new MccEntry(364,"bs",2)); //Bahamas (Commonwealth of the) + table.add(new MccEntry(365,"ai",3)); //Anguilla + table.add(new MccEntry(366,"dm",2)); //Dominica (Commonwealth of) + table.add(new MccEntry(368,"cu",2)); //Cuba + table.add(new MccEntry(370,"do",2)); //Dominican Republic + table.add(new MccEntry(372,"ht",2)); //Haiti (Republic of) + table.add(new MccEntry(374,"tt",2)); //Trinidad and Tobago + table.add(new MccEntry(376,"tc",2)); //Turks and Caicos Islands + table.add(new MccEntry(400,"az",2)); //Azerbaijani Republic + table.add(new MccEntry(401,"kz",2)); //Kazakhstan (Republic of) + table.add(new MccEntry(402,"bt",2)); //Bhutan (Kingdom of) + table.add(new MccEntry(404,"in",2)); //India (Republic of) + table.add(new MccEntry(405,"in",2)); //India (Republic of) + table.add(new MccEntry(410,"pk",2)); //Pakistan (Islamic Republic of) + table.add(new MccEntry(412,"af",2)); //Afghanistan + table.add(new MccEntry(413,"lk",2)); //Sri Lanka (Democratic Socialist Republic of) + table.add(new MccEntry(414,"mm",2)); //Myanmar (Union of) + table.add(new MccEntry(415,"lb",2)); //Lebanon + table.add(new MccEntry(416,"jo",2)); //Jordan (Hashemite Kingdom of) + table.add(new MccEntry(417,"sy",2)); //Syrian Arab Republic + table.add(new MccEntry(418,"iq",2)); //Iraq (Republic of) + table.add(new MccEntry(419,"kw",2)); //Kuwait (State of) + table.add(new MccEntry(420,"sa",2)); //Saudi Arabia (Kingdom of) + table.add(new MccEntry(421,"ye",2)); //Yemen (Republic of) + table.add(new MccEntry(422,"om",2)); //Oman (Sultanate of) + table.add(new MccEntry(424,"ae",2)); //United Arab Emirates + table.add(new MccEntry(425,"il",2)); //Israel (State of) + table.add(new MccEntry(426,"bh",2)); //Bahrain (Kingdom of) + table.add(new MccEntry(427,"qa",2)); //Qatar (State of) + table.add(new MccEntry(428,"mn",2)); //Mongolia + table.add(new MccEntry(429,"np",2)); //Nepal + table.add(new MccEntry(430,"ae",2)); //United Arab Emirates + table.add(new MccEntry(431,"ae",2)); //United Arab Emirates + table.add(new MccEntry(432,"ir",2)); //Iran (Islamic Republic of) + table.add(new MccEntry(434,"uz",2)); //Uzbekistan (Republic of) + table.add(new MccEntry(436,"tj",2)); //Tajikistan (Republic of) + table.add(new MccEntry(437,"kg",2)); //Kyrgyz Republic + table.add(new MccEntry(438,"tm",2)); //Turkmenistan + table.add(new MccEntry(440,"jp",2)); //Japan + table.add(new MccEntry(441,"jp",2)); //Japan + table.add(new MccEntry(450,"kr",2)); //Korea (Republic of) + table.add(new MccEntry(452,"vn",2)); //Viet Nam (Socialist Republic of) + table.add(new MccEntry(454,"hk",2)); //"Hong Kong, China" + table.add(new MccEntry(455,"mo",2)); //"Macao, China" + table.add(new MccEntry(456,"kh",2)); //Cambodia (Kingdom of) + table.add(new MccEntry(457,"la",2)); //Lao People's Democratic Republic + table.add(new MccEntry(460,"cn",2)); //China (People's Republic of) + table.add(new MccEntry(461,"cn",2)); //China (People's Republic of) + table.add(new MccEntry(466,"tw",2)); //"Taiwan, China" + table.add(new MccEntry(467,"kp",2)); //Democratic People's Republic of Korea + table.add(new MccEntry(470,"bd",2)); //Bangladesh (People's Republic of) + table.add(new MccEntry(472,"mv",2)); //Maldives (Republic of) + table.add(new MccEntry(502,"my",2)); //Malaysia + table.add(new MccEntry(505,"au",2)); //Australia + table.add(new MccEntry(510,"id",2)); //Indonesia (Republic of) + table.add(new MccEntry(514,"tl",2)); //Democratic Republic of Timor-Leste + table.add(new MccEntry(515,"ph",2)); //Philippines (Republic of the) + table.add(new MccEntry(520,"th",2)); //Thailand + table.add(new MccEntry(525,"sg",2)); //Singapore (Republic of) + table.add(new MccEntry(528,"bn",2)); //Brunei Darussalam + table.add(new MccEntry(530,"nz",2)); //New Zealand + table.add(new MccEntry(534,"mp",2)); //Northern Mariana Islands (Commonwealth of the) + table.add(new MccEntry(535,"gu",2)); //Guam + table.add(new MccEntry(536,"nr",2)); //Nauru (Republic of) + table.add(new MccEntry(537,"pg",2)); //Papua New Guinea + table.add(new MccEntry(539,"to",2)); //Tonga (Kingdom of) + table.add(new MccEntry(540,"sb",2)); //Solomon Islands + table.add(new MccEntry(541,"vu",2)); //Vanuatu (Republic of) + table.add(new MccEntry(542,"fj",2)); //Fiji (Republic of) + table.add(new MccEntry(543,"wf",2)); //Wallis and Futuna (Territoire franais d'outre-mer) + table.add(new MccEntry(544,"as",2)); //American Samoa + table.add(new MccEntry(545,"ki",2)); //Kiribati (Republic of) + table.add(new MccEntry(546,"nc",2)); //New Caledonia (Territoire franais d'outre-mer) + table.add(new MccEntry(547,"pf",2)); //French Polynesia (Territoire franais d'outre-mer) + table.add(new MccEntry(548,"ck",2)); //Cook Islands + table.add(new MccEntry(549,"ws",2)); //Samoa (Independent State of) + table.add(new MccEntry(550,"fm",2)); //Micronesia (Federated States of) + table.add(new MccEntry(551,"mh",2)); //Marshall Islands (Republic of the) + table.add(new MccEntry(552,"pw",2)); //Palau (Republic of) + table.add(new MccEntry(602,"eg",2)); //Egypt (Arab Republic of) + table.add(new MccEntry(603,"dz",2)); //Algeria (People's Democratic Republic of) + table.add(new MccEntry(604,"ma",2)); //Morocco (Kingdom of) + table.add(new MccEntry(605,"tn",2)); //Tunisia + table.add(new MccEntry(606,"ly",2)); //Libya (Socialist People's Libyan Arab Jamahiriya) + table.add(new MccEntry(607,"gm",2)); //Gambia (Republic of the) + table.add(new MccEntry(608,"sn",2)); //Senegal (Republic of) + table.add(new MccEntry(609,"mr",2)); //Mauritania (Islamic Republic of) + table.add(new MccEntry(610,"ml",2)); //Mali (Republic of) + table.add(new MccEntry(611,"gn",2)); //Guinea (Republic of) + table.add(new MccEntry(612,"ci",2)); //Cte d'Ivoire (Republic of) + table.add(new MccEntry(613,"bf",2)); //Burkina Faso + table.add(new MccEntry(614,"ne",2)); //Niger (Republic of the) + table.add(new MccEntry(615,"tg",2)); //Togolese Republic + table.add(new MccEntry(616,"bj",2)); //Benin (Republic of) + table.add(new MccEntry(617,"mu",2)); //Mauritius (Republic of) + table.add(new MccEntry(618,"lr",2)); //Liberia (Republic of) + table.add(new MccEntry(619,"sl",2)); //Sierra Leone + table.add(new MccEntry(620,"gh",2)); //Ghana + table.add(new MccEntry(621,"ng",2)); //Nigeria (Federal Republic of) + table.add(new MccEntry(622,"td",2)); //Chad (Republic of) + table.add(new MccEntry(623,"cf",2)); //Central African Republic + table.add(new MccEntry(624,"cm",2)); //Cameroon (Republic of) + table.add(new MccEntry(625,"cv",2)); //Cape Verde (Republic of) + table.add(new MccEntry(626,"st",2)); //Sao Tome and Principe (Democratic Republic of) + table.add(new MccEntry(627,"gq",2)); //Equatorial Guinea (Republic of) + table.add(new MccEntry(628,"ga",2)); //Gabonese Republic + table.add(new MccEntry(629,"cg",2)); //Congo (Republic of the) + table.add(new MccEntry(630,"cg",2)); //Democratic Republic of the Congo + table.add(new MccEntry(631,"ao",2)); //Angola (Republic of) + table.add(new MccEntry(632,"gw",2)); //Guinea-Bissau (Republic of) + table.add(new MccEntry(633,"sc",2)); //Seychelles (Republic of) + table.add(new MccEntry(634,"sd",2)); //Sudan (Republic of the) + table.add(new MccEntry(635,"rw",2)); //Rwanda (Republic of) + table.add(new MccEntry(636,"et",2)); //Ethiopia (Federal Democratic Republic of) + table.add(new MccEntry(637,"so",2)); //Somali Democratic Republic + table.add(new MccEntry(638,"dj",2)); //Djibouti (Republic of) + table.add(new MccEntry(639,"ke",2)); //Kenya (Republic of) + table.add(new MccEntry(640,"tz",2)); //Tanzania (United Republic of) + table.add(new MccEntry(641,"ug",2)); //Uganda (Republic of) + table.add(new MccEntry(642,"bi",2)); //Burundi (Republic of) + table.add(new MccEntry(643,"mz",2)); //Mozambique (Republic of) + table.add(new MccEntry(645,"zm",2)); //Zambia (Republic of) + table.add(new MccEntry(646,"mg",2)); //Madagascar (Republic of) + table.add(new MccEntry(647,"re",2)); //Reunion (French Department of) + table.add(new MccEntry(648,"zw",2)); //Zimbabwe (Republic of) + table.add(new MccEntry(649,"na",2)); //Namibia (Republic of) + table.add(new MccEntry(650,"mw",2)); //Malawi + table.add(new MccEntry(651,"ls",2)); //Lesotho (Kingdom of) + table.add(new MccEntry(652,"bw",2)); //Botswana (Republic of) + table.add(new MccEntry(653,"sz",2)); //Swaziland (Kingdom of) + table.add(new MccEntry(654,"km",2)); //Comoros (Union of the) + table.add(new MccEntry(655,"za",2)); //South Africa (Republic of) + table.add(new MccEntry(657,"er",2)); //Eritrea + table.add(new MccEntry(702,"bz",2)); //Belize + table.add(new MccEntry(704,"gt",2)); //Guatemala (Republic of) + table.add(new MccEntry(706,"sv",2)); //El Salvador (Republic of) + table.add(new MccEntry(708,"hn",3)); //Honduras (Republic of) + table.add(new MccEntry(710,"ni",2)); //Nicaragua + table.add(new MccEntry(712,"cr",2)); //Costa Rica + table.add(new MccEntry(714,"pa",2)); //Panama (Republic of) + table.add(new MccEntry(716,"pe",2)); //Peru + table.add(new MccEntry(722,"ar",3)); //Argentine Republic + table.add(new MccEntry(724,"br",2)); //Brazil (Federative Republic of) + table.add(new MccEntry(730,"cl",2)); //Chile + table.add(new MccEntry(732,"co",3)); //Colombia (Republic of) + table.add(new MccEntry(734,"ve",2)); //Venezuela (Bolivarian Republic of) + table.add(new MccEntry(736,"bo",2)); //Bolivia (Republic of) + table.add(new MccEntry(738,"gy",2)); //Guyana + table.add(new MccEntry(740,"ec",2)); //Ecuador + table.add(new MccEntry(742,"gf",2)); //French Guiana (French Department of) + table.add(new MccEntry(744,"py",2)); //Paraguay (Republic of) + table.add(new MccEntry(746,"sr",2)); //Suriname (Republic of) + table.add(new MccEntry(748,"uy",2)); //Uruguay (Eastern Republic of) + table.add(new MccEntry(750,"fk",2)); //Falkland Islands (Malvinas) //table.add(new MccEntry(901,"",2)); //"International Mobile, shared code" Collections.sort(table); diff --git a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl index c600530a4629..d88d0b721f47 100644 --- a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl +++ b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl @@ -16,11 +16,11 @@ package com.android.internal.telephony.gsm; -/** +/** * Used to indicate that the NetworkInfo object is parcelable to aidl. * This is a simple effort to make NetworkInfo parcelable rather than * trying to make the conventional containing object (AsyncResult), - * implement parcelable. This functionality is needed for the + * implement parcelable. This functionality is needed for the * NetworkQueryService to fix 1128695 */ parcelable NetworkInfo; diff --git a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java index 353524531ace..04fd13e715a7 100644 --- a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java +++ b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java @@ -57,9 +57,9 @@ public class NetworkInfo implements Parcelable { return state; } - NetworkInfo(String operatorAlphaLong, - String operatorAlphaShort, - String operatorNumeric, + NetworkInfo(String operatorAlphaLong, + String operatorAlphaShort, + String operatorNumeric, State state) { this.operatorAlphaLong = operatorAlphaLong; @@ -70,11 +70,11 @@ public class NetworkInfo implements Parcelable { } - public NetworkInfo(String operatorAlphaLong, - String operatorAlphaShort, - String operatorNumeric, + public NetworkInfo(String operatorAlphaLong, + String operatorAlphaShort, + String operatorNumeric, String stateString) { - this (operatorAlphaLong, operatorAlphaShort, + this (operatorAlphaLong, operatorAlphaShort, operatorNumeric, rilStateToState(stateString)); } @@ -98,27 +98,27 @@ public class NetworkInfo implements Parcelable { public String toString() { - return "NetworkInfo " + operatorAlphaLong - + "/" + operatorAlphaShort - + "/" + operatorNumeric + return "NetworkInfo " + operatorAlphaLong + + "/" + operatorAlphaShort + + "/" + operatorNumeric + "/" + state; } - - /** + + /** * Parcelable interface implemented below. * This is a simple effort to make NetworkInfo parcelable rather than * trying to make the conventional containing object (AsyncResult), - * implement parcelable. This functionality is needed for the + * implement parcelable. This functionality is needed for the * NetworkQueryService to fix 1128695. */ - + public int describeContents() { return 0; } - /** + /** * Implement the Parcelable interface. - * Method to serialize a NetworkInfo object. + * Method to serialize a NetworkInfo object. */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(operatorAlphaLong); @@ -127,9 +127,9 @@ public class NetworkInfo implements Parcelable { dest.writeSerializable(state); } - /** + /** * Implement the Parcelable interface - * Method to deserialize a NetworkInfo object, or an array thereof. + * Method to deserialize a NetworkInfo object, or an array thereof. */ public static final Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() { diff --git a/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java b/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java index d5d481adc92a..feb78f81153a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java +++ b/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java @@ -19,8 +19,7 @@ package com.android.internal.telephony.gsm; /** * {@hide} */ -public class PDPContextState -{ +public class PDPContextState { public int cid; public boolean active; public String type; diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java index d8d75e154132..c23fad499029 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java +++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java @@ -17,87 +17,23 @@ package com.android.internal.telephony.gsm; import android.os.*; -import com.android.internal.telephony.CommandsInterface; -import android.database.Cursor; -import android.provider.Telephony; import android.util.EventLog; import android.util.Log; -import java.util.ArrayList; +import com.android.internal.telephony.CommandException; +import com.android.internal.telephony.DataConnection; +import com.android.internal.telephony.DataLink; +import com.android.internal.telephony.RILConstants; /** * {@hide} */ -public class PdpConnection extends Handler { +public class PdpConnection extends DataConnection { private static final String LOG_TAG = "GSM"; private static final boolean DBG = true; private static final boolean FAKE_FAIL = false; - public enum PdpState { - ACTIVE, /* has active pdp context */ - ACTIVATING, /* during connecting process */ - INACTIVE; /* has empty pdp context */ - - public String toString() { - switch (this) { - case ACTIVE: return "active"; - case ACTIVATING: return "setting up"; - default: return "inactive"; - } - } - - public boolean isActive() { - return this == ACTIVE; - } - - public boolean isInactive() { - return this == INACTIVE; - } - } - - public enum PdpFailCause { - NONE, - BAD_APN, - BAD_PAP_SECRET, - BARRED, - USER_AUTHENTICATION, - SERVICE_OPTION_NOT_SUPPORTED, - SERVICE_OPTION_NOT_SUBSCRIBED, - SIM_LOCKED, - RADIO_OFF, - NO_SIGNAL, - NO_DATA_PLAN, - RADIO_NOT_AVIALABLE, - SUSPENED_TEMPORARY, - RADIO_ERROR_RETRY, - UNKNOWN; - - public boolean isPermanentFail() { - return (this == RADIO_OFF); - } - - public String toString() { - switch (this) { - case NONE: return "no error"; - case BAD_APN: return "bad apn"; - case BAD_PAP_SECRET:return "bad pap secret"; - case BARRED: return "barred"; - case USER_AUTHENTICATION: return "error user autentication"; - case SERVICE_OPTION_NOT_SUPPORTED: return "data not supported"; - case SERVICE_OPTION_NOT_SUBSCRIBED: return "datt not subcribed"; - case SIM_LOCKED: return "sim locked"; - case RADIO_OFF: return "radio is off"; - case NO_SIGNAL: return "no signal"; - case NO_DATA_PLAN: return "no data plan"; - case RADIO_NOT_AVIALABLE: return "radio not available"; - case SUSPENED_TEMPORARY: return "suspend temporary"; - case RADIO_ERROR_RETRY: return "transient radio error"; - default: return "unknown data error"; - } - } - } - /** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */ private static final int PDP_FAIL_RIL_BARRED = 8; private static final int PDP_FAIL_RIL_BAD_APN = 27; @@ -106,56 +42,20 @@ public class PdpConnection extends Handler { private static final int PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUBSCRIBED = 33; private static final int PDP_FAIL_RIL_ERROR_UNSPECIFIED = 0xffff; - //***** Event codes - private static final int EVENT_SETUP_PDP_DONE = 1; - private static final int EVENT_GET_LAST_FAIL_DONE = 2; - private static final int EVENT_LINK_STATE_CHANGED = 3; - private static final int EVENT_DEACTIVATE_DONE = 4; - private static final int EVENT_FORCE_RETRY = 5; - - //***** Tag IDs for EventLog - private static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100; - //***** Instance Variables - private GSMPhone phone; private String pdp_name; - private PdpState state; - private Message onConnectCompleted; - private Message onDisconnect; - private int cid; - private long createTime; - private long lastFailTime; - private PdpFailCause lastFailCause; - private ApnSetting apn; - private String interfaceName; - private String ipAddress; - private String gatewayAddress; - private String[] dnsServers; - - private static final String NULL_IP = "0.0.0.0"; + protected ApnSetting apn; // dataLink is only used to support pppd link DataLink dataLink; - // receivedDisconnectReq is set when disconnect pdp link during activating - private boolean receivedDisconnectReq; //***** Constructor PdpConnection(GSMPhone phone) { - this.phone = phone; - this.state = PdpState.INACTIVE; - onConnectCompleted = null; - onDisconnect = null; - this.cid = -1; - this.createTime = -1; - this.lastFailTime = -1; - this.lastFailCause = PdpFailCause.NONE; - this.apn = null; + super(phone); this.dataLink = null; - receivedDisconnectReq = false; - this.dnsServers = new String[2]; if (SystemProperties.get("ro.radio.use-ppp","no").equals("yes")) { - dataLink = new PppLink(phone.mDataConnection); + dataLink = new PppLink((GsmDataConnectionTracker) phone.mDataConnection, phone); dataLink.setOnLinkChange(this, EVENT_LINK_STATE_CHANGED, null); } } @@ -172,55 +72,41 @@ public class PdpConnection extends Handler { setHttpProxy (apn.proxy, apn.port); - state = PdpState.ACTIVATING; + state = State.ACTIVATING; this.apn = apn; onConnectCompleted = onCompleted; createTime = -1; lastFailTime = -1; - lastFailCause = PdpFailCause.NONE; + lastFailCause = FailCause.NONE; receivedDisconnectReq = false; if (FAKE_FAIL) { // for debug before baseband implement error in setup PDP if (apn.apn.equalsIgnoreCase("badapn")){ - notifyFail(PdpFailCause.BAD_APN, onConnectCompleted); + notifyFail(FailCause.BAD_APN, onConnectCompleted); return; } } - phone.mCM.setupDefaultPDP(apn.apn, apn.user, apn.password, - obtainMessage(EVENT_SETUP_PDP_DONE)); + phone.mCM.setupDataCall(Integer.toString(RILConstants.GSM_PHONE), null, apn.apn, apn.user, + apn.password, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE)); } - void disconnect(Message msg) { + protected void disconnect(Message msg) { onDisconnect = msg; - if (state == PdpState.ACTIVE) { + if (state == State.ACTIVE) { if (dataLink != null) { dataLink.disconnect(); } if (phone.mCM.getRadioState().isOn()) { - phone.mCM.deactivateDefaultPDP(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg)); } - } else if (state == PdpState.ACTIVATING) { + } else if (state == State.ACTIVATING) { receivedDisconnectReq = true; } } - private void - setHttpProxy(String httpProxy, String httpPort) { - if (httpProxy == null || httpProxy.length() == 0) { - phone.setSystemProperty("net.gprs.http-proxy", null); - return; - } - - if (httpPort == null || httpPort.length() == 0) { - httpPort = "8080"; // Default to port 8080 - } - - phone.setSystemProperty("net.gprs.http-proxy", - "http://" + httpProxy + ":" + httpPort + "/"); - } public String toString() { return "State=" + state + " Apn=" + apn + @@ -228,46 +114,11 @@ public class PdpConnection extends Handler { " lastFailCause=" + lastFailCause; } - public long getConnectionTime() { - return createTime; - } - - public long getLastFailTime() { - return lastFailTime; - } - - public PdpFailCause getLastFailCause() { - return lastFailCause; - } - - public ApnSetting getApn() { - return apn; - } - - String getInterface() { - return interfaceName; - } - - String getIpAddress() { - return ipAddress; - } - - String getGatewayAddress() { - return gatewayAddress; - } - - String[] getDnsServers() { - return dnsServers; - } - public PdpState getState() { - return state; - } - - private void notifyFail(PdpFailCause cause, Message onCompleted) { + protected void notifyFail(FailCause cause, Message onCompleted) { if (onCompleted == null) return; - state = PdpState.INACTIVE; + state = State.INACTIVE; lastFailCause = cause; lastFailTime = System.currentTimeMillis(); onConnectCompleted = null; @@ -282,7 +133,7 @@ public class PdpConnection extends Handler { private void notifySuccess(Message onCompleted) { if (onCompleted == null) return; - state = PdpState.ACTIVE; + state = State.ACTIVE; createTime = System.currentTimeMillis(); onConnectCompleted = null; onCompleted.arg1 = cid; @@ -293,9 +144,9 @@ public class PdpConnection extends Handler { onCompleted.sendToTarget(); } - private void notifyDisconnect(Message msg) { + protected void notifyDisconnect(Message msg) { if (DBG) log("Notify PDP disconnect"); - + if (msg != null) { AsyncResult.forMessage(msg); msg.sendToTarget(); @@ -303,22 +154,7 @@ public class PdpConnection extends Handler { clearSettings(); } - void clearSettings() { - state = PdpState.INACTIVE; - receivedDisconnectReq = false; - createTime = -1; - lastFailTime = -1; - lastFailCause = PdpFailCause.NONE; - apn = null; - onConnectCompleted = null; - interfaceName = null; - ipAddress = null; - gatewayAddress = null; - dnsServers[0] = null; - dnsServers[1] = null; - } - - private void onLinkStateChanged(DataLink.LinkState linkState) { + protected void onLinkStateChanged(DataLink.LinkState linkState) { switch (linkState) { case LINK_UP: notifySuccess(onConnectCompleted); @@ -332,141 +168,107 @@ public class PdpConnection extends Handler { } } - private PdpFailCause getFailCauseFromRequest(int rilCause) { - PdpFailCause cause; + protected FailCause getFailCauseFromRequest(int rilCause) { + FailCause cause; switch (rilCause) { case PDP_FAIL_RIL_BARRED: - cause = PdpFailCause.BARRED; + cause = FailCause.BARRED; break; case PDP_FAIL_RIL_BAD_APN: - cause = PdpFailCause.BAD_APN; + cause = FailCause.BAD_APN; break; case PDP_FAIL_RIL_USER_AUTHENTICATION: - cause = PdpFailCause.USER_AUTHENTICATION; + cause = FailCause.USER_AUTHENTICATION; break; case PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUPPORTED: - cause = PdpFailCause.SERVICE_OPTION_NOT_SUPPORTED; + cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED; break; case PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUBSCRIBED: - cause = PdpFailCause.SERVICE_OPTION_NOT_SUBSCRIBED; + cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED; break; default: - cause = PdpFailCause.UNKNOWN; + cause = FailCause.UNKNOWN; } return cause; } - private void log(String s) { + protected void log(String s) { Log.d(LOG_TAG, "[PdpConnection] " + s); } @Override - public void handleMessage(Message msg) { - AsyncResult ar; - - switch (msg.what) { - case EVENT_SETUP_PDP_DONE: - ar = (AsyncResult) msg.obj; - - if (ar.exception != null) { - Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception); - - if (receivedDisconnectReq) { - // Don't bother reporting the error if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - notifyDisconnect(onDisconnect); - } else { - if ( ar.exception instanceof CommandException && - ((CommandException) (ar.exception)).getCommandError() - == CommandException.Error.RADIO_NOT_AVAILABLE) { - notifyFail(PdpFailCause.RADIO_NOT_AVIALABLE, - onConnectCompleted); - } else { - phone.mCM.getLastPdpFailCause( - obtainMessage(EVENT_GET_LAST_FAIL_DONE)); - } - } + protected void onDeactivated(AsyncResult ar) { + notifyDisconnect((Message) ar.userObj); + if (DBG) log("PDP Connection Deactivated"); + } + + @Override + protected void onSetupConnectionCompleted(AsyncResult ar) { + if (ar.exception != null) { + Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception); + + if (receivedDisconnectReq) { + // Don't bother reporting the error if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + notifyDisconnect(onDisconnect); + } else { + if ( ar.exception instanceof CommandException && + ((CommandException) (ar.exception)).getCommandError() + == CommandException.Error.RADIO_NOT_AVAILABLE) { + notifyFail(FailCause.RADIO_NOT_AVAILABLE, + onConnectCompleted); } else { - if (receivedDisconnectReq) { - // Don't bother reporting success if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - disconnect(onDisconnect); - } else { - String[] response = ((String[]) ar.result); - cid = Integer.parseInt(response[0]); - - if (response.length > 2) { - interfaceName = response[1]; - ipAddress = response[2]; - String prefix = "net." + interfaceName + "."; - gatewayAddress = SystemProperties.get(prefix + "gw"); - dnsServers[0] = SystemProperties.get(prefix + "dns1"); - dnsServers[1] = SystemProperties.get(prefix + "dns2"); - if (DBG) { - log("interface=" + interfaceName + " ipAddress=" + ipAddress - + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0] - + " DNS2=" + dnsServers[1]); - } - - if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])) { - // Work around a race condition where QMI does not fill in DNS: - // Deactivate PDP and let DataConnectionTracker retry. - EventLog.writeEvent(EVENT_LOG_BAD_DNS_ADDRESS, dnsServers[0]); - phone.mCM.deactivateDefaultPDP(cid, - obtainMessage(EVENT_FORCE_RETRY)); - break; - } - } - - if (dataLink != null) { - dataLink.connect(); - } else { - onLinkStateChanged(DataLink.LinkState.LINK_UP); - } - - if (DBG) log("PDP setup on cid = " + cid); + phone.mCM.getLastPdpFailCause( + obtainMessage(EVENT_GET_LAST_FAIL_DONE)); + } + } + } else { + if (receivedDisconnectReq) { + // Don't bother reporting success if there's already a + // pending disconnect request, since DataConnectionTracker + // has already updated its state. + disconnect(onDisconnect); + } else { + String[] response = ((String[]) ar.result); + cid = Integer.parseInt(response[0]); + + if (response.length > 2) { + interfaceName = response[1]; + ipAddress = response[2]; + String prefix = "net." + interfaceName + "."; + gatewayAddress = SystemProperties.get(prefix + "gw"); + dnsServers[0] = SystemProperties.get(prefix + "dns1"); + dnsServers[1] = SystemProperties.get(prefix + "dns2"); + if (DBG) { + log("interface=" + interfaceName + " ipAddress=" + ipAddress + + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0] + + " DNS2=" + dnsServers[1]); + } + + if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])) { + // Work around a race condition where QMI does not fill in DNS: + // Deactivate PDP and let DataConnectionTracker retry. + EventLog.writeEvent(EVENT_LOG_BAD_DNS_ADDRESS, dnsServers[0]); + phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY)); + return; } } - break; - case EVENT_FORCE_RETRY: - if (receivedDisconnectReq) { - notifyDisconnect(onDisconnect); + + if (dataLink != null) { + dataLink.connect(); } else { - ar = (AsyncResult) msg.obj; - notifyFail(PdpFailCause.RADIO_ERROR_RETRY, onConnectCompleted); - } - break; - case EVENT_GET_LAST_FAIL_DONE: - if (receivedDisconnectReq) { - // Don't bother reporting the error if there's already a - // pending disconnect request, since DataConnectionTracker - // has already updated its state. - notifyDisconnect(onDisconnect); - } else { - ar = (AsyncResult) msg.obj; - PdpFailCause cause = PdpFailCause.UNKNOWN; - - if (ar.exception == null) { - int rilFailCause = ((int[]) (ar.result))[0]; - cause = getFailCauseFromRequest(rilFailCause); - } - notifyFail(cause, onConnectCompleted); + onLinkStateChanged(DataLink.LinkState.LINK_UP); } - break; - case EVENT_LINK_STATE_CHANGED: - ar = (AsyncResult) msg.obj; - DataLink.LinkState ls = (DataLink.LinkState) ar.result; - onLinkStateChanged(ls); - break; - case EVENT_DEACTIVATE_DONE: - ar = (AsyncResult) msg.obj; - notifyDisconnect((Message) ar.userObj); - break; + if (DBG) log("PDP setup on cid = " + cid); + } } } + + public ApnSetting getApn() { + return this.apn; + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/PppLink.java b/telephony/java/com/android/internal/telephony/gsm/PppLink.java index 43d4f1f91350..96276968add1 100644 --- a/telephony/java/com/android/internal/telephony/gsm/PppLink.java +++ b/telephony/java/com/android/internal/telephony/gsm/PppLink.java @@ -16,28 +16,31 @@ package com.android.internal.telephony.gsm; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.RandomAccessFile; - import android.database.Cursor; import android.os.Message; import android.os.SystemProperties; import android.os.SystemService; -import com.android.internal.telephony.gsm.DataConnectionTracker.State; -import com.android.internal.util.ArrayUtils; import android.util.Log; +import com.android.internal.telephony.DataLink; +import com.android.internal.telephony.DataConnectionTracker.State; +import com.android.internal.telephony.PhoneBase; +import com.android.internal.util.ArrayUtils; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.RandomAccessFile; + /** * Represents a PPP link. - * + * * Ideally this would be managed by the RIL implementation, but * we currently have implementations where this is not the case. * * {@hide} */ -final class PppLink extends DataLink implements DataLinkInterface { +final class PppLink extends DataLink { private static final String LOG_TAG = "GSM"; static final String PATH_PPP_OPERSTATE = "/sys/class/net/ppp0/operstate"; @@ -69,11 +72,14 @@ final class PppLink extends DataLink implements DataLinkInterface { }; private final byte[] mCheckPPPBuffer = new byte[32]; + private PhoneBase phone; + int lastPppdExitCode = EXIT_OK; - PppLink(DataConnectionTracker dc) { + PppLink(GsmDataConnectionTracker dc, GSMPhone p) { super(dc); + this.phone = p; } public void connect() { @@ -131,7 +137,7 @@ final class PppLink extends DataLink implements DataLinkInterface { checkPPP(); // keep polling in case interface goes down - if (dataConnection.state != State.IDLE) { + if (dataConnection.getState() != State.IDLE) { Message poll = obtainMessage(); poll.what = EVENT_POLL_DATA_CONNECTION; sendMessageDelayed(poll, POLL_SYSFS_MILLIS); @@ -141,7 +147,7 @@ final class PppLink extends DataLink implements DataLinkInterface { } private void checkPPP() { - boolean connecting = (dataConnection.state == State.CONNECTING); + boolean connecting = (dataConnection.getState() == State.CONNECTING); try { RandomAccessFile file = new RandomAccessFile(PATH_PPP_OPERSTATE, "r"); @@ -152,10 +158,10 @@ final class PppLink extends DataLink implements DataLinkInterface { // "unknown" where one might otherwise expect "up" if (ArrayUtils.equals(mCheckPPPBuffer, UP_ASCII_STRING, UP_ASCII_STRING.length) || ArrayUtils.equals(mCheckPPPBuffer, UNKNOWN_ASCII_STRING, - UNKNOWN_ASCII_STRING.length) - && dataConnection.state == State.CONNECTING) { + UNKNOWN_ASCII_STRING.length) + && dataConnection.getState() == State.CONNECTING) { - Log.i(LOG_TAG, + Log.i(LOG_TAG, "found ppp interface. Notifying GPRS connected"); if (mLinkChangeRegistrant != null) { @@ -163,23 +169,23 @@ final class PppLink extends DataLink implements DataLinkInterface { } connecting = false; - } else if (dataConnection.state == State.CONNECTED + } else if (dataConnection.getState() == State.CONNECTED && ArrayUtils.equals(mCheckPPPBuffer, DOWN_ASCII_STRING, - DOWN_ASCII_STRING.length)) { + DOWN_ASCII_STRING.length)) { - Log.i(LOG_TAG, + Log.i(LOG_TAG, "ppp interface went down. Reconnecting..."); if (mLinkChangeRegistrant != null) { mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN); } - } + } } catch (IOException ex) { if (! (ex instanceof FileNotFoundException)) { Log.i(LOG_TAG, "Poll ppp0 ex " + ex.toString()); } - if (dataConnection.state == State.CONNECTED && + if (dataConnection.getState() == State.CONNECTED && mLinkChangeRegistrant != null) { mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN); } @@ -206,4 +212,8 @@ final class PppLink extends DataLink implements DataLinkInterface { } } + + protected void log(String s) { + Log.d(LOG_TAG, "[PppLink] " + s); + } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java index 3c12c37f3c24..ead1327d5d74 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java @@ -16,13 +16,18 @@ package com.android.internal.telephony.gsm; -import com.android.internal.telephony.*; //TODO Remove * -import com.android.internal.telephony.gsm.stk.ImageDescriptor; import android.os.*; import android.os.AsyncResult; -import android.os.RegistrantList; -import android.os.Registrant; import android.util.Log; + +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccException; +import com.android.internal.telephony.IccFileHandler; +import com.android.internal.telephony.IccFileTypeMismatch; +import com.android.internal.telephony.IccIoResult; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; + import java.util.ArrayList; /** @@ -32,415 +37,33 @@ public final class SIMFileHandler extends IccFileHandler { static final String LOG_TAG = "GSM"; //***** Instance Variables - GSMPhone phone; - - - //***** Inner Classes - - static class LoadLinearFixedContext { - - int efid; - int recordNum, recordSize, countRecords; - boolean loadAll; - - Message onLoaded; - - ArrayList<byte[]> results; - - LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) { - this.efid = efid; - this.recordNum = recordNum; - this.onLoaded = onLoaded; - this.loadAll = false; - } - - LoadLinearFixedContext(int efid, Message onLoaded) { - this.efid = efid; - this.recordNum = 1; - this.loadAll = true; - this.onLoaded = onLoaded; - } - - } - //***** Constructor SIMFileHandler(GSMPhone phone) { - this.phone = phone; + super(phone); } - //***** Public Methods - - /** - * Load a record from a SIM Linear Fixed EF - * - * @param fileid EF id - * @param recordNum 1-based (not 0-based) record number - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - protected void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) { - Message response - = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid, recordNum, onLoaded)); - - phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + public void dispose() { + super.dispose(); } - /** - * Load a image instance record from a SIM Linear Fixed EF-IMG - * - * @param recordNum 1-based (not 0-based) record number - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - public void loadEFImgLinearFixed(int recordNum, Message onLoaded) { - Message response = obtainMessage(EVENT_READ_IMG_DONE, - new LoadLinearFixedContext(IccConstants.EF_IMG, recordNum, - onLoaded)); - - phone.mCM.iccIO(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img", - recordNum, READ_RECORD_MODE_ABSOLUTE, - ImageDescriptor.ID_LENGTH, null, null, response); - } - - /** - * get record size for a linear fixed EF - * - * @param fileid EF id - * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[] - * int[0] is the record length int[1] is the total length of the EF - * file int[3] is the number of records in the EF file So int[0] * - * int[3] = int[1] - */ - protected void getEFLinearRecordSize(int fileid, Message onLoaded) { - Message response - = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid, onLoaded)); - phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); - } - - /** - * Load all records from a SIM Linear Fixed EF - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is an ArrayList<byte[]> - * - */ - protected void loadEFLinearFixedAll(int fileid, Message onLoaded) { - Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE, - new LoadLinearFixedContext(fileid,onLoaded)); - - phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); + protected void finalize() { + Log.d(LOG_TAG, "SIMFileHandler finalized"); } - /** - * Load a SIM Transparent EF - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - - protected void loadEFTransparent(int fileid, Message onLoaded) { - Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE, - fileid, 0, onLoaded); - - phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null, - 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response); - } - - /** - * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to - * retrive STK's icon data. - * - * @param fileid EF id - * @param onLoaded - * - * ((AsyncResult)(onLoaded.obj)).result is the byte[] - * - */ - public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset, - int length, Message onLoaded) { - Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0, - onLoaded); - - phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset, - length, null, null, response); - } - - /** - * Update a record in a linear fixed EF - * @param fileid EF id - * @param recordNum 1-based (not 0-based) record number - * @param data must be exactly as long as the record in the EF - * @param pin2 for CHV2 operations, otherwist must be null - * @param onComplete onComplete.obj will be an AsyncResult - * onComplete.obj.userObj will be a IccIoResult on success - */ - protected void updateEFLinearFixed(int fileid, int recordNum, byte[] data, - String pin2, Message onComplete) { - phone.mCM.iccIO(COMMAND_UPDATE_RECORD, fileid, null, - recordNum, READ_RECORD_MODE_ABSOLUTE, data.length, - IccUtils.bytesToHexString(data), pin2, onComplete); - } - - /** - * Update a transparent EF - * @param fileid EF id - * @param data must be exactly as long as the EF - */ - protected void updateEFTransparent(int fileid, byte[] data, Message onComplete) { - phone.mCM.iccIO(COMMAND_UPDATE_BINARY, fileid, null, - 0, 0, data.length, - IccUtils.bytesToHexString(data), null, onComplete); - } - - //***** Overridden from Handler + //***** Overridden from IccFileHandler + @Override public void handleMessage(Message msg) { - AsyncResult ar; - IccIoResult result; - Message response = null; - String str; - LoadLinearFixedContext lc; - - IccException iccException; - byte data[]; - int size; - int fileid; - int recordNum; - int recordSize[]; - - try { - switch (msg.what) { - case EVENT_READ_IMG_DONE: - ar = (AsyncResult) msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (IccIoResult) ar.result; - response = lc.onLoaded; - - iccException = result.getException(); - if (iccException != null) { - sendResult(response, result.payload, ar.exception); - } - break; - case EVENT_READ_ICON_DONE: - ar = (AsyncResult) msg.obj; - response = (Message) ar.userObj; - result = (IccIoResult) ar.result; - - iccException = result.getException(); - if (iccException != null) { - sendResult(response, result.payload, ar.exception); - } - break; - case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE: - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (IccIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - iccException = result.getException(); - if (iccException != null) { - sendResult(response, null, iccException); - break; - } - - data = result.payload; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] || - EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { - throw new IccFileTypeMismatch(); - } - - recordSize = new int[3]; - recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; - recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - recordSize[2] = recordSize[1] / recordSize[0]; - - sendResult(response, recordSize, null); - break; - case EVENT_GET_RECORD_SIZE_DONE: - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (IccIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - iccException = result.getException(); - - if (iccException != null) { - sendResult(response, null, iccException); - break; - } - - data = result.payload; - fileid = lc.efid; - recordNum = lc.recordNum; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { - throw new IccFileTypeMismatch(); - } - - if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) { - throw new IccFileTypeMismatch(); - } - - lc.recordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF; - - size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - - lc.countRecords = size / lc.recordSize; - - if (lc.loadAll) { - lc.results = new ArrayList<byte[]>(lc.countRecords); - } - - phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null, - lc.recordNum, - READ_RECORD_MODE_ABSOLUTE, - lc.recordSize, null, null, - obtainMessage(EVENT_READ_RECORD_DONE, lc)); - break; - case EVENT_GET_BINARY_SIZE_DONE: - ar = (AsyncResult)msg.obj; - response = (Message) ar.userObj; - result = (IccIoResult) ar.result; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - iccException = result.getException(); - - if (iccException != null) { - sendResult(response, null, iccException); - break; - } - - data = result.payload; - - fileid = msg.arg1; - - if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { - throw new IccFileTypeMismatch(); - } - - if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) { - throw new IccFileTypeMismatch(); - } - - size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8) - + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff); - - phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, null, - 0, 0, size, null, null, - obtainMessage(EVENT_READ_BINARY_DONE, - fileid, 0, response)); - break; - - case EVENT_READ_RECORD_DONE: - - ar = (AsyncResult)msg.obj; - lc = (LoadLinearFixedContext) ar.userObj; - result = (IccIoResult) ar.result; - response = lc.onLoaded; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - iccException = result.getException(); - - if (iccException != null) { - sendResult(response, null, iccException); - break; - } - - if (!lc.loadAll) { - sendResult(response, result.payload, null); - } else { - lc.results.add(result.payload); - - lc.recordNum++; - - if (lc.recordNum > lc.countRecords) { - sendResult(response, lc.results, null); - } else { - phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null, - lc.recordNum, - READ_RECORD_MODE_ABSOLUTE, - lc.recordSize, null, null, - obtainMessage(EVENT_READ_RECORD_DONE, lc)); - } - } - - break; - - case EVENT_READ_BINARY_DONE: - ar = (AsyncResult)msg.obj; - response = (Message) ar.userObj; - result = (IccIoResult) ar.result; - - if (ar.exception != null) { - sendResult(response, null, ar.exception); - break; - } - - iccException = result.getException(); - - if (iccException != null) { - sendResult(response, null, iccException); - break; - } - - sendResult(response, result.payload, null); - break; - - }} catch (Exception exc) { - if (response != null) { - sendResult(response, null, exc); - } else { - Log.e(LOG_TAG, "uncaught exception", exc); - } - } + super.handleMessage(msg); } - //***** Private Methods - - private void sendResult(Message response, Object result, Throwable ex) { - if (response == null) { - return; - } - - AsyncResult.forMessage(response, result, ex); + protected void logd(String msg) { + Log.d(LOG_TAG, "[SIMFileHandler] " + msg); + } - response.sendToTarget(); + protected void loge(String msg) { + Log.e(LOG_TAG, "[SIMFileHandler] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java index 57d76c25c927..e33e556b6d7b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java +++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java @@ -17,23 +17,26 @@ package com.android.internal.telephony.gsm; import android.os.AsyncResult; -import android.os.RegistrantList; -import android.os.Registrant; import android.os.Handler; import android.os.Message; -import android.telephony.gsm.SmsMessage; +import android.os.Registrant; import android.util.Log; -import java.util.ArrayList; -import com.android.internal.telephony.IccUtils; +import static com.android.internal.telephony.TelephonyProperties.*; + import com.android.internal.telephony.AdnRecord; import com.android.internal.telephony.AdnRecordCache; import com.android.internal.telephony.AdnRecordLoader; import com.android.internal.telephony.CommandsInterface; +import com.android.internal.telephony.gsm.SimCard; +import com.android.internal.telephony.gsm.SmsMessage; import com.android.internal.telephony.IccException; +import com.android.internal.telephony.IccFileHandler; import com.android.internal.telephony.IccRecords; -import static com.android.internal.telephony.TelephonyProperties.*; -import com.android.internal.telephony.gsm.SimCard; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; + +import java.util.ArrayList; /** * {@hide} @@ -47,36 +50,16 @@ public final class SIMRecords extends IccRecords { //***** Instance Variables - GSMPhone phone; - RegistrantList recordsLoadedRegistrants = new RegistrantList(); - - int recordsToLoad; // number of pending load requests - - AdnRecordCache adnCache; - VoiceMailConstants mVmConfig; - - //***** Cached SIM State; cleared on channel close - boolean recordsRequested = false; // true if we've made requests for the sim records + //***** Cached SIM State; cleared on channel close String imsi; - String iccid; - String msisdn = null; // My mobile number - String msisdnTag = null; - String voiceMailNum = null; - String voiceMailTag = null; - String newVoiceMailNum = null; - String newVoiceMailTag = null; - boolean isVoiceMailFixed = false; - int countVoiceMessages = 0; boolean callForwardingEnabled; - int mncLength = 0; // 0 is used to indicate that the value - // is not initialized - int mailboxIndex = 0; // 0 is no mailbox dailing number associated + /** - * Sates only used by getSpnFsm FSM + * States only used by getSpnFsm FSM */ private Get_Spn_Fsm_State spnState; @@ -157,9 +140,8 @@ public final class SIMRecords extends IccRecords { //***** Constructor - SIMRecords(GSMPhone phone) { - super(phone); - this.phone = phone; + SIMRecords(GSMPhone p) { + super(p); adnCache = new AdnRecordCache(phone); @@ -171,19 +153,26 @@ public final class SIMRecords extends IccRecords { recordsToLoad = 0; - phone.mCM.registerForSIMReady(this, EVENT_SIM_READY, null); - phone.mCM.registerForOffOrNotAvailable( + p.mCM.registerForSIMReady(this, EVENT_SIM_READY, null); + p.mCM.registerForOffOrNotAvailable( this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); - phone.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); - phone.mCM.setOnIccRefresh(this, EVENT_SIM_REFRESH, null); + p.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null); + p.mCM.setOnIccRefresh(this, EVENT_SIM_REFRESH, null); // Start off by setting empty state - onRadioOffOrNotAvailable(); + onRadioOffOrNotAvailable(); } - protected AdnRecordCache getAdnCache() { - return adnCache; + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForSIMReady(this); + phone.mCM.unregisterForOffOrNotAvailable( this); + phone.mCM.unSetOnIccRefresh(this); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SIMRecords finalized"); } protected void onRadioOffOrNotAvailable() { @@ -197,7 +186,7 @@ public final class SIMRecords extends IccRecords { // -1 means no EF_SPN found; treat accordingly. spnDisplayCondition = -1; efMWIS = null; - efCPHS_MWI = null; + efCPHS_MWI = null; spn = null; spdiNetworks = null; pnnHomeName = null; @@ -205,9 +194,9 @@ public final class SIMRecords extends IccRecords { adnCache.reset(); phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, null); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, null); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, null); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY, null); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, null); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null); // recordsRequested is set to false indicating that the SIM // read requests made so far are not valid. This is set to @@ -217,14 +206,6 @@ public final class SIMRecords extends IccRecords { //***** Public Methods - public void registerForRecordsLoaded(Handler h, int what, Object obj) { - Registrant r = new Registrant(h, what, obj); - recordsLoadedRegistrants.add(r); - - if (recordsToLoad == 0 && recordsRequested == true) { - r.notifyRegistrant(new AsyncResult(null, null, null)); - } - } /** Returns null if SIM is not yet ready */ public String getIMSI() { @@ -274,21 +255,13 @@ public final class SIMRecords extends IccRecords { } /** - * Return Service Provider Name stored in SIM - * @return null if SIM is not yet ready - */ - public String getServiceProvideName() { - return spn; - } - - /** * Set voice mail number to SIM record * * The voice mail number can be stored either in EF_MBDN (TS 51.011) or * EF_MAILBOX_CPHS (CPHS 4.2) * * If EF_MBDN is available, store the voice mail number to EF_MBDN - * + * * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS * * So the voice mail number will be stored in both EFs if both are available @@ -346,7 +319,7 @@ public final class SIMRecords extends IccRecords { * Sets the SIM voice message waiting indicator records * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported * @param countWaiting The number of messages waiting, if known. Use - * -1 to indicate that an unknown number of + * -1 to indicate that an unknown number of * messages are waiting */ public void @@ -367,17 +340,17 @@ public final class SIMRecords extends IccRecords { countVoiceMessages = countWaiting; - phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, + phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, (countVoiceMessages != 0) ? "true" : "false"); - phone.notifyMessageWaitingIndicator(); + ((GSMPhone) phone).notifyMessageWaitingIndicator(); try { if (efMWIS != null) { // TS 51.011 10.3.45 // lsb of byte 0 is 'voicemail' status - efMWIS[0] = (byte)((efMWIS[0] & 0xfe) + efMWIS[0] = (byte)((efMWIS[0] & 0xfe) | (countVoiceMessages == 0 ? 0 : 1)); // byte 1 is the number of voice messages waiting @@ -389,17 +362,17 @@ public final class SIMRecords extends IccRecords { efMWIS[1] = (byte) countWaiting; } - ((SIMFileHandler)phone.getIccFileHandler()).updateEFLinearFixed( + phone.getIccFileHandler().updateEFLinearFixed( EF_MWIS, 1, efMWIS, null, obtainMessage (EVENT_UPDATE_DONE, EF_MWIS)); - } + } if (efCPHS_MWI != null) { // Refer CPHS4_2.WW6 B4.2.3 - efCPHS_MWI[0] = (byte)((efCPHS_MWI[0] & 0xf0) + efCPHS_MWI[0] = (byte)((efCPHS_MWI[0] & 0xf0) | (countVoiceMessages == 0 ? 0x5 : 0xa)); - ((SIMFileHandler)phone.getIccFileHandler()).updateEFTransparent( + phone.getIccFileHandler().updateEFTransparent( EF_VOICE_MAIL_INDICATOR_CPHS, efCPHS_MWI, obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS)); } @@ -409,20 +382,6 @@ public final class SIMRecords extends IccRecords { } } - /** @return true if there are messages waiting, false otherwise. */ - public boolean getVoiceMessageWaiting() { - return countVoiceMessages != 0; - } - - /** - * Returns number of voice messages waiting, if available - * If not available (eg, on an older CPHS SIM) -1 is returned if - * getVoiceMessageWaiting() is true - */ - public int getCountVoiceMessages() { - return countVoiceMessages; - } - public boolean getVoiceCallForwardingFlag() { return callForwardingEnabled; } @@ -436,7 +395,7 @@ public final class SIMRecords extends IccRecords { phone.setSystemProperty(PROPERTY_LINE1_VOICE_CALL_FORWARDING, (callForwardingEnabled ? "true" : "false")); - phone.notifyCallForwardingIndicator(); + ((GSMPhone) phone).notifyCallForwardingIndicator(); try { if (mEfCfis != null) { @@ -450,7 +409,7 @@ public final class SIMRecords extends IccRecords { // TODO: Should really update other fields in EF_CFIS, eg, // dialing number. We don't read or use it right now. - ((SIMFileHandler)phone.getIccFileHandler()).updateEFLinearFixed( + phone.getIccFileHandler().updateEFLinearFixed( EF_CFIS, 1, mEfCfis, null, obtainMessage (EVENT_UPDATE_DONE, EF_CFIS)); } @@ -464,7 +423,7 @@ public final class SIMRecords extends IccRecords { | CFF_UNCONDITIONAL_DEACTIVE); } - ((SIMFileHandler)phone.getIccFileHandler()).updateEFTransparent( + phone.getIccFileHandler().updateEFTransparent( EF_CFF_CPHS, mEfCff, obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS)); } @@ -530,19 +489,19 @@ public final class SIMRecords extends IccRecords { case EVENT_RADIO_OFF_OR_NOT_AVAILABLE: onRadioOffOrNotAvailable(); - break; + break; /* IO events */ case EVENT_GET_IMSI_DONE: isRecordLoadResponse = true; - + ar = (AsyncResult)msg.obj; if (ar.exception != null) { Log.e(LOG_TAG, "Exception querying IMSI", ar.exception); break; - } - + } + imsi = (String) ar.result; // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more @@ -551,10 +510,10 @@ public final class SIMRecords extends IccRecords { Log.e(LOG_TAG, "invalid IMSI " + imsi); imsi = null; } - + Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx"); - phone.mSimCard.updateImsiConfiguration(imsi); - phone.mSimCard.broadcastSimStateChangedIntent( + ((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi); + ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( SimCard.INTENT_VALUE_ICC_IMSI, null); break; @@ -604,20 +563,20 @@ public final class SIMRecords extends IccRecords { ar = (AsyncResult)msg.obj; if (ar.exception != null) { - - Log.d(LOG_TAG, "Invalid or missing EF" + + Log.d(LOG_TAG, "Invalid or missing EF" + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? "[MAILBOX]" : "[MBDN]")); // Bug #645770 fall back to CPHS // FIXME should use SST to decide if (msg.what == EVENT_GET_MBDN_DONE) { - //load CPHS on fail... + //load CPHS on fail... // FIXME right now, only load line1's CPHS voice mail entry recordsToLoad += 1; new AdnRecordLoader(phone).loadFromEF( - EF_MAILBOX_CPHS, EF_EXT1, 1, + EF_MAILBOX_CPHS, EF_EXT1, 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); } break; @@ -625,7 +584,8 @@ public final class SIMRecords extends IccRecords { adn = (AdnRecord)ar.result; - Log.d(LOG_TAG, "VM: " + adn + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]")); + Log.d(LOG_TAG, "VM: " + adn + + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]")); if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) { // Bug #645770 fall back to CPHS @@ -633,7 +593,7 @@ public final class SIMRecords extends IccRecords { // FIXME right now, only load line1's CPHS voice mail entry recordsToLoad += 1; new AdnRecordLoader(phone).loadFromEF( - EF_MAILBOX_CPHS, EF_EXT1, 1, + EF_MAILBOX_CPHS, EF_EXT1, 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); break; @@ -697,13 +657,13 @@ public final class SIMRecords extends IccRecords { countVoiceMessages = data[1] & 0xff; if (voiceMailWaiting && countVoiceMessages == 0) { - // Unknown count = -1 + // Unknown count = -1 countVoiceMessages = -1; } - phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, + phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, voiceMailWaiting ? "true" : "false"); - phone.notifyMessageWaitingIndicator(); + ((GSMPhone) phone).notifyMessageWaitingIndicator(); break; case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE: @@ -732,10 +692,10 @@ public final class SIMRecords extends IccRecords { countVoiceMessages = 0; } - phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, - countVoiceMessages != 0 + phone.setSystemProperty(PROPERTY_LINE1_VOICE_MAIL_WAITING, + countVoiceMessages != 0 ? "true" : "false"); - phone.notifyMessageWaitingIndicator(); + ((GSMPhone) phone).notifyMessageWaitingIndicator(); } break; @@ -744,13 +704,13 @@ public final class SIMRecords extends IccRecords { ar = (AsyncResult)msg.obj; data = (byte[])ar.result; - + if (ar.exception != null) { break; - } + } iccid = IccUtils.bcdToString(data, 0, data.length); - + Log.d(LOG_TAG, "iccid: " + iccid); break; @@ -819,7 +779,7 @@ public final class SIMRecords extends IccRecords { phone.setSystemProperty(PROPERTY_LINE1_VOICE_CALL_FORWARDING, (callForwardingEnabled ? "true" : "false")); - phone.notifyCallForwardingIndicator(); + ((GSMPhone) phone).notifyCallForwardingIndicator(); } break; @@ -833,7 +793,7 @@ public final class SIMRecords extends IccRecords { break; } - parseEfSpdi(data); + parseEfSpdi(data); break; case EVENT_UPDATE_DONE: @@ -857,7 +817,7 @@ public final class SIMRecords extends IccRecords { for ( ; tlv.isValidObject() ; tlv.nextObject()) { if (tlv.getTag() == TAG_FULL_NETWORK_NAME) { - pnnHomeName + pnnHomeName = IccUtils.networkNameToString( tlv.getData(), 0, tlv.getData().length); break; @@ -892,7 +852,8 @@ public final class SIMRecords extends IccRecords { + ar.exception + " length " + index.length); } else { Log.d(LOG_TAG, "READ EF_SMS RECORD index=" + index[0]); - ((SIMFileHandler)phone.getIccFileHandler()).loadEFLinearFixed(EF_SMS,index[0],obtainMessage(EVENT_GET_SMS_DONE)); + phone.getIccFileHandler().loadEFLinearFixed(EF_SMS,index[0], + obtainMessage(EVENT_GET_SMS_DONE)); } break; @@ -1013,20 +974,20 @@ public final class SIMRecords extends IccRecords { IccUtils.bytesToHexString(data)); mEfCfis = data; - + // Refer TS 51.011 Section 10.3.46 for the content description callForwardingEnabled = ((data[1] & 0x01) != 0); phone.setSystemProperty(PROPERTY_LINE1_VOICE_CALL_FORWARDING, (callForwardingEnabled ? "true" : "false")); - phone.notifyCallForwardingIndicator(); + ((GSMPhone) phone).notifyCallForwardingIndicator(); break; }}catch (RuntimeException exc) { // I don't want these exceptions to be fatal Log.w(LOG_TAG, "Exception parsing SIM record", exc); - } finally { + } finally { // Count up record load responses even if they are fails if (isRecordLoadResponse) { onRecordLoaded(); @@ -1039,12 +1000,12 @@ public final class SIMRecords extends IccRecords { case EF_MBDN: recordsToLoad++; new AdnRecordLoader(phone).loadFromEF(EF_MBDN, EF_EXT6, - mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE)); + mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE)); break; case EF_MAILBOX_CPHS: recordsToLoad++; new AdnRecordLoader(phone).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1, - 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); + 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE)); break; default: // For now, fetch all records if this is not a @@ -1060,7 +1021,7 @@ public final class SIMRecords extends IccRecords { if (result == null || result.length == 0) { return; } - + switch ((result[0])) { case CommandsInterface.SIM_REFRESH_FILE_UPDATED: // result[1] contains the EFID of the updated file. @@ -1111,7 +1072,7 @@ public final class SIMRecords extends IccRecords { Log.i("ENF", "message text " + message.getMessageBody()); - phone.mSMS.dispatchMessage(message); + ((GSMPhone) phone).mSMS.dispatchMessage(message); } } @@ -1146,7 +1107,7 @@ public final class SIMRecords extends IccRecords { Log.i("ENF", "message text " + message.getMessageBody()); - phone.mSMS.dispatchMessage(message); + ((GSMPhone) phone).mSMS.dispatchMessage(message); // 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3 // 1 == "received by MS from network; message read" @@ -1154,8 +1115,8 @@ public final class SIMRecords extends IccRecords { ba[0] = 1; if (false) { // XXX writing seems to crash RdoServD - ((SIMFileHandler)phone.getIccFileHandler()).updateEFLinearFixed(EF_SMS, i, ba, null, - obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); + phone.getIccFileHandler().updateEFLinearFixed(EF_SMS, + i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i)); } } } @@ -1173,19 +1134,17 @@ public final class SIMRecords extends IccRecords { recordsToLoad = 0; } } - + protected void onAllRecordsLoaded() { Log.d(LOG_TAG, "SIMRecords: record load complete"); // Some fields require more than one SIM record to set - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, - getSIMOperatorNumeric()); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, getSIMOperatorNumeric()); if (imsi != null) { - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY, - MccTable.countryCodeForMcc( - Integer.parseInt(imsi.substring(0,3)))); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, + MccTable.countryCodeForMcc(Integer.parseInt(imsi.substring(0,3)))); } else { Log.e("SIM", "[SIMRecords] onAllRecordsLoaded: imsi is NULL!"); @@ -1195,13 +1154,13 @@ public final class SIMRecords extends IccRecords { recordsLoadedRegistrants.notifyRegistrants( new AsyncResult(null, null, null)); - phone.mSimCard.broadcastSimStateChangedIntent( + ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( SimCard.INTENT_VALUE_ICC_LOADED, null); } - + //***** Private Methods - + private void setVoiceMailByCountry (String spn) { if (mVmConfig.containsCarrier(spn)) { isVoiceMailFixed = true; @@ -1214,7 +1173,7 @@ public final class SIMRecords extends IccRecords { /* broadcast intent SIM_READY here so that we can make sure READY is sent before IMSI ready */ - phone.mSimCard.broadcastSimStateChangedIntent( + ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent( SimCard.INTENT_VALUE_ICC_READY, null); fetchSimRecords(); @@ -1222,14 +1181,14 @@ public final class SIMRecords extends IccRecords { private void fetchSimRecords() { recordsRequested = true; + IccFileHandler iccFh = phone.getIccFileHandler(); - Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad); + Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad); phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE)); recordsToLoad++; - ((SIMFileHandler)phone.getIccFileHandler()).loadEFTransparent(EF_ICCID, - obtainMessage(EVENT_GET_ICCID_DONE)); + iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); recordsToLoad++; // FIXME should examine EF[MSISDN]'s capability configuration @@ -1239,17 +1198,14 @@ public final class SIMRecords extends IccRecords { recordsToLoad++; // Record number is subscriber profile - ((SIMFileHandler)phone.getIccFileHandler()).loadEFLinearFixed(EF_MBI, 1, - obtainMessage(EVENT_GET_MBI_DONE)); + iccFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); recordsToLoad++; - ((SIMFileHandler)phone.getIccFileHandler()).loadEFTransparent(EF_AD, - obtainMessage(EVENT_GET_AD_DONE)); + iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE)); recordsToLoad++; // Record number is subscriber profile - ((SIMFileHandler)phone.getIccFileHandler()).loadEFLinearFixed(EF_MWIS, 1, - obtainMessage(EVENT_GET_MWIS_DONE)); + iccFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE)); recordsToLoad++; @@ -1257,50 +1213,49 @@ public final class SIMRecords extends IccRecords { // the same info as EF[MWIS]. If both exist, both are updated // but the EF[MWIS] data is preferred // Please note this must be loaded after EF[MWIS] - ((SIMFileHandler)phone.getIccFileHandler()).loadEFTransparent( - EF_VOICE_MAIL_INDICATOR_CPHS, + iccFh.loadEFTransparent( + EF_VOICE_MAIL_INDICATOR_CPHS, obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE)); recordsToLoad++; // Same goes for Call Forward Status indicator: fetch both // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred. - ((SIMFileHandler)phone.getIccFileHandler()).loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); + iccFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE)); recordsToLoad++; - ((SIMFileHandler)phone.getIccFileHandler()).loadEFTransparent(EF_CFF_CPHS, - obtainMessage(EVENT_GET_CFF_DONE)); + iccFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE)); recordsToLoad++; getSpnFsm(true, null); - ((SIMFileHandler)phone.getIccFileHandler()).loadEFTransparent(EF_SPDI, - obtainMessage(EVENT_GET_SPDI_DONE)); + iccFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE)); recordsToLoad++; - ((SIMFileHandler)phone.getIccFileHandler()).loadEFLinearFixed(EF_PNN, 1, - obtainMessage(EVENT_GET_PNN_DONE)); + iccFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE)); recordsToLoad++; - ((SIMFileHandler)phone.getIccFileHandler()).loadEFTransparent(EF_SST, - obtainMessage(EVENT_GET_SST_DONE)); + iccFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE)); recordsToLoad++; - ((SIMFileHandler)phone.getIccFileHandler()).loadEFTransparent(EF_INFO_CPHS, - obtainMessage(EVENT_GET_INFO_CPHS_DONE)); + iccFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE)); recordsToLoad++; // XXX should seek instead of examining them all if (false) { // XXX - ((SIMFileHandler)phone.getIccFileHandler()).loadEFLinearFixedAll(EF_SMS, - obtainMessage(EVENT_GET_ALL_SMS_DONE)); + iccFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE)); recordsToLoad++; } if (CRASH_RIL) { - String sms = "0107912160130310f20404d0110041007030208054832b0120ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"; + String sms = "0107912160130310f20404d0110041007030208054832b0120" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffffffffffffffff"; byte[] ba = IccUtils.hexStringToBytes(sms); - ((SIMFileHandler)phone.getIccFileHandler()).updateEFLinearFixed(EF_SMS, 1, ba, null, + iccFh.updateEFLinearFixed(EF_SMS, 1, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, 1)); } } @@ -1387,7 +1342,7 @@ public final class SIMRecords extends IccRecords { case INIT: spn = null; - ((SIMFileHandler)phone.getIccFileHandler()).loadEFTransparent( EF_SPN, + phone.getIccFileHandler().loadEFTransparent( EF_SPN, obtainMessage(EVENT_GET_SPN_DONE)); recordsToLoad++; @@ -1401,16 +1356,16 @@ public final class SIMRecords extends IccRecords { if (DBG) log("Load EF_SPN: " + spn + " spnDisplayCondition: " + spnDisplayCondition); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn); spnState = Get_Spn_Fsm_State.IDLE; } else { - ((SIMFileHandler)phone.getIccFileHandler()).loadEFTransparent( EF_SPN_CPHS, + phone.getIccFileHandler().loadEFTransparent( EF_SPN_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); recordsToLoad++; spnState = Get_Spn_Fsm_State.READ_SPN_CPHS; - + // See TS 51.011 10.3.11. Basically, default to // show PLMN always, and SPN also if roaming. spnDisplayCondition = -1; @@ -1423,12 +1378,12 @@ public final class SIMRecords extends IccRecords { data, 0, data.length - 1 ); if (DBG) log("Load EF_SPN_CPHS: " + spn); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn); spnState = Get_Spn_Fsm_State.IDLE; } else { - ((SIMFileHandler)phone.getIccFileHandler()).loadEFTransparent( EF_SPN_SHORT_CPHS, - obtainMessage(EVENT_GET_SPN_DONE)); + phone.getIccFileHandler().loadEFTransparent( + EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE)); recordsToLoad++; spnState = Get_Spn_Fsm_State.READ_SPN_SHORT_CPHS; @@ -1441,7 +1396,7 @@ public final class SIMRecords extends IccRecords { data, 0, data.length - 1); if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn); - phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn); + phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn); }else { if (DBG) log("No SPN loaded in either CHPS or 3GPP"); } @@ -1479,7 +1434,7 @@ public final class SIMRecords extends IccRecords { spdiNetworks = new ArrayList<String>(plmnEntries.length / 3); for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) { - String plmnCode; + String plmnCode; plmnCode = IccUtils.bcdToString(plmnEntries, i, 3); // Valid operator codes are 5 or 6 digits @@ -1498,7 +1453,9 @@ public final class SIMRecords extends IccRecords { return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED ); } - private void log(String s) { + protected void log(String s) { Log.d(LOG_TAG, "[SIMRecords] " + s); } + } + diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java index 4d5e74d0fce8..9af3aa6a2e1f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimCard.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java @@ -16,6 +16,9 @@ package com.android.internal.telephony.gsm; +import android.app.ActivityManagerNative; +import android.content.Intent; +import android.content.res.Configuration; import android.os.AsyncResult; import android.os.RemoteException; import android.os.Handler; @@ -26,28 +29,28 @@ import android.util.Log; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.IccCard; -import com.android.internal.telephony.TelephonyProperties; import com.android.internal.telephony.Phone; +import com.android.internal.telephony.PhoneProxy; import com.android.internal.telephony.TelephonyIntents; -import android.content.Intent; -import android.content.res.Configuration; -import android.app.ActivityManagerNative; +import com.android.internal.telephony.TelephonyProperties; import static android.Manifest.permission.READ_PHONE_STATE; /** + * Note: this class shares common code with RuimCard, consider a base class to minimize code + * duplication. * {@hide} */ public final class SimCard extends Handler implements IccCard { static final String LOG_TAG="GSM"; - + //***** Instance Variables private static final boolean DBG = true; private GSMPhone phone; private CommandsInterface.IccStatus status = null; private boolean mDesiredPinLocked; - private boolean mDesiredFdnEnabled; + private boolean mDesiredFdnEnabled; private boolean mSimPinLocked = true; // Default to locked private boolean mSimFdnEnabled = false; // Default to disabled. // Will be updated when SIM_READY. @@ -88,7 +91,18 @@ public final class SimCard extends Handler implements IccCard { updateStateProperty(); } - + + public void dispose() { + //Unregister for all events + phone.mCM.unregisterForSIMLockedOrAbsent(this); + phone.mCM.unregisterForOffOrNotAvailable(this); + phone.mCM.unregisterForSIMReady(this); + } + + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SimCard finalized"); + } + //***** SimCard implementation public State @@ -138,7 +152,7 @@ public final class SimCard extends Handler implements IccCard { r.notifyRegistrant(); } } - + public void unregisterForAbsent(Handler h) { absentRegistrants.remove(h); } @@ -156,7 +170,7 @@ public final class SimCard extends Handler implements IccCard { public void unregisterForNetworkLocked(Handler h) { networkLockedRegistrants.remove(h); } - + public void registerForLocked(Handler h, int what, Object obj) { Registrant r = new Registrant (h, what, obj); @@ -173,7 +187,7 @@ public final class SimCard extends Handler implements IccCard { public void supplyPin (String pin, Message onComplete) { - phone.mCM.supplyIccPin(pin, + phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } @@ -182,7 +196,7 @@ public final class SimCard extends Handler implements IccCard { obtainMessage(EVENT_PINPUK_DONE, onComplete)); } public void supplyPin2 (String pin2, Message onComplete) { - phone.mCM.supplyIccPin2(pin2, + phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete)); } public void supplyPuk2 (String puk2, String newPin2, Message onComplete) { @@ -250,7 +264,7 @@ public final class SimCard extends Handler implements IccCard { } public String getServiceProviderName () { - return phone.mSIMRecords.getServiceProvideName(); + return phone.mSIMRecords.getServiceProviderName(); } //***** Handler implementation @@ -413,7 +427,7 @@ public final class SimCard extends Handler implements IccCard { return; } - CommandsInterface.IccStatus newStatus + CommandsInterface.IccStatus newStatus = (CommandsInterface.IccStatus) ar.result; handleSimStatus(newStatus); @@ -424,7 +438,7 @@ public final class SimCard extends Handler implements IccCard { boolean transitionedIntoPinLocked; boolean transitionedIntoAbsent; boolean transitionedIntoNetworkLocked; - + SimCard.State oldState, newState; oldState = getState(); @@ -443,7 +457,7 @@ public final class SimCard extends Handler implements IccCard { if (transitionedIntoPinLocked) { if(DBG) log("Notify SIM pin or puk locked."); pinLockedRegistrants.notifyRegistrants(); - broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED, + broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED, (newState == State.PIN_REQUIRED) ? INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK); } else if (transitionedIntoAbsent) { diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java index e65fa36d763e..076da6bcf68c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java @@ -25,261 +25,77 @@ import android.os.ServiceManager; import android.telephony.PhoneNumberUtils; import android.util.Log; -import java.util.ArrayList; -import java.util.List; -import com.android.internal.telephony.IccPhoneBookInterfaceManager; import com.android.internal.telephony.AdnRecord; import com.android.internal.telephony.AdnRecordCache; +import com.android.internal.telephony.IccPhoneBookInterfaceManager; +import com.android.internal.telephony.PhoneProxy; + +import java.util.ArrayList; +import java.util.List; /** * SimPhoneBookInterfaceManager to provide an inter-process communication to * access ADN-like SIM records. */ -public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { - static final String LOG_TAG = "GSM"; - static final boolean DBG = false; - private GSMPhone phone; - private AdnRecordCache adnCache; - private final Object mLock = new Object(); - private int recordSize[]; - private boolean success; - private List<AdnRecord> records; - private static final boolean ALLOW_SIM_OP_IN_UI_THREAD = false; +public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager { + static final String LOG_TAG = "GSM"; - private static final int EVENT_GET_SIZE_DONE = 1; - private static final int EVENT_LOAD_DONE = 2; - private static final int EVENT_UPDATE_DONE = 3; Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { AsyncResult ar; - switch (msg.what) { - case EVENT_GET_SIZE_DONE: - ar = (AsyncResult) msg.obj; - synchronized (mLock) { - if (ar.exception == null) { - recordSize = (int[])ar.result; - // recordSize[0] is the record length - // recordSize[1] is the total length of the EF file - // recordSize[2] is the number of records in the EF file - log("GET_RECORD_SIZE Size " + recordSize[0] + - " total " + recordSize[1] + - " #record " + recordSize[2]); - mLock.notifyAll(); - } - } - break; - case EVENT_UPDATE_DONE: - ar = (AsyncResult) msg.obj; - synchronized (mLock) { - success = (ar.exception == null); - mLock.notifyAll(); - } - break; - case EVENT_LOAD_DONE: - ar = (AsyncResult)msg.obj; - synchronized (mLock) { - if (ar.exception == null) { - records = (List<AdnRecord>) - ((ArrayList<AdnRecord>) ar.result); - } else { - if(DBG) log("Cannot load ADN records"); - if (records != null) { - records.clear(); - } - } - mLock.notifyAll(); - } + switch(msg.what) { + default: + mBaseHandler.handleMessage(msg); break; } } }; public SimPhoneBookInterfaceManager(GSMPhone phone) { - this.phone = phone; + super(phone); adnCache = phone.mSIMRecords.getAdnCache(); - //publish(); //TODO REMOVE - } - - private void publish() { - // TODO T: Do we have to change the service - // as well to "iccphonebook"? - // defined in: device/commands/binder/Service_info.c - ServiceManager.addService("simphonebook", this); + //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy } - /** - * Replace oldAdn with newAdn in ADN-like record in EF - * - * getAdnRecordsInEf must be called at least once before this function, - * otherwise an error will be returned - * throws SecurityException if no WRITE_CONTACTS permission - * - * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN - * @param oldTag adn tag to be replaced - * @param oldPhoneNumber adn number to be replaced - * Set both oldTag and oldPhoneNubmer to "" means to replace an - * empty record, aka, insert new record - * @param newTag adn tag to be stored - * @param newPhoneNumber adn number ot be stored - * Set both newTag and newPhoneNubmer to "" means to replace the old - * record with empty one, aka, delete old record - * @param pin2 required to update EF_FDN, otherwise must be null - * @return true for success - */ - public boolean - updateAdnRecordsInEfBySearch (int efid, - String oldTag, String oldPhoneNumber, - String newTag, String newPhoneNumber, String pin2) { - - - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.WRITE_CONTACTS permission"); - } - - - if (DBG) log("updateAdnRecordsInEfBySearch: efid=" + efid + - " ("+ oldTag + "," + oldPhoneNumber + ")"+ "==>" + - " ("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); - synchronized(mLock) { - checkThread(); - success = false; - Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber); - AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); - adnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to update by search"); - } - } - return success; + public void dispose() { + super.dispose(); } - /** - * Update an ADN-like EF record by record index - * - * This is useful for iteration the whole ADN file, such as write the whole - * phone book or erase/format the whole phonebook - * throws SecurityException if no WRITE_CONTACTS permission - * - * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN - * @param newTag adn tag to be stored - * @param newPhoneNumber adn number to be stored - * Set both newTag and newPhoneNubmer to "" means to replace the old - * record with empty one, aka, delete old record - * @param index is 1-based adn record index to be updated - * @param pin2 required to update EF_FDN, otherwise must be null - * @return true for success - */ - public boolean - updateAdnRecordsInEfByIndex(int efid, String newTag, - String newPhoneNumber, int index, String pin2) { - - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.WRITE_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.WRITE_CONTACTS permission"); - } - - if (DBG) log("updateAdnRecordsInEfByIndex: efid=" + efid + - " Index=" + index + " ==> " + - "("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2); - synchronized(mLock) { - checkThread(); - success = false; - Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber); - adnCache.updateAdnByIndex(efid, newAdn, index, pin2, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to update by index"); - } - } - return success; + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SimPhoneBookInterfaceManager finalized"); } - /** - * Get the capacity of records in efid - * - * @param efid the EF id of a ADN-like SIM - * @return int[3] array - * recordSizes[0] is the single record length - * recordSizes[1] is the total length of the EF file - * recordSizes[2] is the number of records in the EF file - */ public int[] getAdnRecordsSize(int efid) { - if (DBG) log("getAdnRecordsSize: efid=" + efid); + if (DBG) logd("getAdnRecordsSize: efid=" + efid); synchronized(mLock) { checkThread(); recordSize = new int[3]; - Message response = mHandler.obtainMessage(EVENT_GET_SIZE_DONE); - ((SIMFileHandler)phone.getIccFileHandler()).getEFLinearRecordSize(efid, response); - try { - mLock.wait(); - } catch (InterruptedException e) { - log("interrupted while trying to load from the SIM"); - } - } - - return recordSize; - } - /** - * Loads the AdnRecords in efid and returns them as a - * List of AdnRecords - * - * throws SecurityException if no READ_CONTACTS permission - * - * @param efid the EF id of a ADN-like SIM - * @return List of AdnRecord - */ - public List<AdnRecord> getAdnRecordsInEf(int efid) { - - if (phone.getContext().checkCallingOrSelfPermission( - android.Manifest.permission.READ_CONTACTS) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires android.permission.READ_CONTACTS permission"); - } + //Using mBaseHandler, no difference in EVENT_GET_SIZE_DONE handling + Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE); - if (DBG) log("getAdnRecordsInEF: efid=" + efid); - - synchronized(mLock) { - checkThread(); - Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); - adnCache.requestLoadAllAdnLike(efid, response); + phone.getIccFileHandler().getEFLinearRecordSize(efid, response); try { mLock.wait(); } catch (InterruptedException e) { - log("interrupted while trying to load from the SIM"); + logd("interrupted while trying to load from the SIM"); } } - return records; - } - private void checkThread() { - if (!ALLOW_SIM_OP_IN_UI_THREAD) { - // Make sure this isn't the UI thread, since it will block - if (mHandler.getLooper().equals(Looper.myLooper())) { - Log.e(LOG_TAG, "query() called on the main UI thread!"); - throw new IllegalStateException( - "You cannot call query on this provder from the main UI thread."); - } - } + return recordSize; } - private void log(String msg) { + protected void logd(String msg) { Log.d(LOG_TAG, "[SimPbInterfaceManager] " + msg); } + + protected void loge(String msg) { + Log.e(LOG_TAG, "[SimPbInterfaceManager] " + msg); + } } + diff --git a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java index 26163eb4f6bc..875d8d01f81a 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java @@ -16,21 +16,22 @@ package com.android.internal.telephony.gsm; -import android.app.PendingIntent; import android.content.Context; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; -import android.os.ServiceManager; -import android.telephony.gsm.SmsManager; import android.util.Log; +import com.android.internal.telephony.IccConstants; +import com.android.internal.telephony.IccSmsInterfaceManager; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.PhoneProxy; +import com.android.internal.telephony.SmsRawData; + import java.util.ArrayList; import java.util.List; -import com.android.internal.telephony.IccUtils; -import com.android.internal.telephony.IccConstants; -import com.android.internal.telephony.IccSmsInterfaceManager; +import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; /** * SimSmsInterfaceManager to provide an inter-process communication to @@ -38,9 +39,8 @@ import com.android.internal.telephony.IccSmsInterfaceManager; */ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { static final String LOG_TAG = "GSM"; - static final boolean DBG = false; + static final boolean DBG = true; - private GSMPhone mPhone; private final Object mLock = new Object(); private boolean mSuccess; private List<SmsRawData> mSms; @@ -80,33 +80,31 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { }; public SimSmsInterfaceManager(GSMPhone phone) { - this.mPhone = phone; - //ServiceManager.addService("isms", this); //TODO REMOVE + super(phone); + mDispatcher = new GsmSMSDispatcher(phone); } - private void enforceReceiveAndSend(String message) { - Context context = mPhone.getContext(); + public void dispose() { + } - context.enforceCallingPermission( - "android.permission.RECEIVE_SMS", message); - context.enforceCallingPermission( - "android.permission.SEND_SMS", message); + protected void finalize() { + if(DBG) Log.d(LOG_TAG, "SimSmsInterfaceManager finalized"); } /** * Update the specified message on the SIM. * * @param index record index of message to update - * @param status new message status (STATUS_ON_SIM_READ, - * STATUS_ON_SIM_UNREAD, STATUS_ON_SIM_SENT, - * STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE) + * @param status new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) * @param pdu the raw PDU to store * @return success or not * */ public boolean - updateMessageOnSimEf(int index, int status, byte[] pdu) { - if (DBG) log("updateMessageOnSimEf: index=" + index + + updateMessageOnIccEf(int index, int status, byte[] pdu) { + if (DBG) log("updateMessageOnIccEf: index=" + index + " status=" + status + " ==> " + "("+ pdu + ")"); enforceReceiveAndSend("Updating message on SIM"); @@ -114,13 +112,13 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { mSuccess = false; Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); - if (status == SmsManager.STATUS_ON_SIM_FREE) { + if (status == STATUS_ON_ICC_FREE) { // Special case FREE: call deleteSmsOnSim instead of // manipulating the SIM record mPhone.mCM.deleteSmsOnSim(index, response); } else { byte[] record = makeSmsRecordData(status, pdu); - ((SIMFileHandler)mPhone.getIccFileHandler()).updateEFLinearFixed( + ((SIMFileHandler)mPhone.getIccFileHandler()).updateEFLinearFixed( IccConstants.EF_SMS, index, record, null, response); } @@ -137,13 +135,13 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { * Copy a raw SMS PDU to the SIM. * * @param pdu the raw PDU to store - * @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD, - * STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT) + * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, + * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) * @return success or not * */ - public boolean copyMessageToSimEf(int status, byte[] pdu, byte[] smsc) { - if (DBG) log("copyMessageToSimEf: status=" + status + " ==> " + + public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) { + if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " + "pdu=("+ pdu + "), smsm=(" + smsc +")"); enforceReceiveAndSend("Copying message to SIM"); synchronized(mLock) { @@ -163,11 +161,11 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { } /** - * Retrieves all messages currently stored on SIM. + * Retrieves all messages currently stored on ICC. * - * @return list of SmsRawData of all sms on SIM + * @return list of SmsRawData of all sms on ICC */ - public List<SmsRawData> getAllMessagesFromSimEf() { + public List<SmsRawData> getAllMessagesFromIccEf() { if (DBG) log("getAllMessagesFromEF"); Context context = mPhone.getContext(); @@ -189,119 +187,7 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager { return mSms; } - /** - * Send a Raw PDU SMS - * - * @param smsc the SMSC to send the message through, or NULL for the - * defatult SMSC - * @param pdu the raw PDU to send - * @param sentIntent if not NULL this <code>Intent</code> is - * broadcast when the message is sucessfully sent, or failed. - * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. - * @param deliveryIntent if not NULL this <code>Intent</code> is - * broadcast when the message is delivered to the recipient. The - * raw pdu of the status report is in the extended data ("pdu"). - */ - public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, - PendingIntent deliveryIntent) { - Context context = mPhone.getContext(); - - context.enforceCallingPermission( - "android.permission.SEND_SMS", - "Sending SMS message"); - if (DBG) log("sendRawPdu: smsc=" + smsc + - " pdu="+ pdu + " sentIntent" + sentIntent + - " deliveryIntent" + deliveryIntent); - mPhone.mSMS.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); - } - - /** - * Send a multi-part text based SMS. - * - * @param destinationAddress the address to send the message to - * @param scAddress is the service center address or null to use - * the current default SMSC - * @param parts an <code>ArrayList</code> of strings that, in order, - * comprise the original message - * @param sentIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been sent. - * The result code will be <code>Activity.RESULT_OK<code> for success, - * or one of these errors: - * <code>RESULT_ERROR_GENERIC_FAILURE</code> - * <code>RESULT_ERROR_RADIO_OFF</code> - * <code>RESULT_ERROR_NULL_PDU</code>. - * @param deliveryIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been delivered - * to the recipient. The raw pdu of the status report is in the - * extended data ("pdu"). - */ - public void sendMultipartText(String destinationAddress, String scAddress, List<String> parts, - List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { - Context context = mPhone.getContext(); - - context.enforceCallingPermission( - "android.permission.SEND_SMS", - "Sending SMS message"); - if (DBG) log("sendMultipartText"); - mPhone.mSMS.sendMultipartText(destinationAddress, scAddress, (ArrayList<String>) parts, - (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents); - } - - /** - * Generates an EF_SMS record from status and raw PDU. - * - * @param status Message status. See TS 51.011 10.5.3. - * @param pdu Raw message PDU. - * @return byte array for the record. - */ - private byte[] makeSmsRecordData(int status, byte[] pdu) { - byte[] data = new byte[IccConstants.SMS_RECORD_LENGTH]; - - // Status bits for this record. See TS 51.011 10.5.3 - data[0] = (byte)(status & 7); - - System.arraycopy(pdu, 0, data, 1, pdu.length); - - // Pad out with 0xFF's. - for (int j = pdu.length+1; j < IccConstants.SMS_RECORD_LENGTH; j++) { - data[j] = -1; - } - - return data; - } - - /** - * create SmsRawData lists from all sms record byte[] - * Use null to indicate "free" record - * - * @param messages List of message records from EF_SMS. - * @return SmsRawData list of all in-used records - */ - private ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) { - int count = messages.size(); - ArrayList<SmsRawData> ret; - - ret = new ArrayList<SmsRawData>(count); - - for (int i = 0; i < count; i++) { - byte[] ba = messages.get(i); - if (ba[0] == 0) { - ret.add(null); - } else { - ret.add(new SmsRawData(messages.get(i))); - } - } - - return ret; - } - - private void log(String msg) { + protected void log(String msg) { Log.d(LOG_TAG, "[SimSmsInterfaceManager] " + msg); } } diff --git a/telephony/java/com/android/internal/telephony/gsm/SimTlv.java b/telephony/java/com/android/internal/telephony/gsm/SimTlv.java index 00879ce657b6..30543c7becd1 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SimTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/SimTlv.java @@ -34,9 +34,8 @@ public class SimTlv int curDataOffset; int curDataLength; boolean hasValidTlvObject; - - public SimTlv(byte[] record, int offset, int length) - { + + public SimTlv(byte[] record, int offset, int length) { this.record = record; this.tlvOffset = offset; @@ -46,19 +45,15 @@ public class SimTlv hasValidTlvObject = parseCurrentTlvObject(); } - public boolean - nextObject() - { + public boolean nextObject() { if (!hasValidTlvObject) return false; curOffset = curDataOffset + curDataLength; - hasValidTlvObject = parseCurrentTlvObject(); + hasValidTlvObject = parseCurrentTlvObject(); return hasValidTlvObject; } - public boolean - isValidObject() - { + public boolean isValidObject() { return hasValidTlvObject; } @@ -68,9 +63,7 @@ public class SimTlv * 0 and 0xff are invalid tag values * valid tags range from 1 - 0xfe */ - public int - getTag() - { + public int getTag() { if (!hasValidTlvObject) return 0; return record[curOffset] & 0xff; } @@ -79,10 +72,8 @@ public class SimTlv * Returns data associated with current TLV object * returns null if !isValidObject() */ - - public byte[] - getData() - { + + public byte[] getData() { if (!hasValidTlvObject) return null; byte[] ret = new byte[curDataLength]; @@ -95,14 +86,12 @@ public class SimTlv * @return false on invalid record, true on valid record */ - private boolean - parseCurrentTlvObject() - { + private boolean parseCurrentTlvObject() { // 0x00 and 0xff are invalid tag values if (record[curOffset] == 0 || (record[curOffset] & 0xff) == 0xff) { return false; } - + try { if ((record[curOffset + 1] & 0xff) < 0x80) { // one byte length 0 - 0x7f diff --git a/telephony/java/com/android/internal/telephony/gsm/SimUtils.java b/telephony/java/com/android/internal/telephony/gsm/SimUtils.java deleted file mode 100644 index 5cd5a90d9f2f..000000000000 --- a/telephony/java/com/android/internal/telephony/gsm/SimUtils.java +++ /dev/null @@ -1,329 +0,0 @@ -/* - * 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.gsm; - -import java.io.UnsupportedEncodingException; - -import android.graphics.Bitmap; -import android.graphics.Color; -import android.util.Log; - -/** - * Various methods, useful for dealing with SIM data. - */ -public class SimUtils -{ - static final String LOG_TAG="GSM"; - - /** - * Many fields in GSM SIM's are stored as nibble-swizzled BCD - * - * Assumes left-justified field that may be padded right with 0xf - * values. - * - * Stops on invalid BCD value, returning string so far - */ - public static String - bcdToString(byte[] data, int offset, int length) - { - StringBuilder ret = new StringBuilder(length*2); - - for (int i = offset ; i < offset + length ; i++) { - byte b; - int v; - - v = data[i] & 0xf; - if (v > 9) break; - ret.append((char)('0' + v)); - - v = (data[i] >> 4) & 0xf; - if (v > 9) break; - ret.append((char)('0' + v)); - } - - return ret.toString(); - } - - - /** - * Decodes a GSM-style BCD byte, returning an int ranging from 0-99. - * - * In GSM land, the least significant BCD digit is stored in the most - * significant nibble. - * - * Out-of-range digits are treated as 0 for the sake of the time stamp, - * because of this: - * - * TS 23.040 section 9.2.3.11 - * "if the MS receives a non-integer value in the SCTS, it shall - * assume the digit is set to 0 but shall store the entire field - * exactly as received" - */ - public static int - bcdByteToInt(byte b) - { - int ret = 0; - - // treat out-of-range BCD values as 0 - if ((b & 0xf0) <= 0x90) { - ret = (b >> 4) & 0xf; - } - - if ((b & 0x0f) <= 0x09) { - ret += (b & 0xf) * 10; - } - - return ret; - } - - - /** - * Decodes a string field that's formatted like the EF[ADN] alpha - * identifier - * - * From TS 51.011 10.5.1: - * Coding: - * this alpha tagging shall use either - * - the SMS default 7 bit coded alphabet as defined in - * TS 23.038 [12] with bit 8 set to 0. The alpha identifier - * shall be left justified. Unused bytes shall be set to 'FF'; or - * - one of the UCS2 coded options as defined in annex B. - * - * Annex B from TS 11.11 V8.13.0: - * 1) If the first octet in the alpha string is '80', then the - * remaining octets are 16 bit UCS2 characters ... - * 2) if the first octet in the alpha string is '81', then the - * second octet contains a value indicating the number of - * characters in the string, and the third octet contains an - * 8 bit number which defines bits 15 to 8 of a 16 bit - * base pointer, where bit 16 is set to zero and bits 7 to 1 - * are also set to zero. These sixteen bits constitute a - * base pointer to a "half page" in the UCS2 code space, to be - * used with some or all of the remaining octets in the string. - * The fourth and subsequent octets contain codings as follows: - * If bit 8 of the octet is set to zero, the remaining 7 bits - * of the octet contain a GSM Default Alphabet character, - * whereas if bit 8 of the octet is set to one, then the - * remaining seven bits are an offset value added to the - * 16 bit base pointer defined earlier... - * 3) If the first octet of the alpha string is set to '82', then - * the second octet contains a value indicating the number of - * characters in the string, and the third and fourth octets - * contain a 16 bit number which defines the complete 16 bit - * base pointer to a "half page" in the UCS2 code space... - */ - public static String - adnStringFieldToString(byte[] data, int offset, int length) - { - if (length >= 1) { - if (data[offset] == (byte) 0x80) { - int ucslen = (length - 1) / 2; - String ret = null; - - try { - ret = new String(data, offset + 1, ucslen * 2, "utf-16be"); - } catch (UnsupportedEncodingException ex) { - Log.e(LOG_TAG, "implausible UnsupportedEncodingException", - ex); - } - - if (ret != null) { - // trim off trailing FFFF characters - - ucslen = ret.length(); - while (ucslen > 0 && ret.charAt(ucslen - 1) == '\uFFFF') - ucslen--; - - return ret.substring(0, ucslen); - } - } - } - - boolean isucs2 = false; - char base = '\0'; - int len = 0; - - if (length >= 3 && data[offset] == (byte) 0x81) { - len = data[offset + 1] & 0xFF; - if (len > length - 3) - len = length - 3; - - base = (char) ((data[offset + 2] & 0xFF) << 7); - offset += 3; - isucs2 = true; - } else if (length >= 4 && data[offset] == (byte) 0x82) { - len = data[offset + 1] & 0xFF; - if (len > length - 4) - len = length - 4; - - base = (char) (((data[offset + 2] & 0xFF) << 8) | - (data[offset + 3] & 0xFF)); - offset += 4; - isucs2 = true; - } - - if (isucs2) { - StringBuilder ret = new StringBuilder(); - - while (len > 0) { - // UCS2 subset case - - if (data[offset] < 0) { - ret.append((char) (base + (data[offset] & 0x7F))); - offset++; - len--; - } - - // GSM character set case - - int count = 0; - while (count < len && data[offset + count] >= 0) - count++; - - ret.append(GsmAlphabet.gsm8BitUnpackedToString(data, - offset, count)); - - offset += count; - len -= count; - } - - return ret.toString(); - } - - return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length); - } - - static int - hexCharToInt(char c) - { - if (c >= '0' && c <= '9') return (c - '0'); - if (c >= 'A' && c <= 'F') return (c - 'A' + 10); - if (c >= 'a' && c <= 'f') return (c - 'a' + 10); - - throw new RuntimeException ("invalid hex char '" + c + "'"); - } - - /** - * Converts a hex String to a byte array. - * - * @param s A string of hexadecimal characters, must be an even number of - * chars long - * - * @return byte array representation - * - * @throws RuntimeException on invalid format - */ - public static byte[] - hexStringToBytes(String s) - { - byte[] ret; - - if (s == null) return null; - - int sz = s.length(); - - ret = new byte[sz/2]; - - for (int i=0 ; i <sz ; i+=2) { - ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4) - | hexCharToInt(s.charAt(i+1))); - } - - return ret; - } - - - /** - * Converts a byte array into a String hexidecimal characters - * - * null returns null - */ - public static String - bytesToHexString(byte[] bytes) - { - if (bytes == null) return null; - - StringBuilder ret = new StringBuilder(2*bytes.length); - - for (int i = 0 ; i < bytes.length ; i++) { - int b; - - b = 0x0f & (bytes[i] >> 4); - - ret.append("0123456789abcdef".charAt(b)); - - b = 0x0f & bytes[i]; - - ret.append("0123456789abcdef".charAt(b)); - } - - return ret.toString(); - } - - - /** - * Convert a TS 24.008 Section 10.5.3.5a Network Name field to a string - * "offset" points to "octet 3", the coding scheme byte - * empty string returned on decode error - */ - public static String - networkNameToString(byte[] data, int offset, int length) - { - String ret; - - if ((data[offset] & 0x80) != 0x80 || length < 1) { - return ""; - } - - switch ((data[offset] >>> 4) & 0x7) { - case 0: - // SMS character set - int countSeptets; - int unusedBits = data[offset] & 7; - countSeptets = (((length - 1) * 8) - unusedBits) / 7 ; - ret = GsmAlphabet.gsm7BitPackedToString( - data, offset + 1, countSeptets); - break; - case 1: - // UCS2 - try { - ret = new String(data, - offset + 1, length - 1, "utf-16"); - } catch (UnsupportedEncodingException ex) { - ret = ""; - Log.e(LOG_TAG,"implausible UnsupportedEncodingException", ex); - } - break; - - // unsupported encoding - default: - ret = ""; - break; - } - - // "Add CI" - // "The MS should add the letters for the Country's Initials and - // a separator (e.g. a space) to the text string" - - if ((data[offset] & 0x40) != 0) { - // FIXME(mkf) add country initials here - - } - - return ret; - } -} diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java new file mode 100755 index 000000000000..d70b588e0918 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java @@ -0,0 +1,1058 @@ +/* + * 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.gsm; + +import android.pim.Time; +import android.os.Parcel; +import android.telephony.PhoneNumberUtils; +import android.util.Config; +import android.util.Log; +import com.android.internal.telephony.IccUtils; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; +import com.android.internal.telephony.SmsHeader; +import com.android.internal.telephony.SmsMessageBase; + +import java.io.ByteArrayOutputStream; +import java.io.UnsupportedEncodingException; + +import static android.telephony.SmsMessage.ENCODING_7BIT; +import static android.telephony.SmsMessage.ENCODING_8BIT; +import static android.telephony.SmsMessage.ENCODING_16BIT; +import static android.telephony.SmsMessage.ENCODING_UNKNOWN; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES; +import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS; +import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER; +import static android.telephony.SmsMessage.MessageClass; + +/** + * A Short Message Service message. + * + */ +public class SmsMessage extends SmsMessageBase{ + static final String LOG_TAG = "GSM"; + + private MessageClass messageClass; + + /** + * TP-Message-Type-Indicator + * 9.2.3 + */ + private int mti; + + /** TP-Protocol-Identifier (TP-PID) */ + private int protocolIdentifier; + + // TP-Data-Coding-Scheme + // see TS 23.038 + private int dataCodingScheme; + + // TP-Reply-Path + // e.g. 23.040 9.2.2.1 + private boolean replyPathPresent = false; + + // "Message Marked for Automatic Deletion Group" + // 23.038 Section 4 + private boolean automaticDeletion; + + /** True if Status Report is for SMS-SUBMIT; false for SMS-COMMAND. */ + private boolean forSubmit; + + /** The address of the receiver. */ + private GsmSmsAddress recipientAddress; + + /** Time when SMS-SUBMIT was delivered from SC to MSE. */ + private long dischargeTimeMillis; + + /** + * TP-Status - status of a previously submitted SMS. + * This field applies to SMS-STATUS-REPORT messages. 0 indicates success; + * see TS 23.040, 9.2.3.15 for description of other possible values. + */ + private int status; + + /** + * TP-Status - status of a previously submitted SMS. + * This field is true iff the message is a SMS-STATUS-REPORT message. + */ + private boolean isStatusReportMessage = false; + + public static class SubmitPdu extends SubmitPduBase { + } + + /** + * Create an SmsMessage from a raw PDU. + */ + public static SmsMessage createFromPdu(byte[] pdu) { + try { + SmsMessage msg = new SmsMessage(); + msg.parsePdu(pdu); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the + * +CMT unsolicited response (PDU mode, of course) + * +CMT: [<alpha>],<length><CR><LF><pdu> + * + * Only public for debugging + * + * {@hide} + */ + public static SmsMessage newFromCMT(String[] lines) { + try { + SmsMessage msg = new SmsMessage(); + msg.parsePdu(IccUtils.hexStringToBytes(lines[1])); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** @hide */ + public static SmsMessage newFromCMTI(String line) { + // the thinking here is not to read the message immediately + // FTA test case + Log.e(LOG_TAG, "newFromCMTI: not yet supported"); + return null; + } + + /** @hide */ + public static SmsMessage newFromCDS(String line) { + try { + SmsMessage msg = new SmsMessage(); + msg.parsePdu(IccUtils.hexStringToBytes(line)); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * Note: This functionality is currently not supported in GSM mode. + * @hide + */ + public static SmsMessageBase newFromParcel(Parcel p){ + Log.w(LOG_TAG, "newFromParcel: is not supported in GSM mode."); + return null; + } + + /** + * Create an SmsMessage from an SMS EF record. + * + * @param index Index of SMS record. This should be index in ArrayList + * returned by SmsManager.getAllMessagesFromSim + 1. + * @param data Record data. + * @return An SmsMessage representing the record. + * + * @hide + */ + public static SmsMessage createFromEfRecord(int index, byte[] data) { + try { + SmsMessage msg = new SmsMessage(); + + msg.indexOnIcc = index; + + // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT, + // or STORED_UNSENT + // See TS 51.011 10.5.3 + if ((data[0] & 1) == 0) { + Log.w(LOG_TAG, + "SMS parsing failed: Trying to parse a free record"); + return null; + } else { + msg.statusOnIcc = data[0] & 0x07; + } + + int size = data.length - 1; + + // Note: Data may include trailing FF's. That's OK; message + // should still parse correctly. + byte[] pdu = new byte[size]; + System.arraycopy(data, 1, pdu, 0, size); + msg.parsePdu(pdu); + return msg; + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex); + return null; + } + } + + /** + * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the + * length in bytes (not hex chars) less the SMSC header + */ + public static int getTPLayerLengthForPDU(String pdu) { + int len = pdu.length() / 2; + int smscLen = 0; + + smscLen = Integer.parseInt(pdu.substring(0, 2), 16); + + return len - smscLen - 1; + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + * @hide + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested, byte[] header) { + + // Perform null parameter checks. + if (message == null || destinationAddress == null) { + return null; + } + + SubmitPdu ret = new SubmitPdu(); + // MTI = SMS-SUBMIT, UDHI = header != null + byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00)); + ByteArrayOutputStream bo = getSubmitPduHead( + scAddress, destinationAddress, mtiByte, + statusReportRequested, ret); + + try { + // First, try encoding it with the GSM alphabet + + // User Data (and length) + byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header); + + if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) { + // Message too long + return null; + } + + // TP-Data-Coding-Scheme + // Default encoding, uncompressed + bo.write(0x00); + + // (no TP-Validity-Period) + + bo.write(userData, 0, userData.length); + } catch (EncodeException ex) { + byte[] userData, textPart; + // Encoding to the 7-bit alphabet failed. Let's see if we can + // send it as a UCS-2 encoded message + + try { + textPart = message.getBytes("utf-16be"); + } catch (UnsupportedEncodingException uex) { + Log.e(LOG_TAG, + "Implausible UnsupportedEncodingException ", + uex); + return null; + } + + if (header != null) { + userData = new byte[header.length + textPart.length]; + + System.arraycopy(header, 0, userData, 0, header.length); + System.arraycopy(textPart, 0, userData, header.length, textPart.length); + } + else { + userData = textPart; + } + + if (userData.length > MAX_USER_DATA_BYTES) { + // Message too long + return null; + } + + // TP-Data-Coding-Scheme + // Class 3, UCS-2 encoding, uncompressed + bo.write(0x0b); + + // (no TP-Validity-Period) + + // TP-UDL + bo.write(userData.length); + + bo.write(userData, 0, userData.length); + } + + ret.encodedMessage = bo.toByteArray(); + return ret; + } + + /** + * Get an SMS-SUBMIT PDU for a destination address and a message + * + * @param scAddress Service Centre address. Null means use default. + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, String message, + boolean statusReportRequested) { + + return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null); + } + + /** + * Get an SMS-SUBMIT PDU for a data message to a destination address & port + * + * @param scAddress Service Centre address. null == use default + * @param destinationAddress the address of the destination for the message + * @param destinationPort the port to deliver the message to at the + * destination + * @param data the dat for the message + * @return a <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message. + * Returns null on encode error. + */ + public static SubmitPdu getSubmitPdu(String scAddress, + String destinationAddress, short destinationPort, byte[] data, + boolean statusReportRequested) { + if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) { + Log.e(LOG_TAG, "SMS data message may only contain " + + (MAX_USER_DATA_BYTES - 7) + " bytes"); + return null; + } + + SubmitPdu ret = new SubmitPdu(); + ByteArrayOutputStream bo = getSubmitPduHead( + scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT, + // TP-UDHI = true + statusReportRequested, ret); + + // TP-Data-Coding-Scheme + // No class, 8 bit data + bo.write(0x04); + + // (no TP-Validity-Period) + + // User data size + bo.write(data.length + 7); + + // User data header size + bo.write(0x06); // header is 6 octets + + // User data header, indicating the destination port + bo.write(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT); // port + // addressing + // header + bo.write(0x04); // each port is 2 octets + bo.write((destinationPort >> 8) & 0xFF); // MSB of destination port + bo.write(destinationPort & 0xFF); // LSB of destination port + bo.write(0x00); // MSB of originating port + bo.write(0x00); // LSB of originating port + + // User data + bo.write(data, 0, data.length); + + ret.encodedMessage = bo.toByteArray(); + return ret; + } + + /** + * Create the beginning of a SUBMIT PDU. This is the part of the + * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu}, + * one of which takes a byte array and the other of which takes a + * <code>String</code>. + * + * @param scAddress Service Centre address. null == use default + * @param destinationAddress the address of the destination for the message + * @param mtiByte + * @param ret <code>SubmitPdu</code> containing the encoded SC + * address, if applicable, and the encoded message + */ + private static ByteArrayOutputStream getSubmitPduHead( + String scAddress, String destinationAddress, byte mtiByte, + boolean statusReportRequested, SubmitPdu ret) { + ByteArrayOutputStream bo = new ByteArrayOutputStream( + MAX_USER_DATA_BYTES + 40); + + // SMSC address with length octet, or 0 + if (scAddress == null) { + ret.encodedScAddress = null; + } else { + ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength( + scAddress); + } + + // TP-Message-Type-Indicator (and friends) + if (statusReportRequested) { + // Set TP-Status-Report-Request bit. + mtiByte |= 0x20; + if (Config.LOGD) Log.d(LOG_TAG, "SMS status report requested"); + } + bo.write(mtiByte); + + // space for TP-Message-Reference + bo.write(0); + + byte[] daBytes; + + daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress); + + // destination address length in BCD digits, ignoring TON byte and pad + // TODO Should be better. + bo.write((daBytes.length - 1) * 2 + - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0)); + + // destination address + bo.write(daBytes, 0, daBytes.length); + + // TP-Protocol-Identifier + bo.write(0); + return bo; + } + + static class PduParser { + byte pdu[]; + int cur; + SmsHeader userDataHeader; + byte[] userData; + int mUserDataSeptetPadding; + int mUserDataSize; + + PduParser(String s) { + this(IccUtils.hexStringToBytes(s)); + } + + PduParser(byte[] pdu) { + this.pdu = pdu; + cur = 0; + mUserDataSeptetPadding = 0; + } + + /** + * Parse and return the SC address prepended to SMS messages coming via + * the TS 27.005 / AT interface. Returns null on invalid address + */ + String getSCAddress() { + int len; + String ret; + + // length of SC Address + len = getByte(); + + if (len == 0) { + // no SC address + ret = null; + } else { + // SC address + try { + ret = PhoneNumberUtils + .calledPartyBCDToString(pdu, cur, len); + } catch (RuntimeException tr) { + Log.d(LOG_TAG, "invalid SC address: ", tr); + ret = null; + } + } + + cur += len; + + return ret; + } + + /** + * returns non-sign-extended byte value + */ + int getByte() { + return pdu[cur++] & 0xff; + } + + /** + * Any address except the SC address (eg, originating address) See TS + * 23.040 9.1.2.5 + */ + GsmSmsAddress getAddress() { + GsmSmsAddress ret; + + // "The Address-Length field is an integer representation of + // the number field, i.e. excludes any semi octet containing only + // fill bits." + // The TOA field is not included as part of this + int addressLength = pdu[cur] & 0xff; + int lengthBytes = 2 + (addressLength + 1) / 2; + + ret = new GsmSmsAddress(pdu, cur, lengthBytes); + + cur += lengthBytes; + + return ret; + } + + /** + * Parses an SC timestamp and returns a currentTimeMillis()-style + * timestamp + */ + + long getSCTimestampMillis() { + // TP-Service-Centre-Time-Stamp + int year = IccUtils.bcdByteToInt(pdu[cur++]); + int month = IccUtils.bcdByteToInt(pdu[cur++]); + int day = IccUtils.bcdByteToInt(pdu[cur++]); + int hour = IccUtils.bcdByteToInt(pdu[cur++]); + int minute = IccUtils.bcdByteToInt(pdu[cur++]); + int second = IccUtils.bcdByteToInt(pdu[cur++]); + + // For the timezone, the most significant bit of the + // least signficant nibble is the sign byte + // (meaning the max range of this field is 79 quarter-hours, + // which is more than enough) + + byte tzByte = pdu[cur++]; + + // Mask out sign bit. + int timezoneOffset = IccUtils + .bcdByteToInt((byte) (tzByte & (~0x08))); + + timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset + : -timezoneOffset; + + Time time = new Time(Time.TIMEZONE_UTC); + + // It's 2006. Should I really support years < 2000? + time.year = year >= 90 ? year + 1900 : year + 2000; + time.month = month - 1; + time.monthDay = day; + time.hour = hour; + time.minute = minute; + time.second = second; + + // Timezone offset is in quarter hours. + return time.toMillis(true) - (timezoneOffset * 15 * 60 * 1000); + } + + /** + * Pulls the user data out of the PDU, and separates the payload from + * the header if there is one. + * + * @param hasUserDataHeader true if there is a user data header + * @param dataInSeptets true if the data payload is in septets instead + * of octets + * @return the number of septets or octets in the user data payload + */ + int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) { + int offset = cur; + int userDataLength = pdu[offset++] & 0xff; + int headerSeptets = 0; + + if (hasUserDataHeader) { + int userDataHeaderLength = pdu[offset++] & 0xff; + + byte[] udh = new byte[userDataHeaderLength]; + System.arraycopy(pdu, offset, udh, 0, userDataHeaderLength); + userDataHeader = SmsHeader.parse(udh); + offset += userDataHeaderLength; + + int headerBits = (userDataHeaderLength + 1) * 8; + headerSeptets = headerBits / 7; + headerSeptets += (headerBits % 7) > 0 ? 1 : 0; + mUserDataSeptetPadding = (headerSeptets * 7) - headerBits; + } + + /* + * Here we just create the user data length to be the remainder of + * the pdu minus the user data hearder. This is because the count + * could mean the number of uncompressed sepets if the userdata is + * encoded in 7-bit. + */ + userData = new byte[pdu.length - offset]; + System.arraycopy(pdu, offset, userData, 0, userData.length); + cur = offset; + + if (dataInSeptets) { + // Return the number of septets + return userDataLength - headerSeptets; + } else { + // Return the number of octets + return userData.length; + } + } + + /** + * Returns the user data payload, not including the headers + * + * @return the user data payload, not including the headers + */ + byte[] getUserData() { + return userData; + } + + /** + * Returns the number of padding bits at the begining of the user data + * array before the start of the septets. + * + * @return the number of padding bits at the begining of the user data + * array before the start of the septets + */ + int getUserDataSeptetPadding() { + return mUserDataSeptetPadding; + } + + /** + * Returns an object representing the user data headers + * + * @return an object representing the user data headers + * + * {@hide} + */ + SmsHeader getUserDataHeader() { + return userDataHeader; + } + +/* + XXX Not sure what this one is supposed to be doing, and no one is using + it. + String getUserDataGSM8bit() { + // System.out.println("remainder of pud:" + + // HexDump.dumpHexString(pdu, cur, pdu.length - cur)); + int count = pdu[cur++] & 0xff; + int size = pdu[cur++]; + + // skip over header for now + cur += size; + + if (pdu[cur - 1] == 0x01) { + int tid = pdu[cur++] & 0xff; + int type = pdu[cur++] & 0xff; + + size = pdu[cur++] & 0xff; + + int i = cur; + + while (pdu[i++] != '\0') { + } + + int length = i - cur; + String mimeType = new String(pdu, cur, length); + + cur += length; + + if (false) { + System.out.println("tid = 0x" + HexDump.toHexString(tid)); + System.out.println("type = 0x" + HexDump.toHexString(type)); + System.out.println("header size = " + size); + System.out.println("mimeType = " + mimeType); + System.out.println("remainder of header:" + + HexDump.dumpHexString(pdu, cur, (size - mimeType.length()))); + } + + cur += size - mimeType.length(); + + // System.out.println("data count = " + count + " cur = " + cur + // + " :" + HexDump.dumpHexString(pdu, cur, pdu.length - cur)); + + MMSMessage msg = MMSMessage.parseEncoding(mContext, pdu, cur, + pdu.length - cur); + } else { + System.out.println(new String(pdu, cur, pdu.length - cur - 1)); + } + + return IccUtils.bytesToHexString(pdu); + } +*/ + + /** + * Interprets the user data payload as pack GSM 7bit characters, and + * decodes them into a String. + * + * @param septetCount the number of septets in the user data payload + * @return a String with the decoded characters + */ + String getUserDataGSM7Bit(int septetCount) { + String ret; + + ret = GsmAlphabet.gsm7BitPackedToString(pdu, cur, septetCount, + mUserDataSeptetPadding); + + cur += (septetCount * 7) / 8; + + return ret; + } + + /** + * Interprets the user data payload as UCS2 characters, and + * decodes them into a String. + * + * @param byteCount the number of bytes in the user data payload + * @return a String with the decoded characters + */ + String getUserDataUCS2(int byteCount) { + String ret; + + try { + ret = new String(pdu, cur, byteCount, "utf-16"); + } catch (UnsupportedEncodingException ex) { + ret = ""; + Log.e(LOG_TAG, "implausible UnsupportedEncodingException", ex); + } + + cur += byteCount; + return ret; + } + + boolean moreDataPresent() { + return (pdu.length > cur); + } + } + + /** {@inheritDoc} */ + public int getProtocolIdentifier() { + return protocolIdentifier; + } + + /** {@inheritDoc} */ + public boolean isReplace() { + return (protocolIdentifier & 0xc0) == 0x40 + && (protocolIdentifier & 0x3f) > 0 + && (protocolIdentifier & 0x3f) < 8; + } + + /** {@inheritDoc} */ + public boolean isCphsMwiMessage() { + return ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear() + || ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); + } + + /** {@inheritDoc} */ + public boolean isMWIClearMessage() { + if (isMwi && (mwiSense == false)) { + return true; + } + + return originatingAddress != null + && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageClear(); + } + + /** {@inheritDoc} */ + public boolean isMWISetMessage() { + if (isMwi && (mwiSense == true)) { + return true; + } + + return originatingAddress != null + && ((GsmSmsAddress) originatingAddress).isCphsVoiceMessageSet(); + } + + /** {@inheritDoc} */ + public boolean isMwiDontStore() { + if (isMwi && mwiDontStore) { + return true; + } + + if (isCphsMwiMessage()) { + // See CPHS 4.2 Section B.4.2.1 + // If the user data is a single space char, do not store + // the message. Otherwise, store and display as usual + if (" ".equals(getMessageBody())) { + ; + } + return true; + } + + return false; + } + + /** {@inheritDoc} */ + public int getStatus() { + return status; + } + + /** {@inheritDoc} */ + public boolean isStatusReportMessage() { + return isStatusReportMessage; + } + + /** {@inheritDoc} */ + public boolean isReplyPathPresent() { + return replyPathPresent; + } + + /** + * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6] + * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format: + * ME/TA converts each octet of TP data unit into two IRA character long + * hexad number (e.g. octet with integer value 42 is presented to TE as two + * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast, + * something else... + */ + private void parsePdu(byte[] pdu) { + mPdu = pdu; + // Log.d(LOG_TAG, "raw sms mesage:"); + // Log.d(LOG_TAG, s); + + PduParser p = new PduParser(pdu); + + scAddress = p.getSCAddress(); + + if (scAddress != null) { + if (Config.LOGD) Log.d(LOG_TAG, "SMS SC address: " + scAddress); + } + + // TODO(mkf) support reply path, user data header indicator + + // TP-Message-Type-Indicator + // 9.2.3 + int firstByte = p.getByte(); + + mti = firstByte & 0x3; + switch (mti) { + // TP-Message-Type-Indicator + // 9.2.3 + case 0: + parseSmsDeliver(p, firstByte); + break; + case 2: + parseSmsStatusReport(p, firstByte); + break; + default: + // TODO(mkf) the rest of these + throw new RuntimeException("Unsupported message type"); + } + } + + /** + * Parses a SMS-STATUS-REPORT message. + * + * @param p A PduParser, cued past the first byte. + * @param firstByte The first byte of the PDU, which contains MTI, etc. + */ + private void parseSmsStatusReport(PduParser p, int firstByte) { + isStatusReportMessage = true; + + // TP-Status-Report-Qualifier bit == 0 for SUBMIT + forSubmit = (firstByte & 0x20) == 0x00; + // TP-Message-Reference + messageRef = p.getByte(); + // TP-Recipient-Address + recipientAddress = p.getAddress(); + // TP-Service-Centre-Time-Stamp + scTimeMillis = p.getSCTimestampMillis(); + // TP-Discharge-Time + dischargeTimeMillis = p.getSCTimestampMillis(); + // TP-Status + status = p.getByte(); + + // The following are optional fields that may or may not be present. + if (p.moreDataPresent()) { + // TP-Parameter-Indicator + int extraParams = p.getByte(); + int moreExtraParams = extraParams; + while ((moreExtraParams & 0x80) != 0) { + // We only know how to parse a few extra parameters, all + // indicated in the first TP-PI octet, so skip over any + // additional TP-PI octets. + moreExtraParams = p.getByte(); + } + // TP-Protocol-Identifier + if ((extraParams & 0x01) != 0) { + protocolIdentifier = p.getByte(); + } + // TP-Data-Coding-Scheme + if ((extraParams & 0x02) != 0) { + dataCodingScheme = p.getByte(); + } + // TP-User-Data-Length (implies existence of TP-User-Data) + if ((extraParams & 0x04) != 0) { + boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; + parseUserData(p, hasUserDataHeader); + } + } + } + + private void parseSmsDeliver(PduParser p, int firstByte) { + replyPathPresent = (firstByte & 0x80) == 0x80; + + originatingAddress = p.getAddress(); + + if (originatingAddress != null) { + if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: " + + originatingAddress.address); + } + + // TP-Protocol-Identifier (TP-PID) + // TS 23.040 9.2.3.9 + protocolIdentifier = p.getByte(); + + // TP-Data-Coding-Scheme + // see TS 23.038 + dataCodingScheme = p.getByte(); + + if (Config.LOGV) { + Log.v(LOG_TAG, "SMS TP-PID:" + protocolIdentifier + + " data coding scheme: " + dataCodingScheme); + } + + scTimeMillis = p.getSCTimestampMillis(); + + if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis); + + boolean hasUserDataHeader = (firstByte & 0x40) == 0x40; + + parseUserData(p, hasUserDataHeader); + } + + /** + * Parses the User Data of an SMS. + * + * @param p The current PduParser. + * @param hasUserDataHeader Indicates whether a header is present in the + * User Data. + */ + private void parseUserData(PduParser p, boolean hasUserDataHeader) { + boolean hasMessageClass = false; + boolean userDataCompressed = false; + + int encodingType = ENCODING_UNKNOWN; + + // Look up the data encoding scheme + if ((dataCodingScheme & 0x80) == 0) { + // Bits 7..4 == 0xxx + automaticDeletion = (0 != (dataCodingScheme & 0x40)); + userDataCompressed = (0 != (dataCodingScheme & 0x20)); + hasMessageClass = (0 != (dataCodingScheme & 0x10)); + + if (userDataCompressed) { + Log.w(LOG_TAG, "4 - Unsupported SMS data coding scheme " + + "(compression) " + (dataCodingScheme & 0xff)); + } else { + switch ((dataCodingScheme >> 2) & 0x3) { + case 0: // GSM 7 bit default alphabet + encodingType = ENCODING_7BIT; + break; + + case 2: // UCS 2 (16bit) + encodingType = ENCODING_16BIT; + break; + + case 1: // 8 bit data + case 3: // reserved + Log.w(LOG_TAG, "1 - Unsupported SMS data coding scheme " + + (dataCodingScheme & 0xff)); + encodingType = ENCODING_8BIT; + break; + } + } + } else if ((dataCodingScheme & 0xf0) == 0xf0) { + automaticDeletion = false; + hasMessageClass = true; + userDataCompressed = false; + + if (0 == (dataCodingScheme & 0x04)) { + // GSM 7 bit default alphabet + encodingType = ENCODING_7BIT; + } else { + // 8 bit data + encodingType = ENCODING_8BIT; + } + } else if ((dataCodingScheme & 0xF0) == 0xC0 + || (dataCodingScheme & 0xF0) == 0xD0 + || (dataCodingScheme & 0xF0) == 0xE0) { + // 3GPP TS 23.038 V7.0.0 (2006-03) section 4 + + // 0xC0 == 7 bit, don't store + // 0xD0 == 7 bit, store + // 0xE0 == UCS-2, store + + if ((dataCodingScheme & 0xF0) == 0xE0) { + encodingType = ENCODING_16BIT; + } else { + encodingType = ENCODING_7BIT; + } + + userDataCompressed = false; + boolean active = ((dataCodingScheme & 0x08) == 0x08); + + // bit 0x04 reserved + + if ((dataCodingScheme & 0x03) == 0x00) { + isMwi = true; + mwiSense = active; + mwiDontStore = ((dataCodingScheme & 0xF0) == 0xC0); + } else { + isMwi = false; + + Log.w(LOG_TAG, "MWI for fax, email, or other " + + (dataCodingScheme & 0xff)); + } + } else { + Log.w(LOG_TAG, "3 - Unsupported SMS data coding scheme " + + (dataCodingScheme & 0xff)); + } + + // set both the user data and the user data header. + int count = p.constructUserData(hasUserDataHeader, + encodingType == ENCODING_7BIT); + this.userData = p.getUserData(); + this.userDataHeader = p.getUserDataHeader(); + + switch (encodingType) { + case ENCODING_UNKNOWN: + case ENCODING_8BIT: + messageBody = null; + break; + + case ENCODING_7BIT: + messageBody = p.getUserDataGSM7Bit(count); + break; + + case ENCODING_16BIT: + messageBody = p.getUserDataUCS2(count); + break; + } + + if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'"); + + if (messageBody != null) { + parseMessageBody(); + } + + if (!hasMessageClass) { + messageClass = MessageClass.UNKNOWN; + } else { + switch (dataCodingScheme & 0x3) { + case 0: + messageClass = MessageClass.CLASS_0; + break; + case 1: + messageClass = MessageClass.CLASS_1; + break; + case 2: + messageClass = MessageClass.CLASS_2; + break; + case 3: + messageClass = MessageClass.CLASS_3; + break; + } + } + } + + /** + * {@inheritDoc} + */ + public MessageClass getMessageClass() { + return messageClass; + } + +} diff --git a/telephony/java/com/android/internal/telephony/gsm/SuppServiceNotification.java b/telephony/java/com/android/internal/telephony/gsm/SuppServiceNotification.java index 11ad52d183e3..e68655e76d0b 100644 --- a/telephony/java/com/android/internal/telephony/gsm/SuppServiceNotification.java +++ b/telephony/java/com/android/internal/telephony/gsm/SuppServiceNotification.java @@ -34,7 +34,7 @@ public class SuppServiceNotification { public int type; /** TS 27.007 7.17 "number" (MT only) */ public String number; - + static public final int MO_CODE_UNCONDITIONAL_CF_ACTIVE = 0; static public final int MO_CODE_SOME_CF_ACTIVE = 1; static public final int MO_CODE_CALL_FORWARDED = 2; @@ -44,7 +44,7 @@ public class SuppServiceNotification { static public final int MO_CODE_INCOMING_CALLS_BARRED = 6; static public final int MO_CODE_CLIR_SUPPRESSION_REJECTED = 7; static public final int MO_CODE_CALL_DEFLECTED = 8; - + static public final int MT_CODE_FORWARDED_CALL = 0; static public final int MT_CODE_CUG_CALL = 1; static public final int MT_CODE_CALL_ON_HOLD = 2; diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java b/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java index a43e32fea726..2115dcfe2eca 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/AppInterface.java @@ -141,7 +141,7 @@ public interface AppInterface { void notifyBrowserTermination(boolean isErrorTermination); /** - * Notifies the SIM about the launch browser confirmation. This method + * Notifies the SIM about the launch browser confirmation. This method * should be called only after the application gets notified by {@code * CommandListener.onLaunchBrowser()} or inside that method. * @@ -165,19 +165,19 @@ public interface AppInterface { * * @param input The text string that the user has typed. * @param helpRequired True if just help information is requested on a menu - * item rather than menu selection. False if the menu + * item rather than menu selection. False if the menu * item is actually selected. */ void notifyInput(String input, boolean helpRequired); /** - * Notifies the SIM that the user input a key in Yes/No scenario. - * This method should be called only after the application gets notified by + * Notifies the SIM that the user input a key in Yes/No scenario. + * This method should be called only after the application gets notified by * {@code CommandListener.onGetInkey()} or inside that method. * * @param yesNoResponse User's choice for Yes/No scenario. * @param helpRequired True if just help information is requested on a menu - * item rather than menu selection. False if the menu + * item rather than menu selection. False if the menu * item is actually selected. */ void notifyInkey(boolean yesNoResponse, boolean helpRequired); @@ -189,7 +189,7 @@ public interface AppInterface { * * @param key The key that the user has typed. If the SIM required * @param helpRequired True if just help information is requested on a menu - * item rather than menu selection. False if the menu + * item rather than menu selection. False if the menu * item is actually selected. */ void notifyInkey(char key, boolean helpRequired); @@ -236,12 +236,12 @@ public interface AppInterface { * @param wantsHelp Indicates if the user requested help for the id item. */ void notifySelectedItem(int id, boolean wantsHelp); - + /** - * Notifies the SIM that No response was received from the user for display + * Notifies the SIM that No response was received from the user for display * text message dialog. - * - * * @param terminationCode indication for display text termination. Uses + * + * * @param terminationCode indication for display text termination. Uses * {@code ResultCode } values. */ public void notifyDisplayTextEnded(ResultCode terminationCode); diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java b/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java index f5268e535f7f..52d0cb958f53 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/BerTlv.java @@ -20,9 +20,9 @@ import java.util.List; /** * Class for representing BER-TLV objects. - * + * * @see "ETSI TS 102 223 Annex C" for more information. - * + * * {@hide} */ class BerTlv { @@ -41,16 +41,16 @@ class BerTlv { /** * Gets a list of ComprehensionTlv objects contained in this BER-TLV object. - * + * * @return A list of COMPREHENSION-TLV object */ public List<ComprehensionTlv> getComprehensionTlvs() { return mCompTlvs; } - + /** * Gets a tag id of the BER-TLV object. - * + * * @return A tag integer. */ public int getTag() { @@ -59,7 +59,7 @@ class BerTlv { /** * Decodes a BER-TLV object from a byte array. - * + * * @param data A byte array to decode from * @return A BER-TLV object decoded * @throws ResultException @@ -74,7 +74,7 @@ class BerTlv { tag = data[curIndex++] & 0xff; if (tag != BER_PROACTIVE_COMMAND_TAG) { // If the buffer doesn't contain proactive command tag, but - // start with a command details tlv object ==> skip the length + // start with a command details tlv object ==> skip the length // parsing and look for tlv objects. ComprehensionTlv ctlv = ComprehensionTlv.decode(data, curIndex--); diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandListener.java b/telephony/java/com/android/internal/telephony/gsm/stk/CommandListener.java index 5c9a3e9ad626..1204235a2bc7 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandListener.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandListener.java @@ -40,7 +40,7 @@ public interface CommandListener { * Call back function to be called when the SIM wants a call to be set up. * Application must call {@code AppInterface.acceptOrRejectCall()} after * this method returns or inside this method. - * + * * @param confirmMsg User confirmation phase message. * @param textAttrs List of text attributes to be applied. Can be null. * @param callMsg Call set up phase message. @@ -65,7 +65,7 @@ public interface CommandListener { * Call back function to be called for handling SET_UP_MENU proactive * commands. The menu can be retrieved by calling {@code * AppInterface.getMainMenu}. - * + * * @param menu application main menu. */ void onSetUpMenu(Menu menu); @@ -95,7 +95,7 @@ public interface CommandListener { * Call back function to be called for handling GET_INPUT proactive * commands. Application must call {@code AppInterface.notifyInput()} after * this method returns or inside this method. - * + * * @param text A text to be used as a prompt * @param defaultText A text to be used as a default input * @param minLen Mininum length of response (0 indicates there is no mininum @@ -160,7 +160,7 @@ public interface CommandListener { /** * Call back function to be called for handling LAUNCH_BROWSER proactive * commands. - * + * * @param useDefaultUrl If true, use the system default URL, otherwise use * {@code url} as the URL. * @param confirmMsg A text to be used as the user confirmation message. Can @@ -175,7 +175,7 @@ public interface CommandListener { /** * Call back function to be called for handling PLAY_TONE proactive * commands. - * + * * @param tone Tone to be played * @param text A text to be displayed. Can be null. * @param textAttrs List of text attributes to be applied. Can be null. diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java index d39ad7b4ff36..4a067f16340c 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/CommandParams.java @@ -21,7 +21,7 @@ import android.graphics.Bitmap; import java.util.List; /** - * Container class for proactive command parameters. + * Container class for proactive command parameters. * */ class CommandParams { diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java b/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java index 3cf8ca67a5c6..c8f9d682cbdb 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ComprehensionTlv.java @@ -22,9 +22,9 @@ import java.util.List; /** * Class for representing COMPREHENSION-TLV objects. - * + * * @see "ETSI TS 101 220 subsection 7.1.1" - * + * * {@hide} */ class ComprehensionTlv { @@ -38,7 +38,7 @@ class ComprehensionTlv { * Constructor. Private on purpose. Use * {@link #decodeMany(byte[], int) decodeMany} or * {@link #decode(byte[], int) decode} method. - * + * * @param tag The tag for this object * @param cr Comprehension Required flag * @param length Length of the value @@ -76,7 +76,7 @@ class ComprehensionTlv { /** * Parses a list of COMPREHENSION-TLV objects from a byte array. - * + * * @param data A byte array containing data to be parsed * @param startIndex Index in data at which to start parsing * @return A list of COMPREHENSION-TLV objects parsed @@ -97,7 +97,7 @@ class ComprehensionTlv { /** * Parses an COMPREHENSION-TLV object from a byte array. - * + * * @param data A byte array containing data to be parsed * @param startIndex Index in data at which to start parsing * @return A COMPREHENSION-TLV object parsed diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java b/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java index ee9154191bce..870f2a970220 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/IconLoader.java @@ -28,9 +28,9 @@ import android.os.Message; import android.util.Log; /** - * Class for loading icons from the SIM card. Has two states: single, for loading + * Class for loading icons from the SIM card. Has two states: single, for loading * one icon. Multi, for loading icons list. - * + * */ class IconLoader extends Handler { // members @@ -48,13 +48,13 @@ class IconLoader extends Handler { private static IconLoader sLoader = null; - // Loader state values. + // Loader state values. private static final int STATE_SINGLE_ICON = 1; private static final int STATE_MULTI_ICONS = 2; - // Finished loading single record from a linear-fixed EF-IMG. + // Finished loading single record from a linear-fixed EF-IMG. private static final int EVENT_READ_EF_IMG_RECOED_DONE = 1; - // Finished loading single icon from a Transparent DF-Graphics. + // Finished loading single icon from a Transparent DF-Graphics. private static final int EVENT_READ_ICON_DONE = 2; // Finished loading single colour icon lookup table. private static final int EVENT_READ_CLUT_DONE = 3; @@ -64,7 +64,7 @@ class IconLoader extends Handler { // CLUT entry size, {Red, Green, Black} private static final int CLUT_ENTRY_SIZE = 3; - static private final String TAG = "STK IconLoader"; + static private final String TAG = "STK IconLoader"; private IconLoader(Looper looper , SIMFileHandler fh) { super(looper); @@ -104,7 +104,7 @@ class IconLoader extends Handler { mState = STATE_SINGLE_ICON; startLoadingIcon(recordNumber); } - + private void startLoadingIcon(int recordNumber) { // Reset the load variables. mId = null; @@ -156,10 +156,10 @@ class IconLoader extends Handler { } /** - * Handles Image descriptor parsing and required processing. This is the + * Handles Image descriptor parsing and required processing. This is the * first step required to handle retrieving icons from the SIM. - * - * @param data byte [] containing Image Instance descriptor as defined in + * + * @param data byte [] containing Image Instance descriptor as defined in * TS 51.011. */ private boolean handleImageDescriptor(byte[] rawData) { @@ -213,7 +213,7 @@ class IconLoader extends Handler { * @param data The raw data * @param length The length of image body * @return The bitmap - */ + */ public static Bitmap parseToBnW(byte[] data, int length){ int valueIndex = 0; int width = data[valueIndex++] & 0xFF; @@ -245,7 +245,7 @@ class IconLoader extends Handler { * 0 is black * 1 is white * @param bit to decode - * @return RGB color + * @return RGB color */ private static int bitToBnW(int bit){ if(bit == 1){ @@ -257,11 +257,11 @@ class IconLoader extends Handler { /** * a TS 131.102 image instance of code scheme '11' into color Bitmap - * + * * @param data The raw data * @param length the length of image body * @param transparency with or without transparency - * @param clut coulor lookup table + * @param clut coulor lookup table * @return The color bitmap */ public static Bitmap parseToRGB(byte[] data, int length, @@ -302,9 +302,9 @@ class IconLoader extends Handler { return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888); } - + /** - * Calculate bit mask for a given number of bits. The mask should enable to + * Calculate bit mask for a given number of bits. The mask should enable to * make a bitwise and to the given number of bits. * @param numOfBits number of bits to calculate mask for. * @return bit mask diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java b/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java index e1a20f6fe5f0..6e1f77a7b9c4 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/ImageDescriptor.java @@ -35,7 +35,8 @@ public class ImageDescriptor { static final int CODING_SCHEME_BASIC = 0x11; static final int CODING_SCHEME_COLOUR = 0x21; - public static final int ID_LENGTH = 9; + // public static final int ID_LENGTH = 9; + // ID_LENGTH substituted by IccFileHandlerBase.GET_RESPONSE_EF_IMG_SIZE_BYTES private static final String TAG = "ImageDescriptor"; @@ -51,7 +52,7 @@ public class ImageDescriptor { /** * Extract descriptor information about image instance. - * + * * @param rawData * @param valueIndex * @return ImageDescriptor diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/Service.java b/telephony/java/com/android/internal/telephony/gsm/stk/Service.java index c0ceeefe341c..c1ab99ac9ec7 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/Service.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/Service.java @@ -30,8 +30,8 @@ import android.graphics.drawable.Drawable; import com.android.internal.telephony.IccUtils; import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.gsm.EncodeException; -import com.android.internal.telephony.gsm.GsmAlphabet; +import com.android.internal.telephony.EncodeException; +import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.gsm.SimCard; import com.android.internal.telephony.gsm.SIMFileHandler; import com.android.internal.telephony.gsm.SIMRecords; @@ -55,31 +55,31 @@ import java.util.List; /** * Enumeration for representing the tag value of COMPREHENSION-TLV objects. If * you want to get the actual value, call {@link #value() value} method. - * + * * {@hide} */ enum ComprehensionTlvTag { - COMMAND_DETAILS(0x01), - DEVICE_IDENTITIES(0x02), - RESULT(0x03), - DURATION(0x04), - ALPHA_ID(0x05), - USSD_STRING(0x0a), - TEXT_STRING(0x0d), - TONE(0x0e), - ITEM(0x0f), - ITEM_ID(0x10), - RESPONSE_LENGTH(0x11), - FILE_LIST(0x12), - HELP_REQUEST(0x15), - DEFAULT_TEXT(0x17), - EVENT_LIST(0x19), + COMMAND_DETAILS(0x01), + DEVICE_IDENTITIES(0x02), + RESULT(0x03), + DURATION(0x04), + ALPHA_ID(0x05), + USSD_STRING(0x0a), + TEXT_STRING(0x0d), + TONE(0x0e), + ITEM(0x0f), + ITEM_ID(0x10), + RESPONSE_LENGTH(0x11), + FILE_LIST(0x12), + HELP_REQUEST(0x15), + DEFAULT_TEXT(0x17), + EVENT_LIST(0x19), ICON_ID(0x1e), ITEM_ICON_ID_LIST(0x1f), - IMMEDIATE_RESPONSE(0x2b), - LANGUAGE(0x2d), + IMMEDIATE_RESPONSE(0x2b), + LANGUAGE(0x2d), URL(0x31), - BROWSER_TERMINATION_CAUSE(0x34), + BROWSER_TERMINATION_CAUSE(0x34), TEXT_ATTRIBUTE(0x50); private int mValue; @@ -90,7 +90,7 @@ enum ComprehensionTlvTag { /** * Returns the actual value of this COMPREHENSION-TLV object. - * + * * @return Actual tag value of this object */ public int value() { @@ -102,24 +102,24 @@ enum ComprehensionTlvTag { * Enumeration for representing "Type of Command" of proactive commands. If you * want to create a CommandType object, call the static method {@link * #fromInt(int) fromInt}. - * + * * {@hide} */ enum CommandType { - DISPLAY_TEXT(0x21), - GET_INKEY(0x22), - GET_INPUT(0x23), - LAUNCH_BROWSER(0x15), - PLAY_TONE(0x20), - REFRESH(0x01), - SELECT_ITEM(0x24), - SEND_SS(0x11), - SEND_USSD(0x12), - SEND_SMS(0x13), - SEND_DTMF(0x14), - SET_UP_EVENT_LIST(0x05), - SET_UP_IDLE_MODE_TEXT(0x28), - SET_UP_MENU(0x25), + DISPLAY_TEXT(0x21), + GET_INKEY(0x22), + GET_INPUT(0x23), + LAUNCH_BROWSER(0x15), + PLAY_TONE(0x20), + REFRESH(0x01), + SELECT_ITEM(0x24), + SEND_SS(0x11), + SEND_USSD(0x12), + SEND_SMS(0x13), + SEND_DTMF(0x14), + SET_UP_EVENT_LIST(0x05), + SET_UP_IDLE_MODE_TEXT(0x28), + SET_UP_MENU(0x25), SET_UP_CALL(0x10); private int mValue; @@ -130,7 +130,7 @@ enum CommandType { /** * Create a CommandType object. - * + * * @param value Integer value to be converted to a CommandType object. * @return CommandType object whose "Type of Command" value is {@code * value}. If no CommandType object has that value, null is @@ -148,7 +148,7 @@ enum CommandType { /** * Main class that implements SIM Toolkit Service. - * + * * {@hide} */ public class Service extends Handler implements AppInterface { @@ -156,9 +156,9 @@ public class Service extends Handler implements AppInterface { // Service members. private static Service sInstance; private CommandsInterface mCmdIf; - private SIMRecords mSimRecords; + private static SIMRecords mSimRecords; private Context mContext; - private SimCard mSimCard; + private static SimCard mSimCard; private CommandListener mCmdListener; private Object mCmdListenerLock = new Object(); private CommandParams mCmdParams = null; @@ -209,7 +209,7 @@ public class Service extends Handler implements AppInterface { public static final int UICC_EVENT_BROWSING_STATUS = 0x0f; public static final int UICC_EVENT_FRAMES_INFO_CHANGE = 0x10; public static final int UICC_EVENT_I_WLAN_ACESS_STATUS = 0x11; - + // Command Qualifier values static final int REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE = 0x00; static final int REFRESH_NAA_INIT_AND_FILE_CHANGE = 0x02; @@ -232,17 +232,17 @@ public class Service extends Handler implements AppInterface { static final int APP_INDICATOR_INSTALLED_NORMAL = 2; static final int APP_INDICATOR_INSTALLED_SPECIAL = 3; private static final int APP_INDICATOR_LAUNCHED = 4; - // Use setAppIndication(APP_INSTALL_INDICATOR) to go back for the original + // Use setAppIndication(APP_INSTALL_INDICATOR) to go back for the original // install indication. private static final int APP_INSTALL_INDICATOR = 5; - // Container class to hold temporary icon identifier TLV object info. + // Container class to hold temporary icon identifier TLV object info. class IconId { int recordNumber; boolean selfExplanatory; } - // Container class to hold temporary item icon identifier list TLV object info. + // Container class to hold temporary item icon identifier list TLV object info. class ItemsIconId { int [] recordNumbers; boolean selfExplanatory; @@ -282,10 +282,26 @@ public class Service extends Handler implements AppInterface { mSimCard.registerForAbsent(this, EVENT_SIM_ABSENT, null); } + public void dispose() { + mSimRecords.unregisterForRecordsLoaded(this); + mSimCard.unregisterForAbsent(this); + mCmdIf.unSetOnStkSessionEnd(this); + mCmdIf.unSetOnStkProactiveCmd(this); + mCmdIf.unSetOnStkEvent(this); + mCmdIf.unSetOnStkCallSetUp(this); + + //removing instance + sInstance = null; + } + + protected void finalize() { + Log.d(TAG, "Service finalized"); + } + /** * Used for retrieving the only Service object in the system. There is only * one Service object. - * + * * @param ci CommandsInterface object * @param sr SIMRecords object * @return The only Service object in the system @@ -298,6 +314,14 @@ public class Service extends Handler implements AppInterface { return null; } sInstance = new Service(ci, sr, context, fh, sc); + } else if(mSimCard != sc && mSimRecords != sr) { + Log.d(TAG, "Reinitialize the Service with SimCard and SIMRecords."); + mSimCard = sc; + mSimRecords = sr; + + // re-Register for SIM ready event. + mSimRecords.registerForRecordsLoaded(sInstance, EVENT_SIM_LOADED, null); + mSimCard.registerForAbsent(sInstance, EVENT_SIM_ABSENT, null); } return sInstance; } @@ -305,7 +329,7 @@ public class Service extends Handler implements AppInterface { /** * Used for retrieving the only Service object in the system. There is only * one Service object. - * + * * @return The only Service object in the system */ public static Service getInstance() { @@ -566,7 +590,7 @@ public class Service extends Handler implements AppInterface { result = ResultCode.HELP_INFO_REQUIRED; } else { resp = new GetInkeyInputResponseData(Character.toString(key), - request.isUcs2, false); + request.isUcs2, false); } sendTerminalResponse(request.cmdDet, result, false, 0, resp); @@ -590,7 +614,7 @@ public class Service extends Handler implements AppInterface { if (helpRequired) { result = ResultCode.HELP_INFO_REQUIRED; } else { - resp = new GetInkeyInputResponseData(yesNoResponse); + resp = new GetInkeyInputResponseData(yesNoResponse); } sendTerminalResponse(cmdParams.cmdDet, result, false, 0, resp); @@ -710,19 +734,19 @@ public class Service extends Handler implements AppInterface { throw new AssertionError("Unrecognized STK command: " + msg.what); } } - + /** * Send terminal response for backward move in the proactive SIM session * requested by the user - * + * * Only available when responding following proactive commands - * DISPLAY_TEXT(0x21), - * GET_INKEY(0x22), - * GET_INPUT(0x23), + * DISPLAY_TEXT(0x21), + * GET_INKEY(0x22), + * GET_INPUT(0x23), * SET_UP_MENU(0x25); - * + * * @return true if stk can send backward move response - * + * */ public boolean backwardMove() { CtlvCommandDetails cmdDet = null; @@ -740,14 +764,14 @@ public class Service extends Handler implements AppInterface { /** * Send terminal response for proactive SIM session terminated by the user - * + * * Only available when responding following proactive commands - * DISPLAY_TEXT(0x21), - * GET_INKEY(0x22), - * GET_INPUT(0x23), + * DISPLAY_TEXT(0x21), + * GET_INKEY(0x22), + * GET_INPUT(0x23), * PLAY_TONE(0x20), * SET_UP_MENU(0x25); - * + * * @return true if stk can send terminate session response */ public boolean terminateSession() { @@ -777,7 +801,7 @@ public class Service extends Handler implements AppInterface { /** * Handles RIL_UNSOL_STK_SESSION_END unsolicited command from RIL. - * + * * @param data Null object. Do not use this. */ private void handleSessionEnd(Object data) { @@ -922,7 +946,7 @@ public class Service extends Handler implements AppInterface { * This method parses the data transmitted from the SIM card, and handles * the command according to the "Type of Command". Each proactive command is * handled by a corresponding handleXXX() method. - * + * * @param data String containing SAT/USAT proactive command in hexadecimal * format starting with command tag */ @@ -1052,7 +1076,7 @@ public class Service extends Handler implements AppInterface { callStkApp(CommandType.DISPLAY_TEXT); break; case SELECT_ITEM: - + SelectItemParams params = ((SelectItemParams) mNextCmdParams); Menu menu = params.mMenu; switch(params.mIconLoadState) { @@ -1083,7 +1107,7 @@ public class Service extends Handler implements AppInterface { + "command types!"); } } - + private void callStkApp(CommandType cmdType) { boolean needsResponse = false; mCmdParams = mNextCmdParams; @@ -1211,10 +1235,10 @@ public class Service extends Handler implements AppInterface { /** * Search for a COMPREHENSION-TLV object with the given tag from a list - * + * * @param tag A tag to search for * @param ctlvs List of ComprehensionTlv objects used to search in - * + * * @return A ComprehensionTlv object that has the tag value of {@code tag}. * If no object is found with the tag, null is returned. */ @@ -1229,10 +1253,10 @@ public class Service extends Handler implements AppInterface { * list iterated by {@code iter}. {@code iter} points to the object next to * the found object when this method returns. Used for searching the same * list for similar tags, usually item id. - * + * * @param tag A tag to search for * @param iter Iterator for ComprehensionTlv objects used for search - * + * * @return A ComprehensionTlv object that has the tag value of {@code tag}. * If no object is found with the tag, null is returned. */ @@ -1250,7 +1274,7 @@ public class Service extends Handler implements AppInterface { /** * Search for a Command Details object from a list. - * + * * @param ctlvs List of ComprehensionTlv objects used for search * @return An CtlvCommandDetails object found from the objects. If no * Command Details object is found, ResultException is thrown. @@ -1281,7 +1305,7 @@ public class Service extends Handler implements AppInterface { /** * Search for a Device Identities object from a list. - * + * * @param ctlvs List of ComprehensionTlv objects used for search * @return An CtlvDeviceIdentities object found from the objects. If no * Command Details object is found, ResultException is thrown. @@ -1310,14 +1334,14 @@ public class Service extends Handler implements AppInterface { /** * Processes SETUP_CALL proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive * command object * @param ctlvs List of ComprehensionTlv objects following Command Details * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional + * @return true if the command is processing is pending and additional * asynchronous processing is required. */ private void processSetupCall(CtlvCommandDetails cmdDet, @@ -1373,14 +1397,14 @@ public class Service extends Handler implements AppInterface { /** * Processes DISPLAY_TEXT proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive * command object * @param ctlvs List of ComprehensionTlv objects following Command Details * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional + * @return true if the command is processing is pending and additional * asynchronous processing is required. * @throws ResultException */ @@ -1399,8 +1423,8 @@ public class Service extends Handler implements AppInterface { ctlvs); if (ctlv != null) { params.text = retrieveTextString(ctlv); - } - // If the tlv object doesn't exist or the it is a null object reply + } + // If the tlv object doesn't exist or the it is a null object reply // with command not understood. if (params.text == null) { throw new ResultException(ResultCode.CMD_DATA_NOT_UNDERSTOOD); @@ -1432,13 +1456,13 @@ public class Service extends Handler implements AppInterface { mIconLoader.loadIcon(iconId.recordNumber, this .obtainMessage(EVENT_LOAD_ICON_DONE)); return true; - } + } return false; } /** * Processes SET_UP_MENU proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive @@ -1446,7 +1470,7 @@ public class Service extends Handler implements AppInterface { * @param ctlvs Iterator for ComprehensionTlv objects following Command * Details object and Device Identities object within the proactive * command - * @return true if the command is processing is pending and additional + * @return true if the command is processing is pending and additional * asynchronous processing is required. * @throws ResultException */ @@ -1483,7 +1507,7 @@ public class Service extends Handler implements AppInterface { if (first && item == null) { removeExistingMenu = true; break; - } + } menu.items.add(retrieveItem(ctlv)); first = false; } else { @@ -1545,14 +1569,14 @@ public class Service extends Handler implements AppInterface { /** * Processes SET_UP_IDLE_MODE_TEXT proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive * command object * @param ctlvs List of ComprehensionTlv objects following Command Details * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional + * @return true if the command is processing is pending and additional * asynchronous processing is required. * @throws ResultException */ @@ -1597,20 +1621,20 @@ public class Service extends Handler implements AppInterface { mIconLoader.loadIcon(iconId.recordNumber, this .obtainMessage(EVENT_LOAD_ICON_DONE)); return true; - } + } return false; } /** * Processes GET_INKEY proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive * command object * @param ctlvs List of ComprehensionTlv objects following Command Details * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional + * @return true if the command is processing is pending and additional * asynchronous processing is required. * @throws ResultException */ @@ -1662,14 +1686,14 @@ public class Service extends Handler implements AppInterface { /** * Processes GET_INPUT proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive * command object * @param ctlvs List of ComprehensionTlv objects following Command Details * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional + * @return true if the command is processing is pending and additional * asynchronous processing is required. * @throws ResultException */ @@ -1744,7 +1768,7 @@ public class Service extends Handler implements AppInterface { /** * Processes REFRESH proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive @@ -1762,8 +1786,8 @@ public class Service extends Handler implements AppInterface { } // REFRESH proactive command is rerouted by the baseband and handled by - // the telephony layer. IDLE TEXT should be removed for a REFRESH command - // with "initialization" or "reset" + // the telephony layer. IDLE TEXT should be removed for a REFRESH command + // with "initialization" or "reset" if (mNm == null) { throw new ResultException(ResultCode.TERMINAL_CRNTLY_UNABLE_TO_PROCESS); @@ -1785,14 +1809,14 @@ public class Service extends Handler implements AppInterface { /** * Processes SELECT_ITEM proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive * command object * @param ctlvs List of ComprehensionTlv objects following Command Details * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional + * @return true if the command is processing is pending and additional * asynchronous processing is required. * @throws ResultException */ @@ -1842,7 +1866,7 @@ public class Service extends Handler implements AppInterface { // subtract one. menu.defaultItem = retrieveItemId(ctlv) - 1; } - + ctlv = searchForTag(ComprehensionTlvTag.ICON_ID, ctlvs); if (ctlv != null) { iconLoadState = SelectItemParams.LOAD_TITLE_ICON; @@ -1902,7 +1926,7 @@ public class Service extends Handler implements AppInterface { /** * Processes EVENT_NOTIFY message from baseband. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive @@ -1947,14 +1971,14 @@ public class Service extends Handler implements AppInterface { /** * Processes SET_UP_EVENT_LIST proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive * command object * @param ctlvs List of ComprehensionTlv objects following Command Details * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional + * @return true if the command is processing is pending and additional * asynchronous processing is required. */ private boolean processSetUpEventList(CtlvCommandDetails cmdDet, @@ -1979,14 +2003,14 @@ public class Service extends Handler implements AppInterface { /** * Processes LAUNCH_BROWSER proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive * command object * @param ctlvs List of ComprehensionTlv objects following Command Details * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional + * @return true if the command is processing is pending and additional * asynchronous processing is required. * @throws ResultException */ @@ -2061,14 +2085,14 @@ public class Service extends Handler implements AppInterface { /** * Processes PLAY_TONE proactive command from the SIM card. - * + * * @param cmdDet Command Details object retrieved from the proactive command * object * @param devIds Device Identities object retrieved from the proactive * command object * @param ctlvs List of ComprehensionTlv objects following Command Details * object and Device Identities object within the proactive command - * @return true if the command is processing is pending and additional + * @return true if the command is processing is pending and additional * asynchronous processing is required.t * @throws ResultException */ @@ -2132,7 +2156,7 @@ public class Service extends Handler implements AppInterface { /** * Retrieves text from the Text COMPREHENSION-TLV object, and decodes it * into a {@link java.lang.String}. - * + * * @param ctlv A Text COMPREHENSION-TLV object * @return A {@link java.lang.String} object decoded from the Text object * @throws ResultException @@ -2180,7 +2204,7 @@ public class Service extends Handler implements AppInterface { /** * Retrieves Duration information from the Duration COMPREHENSION-TLV * object. - * + * * @param ctlv A Text Attribute COMPREHENSION-TLV object * @return A Duration object * @throws ResultException @@ -2204,7 +2228,7 @@ public class Service extends Handler implements AppInterface { /** * Retrieves Item information from the COMPREHENSION-TLV object. - * + * * @param ctlv A Text Attribute COMPREHENSION-TLV object * @return An Item * @throws ResultException @@ -2234,7 +2258,7 @@ public class Service extends Handler implements AppInterface { /** * Retrieves Item id information from the COMPREHENSION-TLV object. - * + * * @param ctlv A Text Attribute COMPREHENSION-TLV object * @return An Item id * @throws ResultException @@ -2309,7 +2333,7 @@ public class Service extends Handler implements AppInterface { /** * Retrieves text attribute information from the Text Attribute * COMPREHENSION-TLV object. - * + * * @param ctlv A Text Attribute COMPREHENSION-TLV object * @return A list of TextAttribute objects * @throws ResultException @@ -2368,7 +2392,7 @@ public class Service extends Handler implements AppInterface { /** * Retrieves alpha identifier from an Alpha Identifier COMPREHENSION-TLV * object. - * + * * @param ctlv An Alpha Identifier COMPREHENSION-TLV object * @return String corresponding to the alpha identifier * @throws ResultException @@ -2392,7 +2416,7 @@ public class Service extends Handler implements AppInterface { /** * Handles RIL_UNSOL_STK_EVENT_NOTIFY unsolicited command from RIL. - * + * * @param data String containing SAT/USAT commands or responses sent by ME * to SIM or commands handled by ME, in hexadecimal format starting * with first byte of response data or command tag @@ -2438,11 +2462,11 @@ public class Service extends Handler implements AppInterface { } // There are two scenarios for EVENT_NOTIFY messages: - // 1. A proactive command which is partially handled by the baseband and + // 1. A proactive command which is partially handled by the baseband and // requires UI processing from the application. This messages will be // tagged with PROACTIVE COMMAND tag. - // 2. A notification for an action completed by the baseband. This - // messages will be tagged with UNKNOWN tag and the command type inside + // 2. A notification for an action completed by the baseband. This + // messages will be tagged with UNKNOWN tag and the command type inside // the Command details object should indicate which action was completed. if (berTlv.getTag() == BerTlv.BER_PROACTIVE_COMMAND_TAG) { switch (cmdType) { diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkAppInstaller.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkAppInstaller.java index 07e3e56a31fc..891dce9723cf 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/StkAppInstaller.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkAppInstaller.java @@ -27,7 +27,7 @@ import android.util.Log; * */ public class StkAppInstaller { - // Application state actions: install, uninstall used by StkAppStateReceiver. + // Application state actions: install, uninstall used by StkAppStateReceiver. static final String STK_APP_INSTALL_ACTION = "com.android.stk.action.INSTALL"; static final String STK_APP_UNINSTALL_ACTION = "com.android.stk.action.UNINSTALL"; diff --git a/telephony/java/com/android/internal/telephony/gsm/stk/StkAppStateReceiver.java b/telephony/java/com/android/internal/telephony/gsm/stk/StkAppStateReceiver.java index 778ca2ed3dea..7d1bb91bc481 100644 --- a/telephony/java/com/android/internal/telephony/gsm/stk/StkAppStateReceiver.java +++ b/telephony/java/com/android/internal/telephony/gsm/stk/StkAppStateReceiver.java @@ -23,8 +23,8 @@ import com.android.internal.telephony.gsm.stk.Service; import android.util.Log; /** - * This class implements a Broadcast receiver. It waits for an intent sent by - * the STK service and install/uninstall the STK application. If no intent is + * This class implements a Broadcast receiver. It waits for an intent sent by + * the STK service and install/uninstall the STK application. If no intent is * received when the device finished booting, the application is then unistalled. */ public class StkAppStateReceiver extends BroadcastReceiver { diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java index 3e1879e6e704..15a5761c77f7 100644 --- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java +++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java @@ -23,13 +23,13 @@ import android.util.Log; import com.android.internal.os.HandlerThread; import com.android.internal.telephony.BaseCommands; +import com.android.internal.telephony.CommandException; import com.android.internal.telephony.CommandsInterface; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.gsm.CallFailCause; -import com.android.internal.telephony.gsm.CommandException; import com.android.internal.telephony.DriverCall; +import com.android.internal.telephony.gsm.CallFailCause; import com.android.internal.telephony.gsm.PDPContextState; import com.android.internal.telephony.gsm.SuppServiceNotification; +import com.android.internal.telephony.Phone; import java.util.ArrayList; @@ -489,13 +489,20 @@ public final class SimulatedCommands extends BaseCommands } /** + * @deprecated + */ + public void getPDPContextList(Message result) { + getDataCallList(result); + } + + /** * returned message * retMsg.obj = AsyncResult ar * ar.exception carries exception on failure * ar.userObject contains the orignal value of result.obj * ar.result contains a List of PDPContextState */ - public void getPDPContextList(Message result) { + public void getDataCallList(Message result) { resultSuccess(result, new ArrayList<PDPContextState>(0)); } @@ -745,8 +752,15 @@ public final class SimulatedCommands extends BaseCommands resultSuccess(result, ret); } - public void - getLastPdpFailCause (Message result) { + /** + * @deprecated + */ + public void getLastPdpFailCause (Message result) { + unimplemented(result); + } + + public void getLastDataCallFailCause(Message result) { + // unimplemented(result); } @@ -925,16 +939,35 @@ public final class SimulatedCommands extends BaseCommands unimplemented(response); } + public void deleteSmsOnRuim(int index, Message response) { + Log.d(LOG_TAG, "Delete RUIM message at index " + index); + unimplemented(response); + } + public void writeSmsToSim(int status, String smsc, String pdu, Message response) { Log.d(LOG_TAG, "Write SMS to SIM with status " + status); unimplemented(response); } + public void writeSmsToRuim(int status, String pdu, Message response) { + Log.d(LOG_TAG, "Write SMS to RUIM with status " + status); + unimplemented(response); + } public void setupDefaultPDP(String apn, String user, String password, Message result) { unimplemented(result); } + public void setupDataCall(String radioTechnology, String profile, String apn, String user, + String password, Message result) { + unimplemented(result); + } + + public void deactivateDataCall(int cid, Message result) {unimplemented(result);} + + /** + * @deprecated + */ public void deactivateDefaultPDP(int cid, Message result) {unimplemented(result);} public void setPreferredNetworkType(int networkType , Message result) { @@ -969,7 +1002,7 @@ public final class SimulatedCommands extends BaseCommands } return false; } - + public void setRadioPower(boolean on, Message result) { if(on) { if (isSimLocked()) { @@ -990,6 +1023,10 @@ public final class SimulatedCommands extends BaseCommands unimplemented(result); } + public void acknowledgeLastIncomingCdmaSms(boolean success, Message result) { + unimplemented(result); + } + /** * parameters equivilient to 27.007 AT+CRSM command * response.obj will be an AsyncResult @@ -1064,7 +1101,7 @@ public final class SimulatedCommands extends BaseCommands * @param serviceClass is a sum of SERVICE_CLASSS_* */ public void setCallForward(int action, int cfReason, int serviceClass, - String number, int timeSeconds, Message result) {unimplemented(result);} + String number, int timeSeconds, Message result) {unimplemented(result);} /** * cfReason is one of CF_REASON_* @@ -1075,11 +1112,12 @@ public final class SimulatedCommands extends BaseCommands * An array of length 0 means "disabled for all codes" */ public void queryCallForwardStatus(int cfReason, int serviceClass, - String number, Message result) {unimplemented(result);} + String number, Message result) {unimplemented(result);} public void setNetworkSelectionModeAutomatic(Message result) {unimplemented(result);} - public void setNetworkSelectionModeManual(String operatorNumeric, Message result) {unimplemented(result);} + public void setNetworkSelectionModeManual( + String operatorNumeric, Message result) {unimplemented(result);} /** * Queries whether the current network selection mode is automatic @@ -1308,43 +1346,47 @@ public final class SimulatedCommands extends BaseCommands // ***** Methods for CDMA support public void getDeviceIdentity(Message response) { - //TODO: to be implemented - + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); } - + public void getCDMASubscription(Message response) { - //TODO: to be implemented - + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); } public void setCdmaSubscription(int cdmaSubscriptionType, Message response) { - //TODO: to be implemented + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); } - + public void queryCdmaRoamingPreference(Message response) { - //TODO: to be implemented + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); } - + public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) { - //TODO: to be implemented + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); } public void setPhoneType(int phoneType) { - //TODO: to be implemented - + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); } - + public void getPreferredVoicePrivacy(Message result) { - Log.w(LOG_TAG, "Warning, this function is not completely implemented in the class SimulatedCommands.java."); + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(result); } public void setPreferredVoicePrivacy(boolean enable, Message result) { - Log.w(LOG_TAG, "Warning, this function is not completely implemented in the class SimulatedCommands.java."); + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(result); } - + /** * Set the TTY mode for the CDMA phone * @@ -1353,9 +1395,10 @@ public final class SimulatedCommands extends BaseCommands * @param response is callback message */ public void setTTYModeEnabled(boolean enable, Message response) { - //TODO T: to be implemented + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); } - + /** * Query the TTY mode for the CDMA phone * (AsyncResult)response.obj).result is an int[] with element [0] set to @@ -1365,7 +1408,38 @@ public final class SimulatedCommands extends BaseCommands * @param response is callback message */ public void queryTTYModeEnabled(Message response) { - //TODO T: to be implemented + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); } - + + /** + * {@inheritDoc} + */ + public void sendCDMAFeatureCode(String FeatureCode, Message response) { + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + unimplemented(response); + } + + /** + * {@inheritDoc} + */ + public void sendCdmaSms(byte[] pdu, Message response){ + Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands"); + } + + public void activateCdmaBroadcastSms(int activate, Message result) { + // TODO Auto-generated method stub + + } + + public void getCdmaBroadcastConfig(Message result) { + // TODO Auto-generated method stub + + } + + public void setCdmaBroadcastConfig(int[] configValuesArray, Message result) { + // TODO Auto-generated method stub + + } + } diff --git a/telephony/jni/cdmasms/Android.mk b/telephony/jni/cdmasms/Android.mk new file mode 100644 index 000000000000..3b8699664342 --- /dev/null +++ b/telephony/jni/cdmasms/Android.mk @@ -0,0 +1,28 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + cdma_sms_jni.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libandroid_runtime \ + libnativehelper + +LOCAL_MODULE:= libcdma_sms_jni + +LOCAL_C_INCLUDES += \ + $(JNI_H_INCLUDE) \ + hardware/ril/include/telephony + +ifeq ($(TARGET_PRODUCT),generic) + LOCAL_C_INCLUDES += hardware/ril/reference-cdma-sms + LOCAL_SHARED_LIBRARIES += libreference-cdma-sms + LOCAL_CFLAGS += -DREFERENCE_CDMA_SMS +else +# define vendor implementation +endif + +LOCAL_PRELINK_MODULE := false +include $(BUILD_SHARED_LIBRARY) diff --git a/telephony/jni/cdmasms/cdma_sms_jni.cpp b/telephony/jni/cdmasms/cdma_sms_jni.cpp new file mode 100644 index 000000000000..4b5630e6b251 --- /dev/null +++ b/telephony/jni/cdmasms/cdma_sms_jni.cpp @@ -0,0 +1,1301 @@ +/* + * Copyright (C) 2008 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. + */ + +/** + * @file cdma_sms_jni.cpp + * + * This file implement the Java Native Interface + * for encoding and decoding of SMS + */ + + +#include <nativehelper/jni.h> +#include <nativehelper/JNIHelp.h> +#include <android_runtime/AndroidRuntime.h> +#include <cdma_sms_jni.h> + +#ifdef __cplusplus +extern "C" { +#endif //__cplusplus +#ifdef REFERENCE_CDMA_SMS +#include <reference-cdma-sms.h> +#else +//include vendor library +#endif //REFERENCE_CDMA_SMS +#ifdef __cplusplus +} +#endif //__cplusplus + +#undef LOG_TAG +#define LOG_TAG "CDMA" +#include <utils/Log.h> + +static RIL_CDMA_SMS_ClientBd *clientBdData = NULL; + + +static jint getObjectIntField(JNIEnv * env, jobject obj, const char *name, jint * value) +{ + jclass clazz; + jfieldID field; + +#ifdef DBG_LOG_LEVEL_B + LOGD("getObjectIntField():"); +#endif + + clazz = env->GetObjectClass(obj); + if (NULL == clazz) { + jniThrowException(env, "java/lang/Exception", NULL); + return JNI_FAILURE; + } + + field = env->GetFieldID(clazz, name, "I"); + env->DeleteLocalRef(clazz); + + if (NULL == field) { + jniThrowException(env, "java/lang/NoSuchFieldException", name); + return JNI_FAILURE; + } + + *value = env->GetIntField(obj, field); + +#ifdef DBG_LOG_LEVEL_B + LOGD(" %s = %d\n", name, *value); +#endif + + return JNI_SUCCESS; +} + +static jint setObjectIntField(JNIEnv * env, jobject obj, const char *name, jint value) +{ + jclass clazz; + jfieldID field; + +#ifdef DBG_LOG_LEVEL_B + LOGD("setObjectIntField(): %s = %d\n", name, value); +#endif + + clazz = env->GetObjectClass(obj); + if (NULL == clazz) { + jniThrowException(env, "java/lang/Exception", NULL); + return JNI_FAILURE; + } + + field = env->GetFieldID(clazz, name, "I"); + env->DeleteLocalRef(clazz); + + if (NULL == field) { + jniThrowException(env, "java/lang/NoSuchFieldException", name); + return JNI_FAILURE; + } + + env->SetIntField(obj, field, value); + + return JNI_SUCCESS; +} + +static jint getObjectByteField(JNIEnv * env, jobject obj, const char *name, jbyte * value) +{ + jclass clazz; + jfieldID field; + +#ifdef DBG_LOG_LEVEL_B + LOGD("getObjectByteField():"); +#endif + + clazz = env->GetObjectClass(obj); + if (NULL == clazz) { + jniThrowException(env, "java/lang/Exception", NULL); + return JNI_FAILURE; + } + + field = env->GetFieldID(clazz, name, "B"); + env->DeleteLocalRef(clazz); + + if (NULL == field) { + jniThrowException(env, "java/lang/NoSuchFieldException", name); + return JNI_FAILURE; + } + + *value = env->GetByteField(obj, field); + +#ifdef DBG_LOG_LEVEL_B + LOGD(" %s = %02x\n", name, *value); +#endif + + return JNI_SUCCESS; +} + +static jint setObjectByteField(JNIEnv * env, jobject obj, const char *name, jbyte value) +{ + jclass clazz; + jfieldID field; +#ifdef DBG_LOG_LEVEL_B + LOGD("setObjectByteField(): %s = 0x%02x\n", name, value); +#endif + + clazz = env->GetObjectClass(obj); + if (NULL == clazz) { + jniThrowException(env, "java/lang/Exception", NULL); + return JNI_FAILURE; + } + + field = env->GetFieldID(clazz, name, "B"); + env->DeleteLocalRef(clazz); + + if (NULL == field) { + jniThrowException(env, "java/lang/NoSuchFieldException", name); + return JNI_FAILURE; + } + + env->SetByteField(obj, field, value); + + return JNI_SUCCESS; +} + +static jint getObjectBooleanField(JNIEnv * env, jobject obj, const char *name, jboolean * value) +{ + jclass clazz; + jfieldID field; + +#ifdef DBG_LOG_LEVEL_B + LOGD("getObjectBooleanField():"); +#endif + + clazz = env->GetObjectClass(obj); + if (NULL == clazz) { + jniThrowException(env, "java/lang/Exception", NULL); + return JNI_FAILURE; + } + + field = env->GetFieldID(clazz, name, "Z"); + env->DeleteLocalRef(clazz); + + if (NULL == field) { + jniThrowException(env, "java/lang/NoSuchFieldException", name); + return JNI_FAILURE; + } + + *value = env->GetBooleanField(obj, field); + +#ifdef DBG_LOG_LEVEL_B + LOGD(" %s = %d\n", name, *value); +#endif + + return JNI_SUCCESS; +} + +static jint setObjectBooleanField(JNIEnv * env, jobject obj, const char *name, jboolean value) +{ + jclass clazz; + jfieldID field; + +#ifdef DBG_LOG_LEVEL_B + LOGD("setObjectBooleanField(): %s = %d\n", name, value); +#endif + + clazz = env->GetObjectClass(obj); + if (NULL == clazz) { + jniThrowException(env, "java/lang/Exception", NULL); + return JNI_FAILURE; + } + + field = env->GetFieldID(clazz, name, "Z"); + env->DeleteLocalRef(clazz); + + if (NULL == field) { + jniThrowException(env, "java/lang/NoSuchFieldException", name); + return JNI_FAILURE; + } + + env->SetBooleanField(obj, field, value); + + return JNI_SUCCESS; +} + +static jint getObjectByteArrayField(JNIEnv * env, jobject obj, const char *name, jbyte* arrData, int* length) +{ + jclass clazz; + jfieldID field; + jbyte * data_buf; + +#ifdef DBG_LOG_LEVEL_B + LOGD("getObjectByteArrayField(): %s\n", name); +#endif + + clazz = env->GetObjectClass(obj); + if (NULL == clazz) { + jniThrowException(env, "java/lang/Exception", NULL); + return JNI_FAILURE; + } + + field = env->GetFieldID(clazz, name, "[B"); + env->DeleteLocalRef(clazz); + + if (NULL == field) { + jniThrowException(env, "java/lang/NoSuchFieldException", name); + return JNI_FAILURE; + } + + jbyteArray buffer = (jbyteArray)(env->GetObjectField(obj, field)); + if (buffer != NULL) { + int len = env->GetArrayLength(buffer); + data_buf = env->GetByteArrayElements(buffer, NULL); + for (int i=0; i<len; i++) { + *arrData++ = data_buf[i]; +#ifdef DBG_LOG_LEVEL_B + LOGD(" [%d] = 0x%02x\n", i, data_buf[i]); +#endif + } + *length = len; + } else { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return JNI_FAILURE; + } + + return JNI_SUCCESS; +} + +static jint setObjectByteArrayField(JNIEnv * env, jobject obj, const char *name, jbyte* arrData, int length) +{ + jclass clazz; + jfieldID field; + jbyte* byte_buf; + +#ifdef DBG_LOG_LEVEL_B + LOGD("setObjectByteArrayField(): %s\n", name); +#endif + + clazz = env->GetObjectClass(obj); + if (NULL == clazz) { + jniThrowException(env, "java/lang/Exception", NULL); + return JNI_FAILURE; + } + + field = env->GetFieldID(clazz, name, "[B"); + env->DeleteLocalRef(clazz); + + if (NULL == field) { + jniThrowException(env, "java/lang/NoSuchFieldException", name); + return JNI_FAILURE; + } + + jbyteArray buffer = (jbyteArray)(env->GetObjectField(obj, field)); + if (buffer == NULL) { +#ifdef DBG_LOG_LEVEL_B + LOGD("setObjectByteArrayField(): %s = null\n", name); +#endif + buffer = env->NewByteArray(length); + env->SetObjectField(obj, field, buffer); + } + + if (buffer != NULL) { +#ifdef DBG_LOG_LEVEL_B + for (int i=0; i<length; i++) { + LOGD(" [%d] = 0x%02x\n", i, arrData[i]); + } +#endif + env->SetByteArrayRegion(buffer, 0, length, arrData); + } else { + jniThrowException(env, "java/lang/NullPointerException", NULL); + return JNI_FAILURE; + } + + return JNI_SUCCESS; +} + + +/* native interface */ +JNIEXPORT jint JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsConstructClientBD + (JNIEnv * env, jobject obj) +{ +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsConstructClientBD()...\n"); +#endif + + clientBdData = (RIL_CDMA_SMS_ClientBd *)malloc(sizeof(RIL_CDMA_SMS_ClientBd)); + if (NULL == clientBdData) { + jniThrowException(env, "java/lang/OutOfMemoryError", "clientBdData memory allocation failed"); + return JNI_FAILURE; + } + memset(clientBdData, 0, sizeof(RIL_CDMA_SMS_ClientBd)); + return JNI_SUCCESS; +} + + +/* native interface */ +JNIEXPORT jint JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsDestructClientBD + (JNIEnv * env, jobject obj) +{ +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsDestructClientBD()...\n"); +#endif + + if (clientBdData == NULL) { + jniThrowException(env, "java/lang/NullPointerException", "clientBdData is null"); + return JNI_FAILURE; + } + free(clientBdData); + return JNI_SUCCESS; +} + + +/* native interface */ +JNIEXPORT jint JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetBearerDataPrimitives + (JNIEnv * env, jobject obj, jobject bearerData) +{ + jbyteArray mc_time = NULL; + jbyte mctime_buffer[6]; + int length; + jint intData; + jbyte byteData; + jboolean booleanData; + +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsSetBearerDataPrimitives()...\n"); +#endif + + // mask + if (getObjectIntField(env, bearerData, "mask", &intData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->mask = intData; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->mask = 0x%x\n", clientBdData->mask); +#endif + + // message_id.type + if (getObjectByteField(env, bearerData, "messageType", &byteData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->message_id.type = (RIL_CDMA_SMS_BdMessageType)(byteData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->message_id.type = 0x%02x\n", clientBdData->message_id.type); +#endif + + // message_id.id_number + if ((clientBdData->mask & WMS_MASK_BD_MSG_ID) == WMS_MASK_BD_MSG_ID) { + if (getObjectIntField(env, bearerData, "messageID", &intData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->message_id.id_number = (RIL_CDMA_SMS_MessageNumber)(intData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->message_id.id_number = %d\n", clientBdData->message_id.id_number); +#endif + } + + // message_id.udh_present + if (getObjectBooleanField(env, bearerData, "hasUserDataHeader", &booleanData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->message_id.udh_present = (unsigned char)(booleanData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->message_id.udh_present = %d\n", clientBdData->message_id.udh_present); +#endif + + // user_response + // TODO + + // mc_time + if ((clientBdData->mask & WMS_MASK_BD_MC_TIME) == WMS_MASK_BD_MC_TIME) { + if (getObjectByteArrayField(env, bearerData, "timeStamp", mctime_buffer, &length) != JNI_SUCCESS) + return JNI_FAILURE; + if (mctime_buffer != NULL) { + clientBdData->mc_time.year = mctime_buffer[0]; + clientBdData->mc_time.month = mctime_buffer[1]; + clientBdData->mc_time.day = mctime_buffer[2]; + clientBdData->mc_time.hour = mctime_buffer[3]; + clientBdData->mc_time.minute = mctime_buffer[4]; + clientBdData->mc_time.second = mctime_buffer[5]; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->mc_time.year = %d\n", clientBdData->mc_time.year); + LOGD("clientBdData->mc_time.month = %d\n", clientBdData->mc_time.month); + LOGD("clientBdData->mc_time.day = %d\n", clientBdData->mc_time.day); + LOGD("clientBdData->mc_time.hour = %d\n", clientBdData->mc_time.hour); + LOGD("clientBdData->mc_time.minute = %d\n", clientBdData->mc_time.minute); + LOGD("clientBdData->mc_time.second = %d\n", clientBdData->mc_time.second); +#endif + } + } + + // clientBdData->mc_time.timezone + // TODO + + // validity_absolute; + // TODO + + // validity_relative; + // TODO + + // deferred_absolute + // TODO + + // deferred_relative; + // TODO + + // priority + // TODO + + // privacy + // TODO + + if ((clientBdData->mask & WMS_MASK_BD_REPLY_OPTION) == WMS_MASK_BD_REPLY_OPTION) { + // reply_option.user_ack_requested + if (getObjectBooleanField(env, bearerData, "userAckReq", &booleanData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->reply_option.user_ack_requested = (unsigned char)(booleanData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->reply_option.user_ack_requested = %d\n", clientBdData->reply_option.user_ack_requested); +#endif + // reply_option.user_ack_requested + if (getObjectBooleanField(env, bearerData, "deliveryAckReq", &booleanData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->reply_option.delivery_ack_requested = (unsigned char)(booleanData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->reply_option.delivery_ack_requested = %d\n", clientBdData->reply_option.delivery_ack_requested); +#endif + // reply_option.user_ack_requested + if (getObjectBooleanField(env, bearerData, "readAckReq", &booleanData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->reply_option.read_ack_requested = (unsigned char)(booleanData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->reply_option.read_ack_requested = %d\n", clientBdData->reply_option.read_ack_requested); +#endif + } + + // num_messages + if ((clientBdData->mask & WMS_MASK_BD_NUM_OF_MSGS) == WMS_MASK_BD_NUM_OF_MSGS) { + if (getObjectIntField(env, bearerData, "numberOfMessages", &intData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->num_messages = (unsigned char)(intData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->num_messages = %d\n", clientBdData->num_messages); +#endif + } + + // alert_mode + // TODO + + // language + // TODO + + // display_mode + if ((clientBdData->mask & WMS_MASK_BD_DISPLAY_MODE) == WMS_MASK_BD_DISPLAY_MODE) { + if (getObjectByteField(env, bearerData, "displayMode", &byteData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->display_mode = (RIL_CDMA_SMS_DisplayMode)(byteData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->display_mode = 0x%02x\n", clientBdData->display_mode); +#endif + } + + // delivery_status + if ((clientBdData->mask & WMS_MASK_BD_DELIVERY_STATUS) == WMS_MASK_BD_DELIVERY_STATUS) { + // delivery_status.error_class + if (getObjectIntField(env, bearerData, "errorClass", &intData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->delivery_status.error_class = (RIL_CDMA_SMS_ErrorClass)(intData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->delivery_status.error_class = %d\n", clientBdData->delivery_status.error_class); +#endif + // delivery_status.status + if (getObjectIntField(env, bearerData, "messageStatus", &intData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->delivery_status.status = (RIL_CDMA_SMS_DeliveryStatusE)(intData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->delivery_status.status = %d\n", clientBdData->delivery_status.status); +#endif + } + + // deposit_index + // TODO + + // ip_address + // TODO + + // rsn_no_notify + // TODO + + // other + // TODO + + return JNI_SUCCESS; +} + + +/* native interface */ +JNIEXPORT jint JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetBearerDataPrimitives + (JNIEnv * env, jobject obj, jobject bearerData) +{ + jclass BearerDataClass; + jfieldID field; + jbyte mctime_buffer[6]; + jbyteArray addr_array; + int length; + +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsGetBearerDataPrimitives()...\n"); +#endif + + // mask +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->mask = 0x%x\n", clientBdData->mask); +#endif + if (setObjectIntField(env, bearerData, "mask", clientBdData->mask) != JNI_SUCCESS) + return JNI_FAILURE; + + // message_id.type +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->message_id.type = 0x%02x\n", clientBdData->message_id.type); +#endif + if (setObjectByteField(env, bearerData, "messageType", (jbyte)clientBdData->message_id.type) != JNI_SUCCESS) + return JNI_FAILURE; + + // message_id.id_number + if ((clientBdData->mask & WMS_MASK_BD_MSG_ID) == WMS_MASK_BD_MSG_ID) { +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->message_id.id_number = %d\n", clientBdData->message_id.id_number); +#endif + if (setObjectIntField(env, bearerData, "messageID", clientBdData->message_id.id_number) != JNI_SUCCESS) + return JNI_FAILURE; + } + + // message_id.udh_present +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->message_id.udh_present = %d\n", clientBdData->message_id.udh_present); +#endif + if (setObjectBooleanField(env, bearerData, "hasUserDataHeader", (jboolean)clientBdData->message_id.udh_present) != JNI_SUCCESS) + return JNI_FAILURE; + + // user_response + // TODO + + // mc_time + if ((clientBdData->mask & WMS_MASK_BD_MC_TIME) == WMS_MASK_BD_MC_TIME) { + jclass clazz= env->GetObjectClass(bearerData); + if (NULL == clazz) + return JNI_FAILURE; + jfieldID field = env->GetFieldID(clazz, "timeStamp", "[B"); + env->DeleteLocalRef(clazz); + + addr_array = env->NewByteArray((jsize)6); + env->SetObjectField(bearerData, field, addr_array); + +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->mc_time.year = %d\n", clientBdData->mc_time.year); + LOGD("clientBdData->mc_time.month = %d\n", clientBdData->mc_time.month); + LOGD("clientBdData->mc_time.day = %d\n", clientBdData->mc_time.day); + LOGD("clientBdData->mc_time.hour = %d\n", clientBdData->mc_time.hour); + LOGD("clientBdData->mc_time.minute = %d\n", clientBdData->mc_time.minute); + LOGD("clientBdData->mc_time.second = %d\n", clientBdData->mc_time.second); +#endif + mctime_buffer[0] = clientBdData->mc_time.year; + mctime_buffer[1] = clientBdData->mc_time.month; + mctime_buffer[2] = clientBdData->mc_time.day; + mctime_buffer[3] = clientBdData->mc_time.hour; + mctime_buffer[4] = clientBdData->mc_time.minute; + mctime_buffer[5] = clientBdData->mc_time.second; + length = sizeof(mctime_buffer) / sizeof(jbyte); + if (setObjectByteArrayField(env, bearerData, "timeStamp", mctime_buffer, length) != JNI_SUCCESS) + return JNI_FAILURE; + } + + // clientBdData->mc_time.timezone + // TODO + + // validity_absolute; + // TODO + + // validity_relative; + // TODO + + // deferred_absolute + // TODO + + // deferred_relative; + // TODO + + // priority + // TODO + + // privacy + // TODO + + if ((clientBdData->mask & WMS_MASK_BD_REPLY_OPTION) == WMS_MASK_BD_REPLY_OPTION) { + // reply_option.user_ack_requested +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->reply_option.user_ack_requested = %d\n", clientBdData->reply_option.user_ack_requested); +#endif + if (setObjectBooleanField(env, bearerData, "userAckReq", (jboolean)clientBdData->reply_option.user_ack_requested) != JNI_SUCCESS) + return JNI_FAILURE; + + // reply_option.user_ack_requested +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->reply_option.delivery_ack_requested = %d\n", clientBdData->reply_option.delivery_ack_requested); +#endif + if (setObjectBooleanField(env, bearerData, "deliveryAckReq", (jboolean)clientBdData->reply_option.delivery_ack_requested) != JNI_SUCCESS) + return JNI_FAILURE; + + // reply_option.user_ack_requested +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->reply_option.read_ack_requested = %d\n", clientBdData->reply_option.read_ack_requested); +#endif + if (setObjectBooleanField(env, bearerData, "readAckReq", (jboolean)clientBdData->reply_option.read_ack_requested) != JNI_SUCCESS) + return JNI_FAILURE; + } + + // num_messages + if ((clientBdData->mask & WMS_MASK_BD_NUM_OF_MSGS) == WMS_MASK_BD_NUM_OF_MSGS) { +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->num_messages = %d\n", clientBdData->num_messages); +#endif + if (setObjectIntField(env, bearerData, "numberOfMessages", (int)clientBdData->num_messages) != JNI_SUCCESS) + return JNI_FAILURE; + } + + // alert_mode + // TODO + + // language + // TODO + + // display_mode + if ((clientBdData->mask & WMS_MASK_BD_DISPLAY_MODE) == WMS_MASK_BD_DISPLAY_MODE) { +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->display_mode = 0x%02x\n", clientBdData->display_mode); +#endif + if (setObjectByteField(env, bearerData, "displayMode", (jbyte)clientBdData->display_mode) != JNI_SUCCESS) + return JNI_FAILURE; + } + + // delivery_status + if ((clientBdData->mask & WMS_MASK_BD_DELIVERY_STATUS) == WMS_MASK_BD_DELIVERY_STATUS) { +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->delivery_status.error_class = %d\n", clientBdData->delivery_status.error_class); +#endif + // delivery_status.error_class + if (setObjectIntField(env, bearerData, "errorClass", (int)clientBdData->delivery_status.error_class) != JNI_SUCCESS) + return JNI_FAILURE; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->delivery_status.status = %d\n", clientBdData->delivery_status.status); +#endif + // delivery_status.status + if (setObjectIntField(env, bearerData, "messageStatus", (int)clientBdData->delivery_status.status) != JNI_SUCCESS) + return JNI_FAILURE; + } + + // deposit_index + // TODO + + // ip_address + // TODO + + // rsn_no_notify + // TODO + + // other + // TODO + + return JNI_SUCCESS; +} + + +/* native interface */ +JNIEXPORT jint JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetUserData + (JNIEnv * env, jobject obj, jobject userData) +{ + jclass UserDataClass; + jfieldID field; + jbyteArray arrData = NULL; + jbyte data_buf[RIL_CDMA_SMS_USER_DATA_MAX]; + int length; + jint intData; + jbyte byteData; + jboolean booleanData; + +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsSetUserData()...\n"); +#endif + + // set num_headers to 0 here, increment later + clientBdData->user_data.num_headers = 0; + + // user_data.encoding + if (getObjectIntField(env, userData, "userDataEncoding", &intData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->user_data.encoding = (RIL_CDMA_SMS_UserDataEncoding)(intData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.encoding = %d\n", clientBdData->user_data.encoding); +#endif + + // is91ep_type + // TODO + + // user_data.padding_bits + if (getObjectIntField(env, userData, "paddingBits", &intData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->user_data.padding_bits = (unsigned char)(intData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.padding_bits = %d\n", clientBdData->user_data.padding_bits); +#endif + + // user_data.data + if (getObjectByteArrayField(env, userData, "userData", data_buf, &length) != JNI_SUCCESS ) + return JNI_FAILURE; + for (int i = 0; i < length; i++) { + clientBdData->user_data.data[i] = data_buf[i]; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.data[%d] = 0x%02x\n", i, clientBdData->user_data.data[i]); +#endif + } + + // user_data.data_len + // TODO + + // number_of_digits + clientBdData->user_data.number_of_digits = (unsigned char)(length); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.number_of_digits = %d\n", clientBdData->user_data.number_of_digits); +#endif + + return JNI_SUCCESS; +} + + +/* native interface */ +JNIEXPORT jint JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetUserData + (JNIEnv * env, jobject obj, jobject userData) +{ + jclass UserDataClass; + jfieldID field; + jbyte *data_buf; + int length; + +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsGetUserData()...\n"); +#endif + + // user_data.num_headers +// if (setObjectIntField(env, userData, "mNumberOfHeaders", (int)clientBdData->user_data.num_headers) != JNI_SUCCESS) +// return JNI_FAILURE; + + // user_data.encoding +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.encoding = %d\n", clientBdData->user_data.encoding); +#endif + if (setObjectIntField(env, userData, "userDataEncoding", clientBdData->user_data.encoding) != JNI_SUCCESS) + return JNI_FAILURE; + + // is91ep_type + // TODO + + // user_data.data_len +// if (setObjectIntField(env, userData, "mDataLength", (int)clientBdData->user_data.data_len) != JNI_SUCCESS) +// return JNI_FAILURE; + + // user_data.padding_bits +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.padding_bits = %d\n", clientBdData->user_data.padding_bits); +#endif + if (setObjectIntField(env, userData, "paddingBits", (int)clientBdData->user_data.padding_bits) != JNI_SUCCESS) + return JNI_FAILURE; + + // user_data.data +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.data_len = %d\n", clientBdData->user_data.data_len); +#endif + length = clientBdData->user_data.data_len; +#ifdef DBG_LOG_LEVEL_A + for (int i = 0; i < length; i++) { + LOGD("clientBdData->user_data.data[%d] = 0x%02x\n", i, clientBdData->user_data.data[i]); + } +#endif + data_buf = (jbyte*)clientBdData->user_data.data; + if (setObjectByteArrayField(env, userData, "userData", data_buf, length) != JNI_SUCCESS) + return JNI_FAILURE; + + // number_of_digits + // TODO + + return JNI_SUCCESS; +} + + +/* native interface */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetUserDataHeader + (JNIEnv * env, jobject obj, jint ID, jbyteArray data, jint length, jint index) +{ + jbyte data_buf[length]; + +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsSetUserDataHeader()...\n"); +#endif + + env->GetByteArrayRegion(data, 0, length, data_buf); + + // user_data.headers[index].header_id + clientBdData->user_data.headers[index].header_id = (RIL_CDMA_SMS_UdhId)(ID); + + // user_data.headers[index].u + // TODO: add support for all udh id's + switch(clientBdData->user_data.headers[index].header_id) + { + case RIL_CDMA_SMS_UDH_CONCAT_8: + clientBdData->user_data.headers[index].u.concat_8.msg_ref = data_buf[0]; + clientBdData->user_data.headers[index].u.concat_8.total_sm = data_buf[1]; + clientBdData->user_data.headers[index].u.concat_8.seq_num = data_buf[2]; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].u.concat_8.msg_ref = 0x%02x\n", index, clientBdData->user_data.headers[index].u.concat_8.msg_ref); + LOGD("clientBdData->user_data.headers[%d].u.concat_8.total_sm = 0x%02x\n", index, clientBdData->user_data.headers[index].u.concat_8.total_sm); + LOGD("clientBdData->user_data.headers[%d].u.concat_8.seq_num = 0x%02x\n", index, clientBdData->user_data.headers[index].u.concat_8.seq_num); +#endif + break; + case RIL_CDMA_SMS_UDH_SPECIAL_SM: + clientBdData->user_data.headers[index].u.special_sm.msg_waiting = (RIL_CDMA_SMS_GWMsgWaiting)( + (data_buf[0] << 23) | (data_buf[1] << 15) | + (data_buf[2] << 7) | data_buf[3]); + clientBdData->user_data.headers[index].u.special_sm.msg_waiting_kind = (RIL_CDMA_SMS_GWMsgWaitingKind)( + (data_buf[4] << 23) | (data_buf[5] << 15) | + (data_buf[6] << 7) | data_buf[7]); + clientBdData->user_data.headers[index].u.special_sm.message_count = data_buf[8]; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].u.special_sm.msg_waiting = 0x%04x\n", index, clientBdData->user_data.headers[index].u.special_sm.msg_waiting); + LOGD("clientBdData->user_data.headers[%d].u.special_sm.msg_waiting_kind = 0x%04x\n", index, clientBdData->user_data.headers[index].u.special_sm.msg_waiting_kind); + LOGD("clientBdData->user_data.headers[%d].u.special_sm.message_count = 0x%02x\n", index, clientBdData->user_data.headers[index].u.special_sm.message_count); +#endif + break; + case RIL_CDMA_SMS_UDH_PORT_8: + clientBdData->user_data.headers[index].u.wap_8.dest_port = data_buf[0]; + clientBdData->user_data.headers[index].u.wap_8.orig_port = data_buf[1]; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].u.wap_8.dest_port = 0x%02x\n", index, clientBdData->user_data.headers[index].u.wap_8.dest_port); + LOGD("clientBdData->user_data.headers[%d].u.wap_8.orig_port = 0x%02x\n", index, clientBdData->user_data.headers[index].u.wap_8.orig_port); +#endif + break; + case RIL_CDMA_SMS_UDH_PORT_16: + clientBdData->user_data.headers[index].u.wap_16.dest_port = (data_buf[0] << 7) | data_buf[1]; // unsigned short + clientBdData->user_data.headers[index].u.wap_16.orig_port = (data_buf[2] << 7) | data_buf[3]; // unsigned short +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].u.wap_16.dest_port = 0x%04x\n", index, clientBdData->user_data.headers[index].u.wap_16.dest_port); + LOGD("clientBdData->user_data.headers[%d].u.wap_16.orig_port = 0x%04x\n", index, clientBdData->user_data.headers[index].u.wap_16.orig_port); +#endif + break; + case RIL_CDMA_SMS_UDH_CONCAT_16: + clientBdData->user_data.headers[index].u.concat_16.msg_ref = (data_buf[0] << 7) | data_buf[1]; // unsigned short + clientBdData->user_data.headers[index].u.concat_16.total_sm = data_buf[2]; + clientBdData->user_data.headers[index].u.concat_16.seq_num = data_buf[3]; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].u.concat_16.msg_ref = 0x%04x\n", index, clientBdData->user_data.headers[index].u.concat_16.msg_ref); + LOGD("clientBdData->user_data.headers[%d].u.concat_16.total_sm = 0x%04x\n", index, clientBdData->user_data.headers[index].u.concat_16.total_sm); + LOGD("clientBdData->user_data.headers[%d].u.concat_16.seq_num = 0x%04x\n", index, clientBdData->user_data.headers[index].u.concat_16.seq_num); +#endif + break; + default: + break; + } + + // increment num_of_headers + clientBdData->user_data.num_headers++; + + return JNI_SUCCESS; +} + + +/* native interface */ +JNIEXPORT jbyteArray JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetUserDataHeader + (JNIEnv * env, jobject obj) +{ + jbyteArray arrData = NULL; + jbyte data_buf[sizeof(clientBdData->user_data.headers)]; + int length = 0; + +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsGetUserDataHeader()...\n"); +#endif + +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.num_headers = %d, size = %d\n", clientBdData->user_data.num_headers, sizeof(clientBdData->user_data.headers)); +#endif + + for (int index = 0; index < clientBdData->user_data.num_headers; index++) { + // user_data.headers[index].header_id + data_buf[length++] = (jbyte)clientBdData->user_data.headers[index].header_id; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].header_id = %d", index, clientBdData->user_data.headers[index].header_id); +#endif + + // user_data.headers[index].u + // TODO: add support for all udh id's + switch(clientBdData->user_data.headers[index].header_id) + { + case RIL_CDMA_SMS_UDH_CONCAT_8: +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].u.concat_8.msg_ref = 0x%02x\n", index, clientBdData->user_data.headers[index].u.concat_8.msg_ref); + LOGD("clientBdData->user_data.headers[%d].u.concat_8.total_sm = 0x%02x\n", index, clientBdData->user_data.headers[index].u.concat_8.total_sm); + LOGD("clientBdData->user_data.headers[%d].u.concat_8.seq_num = 0x%02x\n", index, clientBdData->user_data.headers[index].u.concat_8.seq_num); +#endif + data_buf[length++] = 3; + data_buf[length++] = clientBdData->user_data.headers[index].u.concat_8.msg_ref; + data_buf[length++] = clientBdData->user_data.headers[index].u.concat_8.total_sm; + data_buf[length++] = clientBdData->user_data.headers[index].u.concat_8.seq_num; + break; + case RIL_CDMA_SMS_UDH_SPECIAL_SM: +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].u.special_sm.msg_waiting = 0x%04x\n", index, clientBdData->user_data.headers[index].u.special_sm.msg_waiting); + LOGD("clientBdData->user_data.headers[%d].u.special_sm.msg_waiting_kind = 0x%04x\n", index, clientBdData->user_data.headers[index].u.special_sm.msg_waiting_kind); + LOGD("clientBdData->user_data.headers[%d].u.special_sm.message_count = 0x%02x\n", index, clientBdData->user_data.headers[index].u.special_sm.message_count); +#endif + data_buf[length++] = 9; + data_buf[length++] = (clientBdData->user_data.headers[index].u.special_sm.msg_waiting & 0xFF000000) >> 23; // int + data_buf[length++] = (clientBdData->user_data.headers[index].u.special_sm.msg_waiting & 0x00FF0000) >> 15; + data_buf[length++] = (clientBdData->user_data.headers[index].u.special_sm.msg_waiting & 0x0000FF00) >> 7; + data_buf[length++] = clientBdData->user_data.headers[index].u.special_sm.msg_waiting & 0x000000FF; + data_buf[length++] = (clientBdData->user_data.headers[index].u.special_sm.msg_waiting_kind & 0xFF000000) >> 23; // int + data_buf[length++] = (clientBdData->user_data.headers[index].u.special_sm.msg_waiting_kind & 0x00FF0000) >> 15; + data_buf[length++] = (clientBdData->user_data.headers[index].u.special_sm.msg_waiting_kind & 0x0000FF00) >> 7; + data_buf[length++] = clientBdData->user_data.headers[index].u.special_sm.msg_waiting_kind & 0x000000FF; + data_buf[length++] = clientBdData->user_data.headers[index].u.special_sm.message_count; + break; + case RIL_CDMA_SMS_UDH_PORT_8: +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].u.wap_8.dest_port = 0x%02x\n", index, clientBdData->user_data.headers[index].u.wap_8.dest_port); + LOGD("clientBdData->user_data.headers[%d].u.wap_8.orig_port = 0x%02x\n", index, clientBdData->user_data.headers[index].u.wap_8.orig_port); +#endif + data_buf[length++] = 2; + data_buf[length++] = clientBdData->user_data.headers[index].u.wap_8.dest_port; + data_buf[length++] = clientBdData->user_data.headers[index].u.wap_8.orig_port; + break; + case RIL_CDMA_SMS_UDH_PORT_16: +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].u.wap_16.dest_port = 0x%04x\n", index, clientBdData->user_data.headers[index].u.wap_16.dest_port); + LOGD("clientBdData->user_data.headers[%d].u.wap_16.orig_port = 0x%04x\n", index, clientBdData->user_data.headers[index].u.wap_16.orig_port); +#endif + data_buf[length++] = 4; + data_buf[length++] = (clientBdData->user_data.headers[index].u.wap_16.dest_port & 0xFF00) >> 7; // unsigned short + data_buf[length++] = clientBdData->user_data.headers[index].u.wap_16.dest_port & 0x00FF; + data_buf[length++] = (clientBdData->user_data.headers[index].u.wap_16.orig_port & 0xFF00) >> 7; // unsigned short + data_buf[length++] = clientBdData->user_data.headers[index].u.wap_16.orig_port & 0x00FF; + break; + case RIL_CDMA_SMS_UDH_CONCAT_16: +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->user_data.headers[%d].u.concat_16.msg_ref = 0x%04x\n", index, clientBdData->user_data.headers[index].u.concat_16.msg_ref); + LOGD("clientBdData->user_data.headers[%d].u.concat_16.total_sm = 0x%04x\n", index, clientBdData->user_data.headers[index].u.concat_16.total_sm); + LOGD("clientBdData->user_data.headers[%d].u.concat_16.seq_num = 0x%04x\n", index, clientBdData->user_data.headers[index].u.concat_16.seq_num); +#endif + data_buf[length++] = 4; + data_buf[length++] = (clientBdData->user_data.headers[index].u.concat_16.msg_ref & 0xFF00) >> 7; // unsigned short + data_buf[length++] = clientBdData->user_data.headers[index].u.concat_16.msg_ref & 0x00FF; + data_buf[length++] = clientBdData->user_data.headers[index].u.concat_16.total_sm; + data_buf[length++] = clientBdData->user_data.headers[index].u.concat_16.seq_num; + break; + default: + break; + } + } + + if (length != 0) { + arrData = env->NewByteArray((jsize)length); + env->SetByteArrayRegion(arrData, 0, length, data_buf); + } + + return arrData; +} + + +/* native interface */ +JNIEXPORT jint JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetSmsAddress + (JNIEnv * env, jobject obj, jobject smsAddress) +{ + jclass SmsAddressClass; + jfieldID field; + jbyteArray arrData = NULL; + jbyte byte_buf[RIL_CDMA_SMS_ADDRESS_MAX]; + int length; + jint intData; + jbyte byteData; + jboolean booleanData; + +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsSetSmsAddress()...\n"); +#endif + + // callback.digit_mode + if (getObjectByteField(env, smsAddress, "digitMode", &byteData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->callback.digit_mode = (RIL_CDMA_SMS_DigitMode)(byteData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.digit_mode = 0x%02x\n", clientBdData->callback.digit_mode); +#endif + + // callback.number_mode + if (getObjectByteField(env, smsAddress, "numberMode", &byteData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->callback.number_mode = (RIL_CDMA_SMS_NumberMode)(byteData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.number_mode = 0x%02x\n", clientBdData->callback.number_mode); +#endif + + // callback.number_type + if (getObjectIntField(env, smsAddress, "ton", &intData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->callback.number_type = (RIL_CDMA_SMS_NumberType)(intData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.number_type = %d\n", clientBdData->callback.number_type); +#endif + + // callback.number_plan + if (getObjectByteField(env, smsAddress, "numberPlan", &byteData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->callback.number_plan = (RIL_CDMA_SMS_NumberPlan)(byteData); +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.number_plan = 0x%02x\n", clientBdData->callback.number_plan); +#endif + + // callback.number_of_digits + if (getObjectByteField(env, smsAddress, "numberOfDigits", &byteData) != JNI_SUCCESS) + return JNI_FAILURE; + clientBdData->callback.number_of_digits = byteData; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.number_of_digits = %d\n",clientBdData->callback.number_of_digits); +#endif + + // callback.digits + if (getObjectByteArrayField(env, smsAddress, "origBytes", byte_buf, &length) != JNI_SUCCESS) + return JNI_FAILURE; + for (int i = 0; i < clientBdData->callback.number_of_digits; i++) { + clientBdData->callback.digits[i] = byte_buf[i]; +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.digits[%d] = 0x%02x\n", i, clientBdData->callback.digits[i]); +#endif + } + + return JNI_SUCCESS; +} + + +/* native interface */ +JNIEXPORT jint JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetSmsAddress + (JNIEnv * env, jobject obj, jobject smsAddress) +{ + jclass SmsAddressClass; + jfieldID field; + jbyteArray arrData = NULL; + jbyte *byte_buf; + int length; + +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsGetSmsAddress()...\n"); +#endif + + // callback.digit_mode +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.digit_mode = 0x%02x\n", clientBdData->callback.digit_mode); +#endif + if (setObjectByteField(env, smsAddress, "digitMode", (jbyte)clientBdData->callback.digit_mode) != JNI_SUCCESS) + return JNI_FAILURE; + + // callback.number_mode +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.number_mode = 0x%02x\n", clientBdData->callback.number_mode); +#endif + if (setObjectByteField(env, smsAddress, "numberMode", (jbyte)clientBdData->callback.number_mode) != JNI_SUCCESS) + return JNI_FAILURE; + + // callback.number_type +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.number_type = %d\n", clientBdData->callback.number_type); +#endif + if (setObjectIntField(env, smsAddress, "ton", (jint)clientBdData->callback.number_type) != JNI_SUCCESS) + return JNI_FAILURE; + + // callback.number_plan +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.number_plan = 0x%02x\n", clientBdData->callback.number_plan); +#endif + if (setObjectByteField(env, smsAddress, "numberPlan", (jbyte)clientBdData->callback.number_plan) != JNI_SUCCESS) + return JNI_FAILURE; + + // callback.number_of_digits +#ifdef DBG_LOG_LEVEL_A + LOGD("clientBdData->callback.number_of_digits = %d\n", clientBdData->callback.number_of_digits); +#endif + if (setObjectByteField(env, smsAddress, "numberOfDigits", (jbyte)clientBdData->callback.number_of_digits) != JNI_SUCCESS) + return JNI_FAILURE; + + // callback.digits + byte_buf = (jbyte*)clientBdData->callback.digits; + length = clientBdData->callback.number_of_digits; +#ifdef DBG_LOG_LEVEL_A + for (int i = 0; i < length; i++) { + LOGD("clientBdData->callback.digits[%d] = 0x%02x\n", i, clientBdData->callback.digits[i]); + } +#endif + + if (setObjectByteArrayField(env, smsAddress, "origBytes", byte_buf, length) != JNI_SUCCESS) + return JNI_FAILURE; + + return JNI_SUCCESS; +} + + +/* native interface */ +JNIEXPORT jbyteArray JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsEncodeSms + (JNIEnv * env, jobject obj) +{ + RIL_CDMA_Encoded_SMS *encoded_sms = (RIL_CDMA_Encoded_SMS *)malloc(sizeof(RIL_CDMA_Encoded_SMS)); + jbyte* data_buf; + jint result = JNI_SUCCESS; + jbyteArray encodedSMS; + +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsEncodeSms(): entry\n"); +#endif + + if (NULL == encoded_sms) { + jniThrowException(env, "java/lang/NullPointerException", "encoded_sms is null"); + return NULL; + } + memset(encoded_sms, 0, sizeof(RIL_CDMA_Encoded_SMS)); + + // call CDMA SMS encode function + if(wmsts_ril_cdma_encode_sms(clientBdData, encoded_sms) != RIL_E_SUCCESS) { + jniThrowException(env, "java/lang/Exception", "CDMA SMS Encoding failed"); + return NULL; + } + +#ifdef DBG_LOG_LEVEL_A + LOGD(" EncodeSMS: length = %i\n", encoded_sms->length); +#endif + encodedSMS = env->NewByteArray((jsize)encoded_sms->length); + env->SetByteArrayRegion(encodedSMS, 0, encoded_sms->length, (jbyte*)encoded_sms->data); + free(encoded_sms); + + return encodedSMS; +} + + +/* native interface */ +JNIEXPORT jint JNICALL +Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsDecodeSms + (JNIEnv * env, jobject obj, jbyteArray encodedSMS) +{ + RIL_CDMA_Encoded_SMS *encoded_sms = (RIL_CDMA_Encoded_SMS *)malloc(sizeof(RIL_CDMA_Encoded_SMS)); + jbyte* data_buf; + jint result = JNI_SUCCESS; + jsize length; + +#ifdef DBG_LOG_LEVEL_B + LOGD("nativeCdmaSmsDecodeSms(): entry\n"); +#endif + + if (NULL == encoded_sms) { + jniThrowException(env, "java/lang/NullPointerException", "encoded_sms is null"); + return JNI_FAILURE; + } + memset(encoded_sms, 0, sizeof(RIL_CDMA_Encoded_SMS)); + + length = env->GetArrayLength(encodedSMS); + if (length < 0 || length > 255) { + jniThrowException(env, "java/lang/ArrayIndexOutOfBounds", "wrong encoded SMS data length"); + return JNI_FAILURE; + } + encoded_sms->length = length; +#ifdef DBG_LOG_LEVEL_A + LOGD(" DecodeSMS: arrayLength = %d\n", encoded_sms->length); +#endif + data_buf = env->GetByteArrayElements(encodedSMS, NULL); + encoded_sms->data = (unsigned char*)data_buf; + env->ReleaseByteArrayElements(encodedSMS, data_buf, 0); + + // call CDMA SMS decode function + if(wmsts_ril_cdma_decode_sms(encoded_sms, clientBdData) != RIL_E_SUCCESS) { + jniThrowException(env, "java/lang/Exception", "CDMA SMS Decoding failed"); + result = JNI_FAILURE; + } + + free(encoded_sms); + + return result; +} + + +// --------------------------------------------------------------------------- + +static const char *classPathName = "com/android/internal/telephony/cdma/sms/SmsDataCoding"; + +static JNINativeMethod methods[] = { + /* name, signature, funcPtr */ + {"nativeCdmaSmsConstructClientBD", "()I", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsConstructClientBD }, + {"nativeCdmaSmsDestructClientBD", "()I", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsDestructClientBD }, + {"nativeCdmaSmsSetBearerDataPrimitives", "(Lcom/android/internal/telephony/cdma/sms/BearerData;)I", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetBearerDataPrimitives }, + {"nativeCdmaSmsGetBearerDataPrimitives", "(Lcom/android/internal/telephony/cdma/sms/BearerData;)I", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetBearerDataPrimitives }, + {"nativeCdmaSmsSetUserData", "(Lcom/android/internal/telephony/cdma/sms/UserData;)I", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetUserData }, + {"nativeCdmaSmsGetUserData", "(Lcom/android/internal/telephony/cdma/sms/UserData;)I", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetUserData }, + {"nativeCdmaSmsSetUserDataHeader", "(I[BII)I", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetUserDataHeader }, + {"nativeCdmaSmsGetUserDataHeader", "()[B", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetUserDataHeader }, + {"nativeCdmaSmsSetSmsAddress", "(Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;)I", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetSmsAddress }, + {"nativeCdmaSmsGetSmsAddress", "(Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;)I", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetSmsAddress }, + {"nativeCdmaSmsEncodeSms", "()[B", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsEncodeSms }, + {"nativeCdmaSmsDecodeSms", "([B)I", + (void*)Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsDecodeSms }, +}; + +int register_android_cdma_sms_methods(JNIEnv *_env) +{ + return android::AndroidRuntime::registerNativeMethods( + _env, classPathName, methods, NELEM(methods)); +} + +// --------------------------------------------------------------------------- + +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + LOGE("ERROR: GetEnv failed\n"); + goto bail; + } + assert(env != NULL); + + if (register_android_cdma_sms_methods(env) < 0) { + LOGE("ERROR: CDMA SMS native registration failed\n"); + goto bail; + } + + /* success -- return valid version number */ + result = JNI_VERSION_1_4; + +bail: + return result; +} diff --git a/telephony/jni/cdmasms/cdma_sms_jni.h b/telephony/jni/cdmasms/cdma_sms_jni.h new file mode 100644 index 000000000000..253c006cd9a5 --- /dev/null +++ b/telephony/jni/cdmasms/cdma_sms_jni.h @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2008 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. + */ + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class com_android_internal_telephony_cdma_sms_SmsDataCoding */ + +#ifndef _Included_com_android_internal_telephony_cdma_sms_SmsDataCoding +#define _Included_com_android_internal_telephony_cdma_sms_SmsDataCoding +#ifdef __cplusplus +extern "C" { +#endif +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_NULL +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_NULL 0L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_MSG_ID +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_MSG_ID 1L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_USER_DATA +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_USER_DATA 2L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_MC_TIME +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_MC_TIME 8L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS 2048L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_CALLBACK +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_CALLBACK 16384L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE 32768L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_SUCCESS +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_SUCCESS 0L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_FAILURE +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_FAILURE 1L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_DATA_LEN_OUT_OF_RANGE +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_DATA_LEN_OUT_OF_RANGE 2L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_CLASS_UNKNOWN +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_CLASS_UNKNOWN 3L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_FIELD_ID_UNKNOWN +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_FIELD_ID_UNKNOWN 4L +#undef com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_OUT_OF_MEMORY +#define com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_OUT_OF_MEMORY 5L +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsConstructClientBD + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsConstructClientBD + (JNIEnv *, jobject); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsDestructClientBD + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsDestructClientBD + (JNIEnv *, jobject); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsSetBearerDataPrimitives + * Signature: (Lcom/android/internal/telephony/cdma/sms/BearerData;)I + */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetBearerDataPrimitives + (JNIEnv *, jobject, jobject); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsGetBearerDataPrimitives + * Signature: (Lcom/android/internal/telephony/cdma/sms/BearerData;)I + */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetBearerDataPrimitives + (JNIEnv *, jobject, jobject); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsSetUserData + * Signature: (Lcom/android/internal/telephony/cdma/sms/UserData;)I + */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetUserData + (JNIEnv *, jobject, jobject); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsGetUserData + * Signature: (Lcom/android/internal/telephony/cdma/sms/UserData;)I + */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetUserData + (JNIEnv *, jobject, jobject); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsSetUserDataHeader + * Signature: (I[BII)I + */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetUserDataHeader + (JNIEnv *, jobject, jint, jbyteArray, jint, jint); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsGetUserDataHeader + * Signature: ()[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetUserDataHeader + (JNIEnv *, jobject); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsSetSmsAddress + * Signature: (Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;)I + */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsSetSmsAddress + (JNIEnv *, jobject, jobject); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsGetSmsAddress + * Signature: (Lcom/android/internal/telephony/cdma/sms/CdmaSmsAddress;)I + */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsGetSmsAddress + (JNIEnv *, jobject, jobject); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsEncodeSms + * Signature: ()[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsEncodeSms + (JNIEnv *, jobject); + +/* + * Class: com_android_internal_telephony_cdma_sms_SmsDataCoding + * Method: nativeCdmaSmsDecodeSms + * Signature: ([B)I + */ +JNIEXPORT jint JNICALL Java_com_android_internal_telephony_cdma_sms_SmsDataCoding_nativeCdmaSmsDecodeSms + (JNIEnv *, jobject, jbyteArray); + +/** + * CDMA SMS return value defines + */ +#define JNI_SUCCESS \ +com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_SUCCESS /**< Successful operation */ +#define JNI_FAILURE \ +com_android_internal_telephony_cdma_sms_SmsDataCoding_JNI_CDMA_SMS_FAILURE /**< General failure */ + +#ifdef __cplusplus +} +#endif +#endif |