summaryrefslogtreecommitdiff
path: root/telephony/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'telephony/java/com')
-rw-r--r--telephony/java/com/android/internal/telephony/AdnRecord.java77
-rw-r--r--telephony/java/com/android/internal/telephony/AdnRecordLoader.java6
-rw-r--r--telephony/java/com/android/internal/telephony/CallManager.java1414
-rw-r--r--telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java2
-rw-r--r--telephony/java/com/android/internal/telephony/CommandException.java12
-rw-r--r--telephony/java/com/android/internal/telephony/CommandsInterface.java13
-rw-r--r--telephony/java/com/android/internal/telephony/Connection.java52
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnection.java8
-rw-r--r--telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java3
-rw-r--r--telephony/java/com/android/internal/telephony/DriverCall.java1
-rw-r--r--telephony/java/com/android/internal/telephony/GsmAlphabet.java2
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl3
-rw-r--r--telephony/java/com/android/internal/telephony/IccProvider.java4
-rw-r--r--telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java8
-rw-r--r--telephony/java/com/android/internal/telephony/Phone.java28
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneBase.java4
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneFactory.java15
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneProxy.java4
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneSubInfo.java4
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java2
-rw-r--r--telephony/java/com/android/internal/telephony/RIL.java33
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java6
-rw-r--r--telephony/java/com/android/internal/telephony/RetryManager.java21
-rw-r--r--telephony/java/com/android/internal/telephony/SMSDispatcher.java99
-rw-r--r--telephony/java/com/android/internal/telephony/ServiceStateTracker.java7
-rw-r--r--telephony/java/com/android/internal/telephony/SipPhoneNotifier.java237
-rw-r--r--telephony/java/com/android/internal/telephony/UUSInfo.java100
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CDMAPhone.java56
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaCall.java3
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java2
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CdmaConnection.java6
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java6
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaMmiCode.java296
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java23
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java19
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java5
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/SmsMessage.java8
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/TtyIntent.java8
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java15
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/CallFailCause.java3
-rw-r--r--[-rwxr-xr-x]telephony/java/com/android/internal/telephony/gsm/GSMPhone.java22
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmCall.java3
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java20
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmConnection.java10
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java2
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java21
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java45
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java18
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java30
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java5
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/SmsMessage.java22
-rw-r--r--telephony/java/com/android/internal/telephony/sip/CallFailCause.java50
-rw-r--r--telephony/java/com/android/internal/telephony/sip/CallProxy.java114
-rw-r--r--telephony/java/com/android/internal/telephony/sip/SipCallBase.java102
-rw-r--r--telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java373
-rw-r--r--telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java248
-rwxr-xr-xtelephony/java/com/android/internal/telephony/sip/SipPhone.java846
-rwxr-xr-xtelephony/java/com/android/internal/telephony/sip/SipPhoneBase.java553
-rw-r--r--telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java49
-rw-r--r--telephony/java/com/android/internal/telephony/test/SimulatedCommands.java19
60 files changed, 4888 insertions, 279 deletions
diff --git a/telephony/java/com/android/internal/telephony/AdnRecord.java b/telephony/java/com/android/internal/telephony/AdnRecord.java
index 0896ba60ee71..1bf2d3c61d50 100644
--- a/telephony/java/com/android/internal/telephony/AdnRecord.java
+++ b/telephony/java/com/android/internal/telephony/AdnRecord.java
@@ -19,10 +19,9 @@ package com.android.internal.telephony;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
import android.util.Log;
-import com.android.internal.telephony.GsmAlphabet;
-
import java.util.Arrays;
@@ -38,8 +37,8 @@ public class AdnRecord implements Parcelable {
//***** Instance Variables
- String alphaTag = "";
- String number = "";
+ String alphaTag = null;
+ String number = null;
String[] emails;
int extRecord = 0xff;
int efid; // or 0 if none
@@ -63,8 +62,8 @@ public class AdnRecord implements Parcelable {
// ADN offset
static final int ADN_BCD_NUMBER_LENGTH = 0;
static final int ADN_TON_AND_NPI = 1;
- static final int ADN_DAILING_NUMBER_START = 2;
- static final int ADN_DAILING_NUMBER_END = 11;
+ static final int ADN_DIALING_NUMBER_START = 2;
+ static final int ADN_DIALING_NUMBER_END = 11;
static final int ADN_CAPABILITY_ID = 12;
static final int ADN_EXTENSION_ID = 13;
@@ -152,17 +151,31 @@ public class AdnRecord implements Parcelable {
}
public boolean isEmpty() {
- return alphaTag.equals("") && number.equals("") && emails == null;
+ return TextUtils.isEmpty(alphaTag) && TextUtils.isEmpty(number) && emails == null;
}
public boolean hasExtendedRecord() {
return extRecord != 0 && extRecord != 0xff;
}
+ /** Helper function for {@link #isEqual}. */
+ private static boolean stringCompareNullEqualsEmpty(String s1, String s2) {
+ if (s1 == s2) {
+ return true;
+ }
+ if (s1 == null) {
+ s1 = "";
+ }
+ if (s2 == null) {
+ s2 = "";
+ }
+ return (s1.equals(s2));
+ }
+
public boolean isEqual(AdnRecord adn) {
- return ( alphaTag.equals(adn.getAlphaTag()) &&
- number.equals(adn.getNumber()) &&
- Arrays.equals(emails, adn.getEmails()));
+ return ( stringCompareNullEqualsEmpty(alphaTag, adn.alphaTag) &&
+ stringCompareNullEqualsEmpty(number, adn.number) &&
+ Arrays.equals(emails, adn.emails));
}
//***** Parcelable Implementation
@@ -184,36 +197,33 @@ public class AdnRecord implements Parcelable {
*
* @param recordSize is the size X of EF record
* @return hex byte[recordSize] to be written to EF record
- * return nulll for wrong format of dialing nubmer or tag
+ * return null for wrong format of dialing number or tag
*/
public byte[] buildAdnString(int recordSize) {
byte[] bcdNumber;
byte[] byteTag;
- byte[] adnString = null;
+ byte[] adnString;
int footerOffset = recordSize - FOOTER_SIZE_BYTES;
- if (number == null || number.equals("") ||
- alphaTag == null || alphaTag.equals("")) {
+ // create an empty record
+ adnString = new byte[recordSize];
+ for (int i = 0; i < recordSize; i++) {
+ adnString[i] = (byte) 0xFF;
+ }
- Log.w(LOG_TAG, "[buildAdnString] Empty alpha tag or number");
- adnString = new byte[recordSize];
- for (int i = 0; i < recordSize; i++) {
- adnString[i] = (byte) 0xFF;
- }
+ if (TextUtils.isEmpty(number)) {
+ Log.w(LOG_TAG, "[buildAdnString] Empty dialing number");
+ return adnString; // return the empty record (for delete)
} else if (number.length()
- > (ADN_DAILING_NUMBER_END - ADN_DAILING_NUMBER_START + 1) * 2) {
+ > (ADN_DIALING_NUMBER_END - ADN_DIALING_NUMBER_START + 1) * 2) {
Log.w(LOG_TAG,
- "[buildAdnString] Max length of dailing number is 20");
- } else if (alphaTag.length() > footerOffset) {
+ "[buildAdnString] Max length of dialing number is 20");
+ return null;
+ } else if (alphaTag != null && alphaTag.length() > footerOffset) {
Log.w(LOG_TAG,
"[buildAdnString] Max length of tag is " + footerOffset);
+ return null;
} else {
-
- adnString = new byte[recordSize];
- for (int i = 0; i < recordSize; i++) {
- adnString[i] = (byte) 0xFF;
- }
-
bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(number);
System.arraycopy(bcdNumber, 0, adnString,
@@ -222,16 +232,17 @@ public class AdnRecord implements Parcelable {
adnString[footerOffset + ADN_BCD_NUMBER_LENGTH]
= (byte) (bcdNumber.length);
adnString[footerOffset + ADN_CAPABILITY_ID]
- = (byte) 0xFF; // Capacility Id
+ = (byte) 0xFF; // Capability Id
adnString[footerOffset + ADN_EXTENSION_ID]
= (byte) 0xFF; // Extension Record Id
- byteTag = GsmAlphabet.stringToGsm8BitPacked(alphaTag);
- System.arraycopy(byteTag, 0, adnString, 0, byteTag.length);
+ if (!TextUtils.isEmpty(alphaTag)) {
+ byteTag = GsmAlphabet.stringToGsm8BitPacked(alphaTag);
+ System.arraycopy(byteTag, 0, adnString, 0, byteTag.length);
+ }
+ return adnString;
}
-
- return adnString;
}
/**
diff --git a/telephony/java/com/android/internal/telephony/AdnRecordLoader.java b/telephony/java/com/android/internal/telephony/AdnRecordLoader.java
index cfb5aaa84b39..55bdc06b8aea 100644
--- a/telephony/java/com/android/internal/telephony/AdnRecordLoader.java
+++ b/telephony/java/com/android/internal/telephony/AdnRecordLoader.java
@@ -106,7 +106,7 @@ public class AdnRecordLoader extends Handler {
* It will get the record size of EF record and compose hex adn array
* then write the hex array to EF record
*
- * @param adn is set with alphaTag and phoneNubmer
+ * @param adn is set with alphaTag and phone number
* @param ef EF fileid
* @param extensionEF extension EF fileid
* @param recordNumber 1-based record index
@@ -159,7 +159,7 @@ public class AdnRecordLoader extends Handler {
data = adn.buildAdnString(recordSize[0]);
if(data == null) {
- throw new RuntimeException("worong ADN format",
+ throw new RuntimeException("wrong ADN format",
ar.exception);
}
@@ -218,7 +218,7 @@ public class AdnRecordLoader extends Handler {
throw new RuntimeException("load failed", ar.exception);
}
- Log.d(LOG_TAG,"ADN extention EF: 0x"
+ Log.d(LOG_TAG,"ADN extension EF: 0x"
+ Integer.toHexString(extensionEF)
+ ":" + adn.extRecord
+ "\n" + IccUtils.bytesToHexString(data));
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
new file mode 100644
index 000000000000..4bf32829e761
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -0,0 +1,1414 @@
+/*
+ * Copyright (C) 2010 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 com.android.internal.telephony.sip.SipPhone;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RegistrantList;
+import android.telephony.PhoneStateListener;
+import android.telephony.ServiceState;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+
+/**
+ * @hide
+ *
+ * CallManager class provides an abstract layer for PhoneApp to access
+ * and control calls. It implements Phone interface.
+ *
+ * CallManager provides call and connection control as well as
+ * channel capability.
+ *
+ * There are three categories of APIs CallManager provided
+ *
+ * 1. Call control and operation, such as dial() and hangup()
+ * 2. Channel capabilities, such as CanConference()
+ * 3. Register notification
+ *
+ *
+ */
+public final class CallManager {
+
+ private static final String LOG_TAG ="Phone";
+ private static final boolean LOCAL_DEBUG = true;
+
+ private static final int EVENT_DISCONNECT = 100;
+ private static final int EVENT_PRECISE_CALL_STATE_CHANGED = 101;
+ private static final int EVENT_NEW_RINGING_CONNECTION = 102;
+ private static final int EVENT_UNKNOWN_CONNECTION = 103;
+ private static final int EVENT_INCOMING_RING = 104;
+ private static final int EVENT_RINGBACK_TONE = 105;
+ private static final int EVENT_IN_CALL_VOICE_PRIVACY_ON = 106;
+ private static final int EVENT_IN_CALL_VOICE_PRIVACY_OFF = 107;
+ private static final int EVENT_CALL_WAITING = 108;
+ private static final int EVENT_DISPLAY_INFO = 109;
+ private static final int EVENT_SIGNAL_INFO = 110;
+ private static final int EVENT_CDMA_OTA_STATUS_CHANGE = 111;
+ private static final int EVENT_RESEND_INCALL_MUTE = 112;
+ private static final int EVENT_MMI_INITIATE = 113;
+ private static final int EVENT_MMI_COMPLETE = 114;
+ private static final int EVENT_ECM_TIMER_RESET = 115;
+ private static final int EVENT_SUBSCRIPTION_INFO_READY = 116;
+ private static final int EVENT_SUPP_SERVICE_FAILED = 117;
+ private static final int EVENT_SERVICE_STATE_CHANGED = 118;
+
+ // Singleton instance
+ private static final CallManager INSTANCE = new CallManager();
+
+ // list of registered phones
+ private final ArrayList<Phone> mPhones;
+
+ // list of supported ringing calls
+ private final ArrayList<Call> mRingingCalls;
+
+ // list of supported background calls
+ private final ArrayList<Call> mBackgroundCalls;
+
+ // list of supported foreground calls
+ private final ArrayList<Call> mForegroundCalls;
+
+ // empty connection list
+ private final ArrayList<Connection> emptyConnections = new ArrayList<Connection>();
+
+ // default phone as the first phone registered
+ private Phone mDefaultPhone;
+
+ // state registrants
+ protected final RegistrantList mPreciseCallStateRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mNewRingingConnectionRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mIncomingRingRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mDisconnectRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mMmiRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mUnknownConnectionRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mRingbackToneRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mInCallVoicePrivacyOnRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mInCallVoicePrivacyOffRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mCallWaitingRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mDisplayInfoRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mSignalInfoRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mCdmaOtaStatusChangeRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mResendIncallMuteRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mMmiInitiateRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mMmiCompleteRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mEcmTimerResetRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mSubscriptionInfoReadyRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mSuppServiceFailedRegistrants
+ = new RegistrantList();
+
+ protected final RegistrantList mServiceStateChangedRegistrants
+ = new RegistrantList();
+
+ private CallManager() {
+ mPhones = new ArrayList<Phone>();
+ mRingingCalls = new ArrayList<Call>();
+ mBackgroundCalls = new ArrayList<Call>();
+ mForegroundCalls = new ArrayList<Call>();
+ mDefaultPhone = null;
+ }
+
+ /**
+ * get singleton instance of CallManager
+ * @return CallManager
+ */
+ public static CallManager getInstance() {
+ return INSTANCE;
+ }
+
+ /**
+ * Returns all the registered phone objects.
+ * @return all the registered phone objects.
+ */
+ public List<Phone> getAllPhones() {
+ return Collections.unmodifiableList(mPhones);
+ }
+
+ /**
+ * Get current coarse-grained voice call state.
+ * If the Call Manager has an active call and call waiting occurs,
+ * then the phone state is RINGING not OFFHOOK
+ *
+ */
+ public Phone.State getState() {
+ Phone.State s = Phone.State.IDLE;
+
+ for (Phone phone : mPhones) {
+ if (phone.getState() == Phone.State.RINGING) {
+ return Phone.State.RINGING;
+ } else if (phone.getState() == Phone.State.OFFHOOK) {
+ s = Phone.State.OFFHOOK;
+ }
+ }
+ return s;
+ }
+
+ /**
+ * @return the service state of CallManager, which represents the
+ * highest priority state of all the service states of phones
+ *
+ * The priority is defined as
+ *
+ * STATE_IN_SERIVCE > STATE_OUT_OF_SERIVCE > STATE_EMERGENCY > STATE_POWER_OFF
+ *
+ */
+
+ public int getServiceState() {
+ int resultState = ServiceState.STATE_OUT_OF_SERVICE;
+
+ for (Phone phone : mPhones) {
+ int serviceState = phone.getServiceState().getState();
+ if (serviceState == ServiceState.STATE_IN_SERVICE) {
+ // IN_SERVICE has the highest priority
+ resultState = serviceState;
+ break;
+ } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) {
+ // OUT_OF_SERVICE replaces EMERGENCY_ONLY and POWER_OFF
+ // Note: EMERGENCY_ONLY is not in use at this moment
+ if ( resultState == ServiceState.STATE_EMERGENCY_ONLY ||
+ resultState == ServiceState.STATE_POWER_OFF) {
+ resultState = serviceState;
+ }
+ } else if (serviceState == ServiceState.STATE_EMERGENCY_ONLY) {
+ if (resultState == ServiceState.STATE_POWER_OFF) {
+ resultState = serviceState;
+ }
+ }
+ }
+ return resultState;
+ }
+
+ /**
+ * Register phone to CallManager
+ * @param phone
+ * @return true if register successfully
+ */
+ public boolean registerPhone(Phone phone) {
+ if (phone != null && !mPhones.contains(phone)) {
+ if (mPhones.isEmpty()) {
+ mDefaultPhone = phone;
+ }
+ mPhones.add(phone);
+ mRingingCalls.add(phone.getRingingCall());
+ mBackgroundCalls.add(phone.getBackgroundCall());
+ mForegroundCalls.add(phone.getForegroundCall());
+ registerForPhoneStates(phone);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * return the default phone or null if no phone available
+ */
+ public Phone getDefaultPhone() {
+ return mDefaultPhone;
+ }
+
+ /**
+ * @return the phone associated with the foreground call
+ */
+ public Phone getFgPhone() {
+ return getActiveFgCall().getPhone();
+ }
+
+ /**
+ * @return the phone associated with the background call
+ */
+ public Phone getBgPhone() {
+ return getFirstActiveBgCall().getPhone();
+ }
+
+ /**
+ * @return the phone associated with the ringing call
+ */
+ public Phone getRingingPhone() {
+ return getFirstActiveRingingCall().getPhone();
+ }
+
+ /**
+ * unregister phone from CallManager
+ * @param phone
+ */
+ public void unregisterPhone(Phone phone) {
+ if (phone != null && mPhones.contains(phone)) {
+ mPhones.remove(phone);
+ mRingingCalls.remove(phone.getRingingCall());
+ mBackgroundCalls.remove(phone.getBackgroundCall());
+ mForegroundCalls.remove(phone.getForegroundCall());
+ unregisterForPhoneStates(phone);
+ if (phone == mDefaultPhone) {
+ if (mPhones.isEmpty()) {
+ mDefaultPhone = null;
+ } else {
+ mDefaultPhone = mPhones.get(0);
+ }
+ }
+ }
+ }
+
+ public void setAudioMode() {
+ Context context = getContext();
+ if (context == null) return;
+ AudioManager audioManager = (AudioManager)
+ context.getSystemService(Context.AUDIO_SERVICE);
+
+ int mode = AudioManager.MODE_NORMAL;
+ switch (getState()) {
+ case RINGING:
+ mode = AudioManager.MODE_RINGTONE;
+ break;
+ case OFFHOOK:
+ Phone fgPhone = getFgPhone();
+ if (!(fgPhone instanceof SipPhone)) {
+ mode = AudioManager.MODE_IN_CALL;
+ }
+ break;
+ }
+ // calling audioManager.setMode() multiple times in a short period of
+ // time seems to break the audio recorder in in-call mode
+ if (audioManager.getMode() != mode) audioManager.setMode(mode);
+ }
+
+ private Context getContext() {
+ Phone defaultPhone = getDefaultPhone();
+ return ((defaultPhone == null) ? null : defaultPhone.getContext());
+ }
+
+ private void registerForPhoneStates(Phone phone) {
+ phone.registerForPreciseCallStateChanged(mHandler, EVENT_PRECISE_CALL_STATE_CHANGED, null);
+ phone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
+ phone.registerForNewRingingConnection(mHandler, EVENT_NEW_RINGING_CONNECTION, null);
+ phone.registerForUnknownConnection(mHandler, EVENT_UNKNOWN_CONNECTION, null);
+ phone.registerForIncomingRing(mHandler, EVENT_INCOMING_RING, null);
+ phone.registerForRingbackTone(mHandler, EVENT_RINGBACK_TONE, null);
+ phone.registerForInCallVoicePrivacyOn(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_ON, null);
+ phone.registerForInCallVoicePrivacyOff(mHandler, EVENT_IN_CALL_VOICE_PRIVACY_OFF, null);
+ phone.registerForCallWaiting(mHandler, EVENT_CALL_WAITING, null);
+ phone.registerForDisplayInfo(mHandler, EVENT_DISPLAY_INFO, null);
+ phone.registerForSignalInfo(mHandler, EVENT_SIGNAL_INFO, null);
+ phone.registerForCdmaOtaStatusChange(mHandler, EVENT_CDMA_OTA_STATUS_CHANGE, null);
+ phone.registerForResendIncallMute(mHandler, EVENT_RESEND_INCALL_MUTE, null);
+ phone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
+ phone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
+ phone.registerForEcmTimerReset(mHandler, EVENT_ECM_TIMER_RESET, null);
+ phone.registerForSubscriptionInfoReady(mHandler, EVENT_SUBSCRIPTION_INFO_READY, null);
+ phone.registerForSuppServiceFailed(mHandler, EVENT_SUPP_SERVICE_FAILED, null);
+ phone.registerForServiceStateChanged(mHandler, EVENT_SERVICE_STATE_CHANGED, null);
+ }
+
+ private void unregisterForPhoneStates(Phone phone) {
+ phone.unregisterForPreciseCallStateChanged(mHandler);
+ phone.unregisterForDisconnect(mHandler);
+ phone.unregisterForNewRingingConnection(mHandler);
+ phone.unregisterForUnknownConnection(mHandler);
+ phone.unregisterForIncomingRing(mHandler);
+ phone.unregisterForRingbackTone(mHandler);
+ phone.unregisterForInCallVoicePrivacyOn(mHandler);
+ phone.unregisterForInCallVoicePrivacyOff(mHandler);
+ phone.unregisterForCallWaiting(mHandler);
+ phone.unregisterForDisplayInfo(mHandler);
+ phone.unregisterForSignalInfo(mHandler);
+ phone.unregisterForCdmaOtaStatusChange(mHandler);
+ phone.unregisterForResendIncallMute(mHandler);
+ phone.unregisterForMmiInitiate(mHandler);
+ phone.unregisterForMmiComplete(mHandler);
+ phone.unregisterForEcmTimerReset(mHandler);
+ phone.unregisterForSubscriptionInfoReady(mHandler);
+ phone.unregisterForSuppServiceFailed(mHandler);
+ phone.unregisterForServiceStateChanged(mHandler);
+ }
+
+ /**
+ * Answers a ringing or waiting call.
+ *
+ * Active call, if any, go on hold.
+ * If active call can't be held, i.e., a background call of the same channel exists,
+ * the active call will be hang up.
+ *
+ * Answering occurs asynchronously, and final notification occurs via
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
+ *
+ * @exception CallStateException when call is not ringing or waiting
+ */
+ public void acceptCall(Call ringingCall) throws CallStateException {
+ Phone ringingPhone = ringingCall.getPhone();
+
+ if ( hasActiveFgCall() ) {
+ Phone activePhone = getActiveFgCall().getPhone();
+ boolean hasBgCall = ! (activePhone.getBackgroundCall().isIdle());
+ boolean sameChannel = (activePhone == ringingPhone);
+
+ if (LOCAL_DEBUG) {
+ Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + "sameChannel:" + sameChannel);
+ }
+
+ if (sameChannel && hasBgCall) {
+ getActiveFgCall().hangup();
+ } else if (!sameChannel && !hasBgCall) {
+ activePhone.switchHoldingAndActive();
+ } else if (!sameChannel && hasBgCall) {
+ getActiveFgCall().hangup();
+ }
+ }
+
+ ringingPhone.acceptCall();
+ }
+
+ /**
+ * Reject (ignore) a ringing call. In GSM, this means UDUB
+ * (User Determined User Busy). Reject occurs asynchronously,
+ * and final notification occurs via
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
+ *
+ * @exception CallStateException when no call is ringing or waiting
+ */
+ public void rejectCall(Call ringingCall) throws CallStateException {
+ Phone ringingPhone = ringingCall.getPhone();
+
+ ringingPhone.rejectCall();
+ }
+
+ /**
+ * Places active call on hold, and makes held call active.
+ * Switch occurs asynchronously and may fail.
+ *
+ * There are 4 scenarios
+ * 1. only active call but no held call, aka, hold
+ * 2. no active call but only held call, aka, unhold
+ * 3. both active and held calls from same phone, aka, swap
+ * 4. active and held calls from different phones, aka, phone swap
+ *
+ * Final notification occurs via
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
+ *
+ * @exception CallStateException if active call is ringing, waiting, or
+ * dialing/alerting, or heldCall can't be active.
+ * In these cases, this operation may not be performed.
+ */
+ public void switchHoldingAndActive(Call heldCall) throws CallStateException {
+ Phone activePhone = null;
+ Phone heldPhone = null;
+
+ if (hasActiveFgCall()) {
+ activePhone = getActiveFgCall().getPhone();
+ }
+
+ if (heldCall != null) {
+ heldPhone = heldCall.getPhone();
+ }
+
+ if (activePhone != null) {
+ activePhone.switchHoldingAndActive();
+ }
+
+ if (heldPhone != null && heldPhone != activePhone) {
+ heldPhone.switchHoldingAndActive();
+ }
+ }
+
+ /**
+ * Hangup foreground call and resume the specific background call
+ *
+ * Note: this is noop if there is no foreground call or the heldCall is null
+ *
+ * @param heldCall to become foreground
+ * @throws CallStateException
+ */
+ public void hangupForegroundResumeBackground(Call heldCall) throws CallStateException {
+ Phone foregroundPhone = null;
+ Phone backgroundPhone = null;
+
+ if (hasActiveFgCall()) {
+ foregroundPhone = getFgPhone();
+ if (heldCall != null) {
+ backgroundPhone = heldCall.getPhone();
+ if (foregroundPhone == backgroundPhone) {
+ getActiveFgCall().hangup();
+ } else {
+ // the call to be hangup and resumed belongs to different phones
+ getActiveFgCall().hangup();
+ switchHoldingAndActive(heldCall);
+ }
+ }
+ }
+ }
+
+ /**
+ * 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.
+ */
+ public boolean canConference(Call heldCall) {
+ Phone activePhone = null;
+ Phone heldPhone = null;
+
+ if (hasActiveFgCall()) {
+ activePhone = getActiveFgCall().getPhone();
+ }
+
+ if (heldCall != null) {
+ heldPhone = heldCall.getPhone();
+ }
+
+ return heldPhone.getClass().equals(activePhone.getClass());
+ }
+
+ /**
+ * Conferences holding and active. Conference occurs asynchronously
+ * and may fail. Final notification occurs via
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
+ *
+ * @exception CallStateException if canConference() would return false.
+ * In these cases, this operation may not be performed.
+ */
+ public void conference(Call heldCall) throws CallStateException {
+ Phone fgPhone = getFgPhone();
+ if (fgPhone instanceof SipPhone) {
+ ((SipPhone) fgPhone).conference(heldCall);
+ } else if (canConference(heldCall)) {
+ fgPhone.conference();
+ } else {
+ throw(new CallStateException("Can't conference foreground and selected background call"));
+ }
+ }
+
+ /**
+ * 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
+ * handled asynchronously.
+ */
+ public Connection dial(Phone phone, String dialString) throws CallStateException {
+ if ( hasActiveFgCall() ) {
+ Phone activePhone = getActiveFgCall().getPhone();
+ boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
+
+ if (LOCAL_DEBUG) {
+ Log.d(LOG_TAG, "hasBgCall: "+ hasBgCall + "sameChannel:" + (activePhone != phone));
+ }
+
+ if (activePhone != phone) {
+ if (hasBgCall) {
+ Log.d(LOG_TAG, "Hangup");
+ getActiveFgCall().hangup();
+ } else {
+ Log.d(LOG_TAG, "Switch");
+ activePhone.switchHoldingAndActive();
+ }
+ }
+ }
+ return phone.dial(dialString);
+ }
+
+ /**
+ * 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
+ * handled asynchronously.
+ */
+ public Connection dial(Phone phone, String dialString, UUSInfo uusInfo) throws CallStateException {
+ return phone.dial(dialString, uusInfo);
+ }
+
+ /**
+ * clear disconnect connection for each phone
+ */
+ public void clearDisconnected() {
+ for(Phone phone : mPhones) {
+ phone.clearDisconnected();
+ }
+ }
+
+ /**
+ * Whether or not the phone can do explicit call transfer in the current
+ * phone state--that is, one call holding and one call active.
+ * @return true if the phone can do explicit call transfer; false otherwise.
+ */
+ public boolean canTransfer(Call heldCall) {
+ Phone activePhone = null;
+ Phone heldPhone = null;
+
+ if (hasActiveFgCall()) {
+ activePhone = getActiveFgCall().getPhone();
+ }
+
+ if (heldCall != null) {
+ heldPhone = heldCall.getPhone();
+ }
+
+ return (heldPhone == activePhone && activePhone.canTransfer());
+ }
+
+ /**
+ * Connects the held call and active call
+ * Disconnects the subscriber from both calls
+ *
+ * Explicit Call Transfer occurs asynchronously
+ * and may fail. Final notification occurs via
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}.
+ *
+ * @exception CallStateException if canTransfer() would return false.
+ * In these cases, this operation may not be performed.
+ */
+ public void explicitCallTransfer(Call heldCall) throws CallStateException {
+ if (canTransfer(heldCall)) {
+ heldCall.getPhone().explicitCallTransfer();
+ }
+ }
+
+ /**
+ * Returns a list of MMI codes that are pending for a phone. (They have initiated
+ * but have not yet completed).
+ * Presently there is only ever one.
+ *
+ * Use <code>registerForMmiInitiate</code>
+ * and <code>registerForMmiComplete</code> for change notification.
+ * @return null if phone doesn't have or support mmi code
+ */
+ public List<? extends MmiCode> getPendingMmiCodes(Phone phone) {
+ return null;
+ }
+
+ /**
+ * Sends user response to a USSD REQUEST message. An MmiCode instance
+ * representing this response is sent to handlers registered with
+ * registerForMmiInitiate.
+ *
+ * @param ussdMessge Message to send in the response.
+ * @return false if phone doesn't support ussd service
+ */
+ public boolean sendUssdResponse(Phone phone, String ussdMessge) {
+ return false;
+ }
+
+ /**
+ * 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,
+ * false to activate the microphone.
+ */
+
+ public void setMute(boolean muted) {
+ if (hasActiveFgCall()) {
+ getActiveFgCall().getPhone().setMute(muted);
+ }
+ }
+
+ /**
+ * Gets current mute status. Use
+ * {@link #registerForPreciseCallStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPreciseCallStateChanged()}
+ * as a change notifcation, although presently phone state changed is not
+ * fired when setMute() is called.
+ *
+ * @return true is muting, false is unmuting
+ */
+ public boolean getMute() {
+ if (hasActiveFgCall()) {
+ return getActiveFgCall().getPhone().getMute();
+ }
+ return false;
+ }
+
+ /**
+ * Play a DTMF tone on the active call.
+ *
+ * @param c should be one of 0-9, '*' or '#'. Other values will be
+ * silently ignored.
+ * @return false if no active call or the active call doesn't support
+ * dtmf tone
+ */
+ public boolean sendDtmf(char c) {
+ if (hasActiveFgCall()) {
+ getActiveFgCall().getPhone().sendDtmf(c);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Start to paly a DTMF tone on the active call.
+ * or there is a playing DTMF tone.
+ * @param c should be one of 0-9, '*' or '#'. Other values will be
+ * silently ignored.
+ *
+ * @return false if no active call or the active call doesn't support
+ * dtmf tone
+ */
+ public boolean startDtmf(char c) {
+ if (hasActiveFgCall()) {
+ getActiveFgCall().getPhone().sendDtmf(c);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Stop the playing DTMF tone. Ignored if there is no playing DTMF
+ * tone or no active call.
+ */
+ public void stopDtmf() {
+ if (hasActiveFgCall()) getFgPhone().stopDtmf();
+ }
+
+ /**
+ * send burst DTMF tone, it can send the string as single character or multiple character
+ * ignore if there is no active call or not valid digits string.
+ * Valid digit means only includes characters ISO-LATIN characters 0-9, *, #
+ * The difference between sendDtmf and sendBurstDtmf is sendDtmf only sends one character,
+ * this api can send single character and multiple character, also, this api has response
+ * back to caller.
+ *
+ * @param dtmfString is string representing the dialing digit(s) in the active call
+ * @param on the DTMF ON length in milliseconds, or 0 for default
+ * @param off the DTMF OFF length in milliseconds, or 0 for default
+ * @param onComplete is the callback message when the action is processed by BP
+ *
+ */
+ public boolean sendBurstDtmf(String dtmfString, int on, int off, Message onComplete) {
+ if (hasActiveFgCall()) {
+ getActiveFgCall().getPhone().sendBurstDtmf(dtmfString, on, off, onComplete);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 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
+ * no longer connected.</li></ul>
+ */
+ public void registerForDisconnect(Handler h, int what, Object obj) {
+ mDisconnectRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for voice disconnection notification.
+ * Extraneous calls are tolerated silently
+ */
+ public void unregisterForDisconnect(Handler h){
+ mDisconnectRegistrants.remove(h);
+ }
+
+ /**
+ * Register for getting notifications for change in the Call State {@link Call.State}
+ * This is called PreciseCallState because the call state is more precise than the
+ * {@link Phone.State} which can be obtained using the {@link PhoneStateListener}
+ *
+ * Resulting events will have an AsyncResult in <code>Message.obj</code>.
+ * AsyncResult.userData will be set to the obj argument here.
+ * The <em>h</em> parameter is held only by a weak reference.
+ */
+ public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){
+ mPreciseCallStateRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for voice call state change notifications.
+ * Extraneous calls are tolerated silently.
+ */
+ public void unregisterForPreciseCallStateChanged(Handler h){
+ mPreciseCallStateRegistrants.remove(h);
+ }
+
+ /**
+ * 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.
+ */
+ public void registerForUnknownConnection(Handler h, int what, Object obj){
+ mUnknownConnectionRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for unknown connection notifications.
+ */
+ public void unregisterForUnknownConnection(Handler h){
+ mUnknownConnectionRegistrants.remove(h);
+ }
+
+
+ /**
+ * Notifies when a new ringing or waiting connection has appeared.<p>
+ *
+ * Messages received from this:
+ * Message.obj will be an AsyncResult
+ * AsyncResult.userObj = obj
+ * 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
+ * Connection.getCall() == Phone.getRingingCall()
+ */
+ public void registerForNewRingingConnection(Handler h, int what, Object obj){
+ mNewRingingConnectionRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for new ringing connection notification.
+ * Extraneous calls are tolerated silently
+ */
+
+ public void unregisterForNewRingingConnection(Handler h){
+ mNewRingingConnectionRegistrants.remove(h);
+ }
+
+ /**
+ * Notifies when an incoming call rings.<p>
+ *
+ * Messages received from this:
+ * Message.obj will be an AsyncResult
+ * AsyncResult.userObj = obj
+ * AsyncResult.result = a Connection. <p>
+ */
+ public void registerForIncomingRing(Handler h, int what, Object obj){
+ mIncomingRingRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for ring notification.
+ * Extraneous calls are tolerated silently
+ */
+
+ public void unregisterForIncomingRing(Handler h){
+ mIncomingRingRegistrants.remove(h);
+ }
+
+ /**
+ * Notifies when out-band ringback tone is needed.<p>
+ *
+ * Messages received from this:
+ * Message.obj will be an AsyncResult
+ * AsyncResult.userObj = obj
+ * AsyncResult.result = boolean, true to start play ringback tone
+ * and false to stop. <p>
+ */
+ public void registerForRingbackTone(Handler h, int what, Object obj){
+ mRingbackToneRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for ringback tone notification.
+ */
+
+ public void unregisterForRingbackTone(Handler h){
+ mRingbackToneRegistrants.remove(h);
+ }
+
+ /**
+ * Registers the handler to reset the uplink mute state to get
+ * uplink audio.
+ */
+ public void registerForResendIncallMute(Handler h, int what, Object obj){
+ mResendIncallMuteRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for resend incall mute notifications.
+ */
+ public void unregisterForResendIncallMute(Handler h){
+ mResendIncallMuteRegistrants.remove(h);
+ }
+
+ /**
+ * Register for notifications of initiation of a new MMI code request.
+ * MMI codes for GSM are discussed in 3GPP TS 22.030.<p>
+ *
+ * Example: If Phone.dial is called with "*#31#", then the app will
+ * be notified here.<p>
+ *
+ * The returned <code>Message.obj</code> will contain an AsyncResult.
+ *
+ * <code>obj.result</code> will be an "MmiCode" object.
+ */
+ public void registerForMmiInitiate(Handler h, int what, Object obj){
+ mMmiInitiateRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for new MMI initiate notification.
+ * Extraneous calls are tolerated silently
+ */
+ public void unregisterForMmiInitiate(Handler h){
+ mMmiInitiateRegistrants.remove(h);
+ }
+
+ /**
+ * Register for notifications that an MMI request has completed
+ * its network activity and is in its final state. This may mean a state
+ * of COMPLETE, FAILED, or CANCELLED.
+ *
+ * <code>Message.obj</code> will contain an AsyncResult.
+ * <code>obj.result</code> will be an "MmiCode" object
+ */
+ public void registerForMmiComplete(Handler h, int what, Object obj){
+ mMmiCompleteRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for MMI complete notification.
+ * Extraneous calls are tolerated silently
+ */
+ public void unregisterForMmiComplete(Handler h){
+ mMmiCompleteRegistrants.remove(h);
+ }
+
+ /**
+ * Registration point for Ecm timer reset
+ * @param h handler to notify
+ * @param what user-defined message code
+ * @param obj placed in Message.obj
+ */
+ public void registerForEcmTimerReset(Handler h, int what, Object obj){
+ mEcmTimerResetRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregister for notification for Ecm timer reset
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForEcmTimerReset(Handler h){
+ mEcmTimerResetRegistrants.remove(h);
+ }
+
+ /**
+ * Register for ServiceState changed.
+ * Message.obj will contain an AsyncResult.
+ * AsyncResult.result will be a ServiceState instance
+ */
+ public void registerForServiceStateChanged(Handler h, int what, Object obj){
+ mServiceStateChangedRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for ServiceStateChange notification.
+ * Extraneous calls are tolerated silently
+ */
+ public void unregisterForServiceStateChanged(Handler h){
+ mServiceStateChangedRegistrants.remove(h);
+ }
+
+ /**
+ * Register for notifications when a supplementary service attempt fails.
+ * Message.obj will contain an AsyncResult.
+ *
+ * @param h Handler that receives the notification message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+ public void registerForSuppServiceFailed(Handler h, int what, Object obj){
+ mSuppServiceFailedRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregister for notifications when a supplementary service attempt fails.
+ * Extraneous calls are tolerated silently
+ *
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForSuppServiceFailed(Handler h){
+ mSuppServiceFailedRegistrants.remove(h);
+ }
+
+ /**
+ * 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.
+ */
+ public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
+ mInCallVoicePrivacyOnRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregister for notifications when a sInCall VoicePrivacy is enabled
+ *
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForInCallVoicePrivacyOn(Handler h){
+ mInCallVoicePrivacyOnRegistrants.remove(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.
+ */
+ public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
+ mInCallVoicePrivacyOffRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregister for notifications when a sInCall VoicePrivacy is disabled
+ *
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForInCallVoicePrivacyOff(Handler h){
+ mInCallVoicePrivacyOffRegistrants.remove(h);
+ }
+
+ /**
+ * Register for notifications when CDMA call waiting comes
+ *
+ * @param h Handler that receives the notification message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+ public void registerForCallWaiting(Handler h, int what, Object obj){
+ mCallWaitingRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregister for notifications when CDMA Call waiting comes
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForCallWaiting(Handler h){
+ mCallWaitingRegistrants.remove(h);
+ }
+
+
+ /**
+ * Register for signal information notifications from the network.
+ * Message.obj will contain an AsyncResult.
+ * AsyncResult.result will be a SuppServiceNotification instance.
+ *
+ * @param h Handler that receives the notification message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+
+ public void registerForSignalInfo(Handler h, int what, Object obj){
+ mSignalInfoRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for signal information notifications.
+ * Extraneous calls are tolerated silently
+ *
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForSignalInfo(Handler h){
+ mSignalInfoRegistrants.remove(h);
+ }
+
+ /**
+ * Register for display information notifications from the network.
+ * Message.obj will contain an AsyncResult.
+ * AsyncResult.result will be a SuppServiceNotification instance.
+ *
+ * @param h Handler that receives the notification message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+ public void registerForDisplayInfo(Handler h, int what, Object obj){
+ mDisplayInfoRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregisters for display information notifications.
+ * Extraneous calls are tolerated silently
+ *
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForDisplayInfo(Handler h) {
+ mDisplayInfoRegistrants.remove(h);
+ }
+
+ /**
+ * Register for notifications when CDMA OTA Provision status change
+ *
+ * @param h Handler that receives the notification message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+ public void registerForCdmaOtaStatusChange(Handler h, int what, Object obj){
+ mCdmaOtaStatusChangeRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregister for notifications when CDMA OTA Provision status change
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForCdmaOtaStatusChange(Handler h){
+ mCdmaOtaStatusChangeRegistrants.remove(h);
+ }
+
+ /**
+ * Registration point for subscription info ready
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ public void registerForSubscriptionInfoReady(Handler h, int what, Object obj){
+ mSubscriptionInfoReadyRegistrants.addUnique(h, what, obj);
+ }
+
+ /**
+ * Unregister for notifications for subscription info
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForSubscriptionInfoReady(Handler h){
+ mSubscriptionInfoReadyRegistrants.remove(h);
+ }
+
+ /* APIs to access foregroudCalls, backgroudCalls, and ringingCalls
+ * 1. APIs to access list of calls
+ * 2. APIs to check if any active call, which has connection other than
+ * disconnected ones, pleaser refer to Call.isIdle()
+ * 3. APIs to return first active call
+ * 4. APIs to return the connections of first active call
+ * 5. APIs to return other property of first active call
+ */
+
+ /**
+ * @return list of all ringing calls
+ */
+ public ArrayList<Call> getRingingCalls() {
+ return mRingingCalls;
+ }
+
+ /**
+ * @return list of all foreground calls
+ */
+ public ArrayList<Call> getForegroundCalls() {
+ return mForegroundCalls;
+ }
+
+ /**
+ * @return list of all background calls
+ */
+ public ArrayList<Call> getBackgroundCalls() {
+ return mBackgroundCalls;
+ }
+
+ /**
+ * Return true if there is at least one active foreground call
+ */
+ public boolean hasActiveFgCall() {
+ return (getFirstActiveCall(mForegroundCalls) != null);
+ }
+
+ /**
+ * Return true if there is at least one active background call
+ */
+ public boolean hasActiveBgCall() {
+ // TODO since hasActiveBgCall may get called often
+ // better to cache it to improve performance
+ return (getFirstActiveCall(mBackgroundCalls) != null);
+ }
+
+ /**
+ * Return true if there is at least one active ringing call
+ *
+ */
+ public boolean hasActiveRingingCall() {
+ return (getFirstActiveCall(mRingingCalls) != null);
+ }
+
+ /**
+ * return the active foreground call from foreground calls
+ *
+ * Active call means the call is NOT in Call.State.IDLE
+ *
+ * 1. If there is active foreground call, return it
+ * 2. If there is no active foreground call, return the
+ * foreground call associated with default phone, which state is IDLE.
+ * 3. If there is no phone registered at all, return null.
+ *
+ */
+ public Call getActiveFgCall() {
+ for (Call call : mForegroundCalls) {
+ if (call.getState() != Call.State.IDLE) {
+ return call;
+ }
+ }
+ return (mDefaultPhone == null) ?
+ null : mDefaultPhone.getForegroundCall();
+ }
+
+ /**
+ * return one active background call from background calls
+ *
+ * Active call means the call is NOT idle defined by Call.isIdle()
+ *
+ * 1. If there is only one active background call, return it
+ * 2. If there is more than one active background call, return the first one
+ * 3. If there is no active background call, return the background call
+ * associated with default phone, which state is IDLE.
+ * 4. If there is no background call at all, return null.
+ *
+ * Complete background calls list can be get by getBackgroundCalls()
+ */
+ public Call getFirstActiveBgCall() {
+ for (Call call : mBackgroundCalls) {
+ if (!call.isIdle()) {
+ return call;
+ }
+ }
+ return (mDefaultPhone == null) ?
+ null : mDefaultPhone.getBackgroundCall();
+ }
+
+ /**
+ * return one active ringing call from ringing calls
+ *
+ * Active call means the call is NOT idle defined by Call.isIdle()
+ *
+ * 1. If there is only one active ringing call, return it
+ * 2. If there is more than one active ringing call, return the first one
+ * 3. If there is no active ringing call, return the ringing call
+ * associated with default phone, which state is IDLE.
+ * 4. If there is no ringing call at all, return null.
+ *
+ * Complete ringing calls list can be get by getRingingCalls()
+ */
+ public Call getFirstActiveRingingCall() {
+ for (Call call : mRingingCalls) {
+ if (!call.isIdle()) {
+ return call;
+ }
+ }
+ return (mDefaultPhone == null) ?
+ null : mDefaultPhone.getRingingCall();
+ }
+
+ /**
+ * @return the state of active foreground call
+ * return IDLE if there is no active foreground call
+ */
+ public Call.State getActiveFgCallState() {
+ Call fgCall = getActiveFgCall();
+
+ if (fgCall != null) {
+ return fgCall.getState();
+ }
+
+ return Call.State.IDLE;
+ }
+
+ /**
+ * @return the connections of active foreground call
+ * return null if there is no active foreground call
+ */
+ public List<Connection> getFgCallConnections() {
+ Call fgCall = getActiveFgCall();
+ if ( fgCall != null) {
+ return fgCall.getConnections();
+ }
+ return emptyConnections;
+ }
+
+ /**
+ * @return the connections of active background call
+ * return empty list if there is no active background call
+ */
+ public List<Connection> getBgCallConnections() {
+ Call bgCall = getActiveFgCall();
+ if ( bgCall != null) {
+ return bgCall.getConnections();
+ }
+ return emptyConnections;
+ }
+
+ /**
+ * @return the latest connection of active foreground call
+ * return null if there is no active foreground call
+ */
+ public Connection getFgCallLatestConnection() {
+ Call fgCall = getActiveFgCall();
+ if ( fgCall != null) {
+ return fgCall.getLatestConnection();
+ }
+ return null;
+ }
+
+ /**
+ * @return true if there is at least one Foreground call in disconnected state
+ */
+ public boolean hasDisconnectedFgCall() {
+ return (getFirstCallOfState(mForegroundCalls, Call.State.DISCONNECTED) != null);
+ }
+
+ /**
+ * @return true if there is at least one background call in disconnected state
+ */
+ public boolean hasDisconnectedBgCall() {
+ return (getFirstCallOfState(mBackgroundCalls, Call.State.DISCONNECTED) != null);
+ }
+
+ /**
+ * @return the first active call from a call list
+ */
+ private Call getFirstActiveCall(ArrayList<Call> calls) {
+ for (Call call : calls) {
+ if (!call.isIdle()) {
+ return call;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return the first call in a the Call.state from a call list
+ */
+ private Call getFirstCallOfState(ArrayList<Call> calls, Call.State state) {
+ for (Call call : calls) {
+ if (call.getState() == state) {
+ return call;
+ }
+ }
+ return null;
+ }
+
+
+
+
+ private Handler mHandler = new Handler() {
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_DISCONNECT:
+ mDisconnectRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_PRECISE_CALL_STATE_CHANGED:
+ mPreciseCallStateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_NEW_RINGING_CONNECTION:
+ mNewRingingConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_UNKNOWN_CONNECTION:
+ mUnknownConnectionRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_INCOMING_RING:
+ // The event may come from RIL who's not aware of an ongoing fg call
+ if (!hasActiveFgCall()) {
+ mIncomingRingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ }
+ break;
+ case EVENT_RINGBACK_TONE:
+ mRingbackToneRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_IN_CALL_VOICE_PRIVACY_ON:
+ mInCallVoicePrivacyOnRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_IN_CALL_VOICE_PRIVACY_OFF:
+ mInCallVoicePrivacyOffRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_CALL_WAITING:
+ mCallWaitingRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_DISPLAY_INFO:
+ mDisplayInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_SIGNAL_INFO:
+ mSignalInfoRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_CDMA_OTA_STATUS_CHANGE:
+ mCdmaOtaStatusChangeRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_RESEND_INCALL_MUTE:
+ mResendIncallMuteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_MMI_INITIATE:
+ mMmiInitiateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_MMI_COMPLETE:
+ mMmiCompleteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_ECM_TIMER_RESET:
+ mEcmTimerResetRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_SUBSCRIPTION_INFO_READY:
+ mSubscriptionInfoReadyRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_SUPP_SERVICE_FAILED:
+ mSuppServiceFailedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ break;
+ case EVENT_SERVICE_STATE_CHANGED:
+ mServiceStateChangedRegistrants.notifyRegistrants((AsyncResult) msg.obj);
+ }
+ }
+ };
+}
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 802e79b2cadd..798a5a56b847 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -284,7 +284,7 @@ public class CallerInfoAsyncQuery {
*/
public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
OnQueryCompleteListener listener, Object cookie) {
- //contruct the URI object and start Query.
+ //construct the URI object and start Query.
Uri contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
diff --git a/telephony/java/com/android/internal/telephony/CommandException.java b/telephony/java/com/android/internal/telephony/CommandException.java
index eb0a440dff25..94c544ecffd5 100644
--- a/telephony/java/com/android/internal/telephony/CommandException.java
+++ b/telephony/java/com/android/internal/telephony/CommandException.java
@@ -37,6 +37,10 @@ public class CommandException extends RuntimeException {
OP_NOT_ALLOWED_DURING_VOICE_CALL,
OP_NOT_ALLOWED_BEFORE_REG_NW,
SMS_FAIL_RETRY,
+ SIM_ABSENT,
+ SUBSCRIPTION_NOT_AVAILABLE,
+ MODE_NOT_SUPPORTED,
+ FDN_CHECK_FAILURE,
ILLEGAL_SIM_OR_ME,
}
@@ -69,6 +73,14 @@ public class CommandException extends RuntimeException {
return new CommandException(Error.OP_NOT_ALLOWED_BEFORE_REG_NW);
case RILConstants.SMS_SEND_FAIL_RETRY:
return new CommandException(Error.SMS_FAIL_RETRY);
+ case RILConstants.SIM_ABSENT:
+ return new CommandException(Error.SIM_ABSENT);
+ case RILConstants.SUBSCRIPTION_NOT_AVAILABLE:
+ return new CommandException(Error.SUBSCRIPTION_NOT_AVAILABLE);
+ case RILConstants.MODE_NOT_SUPPORTED:
+ return new CommandException(Error.MODE_NOT_SUPPORTED);
+ case RILConstants.FDN_CHECK_FAILURE:
+ return new CommandException(Error.FDN_CHECK_FAILURE);
case RILConstants.ILLEGAL_SIM_OR_ME:
return new CommandException(Error.ILLEGAL_SIM_OR_ME);
default:
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index d90c3056bf76..8e03c5a5bd5e 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -664,6 +664,19 @@ public interface CommandsInterface {
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the orignal value of result.obj
+ * ar.result is null on success and failure
+ *
+ * CLIR_DEFAULT == on "use subscription default value"
+ * CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation)
+ * CLIR_INVOCATION == on "CLIR invocation" (restrict CLI presentation)
+ */
+ void dial(String address, int clirMode, UUSInfo uusInfo, 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 is String containing IMSI on success
*/
void getIMSI(Message result);
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index 37e8a99e6799..c20c2006fe90 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -39,23 +39,26 @@ public abstract class Connection {
CONGESTION, /* outgoing call to congested network */
MMI, /* not presently used; dial() returns null */
INVALID_NUMBER, /* invalid dial string */
+ INVALID_CREDENTIALS, /* invalid credentials */
+ TIMED_OUT, /* client timed out */
LOST_SIGNAL,
LIMIT_EXCEEDED, /* eg GSM ACM limit exceeded */
INCOMING_REJECTED, /* an incoming call that was rejected */
POWER_OFF, /* radio is turned off explicitly */
OUT_OF_SERVICE, /* out of service */
ICC_ERROR, /* No ICC, ICC locked, or other ICC error */
- CALL_BARRED, /* call was blocked by call barrring */
+ CALL_BARRED, /* call was blocked by call barring */
FDN_BLOCKED, /* call was blocked by fixed dial number */
CS_RESTRICTED, /* call was blocked by restricted all voice access */
CS_RESTRICTED_NORMAL, /* call was blocked by restricted normal voice access */
CS_RESTRICTED_EMERGENCY, /* call was blocked by restricted emergency voice access */
+ UNOBTAINABLE_NUMBER, /* Unassigned number (3GPP TS 24.008 table 10.5.123) */
CDMA_LOCKED_UNTIL_POWER_CYCLE, /* MS is locked until next power cycle */
CDMA_DROP,
CDMA_INTERCEPT, /* INTERCEPT order received, MS state idle entered */
CDMA_REORDER, /* MS has been redirected, call is cancelled */
CDMA_SO_REJECT, /* service option rejection */
- CDMA_RETRY_ORDER, /* requeseted service is rejected, retry delay is set */
+ CDMA_RETRY_ORDER, /* requested service is rejected, retry delay is set */
CDMA_ACCESS_FAILURE,
CDMA_PREEMPTED,
CDMA_NOT_EMERGENCY, /* not an emergency call */
@@ -68,8 +71,8 @@ public abstract class Connection {
/* Instance Methods */
/**
- * Gets address (e.g., phone number) associated with connection
- * TODO: distinguish reasons for unavailablity
+ * Gets address (e.g. phone number) associated with connection.
+ * TODO: distinguish reasons for unavailability
*
* @return address or null if unavailable
*/
@@ -77,7 +80,7 @@ public abstract class Connection {
public abstract String getAddress();
/**
- * Gets cdma CNAP name associated with connection
+ * Gets CDMA CNAP name associated with connection.
* @return cnap name or null if unavailable
*/
public String getCnapName() {
@@ -85,15 +88,15 @@ public abstract class Connection {
}
/**
- * Get orignal dial string
- * @return orignal dial string or null if unavailable
+ * Get original dial string.
+ * @return original dial string or null if unavailable
*/
public String getOrigDialString(){
return null;
}
/**
- * Gets cdma CNAP presentation associated with connection
+ * Gets CDMA CNAP presentation associated with connection.
* @return cnap name or null if unavailable
*/
@@ -115,45 +118,45 @@ public abstract class Connection {
public abstract long getCreateTime();
/**
- * Connection connect time in currentTimeMillis() format
- * For outgoing calls: Begins at (DIALING|ALERTING) -> ACTIVE transition
- * For incoming calls: Begins at (INCOMING|WAITING) -> ACTIVE transition
- * Returns 0 before then
+ * Connection connect time in currentTimeMillis() format.
+ * For outgoing calls: Begins at (DIALING|ALERTING) -> ACTIVE transition.
+ * For incoming calls: Begins at (INCOMING|WAITING) -> ACTIVE transition.
+ * Returns 0 before then.
*/
public abstract long getConnectTime();
/**
- * Disconnect time in currentTimeMillis() format
- * The time when this Connection makes a transition into ENDED or FAIL
- * Returns 0 before then
+ * Disconnect time in currentTimeMillis() format.
+ * The time when this Connection makes a transition into ENDED or FAIL.
+ * Returns 0 before then.
*/
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
+ * time since connect.
*/
public abstract long getDurationMillis();
/**
* If this connection is HOLDING, return the number of milliseconds
- * that it has been on hold for (approximently)
- * If this connection is in any other state, return 0
+ * that it has been on hold for (approximately).
+ * If this connection is in any other state, return 0.
*/
public abstract long getHoldDurationMillis();
/**
- * Returns "NOT_DISCONNECTED" if not yet disconnected
+ * Returns "NOT_DISCONNECTED" if not yet disconnected.
*/
public abstract DisconnectCause getDisconnectCause();
/**
* 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)
+ * or false if this call originated here (MO or mobile originated).
*/
public abstract boolean isIncoming();
@@ -273,6 +276,13 @@ public abstract class Connection {
public abstract int getNumberPresentation();
/**
+ * Returns the User to User Signaling (UUS) information associated with
+ * incoming and waiting calls
+ * @return UUSInfo containing the UUS userdata.
+ */
+ public abstract UUSInfo getUUSInfo();
+
+ /**
* Build a human representation of a connection instance, suitable for debugging.
* Don't log personal stuff unless in debug mode.
* @return a string representing the internal state of this connection.
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 1f8bbcfbe424..6634017c84a5 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -164,7 +164,7 @@ public abstract class DataConnection extends HierarchicalStateMachine {
NONE,
OPERATOR_BARRED,
INSUFFICIENT_RESOURCES,
- MISSING_UKNOWN_APN,
+ MISSING_UNKNOWN_APN,
UNKNOWN_PDP_ADDRESS,
USER_AUTHENTICATION,
ACTIVATION_REJECT_GGSN,
@@ -181,7 +181,7 @@ public abstract class DataConnection extends HierarchicalStateMachine {
RADIO_NOT_AVAILABLE;
public boolean isPermanentFail() {
- return (this == OPERATOR_BARRED) || (this == MISSING_UKNOWN_APN) ||
+ return (this == OPERATOR_BARRED) || (this == MISSING_UNKNOWN_APN) ||
(this == UNKNOWN_PDP_ADDRESS) || (this == USER_AUTHENTICATION) ||
(this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) ||
(this == SERVICE_OPTION_NOT_SUPPORTED) ||
@@ -208,12 +208,12 @@ public abstract class DataConnection extends HierarchicalStateMachine {
return "Operator Barred";
case INSUFFICIENT_RESOURCES:
return "Insufficient Resources";
- case MISSING_UKNOWN_APN:
+ case MISSING_UNKNOWN_APN:
return "Missing / Unknown APN";
case UNKNOWN_PDP_ADDRESS:
return "Unknown PDP Address";
case USER_AUTHENTICATION:
- return "Error User Autentication";
+ return "Error User Authentication";
case ACTIVATION_REJECT_GGSN:
return "Activation Reject GGSN";
case ACTIVATION_REJECT_UNSPECIFIED:
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 4da4b6abe73d..057ba0a7ca15 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -102,7 +102,8 @@ public class DefaultPhoneNotifier implements PhoneNotifier {
sender.getActiveApnTypes(),
sender.getInterfaceName(null),
((telephony!=null) ? telephony.getNetworkType() :
- TelephonyManager.NETWORK_TYPE_UNKNOWN));
+ TelephonyManager.NETWORK_TYPE_UNKNOWN),
+ sender.getGateway(null));
} catch (RemoteException ex) {
// system process is dead
}
diff --git a/telephony/java/com/android/internal/telephony/DriverCall.java b/telephony/java/com/android/internal/telephony/DriverCall.java
index 66f6b9cbff95..663c2842a793 100644
--- a/telephony/java/com/android/internal/telephony/DriverCall.java
+++ b/telephony/java/com/android/internal/telephony/DriverCall.java
@@ -49,6 +49,7 @@ public class DriverCall implements Comparable {
public int numberPresentation;
public String name;
public int namePresentation;
+ public UUSInfo uusInfo;
/** returns null on error */
static DriverCall
diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
index ebdd2207db6f..7edf065ee2ce 100644
--- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java
+++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java
@@ -23,7 +23,7 @@ import android.util.Log;
/**
* This class implements the character set mapping between
- * the GSM SMS 7-bit alphabet specifed in TS 23.038 6.2.1
+ * the GSM SMS 7-bit alphabet specified in TS 23.038 6.2.1
* and UTF-16
*
* {@hide}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 5bf8e5826593..87e4b5287c3d 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -32,7 +32,8 @@ interface ITelephonyRegistry {
void notifyCallForwardingChanged(boolean cfi);
void notifyDataActivity(int state);
void notifyDataConnection(int state, boolean isDataConnectivityPossible,
- String reason, String apn, in String[] apnTypes, String interfaceName, int networkType);
+ String reason, String apn, in String[] apnTypes, String interfaceName, int networkType,
+ String gateway);
void notifyDataConnectionFailed(String reason);
void notifyCellLocation(in Bundle cellLocation);
}
diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java
index fa914570c341..3471ec2885af 100644
--- a/telephony/java/com/android/internal/telephony/IccProvider.java
+++ b/telephony/java/com/android/internal/telephony/IccProvider.java
@@ -417,11 +417,11 @@ public class IccProvider extends ContentProvider {
}
}
- if (TextUtils.isEmpty(tag)) {
+ if (TextUtils.isEmpty(number)) {
return 0;
}
- if (efType == FDN && TextUtils.isEmpty(pin2)) {
+ if (efType == IccConstants.EF_FDN && TextUtils.isEmpty(pin2)) {
return 0;
}
diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 8a5a6aee7487..5fef6de70a25 100644
--- a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -57,7 +57,7 @@ public abstract class IccSmsInterfaceManager extends ISms.Stub {
* @param destPort 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.
+ * 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:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
@@ -67,7 +67,7 @@ public abstract class IccSmsInterfaceManager extends ISms.Stub {
* the extra "errorCode" containing a radio technology specific value,
* generally only useful for troubleshooting.<br>
* 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
@@ -94,7 +94,7 @@ public abstract class IccSmsInterfaceManager extends ISms.Stub {
* 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.
+ * 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:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
@@ -140,7 +140,7 @@ public abstract class IccSmsInterfaceManager extends ISms.Stub {
* <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 deliveryIntents if not null, an <code>ArrayList</code> of
* <code>PendingIntent</code>s (one for each message part) that is
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 7179bef9f165..9afade33b006 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -103,6 +103,7 @@ public interface Phone {
static final String DATA_APN_KEY = "apn";
static final String DATA_IFACE_NAME_KEY = "iface";
+ static final String DATA_GATEWAY_KEY = "gateway";
static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable";
static final String PHONE_IN_ECM_STATE = "phoneinECMState";
@@ -177,6 +178,7 @@ public interface Phone {
static final int PHONE_TYPE_NONE = RILConstants.NO_PHONE;
static final int PHONE_TYPE_GSM = RILConstants.GSM_PHONE;
static final int PHONE_TYPE_CDMA = RILConstants.CDMA_PHONE;
+ static final int PHONE_TYPE_SIP = RILConstants.SIP_PHONE;
// Used for preferred network type
// Note NT_* substitute RILConstants.NETWORK_MODE_* above the Phone
@@ -243,15 +245,14 @@ public interface Phone {
/**
* Get the current DataState. No change notification exists at this
* interface -- use
- * {@link com.android.telephony.PhoneStateListener PhoneStateListener}
- * instead.
+ * {@link android.telephony.PhoneStateListener} instead.
*/
DataState getDataConnectionState();
/**
* Get the current DataActivityState. No change notification exists at this
* interface -- use
- * {@link TelephonyManager} instead.
+ * {@link android.telephony.TelephonyManager} instead.
*/
DataActivityState getDataActivityState();
@@ -789,6 +790,19 @@ public interface Phone {
Connection dial(String dialString) throws CallStateException;
/**
+ * Initiate a new voice connection with supplementary User to User
+ * Information. 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 handled asynchronously.
+ */
+ Connection dial(String dialString, UUSInfo uusInfo) throws CallStateException;
+
+ /**
* Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
* without SEND (so <code>dial</code> is not appropriate).
*
@@ -840,7 +854,7 @@ public interface Phone {
* @param dtmfString is string representing the dialing digit(s) in the active call
* @param on the DTMF ON length in milliseconds, or 0 for default
* @param off the DTMF OFF length in milliseconds, or 0 for default
- * @param onCompelte is the callback message when the action is processed by BP
+ * @param onComplete is the callback message when the action is processed by BP
*
*/
void sendBurstDtmf(String dtmfString, int on, int off, Message onComplete);
@@ -980,7 +994,7 @@ public interface Phone {
* ((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.CommandsInterface.getCLIR for details.
+ * @see com.android.internal.telephony.CommandsInterface#getCLIR for details.
*/
void getOutgoingCallerIdDisplay(Message onComplete);
@@ -1002,7 +1016,7 @@ public interface Phone {
* ((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.CommandsInterface.queryCallWaiting for details.
+ * @see com.android.internal.telephony.CommandsInterface#queryCallWaiting for details.
*/
void getCallWaiting(Message onComplete);
@@ -1445,7 +1459,7 @@ public interface Phone {
* setTTYMode
* sets a TTY mode option.
*
- * @param enable is a boolean representing the state that you are
+ * @param ttyMode 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
*/
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index a8f41430488e..ff28773df5c2 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -286,7 +286,7 @@ public abstract class PhoneBase extends Handler implements Phone {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b);
- editor.commit();
+ editor.apply();
}
/**
@@ -543,7 +543,7 @@ public abstract class PhoneBase extends Handler implements Phone {
private void setPropertiesByCarrier() {
String carrier = SystemProperties.get("ro.carrier");
- if (null == carrier || 0 == carrier.length()) {
+ if (null == carrier || 0 == carrier.length() || "unknown".equals(carrier)) {
return;
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java
index cd72752e4328..2e391cb96cb2 100644
--- a/telephony/java/com/android/internal/telephony/PhoneFactory.java
+++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java
@@ -24,6 +24,8 @@ import android.util.Log;
import com.android.internal.telephony.cdma.CDMAPhone;
import com.android.internal.telephony.gsm.GSMPhone;
+import com.android.internal.telephony.sip.SipPhone;
+import com.android.internal.telephony.sip.SipPhoneFactory;
/**
* {@hide}
@@ -109,13 +111,13 @@ public class PhoneFactory {
int phoneType = getPhoneType(networkMode);
if (phoneType == Phone.PHONE_TYPE_GSM) {
+ Log.i(LOG_TAG, "Creating GSMPhone");
sProxyPhone = new PhoneProxy(new GSMPhone(context,
sCommandsInterface, sPhoneNotifier));
- Log.i(LOG_TAG, "Creating GSMPhone");
} else if (phoneType == Phone.PHONE_TYPE_CDMA) {
+ Log.i(LOG_TAG, "Creating CDMAPhone");
sProxyPhone = new PhoneProxy(new CDMAPhone(context,
sCommandsInterface, sPhoneNotifier));
- Log.i(LOG_TAG, "Creating CDMAPhone");
}
sMadeDefaults = true;
@@ -175,4 +177,13 @@ public class PhoneFactory {
return phone;
}
}
+
+ /**
+ * Makes a {@link SipPhone} object.
+ * @param sipUri the local SIP URI the phone runs on
+ * @return the {@code SipPhone} object or null if the SIP URI is not valid
+ */
+ public static SipPhone makeSipPhone(String sipUri) {
+ return SipPhoneFactory.makePhone(sipUri, sContext, sPhoneNotifier);
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 6d3798ed1459..e1511e6ed79f 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -423,6 +423,10 @@ public class PhoneProxy extends Handler implements Phone {
return mActivePhone.dial(dialString);
}
+ public Connection dial(String dialString, UUSInfo uusInfo) throws CallStateException {
+ return mActivePhone.dial(dialString, uusInfo);
+ }
+
public boolean handlePinMmi(String dialString) {
return mActivePhone.handlePinMmi(dialString);
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
index 0b557368b48e..a45cad1114de 100644
--- a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
@@ -69,7 +69,7 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub {
}
/**
- * Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones.
+ * Retrieves the unique subscriber ID, e.g., IMSI for GSM phones.
*/
public String getSubscriberId() {
mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
@@ -111,7 +111,7 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub {
}
/**
- * Retrieves the compelete voice mail number.
+ * Retrieves the complete voice mail number.
*
* @hide
*/
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
index a0360462f2bf..700989397ae9 100644
--- a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
@@ -47,7 +47,7 @@ public class PhoneSubInfoProxy extends IPhoneSubInfo.Stub {
}
/**
- * Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones.
+ * Retrieves the unique subscriber ID, e.g., IMSI for GSM phones.
*/
public String getSubscriberId() {
return mPhoneSubInfo.getSubscriberId();
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index d8e313a79908..3d410fd2c465 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -796,12 +796,26 @@ public final class RIL extends BaseCommands implements CommandsInterface {
public void
dial (String address, int clirMode, Message result) {
+ dial(address, clirMode, null, result);
+ }
+
+ public void
+ dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
rr.mp.writeString(address);
rr.mp.writeInt(clirMode);
rr.mp.writeInt(0); // UUS information is absent
+ if (uusInfo == null) {
+ rr.mp.writeInt(0); // UUS information is absent
+ } else {
+ rr.mp.writeInt(1); // UUS information is present
+ rr.mp.writeInt(uusInfo.getType());
+ rr.mp.writeInt(uusInfo.getDcs());
+ rr.mp.writeByteArray(uusInfo.getUserData());
+ }
+
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
@@ -2837,10 +2851,21 @@ public final class RIL extends BaseCommands implements CommandsInterface {
dc.namePresentation = p.readInt();
int uusInfoPresent = p.readInt();
if (uusInfoPresent == 1) {
- // TODO: Copy the data to dc to forward to the apps.
- p.readInt();
- p.readInt();
- p.createByteArray();
+ dc.uusInfo = new UUSInfo();
+ dc.uusInfo.setType(p.readInt());
+ dc.uusInfo.setDcs(p.readInt());
+ byte[] userData = p.createByteArray();
+ dc.uusInfo.setUserData(userData);
+ Log
+ .v(LOG_TAG, String.format("Incoming UUS : type=%d, dcs=%d, length=%d",
+ dc.uusInfo.getType(), dc.uusInfo.getDcs(),
+ dc.uusInfo.getUserData().length));
+ Log.v(LOG_TAG, "Incoming UUS : data (string)="
+ + new String(dc.uusInfo.getUserData()));
+ Log.v(LOG_TAG, "Incoming UUS : data (hex): "
+ + IccUtils.bytesToHexString(dc.uusInfo.getUserData()));
+ } else {
+ Log.v(LOG_TAG, "Incoming UUS : NOT present!");
}
// Make sure there's a leading + on addresses with a TOA of 145
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 01f4ab274c13..888f72183758 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -45,6 +45,11 @@ public interface RILConstants {
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 SIM_ABSENT = 11; /* ICC card is absent */
+ int SUBSCRIPTION_NOT_AVAILABLE = 12; /* fail to find CDMA subscription from specified
+ location */
+ int MODE_NOT_SUPPORTED = 13; /* HW does not support preferred network type */
+ int FDN_CHECK_FAILURE = 14; /* send operation barred error when FDN is enabled */
int ILLEGAL_SIM_OR_ME = 15; /* network selection failure due
to wrong SIM/ME and no
retries needed */
@@ -74,6 +79,7 @@ public interface RILConstants {
int NO_PHONE = 0;
int GSM_PHONE = 1;
int CDMA_PHONE = 2;
+ int SIP_PHONE = 3;
int CDM_TTY_MODE_DISABLED = 0;
int CDM_TTY_MODE_ENABLED = 1;
diff --git a/telephony/java/com/android/internal/telephony/RetryManager.java b/telephony/java/com/android/internal/telephony/RetryManager.java
index 779f358307ac..b1049a2892b1 100644
--- a/telephony/java/com/android/internal/telephony/RetryManager.java
+++ b/telephony/java/com/android/internal/telephony/RetryManager.java
@@ -25,7 +25,7 @@ import java.util.ArrayList;
/**
* Retry manager allows a simple way to declare a series of
- * retires timeouts. After creating a RetryManager the configure
+ * retry timeouts. After creating a RetryManager the configure
* method is used to define the sequence. A simple linear series
* may be initialized using configure with three integer parameters
* The other configure method allows a series to be declared using
@@ -54,18 +54,18 @@ import java.util.ArrayList;
*<p>
* Examples:
* <ul>
- * <li>3 retires with no randomization value which means its 0:
+ * <li>3 retries with no randomization value which means its 0:
* <ul><li><code>"1000, 2000, 3000"</code></ul>
*
- * <li>10 retires with a 500 default randomization value for each and
+ * <li>10 retries with a 500 default randomization value for each and
* the 4..10 retries all using 3000 as the delay:
* <ul><li><code>"max_retries=10, default_randomization=500, 1000, 2000, 3000"</code></ul>
*
- * <li>4 retires with a 100 as the default randomization value for the first 2 values and
+ * <li>4 retries with a 100 as the default randomization value for the first 2 values and
* the other two having specified values of 500:
* <ul><li><code>"default_randomization=100, 1000, 2000, 4000:500, 5000:500"</code></ul>
*
- * <li>Infinite number of retires with the first one at 1000, the second at 2000 all
+ * <li>Infinite number of retries with the first one at 1000, the second at 2000 all
* others will be at 3000.
* <ul><li><code>"max_retries=infinite,1000,2000,3000</code></ul>
* </ul>
@@ -75,9 +75,6 @@ import java.util.ArrayList;
public class RetryManager {
static public final String LOG_TAG = "RetryManager";
static public final boolean DBG = false;
- static public final int RETRYIES_NOT_STARTED = 0;
- static public final int RETRYIES_ON_GOING = 1;
- static public final int RETRYIES_COMPLETED = 2;
/**
* Retry record with times in milli-seconds
@@ -104,7 +101,7 @@ public class RetryManager {
*/
private int mMaxRetryCount;
- /** The current number of retires */
+ /** The current number of retries */
private int mRetryCount;
/** Random number generator */
@@ -125,7 +122,7 @@ public class RetryManager {
* @param randomizationTime a random value between 0 and
* randomizationTime will be added to retryTime. this
* parameter may be 0.
- * @return true if successfull
+ * @return true if successful
*/
public boolean configure(int maxRetryCount, int retryTime, int randomizationTime) {
Pair<Boolean, Integer> value;
@@ -242,7 +239,7 @@ public class RetryManager {
/**
* Report whether data reconnection should be retried
*
- * @return {@code true} if the max retires has not been reached. {@code
+ * @return {@code true} if the max retries has not been reached. {@code
* false} otherwise.
*/
public boolean isRetryNeeded() {
@@ -289,7 +286,7 @@ public class RetryManager {
if (mRetryCount > mMaxRetryCount) {
mRetryCount = mMaxRetryCount;
}
- if (DBG) log("increseRetryCount: " + mRetryCount);
+ if (DBG) log("increaseRetryCount: " + mRetryCount);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index 764d12ebe067..917e1d823a8a 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -32,9 +32,11 @@ import android.database.Cursor;
import android.database.SQLException;
import android.net.Uri;
import android.os.AsyncResult;
+import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
+import android.os.StatFs;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
import android.provider.Settings;
@@ -44,10 +46,6 @@ import android.util.Config;
import android.util.Log;
import android.view.WindowManager;
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.SmsResponse;
-import com.android.internal.telephony.WapPushOverSms;
import com.android.internal.util.HexDump;
import java.io.ByteArrayOutputStream;
@@ -62,6 +60,7 @@ 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;
import static android.telephony.SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
+import static android.telephony.SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
public abstract class SMSDispatcher extends Handler {
@@ -74,7 +73,7 @@ public abstract class SMSDispatcher extends Handler {
private static final int DEFAULT_SMS_MAX_COUNT = 100;
/** Default timeout for SMS sent query */
- private static final int DEFAULT_SMS_TIMOUEOUT = 6000;
+ private static final int DEFAULT_SMS_TIMEOUT = 6000;
protected static final String[] RAW_PROJECTION = new String[] {
"pdu",
@@ -82,8 +81,6 @@ public abstract class SMSDispatcher extends Handler {
"destination_port",
};
- static final int MAIL_SEND_SMS = 1;
-
static final protected int EVENT_NEW_SMS = 1;
static final protected int EVENT_SEND_SMS_COMPLETE = 2;
@@ -142,7 +139,7 @@ public abstract class SMSDispatcher extends Handler {
private SmsCounter mCounter;
- private ArrayList mSTrackers = new ArrayList(MO_MSG_QUEUE_LIMIT);
+ private ArrayList<SmsTracker> mSTrackers = new ArrayList<SmsTracker>(MO_MSG_QUEUE_LIMIT);
/** Wake lock to ensure device stays awake while dispatching the SMS intent. */
private PowerManager.WakeLock mWakeLock;
@@ -153,10 +150,6 @@ public abstract class SMSDispatcher extends Handler {
*/
private final int WAKE_LOCK_TIMEOUT = 5000;
- private static SmsMessage mSmsMessage;
- private static SmsMessageBase mSmsMessageBase;
- private SmsMessageBase.SubmitPduBase mSubmitPduBase;
-
protected boolean mStorageAvailable = true;
protected boolean mReportMemoryStatusPending = false;
@@ -249,11 +242,9 @@ public abstract class SMSDispatcher extends Handler {
// Register for device storage intents. Use these to notify the RIL
// that storage for SMS is or is not available.
- // TODO: Revisit this for a later release. Storage reporting should
- // rely more on application indication.
IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
- filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
+ filter.addAction(Intent.ACTION_DEVICE_STORAGE_FULL);
+ filter.addAction(Intent.ACTION_DEVICE_STORAGE_NOT_FULL);
mContext.registerReceiver(mResultReceiver, filter);
}
@@ -344,7 +335,7 @@ public abstract class SMSDispatcher extends Handler {
msg.obj = null;
if (mSTrackers.isEmpty() == false) {
try {
- SmsTracker sTracker = (SmsTracker)mSTrackers.remove(0);
+ SmsTracker sTracker = mSTrackers.remove(0);
sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
} catch (CanceledException ex) {
Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
@@ -357,7 +348,7 @@ public abstract class SMSDispatcher extends Handler {
case EVENT_SEND_CONFIRMED_SMS:
if (mSTrackers.isEmpty() == false) {
- SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1);
+ SmsTracker sTracker = mSTrackers.remove(mSTrackers.size() - 1);
if (isMultipartTracker(sTracker)) {
sendMultipartSms(sTracker);
} else {
@@ -371,7 +362,7 @@ public abstract class SMSDispatcher extends Handler {
if (mSTrackers.isEmpty() == false) {
// Remove the latest one.
try {
- SmsTracker sTracker = (SmsTracker)mSTrackers.remove(mSTrackers.size() - 1);
+ SmsTracker sTracker = mSTrackers.remove(mSTrackers.size() - 1);
sTracker.mSentIntent.send(RESULT_ERROR_LIMIT_EXCEEDED);
} catch (CanceledException ex) {
Log.e(TAG, "failed to send back RESULT_ERROR_LIMIT_EXCEEDED");
@@ -499,13 +490,20 @@ public abstract class SMSDispatcher extends Handler {
Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
} else if (tracker.mSentIntent != null) {
+ int error = RESULT_ERROR_GENERIC_FAILURE;
+
+ if (((CommandException)(ar.exception)).getCommandError()
+ == CommandException.Error.FDN_CHECK_FAILURE) {
+ error = RESULT_ERROR_FDN_CHECK_FAILURE;
+ }
// Done retrying; return an error to the app.
try {
Intent fillIn = new Intent();
if (ar.result != null) {
fillIn.putExtra("errorCode", ((SmsResponse)ar.result).errorCode);
}
- tracker.mSentIntent.send(mContext, RESULT_ERROR_GENERIC_FAILURE, fillIn);
+ tracker.mSentIntent.send(mContext, error, fillIn);
+
} catch (CanceledException ex) {}
}
}
@@ -671,7 +669,7 @@ public abstract class SMSDispatcher extends Handler {
* @param destPort 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.
+ * 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:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
@@ -681,7 +679,7 @@ public abstract class SMSDispatcher extends Handler {
* the extra "errorCode" containing a radio technology specific value,
* generally only useful for troubleshooting.<br>
* 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
@@ -698,7 +696,7 @@ public abstract class SMSDispatcher extends Handler {
* 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.
+ * 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:<br>
* <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
@@ -734,7 +732,7 @@ public abstract class SMSDispatcher extends Handler {
* <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 deliveryIntents if not null, an <code>ArrayList</code> of
* <code>PendingIntent</code>s (one for each message part) that is
@@ -750,17 +748,17 @@ public abstract class SMSDispatcher extends Handler {
* 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>
* <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>Intent</code> is
* broadcast when the message is delivered to the recipient. The
@@ -829,7 +827,7 @@ public abstract class SMSDispatcher extends Handler {
mSTrackers.add(tracker);
sendMessageDelayed ( obtainMessage(EVENT_ALERT_TIMEOUT, d),
- DEFAULT_SMS_TIMOUEOUT);
+ DEFAULT_SMS_TIMEOUT);
}
protected String getAppNameByIntent(PendingIntent intent) {
@@ -923,7 +921,7 @@ public abstract class SMSDispatcher extends Handler {
}
/**
- * Keeps track of an SMS that has been sent to the RIL, until it it has
+ * Keeps track of an SMS that has been sent to the RIL, until it has
* successfully been sent, or we're done trying.
*
*/
@@ -964,27 +962,26 @@ public abstract class SMSDispatcher extends Handler {
}
};
- private BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_LOW)) {
- mStorageAvailable = false;
- mCm.reportSmsMemoryStatus(false, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
- } else if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_OK)) {
- mStorageAvailable = true;
- mCm.reportSmsMemoryStatus(true, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
- } else {
- // Assume the intent is one of the SMS receive intents that
- // was sent as an ordered broadcast. Check result and ACK.
- int rc = getResultCode();
- boolean success = (rc == Activity.RESULT_OK)
- || (rc == Intents.RESULT_SMS_HANDLED);
-
- // For a multi-part message, this only ACKs the last part.
- // Previous parts were ACK'd as they were received.
- acknowledgeLastIncomingSms(success, rc, null);
- }
+ private BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_FULL)) {
+ mStorageAvailable = false;
+ mCm.reportSmsMemoryStatus(false, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
+ } else if (intent.getAction().equals(Intent.ACTION_DEVICE_STORAGE_NOT_FULL)) {
+ mStorageAvailable = true;
+ mCm.reportSmsMemoryStatus(true, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
+ } else {
+ // Assume the intent is one of the SMS receive intents that
+ // was sent as an ordered broadcast. Check result and ACK.
+ int rc = getResultCode();
+ boolean success = (rc == Activity.RESULT_OK)
+ || (rc == Intents.RESULT_SMS_HANDLED);
+
+ // For a multi-part message, this only ACKs the last part.
+ // Previous parts were ACK'd as they were received.
+ acknowledgeLastIncomingSms(success, rc, null);
}
-
- };
+ }
+ };
}
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index 73836497dc4e..e8bbe5e9ecac 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -44,6 +44,7 @@ public abstract class ServiceStateTracker extends Handler {
protected static final int DATA_ACCESS_HSDPA = 9;
protected static final int DATA_ACCESS_HSUPA = 10;
protected static final int DATA_ACCESS_HSPA = 11;
+ protected static final int DATA_ACCESS_CDMA_EvDo_B = 12;
protected CommandsInterface cm;
@@ -206,8 +207,8 @@ public abstract class ServiceStateTracker extends Handler {
}
/**
- * Reregister network through toggle perferred network type
- * This is a work aorund to deregister and register network since there is
+ * Re-register network by toggling preferred network type.
+ * This is a work-around to deregister and register network since there is
* no ril api to set COPS=2 (deregister) only.
*
* @param onComplete is dispatched when this is complete. it will be
@@ -229,7 +230,7 @@ public abstract class ServiceStateTracker extends Handler {
/**
* These two flags manage the behavior of the cell lock -- the
* lock should be held if either flag is true. The intention is
- * to allow temporary aquisition of the lock to get a single
+ * to allow temporary acquisition of the lock to get a single
* update. Such a lock grab and release can thus be made to not
* interfere with more permanent lock holds -- in other words, the
* lock will only be released if both flags are false, and so
diff --git a/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java b/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java
new file mode 100644
index 000000000000..4092c6970f9b
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SipPhoneNotifier.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2010 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.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+
+import com.android.internal.telephony.ITelephonyRegistry;
+
+/**
+ * Temporary. Will be removed after integrating with CallManager.
+ * 100% copy from DefaultPhoneNotifier. Cannot access its package level
+ * constructor; thus the copy.
+ * @hide
+ */
+public class SipPhoneNotifier implements PhoneNotifier {
+
+ static final String LOG_TAG = "GSM";
+ private static final boolean DBG = true;
+ private ITelephonyRegistry mRegistry;
+
+ public SipPhoneNotifier() {
+ mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
+ "telephony.registry"));
+ }
+
+ public void notifyPhoneState(Phone sender) {
+ Call ringingCall = sender.getRingingCall();
+ String incomingNumber = "";
+ if (ringingCall != null && ringingCall.getEarliestConnection() != null){
+ incomingNumber = ringingCall.getEarliestConnection().getAddress();
+ }
+ try {
+ mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ public void notifyServiceState(Phone sender) {
+ try {
+ mRegistry.notifyServiceState(sender.getServiceState());
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ public void notifySignalStrength(Phone sender) {
+ try {
+ mRegistry.notifySignalStrength(sender.getSignalStrength());
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ public void notifyMessageWaitingChanged(Phone sender) {
+ try {
+ mRegistry.notifyMessageWaitingChanged(sender.getMessageWaitingIndicator());
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ public void notifyCallForwardingChanged(Phone sender) {
+ try {
+ mRegistry.notifyCallForwardingChanged(sender.getCallForwardingIndicator());
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ public void notifyDataActivity(Phone sender) {
+ try {
+ mRegistry.notifyDataActivity(convertDataActivityState(sender.getDataActivityState()));
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ public void notifyDataConnection(Phone sender, String reason) {
+ TelephonyManager telephony = TelephonyManager.getDefault();
+ try {
+ mRegistry.notifyDataConnection(
+ convertDataState(sender.getDataConnectionState()),
+ sender.isDataConnectivityPossible(), reason,
+ sender.getActiveApn(),
+ sender.getActiveApnTypes(),
+ sender.getInterfaceName(null),
+ ((telephony!=null) ? telephony.getNetworkType() :
+ TelephonyManager.NETWORK_TYPE_UNKNOWN),
+ sender.getGateway(null));
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ public void notifyDataConnectionFailed(Phone sender, String reason) {
+ try {
+ mRegistry.notifyDataConnectionFailed(reason);
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ public void notifyCellLocation(Phone sender) {
+ Bundle data = new Bundle();
+ sender.getCellLocation().fillInNotifierBundle(data);
+ try {
+ mRegistry.notifyCellLocation(data);
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
+ private void log(String s) {
+ Log.d(LOG_TAG, "[PhoneNotifier] " + s);
+ }
+
+ /**
+ * Convert the {@link State} enum into the TelephonyManager.CALL_STATE_* constants
+ * for the public API.
+ */
+ public static int convertCallState(Phone.State state) {
+ switch (state) {
+ case RINGING:
+ return TelephonyManager.CALL_STATE_RINGING;
+ case OFFHOOK:
+ return TelephonyManager.CALL_STATE_OFFHOOK;
+ default:
+ return TelephonyManager.CALL_STATE_IDLE;
+ }
+ }
+
+ /**
+ * Convert the TelephonyManager.CALL_STATE_* constants into the {@link State} enum
+ * for the public API.
+ */
+ public static Phone.State convertCallState(int state) {
+ switch (state) {
+ case TelephonyManager.CALL_STATE_RINGING:
+ return Phone.State.RINGING;
+ case TelephonyManager.CALL_STATE_OFFHOOK:
+ return Phone.State.OFFHOOK;
+ default:
+ return Phone.State.IDLE;
+ }
+ }
+
+ /**
+ * Convert the {@link DataState} enum into the TelephonyManager.DATA_* constants
+ * for the public API.
+ */
+ public static int convertDataState(Phone.DataState state) {
+ switch (state) {
+ case CONNECTING:
+ return TelephonyManager.DATA_CONNECTING;
+ case CONNECTED:
+ return TelephonyManager.DATA_CONNECTED;
+ case SUSPENDED:
+ return TelephonyManager.DATA_SUSPENDED;
+ default:
+ return TelephonyManager.DATA_DISCONNECTED;
+ }
+ }
+
+ /**
+ * Convert the TelephonyManager.DATA_* constants into {@link DataState} enum
+ * for the public API.
+ */
+ public static Phone.DataState convertDataState(int state) {
+ switch (state) {
+ case TelephonyManager.DATA_CONNECTING:
+ return Phone.DataState.CONNECTING;
+ case TelephonyManager.DATA_CONNECTED:
+ return Phone.DataState.CONNECTED;
+ case TelephonyManager.DATA_SUSPENDED:
+ return Phone.DataState.SUSPENDED;
+ default:
+ return Phone.DataState.DISCONNECTED;
+ }
+ }
+
+ /**
+ * Convert the {@link DataState} enum into the TelephonyManager.DATA_* constants
+ * for the public API.
+ */
+ public static int convertDataActivityState(Phone.DataActivityState state) {
+ switch (state) {
+ case DATAIN:
+ return TelephonyManager.DATA_ACTIVITY_IN;
+ case DATAOUT:
+ return TelephonyManager.DATA_ACTIVITY_OUT;
+ case DATAINANDOUT:
+ return TelephonyManager.DATA_ACTIVITY_INOUT;
+ case DORMANT:
+ return TelephonyManager.DATA_ACTIVITY_DORMANT;
+ default:
+ return TelephonyManager.DATA_ACTIVITY_NONE;
+ }
+ }
+
+ /**
+ * Convert the TelephonyManager.DATA_* constants into the {@link DataState} enum
+ * for the public API.
+ */
+ public static Phone.DataActivityState convertDataActivityState(int state) {
+ switch (state) {
+ case TelephonyManager.DATA_ACTIVITY_IN:
+ return Phone.DataActivityState.DATAIN;
+ case TelephonyManager.DATA_ACTIVITY_OUT:
+ return Phone.DataActivityState.DATAOUT;
+ case TelephonyManager.DATA_ACTIVITY_INOUT:
+ return Phone.DataActivityState.DATAINANDOUT;
+ case TelephonyManager.DATA_ACTIVITY_DORMANT:
+ return Phone.DataActivityState.DORMANT;
+ default:
+ return Phone.DataActivityState.NONE;
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/UUSInfo.java b/telephony/java/com/android/internal/telephony/UUSInfo.java
new file mode 100644
index 000000000000..801b84563c98
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/UUSInfo.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 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 class UUSInfo {
+
+ /*
+ * User-to-User signaling Info activation types derived from 3GPP 23.087
+ * v8.0
+ */
+
+ public static final int UUS_TYPE1_IMPLICIT = 0;
+
+ public static final int UUS_TYPE1_REQUIRED = 1;
+
+ public static final int UUS_TYPE1_NOT_REQUIRED = 2;
+
+ public static final int UUS_TYPE2_REQUIRED = 3;
+
+ public static final int UUS_TYPE2_NOT_REQUIRED = 4;
+
+ public static final int UUS_TYPE3_REQUIRED = 5;
+
+ public static final int UUS_TYPE3_NOT_REQUIRED = 6;
+
+ /*
+ * User-to-User Signaling Information data coding schemes. Possible values
+ * for Octet 3 (Protocol Discriminator field) in the UUIE. The values have
+ * been specified in section 10.5.4.25 of 3GPP TS 24.008
+ */
+
+ public static final int UUS_DCS_USP = 0; /* User specified protocol */
+
+ public static final int UUS_DCS_OSIHLP = 1; /* OSI higher layer protocol */
+
+ public static final int UUS_DCS_X244 = 2; /* X.244 */
+
+ public static final int UUS_DCS_RMCF = 3; /*
+ * Reserved for system management
+ * convergence function
+ */
+
+ public static final int UUS_DCS_IA5c = 4; /* IA5 characters */
+
+ private int uusType;
+
+ private int uusDcs;
+
+ private byte[] uusData;
+
+ public UUSInfo() {
+ this.uusType = UUS_TYPE1_IMPLICIT;
+ this.uusDcs = UUS_DCS_IA5c;
+ this.uusData = null;
+ }
+
+ public UUSInfo(int uusType, int uusDcs, byte[] uusData) {
+ this.uusType = uusType;
+ this.uusDcs = uusDcs;
+ this.uusData = uusData;
+ }
+
+ public int getDcs() {
+ return uusDcs;
+ }
+
+ public void setDcs(int uusDcs) {
+ this.uusDcs = uusDcs;
+ }
+
+ public int getType() {
+ return uusType;
+ }
+
+ public void setType(int uusType) {
+ this.uusType = uusType;
+ }
+
+ public byte[] getUserData() {
+ return uusData;
+ }
+
+ public void setUserData(byte[] uusData) {
+ this.uusData = uusData;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 58dfeb985df1..f48c956356a1 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -62,11 +62,13 @@ import com.android.internal.telephony.PhoneProxy;
import com.android.internal.telephony.PhoneSubInfo;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.UUSInfo;
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_ICC_OPERATOR_ISO_COUNTRY;
+import java.util.ArrayList;
import java.util.List;
@@ -98,9 +100,9 @@ public class CDMAPhone extends PhoneBase {
CdmaCallTracker mCT;
CdmaSMSDispatcher mSMS;
CdmaServiceStateTracker mSST;
- RuimFileHandler mRuimFileHandler;
RuimRecords mRuimRecords;
RuimCard mRuimCard;
+ ArrayList <CdmaMmiCode> mPendingMmis = new ArrayList<CdmaMmiCode>();
RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager;
RuimSmsInterfaceManager mRuimSmsInterfaceManager;
PhoneSubInfo mSubInfo;
@@ -155,7 +157,7 @@ public class CDMAPhone extends PhoneBase {
mDataConnection = new CdmaDataConnectionTracker (this);
mRuimCard = new RuimCard(this);
mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this);
- mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this);
+ mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this, mSMS);
mSubInfo = new PhoneSubInfo(this);
mEriManager = new EriManager(this, context, EriManager.ERI_FROM_XML);
@@ -219,6 +221,8 @@ public class CDMAPhone extends PhoneBase {
mSST.unregisterForNetworkAttach(this); //EVENT_REGISTERED_TO_NETWORK
mCM.unSetOnSuppServiceNotification(this);
+ mPendingMmis.clear();
+
//Force all referenced classes to unregister their former registered events
mCT.dispose();
mDataConnection.dispose();
@@ -344,6 +348,10 @@ public class CDMAPhone extends PhoneBase {
return mCT.dial(newDialString);
}
+ public Connection dial(String dialString, UUSInfo uusInfo) throws CallStateException {
+ throw new CallStateException("Sending UUS information NOT supported in CDMA!");
+ }
+
public SignalStrength getSignalStrength() {
return mSST.mSignalStrength;
}
@@ -355,8 +363,7 @@ public class CDMAPhone extends PhoneBase {
public List<? extends MmiCode>
getPendingMmiCodes() {
- Log.e(LOG_TAG, "method getPendingMmiCodes is NOT supported in CDMA!");
- return null;
+ return mPendingMmis;
}
public void registerForSuppServiceNotification(
@@ -373,6 +380,15 @@ public class CDMAPhone extends PhoneBase {
return false;
}
+ boolean isInCall() {
+ CdmaCall.State foregroundCallState = getForegroundCall().getState();
+ CdmaCall.State backgroundCallState = getBackgroundCall().getState();
+ CdmaCall.State ringingCallState = getRingingCall().getState();
+
+ return (foregroundCallState.isAlive() || backgroundCallState.isAlive() || ringingCallState
+ .isAlive());
+ }
+
public void
setNetworkSelectionModeAutomatic(Message response) {
Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!");
@@ -477,7 +493,18 @@ public class CDMAPhone extends PhoneBase {
}
public boolean handlePinMmi(String dialString) {
- Log.e(LOG_TAG, "method handlePinMmi is NOT supported in CDMA!");
+ CdmaMmiCode mmi = CdmaMmiCode.newFromDialString(dialString, this);
+
+ if (mmi == null) {
+ Log.e(LOG_TAG, "Mmi is NULL!");
+ return false;
+ } else if (mmi.isPukCommand()) {
+ mPendingMmis.add(mmi);
+ mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
+ mmi.processCode();
+ return true;
+ }
+ Log.e(LOG_TAG, "Unrecognized mmi!");
return false;
}
@@ -489,6 +516,22 @@ public class CDMAPhone extends PhoneBase {
(mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming());
}
+ /**
+ * Removes the given MMI from the pending list and notifies registrants that
+ * it is complete.
+ *
+ * @param mmi MMI that is done
+ */
+ void onMMIDone(CdmaMmiCode mmi) {
+ /*
+ * Only notify complete if it's on the pending list. Otherwise, it's
+ * already been handled (eg, previously canceled).
+ */
+ if (mPendingMmis.remove(mmi)) {
+ mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
+ }
+ }
+
public void setLine1Number(String alphaTag, String number, Message onComplete) {
Log.e(LOG_TAG, "setLine1Number: not possible in CDMA");
}
@@ -1361,7 +1404,7 @@ public class CDMAPhone extends PhoneBase {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putString(VM_NUMBER_CDMA, number);
- editor.commit();
+ editor.apply();
}
/**
@@ -1410,5 +1453,4 @@ public class CDMAPhone extends PhoneBase {
}
return false;
}
-
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
index c3bb01f6db59..4ad61bb083b6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
@@ -75,8 +75,7 @@ public final class CdmaCall extends Call {
public Phone
getPhone() {
- //TODO, see GsmCall
- return null;
+ return owner.phone;
}
public boolean isMultiparty() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 1005d2045f42..3669e6062b02 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -61,7 +61,7 @@ public final class CdmaCallTracker extends CallTracker {
RegistrantList callWaitingRegistrants = new RegistrantList();
- // connections dropped durin last poll
+ // connections dropped during last poll
ArrayList<CdmaConnection> droppedDuringPoll
= new ArrayList<CdmaConnection>(MAX_CONNECTIONS);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
index 188145b33fcb..fbe455e1ffdd 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -945,4 +945,10 @@ public class CdmaConnection extends Connection {
public int getNumberPresentation() {
return numberPresentation;
}
+
+ @Override
+ public UUSInfo getUUSInfo() {
+ // UUS information not supported in CDMA
+ return null;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 217e1e86b093..9f2a44b743b7 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -114,7 +114,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
// if we have no active Apn this is null
protected ApnSetting mActiveApn;
- // Possibly promoate to base class, the only difference is
+ // Possibly promote to base class, the only difference is
// the INTENT_RECONNECT_ALARM action is a different string.
// Do consider technology changes if it is promoted.
BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
@@ -420,7 +420,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
CdmaDataConnection conn = findFreeDataConnection();
if (conn == null) {
- if (DBG) log("setupData: No free CdmaDataConnectionfound!");
+ if (DBG) log("setupData: No free CdmaDataConnection found!");
return false;
}
@@ -646,7 +646,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
}
/**
- * @override com.android.intenral.telephony.DataConnectionTracker
+ * @override com.android.internal.telephony.DataConnectionTracker
*/
@Override
protected void onEnableNewApn() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaMmiCode.java b/telephony/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
new file mode 100644
index 000000000000..8dd8c2e6c679
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaMmiCode.java
@@ -0,0 +1,296 @@
+/*
+ * 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 com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.MmiCode;
+
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * This class can handle Puk code Mmi
+ *
+ * {@hide}
+ *
+ */
+public final class CdmaMmiCode extends Handler implements MmiCode {
+ static final String LOG_TAG = "CDMA_MMI";
+
+ // Constants
+
+ // From TS 22.030 6.5.2
+ static final String ACTION_REGISTER = "**";
+
+ // Supp Service codes from TS 22.030 Annex B
+ static final String SC_PUK = "05";
+
+ // Event Constant
+
+ static final int EVENT_SET_COMPLETE = 1;
+
+ // Instance Variables
+
+ CDMAPhone phone;
+ Context context;
+
+ String action; // ACTION_REGISTER
+ 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
+
+ State state = State.PENDING;
+ CharSequence message;
+
+ // Class Variables
+
+ static Pattern sPatternSuppService = Pattern.compile(
+ "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)");
+/* 1 2 3 4 5 6 7 8 9 10 11 12
+
+ 1 = Full string up to and including #
+ 2 = action
+ 3 = service code
+ 5 = SIA
+ 7 = SIB
+ 9 = SIC
+ 10 = dialing number
+*/
+
+ static final int MATCH_GROUP_POUND_STRING = 1;
+ static final int MATCH_GROUP_ACTION = 2;
+ static final int MATCH_GROUP_SERVICE_CODE = 3;
+ static final int MATCH_GROUP_SIA = 5;
+ static final int MATCH_GROUP_SIB = 7;
+ static final int MATCH_GROUP_SIC = 9;
+ static final int MATCH_GROUP_PWD_CONFIRM = 11;
+ static final int MATCH_GROUP_DIALING_NUMBER = 12;
+
+
+ // Public Class methods
+
+ /**
+ * Check if provided string contains Mmi code in it and create corresponding
+ * Mmi if it does
+ */
+
+ public static CdmaMmiCode
+ newFromDialString(String dialString, CDMAPhone phone) {
+ Matcher m;
+ CdmaMmiCode ret = null;
+
+ m = sPatternSuppService.matcher(dialString);
+
+ // Is this formatted like a standard supplementary service code?
+ if (m.matches()) {
+ ret = new CdmaMmiCode(phone);
+ ret.poundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING));
+ ret.action = makeEmptyNull(m.group(MATCH_GROUP_ACTION));
+ ret.sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE));
+ ret.sia = makeEmptyNull(m.group(MATCH_GROUP_SIA));
+ ret.sib = makeEmptyNull(m.group(MATCH_GROUP_SIB));
+ ret.sic = makeEmptyNull(m.group(MATCH_GROUP_SIC));
+ ret.pwd = makeEmptyNull(m.group(MATCH_GROUP_PWD_CONFIRM));
+ ret.dialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER));
+
+ }
+
+ return ret;
+ }
+
+ // Private Class methods
+
+ /** make empty strings be null.
+ * Regexp returns empty strings for empty groups
+ */
+ private static String
+ makeEmptyNull (String s) {
+ if (s != null && s.length() == 0) return null;
+
+ return s;
+ }
+
+ // Constructor
+
+ CdmaMmiCode (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() {
+ // Complete or failed cannot be cancelled
+ if (state == State.COMPLETE || state == State.FAILED) {
+ return;
+ }
+
+ state = State.CANCELLED;
+ phone.onMMIDone (this);
+ }
+
+ public boolean isCancelable() {
+ return false;
+ }
+
+ // Instance Methods
+
+ /**
+ * @return true if the Service Code is PIN/PIN2/PUK/PUK2-related
+ */
+ boolean isPukCommand() {
+ return sc != null && sc.equals(SC_PUK);
+ }
+
+ boolean isRegister() {
+ return action != null && action.equals(ACTION_REGISTER);
+ }
+
+ public boolean isUssdRequest() {
+ Log.w(LOG_TAG, "isUssdRequest is not implemented in CdmaMmiCode");
+ return false;
+ }
+
+ /** Process a MMI PUK code */
+ void
+ processCode () {
+ try {
+ if (isPukCommand()) {
+ // sia = old PUK
+ // sib = new PIN
+ // sic = new PIN
+ String oldPinOrPuk = sia;
+ String newPin = sib;
+ int pinLen = newPin.length();
+ if (isRegister()) {
+ if (!newPin.equals(sic)) {
+ // password mismatch; return error
+ handlePasswordError(com.android.internal.R.string.mismatchPin);
+ } else if (pinLen < 4 || pinLen > 8 ) {
+ // invalid length
+ handlePasswordError(com.android.internal.R.string.invalidPin);
+ } else {
+ phone.mCM.supplyIccPuk(oldPinOrPuk, newPin,
+ obtainMessage(EVENT_SET_COMPLETE, this));
+ }
+ } else {
+ throw new RuntimeException ("Invalid or Unsupported MMI Code");
+ }
+ } else {
+ throw new RuntimeException ("Invalid or Unsupported MMI Code");
+ }
+ } catch (RuntimeException exc) {
+ state = State.FAILED;
+ message = context.getText(com.android.internal.R.string.mmiError);
+ phone.onMMIDone(this);
+ }
+ }
+
+ private void handlePasswordError(int res) {
+ state = State.FAILED;
+ StringBuilder sb = new StringBuilder(getScString());
+ sb.append("\n");
+ sb.append(context.getText(res));
+ message = sb;
+ phone.onMMIDone(this);
+ }
+
+ public void
+ handleMessage (Message msg) {
+ AsyncResult ar;
+
+ if (msg.what == EVENT_SET_COMPLETE) {
+ ar = (AsyncResult) (msg.obj);
+ onSetComplete(ar);
+ } else {
+ Log.e(LOG_TAG, "Unexpected reply");
+ }
+ }
+ // Private instance methods
+
+ private CharSequence getScString() {
+ if (sc != null) {
+ if (isPukCommand()) {
+ return context.getText(com.android.internal.R.string.PinMmi);
+ }
+ }
+
+ return "";
+ }
+
+ private void
+ onSetComplete(AsyncResult ar){
+ StringBuilder sb = new StringBuilder(getScString());
+ sb.append("\n");
+
+ if (ar.exception != null) {
+ state = State.FAILED;
+ if (ar.exception instanceof CommandException) {
+ CommandException.Error err = ((CommandException)(ar.exception)).getCommandError();
+ if (err == CommandException.Error.PASSWORD_INCORRECT) {
+ if (isPukCommand()) {
+ sb.append(context.getText(
+ com.android.internal.R.string.badPuk));
+ } else {
+ sb.append(context.getText(
+ com.android.internal.R.string.passwordIncorrect));
+ }
+ } else {
+ sb.append(context.getText(
+ com.android.internal.R.string.mmiError));
+ }
+ } else {
+ sb.append(context.getText(
+ com.android.internal.R.string.mmiError));
+ }
+ } else if (isRegister()) {
+ state = State.COMPLETE;
+ sb.append(context.getText(
+ com.android.internal.R.string.serviceRegistered));
+ } 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/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index ed93aea18988..dceff2a956b6 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -28,21 +28,20 @@ import android.database.SQLException;
import android.os.AsyncResult;
import android.os.Message;
import android.os.SystemProperties;
+import android.preference.PreferenceManager;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
-import android.preference.PreferenceManager;
-import android.util.Config;
-import android.util.Log;
import android.telephony.SmsManager;
import android.telephony.SmsMessage.MessageClass;
+import android.util.Config;
+import android.util.Log;
-import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.SMSDispatcher;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.SMSDispatcher;
import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
-import com.android.internal.telephony.cdma.SmsMessage;
+import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.util.HexDump;
@@ -51,20 +50,16 @@ import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.lang.Boolean;
final class CdmaSMSDispatcher extends SMSDispatcher {
private static final String TAG = "CDMA";
- private CDMAPhone mCdmaPhone;
-
private byte[] mLastDispatchedSmsFingerprint;
private byte[] mLastAcknowledgedSmsFingerprint;
CdmaSMSDispatcher(CDMAPhone phone) {
super(phone);
- mCdmaPhone = phone;
}
/**
@@ -129,10 +124,10 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
Log.d(TAG, "Voicemail count=" + voicemailCount);
// Store the voicemail count in preferences.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(
- ((CDMAPhone) mPhone).getContext());
+ mPhone.getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putInt(CDMAPhone.VM_COUNT_CDMA, voicemailCount);
- editor.commit();
+ editor.apply();
((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount);
handled = true;
} else if (((SmsEnvelope.TELESERVICE_WMT == teleService) ||
@@ -176,7 +171,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
* TODO(cleanup): Why are we using a getter method for this
* (and for so many other sms fields)? Trivial getters and
* setters like this are direct violations of the style guide.
- * If the purpose is to protect agaist writes (by not
+ * If the purpose is to protect against writes (by not
* providing a setter) then any protection is illusory (and
* hence bad) for cases where the values are not primitives,
* such as this call for the header. Since this is an issue
@@ -440,7 +435,7 @@ final class CdmaSMSDispatcher extends SMSDispatcher {
protected void sendSms(SmsTracker tracker) {
HashMap map = tracker.mData;
- byte smsc[] = (byte[]) map.get("smsc");
+ // byte smsc[] = (byte[]) map.get("smsc"); // unused for CDMA
byte pdu[] = (byte[]) map.get("pdu");
Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 39fe007f4b20..2cad6cc00a65 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -66,7 +66,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
CdmaCellLocation cellLoc;
CdmaCellLocation newCellLoc;
- /** if time between NTIZ updates is less than mNitzUpdateSpacing the update may be ignored. */
+ /** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */
private static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10;
private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing",
NITZ_UPDATE_SPACING_DEFAULT);
@@ -395,7 +395,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
}
// Release any temporary cell lock, which could have been
- // aquired to allow a single-shot location update.
+ // acquired to allow a single-shot location update.
disableSingleLocationUpdate();
break;
@@ -591,7 +591,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
boolean showPlmn = false;
int rule = 0;
if (cm.getRadioState().isRUIMReady()) {
- // TODO RUIM SPN is not implemnted, EF_SPN has to be read and Display Condition
+ // TODO RUIM SPN is not implemented, EF_SPN has to be read and Display Condition
// Character Encoding, Language Indicator and SPN has to be set
// rule = phone.mRuimRecords.getDisplayRule(ss.getOperatorNumeric());
// spn = phone.mSIMRecords.getServiceProvideName();
@@ -872,7 +872,6 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
* and start over again if the radio notifies us that some
* event has changed
*/
-
private void
pollState() {
pollingContext = new int[1];
@@ -945,6 +944,9 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
case DATA_ACCESS_CDMA_EvDo_A:
ret = "CDMA - EvDo rev. A";
break;
+ case DATA_ACCESS_CDMA_EvDo_B:
+ ret = "CDMA - EvDo rev. B";
+ break;
default:
if (DBG) {
Log.e(LOG_TAG, "Wrong network. Can not return a string.");
@@ -1237,6 +1239,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
case 6: // RADIO_TECHNOLOGY_1xRTT
case 7: // RADIO_TECHNOLOGY_EVDO_0
case 8: // RADIO_TECHNOLOGY_EVDO_A
+ case 12: // RADIO_TECHNOLOGY_EVDO_B
retVal = ServiceState.STATE_IN_SERVICE;
break;
default:
@@ -1256,7 +1259,7 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
return ServiceState.STATE_IN_SERVICE;
case 2: // 2 is "searching", fall through
case 3: // 3 is "registration denied", fall through
- case 4: // 4 is "unknown" no vaild in current baseband
+ case 4: // 4 is "unknown", not valid in current baseband
return ServiceState.STATE_OUT_OF_SERVICE;
case 5:// 5 is "Registered, roaming"
return ServiceState.STATE_IN_SERVICE;
@@ -1295,12 +1298,12 @@ final class CdmaServiceStateTracker extends ServiceStateTracker {
*/
private boolean isRoamIndForHomeSystem(String roamInd) {
// retrieve the carrier-specified list of ERIs for home system
- String homeRoamIndcators = SystemProperties.get("ro.cdma.homesystem");
+ String homeRoamIndicators = SystemProperties.get("ro.cdma.homesystem");
- if (!TextUtils.isEmpty(homeRoamIndcators)) {
+ if (!TextUtils.isEmpty(homeRoamIndicators)) {
// searches through the comma-separated list for a match,
// return true if one is found.
- for (String homeRoamInd : homeRoamIndcators.split(",")) {
+ for (String homeRoamInd : homeRoamIndicators.split(",")) {
if (homeRoamInd.equals(roamInd)) {
return true;
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
index cfcfd98b6840..e97549dc18f7 100644
--- a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
@@ -27,6 +27,7 @@ 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.SMSDispatcher;
import com.android.internal.telephony.SmsRawData;
import java.util.ArrayList;
@@ -81,9 +82,9 @@ public class RuimSmsInterfaceManager extends IccSmsInterfaceManager {
}
};
- public RuimSmsInterfaceManager(CDMAPhone phone) {
+ public RuimSmsInterfaceManager(CDMAPhone phone, SMSDispatcher dispatcher) {
super(phone);
- mDispatcher = new CdmaSMSDispatcher(phone);
+ mDispatcher = dispatcher;
}
public void dispose() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 403b7a1d16d3..0f3b8ff32699 100755
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -287,7 +287,7 @@ public class SmsMessage extends SmsMessageBase {
* @param destAddr 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
+ * @param smsHeader 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.
@@ -313,7 +313,7 @@ public class SmsMessage extends SmsMessageBase {
}
/**
- * Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
+ * Get an SMS-SUBMIT PDU for a data message to a destination address and port.
*
* @param scAddr Service Centre address. null == use default
* @param destAddr the address of the destination for the message
@@ -355,7 +355,7 @@ public class SmsMessage extends SmsMessageBase {
* Get an SMS-SUBMIT PDU for a data message to a destination address &amp; port
*
* @param destAddr the address of the destination for the message
- * @param userDara the data for the message
+ * @param userData the data for the message
* @param statusReportRequested Indicates whether a report is requested for this message.
* @return a <code>SubmitPdu</code> containing the encoded SC
* address, if applicable, and the encoded message.
@@ -446,7 +446,7 @@ public class SmsMessage extends SmsMessageBase {
*/
public static TextEncodingDetails calculateLength(CharSequence messageBody,
boolean use7bitOnly) {
- return BearerData.calcTextEncodingDetails(messageBody.toString(), use7bitOnly);
+ return BearerData.calcTextEncodingDetails(messageBody, use7bitOnly);
}
/**
diff --git a/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java b/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java
index 3813b1da98e0..4907aa946800 100644
--- a/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java
+++ b/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java
@@ -56,10 +56,10 @@ public class TtyIntent {
/**
* The lookup key for an int that indicates preferred TTY mode.
* Valid modes are:
- * - {@link Phone.TTY_MODE_OFF}
- * - {@link Phone.TTY_MODE_FULL}
- * - {@link Phone.TTY_MODE_HCO}
- * - {@link Phone.TTY_MODE_VCO}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
*
* {@hide}
*/
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index c7032aca0a71..ab79fe98ea2d 100644
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -405,7 +405,8 @@ public final class BearerData {
/**
* Calculate the message text encoding length, fragmentation, and other details.
*
- * @param force ignore (but still count) illegal characters if true
+ * @param msg message text
+ * @param force7BitEncoding ignore (but still count) illegal characters if true
* @return septet count, or -1 on failure
*/
public static TextEncodingDetails calcTextEncodingDetails(CharSequence msg,
@@ -427,9 +428,10 @@ public final class BearerData {
ted.codeUnitCount = msg.length();
int octets = ted.codeUnitCount * 2;
if (octets > MAX_USER_DATA_BYTES) {
- ted.msgCount = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
- ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES_WITH_HEADER
- - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+ ted.msgCount = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) /
+ MAX_USER_DATA_BYTES_WITH_HEADER;
+ ted.codeUnitsRemaining = ((ted.msgCount *
+ MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2;
} else {
ted.msgCount = 1;
ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2;
@@ -802,9 +804,8 @@ public final class BearerData {
* Create serialized representation for BearerData object.
* (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
*
- * @param bearerData an instance of BearerData.
- *
- * @return data byta array of raw encoded SMS bearer data.
+ * @param bData an instance of BearerData.
+ * @return byte array of raw encoded SMS bearer data.
*/
public static byte[] encode(BearerData bData) {
bData.hasUserDataHeader = ((bData.userData != null) &&
diff --git a/telephony/java/com/android/internal/telephony/gsm/CallFailCause.java b/telephony/java/com/android/internal/telephony/gsm/CallFailCause.java
index e7fbf6bd8a8b..af2ad48a9bc0 100644
--- a/telephony/java/com/android/internal/telephony/gsm/CallFailCause.java
+++ b/telephony/java/com/android/internal/telephony/gsm/CallFailCause.java
@@ -25,6 +25,9 @@ package com.android.internal.telephony.gsm;
*
*/
public interface CallFailCause {
+ // Unassigned/Unobtainable number
+ static final int UNOBTAINABLE_NUMBER = 1;
+
static final int NORMAL_CLEARING = 16;
// Busy Tone
static final int USER_BUSY = 17;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 2bb796827049..689a97265ef7 100755..100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -67,6 +67,7 @@ import com.android.internal.telephony.PhoneNotifier;
import com.android.internal.telephony.PhoneProxy;
import com.android.internal.telephony.PhoneSubInfo;
import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.UUSInfo;
import com.android.internal.telephony.gsm.stk.StkService;
import com.android.internal.telephony.test.SimulatedRadioControl;
import com.android.internal.telephony.IccVmNotSupportedException;
@@ -116,10 +117,6 @@ public class GSMPhone extends PhoneBase {
Thread debugPortThread;
ServerSocket debugSocket;
- private int mReportedRadioResets;
- private int mReportedAttemptedConnects;
- private int mReportedSuccessfulConnects;
-
private String mImei;
private String mImeiSv;
private String mVmNumber;
@@ -150,7 +147,7 @@ public class GSMPhone extends PhoneBase {
mSimCard = new SimCard(this);
if (!unitTestMode) {
mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
- mSimSmsIntManager = new SimSmsInterfaceManager(this);
+ mSimSmsIntManager = new SimSmsInterfaceManager(this, mSMS);
mSubInfo = new PhoneSubInfo(this);
}
mStkService = StkService.getInstance(mCM, mSIMRecords, mContext,
@@ -711,7 +708,12 @@ public class GSMPhone extends PhoneBase {
}
public Connection
- dial (String dialString) throws CallStateException {
+ dial(String dialString) throws CallStateException {
+ return dial(dialString, null);
+ }
+
+ public Connection
+ dial (String dialString, UUSInfo uusInfo) throws CallStateException {
// Need to make sure dialString gets parsed properly
String newDialString = PhoneNumberUtils.stripSeparators(dialString);
@@ -727,9 +729,9 @@ public class GSMPhone extends PhoneBase {
"dialing w/ mmi '" + mmi + "'...");
if (mmi == null) {
- return mCT.dial(newDialString);
+ return mCT.dial(newDialString, uusInfo);
} else if (mmi.isTemporaryModeCLIR()) {
- return mCT.dial(mmi.dialingNumber, mmi.getCLIRMode());
+ return mCT.dial(mmi.dialingNumber, mmi.getCLIRMode(), uusInfo);
} else {
mPendingMMIs.add(mmi);
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
@@ -801,7 +803,7 @@ public class GSMPhone extends PhoneBase {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putString(VM_NUMBER, number);
- editor.commit();
+ editor.apply();
setVmSimImsi(getSubscriberId());
}
@@ -824,7 +826,7 @@ public class GSMPhone extends PhoneBase {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putString(VM_SIM_IMSI, imsi);
- editor.commit();
+ editor.apply();
}
public String getVoiceMailAlphaTag() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCall.java b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java
index 9542d20e1e4c..58124a25beea 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCall.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCall.java
@@ -70,8 +70,7 @@ class GsmCall extends Call {
public Phone
getPhone() {
- //TODO
- return null;
+ return owner.phone;
}
public boolean
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
index 87530e42874a..06f310c54a38 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -37,6 +37,7 @@ import com.android.internal.telephony.DriverCall;
import com.android.internal.telephony.EventLogTags;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.UUSInfo;
import com.android.internal.telephony.gsm.CallFailCause;
import com.android.internal.telephony.gsm.GSMPhone;
import com.android.internal.telephony.gsm.GsmCall;
@@ -65,7 +66,7 @@ public final class GsmCallTracker extends CallTracker {
RegistrantList voiceCallStartedRegistrants = new RegistrantList();
- // connections dropped durin last poll
+ // connections dropped during last poll
ArrayList<GsmConnection> droppedDuringPoll
= new ArrayList<GsmConnection>(MAX_CONNECTIONS);
@@ -167,7 +168,7 @@ public final class GsmCallTracker extends CallTracker {
* clirMode is one of the CLIR_ constants
*/
Connection
- dial (String dialString, int clirMode) throws CallStateException {
+ dial (String dialString, int clirMode, UUSInfo uusInfo) throws CallStateException {
// note that this triggers call state changed notif
clearDisconnected();
@@ -213,7 +214,7 @@ public final class GsmCallTracker extends CallTracker {
// Always unmute when initiating a new call
setMute(false);
- cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
+ cm.dial(pendingMO.address, clirMode, uusInfo, obtainCompleteMessage());
}
updatePhoneState();
@@ -222,10 +223,19 @@ public final class GsmCallTracker extends CallTracker {
return pendingMO;
}
+ Connection
+ dial(String dialString) throws CallStateException {
+ return dial(dialString, CommandsInterface.CLIR_DEFAULT, null);
+ }
+
+ Connection
+ dial(String dialString, UUSInfo uusInfo) throws CallStateException {
+ return dial(dialString, CommandsInterface.CLIR_DEFAULT, uusInfo);
+ }
Connection
- dial (String dialString) throws CallStateException {
- return dial(dialString, CommandsInterface.CLIR_DEFAULT);
+ dial(String dialString, int clirMode) throws CallStateException {
+ return dial(dialString, clirMode, null);
}
void
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
index 4788a0130657..7dc25044eb16 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
@@ -73,6 +73,7 @@ public class GsmConnection extends Connection {
DisconnectCause cause = DisconnectCause.NOT_DISCONNECTED;
PostDialState postDialState = PostDialState.NOT_STARTED;
int numberPresentation = Connection.PRESENTATION_ALLOWED;
+ UUSInfo uusInfo;
Handler h;
@@ -126,6 +127,7 @@ public class GsmConnection extends Connection {
isIncoming = dc.isMT;
createTime = System.currentTimeMillis();
numberPresentation = dc.numberPresentation;
+ uusInfo = dc.uusInfo;
this.index = index;
@@ -356,6 +358,9 @@ public class GsmConnection extends Connection {
case CallFailCause.FDN_BLOCKED:
return DisconnectCause.FDN_BLOCKED;
+ case CallFailCause.UNOBTAINABLE_NUMBER:
+ return DisconnectCause.UNOBTAINABLE_NUMBER;
+
case CallFailCause.ERROR_UNSPECIFIED:
case CallFailCause.NORMAL_CLEARING:
default:
@@ -728,4 +733,9 @@ public class GsmConnection extends Connection {
public int getNumberPresentation() {
return numberPresentation;
}
+
+ @Override
+ public UUSInfo getUUSInfo() {
+ return uusInfo;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index d893ec4c4837..09d46dd6e8b2 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -134,7 +134,7 @@ public class GsmDataConnection extends DataConnection {
cause = FailCause.INSUFFICIENT_RESOURCES;
break;
case PDP_FAIL_MISSING_UKNOWN_APN:
- cause = FailCause.MISSING_UKNOWN_APN;
+ cause = FailCause.MISSING_UNKNOWN_APN;
break;
case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE:
cause = FailCause.UNKNOWN_PDP_ADDRESS;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 627d94d387cc..e7d57bc22037 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -45,7 +45,6 @@ import android.provider.Telephony;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
-import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -151,9 +150,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
static final String APN_ID = "apn_id";
private boolean canSetPreferApn = false;
- // for tracking retrys on the default APN
+ // for tracking retries on the default APN
private RetryManager mDefaultRetryManager;
- // for tracking retrys on a secondary APN
+ // for tracking retries on a secondary APN
private RetryManager mSecondaryRetryManager;
BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
@@ -190,8 +189,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
if (!enabled) {
- // when wifi got disabeled, the NETWORK_STATE_CHANGED_ACTION
- // quit and wont report disconnected til next enalbing.
+ // when wifi got disabled, the NETWORK_STATE_CHANGED_ACTION
+ // quit and won't report disconnected til next enabling.
mIsWifiConnected = false;
}
}
@@ -452,7 +451,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
waitingApns = buildWaitingApns();
if (waitingApns.isEmpty()) {
if (DBG) log("No APN found");
- notifyNoData(GsmDataConnection.FailCause.MISSING_UKNOWN_APN);
+ notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN);
return false;
} else {
log ("Create from allApns : " + apnListToString(allApns));
@@ -1130,7 +1129,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
SystemProperties.set("gsm.defaultpdpcontext.active", "true");
if (canSetPreferApn && preferredApn == null) {
- Log.d(LOG_TAG, "PREFERED APN is null");
+ Log.d(LOG_TAG, "PREFERRED APN is null");
preferredApn = mActiveApn;
setPreferredApn(preferredApn.id);
}
@@ -1158,10 +1157,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// No try for permanent failure
if (cause.isPermanentFail()) {
notifyNoData(cause);
- if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
- phone.notifyDataConnection(Phone.REASON_APN_FAILED);
- onEnableApn(apnTypeToId(mRequestedApnType), DISABLED);
- }
+ phone.notifyDataConnection(Phone.REASON_APN_FAILED);
+ onEnableApn(apnTypeToId(mRequestedApnType), DISABLED);
return;
}
@@ -1280,7 +1277,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (allApns.isEmpty()) {
if (DBG) log("No APN found for carrier: " + operator);
preferredApn = null;
- notifyNoData(GsmDataConnection.FailCause.MISSING_UKNOWN_APN);
+ notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN);
} else {
preferredApn = getPreferredApn();
Log.d(LOG_TAG, "Get PreferredAPN");
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index bcbd127497b2..aa16fa30633b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -39,7 +39,7 @@ import java.util.regex.Matcher;
* {@hide}
*
*/
-public final class GsmMmiCode extends Handler implements MmiCode {
+public final class GsmMmiCode extends Handler implements MmiCode {
static final String LOG_TAG = "GSM";
//***** Constants
@@ -51,7 +51,7 @@ public final class GsmMmiCode extends Handler implements MmiCode {
static final String ACTION_REGISTER = "**";
static final String ACTION_ERASURE = "##";
- // Supp Service cocdes from TS 22.030 Annex B
+ // Supp Service codes from TS 22.030 Annex B
//Called line presentation
static final String SC_CLIP = "30";
@@ -154,7 +154,7 @@ public final class GsmMmiCode extends Handler implements MmiCode {
/**
* Some dial strings in GSM are defined to do non-call setup
- * things, such as modify or query supplementry service settings (eg, call
+ * things, such as modify or query supplementary service settings (eg, call
* forwarding). These are generally referred to as "MMI codes".
* We look to see if the dial string contains a valid MMI code (potentially
* with a dial string at the end as well) and return info here.
@@ -457,12 +457,13 @@ public final class GsmMmiCode extends Handler implements MmiCode {
&& !PhoneNumberUtils.isEmergencyNumber(dialString)
&& (phone.isInCall()
|| !((dialString.length() == 2 && dialString.charAt(0) == '1')
- /* While contrary to TS 22.030, there is strong precendence
+ /* While contrary to TS 22.030, there is strong precedence
* for treating "0" and "00" as call setup strings.
*/
|| dialString.equals("0")
|| dialString.equals("00"))));
}
+
/**
* @return true if the Service Code is PIN/PIN2/PUK/PUK2-related
*/
@@ -472,13 +473,12 @@ public final class GsmMmiCode extends Handler implements MmiCode {
}
/**
- * *See TS 22.030 Annex B
+ * See TS 22.030 Annex B.
* In temporary mode, to suppress CLIR for a single call, enter:
- * " * 31 # <called number> SEND "
+ * " * 31 # [called number] SEND "
* In temporary mode, to invoke CLIR for a single call enter:
- * " # 31 # <called number> SEND "
+ * " # 31 # [called number] SEND "
*/
-
boolean
isTemporaryModeCLIR() {
return sc != null && sc.equals(SC_CLIR) && dialingNumber != null
@@ -779,7 +779,7 @@ public final class GsmMmiCode extends Handler implements MmiCode {
// 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 doene in GSMPhone.
+ // The matching up of this is done in GSMPhone.
phone.mCM.sendUSSD(ussdMessage,
obtainMessage(EVENT_USSD_COMPLETE, this));
@@ -832,8 +832,7 @@ public final class GsmMmiCode extends Handler implements MmiCode {
if (ar.exception != null) {
state = State.FAILED;
- message = context.getText(
- com.android.internal.R.string.mmiError);
+ message = getErrorMessage(ar);
phone.onMMIDone(this);
}
@@ -852,6 +851,19 @@ public final class GsmMmiCode extends Handler implements MmiCode {
}
//***** Private instance methods
+ private CharSequence getErrorMessage(AsyncResult ar) {
+
+ if (ar.exception instanceof CommandException) {
+ CommandException.Error err = ((CommandException)(ar.exception)).getCommandError();
+ if (err == CommandException.Error.FDN_CHECK_FAILURE) {
+ Log.i(LOG_TAG, "FDN_CHECK_FAILURE");
+ return context.getText(com.android.internal.R.string.mmiFdnError);
+ }
+ }
+
+ return context.getText(com.android.internal.R.string.mmiError);
+ }
+
private CharSequence getScString() {
if (sc != null) {
if (isServiceCodeCallBarring(sc)) {
@@ -904,6 +916,9 @@ public final class GsmMmiCode extends Handler implements MmiCode {
sb.append("\n");
sb.append(context.getText(
com.android.internal.R.string.needPuk2));
+ } else if (err == CommandException.Error.FDN_CHECK_FAILURE) {
+ Log.i(LOG_TAG, "FDN_CHECK_FAILURE");
+ sb.append(context.getText(com.android.internal.R.string.mmiFdnError));
} else {
sb.append(context.getText(
com.android.internal.R.string.mmiError));
@@ -953,7 +968,7 @@ public final class GsmMmiCode extends Handler implements MmiCode {
if (ar.exception != null) {
state = State.FAILED;
- sb.append(context.getText(com.android.internal.R.string.mmiError));
+ sb.append(getErrorMessage(ar));
} else {
int clirArgs[];
@@ -1123,7 +1138,7 @@ public final class GsmMmiCode extends Handler implements MmiCode {
if (ar.exception != null) {
state = State.FAILED;
- sb.append(context.getText(com.android.internal.R.string.mmiError));
+ sb.append(getErrorMessage(ar));
} else {
CallForwardInfo infos[];
@@ -1141,7 +1156,7 @@ public final class GsmMmiCode extends Handler implements MmiCode {
// Each bit in the service class gets its own result line
// The service classes may be split up over multiple
- // CallForwardInfos. So, for each service classs, find out
+ // CallForwardInfos. So, for each service class, find out
// which CallForwardInfo represents it and then build
// the response text based on that
@@ -1175,7 +1190,7 @@ public final class GsmMmiCode extends Handler implements MmiCode {
if (ar.exception != null) {
state = State.FAILED;
- sb.append(context.getText(com.android.internal.R.string.mmiError));
+ sb.append(getErrorMessage(ar));
} else {
int[] ints = (int[])ar.result;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
index 6ae316d0f08e..3079a64086c7 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -27,13 +27,12 @@ import android.telephony.ServiceState;
import android.util.Config;
import android.util.Log;
-import com.android.internal.telephony.IccUtils;
-import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
-import com.android.internal.telephony.gsm.SmsMessage;
import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.IccUtils;
import com.android.internal.telephony.SMSDispatcher;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails;
import java.util.ArrayList;
import java.util.HashMap;
@@ -94,16 +93,23 @@ final class GsmSMSDispatcher extends SMSDispatcher {
SmsMessage sms = (SmsMessage) smsb;
boolean handled = false;
+ if (sms.isTypeZero()) {
+ // As per 3GPP TS 23.040 9.2.3.9, Type Zero messages should not be
+ // Displayed/Stored/Notified. They should only be acknowledged.
+ Log.d(TAG, "Received short message type 0, Don't display or store it. Send Ack");
+ return Intents.RESULT_SMS_HANDLED;
+ }
+
// Special case the message waiting indicator messages
if (sms.isMWISetMessage()) {
mGsmPhone.updateMessageWaitingIndicator(true);
- handled |= sms.isMwiDontStore();
+ handled = sms.isMwiDontStore();
if (Config.LOGD) {
Log.d(TAG, "Received voice mail indicator set SMS shouldStore=" + !handled);
}
} else if (sms.isMWIClearMessage()) {
mGsmPhone.updateMessageWaitingIndicator(false);
- handled |= sms.isMwiDontStore();
+ handled = sms.isMwiDontStore();
if (Config.LOGD) {
Log.d(TAG, "Received voice mail indicator clear SMS shouldStore=" + !handled);
}
@@ -294,7 +300,7 @@ final class GsmSMSDispatcher extends SMSDispatcher {
map.put("smsc", pdus.encodedScAddress);
map.put("pdu", pdus.encodedMessage);
- SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent);
+ SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent);
sendSms(tracker);
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 50b8eba92701..90ecbd7c4029 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -40,7 +40,6 @@ import android.provider.Settings.SettingNotFoundException;
import android.provider.Telephony.Intents;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
-import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
import android.util.Config;
@@ -130,7 +129,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
*/
private boolean mNeedToRegForSimLoaded;
- /** Started the recheck process after finding gprs should registerd but not. */
+ /** Started the recheck process after finding gprs should registered but not. */
private boolean mStartedGprsRegCheck = false;
/** Already sent the event-log for no gprs register. */
@@ -415,7 +414,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
}
// Release any temporary cell lock, which could have been
- // aquired to allow a single-shot location update.
+ // acquired to allow a single-shot location update.
disableSingleLocationUpdate();
break;
@@ -500,9 +499,9 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
break;
case EVENT_CHECK_REPORT_GPRS:
- if (ss != null && !isGprsConsistant(gprsState, ss.getState())) {
+ if (ss != null && !isGprsConsistent(gprsState, ss.getState())) {
- // Can't register data sevice while voice service is ok
+ // Can't register data service while voice service is ok
// i.e. CREG is ok while CGREG is not
// possible a network or baseband side error
GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
@@ -651,6 +650,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
int lac = -1;
int cid = -1;
int regState = -1;
+ int psc = -1;
if (states.length > 0) {
try {
regState = Integer.parseInt(states[0]);
@@ -662,6 +662,11 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
cid = Integer.parseInt(states[2], 16);
}
}
+ if (states.length > 14) {
+ if (states[14] != null && states[14].length() > 0) {
+ psc = Integer.parseInt(states[14], 16);
+ }
+ }
} catch (NumberFormatException ex) {
Log.w(LOG_TAG, "error parsing RegistrationState: " + ex);
}
@@ -678,6 +683,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
// LAC and CID are -1 if not avail
newCellLoc.setLacAndCid(lac, cid);
+ newCellLoc.setPsc(psc);
break;
case EVENT_POLL_STATE_GPRS:
@@ -1027,7 +1033,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
phone.notifyLocationChanged();
}
- if (! isGprsConsistant(gprsState, ss.getState())) {
+ if (! isGprsConsistent(gprsState, ss.getState())) {
if (!mStartedGprsRegCheck && !mReportedGprsNoReg) {
mStartedGprsRegCheck = true;
@@ -1044,13 +1050,13 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
}
/**
- * Check if GPRS got registred while voice is registered
+ * Check if GPRS got registered while voice is registered.
*
* @param gprsState for GPRS registration state, i.e. CGREG in GSM
* @param serviceState for voice registration state, i.e. CREG in GSM
* @return false if device only register to voice but not gprs
*/
- private boolean isGprsConsistant (int gprsState, int serviceState) {
+ private boolean isGprsConsistent(int gprsState, int serviceState) {
return !((serviceState == ServiceState.STATE_IN_SERVICE) &&
(gprsState != ServiceState.STATE_IN_SERVICE));
}
@@ -1105,13 +1111,13 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
long nextTime;
- // TODO Done't poll signal strength if screen is off
+ // TODO Don't poll signal strength if screen is off
sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
}
/**
- * send signal-strength-changed notification if changed
- * Called both for solicited and unsolicited signal stength updates
+ * Send signal-strength-changed notification if changed.
+ * Called both for solicited and unsolicited signal strength updates.
*/
private void onSignalStrengthResult(AsyncResult ar) {
SignalStrength oldSignalStrength = mSignalStrength;
@@ -1332,7 +1338,7 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
/**
* @return true if phone is camping on a technology (eg UMTS)
- * that could support voice and data simultaniously.
+ * that could support voice and data simultaneously.
*/
boolean isConcurrentVoiceAndData() {
return (networkType >= DATA_ACCESS_UMTS);
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
index 2028ca4a78a8..67ecc77a320a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimSmsInterfaceManager.java
@@ -25,6 +25,7 @@ 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.SMSDispatcher;
import com.android.internal.telephony.SmsRawData;
import java.util.ArrayList;
@@ -78,9 +79,9 @@ public class SimSmsInterfaceManager extends IccSmsInterfaceManager {
}
};
- public SimSmsInterfaceManager(GSMPhone phone) {
+ public SimSmsInterfaceManager(GSMPhone phone, SMSDispatcher dispatcher) {
super(phone);
- mDispatcher = new GsmSMSDispatcher(phone);
+ mDispatcher = dispatcher;
}
public void dispose() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
index d627bafbafe9..50dd402f9bbc 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
@@ -111,6 +111,14 @@ public class SmsMessage extends SmsMessageBase{
}
/**
+ * 3GPP TS 23.040 9.2.3.9 specifies that Type Zero messages are indicated
+ * by TP_PID field set to value 0x40
+ */
+ public boolean isTypeZero() {
+ return (protocolIdentifier == 0x40);
+ }
+
+ /**
* 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: [&lt;alpha>],<length><CR><LF><pdu>
@@ -792,9 +800,10 @@ public class SmsMessage extends SmsMessageBase{
int septets = GsmAlphabet.countGsmSeptets(msgBody, !use7bitOnly);
ted.codeUnitCount = septets;
if (septets > MAX_USER_DATA_SEPTETS) {
- ted.msgCount = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
- ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS_WITH_HEADER
- - (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
+ ted.msgCount = (septets + (MAX_USER_DATA_SEPTETS_WITH_HEADER - 1)) /
+ MAX_USER_DATA_SEPTETS_WITH_HEADER;
+ ted.codeUnitsRemaining = (ted.msgCount *
+ MAX_USER_DATA_SEPTETS_WITH_HEADER) - septets;
} else {
ted.msgCount = 1;
ted.codeUnitsRemaining = MAX_USER_DATA_SEPTETS - septets;
@@ -804,9 +813,10 @@ public class SmsMessage extends SmsMessageBase{
int octets = msgBody.length() * 2;
ted.codeUnitCount = msgBody.length();
if (octets > MAX_USER_DATA_BYTES) {
- ted.msgCount = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
- ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES_WITH_HEADER
- - (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
+ ted.msgCount = (octets + (MAX_USER_DATA_BYTES_WITH_HEADER - 1)) /
+ MAX_USER_DATA_BYTES_WITH_HEADER;
+ ted.codeUnitsRemaining = ((ted.msgCount *
+ MAX_USER_DATA_BYTES_WITH_HEADER) - octets) / 2;
} else {
ted.msgCount = 1;
ted.codeUnitsRemaining = (MAX_USER_DATA_BYTES - octets)/2;
diff --git a/telephony/java/com/android/internal/telephony/sip/CallFailCause.java b/telephony/java/com/android/internal/telephony/sip/CallFailCause.java
new file mode 100644
index 000000000000..58fb408b6161
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/CallFailCause.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 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.sip;
+
+/**
+ * Call fail causes from TS 24.008 .
+ * These are mostly the cause codes we need to distinguish for the UI.
+ * See 22.001 Annex F.4 for mapping of cause codes to local tones.
+ *
+ * {@hide}
+ *
+ */
+public interface CallFailCause {
+ static final int NORMAL_CLEARING = 16;
+ // Busy Tone
+ static final int USER_BUSY = 17;
+
+ // No Tone
+ static final int NUMBER_CHANGED = 22;
+ static final int STATUS_ENQUIRY = 30;
+ static final int NORMAL_UNSPECIFIED = 31;
+
+ // Congestion Tone
+ static final int NO_CIRCUIT_AVAIL = 34;
+ static final int TEMPORARY_FAILURE = 41;
+ static final int SWITCHING_CONGESTION = 42;
+ static final int CHANNEL_NOT_AVAIL = 44;
+ static final int QOS_NOT_AVAIL = 49;
+ static final int BEARER_NOT_AVAIL = 58;
+
+ // others
+ static final int ACM_LIMIT_EXCEEDED = 68;
+ static final int CALL_BARRED = 240;
+ static final int FDN_BLOCKED = 241;
+ static final int ERROR_UNSPECIFIED = 0xffff;
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/CallProxy.java b/telephony/java/com/android/internal/telephony/sip/CallProxy.java
new file mode 100644
index 000000000000..fad9663cf2c3
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/CallProxy.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2010 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.sip;
+
+import com.android.internal.telephony.*;
+import java.util.List;
+
+// TODO: remove this class after integrating with CallManager
+class CallProxy extends Call {
+ private Call mTarget;
+
+ void setTarget(Call target) {
+ mTarget = target;
+ }
+
+ @Override
+ public List<Connection> getConnections() {
+ return mTarget.getConnections();
+ }
+
+ @Override
+ public Phone getPhone() {
+ return mTarget.getPhone();
+ }
+
+ @Override
+ public boolean isMultiparty() {
+ return mTarget.isMultiparty();
+ }
+
+ @Override
+ public void hangup() throws CallStateException {
+ mTarget.hangup();
+ }
+
+ @Override
+ public boolean hasConnection(Connection c) {
+ return mTarget.hasConnection(c);
+ }
+
+ @Override
+ public boolean hasConnections() {
+ return mTarget.hasConnections();
+ }
+
+ @Override
+ public State getState() {
+ return mTarget.getState();
+ }
+
+ @Override
+ public boolean isIdle() {
+ return mTarget.isIdle();
+ }
+
+ @Override
+ public Connection getEarliestConnection() {
+ return mTarget.getEarliestConnection();
+ }
+
+ @Override
+ public long getEarliestCreateTime() {
+ return mTarget.getEarliestCreateTime();
+ }
+
+ @Override
+ public long getEarliestConnectTime() {
+ return mTarget.getEarliestConnectTime();
+ }
+
+ @Override
+ public boolean isDialingOrAlerting() {
+ return mTarget.isDialingOrAlerting();
+ }
+
+ @Override
+ public boolean isRinging() {
+ return mTarget.isRinging();
+ }
+
+ @Override
+ public Connection getLatestConnection() {
+ return mTarget.getLatestConnection();
+ }
+
+ @Override
+ public boolean isGeneric() {
+ return mTarget.isGeneric();
+ }
+
+ @Override
+ public void setGeneric(boolean generic) {
+ mTarget.setGeneric(generic);
+ }
+
+ @Override
+ public void hangupIfAlive() {
+ mTarget.hangupIfAlive();
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCallBase.java b/telephony/java/com/android/internal/telephony/sip/SipCallBase.java
new file mode 100644
index 000000000000..7e407b2122c4
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipCallBase.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2010 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.sip;
+
+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 android.net.sip.SipManager;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+abstract class SipCallBase extends Call {
+ private static final int MAX_CONNECTIONS_PER_CALL = 5;
+
+ protected List<Connection> connections = new ArrayList<Connection>();
+
+ protected abstract void setState(State newState);
+
+ public void dispose() {
+ }
+
+ public List<Connection> getConnections() {
+ // FIXME should return Collections.unmodifiableList();
+ return connections;
+ }
+
+ public boolean isMultiparty() {
+ return connections.size() > 1;
+ }
+
+ public String toString() {
+ return state.toString();
+ }
+
+ /**
+ * Called by SipConnection when it has disconnected
+ */
+ void connectionDisconnected(Connection conn) {
+ if (state != State.DISCONNECTED) {
+ /* 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()
+ != State.DISCONNECTED
+ ) {
+ hasOnlyDisconnectedConnections = false;
+ break;
+ }
+ }
+
+ if (hasOnlyDisconnectedConnections) {
+ state = State.DISCONNECTED;
+ }
+ }
+ }
+
+
+ /*package*/ void detach(Connection conn) {
+ connections.remove(conn);
+
+ if (connections.size() == 0) {
+ state = State.IDLE;
+ }
+ }
+
+ /**
+ * @return true if there's no space in this call for additional
+ * connections to be added via "conference"
+ */
+ /*package*/ boolean isFull() {
+ return connections.size() == MAX_CONNECTIONS_PER_CALL;
+ }
+
+ void clearDisconnected() {
+ for (Iterator<Connection> it = connections.iterator(); it.hasNext(); ) {
+ Connection c = it.next();
+ if (c.getState() == State.DISCONNECTED) it.remove();
+ }
+
+ if (connections.isEmpty()) setState(State.IDLE);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
new file mode 100644
index 000000000000..33c89f862e51
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2010 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.sip;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+
+import com.android.internal.telephony.BaseCommands;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.UUSInfo;
+import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
+
+/**
+ * SIP doesn't need CommandsInterface. The class does nothing but made to work
+ * with PhoneBase's constructor.
+ */
+class SipCommandInterface extends BaseCommands implements CommandsInterface {
+ SipCommandInterface(Context context) {
+ super(context);
+ }
+
+ @Override public void setOnNITZTime(Handler h, int what, Object obj) {
+ }
+
+ public void getIccCardStatus(Message result) {
+ }
+
+ public void supplyIccPin(String pin, Message result) {
+ }
+
+ public void supplyIccPuk(String puk, String newPin, Message result) {
+ }
+
+ public void supplyIccPin2(String pin, Message result) {
+ }
+
+ public void supplyIccPuk2(String puk, String newPin2, Message result) {
+ }
+
+ public void changeIccPin(String oldPin, String newPin, Message result) {
+ }
+
+ public void changeIccPin2(String oldPin2, String newPin2, Message result) {
+ }
+
+ public void changeBarringPassword(String facility, String oldPwd,
+ String newPwd, Message result) {
+ }
+
+ public void supplyNetworkDepersonalization(String netpin, Message result) {
+ }
+
+ public void getCurrentCalls(Message result) {
+ }
+
+ @Deprecated public void getPDPContextList(Message result) {
+ }
+
+ public void getDataCallList(Message result) {
+ }
+
+ public void dial(String address, int clirMode, Message result) {
+ }
+
+ public void dial(String address, int clirMode, UUSInfo uusInfo,
+ Message result) {
+ }
+
+ public void getIMSI(Message result) {
+ }
+
+ public void getIMEI(Message result) {
+ }
+
+ public void getIMEISV(Message result) {
+ }
+
+
+ public void hangupConnection (int gsmIndex, Message result) {
+ }
+
+ public void hangupWaitingOrBackground (Message result) {
+ }
+
+ public void hangupForegroundResumeBackground (Message result) {
+ }
+
+ public void switchWaitingOrHoldingAndActive (Message result) {
+ }
+
+ public void conference (Message result) {
+ }
+
+
+ public void setPreferredVoicePrivacy(boolean enable, Message result) {
+ }
+
+ public void getPreferredVoicePrivacy(Message result) {
+ }
+
+ public void separateConnection (int gsmIndex, Message result) {
+ }
+
+ public void acceptCall (Message result) {
+ }
+
+ public void rejectCall (Message result) {
+ }
+
+ public void explicitCallTransfer (Message result) {
+ }
+
+ public void getLastCallFailCause (Message result) {
+ }
+
+ /** @deprecated */
+ public void getLastPdpFailCause (Message result) {
+ }
+
+ public void getLastDataCallFailCause (Message result) {
+ }
+
+ public void setMute (boolean enableMute, Message response) {
+ }
+
+ public void getMute (Message response) {
+ }
+
+ public void getSignalStrength (Message result) {
+ }
+
+ public void getRegistrationState (Message result) {
+ }
+
+ public void getGPRSRegistrationState (Message result) {
+ }
+
+ public void getOperator(Message result) {
+ }
+
+ public void sendDtmf(char c, Message result) {
+ }
+
+ public void startDtmf(char c, Message result) {
+ }
+
+ public void stopDtmf(Message result) {
+ }
+
+ public void sendBurstDtmf(String dtmfString, int on, int off,
+ Message result) {
+ }
+
+ public void sendSMS (String smscPDU, String pdu, Message result) {
+ }
+
+ public void sendCdmaSms(byte[] pdu, Message result) {
+ }
+
+ public void deleteSmsOnSim(int index, Message response) {
+ }
+
+ public void deleteSmsOnRuim(int index, Message response) {
+ }
+
+ public void writeSmsToSim(int status, String smsc, String pdu, Message response) {
+ }
+
+ public void writeSmsToRuim(int status, String pdu, Message response) {
+ }
+
+ public void setupDefaultPDP(String apn, String user, String password,
+ Message result) {
+ }
+
+ public void deactivateDefaultPDP(int cid, Message result) {
+ }
+
+ public void setupDataCall(String radioTechnology, String profile,
+ String apn, String user, String password, String authType,
+ Message result) {
+ }
+
+ public void deactivateDataCall(int cid, Message result) {
+ }
+
+ public void setRadioPower(boolean on, Message result) {
+ }
+
+ public void setSuppServiceNotifications(boolean enable, Message result) {
+ }
+
+ public void acknowledgeLastIncomingGsmSms(boolean success, int cause,
+ Message result) {
+ }
+
+ public void acknowledgeLastIncomingCdmaSms(boolean success, int cause,
+ Message result) {
+ }
+
+
+ public void iccIO (int command, int fileid, String path, int p1, int p2,
+ int p3, String data, String pin2, Message result) {
+ }
+
+ public void getCLIR(Message result) {
+ }
+
+ public void setCLIR(int clirMode, Message result) {
+ }
+
+ public void queryCallWaiting(int serviceClass, Message response) {
+ }
+
+ public void setCallWaiting(boolean enable, int serviceClass,
+ Message response) {
+ }
+
+ public void setNetworkSelectionModeAutomatic(Message response) {
+ }
+
+ public void setNetworkSelectionModeManual(
+ String operatorNumeric, Message response) {
+ }
+
+ public void getNetworkSelectionMode(Message response) {
+ }
+
+ public void getAvailableNetworks(Message response) {
+ }
+
+ public void setCallForward(int action, int cfReason, int serviceClass,
+ String number, int timeSeconds, Message response) {
+ }
+
+ public void queryCallForwardStatus(int cfReason, int serviceClass,
+ String number, Message response) {
+ }
+
+ public void queryCLIP(Message response) {
+ }
+
+ public void getBasebandVersion (Message response) {
+ }
+
+ public void queryFacilityLock (String facility, String password,
+ int serviceClass, Message response) {
+ }
+
+ public void setFacilityLock (String facility, boolean lockState,
+ String password, int serviceClass, Message response) {
+ }
+
+ public void sendUSSD (String ussdString, Message response) {
+ }
+
+ public void cancelPendingUssd (Message response) {
+ }
+
+ public void resetRadio(Message result) {
+ }
+
+ public void invokeOemRilRequestRaw(byte[] data, Message response) {
+ }
+
+ public void invokeOemRilRequestStrings(String[] strings, Message response) {
+ }
+
+ public void setBandMode (int bandMode, Message response) {
+ }
+
+ public void queryAvailableBandMode (Message response) {
+ }
+
+ public void sendTerminalResponse(String contents, Message response) {
+ }
+
+ public void sendEnvelope(String contents, Message response) {
+ }
+
+ public void handleCallSetupRequestFromSim(
+ boolean accept, Message response) {
+ }
+
+ public void setPreferredNetworkType(int networkType , Message response) {
+ }
+
+ public void getPreferredNetworkType(Message response) {
+ }
+
+ public void getNeighboringCids(Message response) {
+ }
+
+ public void setLocationUpdates(boolean enable, Message response) {
+ }
+
+ public void getSmscAddress(Message result) {
+ }
+
+ public void setSmscAddress(String address, Message result) {
+ }
+
+ public void reportSmsMemoryStatus(boolean available, Message result) {
+ }
+
+ public void reportStkServiceIsRunning(Message result) {
+ }
+
+ public void getGsmBroadcastConfig(Message response) {
+ }
+
+ public void setGsmBroadcastConfig(SmsBroadcastConfigInfo[] config, Message response) {
+ }
+
+ public void setGsmBroadcastActivation(boolean activate, Message response) {
+ }
+
+
+ // ***** Methods for CDMA support
+ public void getDeviceIdentity(Message response) {
+ }
+
+ public void getCDMASubscription(Message response) {
+ }
+
+ public void setPhoneType(int phoneType) { //Set by CDMAPhone and GSMPhone constructor
+ }
+
+ public void queryCdmaRoamingPreference(Message response) {
+ }
+
+ public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
+ }
+
+ public void setCdmaSubscription(int cdmaSubscription , Message response) {
+ }
+
+ public void queryTTYMode(Message response) {
+ }
+
+ public void setTTYMode(int ttyMode, Message response) {
+ }
+
+ public void sendCDMAFeatureCode(String FeatureCode, Message response) {
+ }
+
+ public void getCdmaBroadcastConfig(Message response) {
+ }
+
+ public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) {
+ }
+
+ public void setCdmaBroadcastActivation(boolean activate, Message response) {
+ }
+
+ public void exitEmergencyCallbackMode(Message response) {
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java
new file mode 100644
index 000000000000..6c989b4a0ef4
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipConnectionBase.java
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2010 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.sip;
+
+import android.content.Context;
+import android.net.sip.SipAudioCall;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.SystemClock;
+import android.util.Log;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.ServiceState;
+
+import com.android.internal.telephony.*;
+
+abstract class SipConnectionBase extends Connection {
+ //***** Event Constants
+ private static final int EVENT_DTMF_DONE = 1;
+ private static final int EVENT_PAUSE_DONE = 2;
+ private static final int EVENT_NEXT_POST_DIAL = 3;
+ private static final int EVENT_WAKE_LOCK_TIMEOUT = 4;
+
+ //***** Constants
+ private static final int PAUSE_DELAY_FIRST_MILLIS = 100;
+ private static final int PAUSE_DELAY_MILLIS = 3 * 1000;
+ private static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000;
+
+ private static final String LOG_TAG = "SIP_CONN";
+
+ private SipAudioCall mSipAudioCall;
+
+ private String dialString; // outgoing calls only
+ private String postDialString; // outgoing calls only
+ private int nextPostDialChar; // index into postDialString
+ private boolean isIncoming;
+ private boolean disconnected;
+
+ int index; // index in SipCallTracker.connections[], -1 if unassigned
+ // The Sip index is 1 + this
+
+ /*
+ * These time/timespan values are based on System.currentTimeMillis(),
+ * i.e., "wall clock" time.
+ */
+ private long createTime;
+ private long connectTime;
+ private long disconnectTime;
+
+ /*
+ * These time/timespan values are based on SystemClock.elapsedRealTime(),
+ * i.e., time since boot. They are appropriate for comparison and
+ * calculating deltas.
+ */
+ private long connectTimeReal;
+ private long duration;
+ private long holdingStartTime; // The time when the Connection last transitioned
+ // into HOLDING
+
+ private DisconnectCause mCause = DisconnectCause.NOT_DISCONNECTED;
+ private PostDialState postDialState = PostDialState.NOT_STARTED;
+
+ SipConnectionBase(String calleeSipUri) {
+ dialString = calleeSipUri;
+
+ postDialString = PhoneNumberUtils.extractPostDialPortion(dialString);
+
+ isIncoming = false;
+ createTime = System.currentTimeMillis();
+ }
+
+ protected void setState(Call.State state) {
+ switch (state) {
+ case ACTIVE:
+ if (connectTime == 0) {
+ connectTimeReal = SystemClock.elapsedRealtime();
+ connectTime = System.currentTimeMillis();
+ }
+ break;
+ case DISCONNECTED:
+ duration = SystemClock.elapsedRealtime() - connectTimeReal;
+ disconnectTime = System.currentTimeMillis();
+ break;
+ case HOLDING:
+ holdingStartTime = SystemClock.elapsedRealtime();
+ break;
+ }
+ }
+
+ @Override
+ public long getCreateTime() {
+ return createTime;
+ }
+
+ @Override
+ public long getConnectTime() {
+ return connectTime;
+ }
+
+ @Override
+ public long getDisconnectTime() {
+ return disconnectTime;
+ }
+
+ @Override
+ public long getDurationMillis() {
+ if (connectTimeReal == 0) {
+ return 0;
+ } else if (duration == 0) {
+ return SystemClock.elapsedRealtime() - connectTimeReal;
+ } else {
+ return duration;
+ }
+ }
+
+ @Override
+ public long getHoldDurationMillis() {
+ if (getState() != Call.State.HOLDING) {
+ // If not holding, return 0
+ return 0;
+ } else {
+ return SystemClock.elapsedRealtime() - holdingStartTime;
+ }
+ }
+
+ @Override
+ public DisconnectCause getDisconnectCause() {
+ return mCause;
+ }
+
+ void setDisconnectCause(DisconnectCause cause) {
+ mCause = cause;
+ }
+
+ @Override
+ public PostDialState getPostDialState() {
+ return postDialState;
+ }
+
+ @Override
+ public void proceedAfterWaitChar() {
+ // TODO
+ }
+
+ @Override
+ public void proceedAfterWildChar(String str) {
+ // TODO
+ }
+
+ @Override
+ public void cancelPostDial() {
+ // TODO
+ }
+
+ protected abstract Phone getPhone();
+
+ DisconnectCause disconnectCauseFromCode(int causeCode) {
+ /**
+ * See 22.001 Annex F.4 for mapping of cause codes
+ * to local tones
+ */
+
+ switch (causeCode) {
+ case CallFailCause.USER_BUSY:
+ return DisconnectCause.BUSY;
+
+ 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:
+ default:
+ Phone phone = getPhone();
+ int serviceState = phone.getServiceState().getState();
+ if (serviceState == ServiceState.STATE_POWER_OFF) {
+ return DisconnectCause.POWER_OFF;
+ } else if (serviceState == ServiceState.STATE_OUT_OF_SERVICE
+ || serviceState == ServiceState.STATE_EMERGENCY_ONLY ) {
+ return DisconnectCause.OUT_OF_SERVICE;
+ } else if (causeCode == CallFailCause.ERROR_UNSPECIFIED) {
+ return DisconnectCause.ERROR_UNSPECIFIED;
+ } else if (causeCode == CallFailCause.NORMAL_CLEARING) {
+ return DisconnectCause.NORMAL;
+ } else {
+ // If nothing else matches, report unknown call drop reason
+ // to app, not NORMAL call end.
+ return DisconnectCause.ERROR_UNSPECIFIED;
+ }
+ }
+ }
+
+ @Override
+ public String getRemainingPostDialString() {
+ if (postDialState == PostDialState.CANCELLED
+ || postDialState == PostDialState.COMPLETE
+ || postDialString == null
+ || postDialString.length() <= nextPostDialChar) {
+ return "";
+ }
+
+ return postDialString.substring(nextPostDialChar);
+ }
+
+ private void log(String msg) {
+ Log.d(LOG_TAG, "[SipConn] " + msg);
+ }
+
+ @Override
+ public int getNumberPresentation() {
+ // TODO: add PRESENTATION_URL
+ return Connection.PRESENTATION_ALLOWED;
+ }
+
+ /*
+ @Override
+ public UUSInfo getUUSInfo() {
+ // FIXME: what's this for SIP?
+ return null;
+ }
+ */
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
new file mode 100755
index 000000000000..943f21c9e546
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -0,0 +1,846 @@
+/*
+ * Copyright (C) 2010 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.sip;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.net.rtp.AudioGroup;
+import android.net.rtp.AudioStream;
+import android.net.sip.SipAudioCall;
+import android.net.sip.SipErrorCode;
+import android.net.sip.SipException;
+import android.net.sip.SipManager;
+import android.net.sip.SipProfile;
+import android.net.sip.SipSessionState;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.os.SystemProperties;
+import android.preference.PreferenceManager;
+import android.provider.Telephony;
+import android.telephony.CellLocation;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallerInfo;
+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;
+import com.android.internal.telephony.IccSmsInterfaceManager;
+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.TelephonyProperties;
+import com.android.internal.telephony.UUSInfo;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@hide}
+ */
+public class SipPhone extends SipPhoneBase {
+ private static final String LOG_TAG = "SipPhone";
+ private static final boolean LOCAL_DEBUG = true;
+
+ // A call that is ringing or (call) waiting
+ private SipCall ringingCall = new SipCall();
+ private SipCall foregroundCall = new SipCall();
+ private SipCall backgroundCall = new SipCall();
+
+ private SipManager mSipManager;
+ private SipProfile mProfile;
+
+ SipPhone (Context context, PhoneNotifier notifier, SipProfile profile) {
+ super(context, notifier);
+
+ Log.v(LOG_TAG, " +++++++++++++++++++++ new SipPhone: " + profile.getUriString());
+ ringingCall = new SipCall();
+ foregroundCall = new SipCall();
+ backgroundCall = new SipCall();
+ mProfile = profile;
+ mSipManager = SipManager.getInstance(context);
+
+ // FIXME: what's this for SIP?
+ //Change the system property
+ //SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
+ // new Integer(Phone.PHONE_TYPE_GSM).toString());
+ }
+
+ public String getPhoneName() {
+ return "SIP:" + getUriString(mProfile);
+ }
+
+ public String getSipUri() {
+ return mProfile.getUriString();
+ }
+
+ public boolean equals(SipPhone phone) {
+ return getSipUri().equals(phone.getSipUri());
+ }
+
+ public boolean canTake(Object incomingCall) {
+ synchronized (SipPhone.class) {
+ if (!(incomingCall instanceof SipAudioCall)) return false;
+ if (ringingCall.getState().isAlive()) return false;
+
+ // FIXME: is it true that we cannot take any incoming call if
+ // both foreground and background are active
+ if (foregroundCall.getState().isAlive()
+ && backgroundCall.getState().isAlive()) {
+ return false;
+ }
+
+ SipAudioCall sipAudioCall = (SipAudioCall) incomingCall;
+ Log.v(LOG_TAG, " ++++++ taking call from: "
+ + sipAudioCall.getPeerProfile().getUriString());
+ String localUri = sipAudioCall.getLocalProfile().getUriString();
+ if (localUri.equals(mProfile.getUriString())) {
+ boolean makeCallWait = foregroundCall.getState().isAlive();
+ ringingCall.initIncomingCall(sipAudioCall, makeCallWait);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ public void acceptCall() throws CallStateException {
+ synchronized (SipPhone.class) {
+ // 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() == Call.State.INCOMING) {
+ Log.v(LOG_TAG, "acceptCall");
+ // Always unmute when answering a new call
+ setMute(false);
+ // make ringingCall foreground
+ foregroundCall.switchWith(ringingCall);
+ foregroundCall.acceptCall();
+ } else if (ringingCall.getState() == Call.State.WAITING) {
+ setMute(false);
+ switchHoldingAndActive();
+ // make ringingCall foreground
+ foregroundCall.switchWith(ringingCall);
+ foregroundCall.acceptCall();
+ } else {
+ throw new CallStateException("phone not ringing");
+ }
+ }
+ }
+
+ public void rejectCall() throws CallStateException {
+ synchronized (SipPhone.class) {
+ if (ringingCall.getState().isRinging()) {
+ Log.v(LOG_TAG, "rejectCall");
+ ringingCall.rejectCall();
+ } else {
+ throw new CallStateException("phone not ringing");
+ }
+ }
+ }
+
+ public Connection dial(String dialString, UUSInfo uusinfo) throws CallStateException {
+ return dial(dialString);
+ }
+
+ public Connection dial(String dialString) throws CallStateException {
+ synchronized (SipPhone.class) {
+ return dialInternal(dialString);
+ }
+ }
+
+ private Connection dialInternal(String dialString)
+ throws CallStateException {
+ // TODO: parse SIP URL?
+ // Need to make sure dialString gets parsed properly
+ //String newDialString = PhoneNumberUtils.stripSeparators(dialString);
+ //return mCT.dial(newDialString);
+ clearDisconnected();
+
+ if (!canDial()) {
+ throw new CallStateException("cannot dial in current state");
+ }
+ if (foregroundCall.getState() == SipCall.State.ACTIVE) {
+ switchHoldingAndActive();
+ }
+ if (foregroundCall.getState() != SipCall.State.IDLE) {
+ //we should have failed in !canDial() above before we get here
+ throw new CallStateException("cannot dial in current state");
+ }
+
+ setMute(false);
+ //cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
+ try {
+ Connection c = foregroundCall.dial(dialString);
+ return c;
+ } catch (SipException e) {
+ Log.e(LOG_TAG, "dial()", e);
+ throw new CallStateException("dial error: " + e);
+ }
+ }
+
+ public void switchHoldingAndActive() throws CallStateException {
+ Log.v(LOG_TAG, " ~~~~~~ switch fg and bg");
+ synchronized (SipPhone.class) {
+ foregroundCall.switchWith(backgroundCall);
+ if (backgroundCall.getState().isAlive()) backgroundCall.hold();
+ if (foregroundCall.getState().isAlive()) foregroundCall.unhold();
+ }
+ }
+
+ public boolean canConference() {
+ return true;
+ }
+
+ public void conference() throws CallStateException {
+ synchronized (SipPhone.class) {
+ if ((foregroundCall.getState() != SipCall.State.ACTIVE)
+ || (foregroundCall.getState() != SipCall.State.ACTIVE)) {
+ throw new CallStateException("wrong state to merge calls: fg="
+ + foregroundCall.getState() + ", bg="
+ + backgroundCall.getState());
+ }
+ foregroundCall.merge(backgroundCall);
+ }
+ }
+
+ public void conference(Call that) throws CallStateException {
+ synchronized (SipPhone.class) {
+ if (!(that instanceof SipCall)) {
+ throw new CallStateException("expect " + SipCall.class
+ + ", cannot merge with " + that.getClass());
+ }
+ foregroundCall.merge((SipCall) that);
+ }
+ }
+
+ public boolean canTransfer() {
+ return false;
+ }
+
+ public void explicitCallTransfer() throws CallStateException {
+ //mCT.explicitCallTransfer();
+ }
+
+ public void clearDisconnected() {
+ synchronized (SipPhone.class) {
+ ringingCall.clearDisconnected();
+ foregroundCall.clearDisconnected();
+ backgroundCall.clearDisconnected();
+
+ updatePhoneState();
+ notifyPreciseCallStateChanged();
+ }
+ }
+
+ public void sendDtmf(char c) {
+ if (!PhoneNumberUtils.is12Key(c)) {
+ Log.e(LOG_TAG,
+ "sendDtmf called with invalid character '" + c + "'");
+ } else if (foregroundCall.getState().isAlive()) {
+ synchronized (SipPhone.class) {
+ foregroundCall.sendDtmf(c);
+ }
+ }
+ }
+
+ public void startDtmf(char c) {
+ if (!PhoneNumberUtils.is12Key(c)) {
+ Log.e(LOG_TAG,
+ "startDtmf called with invalid character '" + c + "'");
+ } else {
+ sendDtmf(c);
+ }
+ }
+
+ public void stopDtmf() {
+ // no op
+ }
+
+ public void sendBurstDtmf(String dtmfString) {
+ Log.e(LOG_TAG, "[SipPhone] sendBurstDtmf() is a CDMA method");
+ }
+
+ public void getOutgoingCallerIdDisplay(Message onComplete) {
+ // FIXME: what to reply?
+ AsyncResult.forMessage(onComplete, null, null);
+ onComplete.sendToTarget();
+ }
+
+ public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
+ Message onComplete) {
+ // FIXME: what's this for SIP?
+ AsyncResult.forMessage(onComplete, null, null);
+ onComplete.sendToTarget();
+ }
+
+ public void getCallWaiting(Message onComplete) {
+ // FIXME: what to reply?
+ AsyncResult.forMessage(onComplete, null, null);
+ onComplete.sendToTarget();
+ }
+
+ public void setCallWaiting(boolean enable, Message onComplete) {
+ // FIXME: what to reply?
+ Log.e(LOG_TAG, "call waiting not supported");
+ }
+
+ public void setMute(boolean muted) {
+ synchronized (SipPhone.class) {
+ foregroundCall.setMute(muted);
+ }
+ }
+
+ public boolean getMute() {
+ return foregroundCall.getMute();
+ }
+
+ public Call getForegroundCall() {
+ return foregroundCall;
+ }
+
+ public Call getBackgroundCall() {
+ return backgroundCall;
+ }
+
+ public Call getRingingCall() {
+ return ringingCall;
+ }
+
+ public ServiceState getServiceState() {
+ // FIXME: we may need to provide this when data connectivity is lost
+ // or when server is down
+ return super.getServiceState();
+ }
+
+ private String getUriString(SipProfile p) {
+ // SipProfile.getUriString() may contain "SIP:" and port
+ return p.getUserName() + "@" + getSipDomain(p);
+ }
+
+ private String getSipDomain(SipProfile p) {
+ String domain = p.getSipDomain();
+ // TODO: move this to SipProfile
+ if (domain.endsWith(":5060")) {
+ return domain.substring(0, domain.length() - 5);
+ } else {
+ return domain;
+ }
+ }
+
+ private class SipCall extends SipCallBase {
+ void switchWith(SipCall that) {
+ synchronized (SipPhone.class) {
+ SipCall tmp = new SipCall();
+ tmp.takeOver(this);
+ this.takeOver(that);
+ that.takeOver(tmp);
+ }
+ }
+
+ private void takeOver(SipCall that) {
+ connections = that.connections;
+ state = that.state;
+ for (Connection c : connections) {
+ ((SipConnection) c).changeOwner(this);
+ }
+ }
+
+ @Override
+ public Phone getPhone() {
+ return SipPhone.this;
+ }
+
+ @Override
+ public List<Connection> getConnections() {
+ synchronized (SipPhone.class) {
+ // FIXME should return Collections.unmodifiableList();
+ return connections;
+ }
+ }
+
+ private CallerInfo getCallerInfo(String number) {
+ CallerInfo info = CallerInfo.getCallerInfo(mContext, number);
+ if ((info == null) || (info.name == null)) return null;
+ Log.v(LOG_TAG, "++******++ got info from contact:");
+ Log.v(LOG_TAG, " name: " + info.name);
+ Log.v(LOG_TAG, " numb: " + info.phoneNumber);
+ Log.v(LOG_TAG, " pres: " + info.numberPresentation);
+ return info;
+ }
+
+ Connection dial(String calleeSipUri) throws SipException {
+ CallerInfo info = getCallerInfo(calleeSipUri);
+ if (!calleeSipUri.contains("@")) {
+ calleeSipUri += "@" + getSipDomain(mProfile);
+ if (info != null) info.phoneNumber = calleeSipUri;
+ }
+ try {
+ SipProfile callee =
+ new SipProfile.Builder(calleeSipUri).build();
+ SipConnection c = new SipConnection(this, callee, info);
+ connections.add(c);
+ c.dial();
+ setState(Call.State.DIALING);
+ return c;
+ } catch (ParseException e) {
+ // TODO: notify someone
+ throw new SipException("dial", e);
+ }
+ }
+
+ @Override
+ public void hangup() throws CallStateException {
+ synchronized (SipPhone.class) {
+ Log.v(LOG_TAG, "hang up call: " + getState() + ": " + this
+ + " on phone " + getPhone());
+ CallStateException excp = null;
+ for (Connection c : connections) {
+ try {
+ c.hangup();
+ } catch (CallStateException e) {
+ excp = e;
+ }
+ }
+ if (excp != null) throw excp;
+ setState(State.DISCONNECTING);
+ }
+ }
+
+ void initIncomingCall(SipAudioCall sipAudioCall, boolean makeCallWait) {
+ SipProfile callee = sipAudioCall.getPeerProfile();
+ CallerInfo info = getCallerInfo(getUriString(callee));
+ if (info == null) info = getCallerInfo(callee.getUserName());
+ if (info == null) info = getCallerInfo(callee.getDisplayName());
+ SipConnection c = new SipConnection(this, callee, info);
+ connections.add(c);
+
+ Call.State newState = makeCallWait ? State.WAITING : State.INCOMING;
+ c.initIncomingCall(sipAudioCall, newState);
+
+ setState(newState);
+ notifyNewRingingConnectionP(c);
+ }
+
+ void rejectCall() throws CallStateException {
+ hangup();
+ }
+
+ void acceptCall() throws CallStateException {
+ if (this != foregroundCall) {
+ throw new CallStateException("acceptCall() in a non-fg call");
+ }
+ if (connections.size() != 1) {
+ throw new CallStateException("acceptCall() in a conf call");
+ }
+ ((SipConnection) connections.get(0)).acceptCall();
+ }
+
+ void hold() throws CallStateException {
+ setState(State.HOLDING);
+ AudioGroup audioGroup = getAudioGroup();
+ if (audioGroup != null) {
+ audioGroup.setMode(AudioGroup.MODE_ON_HOLD);
+ }
+ for (Connection c : connections) ((SipConnection) c).hold();
+ }
+
+ void unhold() throws CallStateException {
+ setState(State.ACTIVE);
+ AudioGroup audioGroup = new AudioGroup();
+ for (Connection c : connections) {
+ ((SipConnection) c).unhold(audioGroup);
+ }
+ }
+
+ void setMute(boolean muted) {
+ AudioGroup audioGroup = getAudioGroup();
+ if (audioGroup == null) return;
+ audioGroup.setMode(
+ muted ? AudioGroup.MODE_MUTED : AudioGroup.MODE_NORMAL);
+ }
+
+ boolean getMute() {
+ AudioGroup audioGroup = getAudioGroup();
+ if (audioGroup == null) return false;
+ return (audioGroup.getMode() == AudioGroup.MODE_MUTED);
+ }
+
+ void merge(SipCall that) throws CallStateException {
+ AudioGroup audioGroup = getAudioGroup();
+ for (Connection c : that.connections) {
+ SipConnection conn = (SipConnection) c;
+ add(conn);
+ if (conn.getState() == Call.State.HOLDING) {
+ conn.unhold(audioGroup);
+ }
+ }
+ that.setState(Call.State.IDLE);
+ }
+
+ private void add(SipConnection conn) {
+ SipCall call = conn.getCall();
+ if (call == this) return;
+ if (call != null) call.connections.remove(conn);
+
+ connections.add(conn);
+ conn.changeOwner(this);
+ }
+
+ void sendDtmf(char c) {
+ AudioGroup audioGroup = getAudioGroup();
+ if (audioGroup == null) return;
+ audioGroup.sendDtmf(convertDtmf(c));
+ }
+
+ private int convertDtmf(char c) {
+ int code = c - '0';
+ if ((code < 0) || (code > 9)) {
+ switch (c) {
+ case '*': return 10;
+ case '#': return 11;
+ case 'A': return 12;
+ case 'B': return 13;
+ case 'C': return 14;
+ case 'D': return 15;
+ default:
+ throw new IllegalArgumentException(
+ "invalid DTMF char: " + (int) c);
+ }
+ }
+ return code;
+ }
+
+ @Override
+ protected void setState(State newState) {
+ if (state != newState) {
+ Log.v(LOG_TAG, "++******++ call state changed: " + state
+ + " --> " + newState + ": " + this + ": on phone "
+ + getPhone() + " " + connections.size());
+
+ if (newState == Call.State.ALERTING) {
+ state = newState; // need in ALERTING to enable ringback
+ SipPhone.this.startRingbackTone();
+ } else if (state == Call.State.ALERTING) {
+ SipPhone.this.stopRingbackTone();
+ }
+ state = newState;
+ updatePhoneState();
+ notifyPreciseCallStateChanged();
+ }
+ }
+
+ void onConnectionStateChanged(SipConnection conn) {
+ // this can be called back when a conf call is formed
+ if (state != State.ACTIVE) {
+ setState(conn.getState());
+ }
+ }
+
+ void onConnectionEnded(SipConnection conn) {
+ // set state to DISCONNECTED only when all conns are disconnected
+ if (state != State.DISCONNECTED) {
+ boolean allConnectionsDisconnected = true;
+ for (Connection c : connections) {
+ if (c.getState() != State.DISCONNECTED) {
+ allConnectionsDisconnected = false;
+ break;
+ }
+ }
+ if (allConnectionsDisconnected) setState(State.DISCONNECTED);
+ }
+ notifyDisconnectP(conn);
+ }
+
+ private AudioGroup getAudioGroup() {
+ if (connections.isEmpty()) return null;
+ return ((SipConnection) connections.get(0)).getAudioGroup();
+ }
+ }
+
+ private class SipConnection extends SipConnectionBase {
+ private SipCall mOwner;
+ private SipAudioCall mSipAudioCall;
+ private Call.State mState = Call.State.IDLE;
+ private SipProfile mPeer;
+ private boolean mIncoming = false;
+
+ private SipAudioCallAdapter mAdapter = new SipAudioCallAdapter() {
+ @Override
+ protected void onCallEnded(DisconnectCause cause) {
+ if (getDisconnectCause() != DisconnectCause.LOCAL) {
+ setDisconnectCause(cause);
+ }
+ synchronized (SipPhone.class) {
+ setState(Call.State.DISCONNECTED);
+ mOwner.onConnectionEnded(SipConnection.this);
+ Log.v(LOG_TAG, "-------- connection ended: "
+ + mPeer.getUriString() + ": "
+ + mSipAudioCall.getState() + ", cause: "
+ + getDisconnectCause() + ", on phone "
+ + getPhone());
+ }
+ }
+
+ @Override
+ public void onChanged(SipAudioCall call) {
+ synchronized (SipPhone.class) {
+ Call.State newState = getCallStateFrom(call);
+ if (mState == newState) return;
+ if (newState == Call.State.INCOMING) {
+ setState(mOwner.getState()); // INCOMING or WAITING
+ } else {
+ setState(newState);
+ }
+ mOwner.onConnectionStateChanged(SipConnection.this);
+ Log.v(LOG_TAG, "++******++ connection state changed: "
+ + mPeer.getUriString() + ": " + mState
+ + " on phone " + getPhone());
+ }
+ }
+
+ @Override
+ protected void onError(DisconnectCause cause) {
+ Log.w(LOG_TAG, "SIP error: " + cause);
+ if (mSipAudioCall.isInCall()
+ && (cause != DisconnectCause.LOST_SIGNAL)) {
+ // Don't end the call when in a call.
+ return;
+ }
+
+ onCallEnded(cause);
+ }
+ };
+
+ public SipConnection(SipCall owner, SipProfile callee,
+ CallerInfo info) {
+ super(getUriString(callee));
+ mOwner = owner;
+ mPeer = callee;
+ if (info == null) info = createCallerInfo();
+ setUserData(info);
+ }
+
+ private CallerInfo createCallerInfo() {
+ SipProfile p = mPeer;
+ String name = p.getDisplayName();
+ if (TextUtils.isEmpty(name)) name = p.getUserName();
+ CallerInfo info = new CallerInfo();
+ info.name = name;
+ info.phoneNumber = getUriString(p);
+ return info;
+ }
+
+ void initIncomingCall(SipAudioCall sipAudioCall, Call.State newState) {
+ setState(newState);
+ mSipAudioCall = sipAudioCall;
+ sipAudioCall.setListener(mAdapter); // call back to set state
+ mIncoming = true;
+ }
+
+ void acceptCall() throws CallStateException {
+ try {
+ mSipAudioCall.answerCall();
+ } catch (SipException e) {
+ throw new CallStateException("acceptCall(): " + e);
+ }
+ }
+
+ void changeOwner(SipCall owner) {
+ mOwner = owner;
+ }
+
+ AudioGroup getAudioGroup() {
+ if (mSipAudioCall == null) return null;
+ return mSipAudioCall.getAudioGroup();
+ }
+
+ void dial() throws SipException {
+ setState(Call.State.DIALING);
+ mSipAudioCall = mSipManager.makeAudioCall(mContext, mProfile,
+ mPeer, null);
+ mSipAudioCall.setRingbackToneEnabled(false);
+ mSipAudioCall.setListener(mAdapter);
+ }
+
+ void hold() throws CallStateException {
+ setState(Call.State.HOLDING);
+ try {
+ mSipAudioCall.holdCall();
+ } catch (SipException e) {
+ throw new CallStateException("hold(): " + e);
+ }
+ }
+
+ void unhold(AudioGroup audioGroup) throws CallStateException {
+ mSipAudioCall.setAudioGroup(audioGroup);
+ setState(Call.State.ACTIVE);
+ try {
+ mSipAudioCall.continueCall();
+ } catch (SipException e) {
+ throw new CallStateException("unhold(): " + e);
+ }
+ }
+
+ @Override
+ protected void setState(Call.State state) {
+ if (state == mState) return;
+ super.setState(state);
+ mState = state;
+ }
+
+ @Override
+ public Call.State getState() {
+ return mState;
+ }
+
+ @Override
+ public boolean isIncoming() {
+ return mIncoming;
+ }
+
+ @Override
+ public String getAddress() {
+ return getUriString(mPeer);
+ }
+
+ @Override
+ public SipCall getCall() {
+ return mOwner;
+ }
+
+ @Override
+ protected Phone getPhone() {
+ return mOwner.getPhone();
+ }
+
+ @Override
+ public void hangup() throws CallStateException {
+ synchronized (SipPhone.class) {
+ Log.v(LOG_TAG, "hangup conn: " + mPeer.getUriString() + ": "
+ + ": on phone " + getPhone().getPhoneName());
+ try {
+ mSipAudioCall.endCall();
+ setState(Call.State.DISCONNECTING);
+ setDisconnectCause(DisconnectCause.LOCAL);
+ } catch (SipException e) {
+ throw new CallStateException("hangup(): " + e);
+ }
+ }
+ }
+
+ @Override
+ public void separate() throws CallStateException {
+ synchronized (SipPhone.class) {
+ SipCall call = (SipCall) SipPhone.this.getBackgroundCall();
+ if (call.getState() != Call.State.IDLE) {
+ throw new CallStateException(
+ "cannot put conn back to a call in non-idle state: "
+ + call.getState());
+ }
+ Log.v(LOG_TAG, "separate conn: " + mPeer.getUriString()
+ + " from " + mOwner + " back to " + call);
+
+ AudioGroup audioGroup = call.getAudioGroup(); // may be null
+ call.add(this);
+ mSipAudioCall.setAudioGroup(audioGroup);
+ call.hold();
+ }
+ }
+
+ @Override
+ public UUSInfo getUUSInfo() {
+ return null;
+ }
+ }
+
+ private static Call.State getCallStateFrom(SipAudioCall sipAudioCall) {
+ if (sipAudioCall.isOnHold()) return Call.State.HOLDING;
+ SipSessionState sessionState = sipAudioCall.getState();
+ switch (sessionState) {
+ case READY_TO_CALL: return Call.State.IDLE;
+ case INCOMING_CALL:
+ case INCOMING_CALL_ANSWERING: return Call.State.INCOMING;
+ case OUTGOING_CALL: return Call.State.DIALING;
+ case OUTGOING_CALL_RING_BACK: return Call.State.ALERTING;
+ case OUTGOING_CALL_CANCELING: return Call.State.DISCONNECTING;
+ case IN_CALL: return Call.State.ACTIVE;
+ default:
+ Log.w(LOG_TAG, "illegal connection state: " + sessionState);
+ return Call.State.DISCONNECTED;
+ }
+ }
+
+ private abstract class SipAudioCallAdapter extends SipAudioCall.Adapter {
+ protected abstract void onCallEnded(Connection.DisconnectCause cause);
+ protected abstract void onError(Connection.DisconnectCause cause);
+
+ @Override
+ public void onCallEnded(SipAudioCall call) {
+ onCallEnded(Connection.DisconnectCause.NORMAL);
+ }
+
+ @Override
+ public void onCallBusy(SipAudioCall call) {
+ onCallEnded(Connection.DisconnectCause.BUSY);
+ }
+
+ @Override
+ public void onError(SipAudioCall call, SipErrorCode errorCode,
+ String errorMessage) {
+ switch (errorCode) {
+ case INVALID_REMOTE_URI:
+ onError(Connection.DisconnectCause.INVALID_NUMBER);
+ break;
+ case TIME_OUT:
+ case TRANSACTION_TERMINTED:
+ onError(Connection.DisconnectCause.TIMED_OUT);
+ break;
+ case DATA_CONNECTION_LOST:
+ onError(Connection.DisconnectCause.LOST_SIGNAL);
+ break;
+ case INVALID_CREDENTIALS:
+ onError(Connection.DisconnectCause.INVALID_CREDENTIALS);
+ break;
+ case SOCKET_ERROR:
+ case SERVER_ERROR:
+ case CLIENT_ERROR:
+ default:
+ onError(Connection.DisconnectCause.ERROR_UNSPECIFIED);
+ }
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
new file mode 100755
index 000000000000..9098e6ffb154
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2010 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.sip;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.os.SystemProperties;
+import android.preference.PreferenceManager;
+import android.provider.Telephony;
+import android.telephony.CellLocation;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.ServiceState;
+import android.telephony.SignalStrength;
+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.Call;
+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;
+import com.android.internal.telephony.IccSmsInterfaceManager;
+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.TelephonyProperties;
+//import com.android.internal.telephony.UUSInfo;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+abstract class SipPhoneBase extends PhoneBase {
+ // NOTE that LOG_TAG here is "Sip", which means that log messages
+ // 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 = "SipPhone";
+ private static final boolean LOCAL_DEBUG = true;
+
+ //SipCallTracker mCT;
+ PhoneSubInfo mSubInfo;
+
+ Registrant mPostDialHandler;
+
+ final RegistrantList mRingbackRegistrants = new RegistrantList();
+
+ private State state = State.IDLE;
+
+ public SipPhoneBase(Context context, PhoneNotifier notifier) {
+ super(notifier, context, new SipCommandInterface(context), false);
+
+ // FIXME: what's this for SIP?
+ //Change the system property
+ //SystemProperties.set(TelephonyProperties.CURRENT_ACTIVE_PHONE,
+ // new Integer(Phone.PHONE_TYPE_GSM).toString());
+ }
+
+ public abstract Call getForegroundCall();
+
+ public abstract Call getBackgroundCall();
+
+ public abstract Call getRingingCall();
+
+ /*
+ public Connection dial(String dialString, UUSInfo uusInfo)
+ throws CallStateException {
+ // ignore UUSInfo
+ return dial(dialString);
+ }
+ */
+
+ void migrateFrom(SipPhoneBase from) {
+ migrate(mRingbackRegistrants, from.mRingbackRegistrants);
+ migrate(mPreciseCallStateRegistrants, from.mPreciseCallStateRegistrants);
+ migrate(mNewRingingConnectionRegistrants, from.mNewRingingConnectionRegistrants);
+ migrate(mIncomingRingRegistrants, from.mIncomingRingRegistrants);
+ migrate(mDisconnectRegistrants, from.mDisconnectRegistrants);
+ migrate(mServiceStateRegistrants, from.mServiceStateRegistrants);
+ migrate(mMmiCompleteRegistrants, from.mMmiCompleteRegistrants);
+ migrate(mMmiRegistrants, from.mMmiRegistrants);
+ migrate(mUnknownConnectionRegistrants, from.mUnknownConnectionRegistrants);
+ migrate(mSuppServiceFailedRegistrants, from.mSuppServiceFailedRegistrants);
+ }
+
+ static void migrate(RegistrantList to, RegistrantList from) {
+ from.removeCleared();
+ for (int i = 0, n = from.size(); i < n; i++) {
+ to.add((Registrant) from.get(i));
+ }
+ }
+
+ @Override
+ public void registerForRingbackTone(Handler h, int what, Object obj) {
+ mRingbackRegistrants.addUnique(h, what, obj);
+ }
+
+ @Override
+ public void unregisterForRingbackTone(Handler h) {
+ mRingbackRegistrants.remove(h);
+ }
+
+ protected void startRingbackTone() {
+ AsyncResult result = new AsyncResult(null, new Boolean(true), null);
+ mRingbackRegistrants.notifyRegistrants(result);
+ }
+
+ protected void stopRingbackTone() {
+ AsyncResult result = new AsyncResult(null, new Boolean(false), null);
+ mRingbackRegistrants.notifyRegistrants(result);
+ }
+
+ public void dispose() {
+ mIsTheCurrentActivePhone = false;
+ mSubInfo.dispose();
+ }
+
+ public void removeReferences() {
+ mSubInfo = null;
+ }
+
+ public ServiceState getServiceState() {
+ // FIXME: we may need to provide this when data connectivity is lost
+ // or when server is down
+ ServiceState s = new ServiceState();
+ s.setState(ServiceState.STATE_IN_SERVICE);
+ return s;
+ }
+
+ public CellLocation getCellLocation() {
+ return null; //mSST.cellLoc;
+ }
+
+ public State getState() {
+ return state;
+ }
+
+ public int getPhoneType() {
+ return Phone.PHONE_TYPE_SIP;
+ }
+
+ public SignalStrength getSignalStrength() {
+ return new SignalStrength();
+ }
+
+ public boolean getMessageWaitingIndicator() {
+ return false;
+ }
+
+ public boolean getCallForwardingIndicator() {
+ return false;
+ }
+
+ public List<? extends MmiCode> getPendingMmiCodes() {
+ return new ArrayList<MmiCode>(0);
+ }
+
+ public DataState getDataConnectionState() {
+ return DataState.DISCONNECTED;
+ }
+
+ public DataState getDataConnectionState(String apnType) {
+ return DataState.DISCONNECTED;
+ }
+
+ public DataActivityState getDataActivityState() {
+ return DataActivityState.NONE;
+ }
+
+ /**
+ * Notify any interested party of a Phone state change {@link Phone.State}
+ */
+ void notifyPhoneStateChanged() {
+ mNotifier.notifyPhoneState(this);
+ }
+
+ /**
+ * Notify registrants of a change in the call state. This notifies changes in {@link Call.State}
+ * Use this when changes in the precise call state are needed, else use notifyPhoneStateChanged.
+ */
+ void notifyPreciseCallStateChanged() {
+ /* we'd love it if this was package-scoped*/
+ super.notifyPreciseCallStateChangedP();
+ }
+
+ void notifyNewRingingConnection(Connection c) {
+ /* we'd love it if this was package-scoped*/
+ super.notifyNewRingingConnectionP(c);
+ }
+
+ void notifyDisconnect(Connection cn) {
+ mDisconnectRegistrants.notifyResult(cn);
+ }
+
+ void notifyUnknownConnection() {
+ mUnknownConnectionRegistrants.notifyResult(this);
+ }
+
+ void notifySuppServiceFailed(SuppService code) {
+ mSuppServiceFailedRegistrants.notifyResult(code);
+ }
+
+ void notifyServiceStateChanged(ServiceState ss) {
+ super.notifyServiceStateChangedP(ss);
+ }
+
+ public void notifyCallForwardingIndicator() {
+ mNotifier.notifyCallForwardingChanged(this);
+ }
+
+ public boolean canDial() {
+ int serviceState = getServiceState().getState();
+ Log.v(LOG_TAG, "canDial(): serviceState = " + serviceState);
+ if (serviceState == ServiceState.STATE_POWER_OFF) return false;
+
+ String disableCall = SystemProperties.get(
+ TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
+ Log.v(LOG_TAG, "canDial(): disableCall = " + disableCall);
+ if (disableCall.equals("true")) return false;
+
+ Log.v(LOG_TAG, "canDial(): ringingCall: " + getRingingCall().getState());
+ Log.v(LOG_TAG, "canDial(): foregndCall: " + getForegroundCall().getState());
+ Log.v(LOG_TAG, "canDial(): backgndCall: " + getBackgroundCall().getState());
+ return !getRingingCall().isRinging()
+ && (!getForegroundCall().getState().isAlive()
+ || !getBackgroundCall().getState().isAlive());
+ }
+
+ public boolean handleInCallMmiCommands(String dialString)
+ throws CallStateException {
+ return false;
+ }
+
+ boolean isInCall() {
+ Call.State foregroundCallState = getForegroundCall().getState();
+ Call.State backgroundCallState = getBackgroundCall().getState();
+ Call.State ringingCallState = getRingingCall().getState();
+
+ return (foregroundCallState.isAlive() || backgroundCallState.isAlive()
+ || ringingCallState.isAlive());
+ }
+
+ public boolean handlePinMmi(String dialString) {
+ return false;
+ }
+
+ public void sendUssdResponse(String ussdMessge) {
+ }
+
+ public void registerForSuppServiceNotification(
+ Handler h, int what, Object obj) {
+ }
+
+ public void unregisterForSuppServiceNotification(Handler h) {
+ }
+
+ public void setRadioPower(boolean power) {
+ }
+
+ public String getVoiceMailNumber() {
+ return null;
+ }
+
+ public String getVoiceMailAlphaTag() {
+ return null;
+ }
+
+ public String getDeviceId() {
+ return null;
+ }
+
+ public String getDeviceSvn() {
+ return null;
+ }
+
+ public String getEsn() {
+ Log.e(LOG_TAG, "[SipPhone] getEsn() is a CDMA method");
+ return "0";
+ }
+
+ public String getMeid() {
+ Log.e(LOG_TAG, "[SipPhone] getMeid() is a CDMA method");
+ return "0";
+ }
+
+ public String getSubscriberId() {
+ return null;
+ }
+
+ public String getIccSerialNumber() {
+ return null;
+ }
+
+ public String getLine1Number() {
+ return null;
+ }
+
+ public String getLine1AlphaTag() {
+ return null;
+ }
+
+ public void setLine1Number(String alphaTag, String number, Message onComplete) {
+ // FIXME: what to reply for SIP?
+ AsyncResult.forMessage(onComplete, null, null);
+ onComplete.sendToTarget();
+ }
+
+ public void setVoiceMailNumber(String alphaTag, String voiceMailNumber,
+ Message onComplete) {
+ // FIXME: what to reply for SIP?
+ AsyncResult.forMessage(onComplete, null, null);
+ onComplete.sendToTarget();
+ }
+
+ 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)) {
+ // FIXME: what to reply?
+ AsyncResult.forMessage(onComplete, null, null);
+ onComplete.sendToTarget();
+ }
+ }
+
+ public void setCallForwardingOption(int commandInterfaceCFAction,
+ int commandInterfaceCFReason, String dialingNumber,
+ int timerSeconds, Message onComplete) {
+ if (isValidCommandInterfaceCFAction(commandInterfaceCFAction)
+ && isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
+ // FIXME: what to reply?
+ AsyncResult.forMessage(onComplete, null, null);
+ onComplete.sendToTarget();
+ }
+ }
+
+ public void getOutgoingCallerIdDisplay(Message onComplete) {
+ // FIXME: what to reply?
+ AsyncResult.forMessage(onComplete, null, null);
+ onComplete.sendToTarget();
+ }
+
+ public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
+ Message onComplete) {
+ // FIXME: what's this for SIP?
+ AsyncResult.forMessage(onComplete, null, null);
+ onComplete.sendToTarget();
+ }
+
+ public void getCallWaiting(Message onComplete) {
+ // FIXME: what to reply?
+ AsyncResult.forMessage(onComplete, null, null);
+ onComplete.sendToTarget();
+ }
+
+ public void setCallWaiting(boolean enable, Message onComplete) {
+ // FIXME: what to reply?
+ Log.e(LOG_TAG, "call waiting not supported");
+ }
+
+ public boolean getIccRecordsLoaded() {
+ return false;
+ }
+
+ public IccCard getIccCard() {
+ return null;
+ }
+
+ public void getAvailableNetworks(Message response) {
+ // FIXME: what to reply?
+ }
+
+ public void setNetworkSelectionModeAutomatic(Message response) {
+ // FIXME: what to reply?
+ }
+
+ public void selectNetworkManually(
+ com.android.internal.telephony.gsm.NetworkInfo network,
+ Message response) {
+ // FIXME: what to reply?
+ }
+
+ public void getNeighboringCids(Message response) {
+ // FIXME: what to reply?
+ }
+
+ public void setOnPostDialCharacter(Handler h, int what, Object obj) {
+ mPostDialHandler = new Registrant(h, what, obj);
+ }
+
+ public void getDataCallList(Message response) {
+ // FIXME: what to reply?
+ }
+
+ public List<DataConnection> getCurrentDataConnectionList () {
+ return null;
+ }
+
+ public void updateServiceLocation() {
+ }
+
+ public void enableLocationUpdates() {
+ }
+
+ public void disableLocationUpdates() {
+ }
+
+ public boolean getDataRoamingEnabled() {
+ return false;
+ }
+
+ public void setDataRoamingEnabled(boolean enable) {
+ }
+
+ public boolean enableDataConnectivity() {
+ return false;
+ }
+
+ public boolean disableDataConnectivity() {
+ return false;
+ }
+
+ public boolean isDataConnectivityPossible() {
+ return false;
+ }
+
+ boolean updateCurrentCarrierInProvider() {
+ return false;
+ }
+
+ public void saveClirSetting(int commandInterfaceCLIRMode) {
+ // FIXME: what's this for SIP?
+ }
+
+ /**
+ * Retrieves the PhoneSubInfo of the SipPhone
+ */
+ public PhoneSubInfo getPhoneSubInfo(){
+ return mSubInfo;
+ }
+
+ /** {@inheritDoc} */
+ public IccSmsInterfaceManager getIccSmsInterfaceManager(){
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
+ return null;
+ }
+
+ /** {@inheritDoc} */
+ public IccFileHandler getIccFileHandler(){
+ return null;
+ }
+
+ public void activateCellBroadcastSms(int activate, Message response) {
+ Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP.");
+ }
+
+ public void getCellBroadcastSmsConfig(Message response) {
+ Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP.");
+ }
+
+ public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){
+ Log.e(LOG_TAG, "Error! This functionality is not implemented for SIP.");
+ }
+
+ void updatePhoneState() {
+ State oldState = state;
+
+ if (getRingingCall().isRinging()) {
+ state = State.RINGING;
+ } else if (getForegroundCall().isIdle()
+ && getBackgroundCall().isIdle()) {
+ state = State.IDLE;
+ } else {
+ state = State.OFFHOOK;
+ }
+ Log.e(LOG_TAG, " ^^^^^^ new phone state: " + state);
+
+ if (state != oldState) {
+ notifyPhoneStateChanged();
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java b/telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java
new file mode 100644
index 000000000000..611e3ea020ec
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhoneFactory.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 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.sip;
+
+import com.android.internal.telephony.PhoneNotifier;
+
+import android.content.Context;
+import android.net.sip.SipProfile;
+import android.util.Log;
+
+import java.text.ParseException;
+
+/**
+ * {@hide}
+ */
+public class SipPhoneFactory {
+ /**
+ * Makes a {@link SipPhone} object.
+ * @param sipUri the local SIP URI the phone runs on
+ * @param context {@code Context} needed to create a Phone object
+ * @param phoneNotifier {@code PhoneNotifier} needed to create a Phone
+ * object
+ * @return the {@code SipPhone} object or null if the SIP URI is not valid
+ */
+ public static SipPhone makePhone(String sipUri, Context context,
+ PhoneNotifier phoneNotifier) {
+ try {
+ SipProfile profile = new SipProfile.Builder(sipUri).build();
+ return new SipPhone(context, phoneNotifier, profile);
+ } catch (ParseException e) {
+ Log.w("SipPhoneFactory", "makePhone", e);
+ return null;
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index 11b3fd6fa12c..9c72e5a5052b 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -29,6 +29,7 @@ import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.DataCallState;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.UUSInfo;
import com.android.internal.telephony.gsm.CallFailCause;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
import com.android.internal.telephony.gsm.SuppServiceNotification;
@@ -496,6 +497,23 @@ public final class SimulatedCommands extends BaseCommands
* retMsg.obj = AsyncResult ar
* ar.exception carries exception on failure
* ar.userObject contains the orignal value of result.obj
+ * ar.result is null on success and failure
+ *
+ * CLIR_DEFAULT == on "use subscription default value"
+ * CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation)
+ * CLIR_INVOCATION == on "CLIR invocation" (restrict CLI presentation)
+ */
+ public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
+ simulatedCallState.onDial(address);
+
+ resultSuccess(result, null);
+ }
+
+ /**
+ * returned message
+ * retMsg.obj = AsyncResult ar
+ * ar.exception carries exception on failure
+ * ar.userObject contains the orignal value of result.obj
* ar.result is String containing IMSI on success
*/
public void getIMSI(Message result) {
@@ -826,7 +844,6 @@ public final class SimulatedCommands extends BaseCommands
ret[11] = null;
ret[12] = null;
ret[13] = null;
- ret[14] = null;
resultSuccess(result, ret);
}