AI 144245: Fix merge conflict for megering in the CDMA changes in to master from donutburger.
Automated import of CL 144245
This commit is contained in:
committed by
The Android Open Source Project
parent
3afdd56470
commit
04e71b3db8
@@ -19,8 +19,14 @@ package android.telephony;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.provider.Settings;
|
||||
|
||||
|
||||
import android.telephony.cdma.CdmaCellLocation;
|
||||
import android.telephony.gsm.GsmCellLocation;
|
||||
import com.android.internal.telephony.ITelephony;
|
||||
import com.android.internal.telephony.RILConstants;
|
||||
|
||||
/**
|
||||
* Abstract class that represents the location of the device. Currently the only
|
||||
@@ -56,7 +62,17 @@ public abstract class CellLocation {
|
||||
* @hide
|
||||
*/
|
||||
public static CellLocation newFromBundle(Bundle bundle) {
|
||||
return new GsmCellLocation(bundle);
|
||||
// TODO: My need to be use: Settings.Secure.getInt(mContext, Settings.Secure.CURRENT_ACTIVE_PHONE, 0))
|
||||
// instead of SystemProperties???
|
||||
|
||||
// NOTE here TelephonyManager.getDefault().getPhoneType() cannot be used since at startup
|
||||
// ITelephony have not been created
|
||||
if (RILConstants.CDMA_PHONE ==
|
||||
SystemProperties.getInt(Settings.Secure.CURRENT_ACTIVE_PHONE, 0)) {
|
||||
return new CdmaCellLocation(bundle);
|
||||
} else {
|
||||
return new GsmCellLocation(bundle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,8 +82,20 @@ public abstract class CellLocation {
|
||||
|
||||
/**
|
||||
* Return a new CellLocation object representing an unknown location.
|
||||
*
|
||||
*/
|
||||
public static CellLocation getEmpty() {
|
||||
return new GsmCellLocation();
|
||||
// TODO: My need to be use: Settings.Secure.getInt(mContext, Settings.Secure.CURRENT_ACTIVE_PHONE, 0))
|
||||
// instead of SystemProperties???
|
||||
|
||||
// NOTE here TelephonyManager.getDefault().getPhoneType() cannot be used since at startup
|
||||
// ITelephony have not been created
|
||||
if (RILConstants.CDMA_PHONE ==
|
||||
SystemProperties.getInt(Settings.Secure.CURRENT_ACTIVE_PHONE, 0)) {
|
||||
return new CdmaCellLocation();
|
||||
} else {
|
||||
return new GsmCellLocation();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Watches a {@link TextView} and if a phone number is entered will format it using
|
||||
* {@link PhoneNumberUtils#formatNumber(Editable, int)}. The formatting is based on
|
||||
* {@link PhoneNumberUtils#formatNumber(Editable, int)}. The formatting is based on
|
||||
* the current system locale when this object is created and future locale changes
|
||||
* may not take effect on this instance.
|
||||
*/
|
||||
@@ -35,7 +35,7 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher {
|
||||
static private Locale sCachedLocale;
|
||||
private boolean mFormatting;
|
||||
private boolean mDeletingHyphen;
|
||||
private int mHyphenStart;
|
||||
private int mHyphenStart;
|
||||
private boolean mDeletingBackward;
|
||||
|
||||
public PhoneNumberFormattingTextWatcher() {
|
||||
@@ -60,7 +60,7 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher {
|
||||
text.delete(mHyphenStart, mHyphenStart + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PhoneNumberUtils.formatNumber(text, sFormatType);
|
||||
|
||||
mFormatting = false;
|
||||
@@ -73,8 +73,8 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher {
|
||||
// Make sure user is deleting one char, without a selection
|
||||
final int selStart = Selection.getSelectionStart(s);
|
||||
final int selEnd = Selection.getSelectionEnd(s);
|
||||
if (s.length() > 1 // Can delete another character
|
||||
&& count == 1 // Deleting only one character
|
||||
if (s.length() > 1 // Can delete another character
|
||||
&& count == 1 // Deleting only one character
|
||||
&& after == 0 // Deleting
|
||||
&& s.charAt(start) == '-' // a hyphen
|
||||
&& selStart == selEnd) { // no selection
|
||||
@@ -89,7 +89,7 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher {
|
||||
} else {
|
||||
mDeletingHyphen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
|
||||
@@ -11,18 +11,18 @@ import com.android.internal.telephony.IPhoneStateListener;
|
||||
|
||||
/**
|
||||
* A listener class for monitoring changes in specific telephony states
|
||||
* on the device, including service state, signal strength, message
|
||||
* on the device, including service state, signal strength, message
|
||||
* waiting indicator (voicemail), and others.
|
||||
* <p>
|
||||
* Override the methods for the state that you wish to receive updates for, and
|
||||
* Override the methods for the state that you wish to receive updates for, and
|
||||
* pass your PhoneStateListener object, along with bitwise-or of the LISTEN_
|
||||
* flags to {@link TelephonyManager#listen TelephonyManager.listen()}.
|
||||
* <p>
|
||||
* Note that access to some telephony information is
|
||||
* permission-protected. Your application won't receive updates for protected
|
||||
* information unless it has the appropriate permissions declared in
|
||||
* permission-protected. Your application won't receive updates for protected
|
||||
* information unless it has the appropriate permissions declared in
|
||||
* its manifest file. Where permissions apply, they are noted in the
|
||||
* appropriate LISTEN_ flags.
|
||||
* appropriate LISTEN_ flags.
|
||||
*/
|
||||
public class PhoneStateListener {
|
||||
|
||||
@@ -67,17 +67,17 @@ public class PhoneStateListener {
|
||||
public static final int LISTEN_CALL_FORWARDING_INDICATOR = 0x00000008;
|
||||
|
||||
/**
|
||||
* Listen for changes to the device's cell location. Note that
|
||||
* Listen for changes to the device's cell location. Note that
|
||||
* this will result in frequent callbacks to the listener.
|
||||
* {@more}
|
||||
* Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION
|
||||
* ACCESS_COARSE_LOCATION}
|
||||
* <p>
|
||||
* If you need regular location updates but want more control over
|
||||
* the update interval or location precision, you can set up a listener
|
||||
* through the {@link android.location.LocationManager location manager}
|
||||
* instead.
|
||||
*
|
||||
* If you need regular location updates but want more control over
|
||||
* the update interval or location precision, you can set up a listener
|
||||
* through the {@link android.location.LocationManager location manager}
|
||||
* instead.
|
||||
*
|
||||
* @see #onCellLocationChanged
|
||||
*/
|
||||
public static final int LISTEN_CELL_LOCATION = 0x00000010;
|
||||
@@ -100,7 +100,7 @@ public class PhoneStateListener {
|
||||
* Listen for changes to the direction of data traffic on the data
|
||||
* connection (cellular).
|
||||
*
|
||||
* Example: The status bar uses this to display the appropriate
|
||||
* Example: The status bar uses this to display the appropriate
|
||||
* data-traffic icon.
|
||||
*
|
||||
* @see #onDataActivity
|
||||
@@ -111,7 +111,7 @@ public class PhoneStateListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when device service state changes.
|
||||
* Callback invoked when device service state changes.
|
||||
*
|
||||
* @see ServiceState#STATE_EMERGENCY_ONLY
|
||||
* @see ServiceState#STATE_IN_SERVICE
|
||||
@@ -135,28 +135,28 @@ public class PhoneStateListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when the message-waiting indicator changes.
|
||||
* Callback invoked when the message-waiting indicator changes.
|
||||
*/
|
||||
public void onMessageWaitingIndicatorChanged(boolean mwi) {
|
||||
// default implementation empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when the call-forwarding indicator changes.
|
||||
* Callback invoked when the call-forwarding indicator changes.
|
||||
*/
|
||||
public void onCallForwardingIndicatorChanged(boolean cfi) {
|
||||
// default implementation empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when device cell location changes.
|
||||
* Callback invoked when device cell location changes.
|
||||
*/
|
||||
public void onCellLocationChanged(CellLocation location) {
|
||||
// default implementation empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when device call state changes.
|
||||
* Callback invoked when device call state changes.
|
||||
*
|
||||
* @see TelephonyManager#CALL_STATE_IDLE
|
||||
* @see TelephonyManager#CALL_STATE_RINGING
|
||||
@@ -167,7 +167,7 @@ public class PhoneStateListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when connection state changes.
|
||||
* Callback invoked when connection state changes.
|
||||
*
|
||||
* @see TelephonyManager#DATA_DISCONNECTED
|
||||
* @see TelephonyManager#DATA_CONNECTING
|
||||
@@ -179,7 +179,7 @@ public class PhoneStateListener {
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback invoked when data activity state changes.
|
||||
* Callback invoked when data activity state changes.
|
||||
*
|
||||
* @see TelephonyManager#DATA_ACTIVITY_NONE
|
||||
* @see TelephonyManager#DATA_ACTIVITY_IN
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
**
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ package android.telephony;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import com.android.internal.telephony.Phone;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Contains phone state and service related information.
|
||||
@@ -35,6 +35,8 @@ import com.android.internal.telephony.Phone;
|
||||
*/
|
||||
public class ServiceState implements Parcelable {
|
||||
|
||||
static final String LOG_TAG = "PHONE";
|
||||
|
||||
/**
|
||||
* Normal operation condition, the phone is registered
|
||||
* with an operator either in home network or in roaming.
|
||||
@@ -59,13 +61,61 @@ public class ServiceState implements Parcelable {
|
||||
*/
|
||||
public static final int STATE_POWER_OFF = 3;
|
||||
|
||||
|
||||
/**
|
||||
* Available radio technologies for GSM, UMTS and CDMA.
|
||||
*/
|
||||
/** @hide */
|
||||
public static final int RADIO_TECHNOLOGY_UNKNOWN = 0;
|
||||
/** @hide */
|
||||
public static final int RADIO_TECHNOLOGY_GPRS = 1;
|
||||
/** @hide */
|
||||
public static final int RADIO_TECHNOLOGY_EDGE = 2;
|
||||
/** @hide */
|
||||
public static final int RADIO_TECHNOLOGY_UMTS = 3;
|
||||
/** @hide */
|
||||
public static final int RADIO_TECHNOLOGY_IS95A = 4;
|
||||
/** @hide */
|
||||
public static final int RADIO_TECHNOLOGY_IS95B = 5;
|
||||
/** @hide */
|
||||
public static final int RADIO_TECHNOLOGY_1xRTT = 6;
|
||||
/** @hide */
|
||||
public static final int RADIO_TECHNOLOGY_EVDO_0 = 7;
|
||||
/** @hide */
|
||||
public static final int RADIO_TECHNOLOGY_EVDO_A = 8;
|
||||
|
||||
/**
|
||||
* Available registration states for GSM, UMTS and CDMA.
|
||||
*/
|
||||
/** @hide */
|
||||
public static final int REGISTRATION_STATE_NOT_REGISTERED_AND_NOT_SEARCHING = 0;
|
||||
/** @hide */
|
||||
public static final int REGISTRATION_STATE_HOME_NETWORK = 1;
|
||||
/** @hide */
|
||||
public static final int REGISTRATION_STATE_NOT_REGISTERED_AND_SEARCHING = 2;
|
||||
/** @hide */
|
||||
public static final int REGISTRATION_STATE_REGISTRATION_DENIED = 3;
|
||||
/** @hide */
|
||||
public static final int REGISTRATION_STATE_UNKNOWN = 4;
|
||||
/** @hide */
|
||||
public static final int REGISTRATION_STATE_ROAMING = 5;
|
||||
/** @hide */
|
||||
public static final int REGISTRATION_STATE_ROAMING_AFFILIATE = 6;
|
||||
|
||||
private int mState = STATE_OUT_OF_SERVICE;
|
||||
private boolean mRoaming;
|
||||
private int mExtendedCdmaRoaming;
|
||||
private String mOperatorAlphaLong;
|
||||
private String mOperatorAlphaShort;
|
||||
private String mOperatorNumeric;
|
||||
private boolean mIsManualNetworkSelection;
|
||||
|
||||
//***** CDMA
|
||||
private int mRadioTechnology;
|
||||
private boolean mCssIndicator;
|
||||
private int mNetworkId;
|
||||
private int mSystemId;
|
||||
|
||||
/**
|
||||
* Create a new ServiceState from a intent notifier Bundle
|
||||
*
|
||||
@@ -105,6 +155,11 @@ public class ServiceState implements Parcelable {
|
||||
mOperatorAlphaShort = s.mOperatorAlphaShort;
|
||||
mOperatorNumeric = s.mOperatorNumeric;
|
||||
mIsManualNetworkSelection = s.mIsManualNetworkSelection;
|
||||
mRadioTechnology = s.mRadioTechnology;
|
||||
mCssIndicator = s.mCssIndicator;
|
||||
mNetworkId = s.mNetworkId;
|
||||
mSystemId = s.mSystemId;
|
||||
mExtendedCdmaRoaming = s.mExtendedCdmaRoaming;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,6 +172,11 @@ public class ServiceState implements Parcelable {
|
||||
mOperatorAlphaShort = in.readString();
|
||||
mOperatorNumeric = in.readString();
|
||||
mIsManualNetworkSelection = in.readInt() != 0;
|
||||
mRadioTechnology = in.readInt();
|
||||
mCssIndicator = (in.readInt() != 0);
|
||||
mNetworkId = in.readInt();
|
||||
mSystemId = in.readInt();
|
||||
mExtendedCdmaRoaming = in.readInt();
|
||||
}
|
||||
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
@@ -126,6 +186,11 @@ public class ServiceState implements Parcelable {
|
||||
out.writeString(mOperatorAlphaShort);
|
||||
out.writeString(mOperatorNumeric);
|
||||
out.writeInt(mIsManualNetworkSelection ? 1 : 0);
|
||||
out.writeInt(mRadioTechnology);
|
||||
out.writeInt(mCssIndicator ? 1 : 0);
|
||||
out.writeInt(mNetworkId);
|
||||
out.writeInt(mSystemId);
|
||||
out.writeInt(mExtendedCdmaRoaming);
|
||||
}
|
||||
|
||||
public int describeContents() {
|
||||
@@ -166,6 +231,11 @@ public class ServiceState implements Parcelable {
|
||||
return mRoaming;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getExtendedCdmaRoaming(){
|
||||
return this.mExtendedCdmaRoaming;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current registered operator name in long alphanumeric format
|
||||
*
|
||||
@@ -213,18 +283,19 @@ public class ServiceState implements Parcelable {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (mState * 0x1234)
|
||||
return ((mState * 0x1234)
|
||||
+ (mRoaming ? 1 : 0)
|
||||
+ (mIsManualNetworkSelection ? 1 : 0)
|
||||
+ ((null == mOperatorAlphaLong) ? 0 : mOperatorAlphaLong.hashCode())
|
||||
+ ((null == mOperatorAlphaShort) ? 0 : mOperatorAlphaShort.hashCode())
|
||||
+ ((null == mOperatorNumeric) ? 0 : mOperatorNumeric.hashCode());
|
||||
+ ((null == mOperatorNumeric) ? 0 : mOperatorNumeric.hashCode())
|
||||
+ (mExtendedCdmaRoaming));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object o) {
|
||||
ServiceState s;
|
||||
|
||||
|
||||
try {
|
||||
s = (ServiceState) o;
|
||||
} catch (ClassCastException ex) {
|
||||
@@ -235,21 +306,66 @@ public class ServiceState implements Parcelable {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mState == s.mState
|
||||
return (mState == s.mState
|
||||
&& mRoaming == s.mRoaming
|
||||
&& mIsManualNetworkSelection == s.mIsManualNetworkSelection
|
||||
&& equalsHandlesNulls(mOperatorAlphaLong, s.mOperatorAlphaLong)
|
||||
&& equalsHandlesNulls(mOperatorAlphaShort, s.mOperatorAlphaShort)
|
||||
&& equalsHandlesNulls(mOperatorNumeric, s.mOperatorNumeric);
|
||||
&& equalsHandlesNulls(mOperatorNumeric, s.mOperatorNumeric)
|
||||
&& equalsHandlesNulls(mRadioTechnology, s.mRadioTechnology)
|
||||
&& equalsHandlesNulls(mCssIndicator, s.mCssIndicator)
|
||||
&& equalsHandlesNulls(mNetworkId, s.mNetworkId)
|
||||
&& equalsHandlesNulls(mSystemId, s.mSystemId)
|
||||
&& equalsHandlesNulls(mExtendedCdmaRoaming, s.mExtendedCdmaRoaming));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mState + " " + (mRoaming ? "roaming" : "home")
|
||||
String radioTechnology = new String("Error in radioTechnology");
|
||||
|
||||
switch(this.mRadioTechnology) {
|
||||
case 0:
|
||||
radioTechnology = "Unknown";
|
||||
break;
|
||||
case 1:
|
||||
radioTechnology = "GPRS";
|
||||
break;
|
||||
case 2:
|
||||
radioTechnology = "EDGE";
|
||||
break;
|
||||
case 3:
|
||||
radioTechnology = "UMTS";
|
||||
break;
|
||||
case 4:
|
||||
radioTechnology = "IS95A";
|
||||
break;
|
||||
case 5:
|
||||
radioTechnology = "IS95B";
|
||||
break;
|
||||
case 6:
|
||||
radioTechnology = "1xRTT";
|
||||
break;
|
||||
case 7:
|
||||
radioTechnology = "EvDo rev. 0";
|
||||
break;
|
||||
case 8:
|
||||
radioTechnology = "EvDo rev. A";
|
||||
break;
|
||||
default:
|
||||
Log.w(LOG_TAG, "mRadioTechnology variable out of range.");
|
||||
break;
|
||||
}
|
||||
|
||||
return (mState + " " + (mRoaming ? "roaming" : "home")
|
||||
+ " " + mOperatorAlphaLong
|
||||
+ " " + mOperatorAlphaShort
|
||||
+ " " + mOperatorNumeric
|
||||
+ " " + (mIsManualNetworkSelection ? "(manual)" : "");
|
||||
+ " " + (mIsManualNetworkSelection ? "(manual)" : "")
|
||||
+ " " + radioTechnology
|
||||
+ " " + (mCssIndicator ? "CSS supported" : "CSS not supported")
|
||||
+ "NetworkId: " + mNetworkId
|
||||
+ "SystemId: " + mSystemId
|
||||
+ "ExtendedCdmaRoaming: " + mExtendedCdmaRoaming);
|
||||
}
|
||||
|
||||
public void setStateOutOfService() {
|
||||
@@ -259,6 +375,11 @@ public class ServiceState implements Parcelable {
|
||||
mOperatorAlphaShort = null;
|
||||
mOperatorNumeric = null;
|
||||
mIsManualNetworkSelection = false;
|
||||
mRadioTechnology = 0;
|
||||
mCssIndicator = false;
|
||||
mNetworkId = -1;
|
||||
mSystemId = -1;
|
||||
mExtendedCdmaRoaming = -1;
|
||||
}
|
||||
|
||||
public void setStateOff() {
|
||||
@@ -268,6 +389,11 @@ public class ServiceState implements Parcelable {
|
||||
mOperatorAlphaShort = null;
|
||||
mOperatorNumeric = null;
|
||||
mIsManualNetworkSelection = false;
|
||||
mRadioTechnology = 0;
|
||||
mCssIndicator = false;
|
||||
mNetworkId = -1;
|
||||
mSystemId = -1;
|
||||
mExtendedCdmaRoaming = -1;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
@@ -278,6 +404,11 @@ public class ServiceState implements Parcelable {
|
||||
mRoaming = roaming;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setExtendedCdmaRoaming (int roaming) {
|
||||
this.mExtendedCdmaRoaming = roaming;
|
||||
}
|
||||
|
||||
public void setOperatorName(String longName, String shortName, String numeric) {
|
||||
mOperatorAlphaLong = longName;
|
||||
mOperatorAlphaShort = shortName;
|
||||
@@ -287,7 +418,7 @@ public class ServiceState implements Parcelable {
|
||||
public void setIsManualSelection(boolean isManual) {
|
||||
mIsManualNetworkSelection = isManual;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test whether two objects hold the same data values or both are null
|
||||
*
|
||||
@@ -312,6 +443,11 @@ public class ServiceState implements Parcelable {
|
||||
mOperatorAlphaShort = m.getString("operator-alpha-short");
|
||||
mOperatorNumeric = m.getString("operator-numeric");
|
||||
mIsManualNetworkSelection = m.getBoolean("manual");
|
||||
mRadioTechnology = m.getInt("radioTechnology");
|
||||
mCssIndicator = m.getBoolean("cssIndicator");
|
||||
mNetworkId = m.getInt("networkId");
|
||||
mSystemId = m.getInt("systemId");
|
||||
mExtendedCdmaRoaming = m.getInt("extendedCdmaRoaming");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -327,5 +463,47 @@ public class ServiceState implements Parcelable {
|
||||
m.putString("operator-alpha-short", mOperatorAlphaShort);
|
||||
m.putString("operator-numeric", mOperatorNumeric);
|
||||
m.putBoolean("manual", Boolean.valueOf(mIsManualNetworkSelection));
|
||||
m.putInt("radioTechnology", mRadioTechnology);
|
||||
m.putBoolean("cssIndicator", mCssIndicator);
|
||||
m.putInt("networkId", mNetworkId);
|
||||
m.putInt("systemId", mSystemId);
|
||||
m.putInt("extendedCdmaRoaming", mExtendedCdmaRoaming);
|
||||
}
|
||||
|
||||
//***** CDMA
|
||||
/** @hide */
|
||||
public void setRadioTechnology(int state) {
|
||||
this.mRadioTechnology = state;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setCssIndicator(int css) {
|
||||
this.mCssIndicator = (css != 0);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void setSystemAndNetworkId(int systemId, int networkId) {
|
||||
this.mSystemId = systemId;
|
||||
this.mNetworkId = networkId;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getRadioTechnology() {
|
||||
return this.mRadioTechnology;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getCssIndicator() {
|
||||
return this.mCssIndicator ? 1 : 0;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getNetworkId() {
|
||||
return this.mNetworkId;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getSystemId() {
|
||||
return this.mSystemId;
|
||||
}
|
||||
}
|
||||
|
||||
441
telephony/java/android/telephony/SmsManager.java
Normal file
441
telephony/java/android/telephony/SmsManager.java
Normal file
@@ -0,0 +1,441 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.telephony;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.telephony.EncodeException;
|
||||
import com.android.internal.telephony.GsmAlphabet;
|
||||
import com.android.internal.telephony.ISms;
|
||||
import com.android.internal.telephony.IccConstants;
|
||||
import com.android.internal.telephony.SmsRawData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static android.telephony.SmsMessage.ENCODING_7BIT;
|
||||
import static android.telephony.SmsMessage.ENCODING_8BIT;
|
||||
import static android.telephony.SmsMessage.ENCODING_16BIT;
|
||||
import static android.telephony.SmsMessage.ENCODING_UNKNOWN;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER;
|
||||
|
||||
/**
|
||||
* Manages SMS operations such as sending data, text, and pdu SMS messages.
|
||||
* Get this object by calling the static method SmsManager.getDefault().
|
||||
* @hide
|
||||
*/
|
||||
public final class SmsManager {
|
||||
private static SmsManager sInstance;
|
||||
|
||||
/**
|
||||
* Send a text based SMS.
|
||||
*
|
||||
* @param destinationAddress the address to send the message to
|
||||
* @param scAddress is the service center address or null to use
|
||||
* the current default SMSC
|
||||
* @param text the body of the message to send
|
||||
* @param sentIntent if not NULL this <code>PendingIntent</code> is
|
||||
* broadcast when the message is sucessfully sent, or failed.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
* or one of these errors:
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* The per-application based SMS control checks sentIntent. If sentIntent
|
||||
* is NULL the caller will be checked against all unknown applications,
|
||||
* which cause smaller number of SMS to be sent in checking period.
|
||||
* @param deliveryIntent if not NULL this <code>PendingIntent</code> is
|
||||
* broadcast when the message is delivered to the recipient. The
|
||||
* raw pdu of the status report is in the extended data ("pdu").
|
||||
*
|
||||
* @throws IllegalArgumentException if destinationAddress or text are empty
|
||||
*/
|
||||
public void sendTextMessage(
|
||||
String destinationAddress, String scAddress, String text,
|
||||
PendingIntent sentIntent, PendingIntent deliveryIntent) {
|
||||
if (TextUtils.isEmpty(destinationAddress)) {
|
||||
throw new IllegalArgumentException("Invalid destinationAddress");
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
throw new IllegalArgumentException("Invalid message body");
|
||||
}
|
||||
|
||||
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(
|
||||
scAddress, destinationAddress, text, (deliveryIntent != null));
|
||||
sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Divide a text message into several messages, none bigger than
|
||||
* the maximum SMS message size.
|
||||
*
|
||||
* @param text the original message. Must not be null.
|
||||
* @return an <code>ArrayList</code> of strings that, in order,
|
||||
* comprise the original message
|
||||
*/
|
||||
public ArrayList<String> divideMessage(String text) {
|
||||
int size = text.length();
|
||||
int[] params = SmsMessage.calculateLength(text, false);
|
||||
/* SmsMessage.calculateLength returns an int[4] with:
|
||||
* int[0] being the number of SMS's required,
|
||||
* int[1] the number of code units used,
|
||||
* int[2] is the number of code units remaining until the next message.
|
||||
* int[3] is the encoding type that should be used for the message.
|
||||
*/
|
||||
int messageCount = params[0];
|
||||
int encodingType = params[3];
|
||||
ArrayList<String> result = new ArrayList<String>(messageCount);
|
||||
|
||||
int start = 0;
|
||||
int limit;
|
||||
|
||||
if (messageCount > 1) {
|
||||
limit = (encodingType == ENCODING_7BIT)?
|
||||
MAX_USER_DATA_SEPTETS_WITH_HEADER: MAX_USER_DATA_BYTES_WITH_HEADER;
|
||||
} else {
|
||||
limit = (encodingType == ENCODING_7BIT)?
|
||||
MAX_USER_DATA_SEPTETS: MAX_USER_DATA_BYTES;
|
||||
}
|
||||
|
||||
try {
|
||||
while (start < size) {
|
||||
int end = GsmAlphabet.findLimitIndex(text, start, limit, encodingType);
|
||||
result.add(text.substring(start, end));
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
catch (EncodeException e) {
|
||||
// ignore it.
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a multi-part text based SMS. The callee should have already
|
||||
* divided the message into correctly sized parts by calling
|
||||
* <code>divideMessage</code>.
|
||||
*
|
||||
* @param destinationAddress the address to send the message to
|
||||
* @param scAddress is the service center address or null to use
|
||||
* the current default SMSC
|
||||
* @param parts an <code>ArrayList</code> of strings that, in order,
|
||||
* comprise the original message
|
||||
* @param sentIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been sent.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
* or one of these errors:
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* The per-application based SMS control checks sentIntent. If sentIntent
|
||||
* is NULL the caller will be checked against all unknown applicaitons,
|
||||
* which cause smaller number of SMS to be sent in checking period.
|
||||
* @param deliveryIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been delivered
|
||||
* to the recipient. The raw pdu of the status report is in the
|
||||
* extended data ("pdu").
|
||||
*
|
||||
* @throws IllegalArgumentException if destinationAddress or data are empty
|
||||
*/
|
||||
public void sendMultipartTextMessage(
|
||||
String destinationAddress, String scAddress, ArrayList<String> parts,
|
||||
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
|
||||
if (TextUtils.isEmpty(destinationAddress)) {
|
||||
throw new IllegalArgumentException("Invalid destinationAddress");
|
||||
}
|
||||
if (parts == null || parts.size() < 1) {
|
||||
throw new IllegalArgumentException("Invalid message body");
|
||||
}
|
||||
|
||||
if (parts.size() > 1) {
|
||||
try {
|
||||
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (iccISms != null) {
|
||||
iccISms.sendMultipartText(destinationAddress, scAddress, parts,
|
||||
sentIntents, deliveryIntents);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
} else {
|
||||
PendingIntent sentIntent = null;
|
||||
PendingIntent deliveryIntent = null;
|
||||
if (sentIntents != null && sentIntents.size() > 0) {
|
||||
sentIntent = sentIntents.get(0);
|
||||
}
|
||||
if (deliveryIntents != null && deliveryIntents.size() > 0) {
|
||||
deliveryIntent = deliveryIntents.get(0);
|
||||
}
|
||||
sendTextMessage(destinationAddress, scAddress, parts.get(0),
|
||||
sentIntent, deliveryIntent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a data based SMS to a specific application port.
|
||||
*
|
||||
* @param destinationAddress the address to send the message to
|
||||
* @param scAddress is the service center address or null to use
|
||||
* the current default SMSC
|
||||
* @param destinationPort the port to deliver the message to
|
||||
* @param data the body of the message to send
|
||||
* @param sentIntent if not NULL this <code>PendingIntent</code> is
|
||||
* broadcast when the message is sucessfully sent, or failed.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
* or one of these errors:
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* The per-application based SMS control checks sentIntent. If sentIntent
|
||||
* is NULL the caller will be checked against all unknown applicaitons,
|
||||
* which cause smaller number of SMS to be sent in checking period.
|
||||
* @param deliveryIntent if not NULL this <code>PendingIntent</code> is
|
||||
* broadcast when the message is delivered to the recipient. The
|
||||
* raw pdu of the status report is in the extended data ("pdu").
|
||||
*
|
||||
* @throws IllegalArgumentException if destinationAddress or data are empty
|
||||
*/
|
||||
public void sendDataMessage(
|
||||
String destinationAddress, String scAddress, short destinationPort,
|
||||
byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
|
||||
if (TextUtils.isEmpty(destinationAddress)) {
|
||||
throw new IllegalArgumentException("Invalid destinationAddress");
|
||||
}
|
||||
|
||||
if (data == null || data.length == 0) {
|
||||
throw new IllegalArgumentException("Invalid message data");
|
||||
}
|
||||
|
||||
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(
|
||||
scAddress, destinationAddress,
|
||||
destinationPort, data, (deliveryIntent != null));
|
||||
sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a raw SMS PDU.
|
||||
*
|
||||
* @param smsc the SMSC to send the message through, or NULL for the
|
||||
* default SMSC
|
||||
* @param pdu the raw PDU to send
|
||||
* @param sentIntent if not NULL this <code>PendingIntent</code> is
|
||||
* broadcast when the message is successfully sent, or failed.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
* or one of these errors:
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* The per-application based SMS control checks sentIntent. If sentIntent
|
||||
* is NULL the caller will be checked against all unknown applications,
|
||||
* which cause smaller number of SMS to be sent in checking period.
|
||||
* @param deliveryIntent if not NULL this <code>PendingIntent</code> is
|
||||
* broadcast when the message is delivered to the recipient. The
|
||||
* raw pdu of the status report is in the extended data ("pdu").
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
private void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
|
||||
PendingIntent deliveryIntent) {
|
||||
try {
|
||||
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (iccISms != null) {
|
||||
iccISms.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default instance of the SmsManager
|
||||
*
|
||||
* @return the default instance of the SmsManager
|
||||
*/
|
||||
public static SmsManager getDefault() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new SmsManager();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private SmsManager() {
|
||||
//nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a raw SMS PDU to the ICC.
|
||||
*
|
||||
* @param smsc the SMSC for this message, or NULL for the default SMSC
|
||||
* @param pdu the raw PDU to store
|
||||
* @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
|
||||
* STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
|
||||
* @return true for success
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public boolean copyMessageToIcc(byte[] smsc, byte[] pdu, int status) {
|
||||
boolean success = false;
|
||||
|
||||
try {
|
||||
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (iccISms != null) {
|
||||
success = iccISms.copyMessageToIccEf(status, pdu, smsc);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the specified message from the ICC.
|
||||
*
|
||||
* @param messageIndex is the record index of the message on ICC
|
||||
* @return true for success
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public boolean
|
||||
deleteMessageFromIcc(int messageIndex) {
|
||||
boolean success = false;
|
||||
byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1];
|
||||
Arrays.fill(pdu, (byte)0xff);
|
||||
|
||||
try {
|
||||
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (iccISms != null) {
|
||||
success = iccISms.updateMessageOnIccEf(messageIndex, STATUS_ON_ICC_FREE, pdu);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified message on the ICC.
|
||||
*
|
||||
* @param messageIndex record index of message to update
|
||||
* @param newStatus new message status (STATUS_ON_ICC_READ,
|
||||
* STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
|
||||
* STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
|
||||
* @param pdu the raw PDU to store
|
||||
* @return true for success
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) {
|
||||
boolean success = false;
|
||||
|
||||
try {
|
||||
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (iccISms != null) {
|
||||
success = iccISms.updateMessageOnIccEf(messageIndex, newStatus, pdu);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all messages currently stored on ICC.
|
||||
*
|
||||
* @return <code>ArrayList</code> of <code>SmsMessage</code> objects
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public ArrayList<SmsMessage> getAllMessagesFromIcc() {
|
||||
List<SmsRawData> records = null;
|
||||
|
||||
try {
|
||||
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (iccISms != null) {
|
||||
records = iccISms.getAllMessagesFromIccEf();
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
|
||||
return createMessageListFromRawRecords(records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of <code>SmsMessage</code>s from a list of RawSmsData
|
||||
* records returned by <code>getAllMessagesFromIcc()</code>
|
||||
*
|
||||
* @param records SMS EF records, returned by
|
||||
* <code>getAllMessagesFromIcc</code>
|
||||
* @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
|
||||
*/
|
||||
private ArrayList<SmsMessage> createMessageListFromRawRecords(List records) {
|
||||
ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
|
||||
if (records != null) {
|
||||
int count = records.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
SmsRawData data = (SmsRawData)records.get(i);
|
||||
// List contains all records, including "free" records (null)
|
||||
if (data != null) {
|
||||
SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
|
||||
messages.add(sms);
|
||||
}
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
// see SmsMessage.getStatusOnIcc
|
||||
|
||||
/** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
|
||||
static public final int STATUS_ON_ICC_FREE = 0;
|
||||
|
||||
/** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
|
||||
static public final int STATUS_ON_ICC_READ = 1;
|
||||
|
||||
/** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
|
||||
static public final int STATUS_ON_ICC_UNREAD = 3;
|
||||
|
||||
/** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
|
||||
static public final int STATUS_ON_ICC_SENT = 5;
|
||||
|
||||
/** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
|
||||
static public final int STATUS_ON_ICC_UNSENT = 7;
|
||||
|
||||
// SMS send failure result codes
|
||||
|
||||
/** Generic failure cause */
|
||||
static public final int RESULT_ERROR_GENERIC_FAILURE = 1;
|
||||
/** Failed because radio was explicitly turned off */
|
||||
static public final int RESULT_ERROR_RADIO_OFF = 2;
|
||||
/** Failed because no pdu provided */
|
||||
static public final int RESULT_ERROR_NULL_PDU = 3;
|
||||
/** Failed because service is currently unavailable */
|
||||
static public final int RESULT_ERROR_NO_SERVICE = 4;
|
||||
}
|
||||
628
telephony/java/android/telephony/SmsMessage.java
Normal file
628
telephony/java/android/telephony/SmsMessage.java
Normal file
@@ -0,0 +1,628 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.telephony;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import com.android.internal.telephony.GsmAlphabet;
|
||||
import com.android.internal.telephony.EncodeException;
|
||||
import com.android.internal.telephony.SmsMessageBase;
|
||||
import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
|
||||
|
||||
import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
|
||||
|
||||
|
||||
/**
|
||||
* A Short Message Service message.
|
||||
* @hide
|
||||
*/
|
||||
public class SmsMessage {
|
||||
private static final boolean LOCAL_DEBUG = true;
|
||||
private static final String LOG_TAG = "SMS";
|
||||
|
||||
/**
|
||||
* SMS Class enumeration.
|
||||
* See TS 23.038.
|
||||
*
|
||||
*/
|
||||
public enum MessageClass{
|
||||
UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3;
|
||||
}
|
||||
|
||||
/** Unknown encoding scheme (see TS 23.038) */
|
||||
public static final int ENCODING_UNKNOWN = 0;
|
||||
/** 7-bit encoding scheme (see TS 23.038) */
|
||||
public static final int ENCODING_7BIT = 1;
|
||||
/** 8-bit encoding scheme (see TS 23.038) */
|
||||
public static final int ENCODING_8BIT = 2;
|
||||
/** 16-bit encoding scheme (see TS 23.038) */
|
||||
public static final int ENCODING_16BIT = 3;
|
||||
|
||||
/** The maximum number of payload bytes per message */
|
||||
public static final int MAX_USER_DATA_BYTES = 140;
|
||||
|
||||
/**
|
||||
* The maximum number of payload bytes per message if a user data header
|
||||
* is present. This assumes the header only contains the
|
||||
* CONCATENATED_8_BIT_REFERENCE element.
|
||||
*
|
||||
* @hide pending API Council approval to extend the public API
|
||||
*/
|
||||
public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134;
|
||||
|
||||
/** The maximum number of payload septets per message */
|
||||
public static final int MAX_USER_DATA_SEPTETS = 160;
|
||||
|
||||
/**
|
||||
* The maximum number of payload septets per message if a user data header
|
||||
* is present. This assumes the header only contains the
|
||||
* CONCATENATED_8_BIT_REFERENCE element.
|
||||
*/
|
||||
public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153;
|
||||
|
||||
/** Contains actual SmsMessage. Only public for debugging and for framework layer.
|
||||
* {@hide}
|
||||
*/
|
||||
public SmsMessageBase mWrappedSmsMessage;
|
||||
|
||||
public static class SubmitPdu extends SubmitPduBase {
|
||||
|
||||
//Constructor
|
||||
public SubmitPdu() {
|
||||
}
|
||||
|
||||
/* {@hide} */
|
||||
protected SubmitPdu(SubmitPduBase spb) {
|
||||
this.encodedMessage = spb.encodedMessage;
|
||||
this.encodedScAddress = spb.encodedScAddress;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Constructor
|
||||
public SmsMessage() {
|
||||
this(getSmsFacility());
|
||||
}
|
||||
|
||||
private SmsMessage(SmsMessageBase smb) {
|
||||
mWrappedSmsMessage = smb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an SmsMessage from a raw PDU.
|
||||
*/
|
||||
public static SmsMessage createFromPdu(byte[] pdu) {
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
|
||||
} else {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
|
||||
}
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
|
||||
* +CMT unsolicited response (PDU mode, of course)
|
||||
* +CMT: [<alpha>],<length><CR><LF><pdu>
|
||||
*
|
||||
* Only public for debugging and for RIL
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static SmsMessage newFromCMT(String[] lines){
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMT(lines);
|
||||
} else {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines);
|
||||
}
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
protected static SmsMessage newFromCMTI(String line) {
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCMTI(line);
|
||||
} else {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCMTI(line);
|
||||
}
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static SmsMessage newFromCDS(String line) {
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromCDS(line);
|
||||
} else {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromCDS(line);
|
||||
}
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static SmsMessage newFromParcel(Parcel p) {
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p);
|
||||
} else {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.newFromParcel(p);
|
||||
}
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an SmsMessage from an SMS EF record.
|
||||
*
|
||||
* @param index Index of SMS record. This should be index in ArrayList
|
||||
* returned by SmsManager.getAllMessagesFromSim + 1.
|
||||
* @param data Record data.
|
||||
* @return An SmsMessage representing the record.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static SmsMessage createFromEfRecord(int index, byte[] data) {
|
||||
SmsMessageBase wrappedMessage;
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
|
||||
index, data);
|
||||
} else {
|
||||
wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
|
||||
index, data);
|
||||
}
|
||||
|
||||
return new SmsMessage(wrappedMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
|
||||
* length in bytes (not hex chars) less the SMSC header
|
||||
*/
|
||||
public static int getTPLayerLengthForPDU(String pdu) {
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu);
|
||||
} else {
|
||||
return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of SMS's required to encode the message body and
|
||||
* the number of characters remaining until the next message, given the
|
||||
* current encoding.
|
||||
*
|
||||
* @param messageBody the message to encode
|
||||
* @param use7bitOnly if true, characters that are not part of the GSM
|
||||
* alphabet are counted as a single space char. If false, a
|
||||
* messageBody containing non-GSM alphabet characters is calculated
|
||||
* for 16-bit encoding.
|
||||
* @return an int[4] with int[0] being the number of SMS's required, int[1]
|
||||
* the number of code units used, and int[2] is the number of code
|
||||
* units remaining until the next message. int[3] is the encoding
|
||||
* type that should be used for the message.
|
||||
*/
|
||||
public static int[] calculateLength(CharSequence messageBody, boolean use7bitOnly) {
|
||||
int ret[] = new int[4];
|
||||
|
||||
try {
|
||||
// Try GSM alphabet
|
||||
int septets = GsmAlphabet.countGsmSeptets(messageBody, !use7bitOnly);
|
||||
ret[1] = septets;
|
||||
if (septets > MAX_USER_DATA_SEPTETS) {
|
||||
ret[0] = (septets / MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
|
||||
ret[2] = MAX_USER_DATA_SEPTETS_WITH_HEADER
|
||||
- (septets % MAX_USER_DATA_SEPTETS_WITH_HEADER);
|
||||
} else {
|
||||
ret[0] = 1;
|
||||
ret[2] = MAX_USER_DATA_SEPTETS - septets;
|
||||
}
|
||||
ret[3] = ENCODING_7BIT;
|
||||
} catch (EncodeException ex) {
|
||||
// fall back to UCS-2
|
||||
int octets = messageBody.length() * 2;
|
||||
ret[1] = messageBody.length();
|
||||
if (octets > MAX_USER_DATA_BYTES) {
|
||||
// 6 is the size of the user data header
|
||||
ret[0] = (octets / MAX_USER_DATA_BYTES_WITH_HEADER) + 1;
|
||||
ret[2] = (MAX_USER_DATA_BYTES_WITH_HEADER
|
||||
- (octets % MAX_USER_DATA_BYTES_WITH_HEADER))/2;
|
||||
} else {
|
||||
ret[0] = 1;
|
||||
ret[2] = (MAX_USER_DATA_BYTES - octets)/2;
|
||||
}
|
||||
ret[3] = ENCODING_16BIT;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of SMS's required to encode the message body and
|
||||
* the number of characters remaining until the next message, given the
|
||||
* current encoding.
|
||||
*
|
||||
* @param messageBody the message to encode
|
||||
* @param use7bitOnly if true, characters that are not part of the GSM
|
||||
* alphabet are counted as a single space char. If false, a
|
||||
* messageBody containing non-GSM alphabet characters is calculated
|
||||
* for 16-bit encoding.
|
||||
* @return an int[4] with int[0] being the number of SMS's required, int[1]
|
||||
* the number of code units used, and int[2] is the number of code
|
||||
* units remaining until the next message. int[3] is the encoding
|
||||
* type that should be used for the message.
|
||||
*/
|
||||
public static int[] calculateLength(String messageBody, boolean use7bitOnly) {
|
||||
return calculateLength((CharSequence)messageBody, use7bitOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SMS-SUBMIT PDU for a destination address and a message
|
||||
*
|
||||
* @param scAddress Service Centre address. Null means use default.
|
||||
* @return a <code>SubmitPdu</code> containing the encoded SC
|
||||
* address, if applicable, and the encoded message.
|
||||
* Returns null on encode error.
|
||||
* @hide
|
||||
*/
|
||||
public static SubmitPdu getSubmitPdu(String scAddress,
|
||||
String destinationAddress, String message,
|
||||
boolean statusReportRequested, byte[] header) {
|
||||
SubmitPduBase spb;
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
|
||||
destinationAddress, message, statusReportRequested, header);
|
||||
} else {
|
||||
spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
|
||||
destinationAddress, message, statusReportRequested, header);
|
||||
}
|
||||
|
||||
return new SubmitPdu(spb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SMS-SUBMIT PDU for a destination address and a message
|
||||
*
|
||||
* @param scAddress Service Centre address. Null means use default.
|
||||
* @return a <code>SubmitPdu</code> containing the encoded SC
|
||||
* address, if applicable, and the encoded message.
|
||||
* Returns null on encode error.
|
||||
*/
|
||||
public static SubmitPdu getSubmitPdu(String scAddress,
|
||||
String destinationAddress, String message, boolean statusReportRequested) {
|
||||
SubmitPduBase spb;
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
|
||||
destinationAddress, message, statusReportRequested);
|
||||
} else {
|
||||
spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
|
||||
destinationAddress, message, statusReportRequested);
|
||||
}
|
||||
|
||||
return new SubmitPdu(spb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SMS-SUBMIT PDU for a data message to a destination address & port
|
||||
*
|
||||
* @param scAddress Service Centre address. null == use default
|
||||
* @param destinationAddress the address of the destination for the message
|
||||
* @param destinationPort the port to deliver the message to at the
|
||||
* destination
|
||||
* @param data the dat for the message
|
||||
* @return a <code>SubmitPdu</code> containing the encoded SC
|
||||
* address, if applicable, and the encoded message.
|
||||
* Returns null on encode error.
|
||||
*/
|
||||
public static SubmitPdu getSubmitPdu(String scAddress,
|
||||
String destinationAddress, short destinationPort, byte[] data,
|
||||
boolean statusReportRequested) {
|
||||
SubmitPduBase spb;
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
|
||||
destinationAddress, destinationPort, data, statusReportRequested);
|
||||
} else {
|
||||
spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
|
||||
destinationAddress, destinationPort, data, statusReportRequested);
|
||||
}
|
||||
|
||||
return new SubmitPdu(spb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the SMS service center that relayed this message
|
||||
* or null if there is none.
|
||||
*/
|
||||
public String getServiceCenterAddress() {
|
||||
return mWrappedSmsMessage.getServiceCenterAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the originating address (sender) of this SMS message in String
|
||||
* form or null if unavailable
|
||||
*/
|
||||
public String getOriginatingAddress() {
|
||||
return mWrappedSmsMessage.getOriginatingAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the originating address, or email from address if this message
|
||||
* was from an email gateway. Returns null if originating address
|
||||
* unavailable.
|
||||
*/
|
||||
public String getDisplayOriginatingAddress() {
|
||||
return mWrappedSmsMessage.getDisplayOriginatingAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message body as a String, if it exists and is text based.
|
||||
* @return message body is there is one, otherwise null
|
||||
*/
|
||||
public String getMessageBody() {
|
||||
return mWrappedSmsMessage.getMessageBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of this message.
|
||||
*/
|
||||
public MessageClass getMessageClass() {
|
||||
return mWrappedSmsMessage.getMessageClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message body, or email message body if this message was from
|
||||
* an email gateway. Returns null if message body unavailable.
|
||||
*/
|
||||
public String getDisplayMessageBody() {
|
||||
return mWrappedSmsMessage.getDisplayMessageBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unofficial convention of a subject line enclosed in parens empty string
|
||||
* if not present
|
||||
*/
|
||||
public String getPseudoSubject() {
|
||||
return mWrappedSmsMessage.getPseudoSubject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the service centre timestamp in currentTimeMillis() format
|
||||
*/
|
||||
public long getTimestampMillis() {
|
||||
return mWrappedSmsMessage.getTimestampMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if message is an email.
|
||||
*
|
||||
* @return true if this message came through an email gateway and email
|
||||
* sender / subject / parsed body are available
|
||||
*/
|
||||
public boolean isEmail() {
|
||||
return mWrappedSmsMessage.isEmail();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if isEmail() is true, body of the email sent through the gateway.
|
||||
* null otherwise
|
||||
*/
|
||||
public String getEmailBody() {
|
||||
return mWrappedSmsMessage.getEmailBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if isEmail() is true, email from address of email sent through
|
||||
* the gateway. null otherwise
|
||||
*/
|
||||
public String getEmailFrom() {
|
||||
return mWrappedSmsMessage.getEmailFrom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get protocol identifier.
|
||||
*/
|
||||
public int getProtocolIdentifier() {
|
||||
return mWrappedSmsMessage.getProtocolIdentifier();
|
||||
}
|
||||
|
||||
/**
|
||||
* See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
|
||||
* SMS
|
||||
*/
|
||||
public boolean isReplace() {
|
||||
return mWrappedSmsMessage.isReplace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true for CPHS MWI toggle message.
|
||||
*
|
||||
* @return true if this is a CPHS MWI toggle message See CPHS 4.2 section
|
||||
* B.4.2
|
||||
*/
|
||||
public boolean isCphsMwiMessage() {
|
||||
return mWrappedSmsMessage.isCphsMwiMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if this message is a CPHS voicemail / message waiting
|
||||
* indicator (MWI) clear message
|
||||
*/
|
||||
public boolean isMWIClearMessage() {
|
||||
return mWrappedSmsMessage.isMWIClearMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if this message is a CPHS voicemail / message waiting
|
||||
* indicator (MWI) set message
|
||||
*/
|
||||
public boolean isMWISetMessage() {
|
||||
return mWrappedSmsMessage.isMWISetMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if this message is a "Message Waiting Indication Group:
|
||||
* Discard Message" notification and should not be stored.
|
||||
*/
|
||||
public boolean isMwiDontStore() {
|
||||
return mWrappedSmsMessage.isMwiDontStore();
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the user data section minus the user data header if one was
|
||||
* present.
|
||||
*/
|
||||
public byte[] getUserData() {
|
||||
return mWrappedSmsMessage.getUserData();
|
||||
}
|
||||
|
||||
/* Not part of the SDK interface and only needed by specific classes:
|
||||
protected SmsHeader getUserDataHeader()
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the raw PDU for the message.
|
||||
*
|
||||
* @return the raw PDU for the message.
|
||||
*/
|
||||
public byte[] getPdu() {
|
||||
return mWrappedSmsMessage.getPdu();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the message on the SIM (read, unread, sent, unsent).
|
||||
*
|
||||
* @return the status of the message on the SIM. These are:
|
||||
* SmsManager.STATUS_ON_SIM_FREE
|
||||
* SmsManager.STATUS_ON_SIM_READ
|
||||
* SmsManager.STATUS_ON_SIM_UNREAD
|
||||
* SmsManager.STATUS_ON_SIM_SEND
|
||||
* SmsManager.STATUS_ON_SIM_UNSENT
|
||||
* @deprecated Use getStatusOnIcc instead.
|
||||
*/
|
||||
@Deprecated public int getStatusOnSim() {
|
||||
return mWrappedSmsMessage.getStatusOnIcc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the message on the ICC (read, unread, sent, unsent).
|
||||
*
|
||||
* @return the status of the message on the ICC. These are:
|
||||
* SmsManager.STATUS_ON_ICC_FREE
|
||||
* SmsManager.STATUS_ON_ICC_READ
|
||||
* SmsManager.STATUS_ON_ICC_UNREAD
|
||||
* SmsManager.STATUS_ON_ICC_SEND
|
||||
* SmsManager.STATUS_ON_ICC_UNSENT
|
||||
*/
|
||||
public int getStatusOnIcc() {
|
||||
|
||||
return mWrappedSmsMessage.getStatusOnIcc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record index of the message on the SIM (1-based index).
|
||||
* @return the record index of the message on the SIM, or -1 if this
|
||||
* SmsMessage was not created from a SIM SMS EF record.
|
||||
* @deprecated Use getIndexOnIcc instead.
|
||||
*/
|
||||
@Deprecated public int getIndexOnSim() {
|
||||
return mWrappedSmsMessage.getIndexOnIcc();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record index of the message on the ICC (1-based index).
|
||||
* @return the record index of the message on the ICC, or -1 if this
|
||||
* SmsMessage was not created from a ICC SMS EF record.
|
||||
*/
|
||||
public int getIndexOnIcc() {
|
||||
|
||||
return mWrappedSmsMessage.getIndexOnIcc();
|
||||
}
|
||||
|
||||
/**
|
||||
* GSM:
|
||||
* For an SMS-STATUS-REPORT message, this returns the status field from
|
||||
* the status report. This field indicates the status of a previously
|
||||
* submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a
|
||||
* description of values.
|
||||
* CDMA:
|
||||
* For not interfering with status codes from GSM, the value is
|
||||
* shifted to the bits 31-16.
|
||||
* The value is composed of an error class (bits 25-24) and a status code (bits 23-16).
|
||||
* Possible codes are described in C.S0015-B, v2.0, 4.5.21.
|
||||
*
|
||||
* @return 0 indicates the previously sent message was received.
|
||||
* See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21
|
||||
* for a description of other possible values.
|
||||
*/
|
||||
public int getStatus() {
|
||||
return mWrappedSmsMessage.getStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true iff the message is a SMS-STATUS-REPORT message.
|
||||
*/
|
||||
public boolean isStatusReportMessage() {
|
||||
return mWrappedSmsMessage.isStatusReportMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true iff the <code>TP-Reply-Path</code> bit is set in
|
||||
* this message.
|
||||
*/
|
||||
public boolean isReplyPathPresent() {
|
||||
return mWrappedSmsMessage.isReplyPathPresent();
|
||||
}
|
||||
|
||||
/** This method returns the reference to a specific
|
||||
* SmsMessage object, which is used for accessing its static methods.
|
||||
* @return Specific SmsMessage.
|
||||
*/
|
||||
private static final SmsMessageBase getSmsFacility(){
|
||||
int activePhone = TelephonyManager.getDefault().getPhoneType();
|
||||
if (PHONE_TYPE_CDMA == activePhone) {
|
||||
return new com.android.internal.telephony.cdma.SmsMessage();
|
||||
} else {
|
||||
return new com.android.internal.telephony.gsm.SmsMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,25 +28,31 @@ import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.telephony.CellLocation;
|
||||
|
||||
import com.android.internal.telephony.IPhoneSubInfo;
|
||||
import com.android.internal.telephony.ITelephony;
|
||||
import com.android.internal.telephony.ITelephonyRegistry;
|
||||
import com.android.internal.telephony.RILConstants;
|
||||
import com.android.internal.telephony.TelephonyProperties;
|
||||
|
||||
/**
|
||||
* Provides access to information about the telephony services on
|
||||
* the device. Applications can use the methods in this class to
|
||||
* determine telephony services and states, as well as to access some
|
||||
* types of subscriber information. Applications can also register
|
||||
* a listener to receive notification of telephony state changes.
|
||||
* types of subscriber information. Applications can also register
|
||||
* a listener to receive notification of telephony state changes.
|
||||
* <p>
|
||||
* You do not instantiate this class directly; instead, you retrieve
|
||||
* a reference to an instance through
|
||||
* a reference to an instance through
|
||||
* {@link android.content.Context#getSystemService
|
||||
* Context.getSystemService(Context.TELEPHONY_SERVICE)}.
|
||||
* <p>
|
||||
* Note that acess to some telephony information is
|
||||
* permission-protected. Your application cannot access the protected
|
||||
* information unless it has the appropriate permissions declared in
|
||||
* its manifest file. Where permissions apply, they are noted in the
|
||||
* the methods through which you access the protected information.
|
||||
* permission-protected. Your application cannot access the protected
|
||||
* information unless it has the appropriate permissions declared in
|
||||
* its manifest file. Where permissions apply, they are noted in the
|
||||
* the methods through which you access the protected information.
|
||||
*/
|
||||
public class TelephonyManager {
|
||||
private static final String TAG = "TelephonyManager";
|
||||
@@ -166,10 +172,10 @@ public class TelephonyManager {
|
||||
//
|
||||
|
||||
/**
|
||||
* Returns the software version number for the device, for example,
|
||||
* Returns the software version number for the device, for example,
|
||||
* the IMEI/SV for GSM phones.
|
||||
*
|
||||
* <p>Requires Permission:
|
||||
* <p>Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
|
||||
*/
|
||||
public String getDeviceSoftwareVersion() {
|
||||
@@ -181,10 +187,10 @@ public class TelephonyManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique device ID, for example,the IMEI for GSM
|
||||
* Returns the unique device ID, for example, the IMEI for GSM and the MEID for CDMA
|
||||
* phones.
|
||||
*
|
||||
* <p>Requires Permission:
|
||||
* <p>Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
|
||||
*/
|
||||
public String getDeviceId() {
|
||||
@@ -214,7 +220,7 @@ public class TelephonyManager {
|
||||
* Enables location update notifications. {@link PhoneStateListener#onCellLocationChanged
|
||||
* PhoneStateListener.onCellLocationChanged} will be called on location updates.
|
||||
*
|
||||
* <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES
|
||||
* <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES
|
||||
* CONTROL_LOCATION_UPDATES}
|
||||
*
|
||||
* @hide
|
||||
@@ -270,23 +276,37 @@ public class TelephonyManager {
|
||||
public static final int PHONE_TYPE_GSM = 1;
|
||||
|
||||
/**
|
||||
* Returns a constant indicating the device phone type.
|
||||
*
|
||||
* CDMA phone
|
||||
* @hide
|
||||
*/
|
||||
public static final int PHONE_TYPE_CDMA = 2;
|
||||
|
||||
/**
|
||||
* Returns a constant indicating the device phone type.
|
||||
*
|
||||
* @see #PHONE_TYPE_NONE
|
||||
* @see #PHONE_TYPE_GSM
|
||||
* @see #PHONE_TYPE_CDMA
|
||||
*/
|
||||
public int getPhoneType() {
|
||||
// in the future, we should really check this
|
||||
return PHONE_TYPE_GSM;
|
||||
try{
|
||||
if(getITelephony().getActivePhoneType() == RILConstants.CDMA_PHONE) {
|
||||
return PHONE_TYPE_CDMA;
|
||||
} else {
|
||||
return PHONE_TYPE_GSM;
|
||||
}
|
||||
}catch(RemoteException ex){
|
||||
return PHONE_TYPE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// Current Network
|
||||
//
|
||||
//
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the alphabetic name of current registered operator.
|
||||
* <p>
|
||||
* Availability: Only when user is registered to a network
|
||||
@@ -295,7 +315,7 @@ public class TelephonyManager {
|
||||
return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ALPHA);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the numeric name (MCC+MNC) of current registered operator.
|
||||
* <p>
|
||||
* Availability: Only when user is registered to a network
|
||||
@@ -304,7 +324,7 @@ public class TelephonyManager {
|
||||
return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns true if the device is considered roaming on the current
|
||||
* network, for GSM purposes.
|
||||
* <p>
|
||||
@@ -314,7 +334,7 @@ public class TelephonyManager {
|
||||
return "true".equals(SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING));
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the ISO country code equivilent of the current registered
|
||||
* operator's MCC (Mobile Country Code).
|
||||
* <p>
|
||||
@@ -332,9 +352,20 @@ public class TelephonyManager {
|
||||
public static final int NETWORK_TYPE_EDGE = 2;
|
||||
/** Current network is UMTS */
|
||||
public static final int NETWORK_TYPE_UMTS = 3;
|
||||
/** Current network is CDMA: Either IS95A or IS95B*/
|
||||
/** @hide */
|
||||
public static final int NETWORK_TYPE_CDMA = 4;
|
||||
/** Current network is EVDO revision 0 or revision A*/
|
||||
/** @hide */
|
||||
public static final int NETWORK_TYPE_EVDO_0 = 5;
|
||||
/** @hide */
|
||||
public static final int NETWORK_TYPE_EVDO_A = 6;
|
||||
/** Current network is 1xRTT*/
|
||||
/** @hide */
|
||||
public static final int NETWORK_TYPE_1xRTT = 7;
|
||||
|
||||
/**
|
||||
* Returns a constant indicating the radio technology (network type)
|
||||
* Returns a constant indicating the radio technology (network type)
|
||||
* currently in use on the device.
|
||||
* @return the network type
|
||||
*
|
||||
@@ -342,6 +373,10 @@ public class TelephonyManager {
|
||||
* @see #NETWORK_TYPE_GPRS
|
||||
* @see #NETWORK_TYPE_EDGE
|
||||
* @see #NETWORK_TYPE_UMTS
|
||||
* @see #NETWORK_TYPE_CDMA
|
||||
* @see #NETWORK_TYPE_EVDO_0
|
||||
* @see #NETWORK_TYPE_EVDO_A
|
||||
* @see #NETWORK_TYPE_1xRTT
|
||||
*/
|
||||
public int getNetworkType() {
|
||||
String prop = SystemProperties.get(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE);
|
||||
@@ -354,6 +389,18 @@ public class TelephonyManager {
|
||||
else if ("UMTS".equals(prop)) {
|
||||
return NETWORK_TYPE_UMTS;
|
||||
}
|
||||
else if ("CDMA".equals(prop)) {
|
||||
return NETWORK_TYPE_CDMA;
|
||||
}
|
||||
else if ("CDMA - EvDo rev. 0".equals(prop)) {
|
||||
return NETWORK_TYPE_EVDO_0;
|
||||
}
|
||||
else if ("CDMA - EvDo rev. A".equals(prop)) {
|
||||
return NETWORK_TYPE_EVDO_A;
|
||||
}
|
||||
else if ("CDMA - 1xRTT".equals(prop)) {
|
||||
return NETWORK_TYPE_1xRTT;
|
||||
}
|
||||
else {
|
||||
return NETWORK_TYPE_UNKNOWN;
|
||||
}
|
||||
@@ -374,6 +421,14 @@ public class TelephonyManager {
|
||||
return "EDGE";
|
||||
case NETWORK_TYPE_UMTS:
|
||||
return "UMTS";
|
||||
case NETWORK_TYPE_CDMA:
|
||||
return "CDMA";
|
||||
case NETWORK_TYPE_EVDO_0:
|
||||
return "CDMA - EvDo rev. 0";
|
||||
case NETWORK_TYPE_EVDO_A:
|
||||
return "CDMA - EvDo rev. A";
|
||||
case NETWORK_TYPE_1xRTT:
|
||||
return "CDMA - 1xRTT";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
@@ -387,7 +442,7 @@ public class TelephonyManager {
|
||||
|
||||
/** SIM card state: Unknown. Signifies that the SIM is in transition
|
||||
* between states. For example, when the user inputs the SIM pin
|
||||
* under PIN_REQUIRED state, a query for sim status returns
|
||||
* under PIN_REQUIRED state, a query for sim status returns
|
||||
* this state before turning to SIM_STATE_READY. */
|
||||
public static final int SIM_STATE_UNKNOWN = 0;
|
||||
/** SIM card state: no SIM card is available in the device */
|
||||
@@ -400,11 +455,11 @@ public class TelephonyManager {
|
||||
public static final int SIM_STATE_NETWORK_LOCKED = 4;
|
||||
/** SIM card state: Ready */
|
||||
public static final int SIM_STATE_READY = 5;
|
||||
|
||||
/**
|
||||
* Returns a constant indicating the state of the
|
||||
|
||||
/**
|
||||
* Returns a constant indicating the state of the
|
||||
* device SIM card.
|
||||
*
|
||||
*
|
||||
* @see #SIM_STATE_UNKNOWN
|
||||
* @see #SIM_STATE_ABSENT
|
||||
* @see #SIM_STATE_PIN_REQUIRED
|
||||
@@ -434,7 +489,7 @@ public class TelephonyManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the MCC+MNC (mobile country code + mobile network code) of the
|
||||
* provider of the SIM. 5 or 6 decimal digits.
|
||||
* <p>
|
||||
@@ -443,36 +498,36 @@ public class TelephonyManager {
|
||||
* @see #getSimState
|
||||
*/
|
||||
public String getSimOperator() {
|
||||
return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC);
|
||||
return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Service Provider Name (SPN).
|
||||
/**
|
||||
* Returns the Service Provider Name (SPN).
|
||||
* <p>
|
||||
* Availability: SIM state must be {@link #SIM_STATE_READY}
|
||||
*
|
||||
* @see #getSimState
|
||||
*/
|
||||
public String getSimOperatorName() {
|
||||
return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_ALPHA);
|
||||
return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA);
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Returns the ISO country code equivalent for the SIM provider's country code.
|
||||
*/
|
||||
public String getSimCountryIso() {
|
||||
return SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_ISO_COUNTRY);
|
||||
return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the serial number of the SIM, if applicable.
|
||||
* <p>
|
||||
* Requires Permission:
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
|
||||
*/
|
||||
public String getSimSerialNumber() {
|
||||
try {
|
||||
return getSubscriberInfo().getSimSerialNumber();
|
||||
return getSubscriberInfo().getIccSerialNumber();
|
||||
} catch (RemoteException ex) {
|
||||
}
|
||||
return null;
|
||||
@@ -487,7 +542,7 @@ public class TelephonyManager {
|
||||
/**
|
||||
* Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
|
||||
* <p>
|
||||
* Requires Permission:
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
|
||||
*/
|
||||
public String getSubscriberId() {
|
||||
@@ -499,10 +554,10 @@ public class TelephonyManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the phone number string for line 1, for example, the MSISDN
|
||||
* Returns the phone number string for line 1, for example, the MSISDN
|
||||
* for a GSM phone.
|
||||
* <p>
|
||||
* Requires Permission:
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
|
||||
*/
|
||||
public String getLine1Number() {
|
||||
@@ -514,9 +569,9 @@ public class TelephonyManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alphabetic identifier associated with the line 1 number.
|
||||
* Returns the alphabetic identifier associated with the line 1 number.
|
||||
* <p>
|
||||
* Requires Permission:
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
|
||||
* @hide
|
||||
* nobody seems to call this.
|
||||
@@ -532,7 +587,7 @@ public class TelephonyManager {
|
||||
/**
|
||||
* Returns the voice mail number.
|
||||
* <p>
|
||||
* Requires Permission:
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
|
||||
*/
|
||||
public String getVoiceMailNumber() {
|
||||
@@ -547,7 +602,7 @@ public class TelephonyManager {
|
||||
* Retrieves the alphabetic identifier associated with the voice
|
||||
* mail number.
|
||||
* <p>
|
||||
* Requires Permission:
|
||||
* Requires Permission:
|
||||
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
|
||||
*/
|
||||
public String getVoiceMailAlphaTag() {
|
||||
@@ -567,10 +622,10 @@ public class TelephonyManager {
|
||||
/** Device call state: No activity. */
|
||||
public static final int CALL_STATE_IDLE = 0;
|
||||
/** Device call state: Ringing. A new call arrived and is
|
||||
* ringing or waiting. In the latter case, another call is
|
||||
* ringing or waiting. In the latter case, another call is
|
||||
* already active. */
|
||||
public static final int CALL_STATE_RINGING = 1;
|
||||
/** Device call state: Off-hook. At least one call exists
|
||||
/** Device call state: Off-hook. At least one call exists
|
||||
* that is dialing, active, or on hold, and no calls are ringing
|
||||
* or waiting. */
|
||||
public static final int CALL_STATE_OFFHOOK = 2;
|
||||
@@ -621,13 +676,13 @@ public class TelephonyManager {
|
||||
public static final int DATA_CONNECTING = 1;
|
||||
/** Data connection state: Connected. IP traffic should be available. */
|
||||
public static final int DATA_CONNECTED = 2;
|
||||
/** Data connection state: Suspended. The connection is up, but IP
|
||||
* traffic is temporarily unavailable. For example, in a 2G network,
|
||||
/** Data connection state: Suspended. The connection is up, but IP
|
||||
* traffic is temporarily unavailable. For example, in a 2G network,
|
||||
* data activity may be suspended when a voice call arrives. */
|
||||
public static final int DATA_SUSPENDED = 3;
|
||||
|
||||
/**
|
||||
* Returns a constant indicating the current data connection state
|
||||
* Returns a constant indicating the current data connection state
|
||||
* (cellular).
|
||||
*
|
||||
* @see #DATA_DISCONNECTED
|
||||
@@ -655,26 +710,26 @@ public class TelephonyManager {
|
||||
//
|
||||
|
||||
/**
|
||||
* Registers a listener object to receive notification of changes
|
||||
* in specified telephony states.
|
||||
* Registers a listener object to receive notification of changes
|
||||
* in specified telephony states.
|
||||
* <p>
|
||||
* To register a listener, pass a {@link PhoneStateListener}
|
||||
* and specify at least one telephony state of interest in
|
||||
* the events argument.
|
||||
*
|
||||
* and specify at least one telephony state of interest in
|
||||
* the events argument.
|
||||
*
|
||||
* At registration, and when a specified telephony state
|
||||
* changes, the telephony manager invokes the appropriate
|
||||
* callback method on the listener object and passes the
|
||||
* changes, the telephony manager invokes the appropriate
|
||||
* callback method on the listener object and passes the
|
||||
* current (udpated) values.
|
||||
* <p>
|
||||
* To unregister a listener, pass the listener object and set the
|
||||
* events argument to
|
||||
* events argument to
|
||||
* {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
|
||||
*
|
||||
*
|
||||
* @param listener The {@link PhoneStateListener} object to register
|
||||
* (or unregister)
|
||||
* @param events The telephony state(s) of interest to the listener,
|
||||
* as a bitwise-OR combination of {@link PhoneStateListener}
|
||||
* as a bitwise-OR combination of {@link PhoneStateListener}
|
||||
* LISTEN_ flags.
|
||||
*/
|
||||
public void listen(PhoneStateListener listener, int events) {
|
||||
|
||||
146
telephony/java/android/telephony/cdma/CdmaCellLocation.java
Normal file
146
telephony/java/android/telephony/cdma/CdmaCellLocation.java
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.telephony.cdma;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.telephony.CellLocation;
|
||||
|
||||
/**
|
||||
* Represents the cell location on a GSM phone.
|
||||
* @hide
|
||||
*/
|
||||
public class CdmaCellLocation extends CellLocation {
|
||||
private int mBaseStationId = -1;
|
||||
private int mBaseStationLatitude = -1;
|
||||
private int mBaseStationLongitude = -1;
|
||||
|
||||
/**
|
||||
* Empty constructor. Initializes the LAC and CID to -1.
|
||||
*/
|
||||
public CdmaCellLocation() {
|
||||
this.mBaseStationId = -1;
|
||||
this.mBaseStationLatitude = -1;
|
||||
this.mBaseStationLongitude = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the object from a bundle.
|
||||
*/
|
||||
public CdmaCellLocation(Bundle bundleWithValues) {
|
||||
this.mBaseStationId = bundleWithValues.getInt("baseStationId");
|
||||
this.mBaseStationLatitude = bundleWithValues.getInt("baseStationLatitude");
|
||||
this.mBaseStationLongitude = bundleWithValues.getInt("baseStationLongitude");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return cdma base station identification number, -1 if unknown
|
||||
*/
|
||||
public int getBaseStationId() {
|
||||
return this.mBaseStationId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return cdma base station latitude, -1 if unknown
|
||||
*/
|
||||
public int getBaseStationLatitude() {
|
||||
return this.mBaseStationLatitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return cdma base station longitude, -1 if unknown
|
||||
*/
|
||||
public int getBaseStationLongitude() {
|
||||
return this.mBaseStationLongitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate this object. The cell location data is set to -1.
|
||||
*/
|
||||
public void setStateInvalid() {
|
||||
this.mBaseStationId = -1;
|
||||
this.mBaseStationLatitude = -1;
|
||||
this.mBaseStationLongitude = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cell location data.
|
||||
*/
|
||||
public void setCellLocationData(int baseStationId, int baseStationLatitude,
|
||||
int baseStationLongitude) {
|
||||
// The following values have to be written in the correct sequence
|
||||
this.mBaseStationId = baseStationId;
|
||||
this.mBaseStationLatitude = baseStationLatitude; //values[2];
|
||||
this.mBaseStationLongitude = baseStationLongitude; //values[3];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.mBaseStationId ^ this.mBaseStationLatitude ^ this.mBaseStationLongitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
CdmaCellLocation s;
|
||||
|
||||
try {
|
||||
s = (CdmaCellLocation)o;
|
||||
} catch (ClassCastException ex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (o == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (equalsHandlesNulls(this.mBaseStationId, s.mBaseStationId) &&
|
||||
equalsHandlesNulls(this.mBaseStationLatitude, s.mBaseStationLatitude) &&
|
||||
equalsHandlesNulls(this.mBaseStationLongitude, s.mBaseStationLongitude)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + this.mBaseStationId + ","
|
||||
+ this.mBaseStationLatitude + ","
|
||||
+ this.mBaseStationLongitude + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether two objects hold the same data values or both are null
|
||||
*
|
||||
* @param a first obj
|
||||
* @param b second obj
|
||||
* @return true if two objects equal or both are null
|
||||
*/
|
||||
private static boolean equalsHandlesNulls(Object a, Object b) {
|
||||
return (a == null) ? (b == null) : a.equals (b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the cell location data into the intent notifier Bundle based on service state
|
||||
*
|
||||
* @param bundleToFill intent notifier Bundle
|
||||
*/
|
||||
public void fillInNotifierBundle(Bundle bundleToFill) {
|
||||
bundleToFill.putInt("baseStationId", this.mBaseStationId);
|
||||
bundleToFill.putInt("baseStationLatitude", this.mBaseStationLatitude);
|
||||
bundleToFill.putInt("baseStationLongitude", this.mBaseStationLongitude);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
5
telephony/java/android/telephony/cdma/package.html
Normal file
5
telephony/java/android/telephony/cdma/package.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<HTML>
|
||||
<BODY>
|
||||
Provides APIs for utilizing CDMA-specific telephony features.
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -17,14 +17,12 @@
|
||||
package android.telephony.gsm;
|
||||
|
||||
import android.os.Bundle;
|
||||
import com.android.internal.telephony.Phone;
|
||||
import android.telephony.CellLocation;
|
||||
|
||||
/**
|
||||
* Represents the cell location on a GSM phone.
|
||||
*/
|
||||
public class GsmCellLocation extends CellLocation
|
||||
{
|
||||
public class GsmCellLocation extends CellLocation {
|
||||
private int mLac;
|
||||
private int mCid;
|
||||
|
||||
@@ -82,7 +80,7 @@ public class GsmCellLocation extends CellLocation
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
GsmCellLocation s;
|
||||
|
||||
|
||||
try {
|
||||
s = (GsmCellLocation)o;
|
||||
} catch (ClassCastException ex) {
|
||||
@@ -100,7 +98,7 @@ public class GsmCellLocation extends CellLocation
|
||||
public String toString() {
|
||||
return "["+ mLac + "," + mCid + "]";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test whether two objects hold the same data values or both are null
|
||||
*
|
||||
|
||||
@@ -17,28 +17,35 @@
|
||||
package android.telephony.gsm;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.os.RemoteException;
|
||||
import android.os.IServiceManager;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.ServiceManagerNative;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.internal.telephony.gsm.EncodeException;
|
||||
import com.android.internal.telephony.gsm.GsmAlphabet;
|
||||
import com.android.internal.telephony.gsm.ISms;
|
||||
import com.android.internal.telephony.gsm.SimConstants;
|
||||
import com.android.internal.telephony.gsm.SmsRawData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Manages SMS operations such as sending data, text, and pdu SMS messages.
|
||||
* Get this object by calling the static method SmsManager.getDefault().
|
||||
* @deprecated Replaced by android.telephony.SmsManager that supports both GSM and CDMA.
|
||||
*/
|
||||
public final class SmsManager {
|
||||
@Deprecated public final class SmsManager {
|
||||
private static SmsManager sInstance;
|
||||
private android.telephony.SmsManager mSmsMgrProxy;
|
||||
|
||||
/** Get the default instance of the SmsManager
|
||||
*
|
||||
* @return the default instance of the SmsManager
|
||||
* @deprecated Use android.telephony.SmsManager.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final SmsManager getDefault() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new SmsManager();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private SmsManager() {
|
||||
mSmsMgrProxy = android.telephony.SmsManager.getDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a text based SMS.
|
||||
@@ -55,28 +62,21 @@ public final class SmsManager {
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* The per-application based SMS control checks sentIntent. If sentIntent
|
||||
* is NULL the caller will be checked against all unknown applicaitons,
|
||||
* is NULL the caller will be checked against all unknown applications,
|
||||
* which cause smaller number of SMS to be sent in checking period.
|
||||
* @param deliveryIntent if not NULL this <code>PendingIntent</code> is
|
||||
* broadcast when the message is delivered to the recipient. The
|
||||
* raw pdu of the status report is in the extended data ("pdu").
|
||||
*
|
||||
* @throws IllegalArgumentException if destinationAddress or text are empty
|
||||
* @deprecated Use android.telephony.SmsManager.
|
||||
*/
|
||||
public void sendTextMessage(
|
||||
@Deprecated
|
||||
public final void sendTextMessage(
|
||||
String destinationAddress, String scAddress, String text,
|
||||
PendingIntent sentIntent, PendingIntent deliveryIntent) {
|
||||
if (TextUtils.isEmpty(destinationAddress)) {
|
||||
throw new IllegalArgumentException("Invalid destinationAddress");
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
throw new IllegalArgumentException("Invalid message body");
|
||||
}
|
||||
|
||||
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(
|
||||
scAddress, destinationAddress, text, (deliveryIntent != null));
|
||||
sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
|
||||
mSmsMgrProxy.sendTextMessage(destinationAddress, scAddress, text,
|
||||
sentIntent, deliveryIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,55 +86,24 @@ public final class SmsManager {
|
||||
* @param text the original message. Must not be null.
|
||||
* @return an <code>ArrayList</code> of strings that, in order,
|
||||
* comprise the original message
|
||||
* @deprecated Use android.telephony.SmsManager.
|
||||
*/
|
||||
public ArrayList<String> divideMessage(String text) {
|
||||
int size = text.length();
|
||||
int[] params = SmsMessage.calculateLength(text, false);
|
||||
/* SmsMessage.calculateLength returns an int[4] with:
|
||||
* int[0] being the number of SMS's required,
|
||||
* int[1] the number of code units used,
|
||||
* int[2] is the number of code units remaining until the next message.
|
||||
* int[3] is the encoding type that should be used for the message.
|
||||
*/
|
||||
int messageCount = params[0];
|
||||
int encodingType = params[3];
|
||||
ArrayList<String> result = new ArrayList<String>(messageCount);
|
||||
|
||||
int start = 0;
|
||||
int limit;
|
||||
|
||||
if (messageCount > 1) {
|
||||
limit = (encodingType == SmsMessage.ENCODING_7BIT) ?
|
||||
SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER :
|
||||
SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
|
||||
} else {
|
||||
limit = (encodingType == SmsMessage.ENCODING_7BIT) ?
|
||||
SmsMessage.MAX_USER_DATA_SEPTETS : SmsMessage.MAX_USER_DATA_BYTES;
|
||||
}
|
||||
|
||||
try {
|
||||
while (start < size) {
|
||||
int end = GsmAlphabet.findLimitIndex(text, start, limit, encodingType);
|
||||
result.add(text.substring(start, end));
|
||||
start = end;
|
||||
}
|
||||
} catch (EncodeException e) {
|
||||
// ignore it.
|
||||
}
|
||||
return result;
|
||||
@Deprecated
|
||||
public final ArrayList<String> divideMessage(String text) {
|
||||
return mSmsMgrProxy.divideMessage(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a multi-part text based SMS. The callee should have already
|
||||
* divided the message into correctly sized parts by calling
|
||||
* <code>divideMessage</code>.
|
||||
*
|
||||
*
|
||||
* @param destinationAddress the address to send the message to
|
||||
* @param scAddress is the service center address or null to use
|
||||
* the current default SMSC
|
||||
* @param parts an <code>ArrayList</code> of strings that, in order,
|
||||
* comprise the original message
|
||||
* @param sentIntents if not null, an <code>ArrayList</code> of
|
||||
* @param sentIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been sent.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
@@ -145,44 +114,21 @@ public final class SmsManager {
|
||||
* The per-application based SMS control checks sentIntent. If sentIntent
|
||||
* is NULL the caller will be checked against all unknown applicaitons,
|
||||
* which cause smaller number of SMS to be sent in checking period.
|
||||
* @param deliveryIntents if not null, an <code>ArrayList</code> of
|
||||
* @param deliveryIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been delivered
|
||||
* to the recipient. The raw pdu of the status report is in the
|
||||
* extended data ("pdu").
|
||||
*
|
||||
* @throws IllegalArgumentException if destinationAddress or data are empty
|
||||
* @deprecated Use android.telephony.SmsManager.
|
||||
*/
|
||||
public void sendMultipartTextMessage(
|
||||
@Deprecated
|
||||
public final void sendMultipartTextMessage(
|
||||
String destinationAddress, String scAddress, ArrayList<String> parts,
|
||||
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
|
||||
if (TextUtils.isEmpty(destinationAddress)) {
|
||||
throw new IllegalArgumentException("Invalid destinationAddress");
|
||||
}
|
||||
if (parts == null || parts.size() < 1) {
|
||||
throw new IllegalArgumentException("Invalid message body");
|
||||
}
|
||||
|
||||
if (parts.size() > 1) {
|
||||
try {
|
||||
ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (simISms != null) {
|
||||
simISms.sendMultipartText(destinationAddress, scAddress, parts,
|
||||
sentIntents, deliveryIntents);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
} else {
|
||||
PendingIntent sentIntent = null;
|
||||
PendingIntent deliveryIntent = null;
|
||||
if (sentIntents != null && sentIntents.size() > 0) {
|
||||
sentIntent = sentIntents.get(0);
|
||||
}
|
||||
if (deliveryIntents != null && deliveryIntents.size() > 0) {
|
||||
deliveryIntent = deliveryIntents.get(0);
|
||||
}
|
||||
sendTextMessage(destinationAddress, scAddress, parts.get(0),
|
||||
sentIntent, deliveryIntent);
|
||||
}
|
||||
mSmsMgrProxy.sendMultipartTextMessage(destinationAddress, scAddress, parts,
|
||||
sentIntents, deliveryIntents);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -208,70 +154,14 @@ public final class SmsManager {
|
||||
* raw pdu of the status report is in the extended data ("pdu").
|
||||
*
|
||||
* @throws IllegalArgumentException if destinationAddress or data are empty
|
||||
* @deprecated Use android.telephony.SmsManager.
|
||||
*/
|
||||
public void sendDataMessage(
|
||||
@Deprecated
|
||||
public final void sendDataMessage(
|
||||
String destinationAddress, String scAddress, short destinationPort,
|
||||
byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
|
||||
if (TextUtils.isEmpty(destinationAddress)) {
|
||||
throw new IllegalArgumentException("Invalid destinationAddress");
|
||||
}
|
||||
|
||||
if (data == null || data.length == 0) {
|
||||
throw new IllegalArgumentException("Invalid message data");
|
||||
}
|
||||
|
||||
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
|
||||
destinationPort, data, (deliveryIntent != null));
|
||||
sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a raw SMS PDU.
|
||||
*
|
||||
* @param smsc the SMSC to send the message through, or NULL for the
|
||||
* default SMSC
|
||||
* @param pdu the raw PDU to send
|
||||
* @param sentIntent if not NULL this <code>PendingIntent</code> is
|
||||
* broadcast when the message is sucessfully sent, or failed.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
* or one of these errors:
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* The per-application based SMS control checks sentIntent. If sentIntent
|
||||
* is NULL the caller will be checked against all unknown applicaitons,
|
||||
* which cause smaller number of SMS to be sent in checking period.
|
||||
* @param deliveryIntent if not NULL this <code>PendingIntent</code> is
|
||||
* broadcast when the message is delivered to the recipient. The
|
||||
* raw pdu of the status report is in the extended data ("pdu").
|
||||
*
|
||||
*/
|
||||
private void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
|
||||
PendingIntent deliveryIntent) {
|
||||
try {
|
||||
ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (simISms != null) {
|
||||
simISms.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default instance of the SmsManager
|
||||
*
|
||||
* @return the default instance of the SmsManager
|
||||
*/
|
||||
public static SmsManager getDefault() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new SmsManager();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private SmsManager() {
|
||||
// nothing to see here
|
||||
mSmsMgrProxy.sendDataMessage(destinationAddress, scAddress, destinationPort,
|
||||
data, sentIntent, deliveryIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -282,22 +172,12 @@ public final class SmsManager {
|
||||
* @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD,
|
||||
* STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT)
|
||||
* @return true for success
|
||||
*
|
||||
* @deprecated Use android.telephony.SmsManager.
|
||||
* {@hide}
|
||||
*/
|
||||
public boolean copyMessageToSim(byte[] smsc, byte[] pdu, int status) {
|
||||
boolean success = false;
|
||||
|
||||
try {
|
||||
ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (simISms != null) {
|
||||
success = simISms.copyMessageToSimEf(status, pdu, smsc);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
|
||||
return success;
|
||||
@Deprecated
|
||||
public final boolean copyMessageToSim(byte[] smsc, byte[] pdu, int status) {
|
||||
return mSmsMgrProxy.copyMessageToIcc(smsc, pdu, status);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,26 +185,12 @@ public final class SmsManager {
|
||||
*
|
||||
* @param messageIndex is the record index of the message on SIM
|
||||
* @return true for success
|
||||
*
|
||||
* @deprecated Use android.telephony.SmsManager.
|
||||
* {@hide}
|
||||
*/
|
||||
public boolean
|
||||
deleteMessageFromSim(int messageIndex) {
|
||||
boolean success = false;
|
||||
byte[] pdu = new byte[SimConstants.SMS_RECORD_LENGTH-1];
|
||||
Arrays.fill(pdu, (byte)0xff);
|
||||
|
||||
try {
|
||||
ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (simISms != null) {
|
||||
success = simISms.updateMessageOnSimEf(messageIndex,
|
||||
STATUS_ON_SIM_FREE, pdu);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
|
||||
return success;
|
||||
@Deprecated
|
||||
public final boolean deleteMessageFromSim(int messageIndex) {
|
||||
return mSmsMgrProxy.deleteMessageFromIcc(messageIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,97 +202,59 @@ public final class SmsManager {
|
||||
* STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE)
|
||||
* @param pdu the raw PDU to store
|
||||
* @return true for success
|
||||
*
|
||||
* @deprecated Use android.telephony.SmsManager.
|
||||
* {@hide}
|
||||
*/
|
||||
public boolean updateMessageOnSim(int messageIndex, int newStatus,
|
||||
byte[] pdu) {
|
||||
boolean success = false;
|
||||
|
||||
try {
|
||||
ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (simISms != null) {
|
||||
success = simISms.updateMessageOnSimEf(messageIndex, newStatus, pdu);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
|
||||
return success;
|
||||
@Deprecated
|
||||
public final boolean updateMessageOnSim(int messageIndex, int newStatus, byte[] pdu) {
|
||||
return mSmsMgrProxy.updateMessageOnIcc(messageIndex, newStatus, pdu);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves all messages currently stored on SIM.
|
||||
*
|
||||
* @return <code>ArrayList</code> of <code>SmsMessage</code> objects
|
||||
*
|
||||
* @deprecated Use android.telephony.SmsManager.
|
||||
* {@hide}
|
||||
*/
|
||||
public ArrayList<SmsMessage> getAllMessagesFromSim() {
|
||||
List<SmsRawData> records = null;
|
||||
|
||||
try {
|
||||
ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
|
||||
if (simISms != null) {
|
||||
records = simISms.getAllMessagesFromSimEf();
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
}
|
||||
|
||||
return createMessageListFromRawRecords(records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a list of <code>SmsMessage</code>s from a list of RawSmsData
|
||||
* records returned by <code>getAllMessagesFromSim()</code>
|
||||
*
|
||||
* @param records SMS EF records, returned by
|
||||
* <code>getAllMessagesFromSim</code>
|
||||
* @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
|
||||
*/
|
||||
private ArrayList<SmsMessage> createMessageListFromRawRecords(List records) {
|
||||
ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
|
||||
if (records != null) {
|
||||
int count = records.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
SmsRawData data = (SmsRawData)records.get(i);
|
||||
// List contains all records, including "free" records (null)
|
||||
if (data != null) {
|
||||
SmsMessage sms =
|
||||
SmsMessage.createFromEfRecord(i+1, data.getBytes());
|
||||
messages.add(sms);
|
||||
}
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
@Deprecated
|
||||
public final ArrayList<android.telephony.SmsMessage> getAllMessagesFromSim() {
|
||||
return mSmsMgrProxy.getAllMessagesFromIcc();
|
||||
}
|
||||
|
||||
/** Free space (TS 51.011 10.5.3). */
|
||||
static public final int STATUS_ON_SIM_FREE = 0;
|
||||
/** Free space (TS 51.011 10.5.3).
|
||||
* @deprecated Use android.telephony.SmsManager. */
|
||||
@Deprecated static public final int STATUS_ON_SIM_FREE = 0;
|
||||
|
||||
/** Received and read (TS 51.011 10.5.3). */
|
||||
static public final int STATUS_ON_SIM_READ = 1;
|
||||
/** Received and read (TS 51.011 10.5.3).
|
||||
* @deprecated Use android.telephony.SmsManager. */
|
||||
@Deprecated static public final int STATUS_ON_SIM_READ = 1;
|
||||
|
||||
/** Received and unread (TS 51.011 10.5.3). */
|
||||
static public final int STATUS_ON_SIM_UNREAD = 3;
|
||||
/** Received and unread (TS 51.011 10.5.3).
|
||||
* @deprecated Use android.telephony.SmsManager. */
|
||||
@Deprecated static public final int STATUS_ON_SIM_UNREAD = 3;
|
||||
|
||||
/** Stored and sent (TS 51.011 10.5.3). */
|
||||
static public final int STATUS_ON_SIM_SENT = 5;
|
||||
/** Stored and sent (TS 51.011 10.5.3).
|
||||
* @deprecated Use android.telephony.SmsManager. */
|
||||
@Deprecated static public final int STATUS_ON_SIM_SENT = 5;
|
||||
|
||||
/** Stored and unsent (TS 51.011 10.5.3). */
|
||||
static public final int STATUS_ON_SIM_UNSENT = 7;
|
||||
/** Stored and unsent (TS 51.011 10.5.3).
|
||||
* @deprecated Use android.telephony.SmsManager. */
|
||||
@Deprecated static public final int STATUS_ON_SIM_UNSENT = 7;
|
||||
|
||||
/** Generic failure cause
|
||||
* @deprecated Use android.telephony.SmsManager. */
|
||||
@Deprecated static public final int RESULT_ERROR_GENERIC_FAILURE = 1;
|
||||
|
||||
// SMS send failure result codes
|
||||
/** Failed because radio was explicitly turned off
|
||||
* @deprecated Use android.telephony.SmsManager. */
|
||||
@Deprecated static public final int RESULT_ERROR_RADIO_OFF = 2;
|
||||
|
||||
/** Failed because no pdu provided
|
||||
* @deprecated Use android.telephony.SmsManager. */
|
||||
@Deprecated static public final int RESULT_ERROR_NULL_PDU = 3;
|
||||
|
||||
/** Failed because service is currently unavailable
|
||||
* @deprecated Use android.telephony.SmsManager. */
|
||||
@Deprecated static public final int RESULT_ERROR_NO_SERVICE = 4;
|
||||
|
||||
/** Generic failure cause */
|
||||
static public final int RESULT_ERROR_GENERIC_FAILURE = 1;
|
||||
/** Failed because radio was explicitly turned off */
|
||||
static public final int RESULT_ERROR_RADIO_OFF = 2;
|
||||
/** Failed because no pdu provided */
|
||||
static public final int RESULT_ERROR_NULL_PDU = 3;
|
||||
/** Failed because service is currently unavailable */
|
||||
static public final int RESULT_ERROR_NO_SERVICE = 4;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -34,7 +34,7 @@ public class ATResponseParser
|
||||
{
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
|
||||
public boolean
|
||||
nextBoolean()
|
||||
{
|
||||
@@ -147,7 +147,7 @@ public class ATResponseParser
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Throws ATParseEx if whitespace extends to the end of string */
|
||||
private char
|
||||
skipWhiteSpace (char c)
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
parcelable AdnRecord;
|
||||
|
||||
283
telephony/java/com/android/internal/telephony/AdnRecord.java
Normal file
283
telephony/java/com/android/internal/telephony/AdnRecord.java
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.GsmAlphabet;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Used to load or store ADNs (Abbreviated Dialing Numbers).
|
||||
*
|
||||
* {@hide}
|
||||
*
|
||||
*/
|
||||
public class AdnRecord implements Parcelable {
|
||||
static final String LOG_TAG = "GSM";
|
||||
|
||||
//***** Instance Variables
|
||||
|
||||
String alphaTag = "";
|
||||
String number = "";
|
||||
int extRecord = 0xff;
|
||||
int efid; // or 0 if none
|
||||
int recordNumber; // or 0 if none
|
||||
|
||||
|
||||
//***** Constants
|
||||
|
||||
// In an ADN record, everything but the alpha identifier
|
||||
// is in a footer that's 14 bytes
|
||||
static final int FOOTER_SIZE_BYTES = 14;
|
||||
|
||||
// Maximum size of the un-extended number field
|
||||
static final int MAX_NUMBER_SIZE_BYTES = 11;
|
||||
|
||||
static final int EXT_RECORD_LENGTH_BYTES = 13;
|
||||
static final int EXT_RECORD_TYPE_ADDITIONAL_DATA = 2;
|
||||
static final int EXT_RECORD_TYPE_MASK = 3;
|
||||
static final int MAX_EXT_CALLED_PARTY_LENGTH = 0xa;
|
||||
|
||||
// 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_CAPABILITY_ID = 12;
|
||||
static final int ADN_EXTENSION_ID = 13;
|
||||
|
||||
//***** Static Methods
|
||||
|
||||
public static final Parcelable.Creator<AdnRecord> CREATOR
|
||||
= new Parcelable.Creator<AdnRecord>() {
|
||||
public AdnRecord createFromParcel(Parcel source) {
|
||||
int efid;
|
||||
int recordNumber;
|
||||
String alphaTag;
|
||||
String number;
|
||||
|
||||
efid = source.readInt();
|
||||
recordNumber = source.readInt();
|
||||
alphaTag = source.readString();
|
||||
number = source.readString();
|
||||
|
||||
return new AdnRecord(efid, recordNumber, alphaTag, number);
|
||||
}
|
||||
|
||||
public AdnRecord[] newArray(int size) {
|
||||
return new AdnRecord[size];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//***** Constructor
|
||||
public
|
||||
AdnRecord (byte[] record) {
|
||||
this(0, 0, record);
|
||||
}
|
||||
|
||||
public
|
||||
AdnRecord (int efid, int recordNumber, byte[] record) {
|
||||
this.efid = efid;
|
||||
this.recordNumber = recordNumber;
|
||||
parseRecord(record);
|
||||
}
|
||||
|
||||
public
|
||||
AdnRecord (String alphaTag, String number) {
|
||||
this(0, 0, alphaTag, number);
|
||||
}
|
||||
|
||||
public
|
||||
AdnRecord (int efid, int recordNumber, String alphaTag, String number) {
|
||||
this.efid = efid;
|
||||
this.recordNumber = recordNumber;
|
||||
this.alphaTag = alphaTag;
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
//***** Instance Methods
|
||||
|
||||
public String getAlphaTag() {
|
||||
return alphaTag;
|
||||
}
|
||||
|
||||
public String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "ADN Record '" + alphaTag + "' '" + number + "'";
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return alphaTag.equals("") && number.equals("");
|
||||
}
|
||||
|
||||
public boolean hasExtendedRecord() {
|
||||
return extRecord != 0 && extRecord != 0xff;
|
||||
}
|
||||
|
||||
public boolean isEqual(AdnRecord adn) {
|
||||
return ( alphaTag.equals(adn.getAlphaTag()) &&
|
||||
number.equals(adn.getNumber()) );
|
||||
}
|
||||
//***** Parcelable Implementation
|
||||
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(efid);
|
||||
dest.writeInt(recordNumber);
|
||||
dest.writeString(alphaTag);
|
||||
dest.writeString(number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build adn hex byte array based on record size
|
||||
* The format of byte array is defined in 51.011 10.5.1
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public byte[] buildAdnString(int recordSize) {
|
||||
byte[] bcdNumber;
|
||||
byte[] byteTag;
|
||||
byte[] adnString = null;
|
||||
int footerOffset = recordSize - FOOTER_SIZE_BYTES;
|
||||
|
||||
if (number == null || number.equals("") ||
|
||||
alphaTag == null || alphaTag.equals("")) {
|
||||
|
||||
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;
|
||||
}
|
||||
} else if (number.length()
|
||||
> (ADN_DAILING_NUMBER_END - ADN_DAILING_NUMBER_START + 1) * 2) {
|
||||
Log.w(LOG_TAG,
|
||||
"[buildAdnString] Max length of dailing number is 20");
|
||||
} else if (alphaTag.length() > footerOffset) {
|
||||
Log.w(LOG_TAG,
|
||||
"[buildAdnString] Max length of tag is " + footerOffset);
|
||||
} 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,
|
||||
footerOffset + ADN_TON_AND_NPI, bcdNumber.length);
|
||||
|
||||
adnString[footerOffset + ADN_BCD_NUMBER_LENGTH]
|
||||
= (byte) (bcdNumber.length);
|
||||
adnString[footerOffset + ADN_CAPABILITY_ID]
|
||||
= (byte) 0xFF; // Capacility Id
|
||||
adnString[footerOffset + ADN_EXTENSION_ID]
|
||||
= (byte) 0xFF; // Extension Record Id
|
||||
|
||||
byteTag = GsmAlphabet.stringToGsm8BitPacked(alphaTag);
|
||||
System.arraycopy(byteTag, 0, adnString, 0, byteTag.length);
|
||||
|
||||
}
|
||||
|
||||
return adnString;
|
||||
}
|
||||
|
||||
/**
|
||||
* See TS 51.011 10.5.10
|
||||
*/
|
||||
public void
|
||||
appendExtRecord (byte[] extRecord) {
|
||||
try {
|
||||
if (extRecord.length != EXT_RECORD_LENGTH_BYTES) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((extRecord[0] & EXT_RECORD_TYPE_MASK)
|
||||
!= EXT_RECORD_TYPE_ADDITIONAL_DATA) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((0xff & extRecord[1]) > MAX_EXT_CALLED_PARTY_LENGTH) {
|
||||
// invalid or empty record
|
||||
return;
|
||||
}
|
||||
|
||||
number += PhoneNumberUtils.calledPartyBCDFragmentToString(
|
||||
extRecord, 2, 0xff & extRecord[1]);
|
||||
|
||||
// We don't support ext record chaining.
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
Log.w(LOG_TAG, "Error parsing AdnRecord ext record", ex);
|
||||
}
|
||||
}
|
||||
|
||||
//***** Private Methods
|
||||
|
||||
/**
|
||||
* alphaTag and number are set to null on invalid format
|
||||
*/
|
||||
private void
|
||||
parseRecord(byte[] record) {
|
||||
try {
|
||||
alphaTag = IccUtils.adnStringFieldToString(
|
||||
record, 0, record.length - FOOTER_SIZE_BYTES);
|
||||
|
||||
int footerOffset = record.length - FOOTER_SIZE_BYTES;
|
||||
|
||||
int numberLength = 0xff & record[footerOffset];
|
||||
|
||||
if (numberLength > MAX_NUMBER_SIZE_BYTES) {
|
||||
// Invalid number length
|
||||
number = "";
|
||||
return;
|
||||
}
|
||||
|
||||
// Please note 51.011 10.5.1:
|
||||
//
|
||||
// "If the Dialling Number/SSC String does not contain
|
||||
// a dialling number, e.g. a control string deactivating
|
||||
// a service, the TON/NPI byte shall be set to 'FF' by
|
||||
// the ME (see note 2)."
|
||||
|
||||
number = PhoneNumberUtils.calledPartyBCDToString(
|
||||
record, footerOffset + 1, numberLength);
|
||||
|
||||
|
||||
extRecord = 0xff & record[record.length - 1];
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
Log.w(LOG_TAG, "Error parsing AdnRecord", ex);
|
||||
number = "";
|
||||
alphaTag = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import android.util.Log;
|
||||
@@ -23,18 +23,18 @@ import android.os.Handler;
|
||||
import android.os.AsyncResult;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import com.android.internal.telephony.IccConstants;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public final class AdnRecordCache extends Handler implements SimConstants
|
||||
{
|
||||
public final class AdnRecordCache extends Handler implements IccConstants {
|
||||
//***** Instance Variables
|
||||
|
||||
GSMPhone phone;
|
||||
PhoneBase phone;
|
||||
|
||||
// Indexed by EF ID
|
||||
SparseArray<ArrayList<AdnRecord>> adnLikeFiles
|
||||
SparseArray<ArrayList<AdnRecord>> adnLikeFiles
|
||||
= new SparseArray<ArrayList<AdnRecord>>();
|
||||
|
||||
// People waiting for ADN-like files to be loaded
|
||||
@@ -52,9 +52,8 @@ public final class AdnRecordCache extends Handler implements SimConstants
|
||||
//***** Constructor
|
||||
|
||||
|
||||
/*package*/
|
||||
AdnRecordCache(GSMPhone phone)
|
||||
{
|
||||
|
||||
public AdnRecordCache(PhoneBase phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
@@ -63,14 +62,12 @@ public final class AdnRecordCache extends Handler implements SimConstants
|
||||
/**
|
||||
* Called from SIMRecords.onRadioNotAvailable and SIMRecords.handleSimRefresh.
|
||||
*/
|
||||
/*package*/ void
|
||||
reset()
|
||||
{
|
||||
public void reset() {
|
||||
adnLikeFiles.clear();
|
||||
|
||||
clearWaiters();
|
||||
clearUserWriters();
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void clearWaiters() {
|
||||
@@ -95,29 +92,27 @@ public final class AdnRecordCache extends Handler implements SimConstants
|
||||
* @return List of AdnRecords for efid if we've already loaded them this
|
||||
* radio session, or null if we haven't
|
||||
*/
|
||||
/*package*/ ArrayList<AdnRecord>
|
||||
getRecordsIfLoaded(int efid)
|
||||
{
|
||||
public ArrayList<AdnRecord>
|
||||
getRecordsIfLoaded(int efid) {
|
||||
return adnLikeFiles.get(efid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns extension ef associated with ADN-like EF or -1 if
|
||||
* Returns extension ef associated with ADN-like EF or -1 if
|
||||
* we don't know.
|
||||
*
|
||||
* See 3GPP TS 51.011 for this mapping
|
||||
*/
|
||||
private int
|
||||
extensionEfForEf(int efid)
|
||||
{
|
||||
extensionEfForEf(int efid) {
|
||||
switch (efid) {
|
||||
case EF_MBDN: return EF_EXT6;
|
||||
case EF_ADN: return EF_EXT1;
|
||||
case EF_SDN: return EF_EXT3;
|
||||
case EF_FDN: return EF_EXT2;
|
||||
case EF_MSISDN: return EF_EXT1;
|
||||
case EF_MSISDN: return EF_EXT1;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendErrorResponse(Message response, String errString) {
|
||||
@@ -138,7 +133,7 @@ public final class AdnRecordCache extends Handler implements SimConstants
|
||||
* @param response message to be posted when done
|
||||
* response.exception hold the exception in error
|
||||
*/
|
||||
void updateAdnByIndex(int efid, AdnRecord adn, int recordIndex, String pin2,
|
||||
public void updateAdnByIndex(int efid, AdnRecord adn, int recordIndex, String pin2,
|
||||
Message response) {
|
||||
|
||||
int extensionEF = extensionEfForEf(efid);
|
||||
@@ -174,7 +169,7 @@ public final class AdnRecordCache extends Handler implements SimConstants
|
||||
* @param response message to be posted when done
|
||||
* response.exception hold the exception in error
|
||||
*/
|
||||
void updateAdnBySearch(int efid, AdnRecord oldAdn, AdnRecord newAdn,
|
||||
public void updateAdnBySearch(int efid, AdnRecord oldAdn, AdnRecord newAdn,
|
||||
String pin2, Message response) {
|
||||
|
||||
int extensionEF;
|
||||
@@ -227,9 +222,8 @@ public final class AdnRecordCache extends Handler implements SimConstants
|
||||
* Responds with exception (in response) if efid is not a known ADN-like
|
||||
* record
|
||||
*/
|
||||
/*package*/ void
|
||||
requestLoadAllAdnLike (int efid, Message response)
|
||||
{
|
||||
public void
|
||||
requestLoadAllAdnLike (int efid, Message response) {
|
||||
ArrayList<Message> waiters;
|
||||
ArrayList<AdnRecord> result;
|
||||
|
||||
@@ -256,25 +250,25 @@ public final class AdnRecordCache extends Handler implements SimConstants
|
||||
waiters.add(response);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Start loading efid
|
||||
|
||||
|
||||
waiters = new ArrayList<Message>();
|
||||
waiters.add(response);
|
||||
|
||||
adnLikeWaiters.put(efid, waiters);
|
||||
|
||||
int extensionEF = extensionEfForEf(efid);
|
||||
|
||||
|
||||
if (extensionEF < 0) {
|
||||
// respond with error if not known ADN-like record
|
||||
|
||||
if (response != null) {
|
||||
AsyncResult.forMessage(response).exception
|
||||
AsyncResult.forMessage(response).exception
|
||||
= new RuntimeException("EF is not known ADN-like EF:" + efid);
|
||||
response.sendToTarget();
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -285,8 +279,7 @@ public final class AdnRecordCache extends Handler implements SimConstants
|
||||
//***** Private methods
|
||||
|
||||
private void
|
||||
notifyWaiters(ArrayList<Message> waiters, AsyncResult ar)
|
||||
{
|
||||
notifyWaiters(ArrayList<Message> waiters, AsyncResult ar) {
|
||||
|
||||
if (waiters == null) {
|
||||
return;
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
public class AdnRecordLoader extends Handler {
|
||||
static String LOG_TAG;
|
||||
|
||||
//***** Instance Variables
|
||||
|
||||
PhoneBase phone;
|
||||
int ef;
|
||||
int extensionEF;
|
||||
int pendingExtLoads;
|
||||
Message userResponse;
|
||||
String pin2;
|
||||
|
||||
// For "load one"
|
||||
int recordNumber;
|
||||
|
||||
// for "load all"
|
||||
ArrayList<AdnRecord> adns; // only valid after EVENT_ADN_LOAD_ALL_DONE
|
||||
|
||||
// Either an AdnRecord or a reference to adns depending
|
||||
// if this is a load one or load all operation
|
||||
Object result;
|
||||
|
||||
//***** Event Constants
|
||||
|
||||
static final int EVENT_ADN_LOAD_DONE = 1;
|
||||
static final int EVENT_EXT_RECORD_LOAD_DONE = 2;
|
||||
static final int EVENT_ADN_LOAD_ALL_DONE = 3;
|
||||
static final int EVENT_EF_LINEAR_RECORD_SIZE_DONE = 4;
|
||||
static final int EVENT_UPDATE_RECORD_DONE = 5;
|
||||
|
||||
//***** Constructor
|
||||
|
||||
public AdnRecordLoader(PhoneBase phone) {
|
||||
// The telephony unit-test cases may create AdnRecords
|
||||
// in secondary threads
|
||||
super(phone.getHandler().getLooper());
|
||||
|
||||
this.phone = phone;
|
||||
LOG_TAG = phone.getPhoneName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resulting AdnRecord is placed in response.obj.result
|
||||
* or response.obj.exception is set
|
||||
*/
|
||||
public void
|
||||
loadFromEF(int ef, int extensionEF, int recordNumber,
|
||||
Message response) {
|
||||
this.ef = ef;
|
||||
this.extensionEF = extensionEF;
|
||||
this.recordNumber = recordNumber;
|
||||
this.userResponse = response;
|
||||
|
||||
phone.mIccFileHandler.loadEFLinearFixed(
|
||||
ef, recordNumber,
|
||||
obtainMessage(EVENT_ADN_LOAD_DONE));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Resulting ArrayList<adnRecord> is placed in response.obj.result
|
||||
* or response.obj.exception is set
|
||||
*/
|
||||
public void
|
||||
loadAllFromEF(int ef, int extensionEF,
|
||||
Message response) {
|
||||
this.ef = ef;
|
||||
this.extensionEF = extensionEF;
|
||||
this.userResponse = response;
|
||||
|
||||
phone.mIccFileHandler.loadEFLinearFixedAll(
|
||||
ef,
|
||||
obtainMessage(EVENT_ADN_LOAD_ALL_DONE));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Write adn to a EF SIM record
|
||||
* 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 ef EF fileid
|
||||
* @param extensionEF extension EF fileid
|
||||
* @param recordNumber 1-based record index
|
||||
* @param pin2 for CHV2 operations, must be null if pin2 is not needed
|
||||
* @param response will be sent to its handler when completed
|
||||
*/
|
||||
public void
|
||||
updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber,
|
||||
String pin2, Message response) {
|
||||
this.ef = ef;
|
||||
this.extensionEF = extensionEF;
|
||||
this.recordNumber = recordNumber;
|
||||
this.userResponse = response;
|
||||
this.pin2 = pin2;
|
||||
|
||||
phone.mIccFileHandler.getEFLinearRecordSize( ef,
|
||||
obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn));
|
||||
}
|
||||
|
||||
//***** Overridden from Handler
|
||||
|
||||
public void
|
||||
handleMessage(Message msg) {
|
||||
AsyncResult ar;
|
||||
byte data[];
|
||||
AdnRecord adn;
|
||||
|
||||
try {
|
||||
switch (msg.what) {
|
||||
case EVENT_EF_LINEAR_RECORD_SIZE_DONE:
|
||||
ar = (AsyncResult)(msg.obj);
|
||||
adn = (AdnRecord)(ar.userObj);
|
||||
|
||||
if (ar.exception != null) {
|
||||
throw new RuntimeException("get EF record size failed",
|
||||
ar.exception);
|
||||
}
|
||||
|
||||
int[] recordSize = (int[])ar.result;
|
||||
// recordSize is int[3] array
|
||||
// int[0] is the record length
|
||||
// int[1] is the total length of the EF file
|
||||
// int[2] is the number of records in the EF file
|
||||
// So int[0] * int[2] = int[1]
|
||||
if (recordSize.length != 3 || recordNumber > recordSize[2]) {
|
||||
throw new RuntimeException("get wrong EF record size format",
|
||||
ar.exception);
|
||||
}
|
||||
|
||||
data = adn.buildAdnString(recordSize[0]);
|
||||
|
||||
if(data == null) {
|
||||
throw new RuntimeException("worong ADN format",
|
||||
ar.exception);
|
||||
}
|
||||
|
||||
phone.mIccFileHandler.updateEFLinearFixed(ef, recordNumber,
|
||||
data, pin2, obtainMessage(EVENT_UPDATE_RECORD_DONE));
|
||||
|
||||
pendingExtLoads = 1;
|
||||
|
||||
break;
|
||||
case EVENT_UPDATE_RECORD_DONE:
|
||||
ar = (AsyncResult)(msg.obj);
|
||||
if (ar.exception != null) {
|
||||
throw new RuntimeException("update EF adn record failed",
|
||||
ar.exception);
|
||||
}
|
||||
pendingExtLoads = 0;
|
||||
result = null;
|
||||
break;
|
||||
case EVENT_ADN_LOAD_DONE:
|
||||
ar = (AsyncResult)(msg.obj);
|
||||
data = (byte[])(ar.result);
|
||||
|
||||
if (ar.exception != null) {
|
||||
throw new RuntimeException("load failed", ar.exception);
|
||||
}
|
||||
|
||||
if (false) {
|
||||
Log.d(LOG_TAG,"ADN EF: 0x"
|
||||
+ Integer.toHexString(ef)
|
||||
+ ":" + recordNumber
|
||||
+ "\n" + IccUtils.bytesToHexString(data));
|
||||
}
|
||||
|
||||
adn = new AdnRecord(ef, recordNumber, data);
|
||||
result = adn;
|
||||
|
||||
if (adn.hasExtendedRecord()) {
|
||||
// If we have a valid value in the ext record field,
|
||||
// we're not done yet: we need to read the corresponding
|
||||
// ext record and append it
|
||||
|
||||
pendingExtLoads = 1;
|
||||
|
||||
phone.mIccFileHandler.loadEFLinearFixed(
|
||||
extensionEF, adn.extRecord,
|
||||
obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn));
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_EXT_RECORD_LOAD_DONE:
|
||||
ar = (AsyncResult)(msg.obj);
|
||||
data = (byte[])(ar.result);
|
||||
adn = (AdnRecord)(ar.userObj);
|
||||
|
||||
if (ar.exception != null) {
|
||||
throw new RuntimeException("load failed", ar.exception);
|
||||
}
|
||||
|
||||
Log.d(LOG_TAG,"ADN extention EF: 0x"
|
||||
+ Integer.toHexString(extensionEF)
|
||||
+ ":" + adn.extRecord
|
||||
+ "\n" + IccUtils.bytesToHexString(data));
|
||||
|
||||
adn.appendExtRecord(data);
|
||||
|
||||
pendingExtLoads--;
|
||||
// result should have been set in
|
||||
// EVENT_ADN_LOAD_DONE or EVENT_ADN_LOAD_ALL_DONE
|
||||
break;
|
||||
|
||||
case EVENT_ADN_LOAD_ALL_DONE:
|
||||
ar = (AsyncResult)(msg.obj);
|
||||
ArrayList<byte[]> datas = (ArrayList<byte[]>)(ar.result);
|
||||
|
||||
if (ar.exception != null) {
|
||||
throw new RuntimeException("load failed", ar.exception);
|
||||
}
|
||||
|
||||
adns = new ArrayList<AdnRecord>(datas.size());
|
||||
result = adns;
|
||||
pendingExtLoads = 0;
|
||||
|
||||
for(int i = 0, s = datas.size() ; i < s ; i++) {
|
||||
adn = new AdnRecord(ef, 1 + i, datas.get(i));
|
||||
adns.add(adn);
|
||||
|
||||
if (adn.hasExtendedRecord()) {
|
||||
// If we have a valid value in the ext record field,
|
||||
// we're not done yet: we need to read the corresponding
|
||||
// ext record and append it
|
||||
|
||||
pendingExtLoads++;
|
||||
|
||||
phone.mIccFileHandler.loadEFLinearFixed(
|
||||
extensionEF, adn.extRecord,
|
||||
obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (RuntimeException exc) {
|
||||
if (userResponse != null) {
|
||||
AsyncResult.forMessage(userResponse)
|
||||
.exception = exc;
|
||||
userResponse.sendToTarget();
|
||||
// Loading is all or nothing--either every load succeeds
|
||||
// or we fail the whole thing.
|
||||
userResponse = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (userResponse != null && pendingExtLoads == 0) {
|
||||
AsyncResult.forMessage(userResponse).result
|
||||
= result;
|
||||
|
||||
userResponse.sendToTarget();
|
||||
userResponse = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
580
telephony/java/com/android/internal/telephony/BaseCommands.java
Normal file
580
telephony/java/com/android/internal/telephony/BaseCommands.java
Normal file
@@ -0,0 +1,580 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.RegistrantList;
|
||||
import android.os.Registrant;
|
||||
import android.os.Handler;
|
||||
import android.os.AsyncResult;
|
||||
import android.provider.Checkin;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public abstract class BaseCommands implements CommandsInterface {
|
||||
static final String LOG_TAG = "RILB";
|
||||
|
||||
//***** Instance Variables
|
||||
protected Context mContext;
|
||||
protected RadioState mState = RadioState.RADIO_UNAVAILABLE;
|
||||
protected Object mStateMonitor = new Object();
|
||||
|
||||
protected RegistrantList mRadioStateChangedRegistrants = new RegistrantList();
|
||||
protected RegistrantList mOnRegistrants = new RegistrantList();
|
||||
protected RegistrantList mAvailRegistrants = new RegistrantList();
|
||||
protected RegistrantList mOffOrNotAvailRegistrants = new RegistrantList();
|
||||
protected RegistrantList mNotAvailRegistrants = new RegistrantList();
|
||||
protected RegistrantList mSIMReadyRegistrants = new RegistrantList();
|
||||
protected RegistrantList mSIMLockedRegistrants = new RegistrantList();
|
||||
protected RegistrantList mRUIMReadyRegistrants = new RegistrantList();
|
||||
protected RegistrantList mRUIMLockedRegistrants = new RegistrantList();
|
||||
protected RegistrantList mNVReadyRegistrants = new RegistrantList();
|
||||
protected RegistrantList mCallStateRegistrants = new RegistrantList();
|
||||
protected RegistrantList mNetworkStateRegistrants = new RegistrantList();
|
||||
protected RegistrantList mDataConnectionRegistrants = new RegistrantList();
|
||||
protected RegistrantList mRadioTechnologyChangedRegistrants = new RegistrantList();
|
||||
protected RegistrantList mIccStatusChangedRegistrants = new RegistrantList();
|
||||
protected RegistrantList mVoicePrivacyOnRegistrants = new RegistrantList();
|
||||
protected RegistrantList mVoicePrivacyOffRegistrants = new RegistrantList();
|
||||
protected Registrant mSMSRegistrant;
|
||||
protected Registrant mNITZTimeRegistrant;
|
||||
protected Registrant mSignalStrengthRegistrant;
|
||||
protected Registrant mUSSDRegistrant;
|
||||
protected Registrant mSmsOnSimRegistrant;
|
||||
/** Registrant for handling SMS Status Reports */
|
||||
protected Registrant mSmsStatusRegistrant;
|
||||
/** Registrant for handling Supplementary Service Notifications */
|
||||
protected Registrant mSsnRegistrant;
|
||||
protected Registrant mStkSessionEndRegistrant;
|
||||
protected Registrant mStkProCmdRegistrant;
|
||||
protected Registrant mStkEventRegistrant;
|
||||
protected Registrant mStkCallSetUpRegistrant;
|
||||
/** Registrant for handling SIM/RUIM SMS storage full messages */
|
||||
protected Registrant mIccSmsFullRegistrant;
|
||||
/** Registrant for handling Icc Refresh notifications */
|
||||
protected Registrant mIccRefreshRegistrant;
|
||||
/** Registrant for handling RING notifications */
|
||||
protected Registrant mRingRegistrant;
|
||||
/** Registrant for handling RESTRICTED STATE changed notification */
|
||||
protected Registrant mRestrictedStateRegistrant;
|
||||
|
||||
//Network Mode received from PhoneFactory
|
||||
protected int mNetworkMode;
|
||||
//CDMA subscription received from PhoneFactory
|
||||
protected int mCdmaSubscription;
|
||||
//Type of Phone, GSM or CDMA. Set by CDMAPhone or GSMPhone.
|
||||
protected int mPhoneType;
|
||||
|
||||
|
||||
public BaseCommands(Context context) {
|
||||
mContext = context; // May be null (if so we won't log statistics)
|
||||
}
|
||||
|
||||
//***** CommandsInterface implementation
|
||||
|
||||
public RadioState getRadioState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
|
||||
public void registerForRadioStateChanged(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
mRadioStateChangedRegistrants.add(r);
|
||||
r.notifyRegistrant();
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForRadioStateChanged(Handler h) {
|
||||
synchronized (mStateMonitor) {
|
||||
mRadioStateChangedRegistrants.remove(h);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerForOn(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
mOnRegistrants.add(r);
|
||||
|
||||
if (mState.isOn()) {
|
||||
r.notifyRegistrant(new AsyncResult(null, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
public void unregisterForOn(Handler h) {
|
||||
synchronized (mStateMonitor) {
|
||||
mOnRegistrants.remove(h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void registerForAvailable(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
mAvailRegistrants.add(r);
|
||||
|
||||
if (mState.isAvailable()) {
|
||||
r.notifyRegistrant(new AsyncResult(null, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForAvailable(Handler h) {
|
||||
synchronized(mStateMonitor) {
|
||||
mAvailRegistrants.remove(h);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerForNotAvailable(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
mNotAvailRegistrants.add(r);
|
||||
|
||||
if (!mState.isAvailable()) {
|
||||
r.notifyRegistrant(new AsyncResult(null, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForNotAvailable(Handler h) {
|
||||
synchronized (mStateMonitor) {
|
||||
mNotAvailRegistrants.remove(h);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerForOffOrNotAvailable(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
mOffOrNotAvailRegistrants.add(r);
|
||||
|
||||
if (mState == RadioState.RADIO_OFF || !mState.isAvailable()) {
|
||||
r.notifyRegistrant(new AsyncResult(null, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
public void unregisterForOffOrNotAvailable(Handler h) {
|
||||
synchronized(mStateMonitor) {
|
||||
mOffOrNotAvailRegistrants.remove(h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Any transition into SIM_READY */
|
||||
public void registerForSIMReady(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
mSIMReadyRegistrants.add(r);
|
||||
|
||||
if (mState.isSIMReady()) {
|
||||
r.notifyRegistrant(new AsyncResult(null, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForSIMReady(Handler h) {
|
||||
synchronized (mStateMonitor) {
|
||||
mSIMReadyRegistrants.remove(h);
|
||||
}
|
||||
}
|
||||
|
||||
/** Any transition into RUIM_READY */
|
||||
public void registerForRUIMReady(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
mRUIMReadyRegistrants.add(r);
|
||||
|
||||
if (mState.isRUIMReady()) {
|
||||
r.notifyRegistrant(new AsyncResult(null, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForRUIMReady(Handler h) {
|
||||
synchronized(mStateMonitor) {
|
||||
mRUIMReadyRegistrants.remove(h);
|
||||
}
|
||||
}
|
||||
|
||||
/** Any transition into NV_READY */
|
||||
public void registerForNVReady(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
mNVReadyRegistrants.add(r);
|
||||
|
||||
if (mState.isNVReady()) {
|
||||
r.notifyRegistrant(new AsyncResult(null, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForNVReady(Handler h) {
|
||||
synchronized (mStateMonitor) {
|
||||
mNVReadyRegistrants.remove(h);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerForSIMLockedOrAbsent(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
mSIMLockedRegistrants.add(r);
|
||||
|
||||
if (mState == RadioState.SIM_LOCKED_OR_ABSENT) {
|
||||
r.notifyRegistrant(new AsyncResult(null, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForSIMLockedOrAbsent(Handler h) {
|
||||
synchronized (mStateMonitor) {
|
||||
mSIMLockedRegistrants.remove(h);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerForRUIMLockedOrAbsent(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
mRUIMLockedRegistrants.add(r);
|
||||
|
||||
if (mState == RadioState.RUIM_LOCKED_OR_ABSENT) {
|
||||
r.notifyRegistrant(new AsyncResult(null, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForRUIMLockedOrAbsent(Handler h) {
|
||||
synchronized (mStateMonitor) {
|
||||
mRUIMLockedRegistrants.remove(h);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerForCallStateChanged(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
mCallStateRegistrants.add(r);
|
||||
}
|
||||
|
||||
public void unregisterForCallStateChanged(Handler h) {
|
||||
mCallStateRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void registerForNetworkStateChanged(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
mNetworkStateRegistrants.add(r);
|
||||
}
|
||||
|
||||
public void unregisterForNetworkStateChanged(Handler h) {
|
||||
mNetworkStateRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void registerForDataStateChanged(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
mDataConnectionRegistrants.add(r);
|
||||
}
|
||||
|
||||
public void unregisterForDataStateChanged(Handler h) {
|
||||
mDataConnectionRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void registerForRadioTechnologyChanged(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
mRadioTechnologyChangedRegistrants.add(r);
|
||||
}
|
||||
|
||||
public void unregisterForRadioTechnologyChanged(Handler h) {
|
||||
mRadioTechnologyChangedRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void registerForIccStatusChanged(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
mIccStatusChangedRegistrants.add(r);
|
||||
}
|
||||
|
||||
public void unregisterForIccStatusChanged(Handler h) {
|
||||
mIccStatusChangedRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void setOnNewSMS(Handler h, int what, Object obj) {
|
||||
mSMSRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnNewSMS(Handler h) {
|
||||
mSMSRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnSmsOnSim(Handler h, int what, Object obj) {
|
||||
mSmsOnSimRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnSmsOnSim(Handler h) {
|
||||
mSmsOnSimRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnSmsStatus(Handler h, int what, Object obj) {
|
||||
mSmsStatusRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnSmsStatus(Handler h) {
|
||||
mSmsStatusRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnSignalStrengthUpdate(Handler h, int what, Object obj) {
|
||||
mSignalStrengthRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnSignalStrengthUpdate(Handler h) {
|
||||
mSignalStrengthRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnNITZTime(Handler h, int what, Object obj) {
|
||||
mNITZTimeRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnNITZTime(Handler h) {
|
||||
mNITZTimeRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnUSSD(Handler h, int what, Object obj) {
|
||||
mUSSDRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnUSSD(Handler h) {
|
||||
mUSSDRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnSuppServiceNotification(Handler h, int what, Object obj) {
|
||||
mSsnRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnSuppServiceNotification(Handler h) {
|
||||
mSsnRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnStkSessionEnd(Handler h, int what, Object obj) {
|
||||
mStkSessionEndRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnStkSessionEnd(Handler h) {
|
||||
mStkSessionEndRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnStkProactiveCmd(Handler h, int what, Object obj) {
|
||||
mStkProCmdRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnStkProactiveCmd(Handler h) {
|
||||
mStkProCmdRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnStkEvent(Handler h, int what, Object obj) {
|
||||
mStkEventRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnStkEvent(Handler h) {
|
||||
mStkEventRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnStkCallSetUp(Handler h, int what, Object obj) {
|
||||
mStkCallSetUpRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnStkCallSetUp(Handler h) {
|
||||
mStkCallSetUpRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnIccSmsFull(Handler h, int what, Object obj) {
|
||||
mIccSmsFullRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnIccSmsFull(Handler h) {
|
||||
mIccSmsFullRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnIccRefresh(Handler h, int what, Object obj) {
|
||||
mIccRefreshRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnIccRefresh(Handler h) {
|
||||
mIccRefreshRegistrant.clear();
|
||||
}
|
||||
|
||||
public void setOnCallRing(Handler h, int what, Object obj) {
|
||||
mRingRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnCallRing(Handler h) {
|
||||
mRingRegistrant.clear();
|
||||
}
|
||||
|
||||
public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
mVoicePrivacyOnRegistrants.add(r);
|
||||
}
|
||||
|
||||
public void unregisterForInCallVoicePrivacyOn(Handler h){
|
||||
mVoicePrivacyOnRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
mVoicePrivacyOffRegistrants.add(r);
|
||||
}
|
||||
|
||||
public void unregisterForInCallVoicePrivacyOff(Handler h){
|
||||
mVoicePrivacyOffRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void setOnRestrictedStateChanged(Handler h, int what, Object obj) {
|
||||
mRestrictedStateRegistrant = new Registrant (h, what, obj);
|
||||
}
|
||||
|
||||
public void unSetOnRestrictedStateChanged(Handler h) {
|
||||
mRestrictedStateRegistrant.clear();
|
||||
}
|
||||
|
||||
//***** Protected Methods
|
||||
/**
|
||||
* Store new RadioState and send notification based on the changes
|
||||
*
|
||||
* This function is called only by RIL.java when receiving unsolicited
|
||||
* RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED
|
||||
*
|
||||
* RadioState has 5 values : RADIO_OFF, RADIO_UNAVAILABLE, SIM_NOT_READY,
|
||||
* SIM_LOCKED_OR_ABSENT, and SIM_READY.
|
||||
*
|
||||
* @param newState new RadioState decoded from RIL_UNSOL_RADIO_STATE_CHANGED
|
||||
*/
|
||||
protected void setRadioState(RadioState newState) {
|
||||
RadioState oldState;
|
||||
|
||||
synchronized (mStateMonitor) {
|
||||
if (Config.LOGV) {
|
||||
Log.v(LOG_TAG, "setRadioState old: " + mState
|
||||
+ " new " + newState);
|
||||
}
|
||||
|
||||
oldState = mState;
|
||||
mState = newState;
|
||||
|
||||
if (oldState == mState) {
|
||||
// no state transition
|
||||
return;
|
||||
}
|
||||
|
||||
if (mContext != null &&
|
||||
newState == RadioState.RADIO_UNAVAILABLE &&
|
||||
oldState != RadioState.RADIO_OFF) {
|
||||
Checkin.updateStats(mContext.getContentResolver(),
|
||||
Checkin.Stats.Tag.PHONE_RADIO_RESETS, 1, 0.0);
|
||||
}
|
||||
|
||||
mRadioStateChangedRegistrants.notifyRegistrants();
|
||||
|
||||
if (mState.isAvailable() && !oldState.isAvailable()) {
|
||||
Log.d(LOG_TAG,"Notifying: radio available");
|
||||
mAvailRegistrants.notifyRegistrants();
|
||||
onRadioAvailable();
|
||||
}
|
||||
|
||||
if (!mState.isAvailable() && oldState.isAvailable()) {
|
||||
Log.d(LOG_TAG,"Notifying: radio not available");
|
||||
mNotAvailRegistrants.notifyRegistrants();
|
||||
}
|
||||
|
||||
if (mState.isSIMReady() && !oldState.isSIMReady()) {
|
||||
Log.d(LOG_TAG,"Notifying: SIM ready");
|
||||
mSIMReadyRegistrants.notifyRegistrants();
|
||||
}
|
||||
|
||||
if (mState == RadioState.SIM_LOCKED_OR_ABSENT) {
|
||||
Log.d(LOG_TAG,"Notifying: SIM locked or absent");
|
||||
mSIMLockedRegistrants.notifyRegistrants();
|
||||
}
|
||||
|
||||
if (mState.isRUIMReady() && !oldState.isRUIMReady()) {
|
||||
Log.d(LOG_TAG,"Notifying: RUIM ready");
|
||||
mRUIMReadyRegistrants.notifyRegistrants();
|
||||
}
|
||||
|
||||
if (mState == RadioState.RUIM_LOCKED_OR_ABSENT) {
|
||||
Log.d(LOG_TAG,"Notifying: RUIM locked or absent");
|
||||
mRUIMLockedRegistrants.notifyRegistrants();
|
||||
}
|
||||
if (mState.isNVReady() && !oldState.isNVReady()) {
|
||||
Log.d(LOG_TAG,"Notifying: NV ready");
|
||||
mNVReadyRegistrants.notifyRegistrants();
|
||||
}
|
||||
|
||||
if (mState.isOn() && !oldState.isOn()) {
|
||||
Log.d(LOG_TAG,"Notifying: Radio On");
|
||||
mOnRegistrants.notifyRegistrants();
|
||||
}
|
||||
|
||||
if ((!mState.isOn() || !mState.isAvailable())
|
||||
&& !((!oldState.isOn() || !oldState.isAvailable()))
|
||||
) {
|
||||
Log.d(LOG_TAG,"Notifying: radio off or not available");
|
||||
mOffOrNotAvailRegistrants.notifyRegistrants();
|
||||
}
|
||||
|
||||
/* Radio Technology Change events
|
||||
* NOTE: isGsm and isCdma have no common states in RADIO_OFF or RADIO_UNAVAILABLE; the
|
||||
* current phone is determined by mPhoneType
|
||||
* NOTE: at startup no phone have been created and the RIL determines the mPhoneType
|
||||
* looking based on the networkMode set by the PhoneFactory in the constructor
|
||||
*/
|
||||
|
||||
if (mState.isGsm() && oldState.isCdma()) {
|
||||
Log.d(LOG_TAG,"Notifying: radio technology change CDMA to GSM");
|
||||
mRadioTechnologyChangedRegistrants.notifyRegistrants();
|
||||
}
|
||||
|
||||
if (mState.isGsm() && !oldState.isOn() && (mPhoneType == RILConstants.CDMA_PHONE)) {
|
||||
Log.d(LOG_TAG,"Notifying: radio technology change CDMA OFF to GSM");
|
||||
mRadioTechnologyChangedRegistrants.notifyRegistrants();
|
||||
}
|
||||
|
||||
if (mState.isCdma() && oldState.isGsm()) {
|
||||
Log.d(LOG_TAG,"Notifying: radio technology change GSM to CDMA");
|
||||
mRadioTechnologyChangedRegistrants.notifyRegistrants();
|
||||
}
|
||||
|
||||
if (mState.isCdma() && !oldState.isOn() && (mPhoneType == RILConstants.GSM_PHONE)) {
|
||||
Log.d(LOG_TAG,"Notifying: radio technology change GSM OFF to CDMA");
|
||||
mRadioTechnologyChangedRegistrants.notifyRegistrants();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onRadioAvailable() {
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
@@ -39,6 +40,13 @@ public abstract class Call {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Instance Variables */
|
||||
|
||||
public State state = State.IDLE;
|
||||
|
||||
|
||||
|
||||
/* Instance Methods */
|
||||
|
||||
/** Do not modify the List result!!! This list is not yours to keep
|
||||
@@ -46,36 +54,46 @@ public abstract class Call {
|
||||
*/
|
||||
|
||||
public abstract List<Connection> getConnections();
|
||||
public abstract State getState();
|
||||
public abstract Phone getPhone();
|
||||
public abstract boolean isMultiparty();
|
||||
public abstract void hangup() throws CallStateException;
|
||||
|
||||
|
||||
/**
|
||||
* hasConnection
|
||||
*
|
||||
*
|
||||
* @param c a Connection object
|
||||
* @return true if the call contains the connection object passed in
|
||||
*/
|
||||
public boolean hasConnection(Connection c) {
|
||||
return c.getCall() == this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hasConnections
|
||||
* @return true if the call contains one or more connections
|
||||
*/
|
||||
public boolean hasConnections() {
|
||||
List connections = getConnections();
|
||||
|
||||
|
||||
if (connections == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return connections.size() > 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getState
|
||||
* @return state of class call
|
||||
*/
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* isIdle
|
||||
*
|
||||
*
|
||||
* FIXME rename
|
||||
* @return true if the call contains only disconnected connections (if any)
|
||||
*/
|
||||
@@ -93,27 +111,27 @@ public abstract class Call {
|
||||
long time = Long.MAX_VALUE;
|
||||
Connection c;
|
||||
Connection earliest = null;
|
||||
|
||||
|
||||
l = getConnections();
|
||||
|
||||
|
||||
if (l.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0, s = l.size() ; i < s ; i++) {
|
||||
c = (Connection) l.get(i);
|
||||
long t;
|
||||
|
||||
|
||||
t = c.getCreateTime();
|
||||
|
||||
|
||||
if (t < time) {
|
||||
earliest = c;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return earliest;
|
||||
}
|
||||
|
||||
|
||||
public long
|
||||
getEarliestCreateTime() {
|
||||
List l;
|
||||
@@ -160,9 +178,6 @@ public abstract class Call {
|
||||
return time;
|
||||
}
|
||||
|
||||
public abstract boolean isMultiparty();
|
||||
|
||||
public abstract void hangup() throws CallStateException;
|
||||
|
||||
public boolean
|
||||
isDialingOrAlerting() {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
|
||||
@@ -23,8 +23,7 @@ import android.telephony.PhoneNumberUtils;
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class CallForwardInfo
|
||||
{
|
||||
public class CallForwardInfo {
|
||||
public int status; /*1 = active, 0 = not active */
|
||||
public int reason; /* from TS 27.007 7.11 "reason" */
|
||||
public int serviceClass; /* Sum of CommandsInterface.SERVICE_CLASS */
|
||||
@@ -32,8 +31,7 @@ public class CallForwardInfo
|
||||
public String number; /* "number" from TS 27.007 7.11 */
|
||||
public int timeSeconds; /* for CF no reply only */
|
||||
|
||||
public String toString()
|
||||
{
|
||||
public String toString() {
|
||||
return super.toString() + (status == 0 ? " not active " : " active ")
|
||||
+ " reason: " + reason
|
||||
+ " serviceClass: " + serviceClass
|
||||
123
telephony/java/com/android/internal/telephony/CallTracker.java
Normal file
123
telephony/java/com/android/internal/telephony/CallTracker.java
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.CommandException;
|
||||
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public abstract class CallTracker extends Handler {
|
||||
|
||||
private static final boolean DBG_POLL = false;
|
||||
|
||||
//***** Constants
|
||||
|
||||
static final int POLL_DELAY_MSEC = 250;
|
||||
|
||||
protected int pendingOperations;
|
||||
protected boolean needsPoll;
|
||||
protected Message lastRelevantPoll;
|
||||
|
||||
public CommandsInterface cm;
|
||||
|
||||
|
||||
//***** Events
|
||||
|
||||
protected static final int EVENT_POLL_CALLS_RESULT = 1;
|
||||
protected static final int EVENT_CALL_STATE_CHANGE = 2;
|
||||
protected static final int EVENT_REPOLL_AFTER_DELAY = 3;
|
||||
protected static final int EVENT_OPERATION_COMPLETE = 4;
|
||||
protected static final int EVENT_GET_LAST_CALL_FAIL_CAUSE = 5;
|
||||
|
||||
protected static final int EVENT_SWITCH_RESULT = 8;
|
||||
protected static final int EVENT_RADIO_AVAILABLE = 9;
|
||||
protected static final int EVENT_RADIO_NOT_AVAILABLE = 10;
|
||||
protected static final int EVENT_CONFERENCE_RESULT = 11;
|
||||
protected static final int EVENT_SEPARATE_RESULT = 12;
|
||||
protected static final int EVENT_ECT_RESULT = 13;
|
||||
|
||||
|
||||
protected void pollCallsWhenSafe() {
|
||||
needsPoll = true;
|
||||
|
||||
if (checkNoOperationsPending()) {
|
||||
lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
|
||||
cm.getCurrentCalls(lastRelevantPoll);
|
||||
}
|
||||
}
|
||||
|
||||
protected void
|
||||
pollCallsAfterDelay() {
|
||||
Message msg = obtainMessage();
|
||||
|
||||
msg.what = EVENT_REPOLL_AFTER_DELAY;
|
||||
sendMessageDelayed(msg, POLL_DELAY_MSEC);
|
||||
}
|
||||
|
||||
protected boolean
|
||||
isCommandExceptionRadioNotAvailable(Throwable e) {
|
||||
return e != null && e instanceof CommandException
|
||||
&& ((CommandException)e).getCommandError()
|
||||
== CommandException.Error.RADIO_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
protected abstract void handlePollCalls(AsyncResult ar);
|
||||
|
||||
protected void handleRadioAvailable() {
|
||||
pollCallsWhenSafe();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a complete message that indicates that this operation
|
||||
* does not require polling of getCurrentCalls(). However, if other
|
||||
* operations that do need getCurrentCalls() are pending or are
|
||||
* scheduled while this operation is pending, the invocation
|
||||
* of getCurrentCalls() will be postponed until this
|
||||
* operation is also complete.
|
||||
*/
|
||||
protected Message
|
||||
obtainNoPollCompleteMessage(int what) {
|
||||
pendingOperations++;
|
||||
lastRelevantPoll = null;
|
||||
return obtainMessage(what);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if we're idle or there's a call to getCurrentCalls() pending
|
||||
* but nothing else
|
||||
*/
|
||||
private boolean
|
||||
checkNoOperationsPending() {
|
||||
if (DBG_POLL) log("checkNoOperationsPending: pendingOperations=" +
|
||||
pendingOperations);
|
||||
return pendingOperations == 0;
|
||||
}
|
||||
|
||||
|
||||
//***** Overridden from Handler
|
||||
public abstract void handleMessage (Message msg);
|
||||
|
||||
protected abstract void log(String msg);
|
||||
|
||||
}
|
||||
@@ -37,7 +37,7 @@ import android.util.Log;
|
||||
public class CallerInfoAsyncQuery {
|
||||
|
||||
private static final boolean DBG = false;
|
||||
private static final String LOG_TAG = "CallerInfoAsyncQuery";
|
||||
private static final String LOG_TAG = "PHONE";
|
||||
|
||||
private static final int EVENT_NEW_QUERY = 1;
|
||||
private static final int EVENT_ADD_LISTENER = 2;
|
||||
|
||||
@@ -14,15 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import com.android.internal.telephony.RILConstants;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class CommandException extends RuntimeException
|
||||
{
|
||||
public class CommandException extends RuntimeException {
|
||||
private Error e;
|
||||
|
||||
public enum Error {
|
||||
@@ -38,30 +39,28 @@ public class CommandException extends RuntimeException
|
||||
SMS_FAIL_RETRY,
|
||||
}
|
||||
|
||||
public CommandException(Error e)
|
||||
{
|
||||
public CommandException(Error e) {
|
||||
super(e.toString());
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
public static CommandException
|
||||
fromRilErrno(int ril_errno)
|
||||
{
|
||||
fromRilErrno(int ril_errno) {
|
||||
switch(ril_errno) {
|
||||
case RILConstants.SUCCESS: return null;
|
||||
case RILConstants.RIL_ERRNO_INVALID_RESPONSE:
|
||||
case RILConstants.RIL_ERRNO_INVALID_RESPONSE:
|
||||
return new CommandException(Error.INVALID_RESPONSE);
|
||||
case RILConstants.RADIO_NOT_AVAILABLE:
|
||||
case RILConstants.RADIO_NOT_AVAILABLE:
|
||||
return new CommandException(Error.RADIO_NOT_AVAILABLE);
|
||||
case RILConstants.GENERIC_FAILURE:
|
||||
case RILConstants.GENERIC_FAILURE:
|
||||
return new CommandException(Error.GENERIC_FAILURE);
|
||||
case RILConstants.PASSWORD_INCORRECT:
|
||||
case RILConstants.PASSWORD_INCORRECT:
|
||||
return new CommandException(Error.PASSWORD_INCORRECT);
|
||||
case RILConstants.SIM_PIN2:
|
||||
case RILConstants.SIM_PIN2:
|
||||
return new CommandException(Error.SIM_PIN2);
|
||||
case RILConstants.SIM_PUK2:
|
||||
case RILConstants.SIM_PUK2:
|
||||
return new CommandException(Error.SIM_PUK2);
|
||||
case RILConstants.REQUEST_NOT_SUPPORTED:
|
||||
case RILConstants.REQUEST_NOT_SUPPORTED:
|
||||
return new CommandException(Error.REQUEST_NOT_SUPPORTED);
|
||||
case RILConstants.OP_NOT_ALLOWED_DURING_VOICE_CALL:
|
||||
return new CommandException(Error.OP_NOT_ALLOWED_DURING_VOICE_CALL);
|
||||
@@ -75,8 +74,7 @@ public class CommandException extends RuntimeException
|
||||
}
|
||||
}
|
||||
|
||||
public Error getCommandError()
|
||||
{
|
||||
public Error getCommandError() {
|
||||
return e;
|
||||
}
|
||||
|
||||
@@ -14,50 +14,79 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
import com.android.internal.telephony.*;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.os.Message;
|
||||
import android.os.Handler;
|
||||
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public interface CommandsInterface
|
||||
{
|
||||
public interface CommandsInterface {
|
||||
enum RadioState {
|
||||
RADIO_OFF, /* Radio explictly powered off (eg CFUN=0) */
|
||||
RADIO_UNAVAILABLE, /* Radio unavailable (eg, resetting or not booted) */
|
||||
SIM_NOT_READY, /* Radio is on, but the SIM interface is not ready */
|
||||
SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network
|
||||
SIM_LOCKED_OR_ABSENT, /* SIM PIN locked, PUK required, network
|
||||
personalization, or SIM absent */
|
||||
SIM_READY; /* Radio is on and SIM interface is available */
|
||||
SIM_READY, /* Radio is on and SIM interface is available */
|
||||
RUIM_NOT_READY, /* Radio is on, but the RUIM interface is not ready */
|
||||
RUIM_READY, /* Radio is on and the RUIM interface is available */
|
||||
RUIM_LOCKED_OR_ABSENT, /* RUIM PIN locked, PUK required, network
|
||||
personalization locked, or RUIM absent */
|
||||
NV_NOT_READY, /* Radio is on, but the NV interface is not available */
|
||||
NV_READY; /* Radio is on and the NV interface is available */
|
||||
|
||||
boolean isOn() /* and available...*/
|
||||
{
|
||||
public boolean isOn() /* and available...*/ {
|
||||
return this == SIM_NOT_READY
|
||||
|| this == SIM_LOCKED_OR_ABSENT
|
||||
|| this == SIM_READY
|
||||
|| this == RUIM_NOT_READY
|
||||
|| this == RUIM_READY
|
||||
|| this == RUIM_LOCKED_OR_ABSENT
|
||||
|| this == NV_NOT_READY
|
||||
|| this == NV_READY;
|
||||
}
|
||||
|
||||
public boolean isAvailable() {
|
||||
return this != RADIO_UNAVAILABLE;
|
||||
}
|
||||
|
||||
public boolean isSIMReady() {
|
||||
return this == SIM_READY;
|
||||
}
|
||||
|
||||
public boolean isRUIMReady() {
|
||||
return this == RUIM_READY;
|
||||
}
|
||||
|
||||
public boolean isNVReady() {
|
||||
return this == NV_READY;
|
||||
}
|
||||
|
||||
public boolean isGsm() {
|
||||
return this == SIM_NOT_READY
|
||||
|| this == SIM_LOCKED_OR_ABSENT
|
||||
|| this == SIM_READY;
|
||||
}
|
||||
|
||||
boolean isAvailable()
|
||||
{
|
||||
return this != RADIO_UNAVAILABLE;
|
||||
}
|
||||
|
||||
boolean isSIMReady()
|
||||
{
|
||||
// if you add new states after SIM_READY, include them too
|
||||
return this == SIM_READY;
|
||||
public boolean isCdma() {
|
||||
return this == RUIM_NOT_READY
|
||||
|| this == RUIM_READY
|
||||
|| this == RUIM_LOCKED_OR_ABSENT
|
||||
|| this == NV_NOT_READY
|
||||
|| this == NV_READY;
|
||||
}
|
||||
}
|
||||
|
||||
enum SimStatus {
|
||||
SIM_ABSENT,
|
||||
SIM_NOT_READY,
|
||||
SIM_READY,
|
||||
SIM_PIN,
|
||||
SIM_PUK,
|
||||
SIM_NETWORK_PERSONALIZATION
|
||||
enum IccStatus {
|
||||
ICC_ABSENT,
|
||||
ICC_NOT_READY,
|
||||
ICC_READY,
|
||||
ICC_PIN,
|
||||
ICC_PUK,
|
||||
ICC_NETWORK_PERSONALIZATION
|
||||
}
|
||||
|
||||
//***** Constants
|
||||
@@ -93,7 +122,7 @@ public interface CommandsInterface
|
||||
static final String CB_FACILITY_BA_MT = "AC";
|
||||
static final String CB_FACILITY_BA_SIM = "SC";
|
||||
static final String CB_FACILITY_BA_FD = "FD";
|
||||
|
||||
|
||||
|
||||
// Used for various supp services apis
|
||||
// See 27.007 +CCFC or +CLCK
|
||||
@@ -102,7 +131,7 @@ public interface CommandsInterface
|
||||
static final int SERVICE_CLASS_DATA = (1 << 1); //synoym for 16+32+64+128
|
||||
static final int SERVICE_CLASS_FAX = (1 << 2);
|
||||
static final int SERVICE_CLASS_SMS = (1 << 3);
|
||||
static final int SERVICE_CLASS_DATA_SYNC = (1 << 4);
|
||||
static final int SERVICE_CLASS_DATA_SYNC = (1 << 4);
|
||||
static final int SERVICE_CLASS_DATA_ASYNC = (1 << 5);
|
||||
static final int SERVICE_CLASS_PACKET = (1 << 6);
|
||||
static final int SERVICE_CLASS_PAD = (1 << 7);
|
||||
@@ -122,8 +151,8 @@ public interface CommandsInterface
|
||||
|
||||
RadioState getRadioState();
|
||||
|
||||
/**
|
||||
* Fires on any RadioState transition
|
||||
/**
|
||||
* Fires on any RadioState transition
|
||||
* Always fires immediately as well
|
||||
*
|
||||
* do not attempt to calculate transitions by storing getRadioState() values
|
||||
@@ -131,58 +160,85 @@ public interface CommandsInterface
|
||||
* registration methods
|
||||
*/
|
||||
void registerForRadioStateChanged(Handler h, int what, Object obj);
|
||||
void unregisterForRadioStateChanged(Handler h);
|
||||
|
||||
/**
|
||||
* Fires on any transition into RadioState.isOn()
|
||||
/**
|
||||
* Fires on any transition into RadioState.isOn()
|
||||
* Fires immediately if currently in that state
|
||||
* In general, actions should be idempotent. State may change
|
||||
* before event is received.
|
||||
*/
|
||||
void registerForOn(Handler h, int what, Object obj);
|
||||
void unregisterForOn(Handler h);
|
||||
|
||||
/**
|
||||
* Fires on any transition out of RadioState.isAvailable()
|
||||
/**
|
||||
* Fires on any transition out of RadioState.isAvailable()
|
||||
* Fires immediately if currently in that state
|
||||
* In general, actions should be idempotent. State may change
|
||||
* before event is received.
|
||||
*/
|
||||
void registerForAvailable(Handler h, int what, Object obj);
|
||||
//void unregisterForAvailable(Handler h);
|
||||
/**
|
||||
void unregisterForAvailable(Handler h);
|
||||
|
||||
/**
|
||||
* Fires on any transition into !RadioState.isAvailable()
|
||||
* Fires immediately if currently in that state
|
||||
* In general, actions should be idempotent. State may change
|
||||
* before event is received.
|
||||
*/
|
||||
void registerForNotAvailable(Handler h, int what, Object obj);
|
||||
//void unregisterForNotAvailable(Handler h);
|
||||
/**
|
||||
void unregisterForNotAvailable(Handler h);
|
||||
|
||||
/**
|
||||
* Fires on any transition into RADIO_OFF or !RadioState.isAvailable()
|
||||
* Fires immediately if currently in that state
|
||||
* In general, actions should be idempotent. State may change
|
||||
* before event is received.
|
||||
*/
|
||||
void registerForOffOrNotAvailable(Handler h, int what, Object obj);
|
||||
//void unregisterForNotAvailable(Handler h);
|
||||
void unregisterForOffOrNotAvailable(Handler h);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Fires on any transition into SIM_READY
|
||||
* Fires immediately if if currently in that state
|
||||
* In general, actions should be idempotent. State may change
|
||||
* before event is received.
|
||||
*/
|
||||
void registerForSIMReady(Handler h, int what, Object obj);
|
||||
//void unregisterForSIMReady(Handler h);
|
||||
void unregisterForSIMReady(Handler h);
|
||||
|
||||
/** Any transition into SIM_LOCKED_OR_ABSENT */
|
||||
void registerForSIMLockedOrAbsent(Handler h, int what, Object obj);
|
||||
//void unregisterForSIMLockedOrAbsent(Handler h);
|
||||
void unregisterForSIMLockedOrAbsent(Handler h);
|
||||
|
||||
void registerForCallStateChanged(Handler h, int what, Object obj);
|
||||
//void unregisterForCallStateChanged(Handler h);
|
||||
void unregisterForCallStateChanged(Handler h);
|
||||
void registerForNetworkStateChanged(Handler h, int what, Object obj);
|
||||
//void unregisterForNetworkStateChanged(Handler h);
|
||||
void registerForPDPStateChanged(Handler h, int what, Object obj);
|
||||
//void unregisterForPDPStateChanged(Handler h);
|
||||
void unregisterForNetworkStateChanged(Handler h);
|
||||
void registerForDataStateChanged(Handler h, int what, Object obj);
|
||||
void unregisterForDataStateChanged(Handler h);
|
||||
|
||||
void registerForRadioTechnologyChanged(Handler h, int what, Object obj);
|
||||
void unregisterForRadioTechnologyChanged(Handler h);
|
||||
void registerForNVReady(Handler h, int what, Object obj);
|
||||
void unregisterForNVReady(Handler h);
|
||||
void registerForRUIMLockedOrAbsent(Handler h, int what, Object obj);
|
||||
void unregisterForRUIMLockedOrAbsent(Handler h);
|
||||
|
||||
/** InCall voice privacy notifications */
|
||||
void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj);
|
||||
void unregisterForInCallVoicePrivacyOn(Handler h);
|
||||
void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj);
|
||||
void unregisterForInCallVoicePrivacyOff(Handler h);
|
||||
|
||||
/**
|
||||
* Fires on any transition into RUIM_READY
|
||||
* Fires immediately if if currently in that state
|
||||
* In general, actions should be idempotent. State may change
|
||||
* before event is received.
|
||||
*/
|
||||
void registerForRUIMReady(Handler h, int what, Object obj);
|
||||
void unregisterForRUIMReady(Handler h);
|
||||
|
||||
/**
|
||||
* unlike the register* methods, there's only one new SMS handler
|
||||
@@ -192,21 +248,24 @@ public interface CommandsInterface
|
||||
* AsyncResult.result is a String containing the SMS PDU
|
||||
*/
|
||||
void setOnNewSMS(Handler h, int what, Object obj);
|
||||
void unSetOnNewSMS(Handler h);
|
||||
|
||||
/**
|
||||
* Register for NEW_SMS_ON_SIM unsolicited message
|
||||
* Register for NEW_SMS_ON_SIM unsolicited message
|
||||
*
|
||||
* AsyncResult.result is an int array containing the index of new SMS
|
||||
*/
|
||||
void setOnSmsOnSim(Handler h, int what, Object obj);
|
||||
void unSetOnSmsOnSim(Handler h);
|
||||
|
||||
/**
|
||||
* Register for NEW_SMS_STATUS_REPORT unsolicited message
|
||||
* Register for NEW_SMS_STATUS_REPORT unsolicited message
|
||||
*
|
||||
* AsyncResult.result is a String containing the status report PDU
|
||||
*/
|
||||
void setOnSmsStatus(Handler h, int what, Object obj);
|
||||
|
||||
void unSetOnSmsStatus(Handler h);
|
||||
|
||||
/**
|
||||
* unlike the register* methods, there's only one NITZ time handler
|
||||
*
|
||||
@@ -220,13 +279,14 @@ public interface CommandsInterface
|
||||
* seconds on system startup
|
||||
*/
|
||||
void setOnNITZTime(Handler h, int what, Object obj);
|
||||
void unSetOnNITZTime(Handler h);
|
||||
|
||||
/**
|
||||
* unlike the register* methods, there's only one USSD notify handler
|
||||
*
|
||||
* Represents the arrival of a USSD "notify" message, which may
|
||||
* or may not have been triggered by a previous USSD send
|
||||
*
|
||||
*
|
||||
* AsyncResult.result is a String[]
|
||||
* ((String[])(AsyncResult.result))[0] contains status code
|
||||
* "0" USSD-Notify -- text in ((const char **)data)[1]
|
||||
@@ -241,26 +301,29 @@ public interface CommandsInterface
|
||||
*/
|
||||
|
||||
void setOnUSSD(Handler h, int what, Object obj);
|
||||
void unSetOnUSSD(Handler h);
|
||||
|
||||
/**
|
||||
* unlike the register* methods, there's only one signal strength handler
|
||||
* AsyncResult.result is an int[2]
|
||||
* response.obj.result[0] is received signal strength (0-31, 99)
|
||||
* response.obj.result[1] is bit error rate (0-7, 99)
|
||||
* AsyncResult.result is an int[2]
|
||||
* response.obj.result[0] is received signal strength (0-31, 99)
|
||||
* response.obj.result[1] is bit error rate (0-7, 99)
|
||||
* as defined in TS 27.007 8.5
|
||||
*/
|
||||
|
||||
void setOnSignalStrengthUpdate(Handler h, int what, Object obj);
|
||||
void unSetOnSignalStrengthUpdate(Handler h);
|
||||
|
||||
/**
|
||||
* Sets the handler for SIM SMS storage full unsolicited message.
|
||||
* Sets the handler for SIM/RUIM SMS storage full unsolicited message.
|
||||
* Unlike the register* methods, there's only one notification handler
|
||||
*
|
||||
* @param h Handler for notification message.
|
||||
* @param what User-defined message code.
|
||||
* @param obj User object.
|
||||
*/
|
||||
void setOnSimSmsFull(Handler h, int what, Object obj);
|
||||
void setOnIccSmsFull(Handler h, int what, Object obj);
|
||||
void unSetOnIccSmsFull(Handler h);
|
||||
|
||||
/**
|
||||
* Sets the handler for SIM Refresh notifications.
|
||||
@@ -270,8 +333,9 @@ public interface CommandsInterface
|
||||
* @param what User-defined message code.
|
||||
* @param obj User object.
|
||||
*/
|
||||
void setOnSimRefresh(Handler h, int what, Object obj);
|
||||
|
||||
void setOnIccRefresh(Handler h, int what, Object obj);
|
||||
void unSetOnIccRefresh(Handler h);
|
||||
|
||||
/**
|
||||
* Sets the handler for RING notifications.
|
||||
* Unlike the register* methods, there's only one notification handler
|
||||
@@ -281,7 +345,8 @@ public interface CommandsInterface
|
||||
* @param obj User object.
|
||||
*/
|
||||
void setOnCallRing(Handler h, int what, Object obj);
|
||||
|
||||
void unSetOnCallRing(Handler h);
|
||||
|
||||
/**
|
||||
* Sets the handler for RESTRICTED_STATE changed notification,
|
||||
* eg, for Domain Specific Access Control
|
||||
@@ -292,7 +357,8 @@ public interface CommandsInterface
|
||||
*/
|
||||
|
||||
void setOnRestrictedStateChanged(Handler h, int what, Object obj);
|
||||
|
||||
void unSetOnRestrictedStateChanged(Handler h);
|
||||
|
||||
/**
|
||||
* Sets the handler for Supplementary Service Notifications.
|
||||
* Unlike the register* methods, there's only one notification handler
|
||||
@@ -302,6 +368,7 @@ public interface CommandsInterface
|
||||
* @param obj User object.
|
||||
*/
|
||||
void setOnSuppServiceNotification(Handler h, int what, Object obj);
|
||||
void unSetOnSuppServiceNotification(Handler h);
|
||||
|
||||
/**
|
||||
* Sets the handler for Session End Notifications for STK.
|
||||
@@ -312,6 +379,7 @@ public interface CommandsInterface
|
||||
* @param obj User object.
|
||||
*/
|
||||
void setOnStkSessionEnd(Handler h, int what, Object obj);
|
||||
void unSetOnStkSessionEnd(Handler h);
|
||||
|
||||
/**
|
||||
* Sets the handler for Proactive Commands for STK.
|
||||
@@ -322,6 +390,7 @@ public interface CommandsInterface
|
||||
* @param obj User object.
|
||||
*/
|
||||
void setOnStkProactiveCmd(Handler h, int what, Object obj);
|
||||
void unSetOnStkProactiveCmd(Handler h);
|
||||
|
||||
/**
|
||||
* Sets the handler for Event Notifications for STK.
|
||||
@@ -332,6 +401,7 @@ public interface CommandsInterface
|
||||
* @param obj User object.
|
||||
*/
|
||||
void setOnStkEvent(Handler h, int what, Object obj);
|
||||
void unSetOnStkEvent(Handler h);
|
||||
|
||||
/**
|
||||
* Sets the handler for Call Set Up Notifications for STK.
|
||||
@@ -342,6 +412,7 @@ public interface CommandsInterface
|
||||
* @param obj User object.
|
||||
*/
|
||||
void setOnStkCallSetUp(Handler h, int what, Object obj);
|
||||
void unSetOnStkCallSetUp(Handler h);
|
||||
|
||||
/**
|
||||
* Enables/disbables supplementary service related notifications from
|
||||
@@ -351,19 +422,21 @@ public interface CommandsInterface
|
||||
* @param result Message to be posted when command completes.
|
||||
*/
|
||||
void setSuppServiceNotifications(boolean enable, Message result);
|
||||
//void unSetSuppServiceNotifications(Handler h);
|
||||
|
||||
|
||||
/**
|
||||
* Returns current SIM status.
|
||||
* Returns current ICC status.
|
||||
*
|
||||
* AsyncResult.result is IccStatus
|
||||
*
|
||||
* AsyncResult.result is SimStatus
|
||||
*
|
||||
*/
|
||||
|
||||
void getSimStatus(Message result);
|
||||
void getIccStatus(Message result);
|
||||
|
||||
/**
|
||||
* Supply the SIM PIN to the SIM card
|
||||
*
|
||||
* Supply the ICC PIN to the ICC card
|
||||
*
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
@@ -373,11 +446,11 @@ public interface CommandsInterface
|
||||
* ar.exception and ar.result are null on success
|
||||
*/
|
||||
|
||||
void supplySimPin(String pin, Message result);
|
||||
void supplyIccPin(String pin, Message result);
|
||||
|
||||
/**
|
||||
* Supply the SIM PUK to the SIM card
|
||||
*
|
||||
* Supply the ICC PUK to the ICC card
|
||||
*
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
@@ -387,13 +460,13 @@ public interface CommandsInterface
|
||||
* ar.exception and ar.result are null on success
|
||||
*/
|
||||
|
||||
void supplySimPuk(String puk, String newPin, Message result);
|
||||
void supplyIccPuk(String puk, String newPin, Message result);
|
||||
|
||||
/**
|
||||
* Supply the SIM PIN2 to the SIM card
|
||||
* Only called following operation where SIM_PIN2 was
|
||||
* Supply the ICC PIN2 to the ICC card
|
||||
* Only called following operation where ICC_PIN2 was
|
||||
* returned as a a failure from a previous operation
|
||||
*
|
||||
*
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
@@ -403,13 +476,13 @@ public interface CommandsInterface
|
||||
* ar.exception and ar.result are null on success
|
||||
*/
|
||||
|
||||
void supplySimPin2(String pin2, Message result);
|
||||
void supplyIccPin2(String pin2, Message result);
|
||||
|
||||
/**
|
||||
* Supply the SIM PUK2 to the SIM card
|
||||
* Only called following operation where SIM_PUK2 was
|
||||
* returned as a a failure from a previous operation
|
||||
*
|
||||
*
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
@@ -419,16 +492,16 @@ public interface CommandsInterface
|
||||
* ar.exception and ar.result are null on success
|
||||
*/
|
||||
|
||||
void supplySimPuk2(String puk2, String newPin2, Message result);
|
||||
void supplyIccPuk2(String puk2, String newPin2, Message result);
|
||||
|
||||
void changeSimPin(String oldPin, String newPin, Message result);
|
||||
void changeSimPin2(String oldPin2, String newPin2, Message result);
|
||||
void changeIccPin(String oldPin, String newPin, Message result);
|
||||
void changeIccPin2(String oldPin2, String newPin2, Message result);
|
||||
|
||||
void changeBarringPassword(String facility, String oldPwd, String newPwd, Message result);
|
||||
|
||||
void supplyNetworkDepersonalization(String netpin, Message result);
|
||||
|
||||
/**
|
||||
/**
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
@@ -438,16 +511,26 @@ public interface CommandsInterface
|
||||
*/
|
||||
void getCurrentCalls (Message result);
|
||||
|
||||
/**
|
||||
/**
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
* ar.userObject contains the orignal value of result.obj
|
||||
* ar.result contains a List of PDPContextState
|
||||
* @deprecated
|
||||
*/
|
||||
void getPDPContextList(Message result);
|
||||
|
||||
/**
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
* ar.userObject contains the orignal value of result.obj
|
||||
* ar.result contains a List of PDPContextState
|
||||
*/
|
||||
void getPDPContextList(Message result);
|
||||
void getDataCallList(Message result);
|
||||
|
||||
/**
|
||||
/**
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
@@ -460,7 +543,7 @@ public interface CommandsInterface
|
||||
*/
|
||||
void dial (String address, int clirMode, Message result);
|
||||
|
||||
/**
|
||||
/**
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
@@ -469,7 +552,7 @@ public interface CommandsInterface
|
||||
*/
|
||||
void getIMSI(Message result);
|
||||
|
||||
/**
|
||||
/**
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
@@ -478,7 +561,7 @@ public interface CommandsInterface
|
||||
*/
|
||||
void getIMEI(Message result);
|
||||
|
||||
/**
|
||||
/**
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
* ar.exception carries exception on failure
|
||||
@@ -487,7 +570,7 @@ public interface CommandsInterface
|
||||
*/
|
||||
void getIMEISV(Message result);
|
||||
|
||||
/**
|
||||
/**
|
||||
* Hang up one individual connection.
|
||||
* returned message
|
||||
* retMsg.obj = AsyncResult ar
|
||||
@@ -512,7 +595,7 @@ public interface CommandsInterface
|
||||
|
||||
/**
|
||||
* 3GPP 22.030 6.5.5
|
||||
* "Releases all active calls (if any exist) and accepts
|
||||
* "Releases all active calls (if any exist) and accepts
|
||||
* the other (held or waiting) call."
|
||||
*
|
||||
* ar.exception carries exception on failure
|
||||
@@ -523,7 +606,7 @@ public interface CommandsInterface
|
||||
|
||||
/**
|
||||
* 3GPP 22.030 6.5.5
|
||||
* "Places all active calls (if any exist) on hold and accepts
|
||||
* "Places all active calls (if any exist) on hold and accepts
|
||||
* the other (held or waiting) call."
|
||||
*
|
||||
* ar.exception carries exception on failure
|
||||
@@ -539,12 +622,27 @@ public interface CommandsInterface
|
||||
* ar.exception carries exception on failure
|
||||
* ar.userObject contains the orignal value of result.obj
|
||||
* ar.result is null on success and failure
|
||||
*/
|
||||
*/
|
||||
void conference (Message result);
|
||||
|
||||
/**
|
||||
* Set preferred Voice Privacy (VP).
|
||||
*
|
||||
* @param enable true is enhanced and false is normal VP
|
||||
* @param result is a callback message
|
||||
*/
|
||||
void setPreferredVoicePrivacy(boolean enable, Message result);
|
||||
|
||||
/**
|
||||
* Get currently set preferred Voice Privacy (VP) mode.
|
||||
*
|
||||
* @param result is a callback message
|
||||
*/
|
||||
void getPreferredVoicePrivacy(Message result);
|
||||
|
||||
/**
|
||||
* 3GPP 22.030 6.5.5
|
||||
* "Places all active calls on hold except call X with which
|
||||
* "Places all active calls on hold except call X with which
|
||||
* communication shall be supported."
|
||||
*/
|
||||
void separateConnection (int gsmIndex, Message result);
|
||||
@@ -554,15 +652,15 @@ public interface CommandsInterface
|
||||
* ar.exception carries exception on failure
|
||||
* ar.userObject contains the orignal value of result.obj
|
||||
* ar.result is null on success and failure
|
||||
*/
|
||||
*/
|
||||
void acceptCall (Message result);
|
||||
|
||||
/**
|
||||
/**
|
||||
* also known as UDUB
|
||||
* ar.exception carries exception on failure
|
||||
* ar.userObject contains the orignal value of result.obj
|
||||
* ar.result is null on success and failure
|
||||
*/
|
||||
*/
|
||||
void rejectCall (Message result);
|
||||
|
||||
/**
|
||||
@@ -586,14 +684,21 @@ public interface CommandsInterface
|
||||
void getLastCallFailCause (Message result);
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* Reason for last PDP context deactivate or failure to activate
|
||||
* cause code returned as int[0] in Message.obj.response
|
||||
* returns an integer cause code defined in TS 24.008
|
||||
* section 6.1.3.1.3 or close approximation
|
||||
* @deprecated
|
||||
*/
|
||||
void getLastPdpFailCause (Message result);
|
||||
|
||||
/**
|
||||
* The preferred new alternative to getLastPdpFailCause
|
||||
* that is also CDMA-compatible.
|
||||
*/
|
||||
void getLastDataCallFailCause (Message result);
|
||||
|
||||
void setMute (boolean enableMute, Message response);
|
||||
|
||||
void getMute (Message response);
|
||||
@@ -601,8 +706,8 @@ public interface CommandsInterface
|
||||
/**
|
||||
* response.obj is an AsyncResult
|
||||
* response.obj.result is an int[2]
|
||||
* response.obj.result[0] is received signal strength (0-31, 99)
|
||||
* response.obj.result[1] is bit error rate (0-7, 99)
|
||||
* response.obj.result[0] is received signal strength (0-31, 99)
|
||||
* response.obj.result[1] is bit error rate (0-7, 99)
|
||||
* as defined in TS 27.007 8.5
|
||||
*/
|
||||
void getSignalStrength (Message response);
|
||||
@@ -612,21 +717,21 @@ public interface CommandsInterface
|
||||
* response.obj.result is an int[3]
|
||||
* response.obj.result[0] is registration state 0-5 from TS 27.007 7.2
|
||||
* response.obj.result[1] is LAC if registered or -1 if not
|
||||
* response.obj.result[2] is CID if registered or -1 if not
|
||||
* response.obj.result[2] is CID if registered or -1 if not
|
||||
* valid LAC and CIDs are 0x0000 - 0xffff
|
||||
*
|
||||
*
|
||||
* Please note that registration state 4 ("unknown") is treated
|
||||
* as "out of service" above
|
||||
*/
|
||||
void getRegistrationState (Message response);
|
||||
|
||||
|
||||
/**
|
||||
* response.obj.result is an int[3]
|
||||
* response.obj.result[0] is registration state 0-5 from TS 27.007 7.2
|
||||
* response.obj.result[1] is LAC if registered or -1 if not
|
||||
* response.obj.result[2] is CID if registered or -1 if not
|
||||
* response.obj.result[2] is CID if registered or -1 if not
|
||||
* valid LAC and CIDs are 0x0000 - 0xffff
|
||||
*
|
||||
*
|
||||
* Please note that registration state 4 ("unknown") is treated
|
||||
* as "out of service" above
|
||||
*/
|
||||
@@ -637,14 +742,14 @@ public interface CommandsInterface
|
||||
* response.obj.result[0] is long alpha or null if unregistered
|
||||
* response.obj.result[1] is short alpha or null if unregistered
|
||||
* response.obj.result[2] is numeric or null if unregistered
|
||||
*/
|
||||
*/
|
||||
void getOperator(Message response);
|
||||
|
||||
/**
|
||||
* ar.exception carries exception on failure
|
||||
* ar.userObject contains the orignal value of result.obj
|
||||
* ar.result is null on success and failure
|
||||
*/
|
||||
*/
|
||||
void sendDtmf(char c, Message result);
|
||||
|
||||
|
||||
@@ -667,26 +772,40 @@ public interface CommandsInterface
|
||||
* smscPDU is smsc address in PDU form GSM BCD format prefixed
|
||||
* by a length byte (as expected by TS 27.005) or NULL for default SMSC
|
||||
* pdu is SMS in PDU format as an ASCII hex string
|
||||
* less the SMSC address
|
||||
* less the SMSC address
|
||||
*/
|
||||
void sendSMS (String smscPDU, String pdu, Message response);
|
||||
|
||||
/**
|
||||
* @param pdu is CDMA-SMS in internal pseudo-PDU format
|
||||
* @param response sent when operation completes
|
||||
*/
|
||||
void sendCdmaSms(byte[] pdu, Message response);
|
||||
|
||||
/**
|
||||
* Deletes the specified SMS record from SIM memory (EF_SMS).
|
||||
*
|
||||
*
|
||||
* @param index index of the SMS record to delete
|
||||
* @param response sent when operation completes
|
||||
*/
|
||||
void deleteSmsOnSim(int index, Message response);
|
||||
|
||||
/**
|
||||
* Deletes the specified SMS record from RUIM memory (EF_SMS in DF_CDMA).
|
||||
*
|
||||
* @param index index of the SMS record to delete
|
||||
* @param response sent when operation completes
|
||||
*/
|
||||
void deleteSmsOnRuim(int index, Message response);
|
||||
|
||||
/**
|
||||
* Writes an SMS message to SIM memory (EF_SMS).
|
||||
*
|
||||
*
|
||||
* @param status status of message on SIM. One of:
|
||||
* SmsManger.STATUS_ON_SIM_READ
|
||||
* SmsManger.STATUS_ON_SIM_UNREAD
|
||||
* SmsManger.STATUS_ON_SIM_SENT
|
||||
* SmsManger.STATUS_ON_SIM_UNSENT
|
||||
* SmsManger.STATUS_ON_ICC_READ
|
||||
* SmsManger.STATUS_ON_ICC_UNREAD
|
||||
* SmsManger.STATUS_ON_ICC_SENT
|
||||
* SmsManger.STATUS_ON_ICC_UNSENT
|
||||
* @param pdu message PDU, as hex string
|
||||
* @param response sent when operation completes.
|
||||
* response.obj will be an AsyncResult, and will indicate
|
||||
@@ -694,89 +813,105 @@ public interface CommandsInterface
|
||||
*/
|
||||
void writeSmsToSim(int status, String smsc, String pdu, Message response);
|
||||
|
||||
void writeSmsToRuim(int status, String pdu, Message response);
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param apn
|
||||
* @param user
|
||||
* @param password
|
||||
* @param response
|
||||
*/
|
||||
void setupDefaultPDP(String apn, String user, String password, Message response);
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @param cid
|
||||
* @param response
|
||||
*/
|
||||
void deactivateDefaultPDP(int cid, Message response);
|
||||
|
||||
void setRadioPower(boolean on, Message response);
|
||||
|
||||
void acknowledgeLastIncomingSMS(boolean success, Message response);
|
||||
|
||||
/**
|
||||
* parameters equivilient to 27.007 AT+CRSM command
|
||||
void acknowledgeLastIncomingCdmaSms(boolean success, Message response);
|
||||
|
||||
/**
|
||||
* parameters equivilient to 27.007 AT+CRSM command
|
||||
* response.obj will be an AsyncResult
|
||||
* response.obj.userObj will be a SimIoResult on success
|
||||
* response.obj.userObj will be a IccIoResult on success
|
||||
*/
|
||||
void simIO (int command, int fileid, String path, int p1, int p2, int p3,
|
||||
void iccIO (int command, int fileid, String path, int p1, int p2, int p3,
|
||||
String data, String pin2, Message response);
|
||||
|
||||
/**
|
||||
* (AsyncResult)response.obj).result is an int[] with element [0] set to
|
||||
* 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned".
|
||||
* 1 for "CLIP is provisioned", and 0 for "CLIP is not provisioned".
|
||||
*
|
||||
* @param response is callback message
|
||||
*/
|
||||
|
||||
|
||||
void queryCLIP(Message response);
|
||||
|
||||
/**
|
||||
* response.obj will be a an int[2]
|
||||
*
|
||||
* response.obj[0] will be TS 27.007 +CLIR parameter 'n'
|
||||
* 0 presentation indicator is used according to the subscription of the CLIR service
|
||||
* 1 CLIR invocation
|
||||
* 2 CLIR suppression
|
||||
* 0 presentation indicator is used according to the subscription of the CLIR service
|
||||
* 1 CLIR invocation
|
||||
* 2 CLIR suppression
|
||||
*
|
||||
* response.obj[1] will be TS 27.007 +CLIR parameter 'm'
|
||||
* 0 CLIR not provisioned
|
||||
* 1 CLIR provisioned in permanent mode
|
||||
* 2 unknown (e.g. no network, etc.)
|
||||
* 3 CLIR temporary mode presentation restricted
|
||||
* 4 CLIR temporary mode presentation allowed
|
||||
* 0 CLIR not provisioned
|
||||
* 1 CLIR provisioned in permanent mode
|
||||
* 2 unknown (e.g. no network, etc.)
|
||||
* 3 CLIR temporary mode presentation restricted
|
||||
* 4 CLIR temporary mode presentation allowed
|
||||
*/
|
||||
|
||||
void getCLIR(Message response);
|
||||
|
||||
|
||||
/**
|
||||
* clirMode is one of the CLIR_* constants above
|
||||
*
|
||||
* response.obj is null
|
||||
*/
|
||||
|
||||
|
||||
void setCLIR(int clirMode, Message response);
|
||||
|
||||
/**
|
||||
* (AsyncResult)response.obj).result is an int[] with element [0] set to
|
||||
* 0 for disabled, 1 for enabled.
|
||||
* 0 for disabled, 1 for enabled.
|
||||
*
|
||||
* @param serviceClass is a sum of SERVICE_CLASS_*
|
||||
* @param response is callback message
|
||||
*/
|
||||
|
||||
|
||||
void queryCallWaiting(int serviceClass, Message response);
|
||||
|
||||
|
||||
/**
|
||||
* @param enable is true to enable, false to disable
|
||||
* @param serviceClass is a sum of SERVICE_CLASS_*
|
||||
* @param response is callback message
|
||||
*/
|
||||
|
||||
|
||||
void setCallWaiting(boolean enable, int serviceClass, Message response);
|
||||
|
||||
/**
|
||||
* @param action is one of CF_ACTION_*
|
||||
* @param cfReason is one of CF_REASON_*
|
||||
* @param serviceClass is a sum of SERVICE_CLASSS_*
|
||||
* @param serviceClass is a sum of SERVICE_CLASSS_*
|
||||
*/
|
||||
void setCallForward(int action, int cfReason, int serviceClass,
|
||||
String number, int timeSeconds, Message response);
|
||||
void setCallForward(int action, int cfReason, int serviceClass,
|
||||
String number, int timeSeconds, Message response);
|
||||
|
||||
/**
|
||||
* cfReason is one of CF_REASON_*
|
||||
*
|
||||
* ((AsyncResult)response.obj).result will be an array of
|
||||
* CallForwardInfo's
|
||||
*
|
||||
*
|
||||
* An array of length 0 means "disabled for all codes"
|
||||
*/
|
||||
void queryCallForwardStatus(int cfReason, int serviceClass,
|
||||
@@ -815,7 +950,7 @@ public interface CommandsInterface
|
||||
* @param serviceClass is a sum of SERVICE_CLASS_*
|
||||
* @param response is callback message
|
||||
*/
|
||||
|
||||
|
||||
void queryFacilityLock (String facility, String password, int serviceClass,
|
||||
Message response);
|
||||
|
||||
@@ -828,7 +963,7 @@ public interface CommandsInterface
|
||||
*/
|
||||
void setFacilityLock (String facility, boolean lockState, String password,
|
||||
int serviceClass, Message response);
|
||||
|
||||
|
||||
|
||||
void sendUSSD (String ussdString, Message response);
|
||||
|
||||
@@ -850,7 +985,7 @@ public interface CommandsInterface
|
||||
|
||||
/**
|
||||
* Query the list of band mode supported by RF.
|
||||
*
|
||||
*
|
||||
* @param response is callback message
|
||||
* ((AsyncResult)response.obj).result is an int[] with every
|
||||
* element representing one avialable BM_*_BAND
|
||||
@@ -923,4 +1058,136 @@ public interface CommandsInterface
|
||||
* @param response Callback message
|
||||
*/
|
||||
public void handleCallSetupRequestFromSim(boolean accept, Message response);
|
||||
|
||||
//***** new Methods for CDMA support
|
||||
|
||||
/**
|
||||
* Request the device ESN / MEID / IMEI / IMEISV.
|
||||
* "response" is const char **
|
||||
* [0] is IMEI if GSM subscription is available
|
||||
* [1] is IMEISV if GSM subscription is available
|
||||
* [2] is ESN if CDMA subscription is available
|
||||
* [3] is MEID if CDMA subscription is available
|
||||
*/
|
||||
public void getDeviceIdentity(Message response);
|
||||
|
||||
/**
|
||||
* Request the device IMSI_M / MDN / AH_SID / H_SID / H_NID.
|
||||
* "response" is const char **
|
||||
* [0] is IMSI_M if CDMA subscription is available
|
||||
* [1] is MDN if CDMA subscription is available
|
||||
* [2] is AH_SID (Analog Home SID) if CDMA subscription
|
||||
* [3] is H_SID (Home SID) if CDMA subscription is available
|
||||
* [4] is H_NID (Home SID) if CDMA subscription is available
|
||||
*/
|
||||
public void getCDMASubscription(Message response);
|
||||
|
||||
/**
|
||||
* Send Flash Code.
|
||||
* "response" is is NULL
|
||||
* [0] is a FLASH string
|
||||
*/
|
||||
public void sendCDMAFeatureCode(String FeatureCode, Message response);
|
||||
|
||||
/** Set the Phone type created */
|
||||
void setPhoneType(int phoneType);
|
||||
/**
|
||||
* Query the CDMA roaming preference setting
|
||||
*
|
||||
* @param response is callback message to report one of CDMA_RM_*
|
||||
*/
|
||||
void queryCdmaRoamingPreference(Message response);
|
||||
|
||||
/**
|
||||
* Requests to set the CDMA roaming preference
|
||||
* @param cdmaRoamingType one of CDMA_RM_*
|
||||
* @param response is callback message
|
||||
*/
|
||||
void setCdmaRoamingPreference(int cdmaRoamingType, Message response);
|
||||
|
||||
/**
|
||||
* Requests to set the CDMA subscription mode
|
||||
* @param cdmaSubscriptionType one of CDMA_SUBSCRIPTION_*
|
||||
* @param response is callback message
|
||||
*/
|
||||
void setCdmaSubscription(int cdmaSubscriptionType, Message response);
|
||||
|
||||
/**
|
||||
* Set the TTY mode for the CDMA phone
|
||||
*
|
||||
* @param enable is true to enable, false to disable
|
||||
* @param response is callback message
|
||||
*/
|
||||
void setTTYModeEnabled(boolean enable, Message response);
|
||||
|
||||
/**
|
||||
* Query the TTY mode for the CDMA phone
|
||||
* (AsyncResult)response.obj).result is an int[] with element [0] set to
|
||||
* 0 for disabled, 1 for enabled.
|
||||
*
|
||||
* @param response is callback message
|
||||
*/
|
||||
void queryTTYModeEnabled(Message response);
|
||||
|
||||
/**
|
||||
* Setup a packet data connection On successful completion, the result
|
||||
* message will return the following: [0] indicating PDP CID, which is
|
||||
* generated by RIL. This Connection ID is used in both GSM/UMTS and CDMA
|
||||
* modes [1] indicating the network interface name for GSM/UMTS or CDMA [2]
|
||||
* indicating the IP address for this interface for GSM/UMTS and NULL in the
|
||||
* case of CDMA
|
||||
*
|
||||
* @param radioTechnology
|
||||
* indicates whether to setup connection on radio technology CDMA
|
||||
* (0) or GSM/UMTS (1)
|
||||
* @param profile
|
||||
* Profile Number or NULL to indicate default profile
|
||||
* @param apn
|
||||
* the APN to connect to if radio technology is GSM/UMTS.
|
||||
* Otherwise null for CDMA.
|
||||
* @param user
|
||||
* the username for APN, or NULL
|
||||
* @param password
|
||||
* the password for APN, or NULL
|
||||
* @param result
|
||||
* Callback message
|
||||
*/
|
||||
public void setupDataCall(String radioTechnology, String profile, String apn,
|
||||
String user, String password, Message result);
|
||||
|
||||
/**
|
||||
* Deactivate packet data connection
|
||||
*
|
||||
* @param cid
|
||||
* The connection ID
|
||||
* @param result
|
||||
* Callback message is empty on completion
|
||||
*/
|
||||
public void deactivateDataCall(int cid, Message result);
|
||||
|
||||
/**
|
||||
* Activate or deactivate cell broadcast SMS.
|
||||
*
|
||||
* @param activate
|
||||
* 0 = activate, 1 = deactivate
|
||||
* @param result
|
||||
* Callback message is empty on completion
|
||||
*/
|
||||
public void activateCdmaBroadcastSms(int activate, Message result);
|
||||
|
||||
/**
|
||||
* Configure cdma cell broadcast SMS.
|
||||
*
|
||||
* @param result
|
||||
* Callback message is empty on completion
|
||||
*/
|
||||
public void setCdmaBroadcastConfig(int[] configValuesArray, Message result);
|
||||
|
||||
/**
|
||||
* Query the current configuration of cdma cell broadcast SMS.
|
||||
*
|
||||
* @param result
|
||||
* Callback message contains the configuration from the modem on completion
|
||||
*/
|
||||
public void getCdmaBroadcastConfig(Message result);
|
||||
}
|
||||
@@ -19,8 +19,8 @@ package com.android.internal.telephony;
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public abstract class Connection
|
||||
{
|
||||
public abstract class Connection {
|
||||
|
||||
// Number presentation type for caller id display
|
||||
public static int PRESENTATION_ALLOWED = 1; // normal
|
||||
public static int PRESENTATION_RESTRICTED = 2; // block by user
|
||||
@@ -42,7 +42,7 @@ public abstract class Connection
|
||||
INCOMING_REJECTED, /* an incoming call that was rejected */
|
||||
POWER_OFF, /* radio is turned off explicitly */
|
||||
OUT_OF_SERVICE, /* out of service */
|
||||
SIM_ERROR, /* No SIM, SIM locked, or other SIM error */
|
||||
ICC_ERROR, /* No ICC, ICC locked, or other ICC error */
|
||||
CALL_BARRED, /* call was blocked by call barrring */
|
||||
FDN_BLOCKED, /* call was blocked by fixed dial number */
|
||||
CS_RESTRICTED, /* call was blocked by restricted all voice access */
|
||||
@@ -54,7 +54,7 @@ public abstract class Connection
|
||||
|
||||
/* Instance Methods */
|
||||
|
||||
/**
|
||||
/**
|
||||
* Gets address (e.g., phone number) associated with connection
|
||||
* TODO: distinguish reasons for unavailablity
|
||||
*
|
||||
@@ -92,7 +92,7 @@ public abstract class Connection
|
||||
public abstract long getDisconnectTime();
|
||||
|
||||
/**
|
||||
* returns the number of milliseconds the call has been connected,
|
||||
* returns the number of milliseconds the call has been connected,
|
||||
* or 0 if the call has never connected.
|
||||
* If the call is still connected, then returns the elapsed
|
||||
* time since connect
|
||||
@@ -113,8 +113,8 @@ public abstract class Connection
|
||||
public abstract DisconnectCause getDisconnectCause();
|
||||
|
||||
/**
|
||||
* Returns true of this connection originated elsewhere
|
||||
* ("MT" or mobile terminated; another party called this terminal)
|
||||
* Returns true of this connection originated elsewhere
|
||||
* ("MT" or mobile terminated; another party called this terminal)
|
||||
* or false if this call originated here (MO or mobile originated)
|
||||
*/
|
||||
public abstract boolean isIncoming();
|
||||
@@ -122,32 +122,30 @@ public abstract class Connection
|
||||
/**
|
||||
* If this Connection is connected, then it is associated with
|
||||
* a Call.
|
||||
*
|
||||
*
|
||||
* Returns getCall().getState() or Call.State.IDLE if not
|
||||
* connected
|
||||
*/
|
||||
public Call.State getState()
|
||||
{
|
||||
public Call.State getState() {
|
||||
Call c;
|
||||
|
||||
c = getCall();
|
||||
|
||||
if (c == null) {
|
||||
if (c == null) {
|
||||
return Call.State.IDLE;
|
||||
} else {
|
||||
return c.getState();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* isAlive()
|
||||
*
|
||||
*
|
||||
* @return true if the connection isn't disconnected
|
||||
* (could be active, holding, ringing, dialing, etc)
|
||||
*/
|
||||
public boolean
|
||||
isAlive()
|
||||
{
|
||||
isAlive() {
|
||||
return getState().isAlive();
|
||||
}
|
||||
|
||||
@@ -155,29 +153,26 @@ public abstract class Connection
|
||||
* Returns true if Connection is connected and is INCOMING or WAITING
|
||||
*/
|
||||
public boolean
|
||||
isRinging()
|
||||
{
|
||||
isRinging() {
|
||||
return getState().isRinging();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return the userdata set in setUserData()
|
||||
*/
|
||||
public Object getUserData()
|
||||
{
|
||||
public Object getUserData() {
|
||||
return userData;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param userdata user can store an any userdata in the Connection object.
|
||||
*/
|
||||
public void setUserData(Object userdata)
|
||||
{
|
||||
public void setUserData(Object userdata) {
|
||||
this.userData = userdata;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Hangup individual Connection
|
||||
*/
|
||||
@@ -191,16 +186,16 @@ public abstract class Connection
|
||||
public abstract void separate() throws CallStateException;
|
||||
|
||||
public enum PostDialState {
|
||||
NOT_STARTED, /* The post dial string playback hasn't
|
||||
been started, or this call is not yet
|
||||
NOT_STARTED, /* The post dial string playback hasn't
|
||||
been started, or this call is not yet
|
||||
connected, or this is an incoming call */
|
||||
STARTED, /* The post dial string playback has begun */
|
||||
WAIT, /* The post dial string playback is waiting for a
|
||||
WAIT, /* The post dial string playback is waiting for a
|
||||
call to proceedAfterWaitChar() */
|
||||
WILD, /* The post dial string playback is waiting for a
|
||||
WILD, /* The post dial string playback is waiting for a
|
||||
call to proceedAfterWildChar() */
|
||||
COMPLETE, /* The post dial string playback is complete */
|
||||
CANCELLED /* The post dial string playback was cancelled
|
||||
CANCELLED /* The post dial string playback was cancelled
|
||||
with cancelPostDial() */
|
||||
}
|
||||
|
||||
@@ -215,7 +210,7 @@ public abstract class Connection
|
||||
/**
|
||||
* See Phone.setOnPostDialWaitCharacter()
|
||||
*/
|
||||
|
||||
|
||||
public abstract void proceedAfterWaitChar();
|
||||
|
||||
/**
|
||||
@@ -232,5 +227,5 @@ public abstract class Connection
|
||||
* @return one of PRESENTATION_*
|
||||
*/
|
||||
public abstract int getNumberPresentation();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public abstract class DataConnection extends Handler {
|
||||
|
||||
// the inherited class
|
||||
|
||||
public enum State {
|
||||
ACTIVE, /* has active data connection */
|
||||
ACTIVATING, /* during connecting process */
|
||||
INACTIVE; /* has empty data connection */
|
||||
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case ACTIVE:
|
||||
return "active";
|
||||
case ACTIVATING:
|
||||
return "setting up";
|
||||
default:
|
||||
return "inactive";
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this == ACTIVE;
|
||||
}
|
||||
|
||||
public boolean isInactive() {
|
||||
return this == INACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
public enum FailCause {
|
||||
NONE,
|
||||
BAD_APN,
|
||||
BAD_PAP_SECRET,
|
||||
BARRED,
|
||||
USER_AUTHENTICATION,
|
||||
SERVICE_OPTION_NOT_SUPPORTED,
|
||||
SERVICE_OPTION_NOT_SUBSCRIBED,
|
||||
SIM_LOCKED,
|
||||
RADIO_OFF,
|
||||
NO_SIGNAL,
|
||||
NO_DATA_PLAN,
|
||||
RADIO_NOT_AVAILABLE,
|
||||
SUSPENED_TEMPORARY,
|
||||
RADIO_ERROR_RETRY,
|
||||
UNKNOWN;
|
||||
|
||||
public boolean isPermanentFail() {
|
||||
return (this == RADIO_OFF);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
switch (this) {
|
||||
case NONE:
|
||||
return "no error";
|
||||
case BAD_APN:
|
||||
return "bad apn";
|
||||
case BAD_PAP_SECRET:
|
||||
return "bad pap secret";
|
||||
case BARRED:
|
||||
return "barred";
|
||||
case USER_AUTHENTICATION:
|
||||
return "error user autentication";
|
||||
case SERVICE_OPTION_NOT_SUPPORTED:
|
||||
return "data not supported";
|
||||
case SERVICE_OPTION_NOT_SUBSCRIBED:
|
||||
return "datt not subcribed";
|
||||
case SIM_LOCKED:
|
||||
return "sim locked";
|
||||
case RADIO_OFF:
|
||||
return "radio is off";
|
||||
case NO_SIGNAL:
|
||||
return "no signal";
|
||||
case NO_DATA_PLAN:
|
||||
return "no data plan";
|
||||
case RADIO_NOT_AVAILABLE:
|
||||
return "radio not available";
|
||||
case SUSPENED_TEMPORARY:
|
||||
return "suspend temporary";
|
||||
case RADIO_ERROR_RETRY:
|
||||
return "transient radio error";
|
||||
default:
|
||||
return "unknown data error";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ***** Event codes
|
||||
protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 1;
|
||||
protected static final int EVENT_GET_LAST_FAIL_DONE = 2;
|
||||
protected static final int EVENT_LINK_STATE_CHANGED = 3;
|
||||
protected static final int EVENT_DEACTIVATE_DONE = 4;
|
||||
protected static final int EVENT_FORCE_RETRY = 5;
|
||||
|
||||
//***** Tag IDs for EventLog
|
||||
protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
|
||||
|
||||
|
||||
//***** Member Variables
|
||||
protected PhoneBase phone;
|
||||
protected Message onConnectCompleted;
|
||||
protected Message onDisconnect;
|
||||
protected int cid;
|
||||
protected String interfaceName;
|
||||
protected String ipAddress;
|
||||
protected String gatewayAddress;
|
||||
protected String[] dnsServers;
|
||||
protected State state;
|
||||
protected long createTime;
|
||||
protected long lastFailTime;
|
||||
protected FailCause lastFailCause;
|
||||
protected static final String NULL_IP = "0.0.0.0";
|
||||
Object userData;
|
||||
|
||||
// receivedDisconnectReq is set when disconnect during activation
|
||||
protected boolean receivedDisconnectReq;
|
||||
|
||||
/* Instance Methods */
|
||||
protected abstract void onSetupConnectionCompleted(AsyncResult ar);
|
||||
|
||||
protected abstract void onDeactivated(AsyncResult ar);
|
||||
|
||||
protected abstract void disconnect(Message msg);
|
||||
|
||||
protected abstract void notifyFail(FailCause cause, Message onCompleted);
|
||||
|
||||
protected abstract void notifyDisconnect(Message msg);
|
||||
|
||||
protected abstract void onLinkStateChanged(DataLink.LinkState linkState);
|
||||
|
||||
protected abstract FailCause getFailCauseFromRequest(int rilCause);
|
||||
|
||||
public abstract String toString();
|
||||
|
||||
protected abstract void log(String s);
|
||||
|
||||
|
||||
//***** Constructor
|
||||
protected DataConnection(PhoneBase phone) {
|
||||
super();
|
||||
this.phone = phone;
|
||||
onConnectCompleted = null;
|
||||
onDisconnect = null;
|
||||
this.cid = -1;
|
||||
receivedDisconnectReq = false;
|
||||
this.dnsServers = new String[2];
|
||||
|
||||
clearSettings();
|
||||
}
|
||||
|
||||
protected void setHttpProxy(String httpProxy, String httpPort) {
|
||||
if (httpProxy == null || httpProxy.length() == 0) {
|
||||
phone.setSystemProperty("net.gprs.http-proxy", null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (httpPort == null || httpPort.length() == 0) {
|
||||
httpPort = "8080"; // Default to port 8080
|
||||
}
|
||||
|
||||
phone.setSystemProperty("net.gprs.http-proxy",
|
||||
"http://" + httpProxy + ":" + httpPort + "/");
|
||||
}
|
||||
|
||||
public String getInterface() {
|
||||
return interfaceName;
|
||||
}
|
||||
|
||||
public String getIpAddress() {
|
||||
return ipAddress;
|
||||
}
|
||||
|
||||
public String getGatewayAddress() {
|
||||
return gatewayAddress;
|
||||
}
|
||||
|
||||
public String[] getDnsServers() {
|
||||
return dnsServers;
|
||||
}
|
||||
|
||||
public void clearSettings() {
|
||||
log("DataConnection.clearSettings()");
|
||||
|
||||
this.state = State.INACTIVE;
|
||||
this.createTime = -1;
|
||||
this.lastFailTime = -1;
|
||||
this.lastFailCause = FailCause.NONE;
|
||||
|
||||
receivedDisconnectReq = false;
|
||||
onConnectCompleted = null;
|
||||
interfaceName = null;
|
||||
ipAddress = null;
|
||||
gatewayAddress = null;
|
||||
dnsServers[0] = null;
|
||||
dnsServers[1] = null;
|
||||
}
|
||||
|
||||
protected void onGetLastFailCompleted(AsyncResult ar) {
|
||||
if (receivedDisconnectReq) {
|
||||
// Don't bother reporting the error if there's already a
|
||||
// pending disconnect request, since DataConnectionTracker
|
||||
// has already updated its state.
|
||||
notifyDisconnect(onDisconnect);
|
||||
} else {
|
||||
FailCause cause = FailCause.UNKNOWN;
|
||||
|
||||
if (ar.exception == null) {
|
||||
int rilFailCause = ((int[]) (ar.result))[0];
|
||||
cause = getFailCauseFromRequest(rilFailCause);
|
||||
}
|
||||
notifyFail(cause, onConnectCompleted);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onForceRetry() {
|
||||
if (receivedDisconnectReq) {
|
||||
notifyDisconnect(onDisconnect);
|
||||
} else {
|
||||
notifyFail(FailCause.RADIO_ERROR_RETRY, onConnectCompleted);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
AsyncResult ar;
|
||||
|
||||
log("DataConnection.handleMessage()");
|
||||
|
||||
switch (msg.what) {
|
||||
|
||||
case EVENT_SETUP_DATA_CONNECTION_DONE:
|
||||
onSetupConnectionCompleted((AsyncResult) msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_FORCE_RETRY:
|
||||
onForceRetry();
|
||||
break;
|
||||
|
||||
case EVENT_GET_LAST_FAIL_DONE:
|
||||
onGetLastFailCompleted((AsyncResult) msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_LINK_STATE_CHANGED:
|
||||
ar = (AsyncResult) msg.obj;
|
||||
DataLink.LinkState ls = (DataLink.LinkState) ar.result;
|
||||
onLinkStateChanged(ls);
|
||||
break;
|
||||
|
||||
case EVENT_DEACTIVATE_DONE:
|
||||
onDeactivated((AsyncResult) msg.obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
log("DataConnection.getState()");
|
||||
return state;
|
||||
}
|
||||
|
||||
public long getConnectionTime() {
|
||||
log("DataConnection.getConnectionTime()");
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public long getLastFailTime() {
|
||||
log("DataConnection.getLastFailTime()");
|
||||
return lastFailTime;
|
||||
}
|
||||
|
||||
public FailCause getLastFailCause() {
|
||||
log("DataConnection.getLastFailCause()");
|
||||
return lastFailCause;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.INetStatService;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.SettingNotFoundException;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*
|
||||
*/
|
||||
public abstract class DataConnectionTracker extends Handler {
|
||||
private static final boolean DBG = true;
|
||||
|
||||
/**
|
||||
* IDLE: ready to start data connection setup, default state
|
||||
* INITING: state of issued setupDefaultPDP() but not finish yet
|
||||
* CONNECTING: state of issued startPppd() but not finish yet
|
||||
* SCANNING: data connection fails with one apn but other apns are available
|
||||
* ready to start data connection on other apns (before INITING)
|
||||
* CONNECTED: IP connection is setup
|
||||
* DISCONNECTING: Connection.disconnect() has been called, but PDP
|
||||
* context is not yet deactivated
|
||||
* FAILED: data connection fail for all apns settings
|
||||
*
|
||||
* getDataConnectionState() maps State to DataState
|
||||
* FAILED or IDLE : DISCONNECTED
|
||||
* INITING or CONNECTING or SCANNING: CONNECTING
|
||||
* CONNECTED : CONNECTED or DISCONNECTING
|
||||
*/
|
||||
public enum State {
|
||||
IDLE,
|
||||
INITING,
|
||||
CONNECTING,
|
||||
SCANNING,
|
||||
CONNECTED,
|
||||
DISCONNECTING,
|
||||
FAILED
|
||||
}
|
||||
|
||||
public enum Activity {
|
||||
NONE,
|
||||
DATAIN,
|
||||
DATAOUT,
|
||||
DATAINANDOUT
|
||||
}
|
||||
|
||||
//***** Event Codes
|
||||
protected static final int EVENT_DATA_SETUP_COMPLETE = 1;
|
||||
protected static final int EVENT_RADIO_AVAILABLE = 3;
|
||||
protected static final int EVENT_RECORDS_LOADED = 4;
|
||||
protected static final int EVENT_TRY_SETUP_DATA = 5;
|
||||
protected static final int EVENT_DATA_STATE_CHANGED = 6;
|
||||
protected static final int EVENT_POLL_PDP = 7;
|
||||
protected static final int EVENT_GET_PDP_LIST_COMPLETE = 11;
|
||||
protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12;
|
||||
protected static final int EVENT_VOICE_CALL_STARTED = 14;
|
||||
protected static final int EVENT_VOICE_CALL_ENDED = 15;
|
||||
protected static final int EVENT_GPRS_DETACHED = 19;
|
||||
protected static final int EVENT_LINK_STATE_CHANGED = 20;
|
||||
protected static final int EVENT_ROAMING_ON = 21;
|
||||
protected static final int EVENT_ROAMING_OFF = 22;
|
||||
protected static final int EVENT_ENABLE_NEW_APN = 23;
|
||||
protected static final int EVENT_RESTORE_DEFAULT_APN = 24;
|
||||
protected static final int EVENT_DISCONNECT_DONE = 25;
|
||||
protected static final int EVENT_GPRS_ATTACHED = 26;
|
||||
protected static final int EVENT_START_NETSTAT_POLL = 27;
|
||||
protected static final int EVENT_START_RECOVERY = 28;
|
||||
protected static final int EVENT_APN_CHANGED = 29;
|
||||
protected static final int EVENT_CDMA_DATA_DETACHED = 30;
|
||||
protected static final int EVENT_NV_READY = 31;
|
||||
protected static final int EVENT_PS_RESTRICT_ENABLED = 32;
|
||||
protected static final int EVENT_PS_RESTRICT_DISABLED = 33;
|
||||
|
||||
//***** Constants
|
||||
protected static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000;
|
||||
|
||||
/** Cap out with 1 hour retry interval. */
|
||||
protected static final int RECONNECT_DELAY_MAX_MILLIS = 60 * 60 * 1000;
|
||||
|
||||
/** Slow poll when attempting connection recovery. */
|
||||
protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
|
||||
/** Default ping deadline, in seconds. */
|
||||
protected final int DEFAULT_PING_DEADLINE = 5;
|
||||
/** Default max failure count before attempting to network re-registration. */
|
||||
protected final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
|
||||
|
||||
/**
|
||||
* After detecting a potential connection problem, this is the max number
|
||||
* of subsequent polls before attempting a radio reset. At this point,
|
||||
* poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to
|
||||
* poll for about 2 more minutes.
|
||||
*/
|
||||
protected static final int NO_RECV_POLL_LIMIT = 24;
|
||||
|
||||
// 1 sec. default polling interval when screen is on.
|
||||
protected static final int POLL_NETSTAT_MILLIS = 1000;
|
||||
// 10 min. default polling interval when screen is off.
|
||||
protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
|
||||
// 2 min for round trip time
|
||||
protected static final int POLL_LONGEST_RTT = 120 * 1000;
|
||||
// 10 for packets without ack
|
||||
protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
|
||||
// how long to wait before switching back to default APN
|
||||
protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
|
||||
// system property that can override the above value
|
||||
protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
|
||||
// represents an invalid IP address
|
||||
protected static final String NULL_IP = "0.0.0.0";
|
||||
|
||||
|
||||
// member variables
|
||||
protected PhoneBase phone;
|
||||
protected Activity activity = Activity.NONE;
|
||||
protected State state = State.IDLE;
|
||||
protected Handler mDataConnectionTracker = null;
|
||||
|
||||
|
||||
protected INetStatService netstat;
|
||||
protected long txPkts, rxPkts, sentSinceLastRecv;
|
||||
protected int netStatPollPeriod;
|
||||
protected int mNoRecvPollCount = 0;
|
||||
protected boolean netStatPollEnabled = false;
|
||||
|
||||
// wifi connection status will be updated by sticky intent
|
||||
protected boolean mIsWifiConnected = false;
|
||||
|
||||
/** Intent sent when the reconnect alarm fires. */
|
||||
protected PendingIntent mReconnectIntent = null;
|
||||
|
||||
/** CID of active data connection */
|
||||
protected int cidActive;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
protected DataConnectionTracker(PhoneBase phone) {
|
||||
super();
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public Activity getActivity() {
|
||||
return activity;
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public String getStateInString() {
|
||||
switch (state) {
|
||||
case IDLE: return "IDLE";
|
||||
case INITING: return "INIT";
|
||||
case CONNECTING: return "CING";
|
||||
case SCANNING: return "SCAN";
|
||||
case CONNECTED: return "CNTD";
|
||||
case DISCONNECTING: return "DING";
|
||||
case FAILED: return "FAIL";
|
||||
default: return "ERRO";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The data connection is expected to be setup while device
|
||||
* 1. has Icc card
|
||||
* 2. registered for data service
|
||||
* 3. user doesn't explicitly disable data service
|
||||
* 4. wifi is not on
|
||||
*
|
||||
* @return false while no data connection if all above requirements are met.
|
||||
*/
|
||||
public abstract boolean isDataConnectionAsDesired();
|
||||
|
||||
//The data roaming setting is now located in the shared preferences.
|
||||
// See if the requested preference value is the same as that stored in
|
||||
// the shared values. If it is not, then update it.
|
||||
public void setDataOnRoamingEnabled(boolean enabled) {
|
||||
if (getDataOnRoamingEnabled() != enabled) {
|
||||
Settings.Secure.putInt(phone.getContext().getContentResolver(),
|
||||
Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
|
||||
}
|
||||
Message roamingMsg = phone.getServiceState().getRoaming() ?
|
||||
obtainMessage(EVENT_ROAMING_ON) : obtainMessage(EVENT_ROAMING_OFF);
|
||||
sendMessage(roamingMsg);
|
||||
}
|
||||
|
||||
//Retrieve the data roaming setting from the shared preferences.
|
||||
public boolean getDataOnRoamingEnabled() {
|
||||
try {
|
||||
return Settings.Secure.getInt(phone.getContext().getContentResolver(),
|
||||
Settings.Secure.DATA_ROAMING) > 0;
|
||||
} catch (SettingNotFoundException snfe) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// abstract handler methods
|
||||
protected abstract void onTrySetupData();
|
||||
protected abstract void onRoamingOff();
|
||||
protected abstract void onRoamingOn();
|
||||
protected abstract void onRadioAvailable();
|
||||
protected abstract void onRadioOffOrNotAvailable();
|
||||
protected abstract void onDataSetupComplete(AsyncResult ar);
|
||||
protected abstract void onDisconnectDone(AsyncResult ar);
|
||||
protected abstract void onVoiceCallStarted();
|
||||
protected abstract void onVoiceCallEnded();
|
||||
|
||||
//***** Overridden from Handler
|
||||
public void handleMessage (Message msg) {
|
||||
switch (msg.what) {
|
||||
|
||||
case EVENT_TRY_SETUP_DATA:
|
||||
onTrySetupData();
|
||||
break;
|
||||
|
||||
case EVENT_ROAMING_OFF:
|
||||
onRoamingOff();
|
||||
break;
|
||||
|
||||
case EVENT_ROAMING_ON:
|
||||
onRoamingOn();
|
||||
break;
|
||||
|
||||
case EVENT_RADIO_AVAILABLE:
|
||||
onRadioAvailable();
|
||||
break;
|
||||
|
||||
case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
|
||||
onRadioOffOrNotAvailable();
|
||||
break;
|
||||
|
||||
case EVENT_DATA_SETUP_COMPLETE:
|
||||
cidActive = msg.arg1;
|
||||
onDataSetupComplete((AsyncResult) msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_DISCONNECT_DONE:
|
||||
onDisconnectDone((AsyncResult) msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_VOICE_CALL_STARTED:
|
||||
onVoiceCallStarted();
|
||||
break;
|
||||
|
||||
case EVENT_VOICE_CALL_ENDED:
|
||||
onVoiceCallEnded();
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e("DATA", "Unidentified event = " + msg.what);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply tear down data connections due to radio off
|
||||
* and don't setup again.
|
||||
*/
|
||||
public abstract void cleanConnectionBeforeRadioOff();
|
||||
|
||||
/**
|
||||
* Report the current state of data connectivity (enabled or disabled)
|
||||
* @return {@code false} if data connectivity has been explicitly disabled,
|
||||
* {@code true} otherwise.
|
||||
*/
|
||||
public abstract boolean getDataEnabled();
|
||||
|
||||
/**
|
||||
* Report on whether data connectivity is enabled
|
||||
* @return {@code false} if data connectivity has been explicitly disabled,
|
||||
* {@code true} otherwise.
|
||||
*/
|
||||
public abstract boolean getAnyDataEnabled();
|
||||
|
||||
/**
|
||||
* Prevent mobile data connections from being established,
|
||||
* or once again allow mobile data connections. If the state
|
||||
* toggles, then either tear down or set up data, as
|
||||
* appropriate to match the new state.
|
||||
* @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
|
||||
* @return {@code true} if the operation succeeded
|
||||
*/
|
||||
public abstract boolean setDataEnabled(boolean enable);
|
||||
|
||||
protected abstract void startNetStatPoll();
|
||||
|
||||
protected abstract void stopNetStatPoll();
|
||||
|
||||
protected abstract void restartRadio();
|
||||
|
||||
protected abstract void log(String s);
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Registrant;
|
||||
@@ -24,14 +24,13 @@ import android.os.Registrant;
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
abstract class DataLink extends Handler implements DataLinkInterface {
|
||||
public abstract class DataLink extends Handler implements DataLinkInterface {
|
||||
|
||||
/** Registrant for link status change notifications. */
|
||||
Registrant mLinkChangeRegistrant;
|
||||
|
||||
protected Registrant mLinkChangeRegistrant;
|
||||
protected DataConnectionTracker dataConnection;
|
||||
|
||||
DataLink(DataConnectionTracker dc) {
|
||||
protected DataLink(DataConnectionTracker dc) {
|
||||
dataConnection = dc;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.os.Handler;
|
||||
@@ -24,7 +24,7 @@ import android.os.Handler;
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
interface DataLinkInterface {
|
||||
public interface DataLinkInterface {
|
||||
/**
|
||||
* Link state enumeration.
|
||||
*
|
||||
@@ -35,21 +35,21 @@ interface DataLinkInterface {
|
||||
LINK_DOWN,
|
||||
LINK_EXITED
|
||||
}
|
||||
|
||||
|
||||
/** Normal exit */
|
||||
final static int EXIT_OK = 0;
|
||||
/** Open failed */
|
||||
final static int EXIT_OPEN_FAILED = 7;
|
||||
|
||||
|
||||
/**
|
||||
* Sets the handler for link state change events.
|
||||
*
|
||||
*
|
||||
* @param h Handler
|
||||
* @param what User-defined message code
|
||||
* @param obj User object
|
||||
*/
|
||||
void setOnLinkChange(Handler h, int what, Object obj);
|
||||
|
||||
|
||||
/**
|
||||
* Sets up the data link.
|
||||
*/
|
||||
@@ -59,14 +59,14 @@ interface DataLinkInterface {
|
||||
* Tears down the data link.
|
||||
*/
|
||||
void disconnect();
|
||||
|
||||
|
||||
/**
|
||||
* Returns the exit code for a data link failure.
|
||||
* Returns the exit code for a data link failure.
|
||||
*
|
||||
* @return exit code
|
||||
*/
|
||||
int getLastLinkExitCode();
|
||||
|
||||
|
||||
/**
|
||||
* Sets password information that may be required by the data link
|
||||
* (eg, PAP secrets).
|
||||
@@ -33,7 +33,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier {
|
||||
private static final boolean DBG = true;
|
||||
private ITelephonyRegistry mRegistry;
|
||||
|
||||
/*package*/
|
||||
/*package*/
|
||||
DefaultPhoneNotifier() {
|
||||
mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
|
||||
"telephony.registry"));
|
||||
@@ -94,7 +94,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier {
|
||||
|
||||
public void notifyDataConnection(Phone sender, String reason) {
|
||||
try {
|
||||
mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()),
|
||||
mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()),
|
||||
sender.isDataConnectivityPossible(), reason, sender.getActiveApn(),
|
||||
sender.getInterfaceName(null));
|
||||
} catch (RemoteException ex) {
|
||||
@@ -119,7 +119,7 @@ public class DefaultPhoneNotifier implements PhoneNotifier {
|
||||
// system process is dead
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void log(String s) {
|
||||
Log.d(LOG_TAG, "[PhoneNotifier] " + s);
|
||||
}
|
||||
|
||||
@@ -14,9 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
import com.android.internal.telephony.*;
|
||||
|
||||
package com.android.internal.telephony;
|
||||
//import com.android.internal.telephony.*;
|
||||
import android.util.Log;
|
||||
import java.lang.Comparable;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
@@ -24,10 +23,9 @@ import android.telephony.PhoneNumberUtils;
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class DriverCall implements Comparable
|
||||
{
|
||||
static final String LOG_TAG = "GSM";
|
||||
|
||||
public class DriverCall implements Comparable {
|
||||
static final String LOG_TAG = "RILB";
|
||||
|
||||
public enum State {
|
||||
ACTIVE,
|
||||
HOLDING,
|
||||
@@ -48,11 +46,10 @@ public class DriverCall implements Comparable
|
||||
public boolean isVoice;
|
||||
public int als;
|
||||
public int numberPresentation;
|
||||
|
||||
|
||||
/** returns null on error */
|
||||
static DriverCall
|
||||
fromCLCCLine(String line)
|
||||
{
|
||||
fromCLCCLine(String line) {
|
||||
DriverCall ret = new DriverCall();
|
||||
|
||||
//+CLCC: 1,0,2,0,0,\"+18005551212\",145
|
||||
@@ -66,10 +63,10 @@ public class DriverCall implements Comparable
|
||||
|
||||
ret.isVoice = (0 == p.nextInt());
|
||||
ret.isMpty = p.nextBoolean();
|
||||
|
||||
|
||||
// use ALLOWED as default presentation while parsing CLCC
|
||||
ret.numberPresentation = Connection.PRESENTATION_ALLOWED;
|
||||
|
||||
|
||||
if (p.hasMore()) {
|
||||
// Some lame implementations return strings
|
||||
// like "NOT AVAILABLE" in the CLCC line
|
||||
@@ -98,13 +95,11 @@ public class DriverCall implements Comparable
|
||||
}
|
||||
|
||||
public
|
||||
DriverCall()
|
||||
{
|
||||
DriverCall() {
|
||||
}
|
||||
|
||||
public String
|
||||
toString()
|
||||
{
|
||||
toString() {
|
||||
return "id=" + index + ","
|
||||
+ (isMT ? "mt" : "mo") + ","
|
||||
+ state + ","
|
||||
@@ -114,8 +109,7 @@ public class DriverCall implements Comparable
|
||||
}
|
||||
|
||||
public static State
|
||||
stateFromCLCC(int state) throws ATParseEx
|
||||
{
|
||||
stateFromCLCC(int state) throws ATParseEx {
|
||||
switch(state) {
|
||||
case 0: return State.ACTIVE;
|
||||
case 1: return State.HOLDING;
|
||||
@@ -127,7 +121,7 @@ public class DriverCall implements Comparable
|
||||
throw new ATParseEx("illegal call state " + state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static int
|
||||
presentationFromCLIP(int cli) throws ATParseEx
|
||||
{
|
||||
@@ -141,12 +135,11 @@ public class DriverCall implements Comparable
|
||||
}
|
||||
}
|
||||
|
||||
//***** Comparable Implementation
|
||||
//***** Comparable Implementation
|
||||
|
||||
/** For sorting by index */
|
||||
public int
|
||||
compareTo (Object o)
|
||||
{
|
||||
compareTo (Object o) {
|
||||
DriverCall dc;
|
||||
|
||||
dc = (DriverCall)o;
|
||||
@@ -14,25 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class EncodeException extends Exception
|
||||
{
|
||||
public EncodeException()
|
||||
{
|
||||
public class EncodeException extends Exception {
|
||||
public EncodeException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public EncodeException(String s)
|
||||
{
|
||||
|
||||
public EncodeException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public EncodeException(char c)
|
||||
{
|
||||
public EncodeException(char c) {
|
||||
super("Unencodable char: '" + c + "'");
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.telephony.gsm.SmsMessage;
|
||||
import android.telephony.SmsMessage;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import android.util.Log;
|
||||
@@ -28,16 +28,15 @@ import android.util.Log;
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class GsmAlphabet
|
||||
{
|
||||
public class GsmAlphabet {
|
||||
static final String LOG_TAG = "GSM";
|
||||
|
||||
|
||||
|
||||
|
||||
//***** Constants
|
||||
|
||||
/**
|
||||
* This escapes extended characters, and when present indicates that the
|
||||
* This escapes extended characters, and when present indicates that the
|
||||
* following character should
|
||||
* be looked up in the "extended" table
|
||||
*
|
||||
@@ -55,8 +54,7 @@ public class GsmAlphabet
|
||||
* should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string
|
||||
*/
|
||||
public static int
|
||||
charToGsm(char c)
|
||||
{
|
||||
charToGsm(char c) {
|
||||
try {
|
||||
return charToGsm(c, false);
|
||||
} catch (EncodeException ex) {
|
||||
@@ -67,7 +65,7 @@ public class GsmAlphabet
|
||||
|
||||
/**
|
||||
* char to GSM alphabet char
|
||||
* @param throwException If true, throws EncodeException on invalid char.
|
||||
* @param throwException If true, throws EncodeException on invalid char.
|
||||
* If false, returns GSM alphabet ' ' char.
|
||||
*
|
||||
* Returns GSM_EXTENDED_ESCAPE if this character is in the extended table
|
||||
@@ -76,10 +74,9 @@ public class GsmAlphabet
|
||||
*/
|
||||
|
||||
public static int
|
||||
charToGsm(char c, boolean throwException) throws EncodeException
|
||||
{
|
||||
charToGsm(char c, boolean throwException) throws EncodeException {
|
||||
int ret;
|
||||
|
||||
|
||||
ret = charToGsm.get(c, -1);
|
||||
|
||||
if (ret == -1) {
|
||||
@@ -99,7 +96,7 @@ public class GsmAlphabet
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* char to extended GSM alphabet char
|
||||
@@ -110,10 +107,9 @@ public class GsmAlphabet
|
||||
*
|
||||
*/
|
||||
public static int
|
||||
charToGsmExtended(char c)
|
||||
{
|
||||
charToGsmExtended(char c) {
|
||||
int ret;
|
||||
|
||||
|
||||
ret = charToGsmExtended.get(c, -1);
|
||||
|
||||
if (ret == -1) {
|
||||
@@ -124,34 +120,32 @@ public class GsmAlphabet
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a character in the GSM alphabet into a char
|
||||
* Converts a character in the GSM alphabet into a char
|
||||
*
|
||||
* if GSM_EXTENDED_ESCAPE is passed, 0xffff is returned. In this case,
|
||||
* the following character in the stream should be decoded with
|
||||
* the following character in the stream should be decoded with
|
||||
* gsmExtendedToChar()
|
||||
*
|
||||
* If an unmappable value is passed (one greater than 127), ' ' is returned
|
||||
*/
|
||||
|
||||
public static char
|
||||
gsmToChar(int gsmChar)
|
||||
{
|
||||
gsmToChar(int gsmChar) {
|
||||
return (char)gsmToChar.get(gsmChar, ' ');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Converts a character in the extended GSM alphabet into a char
|
||||
* Converts a character in the extended GSM alphabet into a char
|
||||
*
|
||||
* if GSM_EXTENDED_ESCAPE is passed, ' ' is returned since no second
|
||||
* extension page has yet been defined (see Note 1 in table 6.2.1.1 of
|
||||
* TS 23.038 v7.00)
|
||||
*
|
||||
*
|
||||
* If an unmappable value is passed , ' ' is returned
|
||||
*/
|
||||
|
||||
public static char
|
||||
gsmExtendedToChar(int gsmChar)
|
||||
{
|
||||
gsmExtendedToChar(int gsmChar) {
|
||||
int ret;
|
||||
|
||||
ret = gsmExtendedToChar.get(gsmChar, -1);
|
||||
@@ -205,7 +199,7 @@ public class GsmAlphabet
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String into a byte array containing
|
||||
* Converts a String into a byte array containing
|
||||
* the 7-bit packed GSM Alphabet representation of the string.
|
||||
*
|
||||
* Unencodable chars are encoded as spaces
|
||||
@@ -224,7 +218,7 @@ public class GsmAlphabet
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String into a byte array containing
|
||||
* Converts a String into a byte array containing
|
||||
* the 7-bit packed GSM Alphabet representation of the string.
|
||||
*
|
||||
* Byte 0 in the returned byte array is the count of septets used
|
||||
@@ -238,7 +232,7 @@ public class GsmAlphabet
|
||||
* enforced maximum.
|
||||
* @param startingBitOffset the number of padding bits to put before
|
||||
* the start of the first septet at the begining of the array
|
||||
* @param throwException If true, throws EncodeException on invalid char.
|
||||
* @param throwException If true, throws EncodeException on invalid char.
|
||||
* If false, replaces unencodable char with GSM alphabet space char.
|
||||
*
|
||||
* @throws EncodeException if String is too large to encode
|
||||
@@ -294,27 +288,26 @@ public class GsmAlphabet
|
||||
* @param bitOffset the bit offset that the septet should be packed at
|
||||
* (septet index * 7)
|
||||
*/
|
||||
private static void
|
||||
packSmsChar(byte[] packedChars, int bitOffset, int value)
|
||||
{
|
||||
private static void
|
||||
packSmsChar(byte[] packedChars, int bitOffset, int value) {
|
||||
int byteOffset = bitOffset / 8;
|
||||
int shift = bitOffset % 8;
|
||||
|
||||
packedChars[++byteOffset] |= value << shift;
|
||||
|
||||
if (shift > 1) {
|
||||
packedChars[++byteOffset] = (byte)(value >> (8 - shift));
|
||||
}
|
||||
packedChars[++byteOffset] = (byte)(value >> (8 - shift));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a GSM alphabet 7 bit packed string (SMS string) into a
|
||||
* Convert a GSM alphabet 7 bit packed string (SMS string) into a
|
||||
* {@link java.lang.String}.
|
||||
*
|
||||
* See TS 23.038 6.1.2.1 for SMS Character Packing
|
||||
*
|
||||
* @param pdu the raw data from the pdu
|
||||
* @param offset the byte offset of
|
||||
* @param offset the byte offset of
|
||||
* @param lengthSeptets string length in septets, not bytes
|
||||
* @return String representation or null on decoding exception
|
||||
*/
|
||||
@@ -324,27 +317,26 @@ public class GsmAlphabet
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a GSM alphabet 7 bit packed string (SMS string) into a
|
||||
* Convert a GSM alphabet 7 bit packed string (SMS string) into a
|
||||
* {@link java.lang.String}.
|
||||
*
|
||||
* See TS 23.038 6.1.2.1 for SMS Character Packing
|
||||
*
|
||||
* @param pdu the raw data from the pdu
|
||||
* @param offset the byte offset of
|
||||
* @param offset the byte offset of
|
||||
* @param lengthSeptets string length in septets, not bytes
|
||||
* @param numPaddingBits the number of padding bits before the start of the
|
||||
* string in the first byte
|
||||
* @return String representation or null on decoding exception
|
||||
*/
|
||||
public static String gsm7BitPackedToString(byte[] pdu, int offset,
|
||||
int lengthSeptets, int numPaddingBits)
|
||||
{
|
||||
int lengthSeptets, int numPaddingBits) {
|
||||
StringBuilder ret = new StringBuilder(lengthSeptets);
|
||||
boolean prevCharWasEscape;
|
||||
|
||||
|
||||
try {
|
||||
prevCharWasEscape = false;
|
||||
|
||||
|
||||
for (int i = 0 ; i < lengthSeptets ; i++) {
|
||||
int bitOffset = (7 * i) + numPaddingBits;
|
||||
|
||||
@@ -381,15 +373,14 @@ public class GsmAlphabet
|
||||
|
||||
|
||||
/**
|
||||
* Convert a GSM alphabet string that's stored in 8-bit unpacked
|
||||
* Convert a GSM alphabet string that's stored in 8-bit unpacked
|
||||
* format (as it often appears in SIM records) into a String
|
||||
*
|
||||
* Field may be padded with trailing 0xff's. The decode stops
|
||||
* at the first 0xff encountered.
|
||||
*/
|
||||
public static String
|
||||
gsm8BitUnpackedToString(byte[] data, int offset, int length)
|
||||
{
|
||||
gsm8BitUnpackedToString(byte[] data, int offset, int length) {
|
||||
boolean prevWasEscape;
|
||||
StringBuilder ret = new StringBuilder(length);
|
||||
|
||||
@@ -420,8 +411,8 @@ public class GsmAlphabet
|
||||
prevWasEscape = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret.toString();
|
||||
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -429,8 +420,7 @@ public class GsmAlphabet
|
||||
* array
|
||||
*/
|
||||
public static byte[]
|
||||
stringToGsm8BitPacked(String s)
|
||||
{
|
||||
stringToGsm8BitPacked(String s) {
|
||||
byte[] ret;
|
||||
|
||||
int septets = 0;
|
||||
@@ -452,15 +442,14 @@ public class GsmAlphabet
|
||||
*
|
||||
* Field is padded with 0xff's, string is truncated if necessary
|
||||
*/
|
||||
|
||||
|
||||
public static void
|
||||
stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length)
|
||||
{
|
||||
stringToGsm8BitUnpackedField(String s, byte dest[], int offset, int length) {
|
||||
int outByteIndex = offset;
|
||||
|
||||
// Septets are stored in byte-aligned octets
|
||||
for (int i = 0, sz = s.length()
|
||||
; i < sz && (outByteIndex - offset) < length
|
||||
; i < sz && (outByteIndex - offset) < length
|
||||
; i++
|
||||
) {
|
||||
char c = s.charAt(i);
|
||||
@@ -475,7 +464,7 @@ public class GsmAlphabet
|
||||
|
||||
dest[outByteIndex++] = GSM_EXTENDED_ESCAPE;
|
||||
|
||||
v = GsmAlphabet.charToGsmExtended(c);
|
||||
v = GsmAlphabet.charToGsmExtended(c);
|
||||
}
|
||||
|
||||
dest[outByteIndex++] = (byte)v;
|
||||
@@ -492,8 +481,7 @@ public class GsmAlphabet
|
||||
* needed to represent this character. Counts unencodable char as 1 septet.
|
||||
*/
|
||||
public static int
|
||||
countGsmSeptets(char c)
|
||||
{
|
||||
countGsmSeptets(char c) {
|
||||
try {
|
||||
return countGsmSeptets(c, false);
|
||||
} catch (EncodeException ex) {
|
||||
@@ -509,21 +497,20 @@ public class GsmAlphabet
|
||||
* char. Otherwise, counts invalid char as 1 septet
|
||||
*/
|
||||
public static int
|
||||
countGsmSeptets(char c, boolean throwsException) throws EncodeException
|
||||
{
|
||||
if (charToGsm.get(c, -1) != -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (charToGsmExtended.get(c, -1) != -1) {
|
||||
return 2;
|
||||
}
|
||||
countGsmSeptets(char c, boolean throwsException) throws EncodeException {
|
||||
if (charToGsm.get(c, -1) != -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (charToGsmExtended.get(c, -1) != -1) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (throwsException) {
|
||||
throw new EncodeException(c);
|
||||
} else {
|
||||
// count as a space char
|
||||
return 1;
|
||||
} else {
|
||||
// count as a space char
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,8 +519,7 @@ public class GsmAlphabet
|
||||
* needed to represent this string. Counts unencodable char as 1 septet.
|
||||
*/
|
||||
public static int
|
||||
countGsmSeptets(CharSequence s)
|
||||
{
|
||||
countGsmSeptets(CharSequence s) {
|
||||
try {
|
||||
return countGsmSeptets(s, false);
|
||||
} catch (EncodeException ex) {
|
||||
@@ -549,8 +535,7 @@ public class GsmAlphabet
|
||||
* char. Otherwise, counts invalid char as 1 septet
|
||||
*/
|
||||
public static int
|
||||
countGsmSeptets(CharSequence s, boolean throwsException) throws EncodeException
|
||||
{
|
||||
countGsmSeptets(CharSequence s, boolean throwsException) throws EncodeException {
|
||||
int charIndex = 0;
|
||||
int sz = s.length();
|
||||
int count = 0;
|
||||
@@ -559,9 +544,9 @@ public class GsmAlphabet
|
||||
count += countGsmSeptets(s.charAt(charIndex), throwsException);
|
||||
charIndex++;
|
||||
}
|
||||
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index into <code>s</code> of the first character
|
||||
@@ -623,7 +608,7 @@ public class GsmAlphabet
|
||||
* @return index of first character that won't fit, or the length
|
||||
* of the entire string if everything fits
|
||||
*/
|
||||
public static int
|
||||
public static int
|
||||
findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException {
|
||||
if (encodingType == SmsMessage.ENCODING_7BIT) {
|
||||
return findGsmSeptetLimitIndex(s, start, limit);
|
||||
@@ -643,10 +628,10 @@ public class GsmAlphabet
|
||||
private static final SparseIntArray gsmToChar = new SparseIntArray();
|
||||
private static final SparseIntArray charToGsmExtended = new SparseIntArray();
|
||||
private static final SparseIntArray gsmExtendedToChar = new SparseIntArray();
|
||||
|
||||
|
||||
static {
|
||||
int i = 0;
|
||||
|
||||
|
||||
charToGsm.put('@', i++);
|
||||
charToGsm.put('\u00a3', i++);
|
||||
charToGsm.put('$', i++);
|
||||
@@ -663,7 +648,7 @@ public class GsmAlphabet
|
||||
charToGsm.put('\r', i++);
|
||||
charToGsm.put('\u00c5', i++);
|
||||
charToGsm.put('\u00e5', i++);
|
||||
|
||||
|
||||
charToGsm.put('\u0394', i++);
|
||||
charToGsm.put('_', i++);
|
||||
charToGsm.put('\u03a6', i++);
|
||||
@@ -680,7 +665,7 @@ public class GsmAlphabet
|
||||
charToGsm.put('\u00e6', i++);
|
||||
charToGsm.put('\u00df', i++);
|
||||
charToGsm.put('\u00c9', i++);
|
||||
|
||||
|
||||
charToGsm.put(' ', i++);
|
||||
charToGsm.put('!', i++);
|
||||
charToGsm.put('"', i++);
|
||||
@@ -697,7 +682,7 @@ public class GsmAlphabet
|
||||
charToGsm.put('-', i++);
|
||||
charToGsm.put('.', i++);
|
||||
charToGsm.put('/', i++);
|
||||
|
||||
|
||||
charToGsm.put('0', i++);
|
||||
charToGsm.put('1', i++);
|
||||
charToGsm.put('2', i++);
|
||||
@@ -714,7 +699,7 @@ public class GsmAlphabet
|
||||
charToGsm.put('=', i++);
|
||||
charToGsm.put('>', i++);
|
||||
charToGsm.put('?', i++);
|
||||
|
||||
|
||||
charToGsm.put('\u00a1', i++);
|
||||
charToGsm.put('A', i++);
|
||||
charToGsm.put('B', i++);
|
||||
@@ -731,7 +716,7 @@ public class GsmAlphabet
|
||||
charToGsm.put('M', i++);
|
||||
charToGsm.put('N', i++);
|
||||
charToGsm.put('O', i++);
|
||||
|
||||
|
||||
charToGsm.put('P', i++);
|
||||
charToGsm.put('Q', i++);
|
||||
charToGsm.put('R', i++);
|
||||
@@ -748,7 +733,7 @@ public class GsmAlphabet
|
||||
charToGsm.put('\u0147', i++);
|
||||
charToGsm.put('\u00dc', i++);
|
||||
charToGsm.put('\u00a7', i++);
|
||||
|
||||
|
||||
charToGsm.put('\u00bf', i++);
|
||||
charToGsm.put('a', i++);
|
||||
charToGsm.put('b', i++);
|
||||
@@ -765,7 +750,7 @@ public class GsmAlphabet
|
||||
charToGsm.put('m', i++);
|
||||
charToGsm.put('n', i++);
|
||||
charToGsm.put('o', i++);
|
||||
|
||||
|
||||
charToGsm.put('p', i++);
|
||||
charToGsm.put('q', i++);
|
||||
charToGsm.put('r', i++);
|
||||
@@ -782,8 +767,8 @@ public class GsmAlphabet
|
||||
charToGsm.put('\u00f1', i++);
|
||||
charToGsm.put('\u00fc', i++);
|
||||
charToGsm.put('\u00e0', i++);
|
||||
|
||||
|
||||
|
||||
|
||||
charToGsmExtended.put('\f', 10);
|
||||
charToGsmExtended.put('^', 20);
|
||||
charToGsmExtended.put('{', 40);
|
||||
@@ -794,12 +779,12 @@ public class GsmAlphabet
|
||||
charToGsmExtended.put(']', 62);
|
||||
charToGsmExtended.put('|', 64);
|
||||
charToGsmExtended.put('\u20ac', 101);
|
||||
|
||||
|
||||
int size = charToGsm.size();
|
||||
for (int j=0; j<size; j++) {
|
||||
gsmToChar.put(charToGsm.valueAt(j), charToGsm.keyAt(j));
|
||||
}
|
||||
|
||||
|
||||
size = charToGsmExtended.size();
|
||||
for (int j=0; j<size; j++) {
|
||||
gsmExtendedToChar.put(charToGsmExtended.valueAt(j), charToGsmExtended.keyAt(j));
|
||||
@@ -808,6 +793,6 @@ public class GsmAlphabet
|
||||
|
||||
sGsmSpaceChar = charToGsm.get(' ');
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -14,27 +14,27 @@
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import com.android.internal.telephony.gsm.AdnRecord;
|
||||
import com.android.internal.telephony.AdnRecord;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Interface for applications to access the SIM phone book.
|
||||
|
||||
/** Interface for applications to access the ICC phone book.
|
||||
*
|
||||
* <p>The following code snippet demonstrates a static method to
|
||||
* retrieve the ISimPhoneBook interface from Android:</p>
|
||||
* <pre>private static ISimPhoneBook getSimPhoneBookInterface()
|
||||
* retrieve the IIccPhoneBook interface from Android:</p>
|
||||
* <pre>private static IIccPhoneBook getSimPhoneBookInterface()
|
||||
throws DeadObjectException {
|
||||
IServiceManager sm = ServiceManagerNative.getDefault();
|
||||
ISimPhoneBook spb;
|
||||
spb = ISimPhoneBook.Stub.asInterface(sm.getService("simphonebook"));
|
||||
IIccPhoneBook spb;
|
||||
spb = IIccPhoneBook.Stub.asInterface(sm.getService("iccphonebook"));
|
||||
return spb;
|
||||
}
|
||||
* </pre>
|
||||
*/
|
||||
|
||||
interface ISimPhoneBook {
|
||||
interface IIccPhoneBook {
|
||||
|
||||
/**
|
||||
* Loads the AdnRecords in efid and returns them as a
|
||||
@@ -39,9 +39,9 @@ interface IPhoneSubInfo {
|
||||
String getSubscriberId();
|
||||
|
||||
/**
|
||||
* Retrieves the serial number of the SIM, if applicable.
|
||||
* Retrieves the serial number of the ICC, if applicable.
|
||||
*/
|
||||
String getSimSerialNumber();
|
||||
String getIccSerialNumber();
|
||||
|
||||
/**
|
||||
* Retrieves the phone number string for line 1.
|
||||
@@ -53,13 +53,13 @@ interface IPhoneSubInfo {
|
||||
*/
|
||||
String getLine1AlphaTag();
|
||||
|
||||
/**
|
||||
* Retrieves the voice mail number.
|
||||
*/
|
||||
/**
|
||||
* Retrieves the voice mail number.
|
||||
*/
|
||||
String getVoiceMailNumber();
|
||||
|
||||
/**
|
||||
* Retrieves the alpha identifier associated with the voice mail number.
|
||||
*/
|
||||
/**
|
||||
* Retrieves the alpha identifier associated with the voice mail number.
|
||||
*/
|
||||
String getVoiceMailAlphaTag();
|
||||
}
|
||||
|
||||
@@ -14,20 +14,20 @@
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import com.android.internal.telephony.gsm.SmsRawData;
|
||||
import com.android.internal.telephony.SmsRawData;
|
||||
|
||||
/** Interface for applications to access the SIM phone book.
|
||||
/** Interface for applications to access the ICC phone book.
|
||||
*
|
||||
* <p>The following code snippet demonstrates a static method to
|
||||
* retrieve the ISimSms interface from Android:</p>
|
||||
* <pre>private static ISimSms getSimSmsInterface()
|
||||
* retrieve the ISms interface from Android:</p>
|
||||
* <pre>private static ISms getSmsInterface()
|
||||
throws DeadObjectException {
|
||||
IServiceManager sm = ServiceManagerNative.getDefault();
|
||||
ISimSms ss;
|
||||
ss = ISimSms.Stub.asInterface(sm.getService("isms"));
|
||||
ISms ss;
|
||||
ss = ISms.Stub.asInterface(sm.getService("isms"));
|
||||
return ss;
|
||||
}
|
||||
* </pre>
|
||||
@@ -35,45 +35,45 @@ import com.android.internal.telephony.gsm.SmsRawData;
|
||||
|
||||
interface ISms {
|
||||
/**
|
||||
* Retrieves all messages currently stored on SIM.
|
||||
* Retrieves all messages currently stored on ICC.
|
||||
*
|
||||
* @return list of SmsRawData of all sms on SIM
|
||||
* @return list of SmsRawData of all sms on ICC
|
||||
*/
|
||||
List<SmsRawData> getAllMessagesFromSimEf();
|
||||
List<SmsRawData> getAllMessagesFromIccEf();
|
||||
|
||||
/**
|
||||
* Update the specified message on the SIM.
|
||||
* Update the specified message on the ICC.
|
||||
*
|
||||
* @param messageIndex record index of message to update
|
||||
* @param newStatus new message status (STATUS_ON_SIM_READ,
|
||||
* STATUS_ON_SIM_UNREAD, STATUS_ON_SIM_SENT,
|
||||
* STATUS_ON_SIM_UNSENT, STATUS_ON_SIM_FREE)
|
||||
* @param newStatus new message status (STATUS_ON_ICC_READ,
|
||||
* STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
|
||||
* STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
|
||||
* @param pdu the raw PDU to store
|
||||
* @return success or not
|
||||
*
|
||||
*/
|
||||
boolean updateMessageOnSimEf(int messageIndex, int newStatus,
|
||||
boolean updateMessageOnIccEf(int messageIndex, int newStatus,
|
||||
in byte[] pdu);
|
||||
|
||||
/**
|
||||
* Copy a raw SMS PDU to the SIM.
|
||||
* Copy a raw SMS PDU to the ICC.
|
||||
*
|
||||
* @param pdu the raw PDU to store
|
||||
* @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD,
|
||||
* STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT)
|
||||
* @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
|
||||
* STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
|
||||
* @return success or not
|
||||
*
|
||||
*/
|
||||
boolean copyMessageToSimEf(int status, in byte[] pdu, in byte[] smsc);
|
||||
boolean copyMessageToIccEf(int status, in byte[] pdu, in byte[] smsc);
|
||||
|
||||
/**
|
||||
* Send a SMS
|
||||
*
|
||||
* @param smsc the SMSC to send the message through, or NULL for the
|
||||
* defatult SMSC
|
||||
* default SMSC
|
||||
* @param pdu the raw PDU to send
|
||||
* @param sentIntent if not NULL this <code>Intent</code> is
|
||||
* broadcast when the message is sucessfully sent, or failed.
|
||||
* broadcast when the message is successfully sent, or failed.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
* or one of these errors:
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
@@ -88,13 +88,13 @@ interface ISms {
|
||||
|
||||
/**
|
||||
* Send a multi-part text based SMS.
|
||||
*
|
||||
*
|
||||
* @param destinationAddress the address to send the message to
|
||||
* @param scAddress is the service center address or null to use
|
||||
* the current default SMSC
|
||||
* @param parts an <code>ArrayList</code> of strings that, in order,
|
||||
* comprise the original message
|
||||
* @param sentIntents if not null, an <code>ArrayList</code> of
|
||||
* @param sentIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been sent.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
@@ -102,7 +102,7 @@ interface ISms {
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* @param deliveryIntents if not null, an <code>ArrayList</code> of
|
||||
* @param deliveryIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been delivered
|
||||
* to the recipient. The raw pdu of the status report is in the
|
||||
@@ -21,7 +21,7 @@ import java.util.List;
|
||||
import android.telephony.NeighboringCellInfo;
|
||||
|
||||
/**
|
||||
* Interface used to interact with the phone. Mostly this is used by the
|
||||
* Interface used to interact with the phone. Mostly this is used by the
|
||||
* TelephonyManager class. A few places are still using this directly.
|
||||
* Please clean them up if possible and use TelephonyManager insteadl.
|
||||
*
|
||||
@@ -135,7 +135,7 @@ interface ITelephony {
|
||||
/**
|
||||
* Cancels the missed calls notification.
|
||||
*/
|
||||
void cancelMissedCallsNotification();
|
||||
void cancelMissedCallsNotification();
|
||||
|
||||
/**
|
||||
* Supply a pin to unlock the SIM. Blocks until a result is determined.
|
||||
@@ -147,7 +147,7 @@ interface ITelephony {
|
||||
/**
|
||||
* Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
|
||||
* without SEND (so <code>dial</code> is not appropriate).
|
||||
*
|
||||
*
|
||||
* @param dialString the MMI command to be executed.
|
||||
* @return true if MMI command is executed.
|
||||
*/
|
||||
@@ -213,4 +213,13 @@ interface ITelephony {
|
||||
int getCallState();
|
||||
int getDataActivity();
|
||||
int getDataState();
|
||||
|
||||
/**
|
||||
* Returns the current active phone type as integer.
|
||||
* Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE
|
||||
* and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE
|
||||
*/
|
||||
int getActivePhoneType();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,35 +22,34 @@ import android.os.Handler;
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public interface SimCard
|
||||
{
|
||||
/* The extra data for broacasting intent INTENT_SIM_STATE_CHANGE */
|
||||
static public final String INTENT_KEY_SIM_STATE = "ss";
|
||||
/* NOT_READY means the SIM interface is not ready (eg, radio is off or powering on) */
|
||||
static public final String INTENT_VALUE_SIM_NOT_READY = "NOT_READY";
|
||||
/* ABSENT means SIM is missing */
|
||||
static public final String INTENT_VALUE_SIM_ABSENT = "ABSENT";
|
||||
/* LOCKED means SIM is locked by pin or by network */
|
||||
static public final String INTENT_VALUE_SIM_LOCKED = "LOCKED";
|
||||
/* READY means SIM is ready to access */
|
||||
static public final String INTENT_VALUE_SIM_READY = "READY";
|
||||
/* IMSI means SIM IMSI is ready in property */
|
||||
static public final String INTENT_VALUE_SIM_IMSI = "IMSI";
|
||||
/* LOADED means all SIM records, including IMSI, are loaded */
|
||||
static public final String INTENT_VALUE_SIM_LOADED = "LOADED";
|
||||
/* The extra data for broacasting intent INTENT_SIM_STATE_CHANGE */
|
||||
public interface IccCard {
|
||||
/* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */
|
||||
static public final String INTENT_KEY_ICC_STATE = "ss";
|
||||
/* NOT_READY means the ICC interface is not ready (eg, radio is off or powering on) */
|
||||
static public final String INTENT_VALUE_ICC_NOT_READY = "NOT_READY";
|
||||
/* ABSENT means ICC is missing */
|
||||
static public final String INTENT_VALUE_ICC_ABSENT = "ABSENT";
|
||||
/* LOCKED means ICC is locked by pin or by network */
|
||||
static public final String INTENT_VALUE_ICC_LOCKED = "LOCKED";
|
||||
/* READY means ICC is ready to access */
|
||||
static public final String INTENT_VALUE_ICC_READY = "READY";
|
||||
/* IMSI means ICC IMSI is ready in property */
|
||||
static public final String INTENT_VALUE_ICC_IMSI = "IMSI";
|
||||
/* LOADED means all ICC records, including IMSI, are loaded */
|
||||
static public final String INTENT_VALUE_ICC_LOADED = "LOADED";
|
||||
/* The extra data for broacasting intent INTENT_ICC_STATE_CHANGE */
|
||||
static public final String INTENT_KEY_LOCKED_REASON = "reason";
|
||||
/* PIN means SIM is locked on PIN1 */
|
||||
/* PIN means ICC is locked on PIN1 */
|
||||
static public final String INTENT_VALUE_LOCKED_ON_PIN = "PIN";
|
||||
/* PUK means SIM is locked on PUK1 */
|
||||
/* PUK means ICC is locked on PUK1 */
|
||||
static public final String INTENT_VALUE_LOCKED_ON_PUK = "PUK";
|
||||
/* NETWORK means SIM is locked on NETWORK PERSONALIZATION */
|
||||
/* NETWORK means ICC is locked on NETWORK PERSONALIZATION */
|
||||
static public final String INTENT_VALUE_LOCKED_NETWORK = "NETWORK";
|
||||
|
||||
|
||||
/*
|
||||
UNKNOWN is a transient state, for example, after uesr inputs sim pin under
|
||||
PIN_REQUIRED state, the query for sim status returns UNKNOWN before it
|
||||
UNKNOWN is a transient state, for example, after uesr inputs ICC pin under
|
||||
PIN_REQUIRED state, the query for ICC status returns UNKNOWN before it
|
||||
turns to READY
|
||||
*/
|
||||
public enum State {
|
||||
@@ -73,7 +72,7 @@ public interface SimCard
|
||||
* Notifies handler of any transition into State.ABSENT
|
||||
*/
|
||||
void registerForAbsent(Handler h, int what, Object obj);
|
||||
void unregisterForAbsent(Handler h);
|
||||
void unregisterForAbsent(Handler h);
|
||||
|
||||
/**
|
||||
* Notifies handler of any transition into State.isPinLocked()
|
||||
@@ -88,7 +87,7 @@ public interface SimCard
|
||||
void unregisterForNetworkLocked(Handler h);
|
||||
|
||||
/**
|
||||
* Supply the SIM PIN to the SIM
|
||||
* Supply the ICC PIN to the ICC
|
||||
*
|
||||
* When the operation is complete, onComplete will be sent to it's
|
||||
* Handler.
|
||||
@@ -100,11 +99,11 @@ public interface SimCard
|
||||
*
|
||||
* If the supplied PIN is incorrect:
|
||||
* ((AsyncResult)onComplete.obj).exception != null
|
||||
* && ((AsyncResult)onComplete.obj).exception
|
||||
* && ((AsyncResult)onComplete.obj).exception
|
||||
* instanceof com.android.internal.telephony.gsm.CommandException)
|
||||
* && ((CommandException)(((AsyncResult)onComplete.obj).exception))
|
||||
* .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -114,30 +113,30 @@ public interface SimCard
|
||||
void supplyPuk2 (String puk2, String newPin2, Message onComplete);
|
||||
|
||||
/**
|
||||
* Check whether sim pin lock is enabled
|
||||
* Check whether ICC pin lock is enabled
|
||||
* This is a sync call which returns the cached pin enabled state
|
||||
*
|
||||
* @return true for sim locked enabled
|
||||
* false for sim locked disabled
|
||||
* @return true for ICC locked enabled
|
||||
* false for ICC locked disabled
|
||||
*/
|
||||
boolean getSimLockEnabled ();
|
||||
boolean getIccLockEnabled ();
|
||||
|
||||
/**
|
||||
* Set the sim pin lock enabled or disabled
|
||||
* Set the ICC pin lock enabled or disabled
|
||||
* When the operation is complete, onComplete will be sent to its handler
|
||||
*
|
||||
* @param enabled "true" for locked "false" for unlocked.
|
||||
* @param password needed to change the sim pin state, aka. Pin1
|
||||
* @param password needed to change the ICC pin state, aka. Pin1
|
||||
* @param onComplete
|
||||
* onComplete.obj will be an AsyncResult
|
||||
* ((AsyncResult)onComplete.obj).exception == null on success
|
||||
* ((AsyncResult)onComplete.obj).exception != null on fail
|
||||
*/
|
||||
void setSimLockEnabled(boolean enabled, String password, Message onComplete);
|
||||
void setIccLockEnabled(boolean enabled, String password, Message onComplete);
|
||||
|
||||
|
||||
/**
|
||||
* Change the sim password used in sim pin lock
|
||||
* Change the ICC password used in ICC pin lock
|
||||
* When the operation is complete, onComplete will be sent to its handler
|
||||
*
|
||||
* @param oldPassword is the old password
|
||||
@@ -147,33 +146,33 @@ public interface SimCard
|
||||
* ((AsyncResult)onComplete.obj).exception == null on success
|
||||
* ((AsyncResult)onComplete.obj).exception != null on fail
|
||||
*/
|
||||
void changeSimLockPassword(String oldPassword, String newPassword,
|
||||
void changeIccLockPassword(String oldPassword, String newPassword,
|
||||
Message onComplete);
|
||||
|
||||
/**
|
||||
* Check whether sim fdn (fixed dialing number) is enabled
|
||||
* Check whether ICC fdn (fixed dialing number) is enabled
|
||||
* This is a sync call which returns the cached pin enabled state
|
||||
*
|
||||
* @return true for sim fdn enabled
|
||||
* false for sim fdn disabled
|
||||
* @return true for ICC fdn enabled
|
||||
* false for ICC fdn disabled
|
||||
*/
|
||||
boolean getSimFdnEnabled ();
|
||||
boolean getIccFdnEnabled ();
|
||||
|
||||
/**
|
||||
* Set the sim fdn enabled or disabled
|
||||
* Set the ICC fdn enabled or disabled
|
||||
* When the operation is complete, onComplete will be sent to its handler
|
||||
*
|
||||
* @param enabled "true" for locked "false" for unlocked.
|
||||
* @param password needed to change the sim fdn enable, aka Pin2
|
||||
* @param password needed to change the ICC fdn enable, aka Pin2
|
||||
* @param onComplete
|
||||
* onComplete.obj will be an AsyncResult
|
||||
* ((AsyncResult)onComplete.obj).exception == null on success
|
||||
* ((AsyncResult)onComplete.obj).exception != null on fail
|
||||
*/
|
||||
void setSimFdnEnabled(boolean enabled, String password, Message onComplete);
|
||||
void setIccFdnEnabled(boolean enabled, String password, Message onComplete);
|
||||
|
||||
/**
|
||||
* Change the sim password used in sim fdn enable
|
||||
* Change the ICC password used in ICC fdn enable
|
||||
* When the operation is complete, onComplete will be sent to its handler
|
||||
*
|
||||
* @param oldPassword is the old password
|
||||
@@ -183,13 +182,13 @@ public interface SimCard
|
||||
* ((AsyncResult)onComplete.obj).exception == null on success
|
||||
* ((AsyncResult)onComplete.obj).exception != null on fail
|
||||
*/
|
||||
void changeSimFdnPassword(String oldPassword, String newPassword,
|
||||
void changeIccFdnPassword(String oldPassword, String newPassword,
|
||||
Message onComplete);
|
||||
|
||||
void supplyNetworkDepersonalization (String pin, Message onComplete);
|
||||
|
||||
/**
|
||||
* Returns service provider name stored in SIM card.
|
||||
* Returns service provider name stored in ICC card.
|
||||
* If there is no service provider name associated or the record is not
|
||||
* yet available, null will be returned <p>
|
||||
*
|
||||
@@ -199,7 +198,7 @@ public interface SimCard
|
||||
*
|
||||
* Also available via Android property "gsm.sim.operator.alpha"
|
||||
*
|
||||
* @return Service Provider Name stored in SIM card
|
||||
* @return Service Provider Name stored in ICC card
|
||||
* null if no service provider name associated or the record is not
|
||||
* yet available
|
||||
*
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
/**
|
||||
* See also RIL_AppStatus in include/telephony/ril.h
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class IccCardApplication {
|
||||
public enum AppType{
|
||||
APPTYPE_UNKNOWN,
|
||||
APPTYPE_SIM,
|
||||
APPTYPE_USIM,
|
||||
APPTYPE_RUIM,
|
||||
APPTYPE_CSIM
|
||||
};
|
||||
|
||||
public enum AppState{
|
||||
APPSTATE_UNKNOWN,
|
||||
APPSTATE_DETECTED,
|
||||
APPSTATE_PIN,
|
||||
APPSTATE_PUK,
|
||||
APPSTATE_SUBSCRIPTION_PERSO,
|
||||
APPSTATE_READY;
|
||||
|
||||
boolean isPinRequired() {
|
||||
return this == APPSTATE_PIN;
|
||||
}
|
||||
|
||||
boolean isPukRequired() {
|
||||
return this == APPSTATE_PUK;
|
||||
}
|
||||
|
||||
boolean isSubscriptionPersoEnabled() {
|
||||
return this == APPSTATE_SUBSCRIPTION_PERSO;
|
||||
}
|
||||
|
||||
boolean isAppReady() {
|
||||
return this == APPSTATE_READY;
|
||||
}
|
||||
|
||||
boolean isAppNotReady() {
|
||||
return this == APPSTATE_UNKNOWN ||
|
||||
this == APPSTATE_DETECTED;
|
||||
}
|
||||
};
|
||||
|
||||
public enum PersoSubState{
|
||||
PERSOSUBSTATE_UNKNOWN,
|
||||
PERSOSUBSTATE_IN_PROGRESS,
|
||||
PERSOSUBSTATE_READY,
|
||||
PERSOSUBSTATE_SIM_NETWORK,
|
||||
PERSOSUBSTATE_SIM_NETWORK_SUBSET,
|
||||
PERSOSUBSTATE_SIM_CORPORATE,
|
||||
PERSOSUBSTATE_SIM_SERVICE_PROVIDER,
|
||||
PERSOSUBSTATE_SIM_SIM,
|
||||
PERSOSUBSTATE_SIM_NETWORK_PUK,
|
||||
PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK,
|
||||
PERSOSUBSTATE_SIM_CORPORATE_PUK,
|
||||
PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK,
|
||||
PERSOSUBSTATE_SIM_SIM_PUK,
|
||||
PERSOSUBSTATE_RUIM_NETWORK1,
|
||||
PERSOSUBSTATE_RUIM_NETWORK2,
|
||||
PERSOSUBSTATE_RUIM_HRPD,
|
||||
PERSOSUBSTATE_RUIM_CORPORATE,
|
||||
PERSOSUBSTATE_RUIM_SERVICE_PROVIDER,
|
||||
PERSOSUBSTATE_RUIM_RUIM,
|
||||
PERSOSUBSTATE_RUIM_NETWORK1_PUK,
|
||||
PERSOSUBSTATE_RUIM_NETWORK2_PUK,
|
||||
PERSOSUBSTATE_RUIM_HRPD_PUK,
|
||||
PERSOSUBSTATE_RUIM_CORPORATE_PUK,
|
||||
PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK,
|
||||
PERSOSUBSTATE_RUIM_RUIM_PUK;
|
||||
|
||||
boolean isPersoSubStateUnknown() {
|
||||
return this == PERSOSUBSTATE_UNKNOWN;
|
||||
}
|
||||
};
|
||||
|
||||
public AppType app_type;
|
||||
public AppState app_state;
|
||||
// applicable only if app_state == RIL_APPSTATE_SUBSCRIPTION_PERSO
|
||||
public PersoSubState perso_substate;
|
||||
// null terminated string, e.g., from 0xA0, 0x00 -> 0x41, 0x30, 0x30, 0x30 */
|
||||
public String aid;
|
||||
// null terminated string
|
||||
public String app_label;
|
||||
// applicable to USIM and CSIM
|
||||
public int pin1_replaced;
|
||||
public int pin1;
|
||||
public int pin2;
|
||||
|
||||
AppType AppTypeFromRILInt(int type) {
|
||||
AppType newType;
|
||||
/* RIL_AppType ril.h */
|
||||
switch(type) {
|
||||
case 0: newType = AppType.APPTYPE_UNKNOWN; break;
|
||||
case 1: newType = AppType.APPTYPE_SIM; break;
|
||||
case 2: newType = AppType.APPTYPE_USIM; break;
|
||||
case 3: newType = AppType.APPTYPE_RUIM; break;
|
||||
case 4: newType = AppType.APPTYPE_CSIM; break;
|
||||
default:
|
||||
throw new RuntimeException(
|
||||
"Unrecognized RIL_AppType: " +type);
|
||||
}
|
||||
return newType;
|
||||
}
|
||||
|
||||
AppState AppStateFromRILInt(int state) {
|
||||
AppState newState;
|
||||
/* RIL_AppState ril.h */
|
||||
switch(state) {
|
||||
case 0: newState = AppState.APPSTATE_UNKNOWN; break;
|
||||
case 1: newState = AppState.APPSTATE_DETECTED; break;
|
||||
case 2: newState = AppState.APPSTATE_PIN; break;
|
||||
case 3: newState = AppState.APPSTATE_PUK; break;
|
||||
case 4: newState = AppState.APPSTATE_SUBSCRIPTION_PERSO; break;
|
||||
case 5: newState = AppState.APPSTATE_READY; break;
|
||||
default:
|
||||
throw new RuntimeException(
|
||||
"Unrecognized RIL_AppState: " +state);
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
||||
PersoSubState PersoSubstateFromRILInt(int substate) {
|
||||
PersoSubState newSubState;
|
||||
/* RIL_PeroSubstate ril.h */
|
||||
switch(substate) {
|
||||
case 0: newSubState = PersoSubState.PERSOSUBSTATE_UNKNOWN; break;
|
||||
case 1: newSubState = PersoSubState.PERSOSUBSTATE_IN_PROGRESS; break;
|
||||
case 2: newSubState = PersoSubState.PERSOSUBSTATE_READY; break;
|
||||
case 3: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK; break;
|
||||
case 4: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_SUBSET; break;
|
||||
case 5: newSubState = PersoSubState.PERSOSUBSTATE_SIM_CORPORATE; break;
|
||||
case 6: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SERVICE_PROVIDER; break;
|
||||
case 7: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SIM; break;
|
||||
case 8: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_PUK; break;
|
||||
case 9: newSubState = PersoSubState.PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK; break;
|
||||
case 10: newSubState = PersoSubState.PERSOSUBSTATE_SIM_CORPORATE_PUK; break;
|
||||
case 11: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK; break;
|
||||
case 12: newSubState = PersoSubState.PERSOSUBSTATE_SIM_SIM_PUK; break;
|
||||
case 13: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK1; break;
|
||||
case 14: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK2; break;
|
||||
case 15: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_HRPD; break;
|
||||
case 16: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_CORPORATE; break;
|
||||
case 17: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER; break;
|
||||
case 18: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_RUIM; break;
|
||||
case 19: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK1_PUK; break;
|
||||
case 20: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_NETWORK2_PUK; break;
|
||||
case 21: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_HRPD_PUK ; break;
|
||||
case 22: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_CORPORATE_PUK; break;
|
||||
case 23: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK; break;
|
||||
case 24: newSubState = PersoSubState.PERSOSUBSTATE_RUIM_RUIM_PUK; break;
|
||||
default:
|
||||
throw new RuntimeException(
|
||||
"Unrecognized RIL_PersoSubstate: " +substate);
|
||||
}
|
||||
return newSubState;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* See also RIL_CardStatus in include/telephony/ril.h
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class IccCardStatus {
|
||||
static final int CARD_MAX_APPS = 8;
|
||||
|
||||
public enum CardState {
|
||||
CARDSTATE_ABSENT,
|
||||
CARDSTATE_PRESENT,
|
||||
CARDSTATE_ERROR;
|
||||
|
||||
boolean isCardPresent() {
|
||||
return this == CARDSTATE_PRESENT;
|
||||
}
|
||||
};
|
||||
|
||||
public enum PinState {
|
||||
PINSTATE_UNKNOWN,
|
||||
PINSTATE_ENABLED_NOT_VERIFIED,
|
||||
PINSTATE_ENABLED_VERIFIED,
|
||||
PINSTATE_DISABLED,
|
||||
PINSTATE_ENABLED_BLOCKED,
|
||||
PINSTATE_ENABLED_PERM_BLOCKED
|
||||
};
|
||||
|
||||
public CardState card_state;
|
||||
public PinState universal_pin_state;
|
||||
public int gsm_umts_subscription_app_index;
|
||||
public int cdma_subscription_app_index;
|
||||
public int num_applications;
|
||||
|
||||
ArrayList<IccCardApplication> application = new ArrayList<IccCardApplication>(CARD_MAX_APPS);
|
||||
|
||||
CardState CardStateFromRILInt(int state) {
|
||||
CardState newState;
|
||||
/* RIL_CardState ril.h */
|
||||
switch(state) {
|
||||
case 0: newState = CardState.CARDSTATE_ABSENT; break;
|
||||
case 1: newState = CardState.CARDSTATE_PRESENT; break;
|
||||
case 2: newState = CardState.CARDSTATE_ERROR; break;
|
||||
default:
|
||||
throw new RuntimeException(
|
||||
"Unrecognized RIL_CardState: " +state);
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
||||
PinState PinStateFromRILInt(int state) {
|
||||
PinState newState;
|
||||
/* RIL_PinState ril.h */
|
||||
switch(state) {
|
||||
case 0: newState = PinState.PINSTATE_UNKNOWN; break;
|
||||
case 1: newState = PinState.PINSTATE_ENABLED_NOT_VERIFIED; break;
|
||||
case 2: newState = PinState.PINSTATE_ENABLED_VERIFIED; break;
|
||||
case 3: newState = PinState.PINSTATE_DISABLED; break;
|
||||
case 4: newState = PinState.PINSTATE_ENABLED_BLOCKED; break;
|
||||
case 5: newState = PinState.PINSTATE_ENABLED_PERM_BLOCKED; break;
|
||||
default:
|
||||
throw new RuntimeException(
|
||||
"Unrecognized RIL_PinState: " +state);
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
}
|
||||
@@ -14,13 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public interface SimConstants {
|
||||
// SIM file ids from TS 51.011
|
||||
public interface IccConstants {
|
||||
// GSM SIM file ids from TS 51.011
|
||||
public static final int EF_ADN = 0x6F3A;
|
||||
public static final int EF_FDN = 0x6F3B;
|
||||
public static final int EF_SDN = 0x6F49;
|
||||
@@ -42,7 +42,7 @@ public interface SimConstants {
|
||||
public static final int EF_CFIS = 0x6FCB;
|
||||
public static final int EF_IMG = 0x4f20;
|
||||
|
||||
// SIM file ids from CPHS (phase 2, version 4.2) CPHS4_2.WW6
|
||||
// GSM SIM file ids from CPHS (phase 2, version 4.2) CPHS4_2.WW6
|
||||
public static final int EF_MAILBOX_CPHS = 0x6F17;
|
||||
public static final int EF_VOICE_MAIL_INDICATOR_CPHS = 0x6F11;
|
||||
public static final int EF_CFF_CPHS = 0x6F13;
|
||||
@@ -50,6 +50,10 @@ public interface SimConstants {
|
||||
public static final int EF_SPN_SHORT_CPHS = 0x6f18;
|
||||
public static final int EF_INFO_CPHS = 0x6f16;
|
||||
|
||||
// CDMA RUIM file ids from 3GPP2 C.S0023-0
|
||||
public static final int EF_CST = 0x6f32;
|
||||
public static final int EF_RUIM_SPN =0x6F41;
|
||||
|
||||
// SMS record length from TS 51.011 10.5.3
|
||||
static public final int SMS_RECORD_LENGTH = 176;
|
||||
}
|
||||
@@ -14,20 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class SimFileTypeMismatch extends SimException
|
||||
{
|
||||
SimFileTypeMismatch()
|
||||
{
|
||||
public class IccException extends Exception {
|
||||
public IccException() {
|
||||
|
||||
}
|
||||
|
||||
SimFileTypeMismatch(String s)
|
||||
{
|
||||
public IccException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.os.*;
|
||||
import android.util.Log;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public abstract class IccFileHandler extends Handler {
|
||||
|
||||
//from TS 11.11 9.1 or elsewhere
|
||||
static protected final int COMMAND_READ_BINARY = 0xb0;
|
||||
static protected final int COMMAND_UPDATE_BINARY = 0xd6;
|
||||
static protected final int COMMAND_READ_RECORD = 0xb2;
|
||||
static protected final int COMMAND_UPDATE_RECORD = 0xdc;
|
||||
static protected final int COMMAND_SEEK = 0xa2;
|
||||
static protected final int COMMAND_GET_RESPONSE = 0xc0;
|
||||
|
||||
// from TS 11.11 9.2.5
|
||||
static protected final int READ_RECORD_MODE_ABSOLUTE = 4;
|
||||
|
||||
//***** types of files TS 11.11 9.3
|
||||
static protected final int EF_TYPE_TRANSPARENT = 0;
|
||||
static protected final int EF_TYPE_LINEAR_FIXED = 1;
|
||||
static protected final int EF_TYPE_CYCLIC = 3;
|
||||
|
||||
//***** types of files TS 11.11 9.3
|
||||
static protected final int TYPE_RFU = 0;
|
||||
static protected final int TYPE_MF = 1;
|
||||
static protected final int TYPE_DF = 2;
|
||||
static protected final int TYPE_EF = 4;
|
||||
|
||||
// size of GET_RESPONSE for EF's
|
||||
static protected final int GET_RESPONSE_EF_SIZE_BYTES = 15;
|
||||
static protected final int GET_RESPONSE_EF_IMG_SIZE_BYTES = 10;
|
||||
|
||||
// Byte order received in response to COMMAND_GET_RESPONSE
|
||||
// Refer TS 51.011 Section 9.2.1
|
||||
static protected final int RESPONSE_DATA_RFU_1 = 0;
|
||||
static protected final int RESPONSE_DATA_RFU_2 = 1;
|
||||
|
||||
static protected final int RESPONSE_DATA_FILE_SIZE_1 = 2;
|
||||
static protected final int RESPONSE_DATA_FILE_SIZE_2 = 3;
|
||||
|
||||
static protected final int RESPONSE_DATA_FILE_ID_1 = 4;
|
||||
static protected final int RESPONSE_DATA_FILE_ID_2 = 5;
|
||||
static protected final int RESPONSE_DATA_FILE_TYPE = 6;
|
||||
static protected final int RESPONSE_DATA_RFU_3 = 7;
|
||||
static protected final int RESPONSE_DATA_ACCESS_CONDITION_1 = 8;
|
||||
static protected final int RESPONSE_DATA_ACCESS_CONDITION_2 = 9;
|
||||
static protected final int RESPONSE_DATA_ACCESS_CONDITION_3 = 10;
|
||||
static protected final int RESPONSE_DATA_FILE_STATUS = 11;
|
||||
static protected final int RESPONSE_DATA_LENGTH = 12;
|
||||
static protected final int RESPONSE_DATA_STRUCTURE = 13;
|
||||
static protected final int RESPONSE_DATA_RECORD_LENGTH = 14;
|
||||
|
||||
|
||||
//***** Events
|
||||
|
||||
/** Finished retrieving size of transparent EF; start loading. */
|
||||
static protected final int EVENT_GET_BINARY_SIZE_DONE = 4;
|
||||
/** Finished loading contents of transparent EF; post result. */
|
||||
static protected final int EVENT_READ_BINARY_DONE = 5;
|
||||
/** Finished retrieving size of records for linear-fixed EF; now load. */
|
||||
static protected final int EVENT_GET_RECORD_SIZE_DONE = 6;
|
||||
/** Finished loading single record from a linear-fixed EF; post result. */
|
||||
static protected final int EVENT_READ_RECORD_DONE = 7;
|
||||
/** Finished retrieving record size; post result. */
|
||||
static protected final int EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE = 8;
|
||||
/** Finished retrieving image instance record; post result. */
|
||||
static protected final int EVENT_READ_IMG_DONE = 9;
|
||||
/** Finished retrieving icon data; post result. */
|
||||
static protected final int EVENT_READ_ICON_DONE = 10;
|
||||
|
||||
// member variables
|
||||
protected PhoneBase phone;
|
||||
|
||||
static class LoadLinearFixedContext {
|
||||
|
||||
int efid;
|
||||
int recordNum, recordSize, countRecords;
|
||||
boolean loadAll;
|
||||
|
||||
Message onLoaded;
|
||||
|
||||
ArrayList<byte[]> results;
|
||||
|
||||
LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) {
|
||||
this.efid = efid;
|
||||
this.recordNum = recordNum;
|
||||
this.onLoaded = onLoaded;
|
||||
this.loadAll = false;
|
||||
}
|
||||
|
||||
LoadLinearFixedContext(int efid, Message onLoaded) {
|
||||
this.efid = efid;
|
||||
this.recordNum = 1;
|
||||
this.loadAll = true;
|
||||
this.onLoaded = onLoaded;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
protected IccFileHandler(PhoneBase phone) {
|
||||
super();
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
//***** Public Methods
|
||||
|
||||
/**
|
||||
* Load a record from a SIM Linear Fixed EF
|
||||
*
|
||||
* @param fileid EF id
|
||||
* @param recordNum 1-based (not 0-based) record number
|
||||
* @param onLoaded
|
||||
*
|
||||
* ((AsyncResult)(onLoaded.obj)).result is the byte[]
|
||||
*
|
||||
*/
|
||||
public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) {
|
||||
Message response
|
||||
= obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
|
||||
new LoadLinearFixedContext(fileid, recordNum, onLoaded));
|
||||
|
||||
phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null,
|
||||
0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a image instance record from a SIM Linear Fixed EF-IMG
|
||||
*
|
||||
* @param recordNum 1-based (not 0-based) record number
|
||||
* @param onLoaded
|
||||
*
|
||||
* ((AsyncResult)(onLoaded.obj)).result is the byte[]
|
||||
*
|
||||
*/
|
||||
public void loadEFImgLinearFixed(int recordNum, Message onLoaded) {
|
||||
Message response = obtainMessage(EVENT_READ_IMG_DONE,
|
||||
new LoadLinearFixedContext(IccConstants.EF_IMG, recordNum,
|
||||
onLoaded));
|
||||
|
||||
phone.mCM.iccIO(COMMAND_GET_RESPONSE, IccConstants.EF_IMG, "img",
|
||||
recordNum, READ_RECORD_MODE_ABSOLUTE,
|
||||
GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* get record size for a linear fixed EF
|
||||
*
|
||||
* @param fileid EF id
|
||||
* @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[]
|
||||
* int[0] is the record length int[1] is the total length of the EF
|
||||
* file int[3] is the number of records in the EF file So int[0] *
|
||||
* int[3] = int[1]
|
||||
*/
|
||||
public void getEFLinearRecordSize(int fileid, Message onLoaded) {
|
||||
Message response
|
||||
= obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE,
|
||||
new LoadLinearFixedContext(fileid, onLoaded));
|
||||
phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null,
|
||||
0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all records from a SIM Linear Fixed EF
|
||||
*
|
||||
* @param fileid EF id
|
||||
* @param onLoaded
|
||||
*
|
||||
* ((AsyncResult)(onLoaded.obj)).result is an ArrayList<byte[]>
|
||||
*
|
||||
*/
|
||||
public void loadEFLinearFixedAll(int fileid, Message onLoaded) {
|
||||
Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
|
||||
new LoadLinearFixedContext(fileid,onLoaded));
|
||||
|
||||
phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null,
|
||||
0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a SIM Transparent EF
|
||||
*
|
||||
* @param fileid EF id
|
||||
* @param onLoaded
|
||||
*
|
||||
* ((AsyncResult)(onLoaded.obj)).result is the byte[]
|
||||
*
|
||||
*/
|
||||
|
||||
public void loadEFTransparent(int fileid, Message onLoaded) {
|
||||
Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,
|
||||
fileid, 0, onLoaded);
|
||||
|
||||
phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, null,
|
||||
0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to
|
||||
* retrive STK's icon data.
|
||||
*
|
||||
* @param fileid EF id
|
||||
* @param onLoaded
|
||||
*
|
||||
* ((AsyncResult)(onLoaded.obj)).result is the byte[]
|
||||
*
|
||||
*/
|
||||
public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset,
|
||||
int length, Message onLoaded) {
|
||||
Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
|
||||
onLoaded);
|
||||
|
||||
phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset,
|
||||
length, null, null, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a record in a linear fixed EF
|
||||
* @param fileid EF id
|
||||
* @param recordNum 1-based (not 0-based) record number
|
||||
* @param data must be exactly as long as the record in the EF
|
||||
* @param pin2 for CHV2 operations, otherwist must be null
|
||||
* @param onComplete onComplete.obj will be an AsyncResult
|
||||
* onComplete.obj.userObj will be a IccIoResult on success
|
||||
*/
|
||||
public void updateEFLinearFixed(int fileid, int recordNum, byte[] data,
|
||||
String pin2, Message onComplete) {
|
||||
phone.mCM.iccIO(COMMAND_UPDATE_RECORD, fileid, null,
|
||||
recordNum, READ_RECORD_MODE_ABSOLUTE, data.length,
|
||||
IccUtils.bytesToHexString(data), pin2, onComplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a transparent EF
|
||||
* @param fileid EF id
|
||||
* @param data must be exactly as long as the EF
|
||||
*/
|
||||
public void updateEFTransparent(int fileid, byte[] data, Message onComplete) {
|
||||
phone.mCM.iccIO(COMMAND_UPDATE_BINARY, fileid, null,
|
||||
0, 0, data.length,
|
||||
IccUtils.bytesToHexString(data), null, onComplete);
|
||||
}
|
||||
|
||||
|
||||
//***** Abstract Methods
|
||||
|
||||
|
||||
//***** Private Methods
|
||||
|
||||
private void sendResult(Message response, Object result, Throwable ex) {
|
||||
if (response == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncResult.forMessage(response, result, ex);
|
||||
|
||||
response.sendToTarget();
|
||||
}
|
||||
|
||||
//***** Overridden from Handler
|
||||
|
||||
public void handleMessage(Message msg) {
|
||||
AsyncResult ar;
|
||||
IccIoResult result;
|
||||
Message response = null;
|
||||
String str;
|
||||
LoadLinearFixedContext lc;
|
||||
|
||||
IccException iccException;
|
||||
byte data[];
|
||||
int size;
|
||||
int fileid;
|
||||
int recordNum;
|
||||
int recordSize[];
|
||||
|
||||
try {
|
||||
switch (msg.what) {
|
||||
case EVENT_READ_IMG_DONE:
|
||||
ar = (AsyncResult) msg.obj;
|
||||
lc = (LoadLinearFixedContext) ar.userObj;
|
||||
result = (IccIoResult) ar.result;
|
||||
response = lc.onLoaded;
|
||||
|
||||
iccException = result.getException();
|
||||
if (iccException != null) {
|
||||
sendResult(response, result.payload, ar.exception);
|
||||
}
|
||||
break;
|
||||
case EVENT_READ_ICON_DONE:
|
||||
ar = (AsyncResult) msg.obj;
|
||||
response = (Message) ar.userObj;
|
||||
result = (IccIoResult) ar.result;
|
||||
|
||||
iccException = result.getException();
|
||||
if (iccException != null) {
|
||||
sendResult(response, result.payload, ar.exception);
|
||||
}
|
||||
break;
|
||||
case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
lc = (LoadLinearFixedContext) ar.userObj;
|
||||
result = (IccIoResult) ar.result;
|
||||
response = lc.onLoaded;
|
||||
|
||||
if (ar.exception != null) {
|
||||
sendResult(response, null, ar.exception);
|
||||
break;
|
||||
}
|
||||
|
||||
iccException = result.getException();
|
||||
if (iccException != null) {
|
||||
sendResult(response, null, iccException);
|
||||
break;
|
||||
}
|
||||
|
||||
data = result.payload;
|
||||
|
||||
if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] ||
|
||||
EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
|
||||
throw new IccFileTypeMismatch();
|
||||
}
|
||||
|
||||
recordSize = new int[3];
|
||||
recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
|
||||
recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
|
||||
+ (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
|
||||
recordSize[2] = recordSize[1] / recordSize[0];
|
||||
|
||||
sendResult(response, recordSize, null);
|
||||
break;
|
||||
case EVENT_GET_RECORD_SIZE_DONE:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
lc = (LoadLinearFixedContext) ar.userObj;
|
||||
result = (IccIoResult) ar.result;
|
||||
response = lc.onLoaded;
|
||||
|
||||
if (ar.exception != null) {
|
||||
sendResult(response, null, ar.exception);
|
||||
break;
|
||||
}
|
||||
|
||||
iccException = result.getException();
|
||||
|
||||
if (iccException != null) {
|
||||
sendResult(response, null, iccException);
|
||||
break;
|
||||
}
|
||||
|
||||
data = result.payload;
|
||||
fileid = lc.efid;
|
||||
recordNum = lc.recordNum;
|
||||
|
||||
if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
|
||||
throw new IccFileTypeMismatch();
|
||||
}
|
||||
|
||||
if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
|
||||
throw new IccFileTypeMismatch();
|
||||
}
|
||||
|
||||
lc.recordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
|
||||
|
||||
size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
|
||||
+ (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
|
||||
|
||||
lc.countRecords = size / lc.recordSize;
|
||||
|
||||
if (lc.loadAll) {
|
||||
lc.results = new ArrayList<byte[]>(lc.countRecords);
|
||||
}
|
||||
|
||||
phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null,
|
||||
lc.recordNum,
|
||||
READ_RECORD_MODE_ABSOLUTE,
|
||||
lc.recordSize, null, null,
|
||||
obtainMessage(EVENT_READ_RECORD_DONE, lc));
|
||||
break;
|
||||
case EVENT_GET_BINARY_SIZE_DONE:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
response = (Message) ar.userObj;
|
||||
result = (IccIoResult) ar.result;
|
||||
|
||||
if (ar.exception != null) {
|
||||
sendResult(response, null, ar.exception);
|
||||
break;
|
||||
}
|
||||
|
||||
iccException = result.getException();
|
||||
|
||||
if (iccException != null) {
|
||||
sendResult(response, null, iccException);
|
||||
break;
|
||||
}
|
||||
|
||||
data = result.payload;
|
||||
|
||||
fileid = msg.arg1;
|
||||
|
||||
if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
|
||||
throw new IccFileTypeMismatch();
|
||||
}
|
||||
|
||||
if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
|
||||
throw new IccFileTypeMismatch();
|
||||
}
|
||||
|
||||
size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
|
||||
+ (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
|
||||
|
||||
phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, null,
|
||||
0, 0, size, null, null,
|
||||
obtainMessage(EVENT_READ_BINARY_DONE,
|
||||
fileid, 0, response));
|
||||
break;
|
||||
|
||||
case EVENT_READ_RECORD_DONE:
|
||||
|
||||
ar = (AsyncResult)msg.obj;
|
||||
lc = (LoadLinearFixedContext) ar.userObj;
|
||||
result = (IccIoResult) ar.result;
|
||||
response = lc.onLoaded;
|
||||
|
||||
if (ar.exception != null) {
|
||||
sendResult(response, null, ar.exception);
|
||||
break;
|
||||
}
|
||||
|
||||
iccException = result.getException();
|
||||
|
||||
if (iccException != null) {
|
||||
sendResult(response, null, iccException);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!lc.loadAll) {
|
||||
sendResult(response, result.payload, null);
|
||||
} else {
|
||||
lc.results.add(result.payload);
|
||||
|
||||
lc.recordNum++;
|
||||
|
||||
if (lc.recordNum > lc.countRecords) {
|
||||
sendResult(response, lc.results, null);
|
||||
} else {
|
||||
phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null,
|
||||
lc.recordNum,
|
||||
READ_RECORD_MODE_ABSOLUTE,
|
||||
lc.recordSize, null, null,
|
||||
obtainMessage(EVENT_READ_RECORD_DONE, lc));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case EVENT_READ_BINARY_DONE:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
response = (Message) ar.userObj;
|
||||
result = (IccIoResult) ar.result;
|
||||
|
||||
if (ar.exception != null) {
|
||||
sendResult(response, null, ar.exception);
|
||||
break;
|
||||
}
|
||||
|
||||
iccException = result.getException();
|
||||
|
||||
if (iccException != null) {
|
||||
sendResult(response, null, iccException);
|
||||
break;
|
||||
}
|
||||
|
||||
sendResult(response, result.payload, null);
|
||||
break;
|
||||
|
||||
}} catch (Exception exc) {
|
||||
if (response != null) {
|
||||
sendResult(response, null, exc);
|
||||
} else {
|
||||
loge("uncaught exception" + exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void logd(String s);
|
||||
|
||||
protected abstract void loge(String s);
|
||||
|
||||
}
|
||||
@@ -14,25 +14,21 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class SimFileNotFound extends SimException
|
||||
{
|
||||
SimFileNotFound()
|
||||
{
|
||||
public class IccFileNotFound extends IccException {
|
||||
IccFileNotFound() {
|
||||
|
||||
}
|
||||
|
||||
SimFileNotFound(String s)
|
||||
{
|
||||
IccFileNotFound(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
SimFileNotFound(int ef)
|
||||
{
|
||||
super("SIM EF Not Found 0x" + Integer.toHexString(ef));
|
||||
IccFileNotFound(int ef) {
|
||||
super("ICC EF Not Found 0x" + Integer.toHexString(ef));
|
||||
}
|
||||
}
|
||||
@@ -14,45 +14,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class SimException extends Exception
|
||||
{
|
||||
SimException()
|
||||
{
|
||||
public class IccFileTypeMismatch extends IccException {
|
||||
public IccFileTypeMismatch() {
|
||||
|
||||
}
|
||||
|
||||
SimException(String s)
|
||||
{
|
||||
public IccFileTypeMismatch(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
|
||||
final class SimVmFixedException extends SimException {
|
||||
SimVmFixedException()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SimVmFixedException(String s)
|
||||
{
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
|
||||
final class SimVmNotSupportedException extends SimException {
|
||||
SimVmNotSupportedException()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
SimVmNotSupportedException(String s)
|
||||
{
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,33 +14,30 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class
|
||||
SimIoResult
|
||||
{
|
||||
IccIoResult {
|
||||
int sw1;
|
||||
int sw2;
|
||||
byte[] payload;
|
||||
|
||||
public SimIoResult(int sw1, int sw2, byte[] payload)
|
||||
{
|
||||
public byte[] payload;
|
||||
|
||||
public IccIoResult(int sw1, int sw2, byte[] payload) {
|
||||
this.sw1 = sw1;
|
||||
this.sw2 = sw2;
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public SimIoResult(int sw1, int sw2, String hexString)
|
||||
{
|
||||
this(sw1, sw2, SimUtils.hexStringToBytes(hexString));
|
||||
public IccIoResult(int sw1, int sw2, String hexString) {
|
||||
this(sw1, sw2, IccUtils.hexStringToBytes(hexString));
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "SimIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x"
|
||||
public String toString() {
|
||||
return "IccIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x"
|
||||
+ Integer.toHexString(sw2);
|
||||
}
|
||||
|
||||
@@ -49,27 +46,25 @@ SimIoResult
|
||||
* See GSM 11.11 Section 9.4
|
||||
* (the fun stuff is absent in 51.011)
|
||||
*/
|
||||
public boolean success()
|
||||
{
|
||||
public boolean success() {
|
||||
return sw1 == 0x90 || sw1 == 0x91 || sw1 == 0x9e || sw1 == 0x9f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns exception on error or null if success
|
||||
*/
|
||||
public SimException getException()
|
||||
{
|
||||
public IccException getException() {
|
||||
if (success()) return null;
|
||||
|
||||
|
||||
switch (sw1) {
|
||||
case 0x94:
|
||||
if (sw2 == 0x08) {
|
||||
return new SimFileTypeMismatch();
|
||||
return new IccFileTypeMismatch();
|
||||
} else {
|
||||
return new SimFileNotFound();
|
||||
return new IccFileNotFound();
|
||||
}
|
||||
default:
|
||||
return new SimException("sw1:" + sw1 + " sw2:" + sw2);
|
||||
return new IccException("sw1:" + sw1 + " sw2:" + sw2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.ServiceManager;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* SimPhoneBookInterfaceManager to provide an inter-process communication to
|
||||
* access ADN-like SIM records.
|
||||
*/
|
||||
public abstract class IccPhoneBookInterfaceManager extends IIccPhoneBook.Stub {
|
||||
protected static final boolean DBG = true;
|
||||
|
||||
protected PhoneBase phone;
|
||||
protected AdnRecordCache adnCache;
|
||||
protected Object mLock = new Object();
|
||||
protected int recordSize[];
|
||||
protected boolean success;
|
||||
protected List<AdnRecord> records;
|
||||
|
||||
protected static final boolean ALLOW_SIM_OP_IN_UI_THREAD = false;
|
||||
|
||||
protected static final int EVENT_GET_SIZE_DONE = 1;
|
||||
protected static final int EVENT_LOAD_DONE = 2;
|
||||
protected static final int EVENT_UPDATE_DONE = 3;
|
||||
|
||||
protected Handler mBaseHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
AsyncResult ar;
|
||||
|
||||
switch (msg.what) {
|
||||
case EVENT_GET_SIZE_DONE:
|
||||
ar = (AsyncResult) msg.obj;
|
||||
synchronized (mLock) {
|
||||
if (ar.exception == null) {
|
||||
recordSize = (int[])ar.result;
|
||||
// recordSize[0] is the record length
|
||||
// recordSize[1] is the total length of the EF file
|
||||
// recordSize[2] is the number of records in the EF file
|
||||
logd("GET_RECORD_SIZE Size " + recordSize[0] +
|
||||
" total " + recordSize[1] +
|
||||
" #record " + recordSize[2]);
|
||||
mLock.notifyAll();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EVENT_UPDATE_DONE:
|
||||
ar = (AsyncResult) msg.obj;
|
||||
synchronized (mLock) {
|
||||
success = (ar.exception == null);
|
||||
mLock.notifyAll();
|
||||
}
|
||||
break;
|
||||
case EVENT_LOAD_DONE:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
synchronized (mLock) {
|
||||
if (ar.exception == null) {
|
||||
records = (List<AdnRecord>)
|
||||
((ArrayList<AdnRecord>) ar.result);
|
||||
} else {
|
||||
if(DBG) logd("Cannot load ADN records");
|
||||
if (records != null) {
|
||||
records.clear();
|
||||
}
|
||||
}
|
||||
mLock.notifyAll();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public IccPhoneBookInterfaceManager(PhoneBase phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
protected void publish() {
|
||||
//NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
|
||||
ServiceManager.addService("simphonebook", this);
|
||||
}
|
||||
|
||||
protected abstract void logd(String msg);
|
||||
|
||||
protected abstract void loge(String msg);
|
||||
|
||||
/**
|
||||
* Replace oldAdn with newAdn in ADN-like record in EF
|
||||
*
|
||||
* getAdnRecordsInEf must be called at least once before this function,
|
||||
* otherwise an error will be returned
|
||||
* throws SecurityException if no WRITE_CONTACTS permission
|
||||
*
|
||||
* @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
|
||||
* @param oldTag adn tag to be replaced
|
||||
* @param oldPhoneNumber adn number to be replaced
|
||||
* Set both oldTag and oldPhoneNubmer to "" means to replace an
|
||||
* empty record, aka, insert new record
|
||||
* @param newTag adn tag to be stored
|
||||
* @param newPhoneNumber adn number ot be stored
|
||||
* Set both newTag and newPhoneNubmer to "" means to replace the old
|
||||
* record with empty one, aka, delete old record
|
||||
* @param pin2 required to update EF_FDN, otherwise must be null
|
||||
* @return true for success
|
||||
*/
|
||||
public boolean
|
||||
updateAdnRecordsInEfBySearch (int efid,
|
||||
String oldTag, String oldPhoneNumber,
|
||||
String newTag, String newPhoneNumber, String pin2) {
|
||||
|
||||
|
||||
if (phone.getContext().checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.WRITE_CONTACTS)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException(
|
||||
"Requires android.permission.WRITE_CONTACTS permission");
|
||||
}
|
||||
|
||||
|
||||
if (DBG) logd("updateAdnRecordsInEfBySearch: efid=" + efid +
|
||||
" ("+ oldTag + "," + oldPhoneNumber + ")"+ "==>" +
|
||||
" ("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2);
|
||||
synchronized(mLock) {
|
||||
checkThread();
|
||||
success = false;
|
||||
Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE);
|
||||
AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber);
|
||||
AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber);
|
||||
adnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response);
|
||||
try {
|
||||
mLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
logd("interrupted while trying to update by search");
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an ADN-like EF record by record index
|
||||
*
|
||||
* This is useful for iteration the whole ADN file, such as write the whole
|
||||
* phone book or erase/format the whole phonebook
|
||||
* throws SecurityException if no WRITE_CONTACTS permission
|
||||
*
|
||||
* @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
|
||||
* @param newTag adn tag to be stored
|
||||
* @param newPhoneNumber adn number to be stored
|
||||
* Set both newTag and newPhoneNubmer to "" means to replace the old
|
||||
* record with empty one, aka, delete old record
|
||||
* @param index is 1-based adn record index to be updated
|
||||
* @param pin2 required to update EF_FDN, otherwise must be null
|
||||
* @return true for success
|
||||
*/
|
||||
public boolean
|
||||
updateAdnRecordsInEfByIndex(int efid, String newTag,
|
||||
String newPhoneNumber, int index, String pin2) {
|
||||
|
||||
if (phone.getContext().checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.WRITE_CONTACTS)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException(
|
||||
"Requires android.permission.WRITE_CONTACTS permission");
|
||||
}
|
||||
|
||||
if (DBG) logd("updateAdnRecordsInEfByIndex: efid=" + efid +
|
||||
" Index=" + index + " ==> " +
|
||||
"("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2);
|
||||
synchronized(mLock) {
|
||||
checkThread();
|
||||
success = false;
|
||||
Message response = mBaseHandler.obtainMessage(EVENT_UPDATE_DONE);
|
||||
AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber);
|
||||
adnCache.updateAdnByIndex(efid, newAdn, index, pin2, response);
|
||||
try {
|
||||
mLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
logd("interrupted while trying to update by index");
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the capacity of records in efid
|
||||
*
|
||||
* @param efid the EF id of a ADN-like ICC
|
||||
* @return int[3] array
|
||||
* recordSizes[0] is the single record length
|
||||
* recordSizes[1] is the total length of the EF file
|
||||
* recordSizes[2] is the number of records in the EF file
|
||||
*/
|
||||
public abstract int[] getAdnRecordsSize(int efid);
|
||||
|
||||
/**
|
||||
* Loads the AdnRecords in efid and returns them as a
|
||||
* List of AdnRecords
|
||||
*
|
||||
* throws SecurityException if no READ_CONTACTS permission
|
||||
*
|
||||
* @param efid the EF id of a ADN-like ICC
|
||||
* @return List of AdnRecord
|
||||
*/
|
||||
public List<AdnRecord> getAdnRecordsInEf(int efid) {
|
||||
|
||||
if (phone.getContext().checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.READ_CONTACTS)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
throw new SecurityException(
|
||||
"Requires android.permission.READ_CONTACTS permission");
|
||||
}
|
||||
|
||||
if (DBG) logd("getAdnRecordsInEF: efid=" + efid);
|
||||
|
||||
synchronized(mLock) {
|
||||
checkThread();
|
||||
Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE);
|
||||
adnCache.requestLoadAllAdnLike(efid, response);
|
||||
try {
|
||||
mLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
logd("interrupted while trying to load from the SIM");
|
||||
}
|
||||
}
|
||||
return records;
|
||||
}
|
||||
|
||||
protected void checkThread() {
|
||||
if (!ALLOW_SIM_OP_IN_UI_THREAD) {
|
||||
// Make sure this isn't the UI thread, since it will block
|
||||
if (mBaseHandler.getLooper().equals(Looper.myLooper())) {
|
||||
loge("query() called on the main UI thread!");
|
||||
throw new IllegalStateException(
|
||||
"You cannot call query on this provder from the main UI thread.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.ServiceManager;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* SimPhoneBookInterfaceManager to provide an inter-process communication to
|
||||
* access ADN-like SIM records.
|
||||
*/
|
||||
public class IccPhoneBookInterfaceManagerProxy extends IIccPhoneBook.Stub {
|
||||
private IccPhoneBookInterfaceManager mIccPhoneBookInterfaceManager;
|
||||
|
||||
public IccPhoneBookInterfaceManagerProxy(IccPhoneBookInterfaceManager
|
||||
iccPhoneBookInterfaceManager) {
|
||||
mIccPhoneBookInterfaceManager = iccPhoneBookInterfaceManager;
|
||||
if(ServiceManager.getService("simphonebook") == null) {
|
||||
ServiceManager.addService("simphonebook", this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setmIccPhoneBookInterfaceManager(
|
||||
IccPhoneBookInterfaceManager iccPhoneBookInterfaceManager) {
|
||||
this.mIccPhoneBookInterfaceManager = iccPhoneBookInterfaceManager;
|
||||
}
|
||||
|
||||
public boolean
|
||||
updateAdnRecordsInEfBySearch (int efid,
|
||||
String oldTag, String oldPhoneNumber,
|
||||
String newTag, String newPhoneNumber,
|
||||
String pin2) throws android.os.RemoteException {
|
||||
return mIccPhoneBookInterfaceManager.updateAdnRecordsInEfBySearch(
|
||||
efid, oldTag, oldPhoneNumber, newTag, newPhoneNumber, pin2);
|
||||
}
|
||||
|
||||
public boolean
|
||||
updateAdnRecordsInEfByIndex(int efid, String newTag,
|
||||
String newPhoneNumber, int index, String pin2) throws android.os.RemoteException {
|
||||
return mIccPhoneBookInterfaceManager.updateAdnRecordsInEfByIndex(efid,
|
||||
newTag, newPhoneNumber, index, pin2);
|
||||
}
|
||||
|
||||
public int[] getAdnRecordsSize(int efid) throws android.os.RemoteException {
|
||||
return mIccPhoneBookInterfaceManager.getAdnRecordsSize(efid);
|
||||
}
|
||||
|
||||
public List<AdnRecord> getAdnRecordsInEf(int efid) throws android.os.RemoteException {
|
||||
return mIccPhoneBookInterfaceManager.getAdnRecordsInEf(efid);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.UriMatcher;
|
||||
@@ -31,11 +31,16 @@ import android.util.Log;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.android.internal.telephony.IccConstants;
|
||||
import com.android.internal.telephony.AdnRecord;
|
||||
import com.android.internal.telephony.IIccPhoneBook;
|
||||
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class SimProvider extends ContentProvider {
|
||||
private static final String TAG = "SimProvider";
|
||||
public class IccProvider extends ContentProvider {
|
||||
private static final String TAG = "IccProvider";
|
||||
private static final boolean DBG = false;
|
||||
|
||||
|
||||
@@ -56,9 +61,9 @@ public class SimProvider extends ContentProvider {
|
||||
new UriMatcher(UriMatcher.NO_MATCH);
|
||||
|
||||
static {
|
||||
URL_MATCHER.addURI("sim", "adn", ADN);
|
||||
URL_MATCHER.addURI("sim", "fdn", FDN);
|
||||
URL_MATCHER.addURI("sim", "sdn", SDN);
|
||||
URL_MATCHER.addURI("icc", "adn", ADN);
|
||||
URL_MATCHER.addURI("icc", "fdn", FDN);
|
||||
URL_MATCHER.addURI("icc", "sdn", SDN);
|
||||
}
|
||||
|
||||
|
||||
@@ -81,21 +86,21 @@ public class SimProvider extends ContentProvider {
|
||||
public Cursor query(Uri url, String[] projection, String selection,
|
||||
String[] selectionArgs, String sort) {
|
||||
ArrayList<ArrayList> results;
|
||||
|
||||
|
||||
if (!mSimulator) {
|
||||
switch (URL_MATCHER.match(url)) {
|
||||
case ADN:
|
||||
results = loadFromEf(SimConstants.EF_ADN);
|
||||
results = loadFromEf(IccConstants.EF_ADN);
|
||||
break;
|
||||
|
||||
|
||||
case FDN:
|
||||
results = loadFromEf(SimConstants.EF_FDN);
|
||||
results = loadFromEf(IccConstants.EF_FDN);
|
||||
break;
|
||||
|
||||
|
||||
case SDN:
|
||||
results = loadFromEf(SimConstants.EF_SDN);
|
||||
results = loadFromEf(IccConstants.EF_SDN);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown URL " + url);
|
||||
}
|
||||
@@ -152,11 +157,11 @@ public class SimProvider extends ContentProvider {
|
||||
int match = URL_MATCHER.match(url);
|
||||
switch (match) {
|
||||
case ADN:
|
||||
efType = SimConstants.EF_ADN;
|
||||
efType = IccConstants.EF_ADN;
|
||||
break;
|
||||
|
||||
case FDN:
|
||||
efType = SimConstants.EF_FDN;
|
||||
efType = IccConstants.EF_FDN;
|
||||
pin2 = initialValues.getAsString("pin2");
|
||||
break;
|
||||
|
||||
@@ -167,7 +172,7 @@ public class SimProvider extends ContentProvider {
|
||||
|
||||
String tag = initialValues.getAsString("tag");
|
||||
String number = initialValues.getAsString("number");
|
||||
boolean success = addSimRecordToEf(efType, tag, number, pin2);
|
||||
boolean success = addIccRecordToEf(efType, tag, number, pin2);
|
||||
|
||||
if (!success) {
|
||||
return null;
|
||||
@@ -183,7 +188,7 @@ public class SimProvider extends ContentProvider {
|
||||
buf.append("fdn/");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// TODO: we need to find out the rowId for the newly added record
|
||||
buf.append(0);
|
||||
|
||||
@@ -218,11 +223,11 @@ public class SimProvider extends ContentProvider {
|
||||
int match = URL_MATCHER.match(url);
|
||||
switch (match) {
|
||||
case ADN:
|
||||
efType = SimConstants.EF_ADN;
|
||||
efType = IccConstants.EF_ADN;
|
||||
break;
|
||||
|
||||
case FDN:
|
||||
efType = SimConstants.EF_FDN;
|
||||
efType = IccConstants.EF_FDN;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -269,7 +274,7 @@ public class SimProvider extends ContentProvider {
|
||||
return 0;
|
||||
}
|
||||
|
||||
boolean success = deleteSimRecordFromEf(efType, tag, number, pin2);
|
||||
boolean success = deleteIccRecordFromEf(efType, tag, number, pin2);
|
||||
if (!success) {
|
||||
return 0;
|
||||
}
|
||||
@@ -287,11 +292,11 @@ public class SimProvider extends ContentProvider {
|
||||
int match = URL_MATCHER.match(url);
|
||||
switch (match) {
|
||||
case ADN:
|
||||
efType = SimConstants.EF_ADN;
|
||||
efType = IccConstants.EF_ADN;
|
||||
break;
|
||||
|
||||
case FDN:
|
||||
efType = SimConstants.EF_FDN;
|
||||
efType = IccConstants.EF_FDN;
|
||||
pin2 = values.getAsString("pin2");
|
||||
break;
|
||||
|
||||
@@ -305,7 +310,7 @@ public class SimProvider extends ContentProvider {
|
||||
String newTag = values.getAsString("newTag");
|
||||
String newNumber = values.getAsString("newNumber");
|
||||
|
||||
boolean success = updateSimRecordInEf(efType, tag, number,
|
||||
boolean success = updateIccRecordInEf(efType, tag, number,
|
||||
newTag, newNumber, pin2);
|
||||
|
||||
if (!success) {
|
||||
@@ -322,17 +327,16 @@ public class SimProvider extends ContentProvider {
|
||||
if (DBG) log("loadFromEf: efType=" + efType);
|
||||
|
||||
try {
|
||||
ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface(
|
||||
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
|
||||
ServiceManager.getService("simphonebook"));
|
||||
if (simIpb != null) {
|
||||
adnRecords = simIpb.getAdnRecordsInEf(efType);
|
||||
if (iccIpb != null) {
|
||||
adnRecords = iccIpb.getAdnRecordsInEf(efType);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
} catch (SecurityException ex) {
|
||||
if (DBG) log(ex.toString());
|
||||
}
|
||||
|
||||
if (adnRecords != null) {
|
||||
// Load the results
|
||||
|
||||
@@ -351,8 +355,8 @@ public class SimProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
private boolean
|
||||
addSimRecordToEf(int efType, String name, String number, String pin2) {
|
||||
if (DBG) log("addSimRecordToEf: efType=" + efType + ", name=" + name +
|
||||
addIccRecordToEf(int efType, String name, String number, String pin2) {
|
||||
if (DBG) log("addIccRecordToEf: efType=" + efType + ", name=" + name +
|
||||
", number=" + number);
|
||||
|
||||
boolean success = false;
|
||||
@@ -361,11 +365,12 @@ public class SimProvider extends ContentProvider {
|
||||
// updateAdnRecordsInEfBySearch()? In any case, we will leave
|
||||
// the UI level logic to fill that prereq if necessary. But
|
||||
// hopefully, we can remove this requirement.
|
||||
|
||||
try {
|
||||
ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface(
|
||||
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
|
||||
ServiceManager.getService("simphonebook"));
|
||||
if (simIpb != null) {
|
||||
success = simIpb.updateAdnRecordsInEfBySearch(efType, "", "",
|
||||
if (iccIpb != null) {
|
||||
success = iccIpb.updateAdnRecordsInEfBySearch(efType, "", "",
|
||||
name, number, pin2);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
@@ -373,23 +378,23 @@ public class SimProvider extends ContentProvider {
|
||||
} catch (SecurityException ex) {
|
||||
if (DBG) log(ex.toString());
|
||||
}
|
||||
if (DBG) log("addSimRecordToEf: " + success);
|
||||
if (DBG) log("addIccRecordToEf: " + success);
|
||||
return success;
|
||||
}
|
||||
|
||||
private boolean
|
||||
updateSimRecordInEf(int efType, String oldName, String oldNumber,
|
||||
updateIccRecordInEf(int efType, String oldName, String oldNumber,
|
||||
String newName, String newNumber,String pin2) {
|
||||
if (DBG) log("updateSimRecordInEf: efType=" + efType +
|
||||
if (DBG) log("updateIccRecordInEf: efType=" + efType +
|
||||
", oldname=" + oldName + ", oldnumber=" + oldNumber +
|
||||
", newname=" + newName + ", newnumber=" + newNumber);
|
||||
boolean success = false;
|
||||
|
||||
try {
|
||||
ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface(
|
||||
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
|
||||
ServiceManager.getService("simphonebook"));
|
||||
if (simIpb != null) {
|
||||
success = simIpb.updateAdnRecordsInEfBySearch(efType,
|
||||
if (iccIpb != null) {
|
||||
success = iccIpb.updateAdnRecordsInEfBySearch(efType,
|
||||
oldName, oldNumber, newName, newNumber, pin2);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
@@ -397,34 +402,30 @@ public class SimProvider extends ContentProvider {
|
||||
} catch (SecurityException ex) {
|
||||
if (DBG) log(ex.toString());
|
||||
}
|
||||
|
||||
if (DBG) log("updateSimRecordInEf: " + success);
|
||||
if (DBG) log("updateIccRecordInEf: " + success);
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
private boolean deleteSimRecordFromEf(int efType,
|
||||
String name, String number,
|
||||
String pin2) {
|
||||
if (DBG) log("deleteSimRecordFromEf: efType=" + efType +
|
||||
private boolean deleteIccRecordFromEf(int efType, String name, String number, String pin2) {
|
||||
if (DBG) log("deleteIccRecordFromEf: efType=" + efType +
|
||||
", name=" + name + ", number=" + number + ", pin2=" + pin2);
|
||||
|
||||
boolean success = false;
|
||||
|
||||
try {
|
||||
ISimPhoneBook simIpb = ISimPhoneBook.Stub.asInterface(
|
||||
IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
|
||||
ServiceManager.getService("simphonebook"));
|
||||
if (simIpb != null) {
|
||||
success = simIpb.updateAdnRecordsInEfBySearch(efType,
|
||||
name, number, "", "", pin2);
|
||||
if (iccIpb != null) {
|
||||
success = iccIpb.updateAdnRecordsInEfBySearch(efType,
|
||||
name, number, "", "", pin2);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
// ignore it
|
||||
} catch (SecurityException ex) {
|
||||
if (DBG) log(ex.toString());
|
||||
}
|
||||
|
||||
if (DBG) log("deleteSimRecordFromEf: " + success);
|
||||
if (DBG) log("deleteIccRecordFromEf: " + success);
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -449,7 +450,7 @@ public class SimProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
private void log(String msg) {
|
||||
Log.d(TAG, "[SimProvider] " + msg);
|
||||
Log.d(TAG, "[IccProvider] " + msg);
|
||||
}
|
||||
|
||||
}
|
||||
237
telephony/java/com/android/internal/telephony/IccRecords.java
Normal file
237
telephony/java/com/android/internal/telephony/IccRecords.java
Normal file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Registrant;
|
||||
import android.os.RegistrantList;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public abstract class IccRecords extends Handler implements IccConstants {
|
||||
|
||||
protected static final boolean DBG = true;
|
||||
//***** Instance Variables
|
||||
|
||||
protected PhoneBase phone;
|
||||
protected RegistrantList recordsLoadedRegistrants = new RegistrantList();
|
||||
|
||||
protected int recordsToLoad; // number of pending load requests
|
||||
|
||||
protected AdnRecordCache adnCache;
|
||||
|
||||
//***** Cached SIM State; cleared on channel close
|
||||
|
||||
protected boolean recordsRequested = false; // true if we've made requests for the sim records
|
||||
|
||||
public String iccid;
|
||||
protected String msisdn = null; // My mobile number
|
||||
protected String msisdnTag = null;
|
||||
protected String voiceMailNum = null;
|
||||
protected String voiceMailTag = null;
|
||||
protected String newVoiceMailNum = null;
|
||||
protected String newVoiceMailTag = null;
|
||||
protected boolean isVoiceMailFixed = false;
|
||||
protected int countVoiceMessages = 0;
|
||||
|
||||
protected int mncLength = 0; // 0 is used to indicate that the value
|
||||
// is not initialized
|
||||
protected int mailboxIndex = 0; // 0 is no mailbox dailing number associated
|
||||
|
||||
protected String spn;
|
||||
protected int spnDisplayCondition;
|
||||
|
||||
//***** Constants
|
||||
|
||||
// Bitmasks for SPN display rules.
|
||||
protected static final int SPN_RULE_SHOW_SPN = 0x01;
|
||||
protected static final int SPN_RULE_SHOW_PLMN = 0x02;
|
||||
|
||||
//***** Event Constants
|
||||
protected static final int EVENT_SET_MSISDN_DONE = 30;
|
||||
|
||||
//***** Constructor
|
||||
|
||||
public IccRecords(PhoneBase p) {
|
||||
this.phone = p;
|
||||
}
|
||||
|
||||
protected abstract void onRadioOffOrNotAvailable();
|
||||
|
||||
//***** Public Methods
|
||||
public AdnRecordCache getAdnCache() {
|
||||
return adnCache;
|
||||
}
|
||||
|
||||
public void registerForRecordsLoaded(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant(h, what, obj);
|
||||
recordsLoadedRegistrants.add(r);
|
||||
|
||||
if (recordsToLoad == 0 && recordsRequested == true) {
|
||||
r.notifyRegistrant(new AsyncResult(null, null, null));
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForRecordsLoaded(Handler h) {
|
||||
recordsLoadedRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public String getMsisdnNumber() {
|
||||
return msisdn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set subscriber number to SIM record
|
||||
*
|
||||
* The subscriber number is stored in EF_MSISDN (TS 51.011)
|
||||
*
|
||||
* When the operation is complete, onComplete will be sent to its handler
|
||||
*
|
||||
* @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters)
|
||||
* @param number dailing nubmer (up to 20 digits)
|
||||
* if the number starts with '+', then set to international TOA
|
||||
* @param onComplete
|
||||
* onComplete.obj will be an AsyncResult
|
||||
* ((AsyncResult)onComplete.obj).exception == null on success
|
||||
* ((AsyncResult)onComplete.obj).exception != null on fail
|
||||
*/
|
||||
public void setMsisdnNumber(String alphaTag, String number,
|
||||
Message onComplete) {
|
||||
|
||||
msisdn = number;
|
||||
msisdnTag = alphaTag;
|
||||
|
||||
if(DBG) log("Set MSISDN: " + msisdnTag +" " + msisdn);
|
||||
|
||||
|
||||
AdnRecord adn = new AdnRecord(msisdnTag, msisdn);
|
||||
|
||||
new AdnRecordLoader(phone).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null,
|
||||
obtainMessage(EVENT_SET_MSISDN_DONE, onComplete));
|
||||
}
|
||||
|
||||
public String getMsisdnAlphaTag() {
|
||||
return msisdnTag;
|
||||
}
|
||||
|
||||
public String getVoiceMailNumber() {
|
||||
return voiceMailNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41)
|
||||
* @return null if SIM is not yet ready or no RUIM entry
|
||||
*/
|
||||
public String getServiceProviderName() {
|
||||
return spn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set voice mail number to SIM record
|
||||
*
|
||||
* The voice mail number can be stored either in EF_MBDN (TS 51.011) or
|
||||
* EF_MAILBOX_CPHS (CPHS 4.2)
|
||||
*
|
||||
* If EF_MBDN is available, store the voice mail number to EF_MBDN
|
||||
*
|
||||
* If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
|
||||
*
|
||||
* So the voice mail number will be stored in both EFs if both are available
|
||||
*
|
||||
* Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
|
||||
*
|
||||
* When the operation is complete, onComplete will be sent to its handler
|
||||
*
|
||||
* @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
|
||||
* @param voiceNumber dailing nubmer (upto 20 digits)
|
||||
* if the number is start with '+', then set to international TOA
|
||||
* @param onComplete
|
||||
* onComplete.obj will be an AsyncResult
|
||||
* ((AsyncResult)onComplete.obj).exception == null on success
|
||||
* ((AsyncResult)onComplete.obj).exception != null on fail
|
||||
*/
|
||||
public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber,
|
||||
Message onComplete);
|
||||
|
||||
public String getVoiceMailAlphaTag() {
|
||||
return voiceMailTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SIM voice message waiting indicator records
|
||||
* @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
|
||||
* @param countWaiting The number of messages waiting, if known. Use
|
||||
* -1 to indicate that an unknown number of
|
||||
* messages are waiting
|
||||
*/
|
||||
public abstract void setVoiceMessageWaiting(int line, int countWaiting);
|
||||
|
||||
/** @return true if there are messages waiting, false otherwise. */
|
||||
public boolean getVoiceMessageWaiting() {
|
||||
return countVoiceMessages != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns number of voice messages waiting, if available
|
||||
* If not available (eg, on an older CPHS SIM) -1 is returned if
|
||||
* getVoiceMessageWaiting() is true
|
||||
*/
|
||||
public int getCountVoiceMessages() {
|
||||
return countVoiceMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by STK Service when REFRESH is received.
|
||||
* @param fileChanged indicates whether any files changed
|
||||
* @param fileList if non-null, a list of EF files that changed
|
||||
*/
|
||||
public abstract void onRefresh(boolean fileChanged, int[] fileList);
|
||||
|
||||
|
||||
public boolean getRecordsLoaded() {
|
||||
if (recordsToLoad == 0 && recordsRequested == true) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//***** Overridden from Handler
|
||||
public abstract void handleMessage(Message msg);
|
||||
|
||||
protected abstract void onRecordLoaded();
|
||||
|
||||
protected abstract void onAllRecordsLoaded();
|
||||
|
||||
/**
|
||||
* Returns the SpnDisplayRule based on settings on the SIM and the
|
||||
* specified plmn (currently-registered PLMN). See TS 22.101 Annex A
|
||||
* and TS 51.011 10.3.11 for details.
|
||||
*
|
||||
* If the SPN is not found on the SIM, the rule is always PLMN_ONLY.
|
||||
*/
|
||||
protected abstract int getDisplayRule(String plmn);
|
||||
|
||||
protected abstract void log(String s);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static android.telephony.SmsManager.STATUS_ON_ICC_FREE;
|
||||
|
||||
/**
|
||||
* IccSmsInterfaceManager to provide an inter-process communication to
|
||||
* access Sms in Icc.
|
||||
*/
|
||||
public abstract class IccSmsInterfaceManager extends ISms.Stub {
|
||||
static final boolean DBG = true;
|
||||
|
||||
protected PhoneBase mPhone;
|
||||
protected Context mContext;
|
||||
protected SMSDispatcher mDispatcher;
|
||||
|
||||
protected IccSmsInterfaceManager(PhoneBase phone){
|
||||
mPhone = phone;
|
||||
mContext = phone.getContext();
|
||||
}
|
||||
|
||||
protected void enforceReceiveAndSend(String message) {
|
||||
mContext.enforceCallingPermission(
|
||||
"android.permission.RECEIVE_SMS", message);
|
||||
mContext.enforceCallingPermission(
|
||||
"android.permission.SEND_SMS", message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a Raw PDU SMS
|
||||
*
|
||||
* @param smsc the SMSC to send the message through, or NULL for the
|
||||
* defatult SMSC
|
||||
* @param pdu the raw PDU to send
|
||||
* @param sentIntent if not NULL this <code>Intent</code> is
|
||||
* broadcast when the message is sucessfully sent, or failed.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
* or one of these errors:
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* @param deliveryIntent if not NULL this <code>Intent</code> is
|
||||
* broadcast when the message is delivered to the recipient. The
|
||||
* raw pdu of the status report is in the extended data ("pdu").
|
||||
*/
|
||||
public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
|
||||
PendingIntent deliveryIntent) {
|
||||
Context context = mPhone.getContext();
|
||||
|
||||
context.enforceCallingPermission(
|
||||
"android.permission.SEND_SMS",
|
||||
"Sending SMS message");
|
||||
if (DBG) log("sendRawPdu: smsc=" + smsc +
|
||||
" pdu="+ pdu + " sentIntent" + sentIntent +
|
||||
" deliveryIntent" + deliveryIntent);
|
||||
mDispatcher.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a multi-part text based SMS.
|
||||
*
|
||||
* @param destinationAddress the address to send the message to
|
||||
* @param scAddress is the service center address or null to use
|
||||
* the current default SMSC
|
||||
* @param parts an <code>ArrayList</code> of strings that, in order,
|
||||
* comprise the original message
|
||||
* @param sentIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been sent.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
* or one of these errors:
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* @param deliveryIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been delivered
|
||||
* to the recipient. The raw pdu of the status report is in the
|
||||
* extended data ("pdu").
|
||||
*/
|
||||
public void sendMultipartText(String destinationAddress, String scAddress, List<String> parts,
|
||||
List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
|
||||
Context context = mPhone.getContext();
|
||||
|
||||
context.enforceCallingPermission(
|
||||
"android.permission.SEND_SMS",
|
||||
"Sending SMS message");
|
||||
if (DBG) log("sendMultipartText");
|
||||
mDispatcher.sendMultipartText(destinationAddress, scAddress, (ArrayList<String>) parts,
|
||||
(ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents);
|
||||
}
|
||||
|
||||
/**
|
||||
* create SmsRawData lists from all sms record byte[]
|
||||
* Use null to indicate "free" record
|
||||
*
|
||||
* @param messages List of message records from EF_SMS.
|
||||
* @return SmsRawData list of all in-used records
|
||||
*/
|
||||
protected ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) {
|
||||
int count = messages.size();
|
||||
ArrayList<SmsRawData> ret;
|
||||
|
||||
ret = new ArrayList<SmsRawData>(count);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
byte[] ba = messages.get(i);
|
||||
if (ba[0] == STATUS_ON_ICC_FREE) {
|
||||
ret.add(null);
|
||||
} else {
|
||||
ret.add(new SmsRawData(messages.get(i)));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an EF_SMS record from status and raw PDU.
|
||||
*
|
||||
* @param status Message status. See TS 51.011 10.5.3.
|
||||
* @param pdu Raw message PDU.
|
||||
* @return byte array for the record.
|
||||
*/
|
||||
protected byte[] makeSmsRecordData(int status, byte[] pdu) {
|
||||
byte[] data = new byte[IccConstants.SMS_RECORD_LENGTH];
|
||||
|
||||
// Status bits for this record. See TS 51.011 10.5.3
|
||||
data[0] = (byte)(status & 7);
|
||||
|
||||
System.arraycopy(pdu, 0, data, 1, pdu.length);
|
||||
|
||||
// Pad out with 0xFF's.
|
||||
for (int j = pdu.length+1; j < IccConstants.SMS_RECORD_LENGTH; j++) {
|
||||
data[j] = -1;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
protected abstract void log(String msg);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.os.ServiceManager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class IccSmsInterfaceManagerProxy extends ISms.Stub {
|
||||
private IccSmsInterfaceManager mIccSmsInterfaceManager;
|
||||
|
||||
public IccSmsInterfaceManagerProxy(IccSmsInterfaceManager
|
||||
iccSmsInterfaceManager) {
|
||||
this.mIccSmsInterfaceManager = iccSmsInterfaceManager;
|
||||
if(ServiceManager.getService("isms") == null) {
|
||||
ServiceManager.addService("isms", this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setmIccSmsInterfaceManager(IccSmsInterfaceManager iccSmsInterfaceManager) {
|
||||
this.mIccSmsInterfaceManager = iccSmsInterfaceManager;
|
||||
}
|
||||
|
||||
public boolean
|
||||
updateMessageOnIccEf(int index, int status, byte[] pdu) throws android.os.RemoteException {
|
||||
return mIccSmsInterfaceManager.updateMessageOnIccEf(index, status, pdu);
|
||||
}
|
||||
|
||||
public boolean copyMessageToIccEf(int status, byte[] pdu,
|
||||
byte[] smsc) throws android.os.RemoteException {
|
||||
return mIccSmsInterfaceManager.copyMessageToIccEf(status, pdu, smsc);
|
||||
}
|
||||
|
||||
public List<SmsRawData> getAllMessagesFromIccEf() throws android.os.RemoteException {
|
||||
return mIccSmsInterfaceManager.getAllMessagesFromIccEf();
|
||||
}
|
||||
|
||||
public void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
|
||||
PendingIntent deliveryIntent) throws android.os.RemoteException {
|
||||
mIccSmsInterfaceManager.sendRawPdu(smsc, pdu, sentIntent,
|
||||
deliveryIntent);
|
||||
}
|
||||
|
||||
public void sendMultipartText(String destinationAddress, String scAddress,
|
||||
List<String> parts, List<PendingIntent> sentIntents,
|
||||
List<PendingIntent> deliveryIntents) throws android.os.RemoteException {
|
||||
mIccSmsInterfaceManager.sendMultipartText(destinationAddress, scAddress,
|
||||
parts, sentIntents, deliveryIntents);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,48 +14,48 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.GsmAlphabet;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
/**
|
||||
* Various methods, useful for dealing with SIM data.
|
||||
*/
|
||||
public class SimUtils
|
||||
{
|
||||
static final String LOG_TAG="GSM";
|
||||
public class IccUtils {
|
||||
static final String LOG_TAG="IccUtils";
|
||||
|
||||
/**
|
||||
* Many fields in GSM SIM's are stored as nibble-swizzled BCD
|
||||
*
|
||||
* Assumes left-justified field that may be padded right with 0xf
|
||||
* Assumes left-justified field that may be padded right with 0xf
|
||||
* values.
|
||||
*
|
||||
* Stops on invalid BCD value, returning string so far
|
||||
*/
|
||||
public static String
|
||||
bcdToString(byte[] data, int offset, int length)
|
||||
{
|
||||
bcdToString(byte[] data, int offset, int length) {
|
||||
StringBuilder ret = new StringBuilder(length*2);
|
||||
|
||||
|
||||
for (int i = offset ; i < offset + length ; i++) {
|
||||
byte b;
|
||||
int v;
|
||||
|
||||
|
||||
v = data[i] & 0xf;
|
||||
if (v > 9) break;
|
||||
ret.append((char)('0' + v));
|
||||
|
||||
v = (data[i] >> 4) & 0xf;
|
||||
if (v > 9) break;
|
||||
ret.append((char)('0' + v));
|
||||
ret.append((char)('0' + v));
|
||||
}
|
||||
|
||||
return ret.toString();
|
||||
|
||||
return ret.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public class SimUtils
|
||||
* significant nibble.
|
||||
*
|
||||
* Out-of-range digits are treated as 0 for the sake of the time stamp,
|
||||
* because of this:
|
||||
* because of this:
|
||||
*
|
||||
* TS 23.040 section 9.2.3.11
|
||||
* "if the MS receives a non-integer value in the SCTS, it shall
|
||||
@@ -74,13 +74,12 @@ public class SimUtils
|
||||
* exactly as received"
|
||||
*/
|
||||
public static int
|
||||
bcdByteToInt(byte b)
|
||||
{
|
||||
bcdByteToInt(byte b) {
|
||||
int ret = 0;
|
||||
|
||||
// treat out-of-range BCD values as 0
|
||||
if ((b & 0xf0) <= 0x90) {
|
||||
ret = (b >> 4) & 0xf;
|
||||
ret = (b >> 4) & 0xf;
|
||||
}
|
||||
|
||||
if ((b & 0x0f) <= 0x09) {
|
||||
@@ -90,6 +89,24 @@ public class SimUtils
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Decodes BCD byte like {@link bcdByteToInt}, but the most significant BCD
|
||||
* digit is expected in the most significant nibble.
|
||||
*/
|
||||
public static int
|
||||
beBcdByteToInt(byte b) {
|
||||
int ret = 0;
|
||||
|
||||
// treat out-of-range BCD values as 0
|
||||
if ((b & 0xf0) <= 0x90) {
|
||||
ret = ((b >> 4) & 0xf) * 10;
|
||||
}
|
||||
|
||||
if ((b & 0x0f) <= 0x09) {
|
||||
ret += (b & 0xf);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a string field that's formatted like the EF[ADN] alpha
|
||||
@@ -97,11 +114,11 @@ public class SimUtils
|
||||
*
|
||||
* From TS 51.011 10.5.1:
|
||||
* Coding:
|
||||
* this alpha tagging shall use either
|
||||
* - the SMS default 7 bit coded alphabet as defined in
|
||||
* TS 23.038 [12] with bit 8 set to 0. The alpha identifier
|
||||
* this alpha tagging shall use either
|
||||
* - the SMS default 7 bit coded alphabet as defined in
|
||||
* TS 23.038 [12] with bit 8 set to 0. The alpha identifier
|
||||
* shall be left justified. Unused bytes shall be set to 'FF'; or
|
||||
* - one of the UCS2 coded options as defined in annex B.
|
||||
* - one of the UCS2 coded options as defined in annex B.
|
||||
*
|
||||
* Annex B from TS 11.11 V8.13.0:
|
||||
* 1) If the first octet in the alpha string is '80', then the
|
||||
@@ -109,7 +126,7 @@ public class SimUtils
|
||||
* 2) if the first octet in the alpha string is '81', then the
|
||||
* second octet contains a value indicating the number of
|
||||
* characters in the string, and the third octet contains an
|
||||
* 8 bit number which defines bits 15 to 8 of a 16 bit
|
||||
* 8 bit number which defines bits 15 to 8 of a 16 bit
|
||||
* base pointer, where bit 16 is set to zero and bits 7 to 1
|
||||
* are also set to zero. These sixteen bits constitute a
|
||||
* base pointer to a "half page" in the UCS2 code space, to be
|
||||
@@ -127,8 +144,7 @@ public class SimUtils
|
||||
* base pointer to a "half page" in the UCS2 code space...
|
||||
*/
|
||||
public static String
|
||||
adnStringFieldToString(byte[] data, int offset, int length)
|
||||
{
|
||||
adnStringFieldToString(byte[] data, int offset, int length) {
|
||||
if (length >= 1) {
|
||||
if (data[offset] == (byte) 0x80) {
|
||||
int ucslen = (length - 1) / 2;
|
||||
@@ -208,8 +224,7 @@ public class SimUtils
|
||||
}
|
||||
|
||||
static int
|
||||
hexCharToInt(char c)
|
||||
{
|
||||
hexCharToInt(char c) {
|
||||
if (c >= '0' && c <= '9') return (c - '0');
|
||||
if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
|
||||
if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
|
||||
@@ -219,17 +234,16 @@ public class SimUtils
|
||||
|
||||
/**
|
||||
* Converts a hex String to a byte array.
|
||||
*
|
||||
*
|
||||
* @param s A string of hexadecimal characters, must be an even number of
|
||||
* chars long
|
||||
*
|
||||
* @return byte array representation
|
||||
*
|
||||
*
|
||||
* @throws RuntimeException on invalid format
|
||||
*/
|
||||
public static byte[]
|
||||
hexStringToBytes(String s)
|
||||
{
|
||||
hexStringToBytes(String s) {
|
||||
byte[] ret;
|
||||
|
||||
if (s == null) return null;
|
||||
@@ -239,10 +253,10 @@ public class SimUtils
|
||||
ret = new byte[sz/2];
|
||||
|
||||
for (int i=0 ; i <sz ; i+=2) {
|
||||
ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4)
|
||||
ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4)
|
||||
| hexCharToInt(s.charAt(i+1)));
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -253,10 +267,9 @@ public class SimUtils
|
||||
* null returns null
|
||||
*/
|
||||
public static String
|
||||
bytesToHexString(byte[] bytes)
|
||||
{
|
||||
bytesToHexString(byte[] bytes) {
|
||||
if (bytes == null) return null;
|
||||
|
||||
|
||||
StringBuilder ret = new StringBuilder(2*bytes.length);
|
||||
|
||||
for (int i = 0 ; i < bytes.length ; i++) {
|
||||
@@ -281,10 +294,9 @@ public class SimUtils
|
||||
* empty string returned on decode error
|
||||
*/
|
||||
public static String
|
||||
networkNameToString(byte[] data, int offset, int length)
|
||||
{
|
||||
networkNameToString(byte[] data, int offset, int length) {
|
||||
String ret;
|
||||
|
||||
|
||||
if ((data[offset] & 0x80) != 0x80 || length < 1) {
|
||||
return "";
|
||||
}
|
||||
@@ -295,13 +307,12 @@ public class SimUtils
|
||||
int countSeptets;
|
||||
int unusedBits = data[offset] & 7;
|
||||
countSeptets = (((length - 1) * 8) - unusedBits) / 7 ;
|
||||
ret = GsmAlphabet.gsm7BitPackedToString(
|
||||
data, offset + 1, countSeptets);
|
||||
ret = GsmAlphabet.gsm7BitPackedToString(data, offset + 1, countSeptets);
|
||||
break;
|
||||
case 1:
|
||||
// UCS2
|
||||
try {
|
||||
ret = new String(data,
|
||||
ret = new String(data,
|
||||
offset + 1, length - 1, "utf-16");
|
||||
} catch (UnsupportedEncodingException ex) {
|
||||
ret = "";
|
||||
@@ -332,7 +343,7 @@ public class SimUtils
|
||||
* @param data The raw data
|
||||
* @param length The length of image body
|
||||
* @return The bitmap
|
||||
*/
|
||||
*/
|
||||
public static Bitmap parseToBnW(byte[] data, int length){
|
||||
int valueIndex = 0;
|
||||
int width = data[valueIndex++] & 0xFF;
|
||||
@@ -369,7 +380,7 @@ public class SimUtils
|
||||
|
||||
/**
|
||||
* a TS 131.102 image instance of code scheme '11' into color Bitmap
|
||||
*
|
||||
*
|
||||
* @param data The raw data
|
||||
* @param length the length of image body
|
||||
* @param transparency with or without transparency
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public final class IccVmFixedException extends IccException {
|
||||
IccVmFixedException()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IccVmFixedException(String s)
|
||||
{
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public final class IccVmNotSupportedException extends IccException {
|
||||
IccVmNotSupportedException()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IccVmNotSupportedException(String s)
|
||||
{
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -41,14 +41,14 @@ public interface MmiCode
|
||||
* @return Localized message for UI display, valid only in COMPLETE
|
||||
* or FAILED states. null otherwise
|
||||
*/
|
||||
|
||||
|
||||
public CharSequence getMessage();
|
||||
|
||||
/**
|
||||
* Cancels pending MMI request.
|
||||
* State becomes CANCELLED unless already COMPLETE or FAILED
|
||||
*/
|
||||
public void cancel();
|
||||
public void cancel();
|
||||
|
||||
/**
|
||||
* @return true if the network response is a REQUEST for more user input.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,23 +20,30 @@ import android.app.ActivityManagerNative;
|
||||
import android.app.IActivityManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.RegistrantList;
|
||||
import android.os.SystemProperties;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.telephony.ServiceState;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.telephony.gsm.PdpConnection;
|
||||
import com.android.internal.telephony.test.SimulatedRadioControl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
/**
|
||||
* (<em>Not for SDK use</em>)
|
||||
* (<em>Not for SDK use</em>)
|
||||
* A base implementation for the com.android.internal.telephony.Phone interface.
|
||||
*
|
||||
*
|
||||
* Note that implementations of Phone.java are expected to be used
|
||||
* from a single application thread. This should be the same thread that
|
||||
* originally called PhoneFactory to obtain the interface.
|
||||
@@ -46,42 +53,101 @@ import java.util.Locale;
|
||||
*/
|
||||
|
||||
public abstract class PhoneBase implements Phone {
|
||||
private static final String LOG_TAG = "GSM";
|
||||
private static final String LOG_TAG = "PHONE";
|
||||
private static final boolean LOCAL_DEBUG = true;
|
||||
|
||||
protected final RegistrantList mPhoneStateRegistrants
|
||||
// Key used to read and write the saved network selection value
|
||||
public static final String NETWORK_SELECTION_KEY = "network_selection_key";
|
||||
|
||||
// Key used to read/write "disable data connection on boot" pref (used for testing)
|
||||
public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key";
|
||||
|
||||
//***** Event Constants
|
||||
protected static final int EVENT_RADIO_AVAILABLE = 1;
|
||||
/** Supplementary Service Notification received. */
|
||||
protected static final int EVENT_SSN = 2;
|
||||
protected static final int EVENT_SIM_RECORDS_LOADED = 3;
|
||||
protected static final int EVENT_MMI_DONE = 4;
|
||||
protected static final int EVENT_RADIO_ON = 5;
|
||||
protected static final int EVENT_GET_BASEBAND_VERSION_DONE = 6;
|
||||
protected static final int EVENT_USSD = 7;
|
||||
protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 8;
|
||||
protected static final int EVENT_GET_IMEI_DONE = 9;
|
||||
protected static final int EVENT_GET_IMEISV_DONE = 10;
|
||||
protected static final int EVENT_GET_SIM_STATUS_DONE = 11;
|
||||
protected static final int EVENT_SET_CALL_FORWARD_DONE = 12;
|
||||
protected static final int EVENT_GET_CALL_FORWARD_DONE = 13;
|
||||
protected static final int EVENT_CALL_RING = 14;
|
||||
// Used to intercept the carrier selection calls so that
|
||||
// we can save the values.
|
||||
protected static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 15;
|
||||
protected static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 16;
|
||||
protected static final int EVENT_SET_CLIR_COMPLETE = 17;
|
||||
protected static final int EVENT_REGISTERED_TO_NETWORK = 18;
|
||||
protected static final int EVENT_SET_VM_NUMBER_DONE = 19;
|
||||
// Events for CDMA support
|
||||
protected static final int EVENT_GET_DEVICE_IDENTITY_DONE = 20;
|
||||
protected static final int EVENT_RUIM_RECORDS_LOADED = 21;
|
||||
protected static final int EVENT_NV_READY = 22;
|
||||
protected static final int EVENT_SET_ENHANCED_VP = 23;
|
||||
|
||||
// Key used to read/write current CLIR setting
|
||||
public static final String CLIR_KEY = "clir_key";
|
||||
|
||||
// Key used to read/write "disable DNS server check" pref (used for testing)
|
||||
public static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key";
|
||||
|
||||
//***** Instance Variables
|
||||
public CommandsInterface mCM;
|
||||
protected IccFileHandler mIccFileHandler;
|
||||
boolean mDnsCheckDisabled = false;
|
||||
|
||||
/**
|
||||
* Set a system property, unless we're in unit test mode
|
||||
*/
|
||||
public void
|
||||
setSystemProperty(String property, String value) {
|
||||
if(getUnitTestMode()) {
|
||||
return;
|
||||
}
|
||||
SystemProperties.set(property, value);
|
||||
}
|
||||
|
||||
|
||||
protected final RegistrantList mPhoneStateRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
protected final RegistrantList mNewRingingConnectionRegistrants
|
||||
protected final RegistrantList mNewRingingConnectionRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
protected final RegistrantList mIncomingRingRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
protected final RegistrantList mDisconnectRegistrants
|
||||
protected final RegistrantList mIncomingRingRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
protected final RegistrantList mServiceStateRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
protected final RegistrantList mMmiCompleteRegistrants
|
||||
protected final RegistrantList mDisconnectRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
protected final RegistrantList mMmiRegistrants
|
||||
protected final RegistrantList mServiceStateRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
protected final RegistrantList mUnknownConnectionRegistrants
|
||||
protected final RegistrantList mMmiCompleteRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
protected final RegistrantList mSuppServiceFailedRegistrants
|
||||
|
||||
protected final RegistrantList mMmiRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
|
||||
protected final RegistrantList mUnknownConnectionRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
protected final RegistrantList mSuppServiceFailedRegistrants
|
||||
= new RegistrantList();
|
||||
|
||||
protected Looper mLooper; /* to insure registrants are in correct thread*/
|
||||
|
||||
protected Context mContext;
|
||||
|
||||
/**
|
||||
* PhoneNotifier is an abstraction for all system-wide
|
||||
* state change notification. DefaultPhoneNotifier is
|
||||
/**
|
||||
* PhoneNotifier is an abstraction for all system-wide
|
||||
* state change notification. DefaultPhoneNotifier is
|
||||
* used here unless running we're inside a unit test.
|
||||
*/
|
||||
protected PhoneNotifier mNotifier;
|
||||
@@ -94,7 +160,7 @@ public abstract class PhoneBase implements Phone {
|
||||
* Constructs a PhoneBase in normal (non-unit test) mode.
|
||||
*
|
||||
* @param context Context object from hosting application
|
||||
* @param notifier An instance of DefaultPhoneNotifier,
|
||||
* @param notifier An instance of DefaultPhoneNotifier,
|
||||
* unless unit testing.
|
||||
*/
|
||||
protected PhoneBase(PhoneNotifier notifier, Context context) {
|
||||
@@ -105,13 +171,13 @@ public abstract class PhoneBase implements Phone {
|
||||
* Constructs a PhoneBase in normal (non-unit test) mode.
|
||||
*
|
||||
* @param context Context object from hosting application
|
||||
* @param notifier An instance of DefaultPhoneNotifier,
|
||||
* @param notifier An instance of DefaultPhoneNotifier,
|
||||
* unless unit testing.
|
||||
* @param unitTestMode when true, prevents notifications
|
||||
* @param unitTestMode when true, prevents notifications
|
||||
* of state change events
|
||||
*/
|
||||
protected PhoneBase(PhoneNotifier notifier, Context context,
|
||||
boolean unitTestMode) {
|
||||
protected PhoneBase(PhoneNotifier notifier, Context context,
|
||||
boolean unitTestMode) {
|
||||
this.mNotifier = notifier;
|
||||
this.mContext = context;
|
||||
mLooper = Looper.myLooper();
|
||||
@@ -119,6 +185,9 @@ public abstract class PhoneBase implements Phone {
|
||||
setLocaleByCarrier();
|
||||
|
||||
setUnitTestMode(unitTestMode);
|
||||
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);
|
||||
}
|
||||
|
||||
// Inherited documentation suffices.
|
||||
@@ -126,6 +195,26 @@ public abstract class PhoneBase implements Phone {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the DNS check (i.e., allows "0.0.0.0").
|
||||
* Useful for lab testing environment.
|
||||
* @param b true disables the check, false enables.
|
||||
*/
|
||||
public void disableDnsCheck(boolean b) {
|
||||
mDnsCheckDisabled = b;
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the DNS check is currently disabled.
|
||||
*/
|
||||
public boolean isDnsCheckDisabled() {
|
||||
return mDnsCheckDisabled;
|
||||
}
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void registerForPhoneStateChanged(Handler h, int what, Object obj) {
|
||||
checkCorrectThread(h);
|
||||
@@ -137,29 +226,29 @@ public abstract class PhoneBase implements Phone {
|
||||
public void unregisterForPhoneStateChanged(Handler h) {
|
||||
mPhoneStateRegistrants.remove(h);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notify registrants of a PhoneStateChanged.
|
||||
* Subclasses of Phone probably want to replace this with a
|
||||
* Subclasses of Phone probably want to replace this with a
|
||||
* version scoped to their packages
|
||||
*/
|
||||
protected void notifyCallStateChangedP() {
|
||||
AsyncResult ar = new AsyncResult(null, this, null);
|
||||
mPhoneStateRegistrants.notifyRegistrants(ar);
|
||||
}
|
||||
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void registerForUnknownConnection(Handler h, int what, Object obj) {
|
||||
checkCorrectThread(h);
|
||||
|
||||
|
||||
mUnknownConnectionRegistrants.addUnique(h, what, obj);
|
||||
}
|
||||
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void unregisterForUnknownConnection(Handler h) {
|
||||
mUnknownConnectionRegistrants.remove(h);
|
||||
}
|
||||
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void registerForNewRingingConnection(
|
||||
Handler h, int what, Object obj) {
|
||||
@@ -173,12 +262,33 @@ public abstract class PhoneBase implements Phone {
|
||||
mNewRingingConnectionRegistrants.remove(h);
|
||||
}
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
|
||||
mCM.registerForInCallVoicePrivacyOn(h,what,obj);
|
||||
}
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void unregisterForInCallVoicePrivacyOn(Handler h){
|
||||
mCM.unregisterForInCallVoicePrivacyOn(h);
|
||||
}
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
|
||||
mCM.registerForInCallVoicePrivacyOff(h,what,obj);
|
||||
}
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void unregisterForInCallVoicePrivacyOff(Handler h){
|
||||
mCM.unregisterForInCallVoicePrivacyOff(h);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Notifiy registrants of a new ringing Connection.
|
||||
* Subclasses of Phone probably want to replace this with a
|
||||
* Subclasses of Phone probably want to replace this with a
|
||||
* version scoped to their packages
|
||||
*/
|
||||
protected void notifyNewRingingConnectionP(Connection cn) {
|
||||
protected void notifyNewRingingConnectionP(Connection cn) {
|
||||
AsyncResult ar = new AsyncResult(null, cn, null);
|
||||
mNewRingingConnectionRegistrants.notifyRegistrants(ar);
|
||||
}
|
||||
@@ -187,15 +297,15 @@ public abstract class PhoneBase implements Phone {
|
||||
public void registerForIncomingRing(
|
||||
Handler h, int what, Object obj) {
|
||||
checkCorrectThread(h);
|
||||
|
||||
|
||||
mIncomingRingRegistrants.addUnique(h, what, obj);
|
||||
}
|
||||
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void unregisterForIncomingRing(Handler h) {
|
||||
mIncomingRingRegistrants.remove(h);
|
||||
}
|
||||
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void registerForDisconnect(Handler h, int what, Object obj) {
|
||||
checkCorrectThread(h);
|
||||
@@ -211,15 +321,15 @@ public abstract class PhoneBase implements Phone {
|
||||
// Inherited documentation suffices.
|
||||
public void registerForSuppServiceFailed(Handler h, int what, Object obj) {
|
||||
checkCorrectThread(h);
|
||||
|
||||
|
||||
mSuppServiceFailedRegistrants.addUnique(h, what, obj);
|
||||
}
|
||||
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void unregisterForSuppServiceFailed(Handler h) {
|
||||
mSuppServiceFailedRegistrants.remove(h);
|
||||
}
|
||||
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void registerForMmiInitiate(Handler h, int what, Object obj) {
|
||||
checkCorrectThread(h);
|
||||
@@ -231,7 +341,7 @@ public abstract class PhoneBase implements Phone {
|
||||
public void unregisterForMmiInitiate(Handler h) {
|
||||
mMmiRegistrants.remove(h);
|
||||
}
|
||||
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void registerForMmiComplete(Handler h, int what, Object obj) {
|
||||
checkCorrectThread(h);
|
||||
@@ -247,10 +357,31 @@ public abstract class PhoneBase implements Phone {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses should override this. See documentation in superclass.
|
||||
* Method to retrieve the saved operator id from the Shared Preferences
|
||||
*/
|
||||
public abstract List getPendingMmiCodes();
|
||||
|
||||
private String getSavedNetworkSelection() {
|
||||
// open the shared preferences and search with our key.
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||
return sp.getString(NETWORK_SELECTION_KEY, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to restore the previously saved operator id, or reset to
|
||||
* automatic selection, all depending upon the value in the shared
|
||||
* preferences.
|
||||
*/
|
||||
public void restoreSavedNetworkSelection(Message response) {
|
||||
// retrieve the operator id
|
||||
String networkSelection = getSavedNetworkSelection();
|
||||
|
||||
// set to auto if the id is empty, otherwise select the network.
|
||||
if (TextUtils.isEmpty(networkSelection)) {
|
||||
mCM.setNetworkSelectionModeAutomatic(response);
|
||||
} else {
|
||||
mCM.setNetworkSelectionModeManual(networkSelection, response);
|
||||
}
|
||||
}
|
||||
|
||||
// Inherited documentation suffices.
|
||||
public void setUnitTestMode(boolean f) {
|
||||
mUnitTestMode = f;
|
||||
@@ -260,11 +391,11 @@ public abstract class PhoneBase implements Phone {
|
||||
public boolean getUnitTestMode() {
|
||||
return mUnitTestMode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* To be invoked when a voice call Connection disconnects.
|
||||
*
|
||||
* Subclasses of Phone probably want to replace this with a
|
||||
* Subclasses of Phone probably want to replace this with a
|
||||
* version scoped to their packages
|
||||
*/
|
||||
protected void notifyDisconnectP(Connection cn) {
|
||||
@@ -286,7 +417,7 @@ public abstract class PhoneBase implements Phone {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses of Phone probably want to replace this with a
|
||||
* Subclasses of Phone probably want to replace this with a
|
||||
* version scoped to their packages
|
||||
*/
|
||||
protected void notifyServiceStateChangedP(ServiceState ss) {
|
||||
@@ -312,7 +443,7 @@ public abstract class PhoneBase implements Phone {
|
||||
private void checkCorrectThread(Handler h) {
|
||||
if (h.getLooper() != mLooper) {
|
||||
throw new RuntimeException(
|
||||
"com.android.internal.telephony.Phone must be used from within one thread");
|
||||
"com.android.internal.telephony.Phone must be used from within one thread");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,4 +532,107 @@ public abstract class PhoneBase implements Phone {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieves the Handler of the Phone instance
|
||||
*/
|
||||
public abstract Handler getHandler();
|
||||
|
||||
/**
|
||||
* Retrieves the IccFileHandler of the Phone instance
|
||||
*/
|
||||
public abstract IccFileHandler getIccFileHandler();
|
||||
|
||||
|
||||
/**
|
||||
* Query the status of the CDMA roaming preference
|
||||
*/
|
||||
public void queryCdmaRoamingPreference(Message response) {
|
||||
mCM.queryCdmaRoamingPreference(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status of the CDMA roaming preference
|
||||
*/
|
||||
public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
|
||||
mCM.setCdmaRoamingPreference(cdmaRoamingType, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status of the CDMA subscription mode
|
||||
*/
|
||||
public void setCdmaSubscription(int cdmaSubscriptionType, Message response) {
|
||||
mCM.setCdmaSubscription(cdmaSubscriptionType, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the preferred Network Type: Global, CDMA only or GSM/UMTS only
|
||||
*/
|
||||
public void setPreferredNetworkType(int networkType, Message response) {
|
||||
mCM.setPreferredNetworkType(networkType, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the status of the preferred Network Type: Global, CDMA only or GSM/UMTS only
|
||||
*/
|
||||
public void getPreferredNetworkType(Message response) {
|
||||
mCM.getPreferredNetworkType(response);
|
||||
}
|
||||
|
||||
public void setTTYModeEnabled(boolean enable, Message onComplete) {
|
||||
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
||||
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
||||
}
|
||||
|
||||
public void queryTTYModeEnabled(Message onComplete) {
|
||||
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
||||
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
||||
}
|
||||
|
||||
/**
|
||||
* This should only be called in GSM mode.
|
||||
* Only here for some backward compatibility
|
||||
* issues concerning the GSMPhone class.
|
||||
* @deprecated
|
||||
*/
|
||||
public List<PdpConnection> getCurrentPdpList() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
|
||||
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
||||
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
||||
}
|
||||
|
||||
public void getEnhancedVoicePrivacy(Message onComplete) {
|
||||
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
|
||||
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
|
||||
}
|
||||
|
||||
public void setBandMode(int bandMode, Message response) {
|
||||
mCM.setBandMode(bandMode, response);
|
||||
}
|
||||
|
||||
public void queryAvailableBandMode(Message response) {
|
||||
mCM.queryAvailableBandMode(response);
|
||||
}
|
||||
|
||||
public void invokeOemRilRequestRaw(byte[] data, Message response) {
|
||||
mCM.invokeOemRilRequestRaw(data, response);
|
||||
}
|
||||
|
||||
public void invokeOemRilRequestStrings(String[] strings, Message response) {
|
||||
mCM.invokeOemRilRequestStrings(strings, response);
|
||||
}
|
||||
|
||||
public void notifyDataActivity() {
|
||||
mNotifier.notifyDataActivity(this);
|
||||
}
|
||||
|
||||
public void notifyDataConnection(String reason) {
|
||||
mNotifier.notifyDataConnection(this, reason);
|
||||
}
|
||||
|
||||
public abstract String getPhoneName();
|
||||
|
||||
}
|
||||
|
||||
@@ -16,80 +16,55 @@
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import android.util.Log;
|
||||
import com.android.internal.telephony.gsm.GSMPhone;
|
||||
import com.android.internal.telephony.gsm.RIL;
|
||||
import com.android.internal.telephony.test.ModelInterpreter;
|
||||
import com.android.internal.telephony.test.SimulatedCommands;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemProperties;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.LocalServerSocket;
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.cdma.CDMAPhone;
|
||||
import com.android.internal.telephony.gsm.GSMPhone;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class PhoneFactory
|
||||
{
|
||||
static final String LOG_TAG="GSM";
|
||||
|
||||
public class PhoneFactory {
|
||||
static final String LOG_TAG = "PHONE";
|
||||
static final int SOCKET_OPEN_RETRY_MILLIS = 2 * 1000;
|
||||
static final int SOCKET_OPEN_MAX_RETRY = 3;
|
||||
//***** Class Variables
|
||||
//***** Class Variables
|
||||
|
||||
static private ArrayList<Phone> sPhones = new ArrayList<Phone>();
|
||||
static private Phone sProxyPhone = null;
|
||||
static private CommandsInterface sCommandsInterface = null;
|
||||
|
||||
static private boolean sMadeDefaults = false;
|
||||
static private PhoneNotifier sPhoneNotifier;
|
||||
static private Looper sLooper;
|
||||
static private Context sContext;
|
||||
|
||||
static private Object testMailbox;
|
||||
static final int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;
|
||||
|
||||
static final int preferredCdmaSubscription = RILConstants.PREFERRED_CDMA_SUBSCRIPTION;
|
||||
|
||||
//***** Class Methods
|
||||
|
||||
private static void
|
||||
useNewRIL(Context context)
|
||||
{
|
||||
ModelInterpreter mi = null;
|
||||
GSMPhone phone;
|
||||
|
||||
try {
|
||||
if (false) {
|
||||
mi = new ModelInterpreter(new InetSocketAddress("127.0.0.1", 6502));
|
||||
}
|
||||
|
||||
phone = new GSMPhone(context, new RIL(context), sPhoneNotifier);
|
||||
|
||||
registerPhone (phone);
|
||||
} catch (IOException ex) {
|
||||
Log.e(LOG_TAG, "Error creating ModelInterpreter", ex);
|
||||
}
|
||||
public static void makeDefaultPhones(Context context) {
|
||||
makeDefaultPhone(context);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FIXME replace this with some other way of making these
|
||||
* instances
|
||||
*/
|
||||
public static void
|
||||
makeDefaultPhones(Context context)
|
||||
{
|
||||
synchronized(Phone.class) {
|
||||
if (!sMadeDefaults) {
|
||||
public static void makeDefaultPhone(Context context) {
|
||||
synchronized(Phone.class) {
|
||||
if (!sMadeDefaults) {
|
||||
sLooper = Looper.myLooper();
|
||||
sContext = context;
|
||||
|
||||
if (sLooper == null) {
|
||||
throw new RuntimeException(
|
||||
"PhoneFactory.makeDefaultPhones must be called from Looper thread");
|
||||
"PhoneFactory.makeDefaultPhone must be called from Looper thread");
|
||||
}
|
||||
|
||||
int retryCount = 0;
|
||||
@@ -109,7 +84,7 @@ public class PhoneFactory
|
||||
break;
|
||||
} else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
|
||||
throw new RuntimeException("PhoneFactory probably already running");
|
||||
}else {
|
||||
} else {
|
||||
try {
|
||||
Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
|
||||
} catch (InterruptedException er) {
|
||||
@@ -119,44 +94,71 @@ public class PhoneFactory
|
||||
|
||||
sPhoneNotifier = new DefaultPhoneNotifier();
|
||||
|
||||
if ((SystemProperties.get("ro.radio.noril","")).equals("")) {
|
||||
useNewRIL(context);
|
||||
} else {
|
||||
GSMPhone phone;
|
||||
phone = new GSMPhone(context, new SimulatedCommands(), sPhoneNotifier);
|
||||
registerPhone (phone);
|
||||
}
|
||||
//Get preferredNetworkMode from Settings.System
|
||||
int networkMode = Settings.Secure.getInt(context.getContentResolver(),
|
||||
Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode);
|
||||
Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode));
|
||||
|
||||
//Get preferredNetworkMode from Settings.System
|
||||
int cdmaSubscription = Settings.Secure.getInt(context.getContentResolver(),
|
||||
Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION, preferredCdmaSubscription);
|
||||
Log.i(LOG_TAG, "Cdma Subscription set to " + Integer.toString(cdmaSubscription));
|
||||
|
||||
//reads the system properties and makes commandsinterface
|
||||
sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
|
||||
|
||||
switch(networkMode) {
|
||||
case RILConstants.NETWORK_MODE_WCDMA_PREF:
|
||||
case RILConstants.NETWORK_MODE_GSM_ONLY:
|
||||
case RILConstants.NETWORK_MODE_WCDMA_ONLY:
|
||||
case RILConstants.NETWORK_MODE_GSM_UMTS:
|
||||
sProxyPhone = new PhoneProxy(new GSMPhone(context,
|
||||
sCommandsInterface, sPhoneNotifier));
|
||||
Log.i(LOG_TAG, "Creating GSMPhone");
|
||||
break;
|
||||
case RILConstants.NETWORK_MODE_CDMA:
|
||||
case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
|
||||
case RILConstants.NETWORK_MODE_EVDO_NO_CDMA:
|
||||
sProxyPhone = new PhoneProxy(new CDMAPhone(context,
|
||||
sCommandsInterface, sPhoneNotifier));
|
||||
Log.i(LOG_TAG, "Creating CDMAPhone");
|
||||
break;
|
||||
case RILConstants.NETWORK_MODE_GLOBAL:
|
||||
default:
|
||||
sProxyPhone = new PhoneProxy(new CDMAPhone(context,
|
||||
sCommandsInterface, sPhoneNotifier));
|
||||
Log.i(LOG_TAG, "Creating CDMAPhone");
|
||||
}
|
||||
sMadeDefaults = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Phone getDefaultPhone()
|
||||
{
|
||||
public static Phone getDefaultPhone() {
|
||||
if (sLooper != Looper.myLooper()) {
|
||||
throw new RuntimeException(
|
||||
"PhoneFactory.getDefaultPhone must be called from Looper thread");
|
||||
}
|
||||
|
||||
if (!sMadeDefaults) {
|
||||
throw new IllegalStateException("Default phones haven't been made yet!");
|
||||
}
|
||||
return sProxyPhone;
|
||||
}
|
||||
|
||||
if (sLooper != Looper.myLooper()) {
|
||||
throw new RuntimeException(
|
||||
"PhoneFactory.getDefaultPhone must be called from Looper thread");
|
||||
}
|
||||
|
||||
synchronized (sPhones) {
|
||||
return sPhones.isEmpty() ? null : sPhones.get(0);
|
||||
public static Phone getCdmaPhone() {
|
||||
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
|
||||
Phone phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier);
|
||||
return phone;
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerPhone(Phone p)
|
||||
{
|
||||
if (sLooper != Looper.myLooper()) {
|
||||
throw new RuntimeException(
|
||||
"PhoneFactory.getDefaultPhone must be called from Looper thread");
|
||||
}
|
||||
synchronized (sPhones) {
|
||||
sPhones.add(p);
|
||||
|
||||
public static Phone getGsmPhone() {
|
||||
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
|
||||
Phone phone = new GSMPhone(sContext, sCommandsInterface, sPhoneNotifier);
|
||||
return phone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
675
telephony/java/com/android/internal/telephony/PhoneProxy.java
Normal file
675
telephony/java/com/android/internal/telephony/PhoneProxy.java
Normal file
@@ -0,0 +1,675 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.telephony.CellLocation;
|
||||
import android.telephony.ServiceState;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.cdma.CDMAPhone;
|
||||
import com.android.internal.telephony.gsm.GSMPhone;
|
||||
import com.android.internal.telephony.gsm.NetworkInfo;
|
||||
import com.android.internal.telephony.gsm.PdpConnection;
|
||||
import com.android.internal.telephony.test.SimulatedRadioControl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PhoneProxy extends Handler implements Phone {
|
||||
public final static Object lockForRadioTechnologyChange = new Object();
|
||||
// private static boolean radioTechnologyChangeGsmToCdma = false;
|
||||
// private static boolean radioTechnologyChangeCdmaToGsm = false;
|
||||
|
||||
private Phone mActivePhone;
|
||||
private String mOutgoingPhone;
|
||||
private CommandsInterface mCommandsInterface;
|
||||
private IccSmsInterfaceManagerProxy mIccSmsInterfaceManagerProxy;
|
||||
private IccPhoneBookInterfaceManagerProxy mIccPhoneBookInterfaceManagerProxy;
|
||||
private PhoneSubInfoProxy mPhoneSubInfoProxy;
|
||||
|
||||
private static final int EVENT_RADIO_TECHNOLOGY_CHANGED = 1;
|
||||
private static final String LOG_TAG = "PHONE";
|
||||
|
||||
//***** Class Methods
|
||||
public PhoneProxy(Phone phone) {
|
||||
mActivePhone = phone;
|
||||
mIccSmsInterfaceManagerProxy = new IccSmsInterfaceManagerProxy(
|
||||
phone.getIccSmsInterfaceManager());
|
||||
mIccPhoneBookInterfaceManagerProxy = new IccPhoneBookInterfaceManagerProxy(
|
||||
phone.getIccPhoneBookInterfaceManager());
|
||||
mPhoneSubInfoProxy = new PhoneSubInfoProxy(phone.getPhoneSubInfo());
|
||||
mCommandsInterface = ((PhoneBase)mActivePhone).mCM;
|
||||
mCommandsInterface.registerForRadioTechnologyChanged(
|
||||
this, EVENT_RADIO_TECHNOLOGY_CHANGED, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch(msg.what) {
|
||||
case EVENT_RADIO_TECHNOLOGY_CHANGED:
|
||||
//switch Phone from CDMA to GSM or vice versa
|
||||
mOutgoingPhone = ((PhoneBase)mActivePhone).getPhoneName();
|
||||
logd("Switching phone from " + mOutgoingPhone + "Phone to " +
|
||||
(mOutgoingPhone.equals("GSM") ? "CDMAPhone" : "GSMPhone") );
|
||||
boolean oldPowerState = false; //old power state to off
|
||||
if (mCommandsInterface.getRadioState().isOn()) {
|
||||
oldPowerState = true;
|
||||
logd("Setting Radio Power to Off");
|
||||
mCommandsInterface.setRadioPower(false, null);
|
||||
}
|
||||
if(mOutgoingPhone.equals("GSM")) {
|
||||
logd("Make a new CDMAPhone and destroy the old GSMPhone.");
|
||||
|
||||
((GSMPhone)mActivePhone).dispose();
|
||||
Phone oldPhone = mActivePhone;
|
||||
|
||||
//Give the garbage collector a hint to start the garbage collection asap
|
||||
// NOTE this has been disabled since radio technology change could happen during
|
||||
// e.g. a multimedia playing and could slow the system. Tests needs to be done
|
||||
// to see the effects of the GC call here when system is busy.
|
||||
//System.gc();
|
||||
|
||||
mActivePhone = PhoneFactory.getCdmaPhone();
|
||||
logd("Resetting Radio");
|
||||
mCommandsInterface.setRadioPower(oldPowerState, null);
|
||||
((GSMPhone)oldPhone).removeReferences();
|
||||
oldPhone = null;
|
||||
} else {
|
||||
logd("Make a new GSMPhone and destroy the old CDMAPhone.");
|
||||
|
||||
((CDMAPhone)mActivePhone).dispose();
|
||||
//mActivePhone = null;
|
||||
Phone oldPhone = mActivePhone;
|
||||
|
||||
// Give the GC a hint to start the garbage collection asap
|
||||
// NOTE this has been disabled since radio technology change could happen during
|
||||
// e.g. a multimedia playing and could slow the system. Tests needs to be done
|
||||
// to see the effects of the GC call here when system is busy.
|
||||
//System.gc();
|
||||
|
||||
mActivePhone = PhoneFactory.getGsmPhone();
|
||||
logd("Resetting Radio:");
|
||||
mCommandsInterface.setRadioPower(oldPowerState, null);
|
||||
((CDMAPhone)oldPhone).removeReferences();
|
||||
oldPhone = null;
|
||||
}
|
||||
|
||||
//Set the new interfaces in the proxy's
|
||||
mIccSmsInterfaceManagerProxy.setmIccSmsInterfaceManager(
|
||||
mActivePhone.getIccSmsInterfaceManager());
|
||||
mIccPhoneBookInterfaceManagerProxy.setmIccPhoneBookInterfaceManager(
|
||||
mActivePhone.getIccPhoneBookInterfaceManager());
|
||||
mPhoneSubInfoProxy.setmPhoneSubInfo(this.mActivePhone.getPhoneSubInfo());
|
||||
mCommandsInterface = ((PhoneBase)mActivePhone).mCM;
|
||||
|
||||
//Send an Intent to the PhoneApp that we had a radio technology change
|
||||
Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
|
||||
intent.putExtra(Phone.PHONE_NAME_KEY, mActivePhone.getPhoneName());
|
||||
ActivityManagerNative.broadcastStickyIntent(intent, null);
|
||||
|
||||
break;
|
||||
default:
|
||||
Log.e(LOG_TAG, "Error! This handler was not registered for this message type. Message: "
|
||||
+ msg.what);
|
||||
break;
|
||||
}
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
|
||||
private void logv(String msg) {
|
||||
Log.v(LOG_TAG, "[PhoneProxy] " + msg);
|
||||
}
|
||||
|
||||
private void logd(String msg) {
|
||||
Log.d(LOG_TAG, "[PhoneProxy] " + msg);
|
||||
}
|
||||
|
||||
private void logw(String msg) {
|
||||
Log.w(LOG_TAG, "[PhoneProxy] " + msg);
|
||||
}
|
||||
|
||||
private void loge(String msg) {
|
||||
Log.e(LOG_TAG, "[PhoneProxy] " + msg);
|
||||
}
|
||||
|
||||
|
||||
public ServiceState getServiceState() {
|
||||
return mActivePhone.getServiceState();
|
||||
}
|
||||
|
||||
public CellLocation getCellLocation() {
|
||||
return mActivePhone.getCellLocation();
|
||||
}
|
||||
|
||||
public DataState getDataConnectionState() {
|
||||
return mActivePhone.getDataConnectionState();
|
||||
}
|
||||
|
||||
public DataActivityState getDataActivityState() {
|
||||
return mActivePhone.getDataActivityState();
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mActivePhone.getContext();
|
||||
}
|
||||
|
||||
public void disableDnsCheck(boolean b) {
|
||||
mActivePhone.disableDnsCheck(b);
|
||||
}
|
||||
|
||||
public boolean isDnsCheckDisabled() {
|
||||
return mActivePhone.isDnsCheckDisabled();
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return mActivePhone.getState();
|
||||
}
|
||||
|
||||
public String getPhoneName() {
|
||||
return mActivePhone.getPhoneName();
|
||||
}
|
||||
|
||||
public String[] getActiveApnTypes() {
|
||||
return mActivePhone.getActiveApnTypes();
|
||||
}
|
||||
|
||||
public String getActiveApn() {
|
||||
return mActivePhone.getActiveApn();
|
||||
}
|
||||
|
||||
public int getSignalStrengthASU() {
|
||||
return mActivePhone.getSignalStrengthASU();
|
||||
}
|
||||
|
||||
public void registerForUnknownConnection(Handler h, int what, Object obj) {
|
||||
mActivePhone.registerForUnknownConnection(h, what, obj);
|
||||
}
|
||||
|
||||
public void unregisterForUnknownConnection(Handler h) {
|
||||
mActivePhone.unregisterForUnknownConnection(h);
|
||||
}
|
||||
|
||||
public void registerForPhoneStateChanged(Handler h, int what, Object obj) {
|
||||
mActivePhone.registerForPhoneStateChanged(h, what, obj);
|
||||
}
|
||||
|
||||
public void unregisterForPhoneStateChanged(Handler h) {
|
||||
mActivePhone.unregisterForPhoneStateChanged(h);
|
||||
}
|
||||
|
||||
public void registerForNewRingingConnection(Handler h, int what, Object obj) {
|
||||
mActivePhone.registerForNewRingingConnection(h, what, obj);
|
||||
}
|
||||
|
||||
public void unregisterForNewRingingConnection(Handler h) {
|
||||
mActivePhone.unregisterForNewRingingConnection(h);
|
||||
}
|
||||
|
||||
public void registerForIncomingRing(Handler h, int what, Object obj) {
|
||||
mActivePhone.registerForIncomingRing(h, what, obj);
|
||||
}
|
||||
|
||||
public void unregisterForIncomingRing(Handler h) {
|
||||
mActivePhone.unregisterForIncomingRing(h);
|
||||
}
|
||||
|
||||
public void registerForDisconnect(Handler h, int what, Object obj) {
|
||||
mActivePhone.registerForDisconnect(h, what, obj);
|
||||
}
|
||||
|
||||
public void unregisterForDisconnect(Handler h) {
|
||||
mActivePhone.unregisterForDisconnect(h);
|
||||
}
|
||||
|
||||
public void registerForMmiInitiate(Handler h, int what, Object obj) {
|
||||
mActivePhone.registerForMmiInitiate(h, what, obj);
|
||||
}
|
||||
|
||||
public void unregisterForMmiInitiate(Handler h) {
|
||||
mActivePhone.unregisterForMmiInitiate(h);
|
||||
}
|
||||
|
||||
public void registerForMmiComplete(Handler h, int what, Object obj) {
|
||||
mActivePhone.registerForMmiComplete(h, what, obj);
|
||||
}
|
||||
|
||||
public void unregisterForMmiComplete(Handler h) {
|
||||
mActivePhone.unregisterForMmiComplete(h);
|
||||
}
|
||||
|
||||
public List<? extends MmiCode> getPendingMmiCodes() {
|
||||
return mActivePhone.getPendingMmiCodes();
|
||||
}
|
||||
|
||||
public void sendUssdResponse(String ussdMessge) {
|
||||
mActivePhone.sendUssdResponse(ussdMessge);
|
||||
}
|
||||
|
||||
public void registerForServiceStateChanged(Handler h, int what, Object obj) {
|
||||
mActivePhone.registerForServiceStateChanged(h, what, obj);
|
||||
}
|
||||
|
||||
public void unregisterForServiceStateChanged(Handler h) {
|
||||
mActivePhone.unregisterForServiceStateChanged(h);
|
||||
}
|
||||
|
||||
public void registerForSuppServiceNotification(Handler h, int what, Object obj) {
|
||||
mActivePhone.registerForSuppServiceNotification(h, what, obj);
|
||||
}
|
||||
|
||||
public void unregisterForSuppServiceNotification(Handler h) {
|
||||
mActivePhone.unregisterForSuppServiceNotification(h);
|
||||
}
|
||||
|
||||
public void registerForSuppServiceFailed(Handler h, int what, Object obj) {
|
||||
mActivePhone.registerForSuppServiceFailed(h, what, obj);
|
||||
}
|
||||
|
||||
public void unregisterForSuppServiceFailed(Handler h) {
|
||||
mActivePhone.unregisterForSuppServiceFailed(h);
|
||||
}
|
||||
|
||||
public void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj){
|
||||
mActivePhone.registerForInCallVoicePrivacyOn(h,what,obj);
|
||||
}
|
||||
|
||||
public void unregisterForInCallVoicePrivacyOn(Handler h){
|
||||
mActivePhone.unregisterForInCallVoicePrivacyOn(h);
|
||||
}
|
||||
|
||||
public void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj){
|
||||
mActivePhone.registerForInCallVoicePrivacyOff(h,what,obj);
|
||||
}
|
||||
|
||||
public void unregisterForInCallVoicePrivacyOff(Handler h){
|
||||
mActivePhone.unregisterForInCallVoicePrivacyOff(h);
|
||||
}
|
||||
|
||||
public boolean getIccRecordsLoaded() {
|
||||
return mActivePhone.getIccRecordsLoaded();
|
||||
}
|
||||
|
||||
public IccCard getIccCard() {
|
||||
return mActivePhone.getIccCard();
|
||||
}
|
||||
|
||||
public void acceptCall() throws CallStateException {
|
||||
mActivePhone.acceptCall();
|
||||
}
|
||||
|
||||
public void rejectCall() throws CallStateException {
|
||||
mActivePhone.rejectCall();
|
||||
}
|
||||
|
||||
public void switchHoldingAndActive() throws CallStateException {
|
||||
mActivePhone.switchHoldingAndActive();
|
||||
}
|
||||
|
||||
public boolean canConference() {
|
||||
return mActivePhone.canConference();
|
||||
}
|
||||
|
||||
public void conference() throws CallStateException {
|
||||
mActivePhone.conference();
|
||||
}
|
||||
|
||||
public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
|
||||
mActivePhone.enableEnhancedVoicePrivacy(enable, onComplete);
|
||||
}
|
||||
|
||||
public void getEnhancedVoicePrivacy(Message onComplete) {
|
||||
mActivePhone.getEnhancedVoicePrivacy(onComplete);
|
||||
}
|
||||
|
||||
public boolean canTransfer() {
|
||||
return mActivePhone.canTransfer();
|
||||
}
|
||||
|
||||
public void explicitCallTransfer() throws CallStateException {
|
||||
mActivePhone.explicitCallTransfer();
|
||||
}
|
||||
|
||||
public void clearDisconnected() {
|
||||
mActivePhone.clearDisconnected();
|
||||
}
|
||||
|
||||
public Call getForegroundCall() {
|
||||
return mActivePhone.getForegroundCall();
|
||||
}
|
||||
|
||||
public Call getBackgroundCall() {
|
||||
return mActivePhone.getBackgroundCall();
|
||||
}
|
||||
|
||||
public Call getRingingCall() {
|
||||
return mActivePhone.getRingingCall();
|
||||
}
|
||||
|
||||
public Connection dial(String dialString) throws CallStateException {
|
||||
return mActivePhone.dial(dialString);
|
||||
}
|
||||
|
||||
public boolean handlePinMmi(String dialString) {
|
||||
return mActivePhone.handlePinMmi(dialString);
|
||||
}
|
||||
|
||||
public boolean handleInCallMmiCommands(String command) throws CallStateException {
|
||||
return mActivePhone.handleInCallMmiCommands(command);
|
||||
}
|
||||
|
||||
public void sendDtmf(char c) {
|
||||
mActivePhone.sendDtmf(c);
|
||||
}
|
||||
|
||||
public void startDtmf(char c) {
|
||||
mActivePhone.startDtmf(c);
|
||||
}
|
||||
|
||||
public void stopDtmf() {
|
||||
mActivePhone.stopDtmf();
|
||||
}
|
||||
|
||||
public void setRadioPower(boolean power) {
|
||||
mActivePhone.setRadioPower(power);
|
||||
}
|
||||
|
||||
public boolean getMessageWaitingIndicator() {
|
||||
return mActivePhone.getMessageWaitingIndicator();
|
||||
}
|
||||
|
||||
public boolean getCallForwardingIndicator() {
|
||||
return mActivePhone.getCallForwardingIndicator();
|
||||
}
|
||||
|
||||
public String getLine1Number() {
|
||||
return mActivePhone.getLine1Number();
|
||||
}
|
||||
|
||||
public String getLine1AlphaTag() {
|
||||
return mActivePhone.getLine1AlphaTag();
|
||||
}
|
||||
|
||||
public void setLine1Number(String alphaTag, String number, Message onComplete) {
|
||||
mActivePhone.setLine1Number(alphaTag, number, onComplete);
|
||||
}
|
||||
|
||||
public String getVoiceMailNumber() {
|
||||
return mActivePhone.getVoiceMailNumber();
|
||||
}
|
||||
|
||||
public String getVoiceMailAlphaTag() {
|
||||
return mActivePhone.getVoiceMailAlphaTag();
|
||||
}
|
||||
|
||||
public void setVoiceMailNumber(String alphaTag,String voiceMailNumber,
|
||||
Message onComplete) {
|
||||
mActivePhone.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete);
|
||||
}
|
||||
|
||||
public void getCallForwardingOption(int commandInterfaceCFReason,
|
||||
Message onComplete) {
|
||||
mActivePhone.getCallForwardingOption(commandInterfaceCFReason,
|
||||
onComplete);
|
||||
}
|
||||
|
||||
public void setCallForwardingOption(int commandInterfaceCFReason,
|
||||
int commandInterfaceCFAction, String dialingNumber,
|
||||
int timerSeconds, Message onComplete) {
|
||||
mActivePhone.setCallForwardingOption(commandInterfaceCFReason,
|
||||
commandInterfaceCFAction, dialingNumber, timerSeconds, onComplete);
|
||||
}
|
||||
|
||||
public void getOutgoingCallerIdDisplay(Message onComplete) {
|
||||
mActivePhone.getOutgoingCallerIdDisplay(onComplete);
|
||||
}
|
||||
|
||||
public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
|
||||
Message onComplete) {
|
||||
mActivePhone.setOutgoingCallerIdDisplay(commandInterfaceCLIRMode,
|
||||
onComplete);
|
||||
}
|
||||
|
||||
public void getCallWaiting(Message onComplete) {
|
||||
mActivePhone.getCallWaiting(onComplete);
|
||||
}
|
||||
|
||||
public void setCallWaiting(boolean enable, Message onComplete) {
|
||||
mActivePhone.setCallWaiting(enable, onComplete);
|
||||
}
|
||||
|
||||
public void getAvailableNetworks(Message response) {
|
||||
mActivePhone.getAvailableNetworks(response);
|
||||
}
|
||||
|
||||
public void setNetworkSelectionModeAutomatic(Message response) {
|
||||
mActivePhone.setNetworkSelectionModeAutomatic(response);
|
||||
}
|
||||
|
||||
public void selectNetworkManually(NetworkInfo network, Message response) {
|
||||
mActivePhone.selectNetworkManually(network, response);
|
||||
}
|
||||
|
||||
public void setPreferredNetworkType(int networkType, Message response) {
|
||||
mActivePhone.setPreferredNetworkType(networkType, response);
|
||||
}
|
||||
|
||||
public void getPreferredNetworkType(Message response) {
|
||||
mActivePhone.getPreferredNetworkType(response);
|
||||
}
|
||||
|
||||
public void getNeighboringCids(Message response) {
|
||||
mActivePhone.getNeighboringCids(response);
|
||||
}
|
||||
|
||||
public void setOnPostDialCharacter(Handler h, int what, Object obj) {
|
||||
mActivePhone.setOnPostDialCharacter(h, what, obj);
|
||||
}
|
||||
|
||||
public void setMute(boolean muted) {
|
||||
mActivePhone.setMute(muted);
|
||||
}
|
||||
|
||||
public boolean getMute() {
|
||||
return mActivePhone.getMute();
|
||||
}
|
||||
|
||||
public void invokeOemRilRequestRaw(byte[] data, Message response) {
|
||||
mActivePhone.invokeOemRilRequestRaw(data, response);
|
||||
}
|
||||
|
||||
public void invokeOemRilRequestStrings(String[] strings, Message response) {
|
||||
mActivePhone.invokeOemRilRequestStrings(strings, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public void getPdpContextList(Message response) {
|
||||
mActivePhone.getPdpContextList(response);
|
||||
}
|
||||
|
||||
public void getDataCallList(Message response) {
|
||||
mActivePhone.getDataCallList(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public List<PdpConnection> getCurrentPdpList() {
|
||||
return mActivePhone.getCurrentPdpList();
|
||||
}
|
||||
|
||||
public List<DataConnection> getCurrentDataConnectionList() {
|
||||
return mActivePhone.getCurrentDataConnectionList();
|
||||
}
|
||||
|
||||
public void updateServiceLocation(Message response) {
|
||||
mActivePhone.updateServiceLocation(response);
|
||||
}
|
||||
|
||||
public void enableLocationUpdates() {
|
||||
mActivePhone.enableLocationUpdates();
|
||||
}
|
||||
|
||||
public void disableLocationUpdates() {
|
||||
mActivePhone.disableLocationUpdates();
|
||||
}
|
||||
|
||||
public void setUnitTestMode(boolean f) {
|
||||
mActivePhone.setUnitTestMode(f);
|
||||
}
|
||||
|
||||
public boolean getUnitTestMode() {
|
||||
return mActivePhone.getUnitTestMode();
|
||||
}
|
||||
|
||||
public void setBandMode(int bandMode, Message response) {
|
||||
mActivePhone.setBandMode(bandMode, response);
|
||||
}
|
||||
|
||||
public void queryAvailableBandMode(Message response) {
|
||||
mActivePhone.queryAvailableBandMode(response);
|
||||
}
|
||||
|
||||
public boolean getDataRoamingEnabled() {
|
||||
return mActivePhone.getDataRoamingEnabled();
|
||||
}
|
||||
|
||||
public void setDataRoamingEnabled(boolean enable) {
|
||||
mActivePhone.setDataRoamingEnabled(enable);
|
||||
}
|
||||
|
||||
public void queryCdmaRoamingPreference(Message response) {
|
||||
mActivePhone.queryCdmaRoamingPreference(response);
|
||||
}
|
||||
|
||||
public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
|
||||
mActivePhone.setCdmaRoamingPreference(cdmaRoamingType, response);
|
||||
}
|
||||
|
||||
public void setCdmaSubscription(int cdmaSubscriptionType, Message response) {
|
||||
mActivePhone.setCdmaSubscription(cdmaSubscriptionType, response);
|
||||
}
|
||||
|
||||
public SimulatedRadioControl getSimulatedRadioControl() {
|
||||
return mActivePhone.getSimulatedRadioControl();
|
||||
}
|
||||
|
||||
public boolean enableDataConnectivity() {
|
||||
return mActivePhone.enableDataConnectivity();
|
||||
}
|
||||
|
||||
public boolean disableDataConnectivity() {
|
||||
return mActivePhone.disableDataConnectivity();
|
||||
}
|
||||
|
||||
public int enableApnType(String type) {
|
||||
return mActivePhone.enableApnType(type);
|
||||
}
|
||||
|
||||
public int disableApnType(String type) {
|
||||
return mActivePhone.disableApnType(type);
|
||||
}
|
||||
|
||||
public boolean isDataConnectivityPossible() {
|
||||
return mActivePhone.isDataConnectivityPossible();
|
||||
}
|
||||
|
||||
public String getInterfaceName(String apnType) {
|
||||
return mActivePhone.getInterfaceName(apnType);
|
||||
}
|
||||
|
||||
public String getIpAddress(String apnType) {
|
||||
return mActivePhone.getIpAddress(apnType);
|
||||
}
|
||||
|
||||
public String getGateway(String apnType) {
|
||||
return mActivePhone.getGateway(apnType);
|
||||
}
|
||||
|
||||
public String[] getDnsServers(String apnType) {
|
||||
return mActivePhone.getDnsServers(apnType);
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return mActivePhone.getDeviceId();
|
||||
}
|
||||
|
||||
public String getDeviceSvn() {
|
||||
return mActivePhone.getDeviceSvn();
|
||||
}
|
||||
|
||||
public String getSubscriberId() {
|
||||
return mActivePhone.getSubscriberId();
|
||||
}
|
||||
|
||||
public String getIccSerialNumber() {
|
||||
return mActivePhone.getIccSerialNumber();
|
||||
}
|
||||
|
||||
public String getEsn() {
|
||||
return mActivePhone.getEsn();
|
||||
}
|
||||
|
||||
public String getMeid() {
|
||||
return mActivePhone.getMeid();
|
||||
}
|
||||
|
||||
public PhoneSubInfo getPhoneSubInfo(){
|
||||
return mActivePhone.getPhoneSubInfo();
|
||||
}
|
||||
|
||||
public IccSmsInterfaceManager getIccSmsInterfaceManager(){
|
||||
return mActivePhone.getIccSmsInterfaceManager();
|
||||
}
|
||||
|
||||
public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
|
||||
return mActivePhone.getIccPhoneBookInterfaceManager();
|
||||
}
|
||||
|
||||
public void setTTYModeEnabled(boolean enable, Message onComplete) {
|
||||
mActivePhone.setTTYModeEnabled(enable, onComplete);
|
||||
}
|
||||
|
||||
public void queryTTYModeEnabled(Message onComplete) {
|
||||
mActivePhone.queryTTYModeEnabled(onComplete);
|
||||
}
|
||||
|
||||
public void activateCellBroadcastSms(int activate, Message response) {
|
||||
mActivePhone.activateCellBroadcastSms(activate, response);
|
||||
}
|
||||
|
||||
public void getCellBroadcastSmsConfig(Message response) {
|
||||
mActivePhone.getCellBroadcastSmsConfig(response);
|
||||
}
|
||||
|
||||
public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response) {
|
||||
mActivePhone.setCellBroadcastSmsConfig(configValuesArray, response);
|
||||
}
|
||||
|
||||
public void notifyDataActivity() {
|
||||
mActivePhone.notifyDataActivity();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ import android.util.Log;
|
||||
*
|
||||
* Use android.telephony.TelephonyManager and PhoneStateListener instead.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public final class PhoneStateIntentReceiver extends BroadcastReceiver {
|
||||
private static final String LOG_TAG = "PhoneStateIntRecv";
|
||||
private static final String LOG_TAG = "PHONE";
|
||||
private static final boolean DBG = false;
|
||||
|
||||
public static final String INTENT_KEY_ASU = "asu";
|
||||
@@ -182,7 +182,7 @@ public final class PhoneStateIntentReceiver extends BroadcastReceiver {
|
||||
if (TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED.equals(action)) {
|
||||
mAsu = intent.getIntExtra(INTENT_KEY_ASU, mAsu);
|
||||
if (DBG) Log.d(LOG_TAG, "onReceiveIntent: set asu=" + mAsu);
|
||||
|
||||
|
||||
if (mTarget != null && getNotifySignalStrength()) {
|
||||
Message message = Message.obtain(mTarget, mAsuEventWhat);
|
||||
mTarget.sendMessage(message);
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.ServiceManager;
|
||||
import com.android.internal.telephony.*;
|
||||
import android.util.Log;
|
||||
|
||||
public class PhoneSubInfo extends IPhoneSubInfo.Stub {
|
||||
static final String LOG_TAG = "PHONE";
|
||||
private Phone mPhone;
|
||||
private Context mContext;
|
||||
private static final String READ_PHONE_STATE =
|
||||
@@ -13,10 +28,17 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub {
|
||||
public PhoneSubInfo(Phone phone) {
|
||||
mPhone = phone;
|
||||
mContext = phone.getContext();
|
||||
ServiceManager.addService("iphonesubinfo", this);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
Log.d(LOG_TAG, "PhoneSubInfo finalized");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the unique device ID, e.g., IMEI for GSM phones.
|
||||
* Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones.
|
||||
*/
|
||||
public String getDeviceId() {
|
||||
mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
|
||||
@@ -41,11 +63,11 @@ public class PhoneSubInfo extends IPhoneSubInfo.Stub {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the serial number of the SIM, if applicable.
|
||||
* Retrieves the serial number of the ICC, if applicable.
|
||||
*/
|
||||
public String getSimSerialNumber() {
|
||||
public String getIccSerialNumber() {
|
||||
mContext.enforceCallingOrSelfPermission(READ_PHONE_STATE, "Requires READ_PHONE_STATE");
|
||||
return mPhone.getSimSerialNumber();
|
||||
return mPhone.getIccSerialNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.os.ServiceManager;
|
||||
|
||||
|
||||
public class PhoneSubInfoProxy extends IPhoneSubInfo.Stub {
|
||||
private PhoneSubInfo mPhoneSubInfo;
|
||||
|
||||
public PhoneSubInfoProxy(PhoneSubInfo phoneSubInfo) {
|
||||
mPhoneSubInfo = phoneSubInfo;
|
||||
if(ServiceManager.getService("iphonesubinfo") == null) {
|
||||
ServiceManager.addService("iphonesubinfo", this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setmPhoneSubInfo(PhoneSubInfo phoneSubInfo) {
|
||||
this.mPhoneSubInfo = phoneSubInfo;
|
||||
}
|
||||
|
||||
public String getDeviceId() {
|
||||
return mPhoneSubInfo.getDeviceId();
|
||||
}
|
||||
|
||||
public String getDeviceSvn() {
|
||||
return mPhoneSubInfo.getDeviceSvn();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones.
|
||||
*/
|
||||
public String getSubscriberId() {
|
||||
return mPhoneSubInfo.getSubscriberId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the serial number of the ICC, if applicable.
|
||||
*/
|
||||
public String getIccSerialNumber() {
|
||||
return mPhoneSubInfo.getIccSerialNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the phone number string for line 1.
|
||||
*/
|
||||
public String getLine1Number() {
|
||||
return mPhoneSubInfo.getLine1Number();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the alpha identifier for line 1.
|
||||
*/
|
||||
public String getLine1AlphaTag() {
|
||||
return mPhoneSubInfo.getLine1AlphaTag();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the voice mail number.
|
||||
*/
|
||||
public String getVoiceMailNumber() {
|
||||
return mPhoneSubInfo.getVoiceMailNumber();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the alpha identifier associated with the voice mail number.
|
||||
*/
|
||||
public String getVoiceMailAlphaTag() {
|
||||
return mPhoneSubInfo.getVoiceMailAlphaTag();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,29 +14,62 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
interface RILConstants
|
||||
{
|
||||
public interface RILConstants {
|
||||
// From the top of ril.cpp
|
||||
int RIL_ERRNO_INVALID_RESPONSE = -1;
|
||||
|
||||
// from RIL_Errno
|
||||
int SUCCESS = 0;
|
||||
int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */
|
||||
int RADIO_NOT_AVAILABLE = 1; /* If radio did not start or is resetting */
|
||||
int GENERIC_FAILURE = 2;
|
||||
int PASSWORD_INCORRECT = 3; /* for PIN/PIN2 methods only! */
|
||||
int SIM_PIN2 = 4; /* Operation requires SIM PIN2 to be entered */
|
||||
int SIM_PUK2 = 5; /* Operation requires SIM PIN2 to be entered */
|
||||
int PASSWORD_INCORRECT = 3; /* for PIN/PIN2 methods only! */
|
||||
int SIM_PIN2 = 4; /* Operation requires SIM PIN2 to be entered */
|
||||
int SIM_PUK2 = 5; /* Operation requires SIM PIN2 to be entered */
|
||||
int REQUEST_NOT_SUPPORTED = 6;
|
||||
int REQUEST_CANCELLED = 7;
|
||||
int OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; /* data operation is not allowed during voice call in class C */
|
||||
int OP_NOT_ALLOWED_BEFORE_REG_NW = 9; /* request is not allowed before device registers to network */
|
||||
int SMS_SEND_FAIL_RETRY = 10; /* send sms fail and need retry */
|
||||
int OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; /* data operation is not allowed during voice call in
|
||||
class C */
|
||||
int OP_NOT_ALLOWED_BEFORE_REG_NW = 9; /* request is not allowed before device registers to
|
||||
network */
|
||||
int SMS_SEND_FAIL_RETRY = 10; /* send sms fail and need retry */
|
||||
|
||||
/* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
|
||||
int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */
|
||||
int NETWORK_MODE_GSM_ONLY = 1; /* GSM only */
|
||||
int NETWORK_MODE_WCDMA_ONLY = 2; /* WCDMA only */
|
||||
int NETWORK_MODE_GSM_UMTS = 3; /* GSM/WCDMA (auto mode, according to PRL)
|
||||
AVAILABLE Application Settings menu*/
|
||||
int NETWORK_MODE_CDMA = 4; /* CDMA and EvDo (auto mode, according to PRL)
|
||||
AVAILABLE Application Settings menu*/
|
||||
int NETWORK_MODE_CDMA_NO_EVDO = 5; /* CDMA only */
|
||||
int NETWORK_MODE_EVDO_NO_CDMA = 6; /* EvDo only */
|
||||
int NETWORK_MODE_GLOBAL = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL)
|
||||
AVAILABLE Application Settings menu*/
|
||||
int PREFERRED_NETWORK_MODE = NETWORK_MODE_GLOBAL;
|
||||
|
||||
/* CDMA subscription source. See ril.h RIL_REQUEST_CDMA_SET_SUBSCRIPTION */
|
||||
int SUBSCRIPTION_FROM_RUIM = 0; /* CDMA subscription from RUIM when available */
|
||||
int SUBSCRIPTION_FROM_NV = 1; /* CDMA subscription from NV */
|
||||
int PREFERRED_CDMA_SUBSCRIPTION = SUBSCRIPTION_FROM_NV;
|
||||
|
||||
int CDMA_CELL_BROADCAST_SMS_DISABLED = 1;
|
||||
int CDMA_CELL_BROADCAST_SMS_ENABLED = 0;
|
||||
|
||||
int CDMA_PHONE = 0;
|
||||
int GSM_PHONE = 1;
|
||||
|
||||
int CDM_TTY_MODE_DISABLED = 0;
|
||||
int CDM_TTY_MODE_ENABLED = 1;
|
||||
|
||||
byte CDMA_VOICE_PRIVACY = 0x70; /* "p" value used in Ril_Call.isVoice if Privacy
|
||||
is active */
|
||||
|
||||
/*
|
||||
cat include/telephony/ril.h | \
|
||||
egrep '^#define' | \
|
||||
@@ -76,7 +109,7 @@ cat include/telephony/ril.h | \
|
||||
* Block packet data access due to restriction.
|
||||
*/
|
||||
int RIL_RESTRICTED_STATE_PS_ALL = 0x10;
|
||||
|
||||
|
||||
int RIL_REQUEST_GET_SIM_STATUS = 1;
|
||||
int RIL_REQUEST_ENTER_SIM_PIN = 2;
|
||||
int RIL_REQUEST_ENTER_SIM_PUK = 3;
|
||||
@@ -103,7 +136,7 @@ cat include/telephony/ril.h | \
|
||||
int RIL_REQUEST_DTMF = 24;
|
||||
int RIL_REQUEST_SEND_SMS = 25;
|
||||
int RIL_REQUEST_SEND_SMS_EXPECT_MORE = 26;
|
||||
int RIL_REQUEST_SETUP_DEFAULT_PDP = 27;
|
||||
int RIL_REQUEST_SETUP_DATA_CALL = 27;
|
||||
int RIL_REQUEST_SIM_IO = 28;
|
||||
int RIL_REQUEST_SEND_USSD = 29;
|
||||
int RIL_REQUEST_CANCEL_USSD = 30;
|
||||
@@ -117,7 +150,7 @@ cat include/telephony/ril.h | \
|
||||
int RIL_REQUEST_GET_IMEI = 38;
|
||||
int RIL_REQUEST_GET_IMEISV = 39;
|
||||
int RIL_REQUEST_ANSWER = 40;
|
||||
int RIL_REQUEST_DEACTIVATE_DEFAULT_PDP = 41;
|
||||
int RIL_REQUEST_DEACTIVATE_DATA_CALL = 41;
|
||||
int RIL_REQUEST_QUERY_FACILITY_LOCK = 42;
|
||||
int RIL_REQUEST_SET_FACILITY_LOCK = 43;
|
||||
int RIL_REQUEST_CHANGE_BARRING_PASSWORD = 44;
|
||||
@@ -132,8 +165,8 @@ cat include/telephony/ril.h | \
|
||||
int RIL_REQUEST_SET_MUTE = 53;
|
||||
int RIL_REQUEST_GET_MUTE = 54;
|
||||
int RIL_REQUEST_QUERY_CLIP = 55;
|
||||
int RIL_REQUEST_LAST_PDP_FAIL_CAUSE = 56;
|
||||
int RIL_REQUEST_PDP_CONTEXT_LIST = 57;
|
||||
int RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE = 56;
|
||||
int RIL_REQUEST_DATA_CALL_LIST = 57;
|
||||
int RIL_REQUEST_RESET_RADIO = 58;
|
||||
int RIL_REQUEST_OEM_HOOK_RAW = 59;
|
||||
int RIL_REQUEST_OEM_HOOK_STRINGS = 60;
|
||||
@@ -153,6 +186,28 @@ cat include/telephony/ril.h | \
|
||||
int RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE = 74;
|
||||
int RIL_REQUEST_GET_NEIGHBORING_CELL_IDS = 75;
|
||||
int RIL_REQUEST_SET_LOCATION_UPDATES = 76;
|
||||
int RIL_REQUEST_CDMA_SET_SUBSCRIPTION = 77;
|
||||
int RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE = 78;
|
||||
int RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE = 79;
|
||||
int RIL_REQUEST_SET_TTY_MODE = 80;
|
||||
int RIL_REQUEST_QUERY_TTY_MODE = 81;
|
||||
int RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE = 82;
|
||||
int RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE = 83;
|
||||
int RIL_REQUEST_CDMA_FLASH = 84;
|
||||
int RIL_REQUEST_CDMA_BURST_DTMF = 85;
|
||||
int RIL_REQUEST_CDMA_VALIDATE_AKEY = 86;
|
||||
int RIL_REQUEST_CDMA_SEND_SMS = 87;
|
||||
int RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE = 88;
|
||||
int RIL_REQUEST_GET_BROADCAST_CONFIG = 89;
|
||||
int RIL_REQUEST_SET_BROADCAST_CONFIG = 90;
|
||||
int RIL_REQUEST_BROADCAST_ACTIVATION = 91;
|
||||
int RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG = 92;
|
||||
int RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG = 93;
|
||||
int RIL_REQUEST_CDMA_BROADCAST_ACTIVATION = 94;
|
||||
int RIL_REQUEST_CDMA_SUBSCRIPTION = 99;
|
||||
int RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM = 100;
|
||||
int RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM = 101;
|
||||
int RIL_REQUEST_DEVICE_IDENTITY = 102;
|
||||
int RIL_UNSOL_RESPONSE_BASE = 1000;
|
||||
int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
|
||||
int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
|
||||
@@ -164,7 +219,7 @@ cat include/telephony/ril.h | \
|
||||
int RIL_UNSOL_ON_USSD_REQUEST = 1007;
|
||||
int RIL_UNSOL_NITZ_TIME_RECEIVED = 1008;
|
||||
int RIL_UNSOL_SIGNAL_STRENGTH = 1009;
|
||||
int RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED = 1010;
|
||||
int RIL_UNSOL_DATA_CALL_LIST_CHANGED = 1010;
|
||||
int RIL_UNSOL_SUPP_SVC_NOTIFICATION = 1011;
|
||||
int RIL_UNSOL_STK_SESSION_END = 1012;
|
||||
int RIL_UNSOL_STK_PROACTIVE_COMMAND = 1013;
|
||||
@@ -173,5 +228,9 @@ cat include/telephony/ril.h | \
|
||||
int RIL_UNSOL_SIM_SMS_STORAGE_FULL = 1016;
|
||||
int RIL_UNSOL_SIM_REFRESH = 1017;
|
||||
int RIL_UNSOL_CALL_RING = 1018;
|
||||
int RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED = 1019;
|
||||
int RIL_UNSOL_RESPONSE_CDMA_NEW_SMS = 1020;
|
||||
int RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS = 1021;
|
||||
int RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL = 1022;
|
||||
int RIL_UNSOL_RESTRICTED_STATE_CHANGED = 1023;
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
@@ -32,19 +32,21 @@ import android.net.Uri;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
import android.provider.Telephony;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Telephony.Sms.Intents;
|
||||
import android.telephony.gsm.SmsMessage;
|
||||
import android.telephony.gsm.SmsManager;
|
||||
import com.android.internal.telephony.WapPushOverSms;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.SmsMessage;
|
||||
import android.telephony.ServiceState;
|
||||
import android.util.Config;
|
||||
import com.android.internal.util.HexDump;
|
||||
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;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -52,58 +54,61 @@ import java.util.Random;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
final class SMSDispatcher extends Handler {
|
||||
private static final String TAG = "GSM";
|
||||
import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
|
||||
import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
|
||||
import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
|
||||
import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
|
||||
|
||||
/** Default checking period for SMS sent without uesr permit */
|
||||
|
||||
public abstract class SMSDispatcher extends Handler {
|
||||
private static final String TAG = "SMS";
|
||||
|
||||
/** Default checking period for SMS sent without user permit */
|
||||
private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000;
|
||||
|
||||
/** Default number of SMS sent in checking period without uesr permit */
|
||||
/** Default number of SMS sent in checking period without user permit */
|
||||
private static final int DEFAULT_SMS_MAX_COUNT = 100;
|
||||
|
||||
/** Default timeout for SMS sent query */
|
||||
private static final int DEFAULT_SMS_TIMOUEOUT = 6000;
|
||||
|
||||
private static final String[] RAW_PROJECTION = new String[] {
|
||||
protected static final String[] RAW_PROJECTION = new String[] {
|
||||
"pdu",
|
||||
"sequence",
|
||||
};
|
||||
|
||||
static final int MAIL_SEND_SMS = 1;
|
||||
|
||||
static final int EVENT_NEW_SMS = 1;
|
||||
static final protected int EVENT_NEW_SMS = 1;
|
||||
|
||||
static final int EVENT_SEND_SMS_COMPLETE = 2;
|
||||
static final protected int EVENT_SEND_SMS_COMPLETE = 2;
|
||||
|
||||
/** Retry sending a previously failed SMS message */
|
||||
static final int EVENT_SEND_RETRY = 3;
|
||||
static final protected int EVENT_SEND_RETRY = 3;
|
||||
|
||||
/** Status report received */
|
||||
static final int EVENT_NEW_SMS_STATUS_REPORT = 5;
|
||||
static final protected int EVENT_NEW_SMS_STATUS_REPORT = 5;
|
||||
|
||||
/** SIM storage is full */
|
||||
static final int EVENT_SIM_FULL = 6;
|
||||
/** SIM/RUIM storage is full */
|
||||
static final protected int EVENT_ICC_FULL = 6;
|
||||
|
||||
/** SMS confirm required */
|
||||
static final int EVENT_POST_ALERT = 7;
|
||||
static final protected int EVENT_POST_ALERT = 7;
|
||||
|
||||
/** Send the user confirmed SMS */
|
||||
static final int EVENT_SEND_CONFIRMED_SMS = 8;
|
||||
static final protected int EVENT_SEND_CONFIRMED_SMS = 8;
|
||||
|
||||
/** Alert is timeout */
|
||||
static final int EVENT_ALERT_TIMEOUT = 9;
|
||||
static final protected int EVENT_ALERT_TIMEOUT = 9;
|
||||
|
||||
private final GSMPhone mPhone;
|
||||
protected Phone mPhone;
|
||||
protected Context mContext;
|
||||
protected ContentResolver mResolver;
|
||||
protected CommandsInterface mCm;
|
||||
|
||||
private final WapPushOverSms mWapPush;
|
||||
protected final WapPushOverSms mWapPush;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private final ContentResolver mResolver;
|
||||
|
||||
private final CommandsInterface mCm;
|
||||
|
||||
private final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
|
||||
protected final Uri mRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
|
||||
|
||||
/** Maximum number of times to retry sending a failed SMS. */
|
||||
private static final int MAX_SEND_RETRIES = 3;
|
||||
@@ -117,20 +122,15 @@ final class SMSDispatcher extends Handler {
|
||||
* CONCATENATED_16_BIT_REFERENCE message set. Should be
|
||||
* incremented for each set of concatenated messages.
|
||||
*/
|
||||
private static int sConcatenatedRef;
|
||||
protected static int sConcatenatedRef;
|
||||
|
||||
private SmsCounter mCounter;
|
||||
|
||||
private SmsTracker mSTracker;
|
||||
|
||||
/** Wake lock to ensure device stays awake while dispatching the SMS intent. */
|
||||
private PowerManager.WakeLock mWakeLock;
|
||||
|
||||
/**
|
||||
* Hold the wake lock for 5 seconds, which should be enough time for
|
||||
* any receiver(s) to grab its own wake lock.
|
||||
*/
|
||||
private final int WAKE_LOCK_TIMEOUT = 5000;
|
||||
private static SmsMessage mSmsMessage;
|
||||
private static SmsMessageBase mSmsMessageBase;
|
||||
private SmsMessageBase.SubmitPduBase mSubmitPduBase;
|
||||
|
||||
/**
|
||||
* Implement the per-application based SMS control, which only allows
|
||||
@@ -177,6 +177,7 @@ final class SMSDispatcher extends Handler {
|
||||
while (sent.size() > 0 && (ct - sent.get(0)) > mCheckPeriod ) {
|
||||
sent.remove(0);
|
||||
}
|
||||
|
||||
|
||||
if ( (sent.size() + smsWaiting) <= mMaxAllowed) {
|
||||
for (int i = 0; i < smsWaiting; i++ ) {
|
||||
@@ -188,7 +189,7 @@ final class SMSDispatcher extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
SMSDispatcher(GSMPhone phone) {
|
||||
protected SMSDispatcher(PhoneBase phone) {
|
||||
mPhone = phone;
|
||||
mWapPush = new WapPushOverSms(phone);
|
||||
mContext = phone.getContext();
|
||||
@@ -196,8 +197,6 @@ final class SMSDispatcher extends Handler {
|
||||
mCm = phone.mCM;
|
||||
mSTracker = null;
|
||||
|
||||
createWakelock();
|
||||
|
||||
int check_period = Settings.Gservices.getInt(mResolver,
|
||||
Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS,
|
||||
DEFAULT_SMS_CHECK_PERIOD);
|
||||
@@ -208,19 +207,30 @@ final class SMSDispatcher extends Handler {
|
||||
|
||||
mCm.setOnNewSMS(this, EVENT_NEW_SMS, null);
|
||||
mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);
|
||||
mCm.setOnSimSmsFull(this, EVENT_SIM_FULL, null);
|
||||
mCm.setOnIccSmsFull(this, EVENT_ICC_FULL, null);
|
||||
|
||||
// Don't always start message ref at 0.
|
||||
sConcatenatedRef = new Random().nextInt(256);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
mCm.unSetOnNewSMS(this);
|
||||
mCm.unSetOnSmsStatus(this);
|
||||
mCm.unSetOnIccSmsFull(this);
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
Log.d(TAG, "SMSDispatcher finalized");
|
||||
}
|
||||
|
||||
|
||||
/* TODO: Need to figure out how to keep track of status report routing in a
|
||||
* persistent manner. If the phone process restarts (reboot or crash),
|
||||
* we will lose this list and any status reports that come in after
|
||||
* will be dropped.
|
||||
*/
|
||||
/** Sent messages awaiting a delivery status report. */
|
||||
private final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
|
||||
protected final ArrayList<SmsTracker> deliveryPendingList = new ArrayList<SmsTracker>();
|
||||
|
||||
/**
|
||||
* Handles events coming from the phone stack. Overridden from handler.
|
||||
@@ -242,11 +252,8 @@ final class SMSDispatcher extends Handler {
|
||||
|
||||
ar = (AsyncResult) msg.obj;
|
||||
|
||||
// FIXME unit test leaves cm == null. this should change
|
||||
if (mCm != null) {
|
||||
// FIXME only acknowledge on store
|
||||
mCm.acknowledgeLastIncomingSMS(true, null);
|
||||
}
|
||||
acknowledgeLastIncomingSms(true, null);
|
||||
|
||||
if (ar.exception != null) {
|
||||
Log.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception);
|
||||
@@ -254,12 +261,12 @@ final class SMSDispatcher extends Handler {
|
||||
}
|
||||
|
||||
sms = (SmsMessage) ar.result;
|
||||
dispatchMessage(sms);
|
||||
dispatchMessage(sms.mWrappedSmsMessage);
|
||||
|
||||
break;
|
||||
|
||||
case EVENT_SEND_SMS_COMPLETE:
|
||||
// An outbound SMS has been sucessfully transferred, or failed.
|
||||
// An outbound SMS has been successfully transferred, or failed.
|
||||
handleSendComplete((AsyncResult) msg.obj);
|
||||
break;
|
||||
|
||||
@@ -271,8 +278,8 @@ final class SMSDispatcher extends Handler {
|
||||
handleStatusReport((AsyncResult)msg.obj);
|
||||
break;
|
||||
|
||||
case EVENT_SIM_FULL:
|
||||
handleSimFull();
|
||||
case EVENT_ICC_FULL:
|
||||
handleIccFull();
|
||||
break;
|
||||
|
||||
case EVENT_POST_ALERT:
|
||||
@@ -298,27 +305,14 @@ final class SMSDispatcher extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
private void createWakelock() {
|
||||
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
|
||||
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SMSDispatcher");
|
||||
mWakeLock.setReferenceCounted(true);
|
||||
}
|
||||
|
||||
private void sendBroadcast(Intent intent, String permission) {
|
||||
// Hold a wake lock for WAKE_LOCK_TIMEOUT seconds, enough to give any
|
||||
// receivers time to take their own wake locks.
|
||||
mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
|
||||
mContext.sendBroadcast(intent, permission);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when SIM_FULL message is received from the RIL. Notifies interested
|
||||
* parties that SIM storage for SMS messages is full.
|
||||
*/
|
||||
private void handleSimFull() {
|
||||
private void handleIccFull(){
|
||||
// broadcast SIM_FULL intent
|
||||
Intent intent = new Intent(Intents.SIM_FULL_ACTION);
|
||||
sendBroadcast(intent, "android.permission.RECEIVE_SMS");
|
||||
mPhone.getContext().sendBroadcast(intent, "android.permission.RECEIVE_SMS");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,34 +322,7 @@ final class SMSDispatcher extends Handler {
|
||||
* @param ar AsyncResult passed into the message handler. ar.result should
|
||||
* be a String representing the status report PDU, as ASCII hex.
|
||||
*/
|
||||
private void handleStatusReport(AsyncResult ar) {
|
||||
String pduString = (String) ar.result;
|
||||
SmsMessage sms = SmsMessage.newFromCDS(pduString);
|
||||
|
||||
if (sms != null) {
|
||||
int messageRef = sms.messageRef;
|
||||
for (int i = 0, count = deliveryPendingList.size(); i < count; i++) {
|
||||
SmsTracker tracker = deliveryPendingList.get(i);
|
||||
if (tracker.mMessageRef == messageRef) {
|
||||
// Found it. Remove from list and broadcast.
|
||||
deliveryPendingList.remove(i);
|
||||
PendingIntent intent = tracker.mDeliveryIntent;
|
||||
Intent fillIn = new Intent();
|
||||
fillIn.putExtra("pdu", SimUtils.hexStringToBytes(pduString));
|
||||
try {
|
||||
intent.send(mContext, Activity.RESULT_OK, fillIn);
|
||||
} catch (CanceledException ex) {}
|
||||
|
||||
// Only expect to see one tracker matching this messageref
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mCm != null) {
|
||||
mCm.acknowledgeLastIncomingSMS(true, null);
|
||||
}
|
||||
}
|
||||
protected abstract void handleStatusReport(AsyncResult ar);
|
||||
|
||||
/**
|
||||
* Called when SMS send completes. Broadcasts a sentIntent on success.
|
||||
@@ -366,7 +333,7 @@ final class SMSDispatcher extends Handler {
|
||||
* an SmsResponse instance if send was successful. ar.userObj
|
||||
* should be an SmsTracker instance.
|
||||
*/
|
||||
private void handleSendComplete(AsyncResult ar) {
|
||||
protected void handleSendComplete(AsyncResult ar) {
|
||||
SmsTracker tracker = (SmsTracker) ar.userObj;
|
||||
PendingIntent sentIntent = tracker.mSentIntent;
|
||||
|
||||
@@ -414,7 +381,7 @@ final class SMSDispatcher extends Handler {
|
||||
} else if (tracker.mSentIntent != null) {
|
||||
// Done retrying; return an error to the app.
|
||||
try {
|
||||
tracker.mSentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE);
|
||||
tracker.mSentIntent.send(RESULT_ERROR_GENERIC_FAILURE);
|
||||
} catch (CanceledException ex) {}
|
||||
}
|
||||
}
|
||||
@@ -429,13 +396,13 @@ final class SMSDispatcher extends Handler {
|
||||
* POWER_OFF
|
||||
* @param tracker An SmsTracker for the current message.
|
||||
*/
|
||||
private void handleNotInService(int ss, SmsTracker tracker) {
|
||||
protected void handleNotInService(int ss, SmsTracker tracker) {
|
||||
if (tracker.mSentIntent != null) {
|
||||
try {
|
||||
if (ss == ServiceState.STATE_POWER_OFF) {
|
||||
tracker.mSentIntent.send(SmsManager.RESULT_ERROR_RADIO_OFF);
|
||||
tracker.mSentIntent.send(RESULT_ERROR_RADIO_OFF);
|
||||
} else {
|
||||
tracker.mSentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE);
|
||||
tracker.mSentIntent.send(RESULT_ERROR_NO_SERVICE);
|
||||
}
|
||||
} catch (CanceledException ex) {}
|
||||
}
|
||||
@@ -446,130 +413,14 @@ final class SMSDispatcher extends Handler {
|
||||
*
|
||||
* @param sms the incoming message from the phone
|
||||
*/
|
||||
/* package */ void dispatchMessage(SmsMessage sms) {
|
||||
protected abstract void dispatchMessage(SmsMessageBase sms);
|
||||
|
||||
// If sms is null, means there was a parsing error.
|
||||
// TODO: Should NAK this.
|
||||
if (sms == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean handled = false;
|
||||
|
||||
// Special case the message waiting indicator messages
|
||||
if (sms.isMWISetMessage()) {
|
||||
mPhone.updateMessageWaitingIndicator(true);
|
||||
|
||||
if (sms.isMwiDontStore()) {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (Config.LOGD) {
|
||||
Log.d(TAG,
|
||||
"Received voice mail indicator set SMS shouldStore="
|
||||
+ !handled);
|
||||
}
|
||||
} else if (sms.isMWIClearMessage()) {
|
||||
mPhone.updateMessageWaitingIndicator(false);
|
||||
|
||||
if (sms.isMwiDontStore()) {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (Config.LOGD) {
|
||||
Log.d(TAG,
|
||||
"Received voice mail indicator clear SMS shouldStore="
|
||||
+ !handled);
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the headers to see if this is partial, or port addressed
|
||||
int referenceNumber = -1;
|
||||
int count = 0;
|
||||
int sequence = 0;
|
||||
int destPort = -1;
|
||||
|
||||
SmsHeader header = sms.getUserDataHeader();
|
||||
if (header != null) {
|
||||
for (SmsHeader.Element element : header.getElements()) {
|
||||
try {
|
||||
switch (element.getID()) {
|
||||
case SmsHeader.CONCATENATED_8_BIT_REFERENCE: {
|
||||
byte[] data = element.getData();
|
||||
|
||||
referenceNumber = data[0] & 0xff;
|
||||
count = data[1] & 0xff;
|
||||
sequence = data[2] & 0xff;
|
||||
|
||||
// Per TS 23.040, 9.2.3.24.1: If the count is zero, sequence
|
||||
// is zero, or sequence > count, ignore the entire element
|
||||
if (count == 0 || sequence == 0 || sequence > count) {
|
||||
referenceNumber = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SmsHeader.CONCATENATED_16_BIT_REFERENCE: {
|
||||
byte[] data = element.getData();
|
||||
|
||||
referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff);
|
||||
count = data[2] & 0xff;
|
||||
sequence = data[3] & 0xff;
|
||||
|
||||
// Per TS 23.040, 9.2.3.24.8: If the count is zero, sequence
|
||||
// is zero, or sequence > count, ignore the entire element
|
||||
if (count == 0 || sequence == 0 || sequence > count) {
|
||||
referenceNumber = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: {
|
||||
byte[] data = element.getData();
|
||||
|
||||
destPort = (data[0] & 0xff) << 8;
|
||||
destPort |= (data[1] & 0xff);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
Log.e(TAG, "Bad element in header", e);
|
||||
return; // TODO: NACK the message or something, don't just discard.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (referenceNumber == -1) {
|
||||
// notify everyone of the message if it isn't partial
|
||||
byte[][] pdus = new byte[1][];
|
||||
pdus[0] = sms.getPdu();
|
||||
|
||||
if (destPort != -1) {
|
||||
if (destPort == SmsHeader.PORT_WAP_PUSH) {
|
||||
mWapPush.dispatchWapPdu(sms.getUserData());
|
||||
}
|
||||
// The message was sent to a port, so concoct a URI for it
|
||||
dispatchPortAddressedPdus(pdus, destPort);
|
||||
} else {
|
||||
// It's a normal message, dispatch it
|
||||
dispatchPdus(pdus);
|
||||
}
|
||||
} else {
|
||||
// Process the message part
|
||||
processMessagePart(sms, referenceNumber, sequence, count, destPort);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is the last part send the parts out to the application, otherwise
|
||||
* the part is stored for later processing.
|
||||
*/
|
||||
private void processMessagePart(SmsMessage sms, int referenceNumber,
|
||||
protected void processMessagePart(SmsMessageBase sms, int referenceNumber,
|
||||
int sequence, int count, int destinationPort) {
|
||||
// Lookup all other related parts
|
||||
StringBuilder where = new StringBuilder("reference_number =");
|
||||
@@ -655,10 +506,11 @@ final class SMSDispatcher extends Handler {
|
||||
*
|
||||
* @param pdus The raw PDUs making up the message
|
||||
*/
|
||||
private void dispatchPdus(byte[][] pdus) {
|
||||
protected void dispatchPdus(byte[][] pdus) {
|
||||
Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
|
||||
intent.putExtra("pdus", pdus);
|
||||
sendBroadcast(intent, "android.permission.RECEIVE_SMS");
|
||||
mPhone.getContext().sendBroadcast(
|
||||
intent, "android.permission.RECEIVE_SMS");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -667,11 +519,12 @@ final class SMSDispatcher extends Handler {
|
||||
* @param pdus The raw PDUs making up the message
|
||||
* @param port The destination port of the messages
|
||||
*/
|
||||
private void dispatchPortAddressedPdus(byte[][] pdus, int port) {
|
||||
protected void dispatchPortAddressedPdus(byte[][] pdus, int port) {
|
||||
Uri uri = Uri.parse("sms://localhost:" + port);
|
||||
Intent intent = new Intent(Intents.DATA_SMS_RECEIVED_ACTION, uri);
|
||||
intent.putExtra("pdus", pdus);
|
||||
sendBroadcast(intent, "android.permission.RECEIVE_SMS");
|
||||
mPhone.getContext().sendBroadcast(
|
||||
intent, "android.permission.RECEIVE_SMS");
|
||||
}
|
||||
|
||||
|
||||
@@ -700,114 +553,9 @@ final class SMSDispatcher extends Handler {
|
||||
* to the recipient. The raw pdu of the status report is in the
|
||||
* extended data ("pdu").
|
||||
*/
|
||||
void sendMultipartText(String destinationAddress, String scAddress, ArrayList<String> parts,
|
||||
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
|
||||
|
||||
PendingIntent sentIntent = null;
|
||||
|
||||
|
||||
int ss = mPhone.getServiceState().getState();
|
||||
|
||||
if (ss == ServiceState.STATE_IN_SERVICE) {
|
||||
// Only check SMS sending limit while in service
|
||||
if (sentIntents != null && sentIntents.size() > 0) {
|
||||
sentIntent = sentIntents.get(0);
|
||||
}
|
||||
String appName = getAppNameByIntent(sentIntent);
|
||||
if ( !mCounter.check(appName, parts.size())) {
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("destination", destinationAddress);
|
||||
map.put("scaddress", scAddress);
|
||||
map.put("parts", parts);
|
||||
map.put("sentIntents", sentIntents);
|
||||
map.put("deliveryIntents", deliveryIntents);
|
||||
|
||||
SmsTracker multipartParameter = new SmsTracker(map, null, null);
|
||||
|
||||
sendMessage(obtainMessage(EVENT_POST_ALERT, multipartParameter));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sendMultipartTextWithPermit(destinationAddress,
|
||||
scAddress, parts, sentIntents, deliveryIntents);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a multi-part text based SMS which already passed SMS control check.
|
||||
*
|
||||
* It is the working function for sendMultipartText().
|
||||
*
|
||||
* @param destinationAddress the address to send the message to
|
||||
* @param scAddress is the service center address or null to use
|
||||
* the current default SMSC
|
||||
* @param parts an <code>ArrayList</code> of strings that, in order,
|
||||
* comprise the original message
|
||||
* @param sentIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been sent.
|
||||
* The result code will be <code>Activity.RESULT_OK<code> for success,
|
||||
* or one of these errors:
|
||||
* <code>RESULT_ERROR_GENERIC_FAILURE</code>
|
||||
* <code>RESULT_ERROR_RADIO_OFF</code>
|
||||
* <code>RESULT_ERROR_NULL_PDU</code>.
|
||||
* @param deliveryIntents if not null, an <code>ArrayList</code> of
|
||||
* <code>PendingIntent</code>s (one for each message part) that is
|
||||
* broadcast when the corresponding message part has been delivered
|
||||
* to the recipient. The raw pdu of the status report is in the
|
||||
* extended data ("pdu").
|
||||
*/
|
||||
private void sendMultipartTextWithPermit(String destinationAddress,
|
||||
String scAddress, ArrayList<String> parts,
|
||||
ArrayList<PendingIntent> sentIntents,
|
||||
ArrayList<PendingIntent> deliveryIntents) {
|
||||
|
||||
PendingIntent sentIntent = null;
|
||||
PendingIntent deliveryIntent = null;
|
||||
|
||||
// check if in service
|
||||
int ss = mPhone.getServiceState().getState();
|
||||
if (ss != ServiceState.STATE_IN_SERVICE) {
|
||||
for (int i = 0, count = parts.size(); i < count; i++) {
|
||||
if (sentIntents != null && sentIntents.size() > i) {
|
||||
sentIntent = sentIntents.get(i);
|
||||
}
|
||||
SmsTracker tracker = new SmsTracker(null, sentIntent, null);
|
||||
handleNotInService(ss, tracker);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int ref = ++sConcatenatedRef & 0xff;
|
||||
|
||||
for (int i = 0, count = parts.size(); i < count; i++) {
|
||||
// build SmsHeader
|
||||
byte[] data = new byte[3];
|
||||
data[0] = (byte) ref; // reference #, unique per message
|
||||
data[1] = (byte) count; // total part count
|
||||
data[2] = (byte) (i + 1); // 1-based sequence
|
||||
SmsHeader header = new SmsHeader();
|
||||
header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data));
|
||||
|
||||
if (sentIntents != null && sentIntents.size() > i) {
|
||||
sentIntent = sentIntents.get(i);
|
||||
}
|
||||
if (deliveryIntents != null && deliveryIntents.size() > i) {
|
||||
deliveryIntent = deliveryIntents.get(i);
|
||||
}
|
||||
|
||||
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
|
||||
parts.get(i), deliveryIntent != null, header.toByteArray());
|
||||
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("smsc", pdus.encodedScAddress);
|
||||
map.put("pdu", pdus.encodedMessage);
|
||||
|
||||
SmsTracker tracker = new SmsTracker(map, sentIntent,
|
||||
deliveryIntent);
|
||||
sendSms(tracker);
|
||||
}
|
||||
}
|
||||
protected abstract void sendMultipartText(String destinationAddress, String scAddress,
|
||||
ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
|
||||
ArrayList<PendingIntent> deliveryIntents);
|
||||
|
||||
/**
|
||||
* Send a SMS
|
||||
@@ -829,12 +577,12 @@ final class SMSDispatcher extends Handler {
|
||||
* broadcast when the message is delivered to the recipient. The
|
||||
* raw pdu of the status report is in the extended data ("pdu").
|
||||
*/
|
||||
void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
|
||||
protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
|
||||
PendingIntent deliveryIntent) {
|
||||
if (pdu == null) {
|
||||
if (sentIntent != null) {
|
||||
try {
|
||||
sentIntent.send(SmsManager.RESULT_ERROR_NULL_PDU);
|
||||
sentIntent.send(RESULT_ERROR_NULL_PDU);
|
||||
} catch (CanceledException ex) {}
|
||||
}
|
||||
return;
|
||||
@@ -865,7 +613,7 @@ final class SMSDispatcher extends Handler {
|
||||
*
|
||||
* An SmsTracker for the current message.
|
||||
*/
|
||||
private void handleReachSentLimit(SmsTracker tracker) {
|
||||
protected void handleReachSentLimit(SmsTracker tracker) {
|
||||
|
||||
Resources r = Resources.getSystem();
|
||||
|
||||
@@ -886,7 +634,7 @@ final class SMSDispatcher extends Handler {
|
||||
DEFAULT_SMS_TIMOUEOUT);
|
||||
}
|
||||
|
||||
private String getAppNameByIntent(PendingIntent intent) {
|
||||
protected String getAppNameByIntent(PendingIntent intent) {
|
||||
Resources r = Resources.getSystem();
|
||||
return (intent != null) ? intent.getTargetPackage()
|
||||
: r.getString(R.string.sms_control_default_app_name);
|
||||
@@ -897,41 +645,53 @@ final class SMSDispatcher extends Handler {
|
||||
*
|
||||
* @param tracker holds the SMS message to send
|
||||
*/
|
||||
private void sendSms(SmsTracker tracker) {
|
||||
HashMap map = tracker.mData;
|
||||
|
||||
byte smsc[] = (byte[]) map.get("smsc");
|
||||
byte pdu[] = (byte[]) map.get("pdu");
|
||||
|
||||
Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
|
||||
mCm.sendSMS(SimUtils.bytesToHexString(smsc),
|
||||
SimUtils.bytesToHexString(pdu), reply);
|
||||
}
|
||||
protected abstract void sendSms(SmsTracker tracker);
|
||||
|
||||
/**
|
||||
* Send the multi-part SMS based on multipart Sms tracker
|
||||
*
|
||||
* @param tracker holds the multipart Sms tracker ready to be sent
|
||||
*/
|
||||
private void sendMultipartSms (SmsTracker tracker) {
|
||||
ArrayList<String> parts;
|
||||
ArrayList<PendingIntent> sentIntents;
|
||||
ArrayList<PendingIntent> deliveryIntents;
|
||||
|
||||
HashMap map = tracker.mData;
|
||||
|
||||
String destinationAddress = (String) map.get("destination");
|
||||
String scAddress = (String) map.get("scaddress");
|
||||
|
||||
parts = (ArrayList<String>) map.get("parts");
|
||||
sentIntents = (ArrayList<PendingIntent>) map.get("sentIntents");
|
||||
deliveryIntents = (ArrayList<PendingIntent>) map.get("deliveryIntents");
|
||||
|
||||
sendMultipartTextWithPermit(destinationAddress,
|
||||
scAddress, parts, sentIntents, deliveryIntents);
|
||||
protected abstract void sendMultipartSms (SmsTracker tracker);
|
||||
|
||||
/**
|
||||
* Activate or deactivate cell broadcast SMS.
|
||||
*
|
||||
* @param activate
|
||||
* 0 = activate, 1 = deactivate
|
||||
* @param response
|
||||
* Callback message is empty on completion
|
||||
*/
|
||||
protected abstract void activateCellBroadcastSms(int activate, Message response);
|
||||
|
||||
/**
|
||||
* Query the current configuration of cell broadcast SMS.
|
||||
*
|
||||
* @param response
|
||||
* Callback message contains the configuration from the modem on completion
|
||||
* @see #setCellBroadcastConfig
|
||||
*/
|
||||
protected abstract void getCellBroadcastSmsConfig(Message response);
|
||||
|
||||
/**
|
||||
* Configure cell broadcast SMS.
|
||||
*
|
||||
* @param configValuesArray
|
||||
* The first element defines the number of triples that follow.
|
||||
* A triple is made up of the service category, the language identifier
|
||||
* and a boolean that specifies whether the category is set active.
|
||||
* @param response
|
||||
* Callback message is empty on completion
|
||||
*/
|
||||
protected abstract void setCellBroadcastConfig(int[] configValuesArray, Message response);
|
||||
|
||||
/**
|
||||
* Send an acknowledge message.
|
||||
* @param success indicates that last message was successfully received.
|
||||
* @param response callback message sent when operation completes.
|
||||
*/
|
||||
protected abstract void acknowledgeLastIncomingSms(boolean success, Message response);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a SmsTracker holds multi-part Sms
|
||||
*
|
||||
@@ -942,19 +702,20 @@ final class SMSDispatcher extends Handler {
|
||||
HashMap map = tracker.mData;
|
||||
return ( map.get("parts") != null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Keeps track of an SMS that has been sent to the RIL, until it it has
|
||||
* successfully been sent, or we're done trying.
|
||||
*
|
||||
*/
|
||||
static class SmsTracker {
|
||||
HashMap mData;
|
||||
int mRetryCount;
|
||||
int mMessageRef;
|
||||
static protected class SmsTracker {
|
||||
// fields need to be public for derived SmsDispatchers
|
||||
public HashMap mData;
|
||||
public int mRetryCount;
|
||||
public int mMessageRef;
|
||||
|
||||
PendingIntent mSentIntent;
|
||||
PendingIntent mDeliveryIntent;
|
||||
public PendingIntent mSentIntent;
|
||||
public PendingIntent mDeliveryIntent;
|
||||
|
||||
SmsTracker(HashMap data, PendingIntent sentIntent,
|
||||
PendingIntent deliveryIntent) {
|
||||
@@ -963,17 +724,21 @@ final class SMSDispatcher extends Handler {
|
||||
mDeliveryIntent = deliveryIntent;
|
||||
mRetryCount = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected SmsTracker SmsTrackerFactory(HashMap data, PendingIntent sentIntent,
|
||||
PendingIntent deliveryIntent) {
|
||||
return new SmsTracker(data, sentIntent, deliveryIntent);
|
||||
}
|
||||
|
||||
private DialogInterface.OnClickListener mListener =
|
||||
new DialogInterface.OnClickListener() {
|
||||
new DialogInterface.OnClickListener() {
|
||||
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
Log.d(TAG, "click YES to send out sms");
|
||||
sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS));
|
||||
}
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == DialogInterface.BUTTON_POSITIVE) {
|
||||
Log.d(TAG, "click YES to send out sms");
|
||||
sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS));
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Registrant;
|
||||
import android.os.RegistrantList;
|
||||
import android.telephony.ServiceState;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public abstract class ServiceStateTracker extends Handler {
|
||||
/**
|
||||
* The access technology currently in use:
|
||||
* 0 = unknown
|
||||
* 1 = GPRS only
|
||||
* 2 = EDGE
|
||||
* 3 = UMTS
|
||||
*/
|
||||
protected static final int DATA_ACCESS_UNKNOWN = 0;
|
||||
protected static final int DATA_ACCESS_GPRS = 1;
|
||||
protected static final int DATA_ACCESS_EDGE = 2;
|
||||
protected static final int DATA_ACCESS_UMTS = 3;
|
||||
protected static final int DATA_ACCESS_CDMA_IS95A = 4;
|
||||
protected static final int DATA_ACCESS_CDMA_IS95B = 5;
|
||||
protected static final int DATA_ACCESS_CDMA_1xRTT = 6;
|
||||
protected static final int DATA_ACCESS_CDMA_EvDo_0 = 7;
|
||||
protected static final int DATA_ACCESS_CDMA_EvDo_A = 8;
|
||||
//***** Instance Variables
|
||||
|
||||
protected CommandsInterface cm;
|
||||
|
||||
public ServiceState ss;
|
||||
protected ServiceState newSS;
|
||||
|
||||
// Used as a unique identifier to track requests associated with a poll
|
||||
// and ignore stale responses.The value is a count-down of expected responses
|
||||
// in this pollingContext
|
||||
protected int[] pollingContext;
|
||||
protected boolean mDesiredPowerState;
|
||||
|
||||
protected boolean dontPollSignalStrength = false; // Default is to poll strength
|
||||
// If we're getting unsolicited signal strength updates from the radio,
|
||||
// set value to true and don't bother polling any more
|
||||
|
||||
protected RegistrantList networkAttachedRegistrants = new RegistrantList();
|
||||
protected RegistrantList roamingOnRegistrants = new RegistrantList();
|
||||
protected RegistrantList roamingOffRegistrants = new RegistrantList();
|
||||
|
||||
//***** Constants
|
||||
|
||||
protected static final boolean DBG = true;
|
||||
|
||||
// signal strength poll rate
|
||||
protected static final int POLL_PERIOD_MILLIS = 20 * 1000;
|
||||
|
||||
// waiting period before recheck gprs and voice registration
|
||||
public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
|
||||
|
||||
public static final int MAX_NUM_DATA_STATE_READS = 15;
|
||||
public static final int DATA_STATE_POLL_SLEEP_MS = 100;
|
||||
|
||||
//*****GSM events
|
||||
protected static final int EVENT_RADIO_STATE_CHANGED = 1;
|
||||
protected static final int EVENT_NETWORK_STATE_CHANGED = 2;
|
||||
protected static final int EVENT_GET_SIGNAL_STRENGTH = 3;
|
||||
protected static final int EVENT_POLL_STATE_REGISTRATION = 4;
|
||||
protected static final int EVENT_POLL_STATE_GPRS = 5;
|
||||
protected static final int EVENT_POLL_STATE_OPERATOR = 6;
|
||||
protected static final int EVENT_POLL_SIGNAL_STRENGTH = 10;
|
||||
protected static final int EVENT_NITZ_TIME = 11;
|
||||
protected static final int EVENT_SIGNAL_STRENGTH_UPDATE = 12;
|
||||
protected static final int EVENT_RADIO_AVAILABLE = 13;
|
||||
protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14;
|
||||
protected static final int EVENT_GET_LOC_DONE = 15;
|
||||
protected static final int EVENT_SIM_RECORDS_LOADED = 16;
|
||||
protected static final int EVENT_SIM_READY = 17;
|
||||
protected static final int EVENT_LOCATION_UPDATES_ENABLED = 18;
|
||||
protected static final int EVENT_GET_PREFERRED_NETWORK_TYPE = 19;
|
||||
protected static final int EVENT_SET_PREFERRED_NETWORK_TYPE = 20;
|
||||
protected static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21;
|
||||
protected static final int EVENT_CHECK_REPORT_GPRS = 22;
|
||||
protected static final int EVENT_RESTRICTED_STATE_CHANGED = 23;
|
||||
|
||||
//*****CDMA events:
|
||||
protected static final int EVENT_POLL_STATE_REGISTRATION_CDMA = 24;
|
||||
protected static final int EVENT_POLL_STATE_OPERATOR_CDMA = 25;
|
||||
protected static final int EVENT_RUIM_READY = 26;
|
||||
protected static final int EVENT_RUIM_RECORDS_LOADED = 27;
|
||||
protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA = 28;
|
||||
protected static final int EVENT_POLL_SIGNAL_STRENGTH_CDMA = 29;
|
||||
protected static final int EVENT_GET_SIGNAL_STRENGTH_CDMA = 30;
|
||||
protected static final int EVENT_NETWORK_STATE_CHANGED_CDMA = 31;
|
||||
protected static final int EVENT_GET_LOC_DONE_CDMA = 32;
|
||||
protected static final int EVENT_SIGNAL_STRENGTH_UPDATE_CDMA = 33;
|
||||
protected static final int EVENT_NV_LOADED = 34;
|
||||
|
||||
// Event Log Tags
|
||||
protected static final int EVENT_LOG_CGREG_FAIL = 50107;
|
||||
protected static final int EVENT_DATA_STATE_RADIO_OFF = 50108;
|
||||
|
||||
//***** Time Zones
|
||||
protected static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
|
||||
|
||||
// List of ISO codes for countries that can have an offset of GMT+0
|
||||
// when not in daylight savings time. This ignores some small places
|
||||
// such as the Canary Islands (Spain) and Danmarkshavn (Denmark).
|
||||
// The list must be sorted by code.
|
||||
protected static final String[] GMT_COUNTRY_CODES = {
|
||||
"bf", // Burkina Faso
|
||||
"ci", // Cote d'Ivoire
|
||||
"eh", // Western Sahara
|
||||
"fo", // Faroe Islands, Denmark
|
||||
"gh", // Ghana
|
||||
"gm", // Gambia
|
||||
"gn", // Guinea
|
||||
"gw", // Guinea Bissau
|
||||
"ie", // Ireland
|
||||
"lr", // Liberia
|
||||
"is", // Iceland
|
||||
"ma", // Morocco
|
||||
"ml", // Mali
|
||||
"mr", // Mauritania
|
||||
"pt", // Portugal
|
||||
"sl", // Sierra Leone
|
||||
"sn", // Senegal
|
||||
"st", // Sao Tome and Principe
|
||||
"tg", // Togo
|
||||
"uk", // U.K
|
||||
};
|
||||
|
||||
|
||||
//***** Constructors
|
||||
public ServiceStateTracker() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registration point for combined roaming on
|
||||
* combined roaming is true when roaming is true and ONS differs SPN
|
||||
*
|
||||
* @param h handler to notify
|
||||
* @param what what code of message when delivered
|
||||
* @param obj placed in Message.obj
|
||||
*/
|
||||
public void registerForRoamingOn(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant(h, what, obj);
|
||||
roamingOnRegistrants.add(r);
|
||||
|
||||
if (ss.getRoaming()) {
|
||||
r.notifyRegistrant();
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForRoamingOn(Handler h) {
|
||||
roamingOnRegistrants.remove(h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registration point for combined roaming off
|
||||
* combined roaming is true when roaming is true and ONS differs SPN
|
||||
*
|
||||
* @param h handler to notify
|
||||
* @param what what code of message when delivered
|
||||
* @param obj placed in Message.obj
|
||||
*/
|
||||
public void registerForRoamingOff(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant(h, what, obj);
|
||||
roamingOffRegistrants.add(r);
|
||||
|
||||
if (!ss.getRoaming()) {
|
||||
r.notifyRegistrant();
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForRoamingOff(Handler h) {
|
||||
roamingOffRegistrants.remove(h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reregister network through toggle perferred network type
|
||||
* This is a work aorund to deregister and register network since there is
|
||||
* no ril api to set COPS=2 (deregister) only.
|
||||
*
|
||||
* @param onComplete is dispatched when this is complete. it will be
|
||||
* an AsyncResult, and onComplete.obj.exception will be non-null
|
||||
* on failure.
|
||||
*/
|
||||
public void reRegisterNetwork(Message onComplete) {
|
||||
cm.getPreferredNetworkType(
|
||||
obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete));
|
||||
}
|
||||
|
||||
|
||||
//***** Called from Phone
|
||||
public void
|
||||
setRadioPower(boolean power) {
|
||||
mDesiredPowerState = power;
|
||||
|
||||
setPowerStateToDesired();
|
||||
}
|
||||
|
||||
|
||||
public void enableLocationUpdates() {
|
||||
cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
|
||||
}
|
||||
|
||||
public void disableLocationUpdates() {
|
||||
cm.setLocationUpdates(false, null);
|
||||
}
|
||||
|
||||
//***** Overridden from Handler
|
||||
public abstract void handleMessage(Message msg);
|
||||
|
||||
//***** Protected abstract Methods
|
||||
protected abstract void handlePollStateResult(int what, AsyncResult ar);
|
||||
protected abstract void updateSpnDisplay();
|
||||
protected abstract void setPowerStateToDesired();
|
||||
|
||||
/** Cancel a pending (if any) pollState() operation */
|
||||
protected void cancelPollState() {
|
||||
// This will effectively cancel the rest of the poll requests
|
||||
pollingContext = new int[1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
public abstract class SmsAddress {
|
||||
// From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118
|
||||
// and C.S0005-D table 2.7.1.3.2.4-2
|
||||
public static final int TON_UNKNOWN = 0;
|
||||
public static final int TON_INTERNATIONAL = 1;
|
||||
public static final int TON_NATIONAL = 2;
|
||||
public static final int TON_NETWORK = 3;
|
||||
public static final int TON_SUBSCRIBER = 4;
|
||||
public static final int TON_ALPHANUMERIC = 5;
|
||||
public static final int TON_ABBREVIATED = 6;
|
||||
|
||||
public int ton;
|
||||
public String address;
|
||||
public byte[] origBytes;
|
||||
|
||||
/**
|
||||
* Returns the address of the SMS message in String form or null if unavailable
|
||||
*/
|
||||
public String getAddressString() {
|
||||
return address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is an alphanumeric address
|
||||
*/
|
||||
public boolean isAlphanumeric() {
|
||||
return ton == TON_ALPHANUMERIC;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a network address
|
||||
*/
|
||||
public boolean isNetworkSpecific() {
|
||||
return ton == TON_NETWORK;
|
||||
}
|
||||
|
||||
public boolean couldBeEmailGateway() {
|
||||
// Some carriers seems to send email gateway messages in this form:
|
||||
// from: an UNKNOWN TON, 3 or 4 digits long, beginning with a 5
|
||||
// PID: 0x00, Data coding scheme 0x03
|
||||
// So we just attempt to treat any message from an address length <= 4
|
||||
// as an email gateway
|
||||
|
||||
return address.length() <= 4;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import com.android.internal.util.HexDump;
|
||||
|
||||
@@ -24,8 +24,7 @@ import java.util.ArrayList;
|
||||
* This class represents a SMS user data header.
|
||||
*
|
||||
*/
|
||||
public class SmsHeader
|
||||
{
|
||||
public class SmsHeader {
|
||||
/** See TS 23.040 9.2.3.24 for description of this element ID. */
|
||||
public static final int CONCATENATED_8_BIT_REFERENCE = 0x00;
|
||||
/** See TS 23.040 9.2.3.24 for description of this element ID. */
|
||||
@@ -42,6 +41,7 @@ public class SmsHeader
|
||||
|
||||
private byte[] m_data;
|
||||
private ArrayList<Element> m_elements = new ArrayList<Element>();
|
||||
public int nbrOfHeaders;
|
||||
|
||||
/**
|
||||
* Creates an SmsHeader object from raw user data header bytes.
|
||||
@@ -49,36 +49,33 @@ public class SmsHeader
|
||||
* @param data is user data header bytes
|
||||
* @return an SmsHeader object
|
||||
*/
|
||||
public static SmsHeader parse(byte[] data)
|
||||
{
|
||||
public static SmsHeader parse(byte[] data) {
|
||||
SmsHeader header = new SmsHeader();
|
||||
header.m_data = data;
|
||||
|
||||
int index = 0;
|
||||
while (index < data.length)
|
||||
{
|
||||
header.nbrOfHeaders = 0;
|
||||
while (index < data.length) {
|
||||
int id = data[index++] & 0xff;
|
||||
int length = data[index++] & 0xff;
|
||||
byte[] elementData = new byte[length];
|
||||
System.arraycopy(data, index, elementData, 0, length);
|
||||
header.add(new Element(id, elementData));
|
||||
index += length;
|
||||
header.nbrOfHeaders++;
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
public SmsHeader()
|
||||
{
|
||||
}
|
||||
public SmsHeader() { }
|
||||
|
||||
/**
|
||||
* Returns the list of SmsHeader Elements that make up the header.
|
||||
*
|
||||
* @return the list of SmsHeader Elements.
|
||||
*/
|
||||
public ArrayList<Element> getElements()
|
||||
{
|
||||
public ArrayList<Element> getElements() {
|
||||
return m_elements;
|
||||
}
|
||||
|
||||
@@ -87,14 +84,12 @@ public class SmsHeader
|
||||
*
|
||||
* @param element to add.
|
||||
*/
|
||||
public void add(Element element)
|
||||
{
|
||||
public void add(Element element) {
|
||||
m_elements.add(element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("UDH LENGTH: " + m_data.length + " octets");
|
||||
@@ -104,40 +99,56 @@ public class SmsHeader
|
||||
|
||||
for (Element e : getElements()) {
|
||||
builder.append(" 0x" + HexDump.toHexString((byte)e.getID()) + " - ");
|
||||
switch (e.getID())
|
||||
{
|
||||
case CONCATENATED_8_BIT_REFERENCE:
|
||||
{
|
||||
switch (e.getID()) {
|
||||
case CONCATENATED_8_BIT_REFERENCE: {
|
||||
builder.append("Concatenated Short Message 8bit ref\n");
|
||||
byte[] data = e.getData();
|
||||
builder.append(" " + data.length + " (0x");
|
||||
builder.append(HexDump.toHexString((byte)data.length)+") Bytes - Information Element\n");
|
||||
builder.append(HexDump.toHexString((byte)data.length)
|
||||
+ ") Bytes - Information Element\n");
|
||||
builder.append(" " + data[0] + " : SM reference number\n");
|
||||
builder.append(" " + data[1] + " : number of messages\n");
|
||||
builder.append(" " + data[2] + " : this SM sequence number\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case CONCATENATED_16_BIT_REFERENCE:
|
||||
{
|
||||
case CONCATENATED_16_BIT_REFERENCE: {
|
||||
builder.append("Concatenated Short Message 16bit ref\n");
|
||||
byte[] data = e.getData();
|
||||
builder.append(" " + data.length + " (0x");
|
||||
builder.append(HexDump.toHexString((byte)data.length)+") Bytes - Information Element\n");
|
||||
builder.append(" " + (data[0] & 0xff) * 256 + (data[1] & 0xff) +
|
||||
" : SM reference number\n");
|
||||
builder.append(HexDump.toHexString((byte)data.length)
|
||||
+ ") Bytes - Information Element\n");
|
||||
builder.append(" " + (data[0] & 0xff) * 256 + (data[1] & 0xff)
|
||||
+ " : SM reference number\n");
|
||||
builder.append(" " + data[2] + " : number of messages\n");
|
||||
builder.append(" " + data[3] + " : this SM sequence number\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case APPLICATION_PORT_ADDRESSING_16_BIT:
|
||||
case APPLICATION_PORT_ADDRESSING_8_BIT:
|
||||
{
|
||||
builder.append("Application port addressing 8bit\n");
|
||||
byte[] data = e.getData();
|
||||
|
||||
builder.append(" " + data.length + " (0x");
|
||||
builder.append(HexDump.toHexString(
|
||||
(byte)data.length) + ") Bytes - Information Element\n");
|
||||
|
||||
int source = (data[0] & 0xff);
|
||||
builder.append(" " + source + " : DESTINATION port\n");
|
||||
|
||||
int dest = (data[1] & 0xff);
|
||||
builder.append(" " + dest + " : SOURCE port\n");
|
||||
break;
|
||||
}
|
||||
|
||||
case APPLICATION_PORT_ADDRESSING_16_BIT: {
|
||||
builder.append("Application port addressing 16bit\n");
|
||||
byte[] data = e.getData();
|
||||
|
||||
builder.append(" " + data.length + " (0x");
|
||||
builder.append(HexDump.toHexString((byte)data.length)+") Bytes - Information Element\n");
|
||||
builder.append(HexDump.toHexString((byte)data.length)
|
||||
+ ") Bytes - Information Element\n");
|
||||
|
||||
int source = (data[0] & 0xff) << 8;
|
||||
source |= (data[1] & 0xff);
|
||||
@@ -149,8 +160,7 @@ public class SmsHeader
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
default: {
|
||||
builder.append("Unknown element\n");
|
||||
break;
|
||||
}
|
||||
@@ -202,13 +212,11 @@ public class SmsHeader
|
||||
* See TS 23.040 9.2.3.24.
|
||||
*
|
||||
*/
|
||||
public static class Element
|
||||
{
|
||||
public static class Element {
|
||||
private byte[] m_data;
|
||||
private int m_id;
|
||||
|
||||
public Element(int id, byte[] data)
|
||||
{
|
||||
public Element(int id, byte[] data) {
|
||||
m_id = id;
|
||||
m_data = data;
|
||||
}
|
||||
@@ -218,8 +226,7 @@ public class SmsHeader
|
||||
*
|
||||
* @return the IE identifier.
|
||||
*/
|
||||
public int getID()
|
||||
{
|
||||
public int getID() {
|
||||
return m_id;
|
||||
}
|
||||
|
||||
@@ -228,8 +235,7 @@ public class SmsHeader
|
||||
*
|
||||
* @return element data.
|
||||
*/
|
||||
public byte[] getData()
|
||||
{
|
||||
public byte[] getData() {
|
||||
return m_data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.util.Log;
|
||||
import com.android.internal.telephony.SmsHeader;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static android.telephony.SmsMessage.ENCODING_7BIT;
|
||||
import static android.telephony.SmsMessage.ENCODING_16BIT;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER;
|
||||
import static android.telephony.SmsMessage.MessageClass;
|
||||
import static com.android.internal.telephony.SmsAddress.TON_ABBREVIATED;
|
||||
import static com.android.internal.telephony.SmsAddress.TON_ALPHANUMERIC;
|
||||
import static com.android.internal.telephony.SmsAddress.TON_INTERNATIONAL;
|
||||
import static com.android.internal.telephony.SmsAddress.TON_NATIONAL;
|
||||
import static com.android.internal.telephony.SmsAddress.TON_NETWORK;
|
||||
import static com.android.internal.telephony.SmsAddress.TON_SUBSCRIBER;
|
||||
import static com.android.internal.telephony.SmsAddress.TON_UNKNOWN;
|
||||
|
||||
/**
|
||||
* Base class declaring the specific methods and members for SmsMessage.
|
||||
* {@hide}
|
||||
*/
|
||||
public abstract class SmsMessageBase {
|
||||
private static final String LOG_TAG = "SMS";
|
||||
|
||||
/** {@hide} The address of the SMSC. May be null */
|
||||
protected String scAddress;
|
||||
|
||||
/** {@hide} The address of the sender */
|
||||
protected SmsAddress originatingAddress;
|
||||
|
||||
/** {@hide} The message body as a string. May be null if the message isn't text */
|
||||
protected String messageBody;
|
||||
|
||||
/** {@hide} */
|
||||
protected String pseudoSubject;
|
||||
|
||||
/** {@hide} Non-null if this is an email gateway message */
|
||||
protected String emailFrom;
|
||||
|
||||
/** {@hide} Non-null if this is an email gateway message */
|
||||
protected String emailBody;
|
||||
|
||||
/** {@hide} */
|
||||
protected boolean isEmail;
|
||||
|
||||
/** {@hide} */
|
||||
protected long scTimeMillis;
|
||||
|
||||
/** {@hide} The raw PDU of the message */
|
||||
protected byte[] mPdu;
|
||||
|
||||
/** {@hide} The raw bytes for the user data section of the message */
|
||||
protected byte[] userData;
|
||||
|
||||
/** {@hide} */
|
||||
protected SmsHeader userDataHeader;
|
||||
|
||||
// "Message Waiting Indication Group"
|
||||
// 23.038 Section 4
|
||||
/** {@hide} */
|
||||
protected boolean isMwi;
|
||||
|
||||
/** {@hide} */
|
||||
protected boolean mwiSense;
|
||||
|
||||
/** {@hide} */
|
||||
protected boolean mwiDontStore;
|
||||
|
||||
/**
|
||||
* Indicates status for messages stored on the ICC.
|
||||
*/
|
||||
protected int statusOnIcc = -1;
|
||||
|
||||
/**
|
||||
* Record index of message in the EF.
|
||||
*/
|
||||
protected int indexOnIcc = -1;
|
||||
|
||||
/** TP-Message-Reference - Message Reference of sent message. @hide */
|
||||
public int messageRef;
|
||||
|
||||
public static abstract class SubmitPduBase {
|
||||
public byte[] encodedScAddress; // Null if not applicable.
|
||||
public byte[] encodedMessage;
|
||||
|
||||
public String toString() {
|
||||
return "SubmitPdu: encodedScAddress = "
|
||||
+ Arrays.toString(encodedScAddress)
|
||||
+ ", encodedMessage = "
|
||||
+ Arrays.toString(encodedMessage);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address of the SMS service center that relayed this message
|
||||
* or null if there is none.
|
||||
*/
|
||||
public String getServiceCenterAddress() {
|
||||
return scAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the originating address (sender) of this SMS message in String
|
||||
* form or null if unavailable
|
||||
*/
|
||||
public String getOriginatingAddress() {
|
||||
if (originatingAddress == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return originatingAddress.getAddressString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the originating address, or email from address if this message
|
||||
* was from an email gateway. Returns null if originating address
|
||||
* unavailable.
|
||||
*/
|
||||
public String getDisplayOriginatingAddress() {
|
||||
if (isEmail) {
|
||||
return emailFrom;
|
||||
} else {
|
||||
return getOriginatingAddress();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message body as a String, if it exists and is text based.
|
||||
* @return message body is there is one, otherwise null
|
||||
*/
|
||||
public String getMessageBody() {
|
||||
return messageBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of this message.
|
||||
*/
|
||||
public abstract MessageClass getMessageClass();
|
||||
|
||||
/**
|
||||
* Returns the message body, or email message body if this message was from
|
||||
* an email gateway. Returns null if message body unavailable.
|
||||
*/
|
||||
public String getDisplayMessageBody() {
|
||||
if (isEmail) {
|
||||
return emailBody;
|
||||
} else {
|
||||
return getMessageBody();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unofficial convention of a subject line enclosed in parens empty string
|
||||
* if not present
|
||||
*/
|
||||
public String getPseudoSubject() {
|
||||
return pseudoSubject == null ? "" : pseudoSubject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the service centre timestamp in currentTimeMillis() format
|
||||
*/
|
||||
public long getTimestampMillis() {
|
||||
return scTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if message is an email.
|
||||
*
|
||||
* @return true if this message came through an email gateway and email
|
||||
* sender / subject / parsed body are available
|
||||
*/
|
||||
public boolean isEmail() {
|
||||
return isEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if isEmail() is true, body of the email sent through the gateway.
|
||||
* null otherwise
|
||||
*/
|
||||
public String getEmailBody() {
|
||||
return emailBody;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if isEmail() is true, email from address of email sent through
|
||||
* the gateway. null otherwise
|
||||
*/
|
||||
public String getEmailFrom() {
|
||||
return emailFrom;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get protocol identifier.
|
||||
*/
|
||||
public abstract int getProtocolIdentifier();
|
||||
|
||||
/**
|
||||
* See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
|
||||
* SMS
|
||||
*/
|
||||
public abstract boolean isReplace();
|
||||
|
||||
/**
|
||||
* Returns true for CPHS MWI toggle message.
|
||||
*
|
||||
* @return true if this is a CPHS MWI toggle message See CPHS 4.2 section
|
||||
* B.4.2
|
||||
*/
|
||||
public abstract boolean isCphsMwiMessage();
|
||||
|
||||
/**
|
||||
* returns true if this message is a CPHS voicemail / message waiting
|
||||
* indicator (MWI) clear message
|
||||
*/
|
||||
public abstract boolean isMWIClearMessage();
|
||||
|
||||
/**
|
||||
* returns true if this message is a CPHS voicemail / message waiting
|
||||
* indicator (MWI) set message
|
||||
*/
|
||||
public abstract boolean isMWISetMessage();
|
||||
|
||||
/**
|
||||
* returns true if this message is a "Message Waiting Indication Group:
|
||||
* Discard Message" notification and should not be stored.
|
||||
*/
|
||||
public abstract boolean isMwiDontStore();
|
||||
|
||||
/**
|
||||
* returns the user data section minus the user data header if one was
|
||||
* present.
|
||||
*/
|
||||
public byte[] getUserData() {
|
||||
return userData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object representing the user data header
|
||||
*
|
||||
* @return an object representing the user data header
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public SmsHeader getUserDataHeader() {
|
||||
return userDataHeader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the raw PDU for the message.
|
||||
*
|
||||
* @return the raw PDU for the message.
|
||||
*/
|
||||
public byte[] getPdu() {
|
||||
return mPdu;
|
||||
}
|
||||
|
||||
/**
|
||||
* For an SMS-STATUS-REPORT message, this returns the status field from
|
||||
* the status report. This field indicates the status of a previously
|
||||
* submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a
|
||||
* description of values.
|
||||
*
|
||||
* @return 0 indicates the previously sent message was received.
|
||||
* See TS 23.040, 9.9.2.3.15 for a description of other possible
|
||||
* values.
|
||||
*/
|
||||
public abstract int getStatus();
|
||||
|
||||
/**
|
||||
* Return true iff the message is a SMS-STATUS-REPORT message.
|
||||
*/
|
||||
public abstract boolean isStatusReportMessage();
|
||||
|
||||
/**
|
||||
* Returns true iff the <code>TP-Reply-Path</code> bit is set in
|
||||
* this message.
|
||||
*/
|
||||
public abstract boolean isReplyPathPresent();
|
||||
|
||||
/**
|
||||
* Returns the status of the message on the ICC (read, unread, sent, unsent).
|
||||
*
|
||||
* @return the status of the message on the ICC. These are:
|
||||
* SmsManager.STATUS_ON_ICC_FREE
|
||||
* SmsManager.STATUS_ON_ICC_READ
|
||||
* SmsManager.STATUS_ON_ICC_UNREAD
|
||||
* SmsManager.STATUS_ON_ICC_SEND
|
||||
* SmsManager.STATUS_ON_ICC_UNSENT
|
||||
*/
|
||||
public int getStatusOnIcc() {
|
||||
return statusOnIcc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record index of the message on the ICC (1-based index).
|
||||
* @return the record index of the message on the ICC, or -1 if this
|
||||
* SmsMessage was not created from a ICC SMS EF record.
|
||||
*/
|
||||
public int getIndexOnIcc() {
|
||||
return indexOnIcc;
|
||||
}
|
||||
|
||||
protected void parseMessageBody() {
|
||||
if (originatingAddress.couldBeEmailGateway()) {
|
||||
extractEmailAddressFromMessageBody();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to parse this message as an email gateway message -> Neither
|
||||
* of the standard ways are currently supported: There are two ways
|
||||
* specified in TS 23.040 Section 3.8 (not supported via this mechanism) -
|
||||
* SMS message "may have its TP-PID set for internet electronic mail - MT
|
||||
* SMS format: [<from-address><space>]<message> - "Depending on the
|
||||
* nature of the gateway, the destination/origination address is either
|
||||
* derived from the content of the SMS TP-OA or TP-DA field, or the
|
||||
* TP-OA/TP-DA field contains a generic gateway address and the to/from
|
||||
* address is added at the beginning as shown above." - multiple addreses
|
||||
* separated by commas, no spaces - subject field delimited by '()' or '##'
|
||||
* and '#' Section 9.2.3.24.11
|
||||
*/
|
||||
protected void extractEmailAddressFromMessageBody() {
|
||||
|
||||
/*
|
||||
* a little guesswork here. I haven't found doc for this.
|
||||
* the format could be either
|
||||
*
|
||||
* 1. [x@y][ ]/[subject][ ]/[body]
|
||||
* -or-
|
||||
* 2. [x@y][ ]/[body]
|
||||
*/
|
||||
int slash = 0, slash2 = 0, atSymbol = 0;
|
||||
|
||||
try {
|
||||
slash = messageBody.indexOf(" /");
|
||||
if (slash == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
atSymbol = messageBody.indexOf('@');
|
||||
if (atSymbol == -1 || atSymbol > slash) {
|
||||
return;
|
||||
}
|
||||
|
||||
emailFrom = messageBody.substring(0, slash);
|
||||
|
||||
slash2 = messageBody.indexOf(" /", slash + 2);
|
||||
|
||||
if (slash2 == -1) {
|
||||
pseudoSubject = null;
|
||||
emailBody = messageBody.substring(slash + 2);
|
||||
} else {
|
||||
pseudoSubject = messageBody.substring(slash + 2, slash2);
|
||||
emailBody = messageBody.substring(slash2 + 2);
|
||||
}
|
||||
|
||||
isEmail = true;
|
||||
} catch (Exception ex) {
|
||||
Log.w(LOG_TAG,
|
||||
"extractEmailAddressFromMessageBody: exception slash="
|
||||
+ slash + ", atSymbol=" + atSymbol + ", slash2="
|
||||
+ slash2, ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
parcelable SmsRawData;
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* A parcelable holder class of byte[] for ISms aidl implementation
|
||||
@@ -50,7 +50,7 @@ public class SmsRawData implements Parcelable {
|
||||
public byte[] getBytes() {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
@@ -14,20 +14,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
/**
|
||||
* Object returned by the RIL upon successful completion of sendSMS.
|
||||
* Contains message reference and ackPdu.
|
||||
*
|
||||
*/
|
||||
class SmsResponse {
|
||||
public class SmsResponse {
|
||||
/** Message reference of the just-sent SMS. */
|
||||
int messageRef;
|
||||
/** ackPdu for the just-sent SMS. */
|
||||
String ackPdu;
|
||||
|
||||
SmsResponse(int messageRef, String ackPdu) {
|
||||
public SmsResponse(int messageRef, String ackPdu) {
|
||||
this.messageRef = messageRef;
|
||||
this.ackPdu = ackPdu;
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.gsm;
|
||||
package com.android.internal.telephony;
|
||||
|
||||
/* This class contains the details related to Telephony Event Logging */
|
||||
public final class TelephonyEventLog {
|
||||
@@ -35,6 +35,24 @@ public class TelephonyIntents {
|
||||
*/
|
||||
public static final String ACTION_SERVICE_STATE_CHANGED = "android.intent.action.SERVICE_STATE";
|
||||
|
||||
/**
|
||||
* <p>Broadcast Action: The radio technology has changed. The intent will have the following
|
||||
* extra values:</p>
|
||||
* <ul>
|
||||
* <li><em>phoneName</em> - A string version of the new phone name.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p class="note">
|
||||
* You can <em>not</em> receive this through components declared
|
||||
* in manifests, only by explicitly registering for it with
|
||||
* {@link android.content.Context#registerReceiver(android.content.BroadcastReceiver,
|
||||
* android.content.IntentFilter) Context.registerReceiver()}.
|
||||
*
|
||||
* <p class="note">
|
||||
* Requires no permission.
|
||||
*/
|
||||
public static final String ACTION_RADIO_TECHNOLOGY_CHANGED
|
||||
= "android.intent.action.RADIO_TECHNOLOGY";
|
||||
|
||||
/**
|
||||
* Broadcast Action: The phone's signal strength has changed. The intent will have the
|
||||
@@ -47,7 +65,7 @@ public class TelephonyIntents {
|
||||
* <ul><li>0 means "-113 dBm or less".</li><li>31 means "-51 dBm or greater".</li></ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
*
|
||||
* <p class="note">
|
||||
* You can <em>not</em> receive this through components declared
|
||||
* in manifests, only by exlicitly registering for it with
|
||||
|
||||
@@ -26,8 +26,11 @@ public interface TelephonyProperties
|
||||
{
|
||||
//****** Baseband and Radio Interface version
|
||||
|
||||
/**
|
||||
* Baseband version
|
||||
//TODO T: property strings do not have to be gsm specific
|
||||
// change gsm.*operator.*" properties to "operator.*" properties
|
||||
|
||||
/**
|
||||
* Baseband version
|
||||
* Availability: property is available any time radio is on
|
||||
*/
|
||||
static final String PROPERTY_BASEBAND_VERSION = "gsm.version.baseband";
|
||||
@@ -47,6 +50,12 @@ public interface TelephonyProperties
|
||||
*/
|
||||
static final String PROPERTY_OPERATOR_NUMERIC = "gsm.operator.numeric";
|
||||
|
||||
/** 'true' if the device is on a manually selected network
|
||||
*
|
||||
* Availability: when registered to a network
|
||||
*/
|
||||
static final String PROPERTY_OPERATOR_ISMANUAL = "operator.ismanual";
|
||||
|
||||
/** 'true' if the device is considered roaming on this network for GSM
|
||||
* purposes.
|
||||
* Availability: when registered to a network
|
||||
@@ -60,7 +69,7 @@ public interface TelephonyProperties
|
||||
static final String PROPERTY_OPERATOR_ISO_COUNTRY = "gsm.operator.iso-country";
|
||||
|
||||
//****** SIM Card
|
||||
/**
|
||||
/**
|
||||
* One of <code>"UNKNOWN"</code> <code>"ABSENT"</code> <code>"PIN_REQUIRED"</code>
|
||||
* <code>"PUK_REQUIRED"</code> <code>"NETWORK_LOCKED"</code> or <code>"READY"</code>
|
||||
*/
|
||||
@@ -70,15 +79,15 @@ public interface TelephonyProperties
|
||||
* provider of the SIM. 5 or 6 decimal digits.
|
||||
* Availablity: SIM state must be "READY"
|
||||
*/
|
||||
static String PROPERTY_SIM_OPERATOR_NUMERIC = "gsm.sim.operator.numeric";
|
||||
static String PROPERTY_ICC_OPERATOR_NUMERIC = "gsm.sim.operator.numeric";
|
||||
|
||||
/** PROPERTY_SIM_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name.
|
||||
/** PROPERTY_ICC_OPERATOR_ALPHA is also known as the SPN, or Service Provider Name.
|
||||
* Availablity: SIM state must be "READY"
|
||||
*/
|
||||
static String PROPERTY_SIM_OPERATOR_ALPHA = "gsm.sim.operator.alpha";
|
||||
static String PROPERTY_ICC_OPERATOR_ALPHA = "gsm.sim.operator.alpha";
|
||||
|
||||
/** ISO country code equivalent for the SIM provider's country code*/
|
||||
static String PROPERTY_SIM_OPERATOR_ISO_COUNTRY = "gsm.sim.operator.iso-country";
|
||||
static String PROPERTY_ICC_OPERATOR_ISO_COUNTRY = "gsm.sim.operator.iso-country";
|
||||
|
||||
/**
|
||||
* Indicates the available radio technology. Values include: <code>"unknown"</code>,
|
||||
|
||||
@@ -22,7 +22,6 @@ import android.os.PowerManager;
|
||||
import android.provider.Telephony.Sms.Intents;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
import com.android.internal.telephony.gsm.SimUtils;
|
||||
|
||||
|
||||
/**
|
||||
@@ -44,6 +43,7 @@ public class WapPushOverSms {
|
||||
private final int WAKE_LOCK_TIMEOUT = 5000;
|
||||
|
||||
public WapPushOverSms(Phone phone) {
|
||||
|
||||
mContext = phone.getContext();
|
||||
createWakelock();
|
||||
}
|
||||
@@ -56,7 +56,7 @@ public class WapPushOverSms {
|
||||
*/
|
||||
public void dispatchWapPdu(byte[] pdu) {
|
||||
|
||||
if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + SimUtils.bytesToHexString(pdu));
|
||||
if (Config.LOGD) Log.d(LOG_TAG, "Rx: " + IccUtils.bytesToHexString(pdu));
|
||||
|
||||
int index = 0;
|
||||
int transactionId = pdu[index++] & 0xFF;
|
||||
@@ -225,3 +225,4 @@ public class WapPushOverSms {
|
||||
mContext.sendBroadcast(intent, permission);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,916 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.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.provider.Settings;
|
||||
import android.telephony.CellLocation;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.telephony.ServiceState;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_BASEBAND_VERSION;
|
||||
|
||||
import com.android.internal.telephony.CallStateException;
|
||||
import com.android.internal.telephony.CommandsInterface;
|
||||
import com.android.internal.telephony.Connection;
|
||||
import com.android.internal.telephony.DataConnection;
|
||||
import com.android.internal.telephony.IccCard;
|
||||
import com.android.internal.telephony.IccFileHandler;
|
||||
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
|
||||
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.RILConstants;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class CDMAPhone extends PhoneBase {
|
||||
static final String LOG_TAG = "CDMA";
|
||||
private static final boolean LOCAL_DEBUG = true;
|
||||
|
||||
//***** Instance Variables
|
||||
CdmaCallTracker mCT;
|
||||
CdmaSMSDispatcher mSMS;
|
||||
CdmaServiceStateTracker mSST;
|
||||
CdmaDataConnectionTracker mDataConnection;
|
||||
RuimFileHandler mRuimFileHandler;
|
||||
RuimRecords mRuimRecords;
|
||||
RuimCard mRuimCard;
|
||||
MyHandler h;
|
||||
ArrayList <FeatureCode> mPendingMMIs = new ArrayList<FeatureCode>();
|
||||
RuimPhoneBookInterfaceManager mRuimPhoneBookInterfaceManager;
|
||||
RuimSmsInterfaceManager mRuimSmsInterfaceManager;
|
||||
PhoneSubInfo mSubInfo;
|
||||
|
||||
protected RegistrantList mNvLoadedRegistrants = new RegistrantList();
|
||||
private String mEsn;
|
||||
private String mMeid;
|
||||
|
||||
Registrant mPostDialHandler;
|
||||
|
||||
|
||||
//***** Constructors
|
||||
public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier) {
|
||||
this(context,ci,notifier, false);
|
||||
}
|
||||
|
||||
public CDMAPhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
|
||||
boolean unitTestMode) {
|
||||
super(notifier, context, unitTestMode);
|
||||
|
||||
h = new MyHandler();
|
||||
mCM = ci;
|
||||
|
||||
mCM.setPhoneType(RILConstants.CDMA_PHONE);
|
||||
mCT = new CdmaCallTracker(this);
|
||||
mSST = new CdmaServiceStateTracker (this);
|
||||
mSMS = new CdmaSMSDispatcher(this);
|
||||
mIccFileHandler = new RuimFileHandler(this);
|
||||
mRuimRecords = new RuimRecords(this);
|
||||
mDataConnection = new CdmaDataConnectionTracker (this);
|
||||
mRuimCard = new RuimCard(this);
|
||||
mRuimPhoneBookInterfaceManager = new RuimPhoneBookInterfaceManager(this);
|
||||
mRuimSmsInterfaceManager = new RuimSmsInterfaceManager(this);
|
||||
mSubInfo = new PhoneSubInfo(this);
|
||||
|
||||
mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null);
|
||||
mRuimRecords.registerForRecordsLoaded(h, EVENT_RUIM_RECORDS_LOADED, null);
|
||||
mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
|
||||
mCM.registerForOn(h, EVENT_RADIO_ON, null);
|
||||
mCM.setOnSuppServiceNotification(h, EVENT_SSN, null);
|
||||
mCM.setOnCallRing(h, EVENT_CALL_RING, null);
|
||||
mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null);
|
||||
mCM.registerForNVReady(h, EVENT_NV_READY, null);
|
||||
|
||||
//Change the system setting
|
||||
Settings.Secure.putInt(mContext.getContentResolver(),
|
||||
Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.CDMA_PHONE);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
synchronized(PhoneProxy.lockForRadioTechnologyChange) {
|
||||
|
||||
//Unregister from all former registered events
|
||||
mRuimRecords.unregisterForRecordsLoaded(h); //EVENT_RUIM_RECORDS_LOADED
|
||||
mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE
|
||||
mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
|
||||
mCM.unregisterForOn(h); //EVENT_RADIO_ON
|
||||
mCM.unregisterForNVReady(h); //EVENT_NV_READY
|
||||
mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK
|
||||
mCM.unSetOnSuppServiceNotification(h);
|
||||
mCM.unSetOnCallRing(h);
|
||||
|
||||
//Force all referenced classes to unregister their former registered events
|
||||
mCT.dispose();
|
||||
mDataConnection.dispose();
|
||||
mSST.dispose();
|
||||
mSMS.dispose();
|
||||
mIccFileHandler.dispose(); // instance of RuimFileHandler
|
||||
mRuimRecords.dispose();
|
||||
mRuimCard.dispose();
|
||||
mRuimPhoneBookInterfaceManager.dispose();
|
||||
mRuimSmsInterfaceManager.dispose();
|
||||
mSubInfo.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeReferences() {
|
||||
this.mRuimPhoneBookInterfaceManager = null;
|
||||
this.mRuimSmsInterfaceManager = null;
|
||||
this.mSMS = null;
|
||||
this.mSubInfo = null;
|
||||
this.mRuimRecords = null;
|
||||
this.mIccFileHandler = null;
|
||||
this.mRuimCard = null;
|
||||
this.mDataConnection = null;
|
||||
this.mCT = null;
|
||||
this.mSST = null;
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if(LOCAL_DEBUG) Log.d(LOG_TAG, "CDMAPhone finalized");
|
||||
}
|
||||
|
||||
|
||||
//***** Overridden from Phone
|
||||
public ServiceState getServiceState() {
|
||||
return mSST.ss;
|
||||
}
|
||||
|
||||
public Phone.State
|
||||
getState() {
|
||||
return mCT.state;
|
||||
}
|
||||
|
||||
public String
|
||||
getPhoneName() {
|
||||
return "CDMA";
|
||||
}
|
||||
|
||||
public boolean canTransfer() {
|
||||
Log.e(LOG_TAG, "canTransfer: not possible in CDMA");
|
||||
return false;
|
||||
}
|
||||
|
||||
public CdmaCall
|
||||
getRingingCall() {
|
||||
return mCT.ringingCall;
|
||||
}
|
||||
|
||||
public void setMute(boolean muted) {
|
||||
mCT.setMute(muted);
|
||||
}
|
||||
|
||||
public boolean getMute() {
|
||||
return mCT.getMute();
|
||||
}
|
||||
|
||||
public void conference() throws CallStateException {
|
||||
// three way calls in CDMA will be handled by feature codes
|
||||
Log.e(LOG_TAG, "conference: not possible in CDMA");
|
||||
}
|
||||
|
||||
public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
|
||||
this.mCM.setPreferredVoicePrivacy(enable, onComplete);
|
||||
}
|
||||
|
||||
public void getEnhancedVoicePrivacy(Message onComplete) {
|
||||
this.mCM.getPreferredVoicePrivacy(onComplete);
|
||||
}
|
||||
|
||||
public void clearDisconnected() {
|
||||
mCT.clearDisconnected();
|
||||
}
|
||||
|
||||
public DataActivityState getDataActivityState() {
|
||||
DataActivityState ret = DataActivityState.NONE;
|
||||
|
||||
if (mSST.getCurrentCdmaDataConnectionState() != ServiceState.RADIO_TECHNOLOGY_UNKNOWN) {
|
||||
|
||||
switch (mDataConnection.getActivity()) {
|
||||
case DATAIN:
|
||||
ret = DataActivityState.DATAIN;
|
||||
break;
|
||||
|
||||
case DATAOUT:
|
||||
ret = DataActivityState.DATAOUT;
|
||||
break;
|
||||
|
||||
case DATAINANDOUT:
|
||||
ret = DataActivityState.DATAINANDOUT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*package*/ void
|
||||
notifySignalStrength() {
|
||||
mNotifier.notifySignalStrength(this);
|
||||
}
|
||||
|
||||
public Connection
|
||||
dial (String dialString) throws CallStateException {
|
||||
// Need to make sure dialString gets parsed properly
|
||||
String newDialString = PhoneNumberUtils.stripSeparators(dialString);
|
||||
|
||||
FeatureCode fc = FeatureCode.newFromDialString(newDialString, this);
|
||||
if (LOCAL_DEBUG) Log.d(LOG_TAG,
|
||||
"dialing w/ fc '" + fc + "'...");
|
||||
// check for feature code
|
||||
if (fc == null) {
|
||||
// check if call in progress
|
||||
if (!mCT.foregroundCall.isIdle()) {
|
||||
FeatureCode digits = new FeatureCode(this);
|
||||
// use dial number as poundString
|
||||
digits.poundString = newDialString;
|
||||
mPendingMMIs.add(fc);
|
||||
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, fc, null));
|
||||
digits.processCode();
|
||||
return null;
|
||||
} else {
|
||||
return mCT.dial(newDialString);
|
||||
}
|
||||
} else {
|
||||
mPendingMMIs.add(fc);
|
||||
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, fc, null));
|
||||
fc.processCode();
|
||||
|
||||
// FIXME should this return null or something else?
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSignalStrengthASU() {
|
||||
return mSST.rssi == 99 ? -1 : mSST.rssi;
|
||||
}
|
||||
|
||||
public boolean
|
||||
getMessageWaitingIndicator() {
|
||||
Log.e(LOG_TAG, "method getMessageWaitingIndicator is NOT supported in CDMA!");
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<? extends MmiCode>
|
||||
getPendingMmiCodes() {
|
||||
Log.e(LOG_TAG, "method getPendingMmiCodes is NOT supported in CDMA!");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void registerForSuppServiceNotification(
|
||||
Handler h, int what, Object obj) {
|
||||
Log.e(LOG_TAG, "method registerForSuppServiceNotification is NOT supported in CDMA!");
|
||||
}
|
||||
|
||||
public CdmaCall getBackgroundCall() {
|
||||
return mCT.backgroundCall;
|
||||
}
|
||||
|
||||
public String getGateway(String apnType) {
|
||||
return mDataConnection.getGateway();
|
||||
}
|
||||
|
||||
public boolean handleInCallMmiCommands(String dialString) {
|
||||
Log.e(LOG_TAG, "method handleInCallMmiCommands is NOT supported in CDMA!");
|
||||
return false;
|
||||
}
|
||||
|
||||
public int enableApnType(String type) {
|
||||
// This request is mainly used to enable MMS APN
|
||||
// In CDMA there is no need to enable/disable a different APN for MMS
|
||||
Log.d(LOG_TAG, "Request to enableApnType("+type+")");
|
||||
if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
|
||||
return Phone.APN_ALREADY_ACTIVE;
|
||||
} else {
|
||||
return Phone.APN_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
public int disableApnType(String type) {
|
||||
// This request is mainly used to disable MMS APN
|
||||
// In CDMA there is no need to enable/disable a different APN for MMS
|
||||
Log.d(LOG_TAG, "Request to disableApnType("+type+")");
|
||||
if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
|
||||
return Phone.APN_REQUEST_STARTED;
|
||||
} else {
|
||||
return Phone.APN_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
public String getActiveApn() {
|
||||
Log.d(LOG_TAG, "Request to getActiveApn()");
|
||||
return null;
|
||||
}
|
||||
|
||||
public void
|
||||
setNetworkSelectionModeAutomatic(Message response) {
|
||||
Log.e(LOG_TAG, "method setNetworkSelectionModeAutomatic is NOT supported in CDMA!");
|
||||
}
|
||||
|
||||
public void unregisterForSuppServiceNotification(Handler h) {
|
||||
Log.e(LOG_TAG, "method unregisterForSuppServiceNotification is NOT supported in CDMA!");
|
||||
}
|
||||
|
||||
public void
|
||||
acceptCall() throws CallStateException {
|
||||
mCT.acceptCall();
|
||||
}
|
||||
|
||||
public void
|
||||
rejectCall() throws CallStateException {
|
||||
mCT.rejectCall();
|
||||
}
|
||||
|
||||
public void
|
||||
switchHoldingAndActive() throws CallStateException {
|
||||
mCT.switchWaitingOrHoldingAndActive();
|
||||
}
|
||||
|
||||
public String getLine1Number() {
|
||||
return mRuimRecords.getMdnNumber();
|
||||
}
|
||||
|
||||
public void getCallWaiting(Message onComplete) {
|
||||
mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
|
||||
}
|
||||
|
||||
public void
|
||||
setRadioPower(boolean power) {
|
||||
mSST.setRadioPower(power);
|
||||
}
|
||||
|
||||
public String getEsn() {
|
||||
return mEsn;
|
||||
}
|
||||
|
||||
public String getMeid() {
|
||||
return mMeid;
|
||||
}
|
||||
|
||||
//returns MEID in CDMA
|
||||
public String getDeviceId() {
|
||||
return getMeid();
|
||||
}
|
||||
|
||||
public String getDeviceSvn() {
|
||||
Log.d(LOG_TAG, "getDeviceSvn(): return 0");
|
||||
return "0";
|
||||
}
|
||||
|
||||
public String getSubscriberId() {
|
||||
Log.e(LOG_TAG, "method getSubscriberId for IMSI is NOT supported in CDMA!");
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean canConference() {
|
||||
Log.e(LOG_TAG, "canConference: not possible in CDMA");
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getInterfaceName(String apnType) {
|
||||
return mDataConnection.getInterfaceName();
|
||||
}
|
||||
|
||||
public CellLocation getCellLocation() {
|
||||
return mSST.cellLoc;
|
||||
}
|
||||
|
||||
public boolean disableDataConnectivity() {
|
||||
return mDataConnection.setDataEnabled(false);
|
||||
}
|
||||
|
||||
public CdmaCall getForegroundCall() {
|
||||
return mCT.foregroundCall;
|
||||
}
|
||||
|
||||
public void
|
||||
selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network,
|
||||
Message response) {
|
||||
Log.e(LOG_TAG, "selectNetworkManually: not possible in CDMA");
|
||||
}
|
||||
|
||||
public void setOnPostDialCharacter(Handler h, int what, Object obj) {
|
||||
Log.e(LOG_TAG, "setOnPostDialCharacter: not possible in CDMA");
|
||||
}
|
||||
|
||||
public boolean handlePinMmi(String dialString) {
|
||||
Log.e(LOG_TAG, "method handlePinMmi is NOT supported in CDMA!");
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isDataConnectivityPossible() {
|
||||
boolean noData = mDataConnection.getDataEnabled() &&
|
||||
getDataConnectionState() == DataState.DISCONNECTED;
|
||||
return !noData && getIccCard().getState() == IccCard.State.READY &&
|
||||
getServiceState().getState() == ServiceState.STATE_IN_SERVICE &&
|
||||
(mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming());
|
||||
}
|
||||
|
||||
public void setLine1Number(String alphaTag, String number, Message onComplete) {
|
||||
Log.e(LOG_TAG, "setLine1Number: not possible in CDMA");
|
||||
}
|
||||
|
||||
public String[] getDnsServers(String apnType) {
|
||||
return mDataConnection.getDnsServers();
|
||||
}
|
||||
|
||||
public IccCard getIccCard() {
|
||||
return mRuimCard;
|
||||
}
|
||||
|
||||
public String getIccSerialNumber() {
|
||||
return mRuimRecords.iccid;
|
||||
}
|
||||
|
||||
public void setCallWaiting(boolean enable, Message onComplete) {
|
||||
Log.e(LOG_TAG, "method setCallWaiting is NOT supported in CDMA!");
|
||||
}
|
||||
|
||||
public void updateServiceLocation(Message response) {
|
||||
mSST.getLacAndCid(response);
|
||||
}
|
||||
|
||||
public void setDataRoamingEnabled(boolean enable) {
|
||||
mDataConnection.setDataOnRoamingEnabled(enable);
|
||||
}
|
||||
|
||||
public String getIpAddress(String apnType) {
|
||||
return mDataConnection.getIpAddress();
|
||||
}
|
||||
|
||||
public void
|
||||
getNeighboringCids(Message response) {
|
||||
// WINK:TODO: implement after Cupcake merge
|
||||
mCM.getNeighboringCids(response); // workaround.
|
||||
}
|
||||
|
||||
public DataState getDataConnectionState() {
|
||||
DataState ret = DataState.DISCONNECTED;
|
||||
|
||||
if ((SystemProperties.get("adb.connected", "").length() > 0)
|
||||
&& (SystemProperties.get("android.net.use-adb-networking", "")
|
||||
.length() > 0)) {
|
||||
// We're connected to an ADB host and we have USB networking
|
||||
// turned on. No matter what the radio state is,
|
||||
// we report data connected
|
||||
|
||||
ret = DataState.CONNECTED;
|
||||
} else if (mSST.getCurrentCdmaDataConnectionState()
|
||||
== ServiceState.RADIO_TECHNOLOGY_UNKNOWN) {
|
||||
// If we're out of service, open TCP sockets may still work
|
||||
// but no data will flow
|
||||
ret = DataState.DISCONNECTED;
|
||||
} else {
|
||||
switch (mDataConnection.getState()) {
|
||||
case FAILED:
|
||||
case IDLE:
|
||||
ret = DataState.DISCONNECTED;
|
||||
break;
|
||||
|
||||
case CONNECTED:
|
||||
case DISCONNECTING:
|
||||
if ( mCT.state != Phone.State.IDLE
|
||||
&& !mSST.isConcurrentVoiceAndData()) {
|
||||
ret = DataState.SUSPENDED;
|
||||
} else {
|
||||
ret = DataState.CONNECTED;
|
||||
}
|
||||
break;
|
||||
|
||||
case INITING:
|
||||
case CONNECTING:
|
||||
case SCANNING:
|
||||
ret = DataState.CONNECTING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void sendUssdResponse(String ussdMessge) {
|
||||
Log.e(LOG_TAG, "sendUssdResponse: not possible in CDMA");
|
||||
}
|
||||
|
||||
public void sendDtmf(char c) {
|
||||
if (!PhoneNumberUtils.is12Key(c)) {
|
||||
Log.e(LOG_TAG,
|
||||
"sendDtmf called with invalid character '" + c + "'");
|
||||
} else {
|
||||
if (mCT.state == Phone.State.OFFHOOK) {
|
||||
mCM.sendDtmf(c, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startDtmf(char c) {
|
||||
if (!PhoneNumberUtils.is12Key(c)) {
|
||||
Log.e(LOG_TAG,
|
||||
"startDtmf called with invalid character '" + c + "'");
|
||||
} else {
|
||||
mCM.startDtmf(c, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void stopDtmf() {
|
||||
mCM.stopDtmf(null);
|
||||
}
|
||||
|
||||
public void getAvailableNetworks(Message response) {
|
||||
Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA");
|
||||
}
|
||||
|
||||
public String[] getActiveApnTypes() {
|
||||
String[] result;
|
||||
Log.d(LOG_TAG, "Request to getActiveApn()");
|
||||
result = new String[1];
|
||||
result[0] = Phone.APN_TYPE_DEFAULT;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode, Message onComplete) {
|
||||
Log.e(LOG_TAG, "getAvailableNetworks: not possible in CDMA");
|
||||
}
|
||||
|
||||
public void enableLocationUpdates() {
|
||||
mSST.enableLocationUpdates();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public void getPdpContextList(Message response) {
|
||||
getDataCallList(response);
|
||||
}
|
||||
|
||||
public void getDataCallList(Message response) {
|
||||
mCM.getDataCallList(response);
|
||||
}
|
||||
|
||||
public boolean getDataRoamingEnabled() {
|
||||
return mDataConnection.getDataOnRoamingEnabled();
|
||||
}
|
||||
|
||||
public List<DataConnection> getCurrentDataConnectionList () {
|
||||
return mDataConnection.getAllDataConnections();
|
||||
}
|
||||
|
||||
public void setVoiceMailNumber(String alphaTag,
|
||||
String voiceMailNumber,
|
||||
Message onComplete) {
|
||||
//mSIMRecords.setVoiceMailNumber(alphaTag, voiceMailNumber, onComplete);
|
||||
//TODO: Where do we have to store this value has to be clarified with QC
|
||||
}
|
||||
|
||||
public String getVoiceMailNumber() {
|
||||
//TODO: Where can we get this value has to be clarified with QC
|
||||
//return mSIMRecords.getVoiceMailNumber();
|
||||
// throw new RuntimeException();
|
||||
return "12345";
|
||||
}
|
||||
|
||||
public String getVoiceMailAlphaTag() {
|
||||
// TODO: Where can we get this value has to be clarified with QC.
|
||||
String ret = "";//TODO: Remove = "", if we know where to get this value.
|
||||
|
||||
//ret = mSIMRecords.getVoiceMailAlphaTag();
|
||||
|
||||
if (ret == null || ret.length() == 0) {
|
||||
return mContext.getText(
|
||||
com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean enableDataConnectivity() {
|
||||
return mDataConnection.setDataEnabled(true);
|
||||
}
|
||||
|
||||
public void disableLocationUpdates() {
|
||||
mSST.disableLocationUpdates();
|
||||
}
|
||||
|
||||
public boolean getIccRecordsLoaded() {
|
||||
return mRuimRecords.getRecordsLoaded();
|
||||
}
|
||||
|
||||
public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
|
||||
Log.e(LOG_TAG, "getCallForwardingOption: not possible in CDMA");
|
||||
}
|
||||
|
||||
public void setCallForwardingOption(int commandInterfaceCFAction,
|
||||
int commandInterfaceCFReason,
|
||||
String dialingNumber,
|
||||
int timerSeconds,
|
||||
Message onComplete) {
|
||||
Log.e(LOG_TAG, "setCallForwardingOption: not possible in CDMA");
|
||||
}
|
||||
|
||||
public void
|
||||
getOutgoingCallerIdDisplay(Message onComplete) {
|
||||
Log.e(LOG_TAG, "getOutgoingCallerIdDisplay: not possible in CDMA");
|
||||
}
|
||||
|
||||
public boolean
|
||||
getCallForwardingIndicator() {
|
||||
Log.e(LOG_TAG, "getCallForwardingIndicator: not possible in CDMA");
|
||||
return false;
|
||||
}
|
||||
|
||||
public void explicitCallTransfer() {
|
||||
Log.e(LOG_TAG, "explicitCallTransfer: not possible in CDMA");
|
||||
}
|
||||
|
||||
public String getLine1AlphaTag() {
|
||||
Log.e(LOG_TAG, "getLine1AlphaTag: not possible in CDMA");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify any interested party of a Phone state change.
|
||||
*/
|
||||
/*package*/ void notifyPhoneStateChanged() {
|
||||
mNotifier.notifyPhoneState(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies registrants (ie, activities in the Phone app) about
|
||||
* changes to call state (including Phone and Connection changes).
|
||||
*/
|
||||
/*package*/ void notifyCallStateChanged() {
|
||||
/* we'd love it if this was package-scoped*/
|
||||
super.notifyCallStateChangedP();
|
||||
}
|
||||
|
||||
void notifyServiceStateChanged(ServiceState ss) {
|
||||
super.notifyServiceStateChangedP(ss);
|
||||
}
|
||||
|
||||
void notifyLocationChanged() {
|
||||
mNotifier.notifyCellLocation(this);
|
||||
}
|
||||
|
||||
/*package*/ void notifyNewRingingConnection(Connection c) {
|
||||
/* we'd love it if this was package-scoped*/
|
||||
super.notifyNewRingingConnectionP(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifiy registrants of a RING event.
|
||||
*/
|
||||
void notifyIncomingRing() {
|
||||
AsyncResult ar = new AsyncResult(null, this, null);
|
||||
mIncomingRingRegistrants.notifyRegistrants(ar);
|
||||
}
|
||||
|
||||
/*package*/ void notifyDisconnect(Connection cn) {
|
||||
mDisconnectRegistrants.notifyResult(cn);
|
||||
}
|
||||
|
||||
void notifyUnknownConnection() {
|
||||
mUnknownConnectionRegistrants.notifyResult(this);
|
||||
}
|
||||
|
||||
/*package*/ void
|
||||
updateMessageWaitingIndicator(boolean mwi) {
|
||||
// this also calls notifyMessageWaitingIndicator()
|
||||
mRuimRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the given FC from the pending list and notifies
|
||||
* registrants that it is complete.
|
||||
* @param fc FC that is done
|
||||
*/
|
||||
/*package*/ void onMMIDone(FeatureCode fc) {
|
||||
/* Only notify complete if it's on the pending list.
|
||||
* Otherwise, it's already been handled (eg, previously canceled).
|
||||
* The exception is cancellation of an incoming USSD-REQUEST, which is
|
||||
* not on the list.
|
||||
*/
|
||||
if (mPendingMMIs.remove(fc)) {
|
||||
mMmiCompleteRegistrants.notifyRegistrants(
|
||||
new AsyncResult(null, fc, null));
|
||||
}
|
||||
}
|
||||
|
||||
//***** Inner Classes
|
||||
class MyHandler extends Handler {
|
||||
MyHandler() {
|
||||
}
|
||||
|
||||
MyHandler(Looper l) {
|
||||
super(l);
|
||||
}
|
||||
|
||||
public void handleMessage(Message msg) {
|
||||
AsyncResult ar;
|
||||
Message onComplete;
|
||||
|
||||
switch(msg.what) {
|
||||
case EVENT_RADIO_AVAILABLE: {
|
||||
mCM.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
|
||||
|
||||
mCM.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_GET_BASEBAND_VERSION_DONE:{
|
||||
ar = (AsyncResult)msg.obj;
|
||||
|
||||
if (ar.exception != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (LOCAL_DEBUG) Log.d(LOG_TAG, "Baseband version: " + ar.result);
|
||||
setSystemProperty(PROPERTY_BASEBAND_VERSION, (String)ar.result);
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_GET_DEVICE_IDENTITY_DONE:{
|
||||
ar = (AsyncResult)msg.obj;
|
||||
|
||||
if (ar.exception != null) {
|
||||
break;
|
||||
}
|
||||
String[] respId = (String[])ar.result;
|
||||
mEsn = respId[2];
|
||||
mMeid = respId[3];
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_RUIM_RECORDS_LOADED:{
|
||||
Log.d(LOG_TAG, "Event EVENT_RUIM_RECORDS_LOADED Received");
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:{
|
||||
Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_RADIO_ON:{
|
||||
Log.d(LOG_TAG, "Event EVENT_RADIO_ON Received");
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_SSN:{
|
||||
Log.d(LOG_TAG, "Event EVENT_SSN Received");
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_CALL_RING:{
|
||||
Log.d(LOG_TAG, "Event EVENT_CALL_RING Received");
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_REGISTERED_TO_NETWORK:{
|
||||
Log.d(LOG_TAG, "Event EVENT_REGISTERED_TO_NETWORK Received");
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_NV_READY:{
|
||||
Log.d(LOG_TAG, "Event EVENT_NV_READY Received");
|
||||
//Inform the Service State Tracker
|
||||
mNvLoadedRegistrants.notifyRegistrants();
|
||||
}
|
||||
break;
|
||||
|
||||
default:{
|
||||
throw new RuntimeException("unexpected event not handled");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the PhoneSubInfo of the CDMAPhone
|
||||
*/
|
||||
public PhoneSubInfo getPhoneSubInfo(){
|
||||
return mSubInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the IccSmsInterfaceManager of the CDMAPhone
|
||||
*/
|
||||
public IccSmsInterfaceManager getIccSmsInterfaceManager(){
|
||||
return mRuimSmsInterfaceManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the IccPhoneBookInterfaceManager of the CDMAPhone
|
||||
*/
|
||||
public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
|
||||
return mRuimPhoneBookInterfaceManager;
|
||||
}
|
||||
|
||||
public void registerForNvLoaded(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
mNvLoadedRegistrants.add(r);
|
||||
}
|
||||
|
||||
public void unregisterForNvLoaded(Handler h) {
|
||||
mNvLoadedRegistrants.remove(h);
|
||||
}
|
||||
|
||||
// override for allowing access from other classes of this package
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public final void setSystemProperty(String property, String value) {
|
||||
super.setSystemProperty(property, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Handler getHandler(){
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public IccFileHandler getIccFileHandler(){
|
||||
return this.mIccFileHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the TTY mode of the CDMAPhone
|
||||
*/
|
||||
public void setTTYModeEnabled(boolean enable, Message onComplete) {
|
||||
this.mCM.setTTYModeEnabled(enable, onComplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the TTY mode of the CDMAPhone
|
||||
*/
|
||||
public void queryTTYModeEnabled(Message onComplete) {
|
||||
this.mCM.queryTTYModeEnabled(onComplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate or deactivate cell broadcast SMS.
|
||||
*
|
||||
* @param activate
|
||||
* 0 = activate, 1 = deactivate
|
||||
* @param response
|
||||
* Callback message is empty on completion
|
||||
*/
|
||||
public void activateCellBroadcastSms(int activate, Message response) {
|
||||
mSMS.activateCellBroadcastSms(activate, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the current configuration of cdma cell broadcast SMS.
|
||||
*
|
||||
* @param response
|
||||
* Callback message is empty on completion
|
||||
*/
|
||||
public void getCellBroadcastSmsConfig(Message response){
|
||||
mSMS.getCellBroadcastSmsConfig(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure cdma cell broadcast SMS.
|
||||
*
|
||||
* @param response
|
||||
* Callback message is empty on completion
|
||||
*/
|
||||
public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){
|
||||
mSMS.setCellBroadcastConfig(configValuesArray, response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
209
telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
Normal file
209
telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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 java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.android.internal.telephony.Call;
|
||||
import com.android.internal.telephony.CallStateException;
|
||||
import com.android.internal.telephony.Connection;
|
||||
import com.android.internal.telephony.DriverCall;
|
||||
import com.android.internal.telephony.Phone;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public final class CdmaCall extends Call {
|
||||
/*************************** Instance Variables **************************/
|
||||
|
||||
/*package*/ ArrayList<Connection> connections = new ArrayList<Connection>();
|
||||
/*package*/ State state = State.IDLE;
|
||||
/*package*/ CdmaCallTracker owner;
|
||||
|
||||
/***************************** Class Methods *****************************/
|
||||
|
||||
static State
|
||||
stateFromDCState (DriverCall.State dcState) {
|
||||
switch (dcState) {
|
||||
case ACTIVE: return State.ACTIVE;
|
||||
case HOLDING: return State.HOLDING;
|
||||
case DIALING: return State.DIALING;
|
||||
case ALERTING: return State.ALERTING;
|
||||
case INCOMING: return State.INCOMING;
|
||||
case WAITING: return State.WAITING;
|
||||
default: throw new RuntimeException ("illegal call state:" + dcState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************** Constructors *****************************/
|
||||
/*package*/
|
||||
CdmaCall (CdmaCallTracker owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
/************************** Overridden from Call *************************/
|
||||
public List<Connection>
|
||||
getConnections() {
|
||||
// FIXME should return Collections.unmodifiableList();
|
||||
return connections;
|
||||
}
|
||||
|
||||
public State
|
||||
getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public Phone
|
||||
getPhone() {
|
||||
//TODO, see GsmCall
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isMultiparty() {
|
||||
return connections.size() > 1;
|
||||
}
|
||||
|
||||
/** Please note: if this is the foreground call and a
|
||||
* background call exists, the background call will be resumed
|
||||
* because an AT+CHLD=1 will be sent
|
||||
*/
|
||||
public void
|
||||
hangup() throws CallStateException {
|
||||
owner.hangup(this);
|
||||
}
|
||||
|
||||
public String
|
||||
toString() {
|
||||
return state.toString();
|
||||
}
|
||||
|
||||
//***** Called from CdmaConnection
|
||||
|
||||
/*package*/ void
|
||||
attach(Connection conn, DriverCall dc) {
|
||||
connections.add(conn);
|
||||
|
||||
state = stateFromDCState (dc.state);
|
||||
}
|
||||
|
||||
/*package*/ void
|
||||
attachFake(Connection conn, State state) {
|
||||
connections.add(conn);
|
||||
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by CdmaConnection when it has disconnected
|
||||
*/
|
||||
void
|
||||
connectionDisconnected(CdmaConnection 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(CdmaConnection conn) {
|
||||
connections.remove(conn);
|
||||
|
||||
if (connections.size() == 0) {
|
||||
state = State.IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ boolean
|
||||
update (CdmaConnection conn, DriverCall dc) {
|
||||
State newState;
|
||||
boolean changed = false;
|
||||
|
||||
newState = stateFromDCState(dc.state);
|
||||
|
||||
if (newState != state) {
|
||||
state = newState;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if there's no space in this call for additional
|
||||
* connections to be added via "conference"
|
||||
*/
|
||||
/*package*/ boolean
|
||||
isFull() {
|
||||
return connections.size() == CdmaCallTracker.MAX_CONNECTIONS_PER_CALL;
|
||||
}
|
||||
|
||||
//***** Called from CdmaCallTracker
|
||||
|
||||
|
||||
/**
|
||||
* Called when this Call is being hung up locally (eg, user pressed "end")
|
||||
* Note that at this point, the hangup request has been dispatched to the radio
|
||||
* but no response has yet been received so update() has not yet been called
|
||||
*/
|
||||
void
|
||||
onHangupLocal() {
|
||||
for (int i = 0, s = connections.size()
|
||||
; i < s; i++
|
||||
) {
|
||||
CdmaConnection cn = (CdmaConnection)connections.get(i);
|
||||
|
||||
cn.onHangupLocal();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when it's time to clean up disconnected Connection objects
|
||||
*/
|
||||
void clearDisconnected() {
|
||||
for (int i = connections.size() - 1 ; i >= 0 ; i--) {
|
||||
CdmaConnection cn = (CdmaConnection)connections.get(i);
|
||||
|
||||
if (cn.getState() == State.DISCONNECTED) {
|
||||
connections.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (connections.size() == 0) {
|
||||
state = State.IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,860 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Registrant;
|
||||
import android.os.RegistrantList;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.telephony.ServiceState;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.CallStateException;
|
||||
import com.android.internal.telephony.CallTracker;
|
||||
import com.android.internal.telephony.CommandsInterface;
|
||||
import com.android.internal.telephony.Connection;
|
||||
import com.android.internal.telephony.DriverCall;
|
||||
import com.android.internal.telephony.Phone;
|
||||
import com.android.internal.telephony.PhoneProxy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public final class CdmaCallTracker extends CallTracker {
|
||||
static final String LOG_TAG = "CDMA";
|
||||
|
||||
private static final boolean REPEAT_POLLING = false;
|
||||
|
||||
private static final boolean DBG_POLL = false;
|
||||
|
||||
//***** Constants
|
||||
|
||||
static final int MAX_CONNECTIONS = 1; // only 1 connection allowed in CDMA
|
||||
static final int MAX_CONNECTIONS_PER_CALL = 1; // only 1 connection allowed per call
|
||||
|
||||
//***** Instance Variables
|
||||
|
||||
CdmaConnection connections[] = new CdmaConnection[MAX_CONNECTIONS];
|
||||
RegistrantList voiceCallEndedRegistrants = new RegistrantList();
|
||||
RegistrantList voiceCallStartedRegistrants = new RegistrantList();
|
||||
|
||||
|
||||
// connections dropped durin last poll
|
||||
ArrayList<CdmaConnection> droppedDuringPoll
|
||||
= new ArrayList<CdmaConnection>(MAX_CONNECTIONS);
|
||||
|
||||
CdmaCall ringingCall = new CdmaCall(this);
|
||||
// A call that is ringing or (call) waiting
|
||||
CdmaCall foregroundCall = new CdmaCall(this);
|
||||
CdmaCall backgroundCall = new CdmaCall(this);
|
||||
|
||||
CdmaConnection pendingMO;
|
||||
boolean hangupPendingMO;
|
||||
|
||||
CDMAPhone phone;
|
||||
|
||||
boolean desiredMute = false; // false = mute off
|
||||
|
||||
Phone.State state = Phone.State.IDLE;
|
||||
|
||||
|
||||
// boolean needsPoll;
|
||||
|
||||
|
||||
|
||||
//***** Events
|
||||
|
||||
//***** Constructors
|
||||
CdmaCallTracker(CDMAPhone phone) {
|
||||
this.phone = phone;
|
||||
cm = phone.mCM;
|
||||
cm.registerForCallStateChanged(this, EVENT_CALL_STATE_CHANGE, null);
|
||||
cm.registerForOn(this, EVENT_RADIO_AVAILABLE, null);
|
||||
cm.registerForNotAvailable(this, EVENT_RADIO_NOT_AVAILABLE, null);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
cm.unregisterForCallStateChanged(this);
|
||||
cm.unregisterForOn(this);
|
||||
cm.unregisterForNotAvailable(this);
|
||||
|
||||
for(CdmaConnection c : connections) {
|
||||
try {
|
||||
if(c != null) hangup(c);
|
||||
} catch (CallStateException ex) {
|
||||
Log.e(LOG_TAG, "unexpected error on hangup during dispose");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
if(pendingMO != null) hangup(pendingMO);
|
||||
} catch (CallStateException ex) {
|
||||
Log.e(LOG_TAG, "unexpected error on hangup during dispose");
|
||||
}
|
||||
|
||||
clearDisconnected();
|
||||
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
Log.d(LOG_TAG, "CdmaCallTracker finalized");
|
||||
}
|
||||
|
||||
//***** Instance Methods
|
||||
|
||||
//***** Public Methods
|
||||
public void registerForVoiceCallStarted(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant(h, what, obj);
|
||||
voiceCallStartedRegistrants.add(r);
|
||||
}
|
||||
public void unregisterForVoiceCallStarted(Handler h) {
|
||||
voiceCallStartedRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void registerForVoiceCallEnded(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant(h, what, obj);
|
||||
voiceCallEndedRegistrants.add(r);
|
||||
}
|
||||
|
||||
public void unregisterForVoiceCallEnded(Handler h) {
|
||||
voiceCallEndedRegistrants.remove(h);
|
||||
}
|
||||
|
||||
private void
|
||||
fakeHoldForegroundBeforeDial() {
|
||||
List<Connection> connCopy;
|
||||
|
||||
// We need to make a copy here, since fakeHoldBeforeDial()
|
||||
// modifies the lists, and we don't want to reverse the order
|
||||
connCopy = (List<Connection>) foregroundCall.connections.clone();
|
||||
|
||||
for (int i = 0, s = connCopy.size() ; i < s ; i++) {
|
||||
CdmaConnection conn = (CdmaConnection)connCopy.get(i);
|
||||
|
||||
conn.fakeHoldBeforeDial();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clirMode is one of the CLIR_ constants
|
||||
*/
|
||||
Connection
|
||||
dial (String dialString, int clirMode) throws CallStateException {
|
||||
// note that this triggers call state changed notif
|
||||
clearDisconnected();
|
||||
|
||||
if (!canDial()) {
|
||||
throw new CallStateException("cannot dial in current state");
|
||||
}
|
||||
|
||||
// The new call must be assigned to the foreground call.
|
||||
// That call must be idle, so place anything that's
|
||||
// there on hold
|
||||
if (foregroundCall.getState() == CdmaCall.State.ACTIVE) {
|
||||
// this will probably be done by the radio anyway
|
||||
// but the dial might fail before this happens
|
||||
// and we need to make sure the foreground call is clear
|
||||
// for the newly dialed connection
|
||||
switchWaitingOrHoldingAndActive();
|
||||
|
||||
// Fake local state so that
|
||||
// a) foregroundCall is empty for the newly dialed connection
|
||||
// b) hasNonHangupStateChanged remains false in the
|
||||
// next poll, so that we don't clear a failed dialing call
|
||||
fakeHoldForegroundBeforeDial();
|
||||
}
|
||||
|
||||
if (foregroundCall.getState() != CdmaCall.State.IDLE) {
|
||||
//we should have failed in !canDial() above before we get here
|
||||
throw new CallStateException("cannot dial in current state");
|
||||
}
|
||||
|
||||
pendingMO = new CdmaConnection(phone.getContext(), dialString, this, foregroundCall);
|
||||
hangupPendingMO = false;
|
||||
|
||||
if (pendingMO.address == null || pendingMO.address.length() == 0
|
||||
|| pendingMO.address.indexOf(PhoneNumberUtils.WILD) >= 0
|
||||
) {
|
||||
// Phone number is invalid
|
||||
pendingMO.cause = Connection.DisconnectCause.INVALID_NUMBER;
|
||||
|
||||
// handlePollCalls() will notice this call not present
|
||||
// and will mark it as dropped.
|
||||
pollCallsWhenSafe();
|
||||
} else {
|
||||
// Always unmute when initiating a new call
|
||||
setMute(false);
|
||||
|
||||
cm.dial(pendingMO.address, clirMode, obtainCompleteMessage());
|
||||
}
|
||||
|
||||
updatePhoneState();
|
||||
phone.notifyCallStateChanged();
|
||||
|
||||
return pendingMO;
|
||||
}
|
||||
|
||||
|
||||
Connection
|
||||
dial (String dialString) throws CallStateException {
|
||||
return dial(dialString, CommandsInterface.CLIR_DEFAULT);
|
||||
}
|
||||
|
||||
void
|
||||
acceptCall () throws CallStateException {
|
||||
// FIXME if SWITCH fails, should retry with ANSWER
|
||||
// in case the active/holding call disappeared and this
|
||||
// is no longer call waiting
|
||||
|
||||
if (ringingCall.getState() == CdmaCall.State.INCOMING) {
|
||||
Log.i("phone", "acceptCall: incoming...");
|
||||
// Always unmute when answering a new call
|
||||
setMute(false);
|
||||
cm.acceptCall(obtainCompleteMessage());
|
||||
} else if (ringingCall.getState() == CdmaCall.State.WAITING) {
|
||||
setMute(false);
|
||||
switchWaitingOrHoldingAndActive();
|
||||
} else {
|
||||
throw new CallStateException("phone not ringing");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rejectCall () throws CallStateException {
|
||||
// AT+CHLD=0 means "release held or UDUB"
|
||||
// so if the phone isn't ringing, this could hang up held
|
||||
if (ringingCall.getState().isRinging()) {
|
||||
cm.rejectCall(obtainCompleteMessage());
|
||||
} else {
|
||||
throw new CallStateException("phone not ringing");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
switchWaitingOrHoldingAndActive() throws CallStateException {
|
||||
// Should we bother with this check?
|
||||
if (ringingCall.getState() == CdmaCall.State.INCOMING) {
|
||||
throw new CallStateException("cannot be in the incoming state");
|
||||
} else {
|
||||
cm.sendCDMAFeatureCode("", obtainCompleteMessage(EVENT_SWITCH_RESULT));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conference() throws CallStateException {
|
||||
// three way calls in CDMA will be handled by feature codes
|
||||
Log.e(LOG_TAG, "conference: not possible in CDMA");
|
||||
}
|
||||
|
||||
void
|
||||
explicitCallTransfer() throws CallStateException {
|
||||
cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT));
|
||||
}
|
||||
|
||||
void
|
||||
clearDisconnected() {
|
||||
internalClearDisconnected();
|
||||
|
||||
updatePhoneState();
|
||||
phone.notifyCallStateChanged();
|
||||
}
|
||||
|
||||
boolean
|
||||
canConference() {
|
||||
return foregroundCall.getState() == CdmaCall.State.ACTIVE
|
||||
&& backgroundCall.getState() == CdmaCall.State.HOLDING
|
||||
&& !backgroundCall.isFull()
|
||||
&& !foregroundCall.isFull();
|
||||
}
|
||||
|
||||
boolean
|
||||
canDial() {
|
||||
boolean ret;
|
||||
int serviceState = phone.getServiceState().getState();
|
||||
|
||||
ret = (serviceState != ServiceState.STATE_POWER_OFF) &&
|
||||
pendingMO == null
|
||||
&& !ringingCall.isRinging()
|
||||
&& (!foregroundCall.getState().isAlive()
|
||||
|| !backgroundCall.getState().isAlive());
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
boolean
|
||||
canTransfer() {
|
||||
Log.e(LOG_TAG, "canTransfer: not possible in CDMA");
|
||||
return false;
|
||||
}
|
||||
|
||||
//***** Private Instance Methods
|
||||
|
||||
private void
|
||||
internalClearDisconnected() {
|
||||
ringingCall.clearDisconnected();
|
||||
foregroundCall.clearDisconnected();
|
||||
backgroundCall.clearDisconnected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a message to use for signalling "invoke getCurrentCalls() when
|
||||
* this operation and all other pending operations are complete
|
||||
*/
|
||||
private Message
|
||||
obtainCompleteMessage() {
|
||||
return obtainCompleteMessage(EVENT_OPERATION_COMPLETE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a message to use for signalling "invoke getCurrentCalls() when
|
||||
* this operation and all other pending operations are complete
|
||||
*/
|
||||
private Message
|
||||
obtainCompleteMessage(int what) {
|
||||
pendingOperations++;
|
||||
lastRelevantPoll = null;
|
||||
needsPoll = true;
|
||||
|
||||
if (DBG_POLL) log("obtainCompleteMessage: pendingOperations=" +
|
||||
pendingOperations + ", needsPoll=" + needsPoll);
|
||||
|
||||
return obtainMessage(what);
|
||||
}
|
||||
|
||||
private void
|
||||
operationComplete() {
|
||||
pendingOperations--;
|
||||
|
||||
if (DBG_POLL) log("operationComplete: pendingOperations=" +
|
||||
pendingOperations + ", needsPoll=" + needsPoll);
|
||||
|
||||
if (pendingOperations == 0 && needsPoll) {
|
||||
lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
|
||||
cm.getCurrentCalls(lastRelevantPoll);
|
||||
} else if (pendingOperations < 0) {
|
||||
// this should never happen
|
||||
Log.e(LOG_TAG,"CdmaCallTracker.pendingOperations < 0");
|
||||
pendingOperations = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void
|
||||
updatePhoneState() {
|
||||
Phone.State oldState = state;
|
||||
|
||||
if (ringingCall.isRinging()) {
|
||||
state = Phone.State.RINGING;
|
||||
} else if (pendingMO != null ||
|
||||
!(foregroundCall.isIdle() && backgroundCall.isIdle())) {
|
||||
state = Phone.State.OFFHOOK;
|
||||
} else {
|
||||
state = Phone.State.IDLE;
|
||||
}
|
||||
|
||||
if (state == Phone.State.IDLE && oldState != state) {
|
||||
voiceCallEndedRegistrants.notifyRegistrants(
|
||||
new AsyncResult(null, null, null));
|
||||
} else if (oldState == Phone.State.IDLE && oldState != state) {
|
||||
voiceCallStartedRegistrants.notifyRegistrants (
|
||||
new AsyncResult(null, null, null));
|
||||
}
|
||||
|
||||
if (state != oldState) {
|
||||
phone.notifyPhoneStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// ***** Overwritten from CallTracker
|
||||
|
||||
protected void
|
||||
handlePollCalls(AsyncResult ar) {
|
||||
List polledCalls;
|
||||
|
||||
if (ar.exception == null) {
|
||||
polledCalls = (List)ar.result;
|
||||
} else if (isCommandExceptionRadioNotAvailable(ar.exception)) {
|
||||
// just a dummy empty ArrayList to cause the loop
|
||||
// to hang up all the calls
|
||||
polledCalls = new ArrayList();
|
||||
} else {
|
||||
// Radio probably wasn't ready--try again in a bit
|
||||
// But don't keep polling if the channel is closed
|
||||
pollCallsAfterDelay();
|
||||
return;
|
||||
}
|
||||
|
||||
Connection newRinging = null; //or waiting
|
||||
boolean hasNonHangupStateChanged = false; // Any change besides
|
||||
// a dropped connection
|
||||
boolean needsPollDelay = false;
|
||||
boolean unknownConnectionAppeared = false;
|
||||
|
||||
for (int i = 0, curDC = 0, dcSize = polledCalls.size()
|
||||
; i < connections.length; i++) {
|
||||
CdmaConnection conn = connections[i];
|
||||
DriverCall dc = null;
|
||||
|
||||
// polledCall list is sparse
|
||||
if (curDC < dcSize) {
|
||||
dc = (DriverCall) polledCalls.get(curDC);
|
||||
|
||||
if (dc.index == i+1) {
|
||||
curDC++;
|
||||
} else {
|
||||
dc = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (DBG_POLL) log("poll: conn[i=" + i + "]=" +
|
||||
conn+", dc=" + dc);
|
||||
|
||||
if (conn == null && dc != null) {
|
||||
// Connection appeared in CLCC response that we don't know about
|
||||
if (pendingMO != null && pendingMO.compareTo(dc)) {
|
||||
|
||||
if (DBG_POLL) log("poll: pendingMO=" + pendingMO);
|
||||
|
||||
// It's our pending mobile originating call
|
||||
connections[i] = pendingMO;
|
||||
pendingMO.index = i;
|
||||
pendingMO.update(dc);
|
||||
pendingMO = null;
|
||||
|
||||
// Someone has already asked to hangup this call
|
||||
if (hangupPendingMO) {
|
||||
hangupPendingMO = false;
|
||||
try {
|
||||
if (Phone.DEBUG_PHONE) log(
|
||||
"poll: hangupPendingMO, hangup conn " + i);
|
||||
hangup(connections[i]);
|
||||
} catch (CallStateException ex) {
|
||||
Log.e(LOG_TAG, "unexpected error on hangup");
|
||||
}
|
||||
|
||||
// Do not continue processing this poll
|
||||
// Wait for hangup and repoll
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
connections[i] = new CdmaConnection(phone.getContext(), dc, this, i);
|
||||
|
||||
// it's a ringing call
|
||||
if (connections[i].getCall() == ringingCall) {
|
||||
newRinging = connections[i];
|
||||
} else {
|
||||
// Something strange happened: a call appeared
|
||||
// which is neither a ringing call or one we created.
|
||||
// Either we've crashed and re-attached to an existing
|
||||
// call, or something else (eg, SIM) initiated the call.
|
||||
|
||||
Log.i(LOG_TAG,"Phantom call appeared " + dc);
|
||||
|
||||
// If it's a connected call, set the connect time so that
|
||||
// it's non-zero. It may not be accurate, but at least
|
||||
// it won't appear as a Missed Call.
|
||||
if (dc.state != DriverCall.State.ALERTING
|
||||
&& dc.state != DriverCall.State.DIALING) {
|
||||
connections[i].connectTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
unknownConnectionAppeared = true;
|
||||
}
|
||||
}
|
||||
hasNonHangupStateChanged = true;
|
||||
} else if (conn != null && dc == null) {
|
||||
// Connection missing in CLCC response that we were
|
||||
// tracking.
|
||||
droppedDuringPoll.add(conn);
|
||||
// Dropped connections are removed from the CallTracker
|
||||
// list but kept in the Call list
|
||||
connections[i] = null;
|
||||
} else if (conn != null && dc != null && !conn.compareTo(dc)) {
|
||||
// Connection in CLCC response does not match what
|
||||
// we were tracking. Assume dropped call and new call
|
||||
|
||||
droppedDuringPoll.add(conn);
|
||||
connections[i] = new CdmaConnection (phone.getContext(), dc, this, i);
|
||||
|
||||
if (connections[i].getCall() == ringingCall) {
|
||||
newRinging = connections[i];
|
||||
} // else something strange happened
|
||||
hasNonHangupStateChanged = true;
|
||||
} else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */
|
||||
boolean changed;
|
||||
changed = conn.update(dc);
|
||||
hasNonHangupStateChanged = hasNonHangupStateChanged || changed;
|
||||
}
|
||||
|
||||
if (REPEAT_POLLING) {
|
||||
if (dc != null) {
|
||||
// FIXME with RIL, we should not need this anymore
|
||||
if ((dc.state == DriverCall.State.DIALING
|
||||
/*&& cm.getOption(cm.OPTION_POLL_DIALING)*/)
|
||||
|| (dc.state == DriverCall.State.ALERTING
|
||||
/*&& cm.getOption(cm.OPTION_POLL_ALERTING)*/)
|
||||
|| (dc.state == DriverCall.State.INCOMING
|
||||
/*&& cm.getOption(cm.OPTION_POLL_INCOMING)*/)
|
||||
|| (dc.state == DriverCall.State.WAITING
|
||||
/*&& cm.getOption(cm.OPTION_POLL_WAITING)*/)
|
||||
) {
|
||||
// Sometimes there's no unsolicited notification
|
||||
// for state transitions
|
||||
needsPollDelay = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This is the first poll after an ATD.
|
||||
// We expect the pending call to appear in the list
|
||||
// If it does not, we land here
|
||||
if (pendingMO != null) {
|
||||
Log.d(LOG_TAG,"Pending MO dropped before poll fg state:"
|
||||
+ foregroundCall.getState());
|
||||
|
||||
droppedDuringPoll.add(pendingMO);
|
||||
pendingMO = null;
|
||||
hangupPendingMO = false;
|
||||
}
|
||||
|
||||
if (newRinging != null) {
|
||||
phone.notifyNewRingingConnection(newRinging);
|
||||
}
|
||||
|
||||
// clear the "local hangup" and "missed/rejected call"
|
||||
// cases from the "dropped during poll" list
|
||||
// These cases need no "last call fail" reason
|
||||
for (int i = droppedDuringPoll.size() - 1; i >= 0 ; i--) {
|
||||
CdmaConnection conn = droppedDuringPoll.get(i);
|
||||
|
||||
if (conn.isIncoming() && conn.getConnectTime() == 0) {
|
||||
// Missed or rejected call
|
||||
Connection.DisconnectCause cause;
|
||||
if (conn.cause == Connection.DisconnectCause.LOCAL) {
|
||||
cause = Connection.DisconnectCause.INCOMING_REJECTED;
|
||||
} else {
|
||||
cause = Connection.DisconnectCause.INCOMING_MISSED;
|
||||
}
|
||||
|
||||
if (Phone.DEBUG_PHONE) {
|
||||
log("missed/rejected call, conn.cause=" + conn.cause);
|
||||
log("setting cause to " + cause);
|
||||
}
|
||||
droppedDuringPoll.remove(i);
|
||||
conn.onDisconnect(cause);
|
||||
} else if (conn.cause == Connection.DisconnectCause.LOCAL) {
|
||||
// Local hangup
|
||||
droppedDuringPoll.remove(i);
|
||||
conn.onDisconnect(Connection.DisconnectCause.LOCAL);
|
||||
} else if (conn.cause == Connection.DisconnectCause.INVALID_NUMBER) {
|
||||
droppedDuringPoll.remove(i);
|
||||
conn.onDisconnect(Connection.DisconnectCause.INVALID_NUMBER);
|
||||
}
|
||||
}
|
||||
|
||||
// Any non-local disconnects: determine cause
|
||||
if (droppedDuringPoll.size() > 0) {
|
||||
cm.getLastCallFailCause(
|
||||
obtainNoPollCompleteMessage(EVENT_GET_LAST_CALL_FAIL_CAUSE));
|
||||
}
|
||||
|
||||
if (needsPollDelay) {
|
||||
pollCallsAfterDelay();
|
||||
}
|
||||
|
||||
// Cases when we can no longer keep disconnected Connection's
|
||||
// with their previous calls
|
||||
// 1) the phone has started to ring
|
||||
// 2) A Call/Connection object has changed state...
|
||||
// we may have switched or held or answered (but not hung up)
|
||||
if (newRinging != null || hasNonHangupStateChanged) {
|
||||
internalClearDisconnected();
|
||||
}
|
||||
|
||||
updatePhoneState();
|
||||
|
||||
if (unknownConnectionAppeared) {
|
||||
phone.notifyUnknownConnection();
|
||||
}
|
||||
|
||||
if (hasNonHangupStateChanged || newRinging != null) {
|
||||
phone.notifyCallStateChanged();
|
||||
}
|
||||
|
||||
//dumpState();
|
||||
}
|
||||
|
||||
//***** Called from CdmaConnection
|
||||
/*package*/ void
|
||||
hangup (CdmaConnection conn) throws CallStateException {
|
||||
if (conn.owner != this) {
|
||||
throw new CallStateException ("CdmaConnection " + conn
|
||||
+ "does not belong to CdmaCallTracker " + this);
|
||||
}
|
||||
|
||||
if (conn == pendingMO) {
|
||||
// We're hanging up an outgoing call that doesn't have it's
|
||||
// GSM index assigned yet
|
||||
|
||||
if (Phone.DEBUG_PHONE) log("hangup: set hangupPendingMO to true");
|
||||
hangupPendingMO = true;
|
||||
} else {
|
||||
try {
|
||||
cm.hangupConnection (conn.getCDMAIndex(), obtainCompleteMessage());
|
||||
} catch (CallStateException ex) {
|
||||
// Ignore "connection not found"
|
||||
// Call may have hung up already
|
||||
Log.w(LOG_TAG,"CdmaCallTracker WARN: hangup() on absent connection "
|
||||
+ conn);
|
||||
}
|
||||
}
|
||||
|
||||
conn.onHangupLocal();
|
||||
}
|
||||
|
||||
/*package*/ void
|
||||
separate (CdmaConnection conn) throws CallStateException {
|
||||
if (conn.owner != this) {
|
||||
throw new CallStateException ("CdmaConnection " + conn
|
||||
+ "does not belong to CdmaCallTracker " + this);
|
||||
}
|
||||
try {
|
||||
cm.separateConnection (conn.getCDMAIndex(),
|
||||
obtainCompleteMessage(EVENT_SEPARATE_RESULT));
|
||||
} catch (CallStateException ex) {
|
||||
// Ignore "connection not found"
|
||||
// Call may have hung up already
|
||||
Log.w(LOG_TAG,"CdmaCallTracker WARN: separate() on absent connection "
|
||||
+ conn);
|
||||
}
|
||||
}
|
||||
|
||||
//***** Called from CDMAPhone
|
||||
|
||||
/*package*/ void
|
||||
setMute(boolean mute) {
|
||||
desiredMute = mute;
|
||||
cm.setMute(desiredMute, null);
|
||||
}
|
||||
|
||||
/*package*/ boolean
|
||||
getMute() {
|
||||
return desiredMute;
|
||||
}
|
||||
|
||||
|
||||
//***** Called from CdmaCall
|
||||
|
||||
/* package */ void
|
||||
hangup (CdmaCall call) throws CallStateException {
|
||||
if (call.getConnections().size() == 0) {
|
||||
throw new CallStateException("no connections in call");
|
||||
}
|
||||
|
||||
if (call == ringingCall) {
|
||||
if (Phone.DEBUG_PHONE) log("(ringing) hangup waiting or background");
|
||||
cm.hangupWaitingOrBackground(obtainCompleteMessage());
|
||||
} else if (call == foregroundCall) {
|
||||
if (call.isDialingOrAlerting()) {
|
||||
if (Phone.DEBUG_PHONE) {
|
||||
log("(foregnd) hangup dialing or alerting...");
|
||||
}
|
||||
hangup((CdmaConnection)(call.getConnections().get(0)));
|
||||
} else {
|
||||
hangupForegroundResumeBackground();
|
||||
}
|
||||
} else if (call == backgroundCall) {
|
||||
if (ringingCall.isRinging()) {
|
||||
if (Phone.DEBUG_PHONE) {
|
||||
log("hangup all conns in background call");
|
||||
}
|
||||
hangupAllConnections(call);
|
||||
} else {
|
||||
hangupWaitingOrBackground();
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException ("CdmaCall " + call +
|
||||
"does not belong to CdmaCallTracker " + this);
|
||||
}
|
||||
|
||||
call.onHangupLocal();
|
||||
}
|
||||
|
||||
/* package */
|
||||
void hangupWaitingOrBackground() {
|
||||
if (Phone.DEBUG_PHONE) log("hangupWaitingOrBackground");
|
||||
cm.hangupWaitingOrBackground(obtainCompleteMessage());
|
||||
}
|
||||
|
||||
/* package */
|
||||
void hangupForegroundResumeBackground() {
|
||||
if (Phone.DEBUG_PHONE) log("hangupForegroundResumeBackground");
|
||||
cm.hangupForegroundResumeBackground(obtainCompleteMessage());
|
||||
}
|
||||
|
||||
void hangupConnectionByIndex(CdmaCall call, int index)
|
||||
throws CallStateException {
|
||||
int count = call.connections.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
CdmaConnection cn = (CdmaConnection)call.connections.get(i);
|
||||
if (cn.getCDMAIndex() == index) {
|
||||
cm.hangupConnection(index, obtainCompleteMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new CallStateException("no gsm index found");
|
||||
}
|
||||
|
||||
void hangupAllConnections(CdmaCall call) throws CallStateException{
|
||||
try {
|
||||
int count = call.connections.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
CdmaConnection cn = (CdmaConnection)call.connections.get(i);
|
||||
cm.hangupConnection(cn.getCDMAIndex(), obtainCompleteMessage());
|
||||
}
|
||||
} catch (CallStateException ex) {
|
||||
Log.e(LOG_TAG, "hangupConnectionByIndex caught " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
/* package */
|
||||
CdmaConnection getConnectionByIndex(CdmaCall call, int index)
|
||||
throws CallStateException {
|
||||
int count = call.connections.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
CdmaConnection cn = (CdmaConnection)call.connections.get(i);
|
||||
if (cn.getCDMAIndex() == index) {
|
||||
return cn;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Phone.SuppService getFailedService(int what) {
|
||||
switch (what) {
|
||||
case EVENT_SWITCH_RESULT:
|
||||
return Phone.SuppService.SWITCH;
|
||||
case EVENT_CONFERENCE_RESULT:
|
||||
return Phone.SuppService.CONFERENCE;
|
||||
case EVENT_SEPARATE_RESULT:
|
||||
return Phone.SuppService.SEPARATE;
|
||||
case EVENT_ECT_RESULT:
|
||||
return Phone.SuppService.TRANSFER;
|
||||
}
|
||||
return Phone.SuppService.UNKNOWN;
|
||||
}
|
||||
|
||||
private void handleRadioNotAvailable() {
|
||||
// handlePollCalls will clear out its
|
||||
// call list when it gets the CommandException
|
||||
// error result from this
|
||||
pollCallsWhenSafe();
|
||||
}
|
||||
|
||||
//****** Overridden from Handler
|
||||
|
||||
public void
|
||||
handleMessage (Message msg) {
|
||||
AsyncResult ar;
|
||||
|
||||
switch (msg.what) {
|
||||
case EVENT_POLL_CALLS_RESULT:{
|
||||
Log.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");
|
||||
ar = (AsyncResult)msg.obj;
|
||||
|
||||
if(msg == lastRelevantPoll) {
|
||||
if(DBG_POLL) log(
|
||||
"handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
|
||||
needsPoll = false;
|
||||
lastRelevantPoll = null;
|
||||
handlePollCalls((AsyncResult)msg.obj);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_OPERATION_COMPLETE:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
operationComplete();
|
||||
break;
|
||||
|
||||
case EVENT_SWITCH_RESULT:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
operationComplete();
|
||||
break;
|
||||
|
||||
case EVENT_GET_LAST_CALL_FAIL_CAUSE:
|
||||
int causeCode;
|
||||
ar = (AsyncResult)msg.obj;
|
||||
|
||||
operationComplete();
|
||||
|
||||
if (ar.exception != null) {
|
||||
// An exception occurred...just treat the disconnect
|
||||
// cause as "normal"
|
||||
causeCode = CallFailCause.NORMAL_CLEARING;
|
||||
Log.i(LOG_TAG,
|
||||
"Exception during getLastCallFailCause, assuming normal disconnect");
|
||||
} else {
|
||||
causeCode = ((int[])ar.result)[0];
|
||||
}
|
||||
|
||||
for (int i = 0, s = droppedDuringPoll.size()
|
||||
; i < s ; i++
|
||||
) {
|
||||
CdmaConnection conn = droppedDuringPoll.get(i);
|
||||
|
||||
conn.onRemoteDisconnect(causeCode);
|
||||
}
|
||||
|
||||
updatePhoneState();
|
||||
|
||||
phone.notifyCallStateChanged();
|
||||
droppedDuringPoll.clear();
|
||||
break;
|
||||
|
||||
case EVENT_CALL_STATE_CHANGE:
|
||||
pollCallsWhenSafe();
|
||||
break;
|
||||
|
||||
case EVENT_RADIO_AVAILABLE:
|
||||
handleRadioAvailable();
|
||||
break;
|
||||
|
||||
case EVENT_RADIO_NOT_AVAILABLE:
|
||||
handleRadioNotAvailable();
|
||||
break;
|
||||
|
||||
default:{
|
||||
throw new RuntimeException("unexpected event not handled");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void log(String msg) {
|
||||
Log.d(LOG_TAG, "[CdmaCallTracker] " + msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,705 @@
|
||||
/*
|
||||
* 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 com.android.internal.telephony.*;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Registrant;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.telephony.ServiceState;
|
||||
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public class CdmaConnection extends Connection {
|
||||
static final String LOG_TAG = "CDMA";
|
||||
|
||||
//***** Instance Variables
|
||||
|
||||
CdmaCallTracker owner;
|
||||
CdmaCall parent;
|
||||
|
||||
|
||||
String address; // MAY BE NULL!!!
|
||||
String dialString; // outgoing calls only
|
||||
String postDialString; // outgoing calls only
|
||||
boolean isIncoming;
|
||||
boolean disconnected;
|
||||
|
||||
int index; // index in CdmaCallTracker.connections[], -1 if unassigned
|
||||
|
||||
/*
|
||||
* These time/timespan values are based on System.currentTimeMillis(),
|
||||
* i.e., "wall clock" time.
|
||||
*/
|
||||
long createTime;
|
||||
long connectTime;
|
||||
long disconnectTime;
|
||||
|
||||
/*
|
||||
* These time/timespan values are based on SystemClock.elapsedRealTime(),
|
||||
* i.e., time since boot. They are appropriate for comparison and
|
||||
* calculating deltas.
|
||||
*/
|
||||
long connectTimeReal;
|
||||
long duration;
|
||||
long holdingStartTime; // The time when the Connection last transitioned
|
||||
// into HOLDING
|
||||
|
||||
int nextPostDialChar; // index into postDialString
|
||||
|
||||
DisconnectCause cause = DisconnectCause.NOT_DISCONNECTED;
|
||||
PostDialState postDialState = PostDialState.NOT_STARTED;
|
||||
int numberPresentation = Connection.PRESENTATION_ALLOWED;
|
||||
|
||||
Handler h;
|
||||
|
||||
private PowerManager.WakeLock mPartialWakeLock;
|
||||
|
||||
//***** Event Constants
|
||||
static final int EVENT_DTMF_DONE = 1;
|
||||
static final int EVENT_PAUSE_DONE = 2;
|
||||
static final int EVENT_NEXT_POST_DIAL = 3;
|
||||
static final int EVENT_WAKE_LOCK_TIMEOUT = 4;
|
||||
|
||||
//***** Constants
|
||||
static final int PAUSE_DELAY_FIRST_MILLIS = 100;
|
||||
static final int PAUSE_DELAY_MILLIS = 3 * 1000;
|
||||
static final int WAKE_LOCK_TIMEOUT_MILLIS = 60*1000;
|
||||
|
||||
//***** Inner Classes
|
||||
|
||||
class MyHandler extends Handler {
|
||||
MyHandler(Looper l) {super(l);}
|
||||
|
||||
public void
|
||||
handleMessage(Message msg) {
|
||||
|
||||
switch (msg.what) {
|
||||
case EVENT_NEXT_POST_DIAL:
|
||||
case EVENT_DTMF_DONE:
|
||||
case EVENT_PAUSE_DONE:
|
||||
processNextPostDialChar();
|
||||
break;
|
||||
case EVENT_WAKE_LOCK_TIMEOUT:
|
||||
releaseWakeLock();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//***** Constructors
|
||||
|
||||
/** This is probably an MT call that we first saw in a CLCC response */
|
||||
/*package*/
|
||||
CdmaConnection (Context context, DriverCall dc, CdmaCallTracker ct, int index) {
|
||||
createWakeLock(context);
|
||||
acquireWakeLock();
|
||||
|
||||
owner = ct;
|
||||
h = new MyHandler(owner.getLooper());
|
||||
|
||||
address = dc.number;
|
||||
|
||||
isIncoming = dc.isMT;
|
||||
createTime = System.currentTimeMillis();
|
||||
numberPresentation = dc.numberPresentation;
|
||||
|
||||
this.index = index;
|
||||
|
||||
parent = parentFromDCState (dc.state);
|
||||
parent.attach(this, dc);
|
||||
}
|
||||
|
||||
/** This is an MO call, created when dialing */
|
||||
/*package*/
|
||||
CdmaConnection (Context context, String dialString, CdmaCallTracker ct, CdmaCall parent) {
|
||||
createWakeLock(context);
|
||||
acquireWakeLock();
|
||||
|
||||
owner = ct;
|
||||
h = new MyHandler(owner.getLooper());
|
||||
|
||||
this.dialString = dialString;
|
||||
|
||||
this.address = PhoneNumberUtils.extractNetworkPortion(dialString);
|
||||
this.postDialString = PhoneNumberUtils.extractPostDialPortion(dialString);
|
||||
|
||||
index = -1;
|
||||
|
||||
isIncoming = false;
|
||||
createTime = System.currentTimeMillis();
|
||||
|
||||
this.parent = parent;
|
||||
parent.attachFake(this, CdmaCall.State.DIALING);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
static boolean
|
||||
equalsHandlesNulls (Object a, Object b) {
|
||||
return (a == null) ? (b == null) : a.equals (b);
|
||||
}
|
||||
|
||||
/*package*/ boolean
|
||||
compareTo(DriverCall c) {
|
||||
// On mobile originated (MO) calls, the phone number may have changed
|
||||
// due to a SIM Toolkit call control modification.
|
||||
//
|
||||
// We assume we know when MO calls are created (since we created them)
|
||||
// and therefore don't need to compare the phone number anyway.
|
||||
if (! (isIncoming || c.isMT)) return true;
|
||||
|
||||
// ... but we can compare phone numbers on MT calls, and we have
|
||||
// no control over when they begin, so we might as well
|
||||
|
||||
String cAddress = PhoneNumberUtils.stringFromStringAndTOA(c.number, c.TOA);
|
||||
return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress);
|
||||
}
|
||||
|
||||
public String
|
||||
toString() {
|
||||
return (isIncoming ? "incoming" : "outgoing");
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public CdmaCall getCall() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public long getConnectTime() {
|
||||
return connectTime;
|
||||
}
|
||||
|
||||
public long getDisconnectTime() {
|
||||
return disconnectTime;
|
||||
}
|
||||
|
||||
public long getDurationMillis() {
|
||||
if (connectTimeReal == 0) {
|
||||
return 0;
|
||||
} else if (duration == 0) {
|
||||
return SystemClock.elapsedRealtime() - connectTimeReal;
|
||||
} else {
|
||||
return duration;
|
||||
}
|
||||
}
|
||||
|
||||
public long getHoldDurationMillis() {
|
||||
if (getState() != CdmaCall.State.HOLDING) {
|
||||
// If not holding, return 0
|
||||
return 0;
|
||||
} else {
|
||||
return SystemClock.elapsedRealtime() - holdingStartTime;
|
||||
}
|
||||
}
|
||||
|
||||
public DisconnectCause getDisconnectCause() {
|
||||
return cause;
|
||||
}
|
||||
|
||||
public boolean isIncoming() {
|
||||
return isIncoming;
|
||||
}
|
||||
|
||||
public CdmaCall.State getState() {
|
||||
if (disconnected) {
|
||||
return CdmaCall.State.DISCONNECTED;
|
||||
} else {
|
||||
return super.getState();
|
||||
}
|
||||
}
|
||||
|
||||
public void hangup() throws CallStateException {
|
||||
if (!disconnected) {
|
||||
owner.hangup(this);
|
||||
} else {
|
||||
throw new CallStateException ("disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
public void separate() throws CallStateException {
|
||||
if (!disconnected) {
|
||||
owner.separate(this);
|
||||
} else {
|
||||
throw new CallStateException ("disconnected");
|
||||
}
|
||||
}
|
||||
|
||||
public PostDialState getPostDialState() {
|
||||
return postDialState;
|
||||
}
|
||||
|
||||
public void proceedAfterWaitChar() {
|
||||
if (postDialState != PostDialState.WAIT) {
|
||||
Log.w(LOG_TAG, "CdmaConnection.proceedAfterWaitChar(): Expected "
|
||||
+ "getPostDialState() to be WAIT but was " + postDialState);
|
||||
return;
|
||||
}
|
||||
|
||||
setPostDialState(PostDialState.STARTED);
|
||||
|
||||
processNextPostDialChar();
|
||||
}
|
||||
|
||||
public void proceedAfterWildChar(String str) {
|
||||
if (postDialState != PostDialState.WILD) {
|
||||
Log.w(LOG_TAG, "CdmaConnection.proceedAfterWaitChar(): Expected "
|
||||
+ "getPostDialState() to be WILD but was " + postDialState);
|
||||
return;
|
||||
}
|
||||
|
||||
setPostDialState(PostDialState.STARTED);
|
||||
|
||||
if (false) {
|
||||
boolean playedTone = false;
|
||||
int len = (str != null ? str.length() : 0);
|
||||
|
||||
for (int i=0; i<len; i++) {
|
||||
char c = str.charAt(i);
|
||||
Message msg = null;
|
||||
|
||||
if (i == len-1) {
|
||||
msg = h.obtainMessage(EVENT_DTMF_DONE);
|
||||
}
|
||||
|
||||
if (PhoneNumberUtils.is12Key(c)) {
|
||||
owner.cm.sendDtmf(c, msg);
|
||||
playedTone = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!playedTone) {
|
||||
processNextPostDialChar();
|
||||
}
|
||||
} else {
|
||||
// make a new postDialString, with the wild char replacement string
|
||||
// at the beginning, followed by the remaining postDialString.
|
||||
|
||||
StringBuilder buf = new StringBuilder(str);
|
||||
buf.append(postDialString.substring(nextPostDialChar));
|
||||
postDialString = buf.toString();
|
||||
nextPostDialChar = 0;
|
||||
if (Phone.DEBUG_PHONE) {
|
||||
log("proceedAfterWildChar: new postDialString is " +
|
||||
postDialString);
|
||||
}
|
||||
|
||||
processNextPostDialChar();
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelPostDial() {
|
||||
setPostDialState(PostDialState.CANCELLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this Connection is being hung up locally (eg, user pressed "end")
|
||||
* Note that at this point, the hangup request has been dispatched to the radio
|
||||
* but no response has yet been received so update() has not yet been called
|
||||
*/
|
||||
void
|
||||
onHangupLocal() {
|
||||
cause = DisconnectCause.LOCAL;
|
||||
}
|
||||
|
||||
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.ERROR_UNSPECIFIED:
|
||||
case CallFailCause.NORMAL_CLEARING:
|
||||
default:
|
||||
CDMAPhone phone = owner.phone;
|
||||
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 (phone.mCM.getRadioState() != CommandsInterface.RadioState.NV_READY
|
||||
&& phone.getIccCard().getState() != RuimCard.State.READY) {
|
||||
return DisconnectCause.ICC_ERROR;
|
||||
} else {
|
||||
return DisconnectCause.NORMAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*package*/ void
|
||||
onRemoteDisconnect(int causeCode) {
|
||||
onDisconnect(disconnectCauseFromCode(causeCode));
|
||||
}
|
||||
|
||||
/** Called when the radio indicates the connection has been disconnected */
|
||||
/*package*/ void
|
||||
onDisconnect(DisconnectCause cause) {
|
||||
this.cause = cause;
|
||||
|
||||
if (!disconnected) {
|
||||
index = -1;
|
||||
|
||||
disconnectTime = System.currentTimeMillis();
|
||||
duration = SystemClock.elapsedRealtime() - connectTimeReal;
|
||||
disconnected = true;
|
||||
|
||||
if (Config.LOGD) Log.d(LOG_TAG,
|
||||
"[CDMAConn] onDisconnect: cause=" + cause);
|
||||
|
||||
owner.phone.notifyDisconnect(this);
|
||||
|
||||
if (parent != null) {
|
||||
parent.connectionDisconnected(this);
|
||||
}
|
||||
}
|
||||
releaseWakeLock();
|
||||
}
|
||||
|
||||
// Returns true if state has changed, false if nothing changed
|
||||
/*package*/ boolean
|
||||
update (DriverCall dc) {
|
||||
CdmaCall newParent;
|
||||
boolean changed = false;
|
||||
boolean wasConnectingInOrOut = isConnectingInOrOut();
|
||||
boolean wasHolding = (getState() == CdmaCall.State.HOLDING);
|
||||
|
||||
newParent = parentFromDCState(dc.state);
|
||||
|
||||
if (!equalsHandlesNulls(address, dc.number)) {
|
||||
if (Phone.DEBUG_PHONE) log("update: phone # changed!");
|
||||
address = dc.number;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (newParent != parent) {
|
||||
if (parent != null) {
|
||||
parent.detach(this);
|
||||
}
|
||||
newParent.attach(this, dc);
|
||||
parent = newParent;
|
||||
changed = true;
|
||||
} else {
|
||||
boolean parentStateChange;
|
||||
parentStateChange = parent.update (this, dc);
|
||||
changed = changed || parentStateChange;
|
||||
}
|
||||
|
||||
/** Some state-transition events */
|
||||
|
||||
if (Phone.DEBUG_PHONE) log(
|
||||
"update: parent=" + parent +
|
||||
", hasNewParent=" + (newParent != parent) +
|
||||
", wasConnectingInOrOut=" + wasConnectingInOrOut +
|
||||
", wasHolding=" + wasHolding +
|
||||
", isConnectingInOrOut=" + isConnectingInOrOut() +
|
||||
", changed=" + changed);
|
||||
|
||||
|
||||
if (wasConnectingInOrOut && !isConnectingInOrOut()) {
|
||||
onConnectedInOrOut();
|
||||
}
|
||||
|
||||
if (changed && !wasHolding && (getState() == CdmaCall.State.HOLDING)) {
|
||||
// We've transitioned into HOLDING
|
||||
onStartedHolding();
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this Connection is in the foregroundCall
|
||||
* when a dial is initiated.
|
||||
* We know we're ACTIVE, and we know we're going to end up
|
||||
* HOLDING in the backgroundCall
|
||||
*/
|
||||
void
|
||||
fakeHoldBeforeDial() {
|
||||
if (parent != null) {
|
||||
parent.detach(this);
|
||||
}
|
||||
|
||||
parent = owner.backgroundCall;
|
||||
parent.attachFake(this, CdmaCall.State.HOLDING);
|
||||
|
||||
onStartedHolding();
|
||||
}
|
||||
|
||||
/*package*/ int
|
||||
getCDMAIndex() throws CallStateException {
|
||||
if (index >= 0) {
|
||||
return index + 1;
|
||||
} else {
|
||||
throw new CallStateException ("CDMA connection index not assigned");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An incoming or outgoing call has connected
|
||||
*/
|
||||
void
|
||||
onConnectedInOrOut() {
|
||||
connectTime = System.currentTimeMillis();
|
||||
connectTimeReal = SystemClock.elapsedRealtime();
|
||||
duration = 0;
|
||||
|
||||
// bug #678474: incoming call interpreted as missed call, even though
|
||||
// it sounds like the user has picked up the call.
|
||||
if (Phone.DEBUG_PHONE) {
|
||||
log("onConnectedInOrOut: connectTime=" + connectTime);
|
||||
}
|
||||
|
||||
if (!isIncoming) {
|
||||
// outgoing calls only
|
||||
processNextPostDialChar();
|
||||
}
|
||||
releaseWakeLock();
|
||||
}
|
||||
|
||||
private void
|
||||
onStartedHolding() {
|
||||
holdingStartTime = SystemClock.elapsedRealtime();
|
||||
}
|
||||
/**
|
||||
* Performs the appropriate action for a post-dial char, but does not
|
||||
* notify application. returns false if the character is invalid and
|
||||
* should be ignored
|
||||
*/
|
||||
private boolean
|
||||
processPostDialChar(char c) {
|
||||
if (PhoneNumberUtils.is12Key(c)) {
|
||||
owner.cm.sendDtmf(c, h.obtainMessage(EVENT_DTMF_DONE));
|
||||
} else if (c == PhoneNumberUtils.PAUSE) {
|
||||
// From TS 22.101:
|
||||
|
||||
// "The first occurrence of the "DTMF Control Digits Separator"
|
||||
// shall be used by the ME to distinguish between the addressing
|
||||
// digits (i.e. the phone number) and the DTMF digits...."
|
||||
|
||||
if (nextPostDialChar == 1) {
|
||||
// The first occurrence.
|
||||
// We don't need to pause here, but wait for just a bit anyway
|
||||
h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE),
|
||||
PAUSE_DELAY_FIRST_MILLIS);
|
||||
} else {
|
||||
// It continues...
|
||||
// "Upon subsequent occurrences of the separator, the UE shall
|
||||
// pause again for 3 seconds (\u00B1 20 %) before sending any
|
||||
// further DTMF digits."
|
||||
h.sendMessageDelayed(h.obtainMessage(EVENT_PAUSE_DONE),
|
||||
PAUSE_DELAY_MILLIS);
|
||||
}
|
||||
} else if (c == PhoneNumberUtils.WAIT) {
|
||||
setPostDialState(PostDialState.WAIT);
|
||||
} else if (c == PhoneNumberUtils.WILD) {
|
||||
setPostDialState(PostDialState.WILD);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public String
|
||||
getRemainingPostDialString() {
|
||||
if (postDialState == PostDialState.CANCELLED
|
||||
|| postDialState == PostDialState.COMPLETE
|
||||
|| postDialString == null
|
||||
|| postDialString.length() <= nextPostDialChar
|
||||
) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return postDialString.substring(nextPostDialChar);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize()
|
||||
{
|
||||
/**
|
||||
* It is understood that This finializer is not guaranteed
|
||||
* to be called and the release lock call is here just in
|
||||
* case there is some path that doesn't call onDisconnect
|
||||
* and or onConnectedInOrOut.
|
||||
*/
|
||||
if (mPartialWakeLock.isHeld()) {
|
||||
Log.e(LOG_TAG, "[CdmaConn] UNEXPECTED; mPartialWakeLock is held when finalizing.");
|
||||
}
|
||||
releaseWakeLock();
|
||||
}
|
||||
|
||||
private void
|
||||
processNextPostDialChar() {
|
||||
char c = 0;
|
||||
Registrant postDialHandler;
|
||||
|
||||
if (postDialState == PostDialState.CANCELLED) {
|
||||
//Log.v("CDMA", "##### processNextPostDialChar: postDialState == CANCELLED, bail");
|
||||
return;
|
||||
}
|
||||
|
||||
if (postDialString == null ||
|
||||
postDialString.length() <= nextPostDialChar) {
|
||||
setPostDialState(PostDialState.COMPLETE);
|
||||
|
||||
// notifyMessage.arg1 is 0 on complete
|
||||
c = 0;
|
||||
} else {
|
||||
boolean isValid;
|
||||
|
||||
setPostDialState(PostDialState.STARTED);
|
||||
|
||||
c = postDialString.charAt(nextPostDialChar++);
|
||||
|
||||
isValid = processPostDialChar(c);
|
||||
|
||||
if (!isValid) {
|
||||
// Will call processNextPostDialChar
|
||||
h.obtainMessage(EVENT_NEXT_POST_DIAL).sendToTarget();
|
||||
// Don't notify application
|
||||
Log.e("CDMA", "processNextPostDialChar: c=" + c + " isn't valid!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
postDialHandler = owner.phone.mPostDialHandler;
|
||||
|
||||
Message notifyMessage;
|
||||
|
||||
if (postDialHandler != null &&
|
||||
(notifyMessage = postDialHandler.messageForRegistrant()) != null) {
|
||||
// The AsyncResult.result is the Connection object
|
||||
PostDialState state = postDialState;
|
||||
AsyncResult ar = AsyncResult.forMessage(notifyMessage);
|
||||
ar.result = this;
|
||||
ar.userObj = state;
|
||||
|
||||
// arg1 is the character that was/is being processed
|
||||
notifyMessage.arg1 = c;
|
||||
|
||||
notifyMessage.sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** "connecting" means "has never been ACTIVE" for both incoming
|
||||
* and outgoing calls
|
||||
*/
|
||||
private boolean
|
||||
isConnectingInOrOut() {
|
||||
return parent == null || parent == owner.ringingCall
|
||||
|| parent.state == CdmaCall.State.DIALING
|
||||
|| parent.state == CdmaCall.State.ALERTING;
|
||||
}
|
||||
|
||||
private CdmaCall
|
||||
parentFromDCState (DriverCall.State state) {
|
||||
switch (state) {
|
||||
case ACTIVE:
|
||||
case DIALING:
|
||||
case ALERTING:
|
||||
return owner.foregroundCall;
|
||||
//break;
|
||||
|
||||
case HOLDING:
|
||||
return owner.backgroundCall;
|
||||
//break;
|
||||
|
||||
case INCOMING:
|
||||
case WAITING:
|
||||
return owner.ringingCall;
|
||||
//break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("illegal call state: " + state);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set post dial state and acquire wake lock while switching to "started"
|
||||
* state, the wake lock will be released if state switches out of "started"
|
||||
* state or after WAKE_LOCK_TIMEOUT_MILLIS.
|
||||
* @param s new PostDialState
|
||||
*/
|
||||
private void setPostDialState(PostDialState s) {
|
||||
if (postDialState != PostDialState.STARTED
|
||||
&& s == PostDialState.STARTED) {
|
||||
acquireWakeLock();
|
||||
Message msg = h.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);
|
||||
h.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT_MILLIS);
|
||||
} else if (postDialState == PostDialState.STARTED
|
||||
&& s != PostDialState.STARTED) {
|
||||
h.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
|
||||
releaseWakeLock();
|
||||
}
|
||||
postDialState = s;
|
||||
}
|
||||
|
||||
private void
|
||||
createWakeLock(Context context) {
|
||||
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
|
||||
}
|
||||
|
||||
private void
|
||||
acquireWakeLock() {
|
||||
log("acquireWakeLock");
|
||||
mPartialWakeLock.acquire();
|
||||
}
|
||||
|
||||
private void
|
||||
releaseWakeLock() {
|
||||
synchronized(mPartialWakeLock) {
|
||||
if (mPartialWakeLock.isHeld()) {
|
||||
log("releaseWakeLock");
|
||||
mPartialWakeLock.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void log(String msg) {
|
||||
Log.d(LOG_TAG, "[CDMAConn] " + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberPresentation() {
|
||||
return numberPresentation;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.os.*;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.CommandException;
|
||||
import com.android.internal.telephony.DataConnection;
|
||||
import com.android.internal.telephony.DataLink;
|
||||
import com.android.internal.telephony.RILConstants;
|
||||
import com.android.internal.telephony.TelephonyEventLog;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*
|
||||
*/
|
||||
public class CdmaDataConnection extends DataConnection {
|
||||
|
||||
private static final String LOG_TAG = "CDMA";
|
||||
private static final boolean DBG = true;
|
||||
|
||||
/** Fail cause of last Data Call activate from RIL_LastDataCallActivateFailCause */
|
||||
private final static int PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING = 8;
|
||||
private final static int PS_NET_DOWN_REASON_UNKNOWN_APN = 27;
|
||||
private final static int PS_NET_DOWN_REASON_AUTH_FAILED = 29;
|
||||
private final static int PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED = 32;
|
||||
private final static int PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED = 33;
|
||||
|
||||
/** It is likely that the number of error codes listed below will be removed
|
||||
* in the foreseeable future. They have been added, but not agreed upon.
|
||||
*
|
||||
*/
|
||||
private final static int PS_NET_DOWN_REASON_NOT_SPECIFIED = 0;
|
||||
private final static int PS_NET_DOWN_REASON_CLOSE_IN_PROGRESS = 1;
|
||||
private final static int PS_NET_DOWN_REASON_NW_INITIATED_TERMINATION = 2;
|
||||
private final static int PS_NET_DOWN_REASON_APP_PREEMPTED = 3;
|
||||
private final static int PS_NET_DOWN_REASON_LLC_SNDCP_FAILURE = 25;
|
||||
private final static int PS_NET_DOWN_REASON_INSUFFICIENT_RESOURCES = 26;
|
||||
private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP = 28;
|
||||
private final static int PS_NET_DOWN_REASON_GGSN_REJECT = 30;
|
||||
private final static int PS_NET_DOWN_REASON_ACTIVATION_REJECT = 31;
|
||||
private final static int PS_NET_DOWN_REASON_OPTION_TEMP_OOO = 34;
|
||||
private final static int PS_NET_DOWN_REASON_NSAPI_ALREADY_USED = 35;
|
||||
private final static int PS_NET_DOWN_REASON_REGULAR_DEACTIVATION = 36;
|
||||
private final static int PS_NET_DOWN_REASON_QOS_NOT_ACCEPTED = 37;
|
||||
private final static int PS_NET_DOWN_REASON_NETWORK_FAILURE = 38;
|
||||
private final static int PS_NET_DOWN_REASON_UMTS_REATTACH_REQ = 39;
|
||||
private final static int PS_NET_DOWN_REASON_TFT_SEMANTIC_ERROR = 41;
|
||||
private final static int PS_NET_DOWN_REASON_TFT_SYNTAX_ERROR = 42;
|
||||
private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP_CONTEXT = 43;
|
||||
private final static int PS_NET_DOWN_REASON_FILTER_SEMANTIC_ERROR = 44;
|
||||
private final static int PS_NET_DOWN_REASON_FILTER_SYNTAX_ERROR = 45;
|
||||
private final static int PS_NET_DOWN_REASON_PDP_WITHOUT_ACTIVE_TFT = 46;
|
||||
private final static int PS_NET_DOWN_REASON_INVALID_TRANSACTION_ID = 81;
|
||||
private final static int PS_NET_DOWN_REASON_MESSAGE_INCORRECT_SEMANTIC = 95;
|
||||
private final static int PS_NET_DOWN_REASON_INVALID_MANDATORY_INFO = 96;
|
||||
private final static int PS_NET_DOWN_REASON_MESSAGE_TYPE_UNSUPPORTED = 97;
|
||||
private final static int PS_NET_DOWN_REASON_MSG_TYPE_NONCOMPATIBLE_STATE = 98;
|
||||
private final static int PS_NET_DOWN_REASON_UNKNOWN_INFO_ELEMENT = 99;
|
||||
private final static int PS_NET_DOWN_REASON_CONDITIONAL_IE_ERROR = 100;
|
||||
private final static int PS_NET_DOWN_REASON_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101;
|
||||
private final static int PS_NET_DOWN_REASON_PROTOCOL_ERROR = 111;
|
||||
private final static int PS_NET_DOWN_REASON_APN_TYPE_CONFLICT = 112;
|
||||
private final static int PS_NET_DOWN_REASON_UNKNOWN_CAUSE_CODE = 113;
|
||||
private final static int PS_NET_DOWN_REASON_INTERNAL_MIN = 200;
|
||||
private final static int PS_NET_DOWN_REASON_INTERNAL_ERROR = 201;
|
||||
private final static int PS_NET_DOWN_REASON_INTERNAL_CALL_ENDED = 202;
|
||||
private final static int PS_NET_DOWN_REASON_INTERNAL_UNKNOWN_CAUSE_CODE = 203;
|
||||
private final static int PS_NET_DOWN_REASON_INTERNAL_MAX = 204;
|
||||
private final static int PS_NET_DOWN_REASON_CDMA_LOCK = 500;
|
||||
private final static int PS_NET_DOWN_REASON_INTERCEPT = 501;
|
||||
private final static int PS_NET_DOWN_REASON_REORDER = 502;
|
||||
private final static int PS_NET_DOWN_REASON_REL_SO_REJ = 503;
|
||||
private final static int PS_NET_DOWN_REASON_INCOM_CALL = 504;
|
||||
private final static int PS_NET_DOWN_REASON_ALERT_STOP = 505;
|
||||
private final static int PS_NET_DOWN_REASON_ACTIVATION = 506;
|
||||
private final static int PS_NET_DOWN_REASON_MAX_ACCESS_PROBE = 507;
|
||||
private final static int PS_NET_DOWN_REASON_CCS_NOT_SUPPORTED_BY_BS = 508;
|
||||
private final static int PS_NET_DOWN_REASON_NO_RESPONSE_FROM_BS = 509;
|
||||
private final static int PS_NET_DOWN_REASON_REJECTED_BY_BS = 510;
|
||||
private final static int PS_NET_DOWN_REASON_INCOMPATIBLE = 511;
|
||||
private final static int PS_NET_DOWN_REASON_ALREADY_IN_TC = 512;
|
||||
private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_GPS = 513;
|
||||
private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_SMS = 514;
|
||||
private final static int PS_NET_DOWN_REASON_NO_CDMA_SRV = 515;
|
||||
private final static int PS_NET_DOWN_REASON_CONF_FAILED = 1000;
|
||||
private final static int PS_NET_DOWN_REASON_INCOM_REJ = 1001;
|
||||
private final static int PS_NET_DOWN_REASON_NO_GW_SRV = 1002;
|
||||
private final static int PS_NET_DOWN_REASON_CD_GEN_OR_BUSY = 1500;
|
||||
private final static int PS_NET_DOWN_REASON_CD_BILL_OR_AUTH = 1501;
|
||||
private final static int PS_NET_DOWN_REASON_CHG_HDR = 1502;
|
||||
private final static int PS_NET_DOWN_REASON_EXIT_HDR = 1503;
|
||||
private final static int PS_NET_DOWN_REASON_HDR_NO_SESSION = 1504;
|
||||
private final static int PS_NET_DOWN_REASON_HDR_ORIG_DURING_GPS_FIX = 1505;
|
||||
private final static int PS_NET_DOWN_REASON_HDR_CS_TIMEOUT = 1506;
|
||||
private final static int PS_NET_DOWN_REASON_HDR_RELEASED_BY_CM = 1507;
|
||||
private final static int PS_NET_DOWN_REASON_CLIENT_END = 2000;
|
||||
private final static int PS_NET_DOWN_REASON_NO_SRV = 2001;
|
||||
private final static int PS_NET_DOWN_REASON_FADE = 2002;
|
||||
private final static int PS_NET_DOWN_REASON_REL_NORMAL = 2003;
|
||||
private final static int PS_NET_DOWN_REASON_ACC_IN_PROG = 2004;
|
||||
private final static int PS_NET_DOWN_REASON_ACC_FAIL = 2005;
|
||||
private final static int PS_NET_DOWN_REASON_REDIR_OR_HANDOFF = 2006;
|
||||
|
||||
// ***** Instance Variables
|
||||
|
||||
// ***** Constructor
|
||||
CdmaDataConnection(CDMAPhone phone) {
|
||||
super(phone);
|
||||
|
||||
if (DBG) log("CdmaDataConnection <constructor>");
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a data connection
|
||||
*
|
||||
* @param onCompleted
|
||||
* notify success or not after down
|
||||
*/
|
||||
void connect(Message onCompleted) {
|
||||
if (DBG) log("CdmaDataConnection Connecting...");
|
||||
|
||||
state = State.ACTIVATING;
|
||||
onConnectCompleted = onCompleted;
|
||||
createTime = -1;
|
||||
lastFailTime = -1;
|
||||
lastFailCause = FailCause.NONE;
|
||||
receivedDisconnectReq = false;
|
||||
phone.mCM.setupDataCall(Integer.toString(RILConstants.CDMA_PHONE), null, null, null,
|
||||
null, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
|
||||
}
|
||||
|
||||
protected void disconnect(Message msg) {
|
||||
onDisconnect = msg;
|
||||
if (state == State.ACTIVE) {
|
||||
if (phone.mCM.getRadioState().isOn()) {
|
||||
phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg));
|
||||
}
|
||||
} else if (state == State.ACTIVATING) {
|
||||
receivedDisconnectReq = true;
|
||||
} else {
|
||||
// state == INACTIVE. Nothing to do, so notify immediately.
|
||||
notifyDisconnect(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
return "State=" + state + " create=" + createTime + " lastFail="
|
||||
+ lastFailTime + " lastFailCause=" + lastFailCause;
|
||||
}
|
||||
|
||||
|
||||
protected void notifyFail(FailCause cause, Message onCompleted) {
|
||||
if (onCompleted == null) {
|
||||
return;
|
||||
}
|
||||
state = State.INACTIVE;
|
||||
lastFailCause = cause;
|
||||
lastFailTime = System.currentTimeMillis();
|
||||
onConnectCompleted = null;
|
||||
|
||||
if(DBG) {
|
||||
log("Notify data connection fail at " + lastFailTime +
|
||||
" due to " + lastFailCause);
|
||||
}
|
||||
|
||||
AsyncResult.forMessage(onCompleted, cause, new Exception());
|
||||
onCompleted.sendToTarget();
|
||||
}
|
||||
|
||||
protected void notifySuccess(Message onCompleted) {
|
||||
if (onCompleted == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
state = State.ACTIVE;
|
||||
createTime = System.currentTimeMillis();
|
||||
onConnectCompleted = null;
|
||||
onCompleted.arg1 = cid;
|
||||
|
||||
if (DBG) log("Notify data connection success at " + createTime);
|
||||
|
||||
AsyncResult.forMessage(onCompleted);
|
||||
onCompleted.sendToTarget();
|
||||
}
|
||||
|
||||
protected void notifyDisconnect(Message msg) {
|
||||
if (DBG) log("Notify data connection disconnect");
|
||||
|
||||
if (msg != null) {
|
||||
AsyncResult.forMessage(msg);
|
||||
msg.sendToTarget();
|
||||
}
|
||||
clearSettings();
|
||||
}
|
||||
|
||||
protected void onLinkStateChanged(DataLink.LinkState linkState) {
|
||||
switch (linkState) {
|
||||
case LINK_UP:
|
||||
notifySuccess(onConnectCompleted);
|
||||
break;
|
||||
|
||||
case LINK_DOWN:
|
||||
case LINK_EXITED:
|
||||
phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected FailCause getFailCauseFromRequest(int rilCause) {
|
||||
FailCause cause;
|
||||
|
||||
switch (rilCause) {
|
||||
case PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING:
|
||||
cause = FailCause.BARRED;
|
||||
break;
|
||||
case PS_NET_DOWN_REASON_AUTH_FAILED:
|
||||
cause = FailCause.USER_AUTHENTICATION;
|
||||
break;
|
||||
case PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED:
|
||||
cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED;
|
||||
break;
|
||||
case PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED:
|
||||
cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED;
|
||||
break;
|
||||
default:
|
||||
cause = FailCause.UNKNOWN;
|
||||
}
|
||||
return cause;
|
||||
}
|
||||
|
||||
protected void log(String s) {
|
||||
Log.d(LOG_TAG, "[CdmaDataConnection] " + s);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeactivated(AsyncResult ar) {
|
||||
notifyDisconnect((Message) ar.userObj);
|
||||
if (DBG) log("CDMA Connection Deactivated");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSetupConnectionCompleted(AsyncResult ar) {
|
||||
if (ar.exception != null) {
|
||||
Log.e(LOG_TAG, "CdmaDataConnection Init failed " + ar.exception);
|
||||
|
||||
if (receivedDisconnectReq) {
|
||||
// Don't bother reporting the error if there's already a
|
||||
// pending disconnect request, since DataConnectionTracker
|
||||
// has already updated its state.
|
||||
notifyDisconnect(onDisconnect);
|
||||
} else {
|
||||
if (ar.exception instanceof CommandException
|
||||
&& ((CommandException) (ar.exception)).getCommandError()
|
||||
== CommandException.Error.RADIO_NOT_AVAILABLE) {
|
||||
notifyFail(FailCause.RADIO_NOT_AVAILABLE, onConnectCompleted);
|
||||
} else {
|
||||
phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (receivedDisconnectReq) {
|
||||
// Don't bother reporting success if there's already a
|
||||
// pending disconnect request, since DataConnectionTracker
|
||||
// has already updated its state.
|
||||
disconnect(onDisconnect);
|
||||
} else {
|
||||
String[] response = ((String[]) ar.result);
|
||||
cid = Integer.parseInt(response[0]);
|
||||
|
||||
if (response.length > 2) {
|
||||
interfaceName = response[1];
|
||||
ipAddress = response[2];
|
||||
String prefix = "net." + interfaceName + ".";
|
||||
gatewayAddress = SystemProperties.get(prefix + "gw");
|
||||
dnsServers[0] = SystemProperties.get(prefix + "dns1");
|
||||
dnsServers[1] = SystemProperties.get(prefix + "dns2");
|
||||
if (DBG) {
|
||||
log("interface=" + interfaceName + " ipAddress=" + ipAddress
|
||||
+ " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
|
||||
+ " DNS2=" + dnsServers[1]);
|
||||
}
|
||||
|
||||
if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
|
||||
&& !((CDMAPhone) phone).isDnsCheckDisabled()) {
|
||||
// Work around a race condition where QMI does not fill in DNS:
|
||||
// Deactivate PDP and let DataConnectionTracker retry.
|
||||
EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
|
||||
dnsServers[0]);
|
||||
phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
onLinkStateChanged(DataLink.LinkState.LINK_UP);
|
||||
|
||||
if (DBG) log("CdmaDataConnection setup on cid = " + cid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,929 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.INetStatService;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.provider.Checkin;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.SettingNotFoundException;
|
||||
import android.telephony.ServiceState;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.EventLog;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.CommandsInterface;
|
||||
import com.android.internal.telephony.DataConnection;
|
||||
import com.android.internal.telephony.DataConnection.FailCause;
|
||||
import com.android.internal.telephony.DataConnectionTracker;
|
||||
import com.android.internal.telephony.Phone;
|
||||
import com.android.internal.telephony.PhoneProxy;
|
||||
import com.android.internal.telephony.TelephonyEventLog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* WINK:TODO: In GsmDataConnectionTracker there are
|
||||
* EventLog's used quite a few places maybe
|
||||
* more need to be added in this file?
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public final class CdmaDataConnectionTracker extends DataConnectionTracker {
|
||||
private static final String LOG_TAG = "CDMA";
|
||||
private static final boolean DBG = true;
|
||||
|
||||
//***** Instance Variables
|
||||
|
||||
// Indicates baseband will not auto-attach
|
||||
private boolean noAutoAttach = false;
|
||||
long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
|
||||
private boolean mIsScreenOn = true;
|
||||
|
||||
//useful for debugging
|
||||
boolean failNextConnect = false;
|
||||
|
||||
/**
|
||||
* dataConnectionList holds all the Data connection
|
||||
*/
|
||||
private ArrayList<DataConnection> dataConnectionList;
|
||||
|
||||
/** Currently active CdmaDataConnection */
|
||||
private CdmaDataConnection mActiveDataConnection;
|
||||
|
||||
/** Defined cdma connection profiles */
|
||||
private static int EXTERNAL_NETWORK_DEFAULT_ID = 0;
|
||||
private static int EXTERNAL_NETWORK_NUM_TYPES = 1;
|
||||
|
||||
private boolean[] dataEnabled = new boolean[EXTERNAL_NETWORK_NUM_TYPES];
|
||||
|
||||
//***** Constants
|
||||
|
||||
/**
|
||||
* Pool size of CdmaDataConnection objects.
|
||||
*/
|
||||
private static final int DATA_CONNECTION_POOL_SIZE = 1;
|
||||
|
||||
private static final int POLL_CONNECTION_MILLIS = 5 * 1000;
|
||||
private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.cdma-reconnect";
|
||||
private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
|
||||
|
||||
// Possibly promoate 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 ()
|
||||
{
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent)
|
||||
{
|
||||
String action = intent.getAction();
|
||||
if (action.equals(Intent.ACTION_SCREEN_ON)) {
|
||||
mIsScreenOn = true;
|
||||
stopNetStatPoll();
|
||||
startNetStatPoll();
|
||||
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
|
||||
mIsScreenOn = false;
|
||||
stopNetStatPoll();
|
||||
startNetStatPoll();
|
||||
} else if (action.equals((INTENT_RECONNECT_ALARM))) {
|
||||
Log.d(LOG_TAG, "Data reconnect alarm. Previous state was " + state);
|
||||
|
||||
String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
|
||||
if (state == State.FAILED) {
|
||||
cleanUpConnection(false, reason);
|
||||
}
|
||||
trySetupData(reason);
|
||||
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
|
||||
final android.net.NetworkInfo networkInfo = (NetworkInfo)
|
||||
intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
|
||||
mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
|
||||
} else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
|
||||
final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
|
||||
WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
|
||||
|
||||
if (!enabled) {
|
||||
// when wifi got disabeled, the NETWORK_STATE_CHANGED_ACTION
|
||||
// quit and wont report disconnected til next enalbing.
|
||||
mIsWifiConnected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//***** Constructor
|
||||
|
||||
CdmaDataConnectionTracker(CDMAPhone p) {
|
||||
super(p);
|
||||
|
||||
p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
|
||||
p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
|
||||
p.mRuimRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
|
||||
p.mCM.registerForNVReady(this, EVENT_NV_READY, null);
|
||||
p.mCM.registerForDataStateChanged (this, EVENT_DATA_STATE_CHANGED, null);
|
||||
p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
|
||||
p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
|
||||
p.mSST.registerForCdmaDataConnectionAttached(this, EVENT_TRY_SETUP_DATA, null);
|
||||
p.mSST.registerForCdmaDataConnectionDetached(this, EVENT_CDMA_DATA_DETACHED, null);
|
||||
p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null);
|
||||
p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
|
||||
|
||||
this.netstat = INetStatService.Stub.asInterface(ServiceManager.getService("netstat"));
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(INTENT_RECONNECT_ALARM);
|
||||
filter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
||||
|
||||
p.getContext().registerReceiver(mIntentReceiver, filter, null, p.h);
|
||||
|
||||
mDataConnectionTracker = this;
|
||||
|
||||
createAllDataConnectionList();
|
||||
|
||||
// This preference tells us 1) initial condition for "dataEnabled",
|
||||
// and 2) whether the RIL will setup the baseband to auto-PS attach.
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
|
||||
|
||||
dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID] =
|
||||
!sp.getBoolean(CDMAPhone.DATA_DISABLED_ON_BOOT_KEY, false);
|
||||
noAutoAttach = !dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID];
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
//Unregister from all events
|
||||
phone.mCM.unregisterForAvailable(this);
|
||||
phone.mCM.unregisterForOffOrNotAvailable(this);
|
||||
((CDMAPhone) phone).mRuimRecords.unregisterForRecordsLoaded(this);
|
||||
phone.mCM.unregisterForNVReady(this);
|
||||
phone.mCM.unregisterForDataStateChanged(this);
|
||||
((CDMAPhone) phone).mCT.unregisterForVoiceCallEnded(this);
|
||||
((CDMAPhone) phone).mCT.unregisterForVoiceCallStarted(this);
|
||||
((CDMAPhone) phone).mSST.unregisterForCdmaDataConnectionAttached(this);
|
||||
((CDMAPhone) phone).mSST.unregisterForCdmaDataConnectionDetached(this);
|
||||
((CDMAPhone) phone).mSST.unregisterForRoamingOn(this);
|
||||
((CDMAPhone) phone).mSST.unregisterForRoamingOff(this);
|
||||
|
||||
phone.getContext().unregisterReceiver(this.mIntentReceiver);
|
||||
destroyAllDataConnectionList();
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if(DBG) Log.d(LOG_TAG, "CdmaDataConnectionTracker finalized");
|
||||
}
|
||||
|
||||
void setState(State s) {
|
||||
if (DBG) log ("setState: " + s);
|
||||
if (state != s) {
|
||||
if (s == State.INITING) { // request Data connection context
|
||||
Checkin.updateStats(phone.getContext().getContentResolver(),
|
||||
Checkin.Stats.Tag.PHONE_CDMA_DATA_ATTEMPTED, 1, 0.0);
|
||||
}
|
||||
|
||||
if (s == State.CONNECTED) { // pppd is up
|
||||
Checkin.updateStats(phone.getContext().getContentResolver(),
|
||||
Checkin.Stats.Tag.PHONE_CDMA_DATA_CONNECTED, 1, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
state = s;
|
||||
}
|
||||
|
||||
public int enableApnType(String type) {
|
||||
// This request is mainly used to enable MMS APN
|
||||
// In CDMA there is no need to enable/disable a different APN for MMS
|
||||
Log.d(LOG_TAG, "Request to enableApnType("+type+")");
|
||||
if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
|
||||
return Phone.APN_ALREADY_ACTIVE;
|
||||
} else {
|
||||
return Phone.APN_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
public int disableApnType(String type) {
|
||||
// This request is mainly used to disable MMS APN
|
||||
// In CDMA there is no need to enable/disable a different APN for MMS
|
||||
Log.d(LOG_TAG, "Request to disableApnType("+type+")");
|
||||
if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
|
||||
return Phone.APN_REQUEST_STARTED;
|
||||
} else {
|
||||
return Phone.APN_REQUEST_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEnabled(int cdmaDataProfile) {
|
||||
return dataEnabled[cdmaDataProfile];
|
||||
}
|
||||
|
||||
private void setEnabled(int cdmaDataProfile, boolean enable) {
|
||||
Log.d(LOG_TAG, "setEnabled(" + cdmaDataProfile + ", " + enable + ')');
|
||||
dataEnabled[cdmaDataProfile] = enable;
|
||||
Log.d(LOG_TAG, "dataEnabled[DEFAULT_PROFILE]=" + dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply tear down data connections due to radio off
|
||||
* and don't setup again.
|
||||
*/
|
||||
public void cleanConnectionBeforeRadioOff() {
|
||||
cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* The data connection is expected to be setup while device
|
||||
* 1. has ruim card or non-volatile data store
|
||||
* 2. registered to data connection service
|
||||
* 3. user doesn't explicitly disable data service
|
||||
* 4. wifi is not on
|
||||
*
|
||||
* @return false while no data connection if all above requirements are met.
|
||||
*/
|
||||
public boolean isDataConnectionAsDesired() {
|
||||
boolean roaming = phone.getServiceState().getRoaming();
|
||||
|
||||
if ( ((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) ||
|
||||
((CDMAPhone) phone).mRuimRecords.getRecordsLoaded()) &&
|
||||
((CDMAPhone) phone).mSST.getCurrentCdmaDataConnectionState() ==
|
||||
ServiceState.STATE_IN_SERVICE &&
|
||||
(!roaming || getDataOnRoamingEnabled()) &&
|
||||
!mIsWifiConnected ) {
|
||||
return (state == State.CONNECTED);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent mobile data connections from being established,
|
||||
* or once again allow mobile data connections. If the state
|
||||
* toggles, then either tear down or set up data, as
|
||||
* appropriate to match the new state.
|
||||
* <p>This operation only affects the default connection
|
||||
* @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
|
||||
* @return {@code true} if the operation succeeded
|
||||
*/
|
||||
public boolean setDataEnabled(boolean enable) {
|
||||
|
||||
boolean isEnabled = isEnabled(EXTERNAL_NETWORK_DEFAULT_ID);
|
||||
|
||||
Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled);
|
||||
if (!isEnabled && enable) {
|
||||
setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, true);
|
||||
return trySetupData(Phone.REASON_DATA_ENABLED);
|
||||
} else if (!enable) {
|
||||
setEnabled(EXTERNAL_NETWORK_DEFAULT_ID, false);
|
||||
return false;
|
||||
} else // isEnabled && enable
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report the current state of data connectivity (enabled or disabled)
|
||||
* @return {@code false} if data connectivity has been explicitly disabled,
|
||||
* {@code true} otherwise.
|
||||
*/
|
||||
public boolean getDataEnabled() {
|
||||
return dataEnabled[EXTERNAL_NETWORK_DEFAULT_ID];
|
||||
}
|
||||
|
||||
/**
|
||||
* Report on whether data connectivity is enabled
|
||||
* @return {@code false} if data connectivity has been explicitly disabled,
|
||||
* {@code true} otherwise.
|
||||
*/
|
||||
public boolean getAnyDataEnabled() {
|
||||
for (int i=0; i < EXTERNAL_NETWORK_NUM_TYPES; i++) {
|
||||
if (isEnabled(i)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isDataAllowed() {
|
||||
boolean roaming = phone.getServiceState().getRoaming();
|
||||
return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled());
|
||||
}
|
||||
|
||||
private boolean trySetupData(String reason) {
|
||||
if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason));
|
||||
|
||||
if (phone.getSimulatedRadioControl() != null) {
|
||||
// Assume data is connected on the simulator
|
||||
// FIXME this can be improved
|
||||
setState(State.CONNECTED);
|
||||
phone.notifyDataConnection(reason);
|
||||
|
||||
Log.i(LOG_TAG, "(fix?) We're on the simulator; assuming data is connected");
|
||||
return true;
|
||||
}
|
||||
|
||||
int psState = ((CDMAPhone) phone).mSST.getCurrentCdmaDataConnectionState();
|
||||
boolean roaming = phone.getServiceState().getRoaming();
|
||||
|
||||
if ((state == State.IDLE || state == State.SCANNING)
|
||||
&& (psState == ServiceState.RADIO_TECHNOLOGY_1xRTT ||
|
||||
psState == ServiceState.RADIO_TECHNOLOGY_EVDO_0 ||
|
||||
psState == ServiceState.RADIO_TECHNOLOGY_EVDO_A)
|
||||
&& ((phone.mCM.getRadioState() == CommandsInterface.RadioState.NV_READY) ||
|
||||
((CDMAPhone) phone).mRuimRecords.getRecordsLoaded())
|
||||
&& (((CDMAPhone) phone).mSST.isConcurrentVoiceAndData() ||
|
||||
phone.getState() == Phone.State.IDLE )
|
||||
&& isDataAllowed()) {
|
||||
|
||||
return setupData(reason);
|
||||
|
||||
} else {
|
||||
if (DBG) {
|
||||
log("trySetupData: Not ready for data: " +
|
||||
" dataState=" + state +
|
||||
" PS state=" + psState +
|
||||
" radio state=" + phone.mCM.getRadioState() +
|
||||
" ruim=" + ((CDMAPhone) phone).mRuimRecords.getRecordsLoaded() +
|
||||
" concurrentVoice&Data=" + ((CDMAPhone) phone).mSST.isConcurrentVoiceAndData() +
|
||||
" phoneState=" + phone.getState() +
|
||||
" dataEnabled=" + getAnyDataEnabled() +
|
||||
" roaming=" + roaming +
|
||||
" dataOnRoamingEnable=" + getDataOnRoamingEnabled());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If tearDown is true, this only tears down a CONNECTED session. Presently,
|
||||
* there is no mechanism for abandoning an INITING/CONNECTING session,
|
||||
* but would likely involve cancelling pending async requests or
|
||||
* setting a flag or new state to ignore them when they came in
|
||||
* @param tearDown true if the underlying DataConnection should be
|
||||
* disconnected.
|
||||
* @param reason reason for the clean up.
|
||||
*/
|
||||
private void cleanUpConnection(boolean tearDown, String reason) {
|
||||
if (DBG) log("Clean up connection due to " + reason);
|
||||
|
||||
// Clear the reconnect alarm, if set.
|
||||
if (mReconnectIntent != null) {
|
||||
AlarmManager am =
|
||||
(AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
|
||||
am.cancel(mReconnectIntent);
|
||||
mReconnectIntent = null;
|
||||
}
|
||||
|
||||
for (DataConnection connBase : dataConnectionList) {
|
||||
CdmaDataConnection conn = (CdmaDataConnection) connBase;
|
||||
|
||||
if(conn != null) {
|
||||
if (tearDown) {
|
||||
Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
|
||||
conn.disconnect(msg);
|
||||
} else {
|
||||
conn.clearSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stopNetStatPoll();
|
||||
|
||||
/*
|
||||
* If we've been asked to tear down the connection,
|
||||
* set the state to DISCONNECTING. However, there's
|
||||
* a race that can occur if for some reason we were
|
||||
* already in the IDLE state. In that case, the call
|
||||
* to conn.disconnect() above will immediately post
|
||||
* a message to the handler thread that the disconnect
|
||||
* is done, and if the handler runs before the code
|
||||
* below does, the handler will have set the state to
|
||||
* IDLE before the code below runs. If we didn't check
|
||||
* for that, future calls to trySetupData would fail,
|
||||
* and we would never get out of the DISCONNECTING state.
|
||||
*/
|
||||
if (!tearDown) {
|
||||
setState(State.IDLE);
|
||||
phone.notifyDataConnection(reason);
|
||||
} else if (state != State.IDLE) {
|
||||
setState(State.DISCONNECTING);
|
||||
}
|
||||
}
|
||||
|
||||
private CdmaDataConnection findFreeDataConnection() {
|
||||
for (DataConnection connBase : dataConnectionList) {
|
||||
CdmaDataConnection conn = (CdmaDataConnection) connBase;
|
||||
if (conn.getState() == DataConnection.State.INACTIVE) {
|
||||
return conn;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean setupData(String reason) {
|
||||
|
||||
CdmaDataConnection conn = findFreeDataConnection();
|
||||
|
||||
if (conn == null) {
|
||||
if (DBG) log("setupData: No free CdmaDataConnectionfound!");
|
||||
return false;
|
||||
}
|
||||
|
||||
mActiveDataConnection = conn;
|
||||
|
||||
Message msg = obtainMessage();
|
||||
msg.what = EVENT_DATA_SETUP_COMPLETE;
|
||||
msg.obj = reason;
|
||||
conn.connect(msg);
|
||||
|
||||
setState(State.INITING);
|
||||
phone.notifyDataConnection(reason);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void notifyDefaultData(String reason) {
|
||||
setState(State.CONNECTED);
|
||||
phone.notifyDataConnection(reason);
|
||||
startNetStatPoll();
|
||||
// reset reconnect timer
|
||||
nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
|
||||
}
|
||||
|
||||
private void resetPollStats() {
|
||||
txPkts = -1;
|
||||
rxPkts = -1;
|
||||
sentSinceLastRecv = 0;
|
||||
netStatPollPeriod = POLL_NETSTAT_MILLIS;
|
||||
mNoRecvPollCount = 0;
|
||||
}
|
||||
|
||||
protected void startNetStatPoll() {
|
||||
if (state == State.CONNECTED && netStatPollEnabled == false) {
|
||||
Log.d(LOG_TAG, "[DataConnection] Start poll NetStat");
|
||||
resetPollStats();
|
||||
netStatPollEnabled = true;
|
||||
mPollNetStat.run();
|
||||
}
|
||||
}
|
||||
|
||||
protected void stopNetStatPoll() {
|
||||
netStatPollEnabled = false;
|
||||
removeCallbacks(mPollNetStat);
|
||||
Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat");
|
||||
}
|
||||
|
||||
protected void restartRadio() {
|
||||
Log.d(LOG_TAG, "************TURN OFF RADIO**************");
|
||||
cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
|
||||
phone.mCM.setRadioPower(false, null);
|
||||
/* Note: no need to call setRadioPower(true). Assuming the desired
|
||||
* radio power state is still ON (as tracked by ServiceStateTracker),
|
||||
* ServiceStateTracker will call setRadioPower when it receives the
|
||||
* RADIO_STATE_CHANGED notification for the power off. And if the
|
||||
* desired power state has changed in the interim, we don't want to
|
||||
* override it with an unconditional power on.
|
||||
*/
|
||||
}
|
||||
|
||||
private Runnable mPollNetStat = new Runnable() {
|
||||
|
||||
public void run() {
|
||||
long sent, received;
|
||||
long preTxPkts = -1, preRxPkts = -1;
|
||||
|
||||
Activity newActivity;
|
||||
|
||||
preTxPkts = txPkts;
|
||||
preRxPkts = rxPkts;
|
||||
|
||||
// check if netstat is still valid to avoid NullPointerException after NTC
|
||||
if (netstat != null) {
|
||||
try {
|
||||
txPkts = netstat.getMobileTxPackets();
|
||||
rxPkts = netstat.getMobileRxPackets();
|
||||
} catch (RemoteException e) {
|
||||
txPkts = 0;
|
||||
rxPkts = 0;
|
||||
}
|
||||
|
||||
//Log.d(LOG_TAG, "rx " + String.valueOf(rxPkts) + " tx " + String.valueOf(txPkts));
|
||||
|
||||
if (netStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) {
|
||||
sent = txPkts - preTxPkts;
|
||||
received = rxPkts - preRxPkts;
|
||||
|
||||
if ( sent > 0 && received > 0 ) {
|
||||
sentSinceLastRecv = 0;
|
||||
newActivity = Activity.DATAINANDOUT;
|
||||
} else if (sent > 0 && received == 0) {
|
||||
if (phone.getState() == Phone.State.IDLE) {
|
||||
sentSinceLastRecv += sent;
|
||||
} else {
|
||||
sentSinceLastRecv = 0;
|
||||
}
|
||||
newActivity = Activity.DATAOUT;
|
||||
} else if (sent == 0 && received > 0) {
|
||||
sentSinceLastRecv = 0;
|
||||
newActivity = Activity.DATAIN;
|
||||
} else if (sent == 0 && received == 0) {
|
||||
newActivity = Activity.NONE;
|
||||
} else {
|
||||
sentSinceLastRecv = 0;
|
||||
newActivity = Activity.NONE;
|
||||
}
|
||||
|
||||
if (activity != newActivity) {
|
||||
activity = newActivity;
|
||||
phone.notifyDataActivity();
|
||||
}
|
||||
}
|
||||
|
||||
if (sentSinceLastRecv >= NUMBER_SENT_PACKETS_OF_HANG) {
|
||||
// we already have NUMBER_SENT_PACKETS sent without ack
|
||||
if (mNoRecvPollCount < NO_RECV_POLL_LIMIT) {
|
||||
mNoRecvPollCount++;
|
||||
// Slow down the poll interval to let things happen
|
||||
netStatPollPeriod = POLL_NETSTAT_SLOW_MILLIS;
|
||||
} else {
|
||||
if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) +
|
||||
" pkts since last received");
|
||||
// We've exceeded the threshold. Restart the radio.
|
||||
netStatPollEnabled = false;
|
||||
stopNetStatPoll();
|
||||
restartRadio();
|
||||
}
|
||||
} else {
|
||||
mNoRecvPollCount = 0;
|
||||
netStatPollPeriod = POLL_NETSTAT_MILLIS;
|
||||
}
|
||||
|
||||
if (netStatPollEnabled) {
|
||||
mDataConnectionTracker.postDelayed(this, netStatPollPeriod);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if the last fail cause is something that
|
||||
* seems like it deserves an error notification.
|
||||
* Transient errors are ignored
|
||||
*/
|
||||
private boolean
|
||||
shouldPostNotification(FailCause cause) {
|
||||
return (cause != FailCause.UNKNOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if data connection need to be setup after disconnected due to
|
||||
* reason.
|
||||
*
|
||||
* @param reason the reason why data is disconnected
|
||||
* @return true if try setup data connection is need for this reason
|
||||
*/
|
||||
private boolean retryAfterDisconnected(String reason) {
|
||||
boolean retry = true;
|
||||
|
||||
if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
|
||||
Phone.REASON_DATA_DISABLED.equals(reason) ) {
|
||||
retry = false;
|
||||
}
|
||||
return retry;
|
||||
}
|
||||
|
||||
private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
|
||||
if (state == State.FAILED) {
|
||||
Log.d(LOG_TAG, "Data Connection activate failed. Scheduling next attempt for "
|
||||
+ (nextReconnectDelay / 1000) + "s");
|
||||
|
||||
AlarmManager am =
|
||||
(AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
|
||||
Intent intent = new Intent(INTENT_RECONNECT_ALARM);
|
||||
intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, reason);
|
||||
mReconnectIntent = PendingIntent.getBroadcast(
|
||||
phone.getContext(), 0, intent, 0);
|
||||
am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime() + nextReconnectDelay,
|
||||
mReconnectIntent);
|
||||
|
||||
// double it for next time
|
||||
nextReconnectDelay *= 2;
|
||||
if (nextReconnectDelay > RECONNECT_DELAY_MAX_MILLIS) {
|
||||
nextReconnectDelay = RECONNECT_DELAY_MAX_MILLIS;
|
||||
}
|
||||
|
||||
if (!shouldPostNotification(lastFailCauseCode)) {
|
||||
Log.d(LOG_TAG,"NOT Posting Data Connection Unavailable notification "
|
||||
+ "-- likely transient error");
|
||||
} else {
|
||||
notifyNoData(lastFailCauseCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyNoData(FailCause lastFailCauseCode) {
|
||||
setState(State.FAILED);
|
||||
}
|
||||
|
||||
protected void onRecordsLoaded() {
|
||||
if (state == State.FAILED) {
|
||||
cleanUpConnection(false, null);
|
||||
}
|
||||
sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
|
||||
}
|
||||
|
||||
protected void onNVReady() {
|
||||
if (state == State.FAILED) {
|
||||
cleanUpConnection(false, null);
|
||||
}
|
||||
sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
|
||||
}
|
||||
|
||||
/**
|
||||
* @override com.android.internal.telephony.DataConnectionTracker
|
||||
*/
|
||||
protected void onTrySetupData() {
|
||||
trySetupData(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override com.android.internal.telephony.DataConnectionTracker
|
||||
*/
|
||||
protected void onRoamingOff() {
|
||||
trySetupData(Phone.REASON_ROAMING_OFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override com.android.internal.telephony.DataConnectionTracker
|
||||
*/
|
||||
protected void onRoamingOn() {
|
||||
if (getDataOnRoamingEnabled()) {
|
||||
trySetupData(Phone.REASON_ROAMING_ON);
|
||||
} else {
|
||||
if (DBG) log("Tear down data connection on roaming.");
|
||||
cleanUpConnection(true, Phone.REASON_ROAMING_ON);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override com.android.internal.telephony.DataConnectionTracker
|
||||
*/
|
||||
protected void onRadioAvailable() {
|
||||
if (phone.getSimulatedRadioControl() != null) {
|
||||
// Assume data is connected on the simulator
|
||||
// FIXME this can be improved
|
||||
setState(State.CONNECTED);
|
||||
phone.notifyDataConnection(null);
|
||||
|
||||
Log.i(LOG_TAG, "We're on the simulator; assuming data is connected");
|
||||
}
|
||||
|
||||
if (state != State.IDLE) {
|
||||
cleanUpConnection(true, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override com.android.internal.telephony.DataConnectionTracker
|
||||
*/
|
||||
protected void onRadioOffOrNotAvailable() {
|
||||
// Make sure our reconnect delay starts at the initial value
|
||||
// next time the radio comes on
|
||||
nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
|
||||
|
||||
if (phone.getSimulatedRadioControl() != null) {
|
||||
// Assume data is connected on the simulator
|
||||
// FIXME this can be improved
|
||||
Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless");
|
||||
} else {
|
||||
if (DBG) log("Radio is off and clean up all connection");
|
||||
cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override com.android.internal.telephony.DataConnectionTracker
|
||||
*/
|
||||
protected void onDataSetupComplete(AsyncResult ar) {
|
||||
String reason = null;
|
||||
if (ar.userObj instanceof String) {
|
||||
reason = (String) ar.userObj;
|
||||
}
|
||||
|
||||
if (ar.exception == null) {
|
||||
// everything is setup
|
||||
notifyDefaultData(reason);
|
||||
} else {
|
||||
FailCause cause = (FailCause) (ar.result);
|
||||
if(DBG) log("Data Connection setup failed " + cause);
|
||||
|
||||
// No try for permanent failure
|
||||
if (cause.isPermanentFail()) {
|
||||
notifyNoData(cause);
|
||||
}
|
||||
|
||||
if (tryAgain(cause)) {
|
||||
trySetupData(reason);
|
||||
} else {
|
||||
startDelayedRetry(cause, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override com.android.internal.telephony.DataConnectionTracker
|
||||
*/
|
||||
protected void onDisconnectDone(AsyncResult ar) {
|
||||
if(DBG) log("EVENT_DISCONNECT_DONE");
|
||||
String reason = null;
|
||||
if (ar.userObj instanceof String) {
|
||||
reason = (String) ar.userObj;
|
||||
}
|
||||
setState(State.IDLE);
|
||||
phone.notifyDataConnection(reason);
|
||||
if (retryAfterDisconnected(reason)) {
|
||||
trySetupData(reason);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override com.android.internal.telephony.DataConnectionTracker
|
||||
*/
|
||||
protected void onVoiceCallStarted() {
|
||||
if (state == State.CONNECTED && !((CDMAPhone) phone).mSST.isConcurrentVoiceAndData()) {
|
||||
stopNetStatPoll();
|
||||
phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override com.android.internal.telephony.DataConnectionTracker
|
||||
*/
|
||||
protected void onVoiceCallEnded() {
|
||||
if (state == State.CONNECTED) {
|
||||
if (!((CDMAPhone) phone).mSST.isConcurrentVoiceAndData()) {
|
||||
startNetStatPoll();
|
||||
phone.notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
|
||||
} else {
|
||||
// clean slate after call end.
|
||||
resetPollStats();
|
||||
}
|
||||
} else {
|
||||
// in case data setup was attempted when we were on a voice call
|
||||
trySetupData(Phone.REASON_VOICE_CALL_ENDED);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tryAgain(FailCause cause) {
|
||||
return (cause != FailCause.RADIO_NOT_AVAILABLE)
|
||||
&& (cause != FailCause.RADIO_OFF)
|
||||
&& (cause != FailCause.RADIO_ERROR_RETRY)
|
||||
&& (cause != FailCause.NO_SIGNAL)
|
||||
&& (cause != FailCause.SIM_LOCKED);
|
||||
}
|
||||
|
||||
private void createAllDataConnectionList() {
|
||||
dataConnectionList = new ArrayList<DataConnection>();
|
||||
CdmaDataConnection dataConn;
|
||||
|
||||
for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) {
|
||||
dataConn = new CdmaDataConnection(((CDMAPhone) phone));
|
||||
dataConnectionList.add(dataConn);
|
||||
}
|
||||
}
|
||||
|
||||
private void destroyAllDataConnectionList() {
|
||||
if(dataConnectionList != null) {
|
||||
CdmaDataConnection pdp;
|
||||
dataConnectionList.removeAll(dataConnectionList);
|
||||
}
|
||||
}
|
||||
|
||||
private void onCdmaDataAttached() {
|
||||
if (state == State.CONNECTED) {
|
||||
startNetStatPoll();
|
||||
phone.notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED);
|
||||
} else {
|
||||
if (state == State.FAILED) {
|
||||
cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED);
|
||||
nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
|
||||
}
|
||||
trySetupData(Phone.REASON_CDMA_DATA_DETACHED);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onDataStateChanged (AsyncResult ar) {
|
||||
if (ar.exception != null) {
|
||||
// This is probably "radio not available" or something
|
||||
// of that sort. If so, the whole connection is going
|
||||
// to come down soon anyway
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == State.CONNECTED) {
|
||||
Log.i(LOG_TAG, "Data connection has changed.");
|
||||
|
||||
int cid = -1;
|
||||
EventLog.List val = new EventLog.List(cid,
|
||||
TelephonyManager.getDefault().getNetworkType());
|
||||
EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
|
||||
|
||||
cleanUpConnection(true, null);
|
||||
}
|
||||
Log.i(LOG_TAG, "Data connection has changed.");
|
||||
}
|
||||
|
||||
String getInterfaceName() {
|
||||
if (mActiveDataConnection != null) {
|
||||
return mActiveDataConnection.getInterface();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String getIpAddress() {
|
||||
if (mActiveDataConnection != null) {
|
||||
return mActiveDataConnection.getIpAddress();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String getGateway() {
|
||||
if (mActiveDataConnection != null) {
|
||||
return mActiveDataConnection.getGatewayAddress();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected String[] getDnsServers() {
|
||||
if (mActiveDataConnection != null) {
|
||||
return mActiveDataConnection.getDnsServers();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ArrayList<DataConnection> getAllDataConnections() {
|
||||
return dataConnectionList;
|
||||
}
|
||||
|
||||
private void startDelayedRetry(FailCause cause, String reason) {
|
||||
notifyNoData(cause);
|
||||
reconnectAfterFail(cause, reason);
|
||||
}
|
||||
|
||||
public void handleMessage (Message msg) {
|
||||
|
||||
switch (msg.what) {
|
||||
case EVENT_RECORDS_LOADED:
|
||||
onRecordsLoaded();
|
||||
break;
|
||||
|
||||
case EVENT_NV_READY:
|
||||
onNVReady();
|
||||
break;
|
||||
|
||||
case EVENT_CDMA_DATA_DETACHED:
|
||||
onCdmaDataAttached();
|
||||
break;
|
||||
|
||||
case EVENT_DATA_STATE_CHANGED:
|
||||
onDataStateChanged((AsyncResult) msg.obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
// handle the message in the super class DataConnectionTracker
|
||||
super.handleMessage(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void log(String s) {
|
||||
Log.d(LOG_TAG, "[CdmaDataConnectionTracker] " + s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Message;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.SmsHeader;
|
||||
import com.android.internal.telephony.SmsMessageBase;
|
||||
import com.android.internal.telephony.SMSDispatcher;
|
||||
//import com.android.internal.telephony.SMSDispatcher.SmsTracker;
|
||||
import com.android.internal.telephony.cdma.SmsMessage;
|
||||
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
|
||||
import com.android.internal.util.HexDump;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
final class CdmaSMSDispatcher extends SMSDispatcher {
|
||||
private static final String TAG = "CDMA";
|
||||
|
||||
CdmaSMSDispatcher(CDMAPhone phone) {
|
||||
super(phone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a status report is received. This should correspond to
|
||||
* a previously successful SEND.
|
||||
* Is a special GSM function, should never be called in CDMA!!
|
||||
*
|
||||
* @param ar AsyncResult passed into the message handler. ar.result should
|
||||
* be a String representing the status report PDU, as ASCII hex.
|
||||
*/
|
||||
protected void handleStatusReport(AsyncResult ar) {
|
||||
Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an incoming SMS messages.
|
||||
*
|
||||
* @param smsb the incoming message from the phone
|
||||
*/
|
||||
protected void dispatchMessage(SmsMessageBase smsb) {
|
||||
|
||||
// If sms is null, means there was a parsing error.
|
||||
// TODO: Should NAK this.
|
||||
if (smsb == null) {
|
||||
return;
|
||||
}
|
||||
SmsMessage sms = (SmsMessage) smsb;
|
||||
int teleService;
|
||||
boolean handled = false;
|
||||
|
||||
// Decode BD stream and set sms variables.
|
||||
sms.parseSms();
|
||||
teleService = sms.getTeleService();
|
||||
|
||||
// Teleservices W(E)MT and VMN are handled together:
|
||||
if ((SmsEnvelope.TELESERVICE_WMT == teleService)
|
||||
||(SmsEnvelope.TELESERVICE_WEMT == teleService)
|
||||
||(SmsEnvelope.TELESERVICE_VMN == teleService)){
|
||||
// From here on we need decoded BD.
|
||||
// Special case the message waiting indicator messages
|
||||
if (sms.isMWISetMessage()) {
|
||||
((CDMAPhone) mPhone).updateMessageWaitingIndicator(true);
|
||||
|
||||
if (sms.isMwiDontStore()) {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (Config.LOGD) {
|
||||
Log.d(TAG,
|
||||
"Received voice mail indicator set SMS shouldStore=" + !handled);
|
||||
}
|
||||
} else if (sms.isMWIClearMessage()) {
|
||||
((CDMAPhone) mPhone).updateMessageWaitingIndicator(false);
|
||||
|
||||
if (sms.isMwiDontStore()) {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (Config.LOGD) {
|
||||
Log.d(TAG,
|
||||
"Received voice mail indicator clear SMS shouldStore=" + !handled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null == sms.getUserData()){
|
||||
handled = true;
|
||||
if (Config.LOGD) {
|
||||
Log.d(TAG, "Received SMS without user data");
|
||||
}
|
||||
}
|
||||
|
||||
if (handled) return;
|
||||
|
||||
if (SmsEnvelope.TELESERVICE_WAP == teleService){
|
||||
processCdmaWapPdu(sms.getUserData(), sms.messageRef, sms.getOriginatingAddress());
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the headers to see if this is partial, or port addressed
|
||||
int referenceNumber = -1;
|
||||
int count = 0;
|
||||
int sequence = 0;
|
||||
int destPort = -1;
|
||||
// From here on we need BD distributed to SMS member variables.
|
||||
|
||||
SmsHeader header = sms.getUserDataHeader();
|
||||
if (header != null) {
|
||||
for (SmsHeader.Element element : header.getElements()) {
|
||||
try {
|
||||
switch (element.getID()) {
|
||||
case SmsHeader.CONCATENATED_8_BIT_REFERENCE: {
|
||||
byte[] data = element.getData();
|
||||
|
||||
referenceNumber = data[0] & 0xff;
|
||||
count = data[1] & 0xff;
|
||||
sequence = data[2] & 0xff;
|
||||
|
||||
// Per TS 23.040, 9.2.3.24.1: If the count is zero, sequence
|
||||
// is zero, or sequence > count, ignore the entire element
|
||||
if (count == 0 || sequence == 0 || sequence > count) {
|
||||
referenceNumber = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SmsHeader.CONCATENATED_16_BIT_REFERENCE: {
|
||||
byte[] data = element.getData();
|
||||
|
||||
referenceNumber = (data[0] & 0xff) * 256 + (data[1] & 0xff);
|
||||
count = data[2] & 0xff;
|
||||
sequence = data[3] & 0xff;
|
||||
|
||||
// Per TS 23.040, 9.2.3.24.8: If the count is zero, sequence
|
||||
// is zero, or sequence > count, ignore the entire element
|
||||
if (count == 0 || sequence == 0 || sequence > count) {
|
||||
referenceNumber = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT: {
|
||||
byte[] data = element.getData();
|
||||
|
||||
destPort = (data[0] & 0xff) << 8;
|
||||
destPort |= (data[1] & 0xff);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
Log.e(TAG, "Bad element in header", e);
|
||||
return; // TODO: NACK the message or something, don't just discard.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (referenceNumber == -1) {
|
||||
// notify everyone of the message if it isn't partial
|
||||
byte[][] pdus = new byte[1][];
|
||||
pdus[0] = sms.getPdu();
|
||||
|
||||
if (destPort != -1) {// GSM-style WAP indication
|
||||
if (destPort == SmsHeader.PORT_WAP_PUSH) {
|
||||
mWapPush.dispatchWapPdu(sms.getUserData());
|
||||
}
|
||||
// The message was sent to a port, so concoct a URI for it
|
||||
dispatchPortAddressedPdus(pdus, destPort);
|
||||
} else {
|
||||
// It's a normal message, dispatch it
|
||||
dispatchPdus(pdus);
|
||||
}
|
||||
} else {
|
||||
// Process the message part
|
||||
processMessagePart(sms, referenceNumber, sequence, count, destPort);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes inbound messages that are in the WAP-WDP PDU format. See
|
||||
* wap-259-wdp-20010614-a section 6.5 for details on the WAP-WDP PDU format.
|
||||
* WDP segments are gathered until a datagram completes and gets dispatched.
|
||||
*
|
||||
* @param pdu The WAP-WDP PDU segment
|
||||
*/
|
||||
protected void processCdmaWapPdu(byte[] pdu, int referenceNumber, String address) {
|
||||
int segment;
|
||||
int totalSegments;
|
||||
int index = 0;
|
||||
int msgType;
|
||||
|
||||
int sourcePort;
|
||||
int destinationPort;
|
||||
|
||||
msgType = pdu[index++];
|
||||
if (msgType != 0){
|
||||
Log.w(TAG, "Received a WAP SMS which is not WDP. Discard.");
|
||||
return;
|
||||
}
|
||||
totalSegments = pdu[index++]; // >=1
|
||||
segment = pdu[index++]; // >=0
|
||||
|
||||
//process WDP segment
|
||||
sourcePort = (0xFF & pdu[index++]) << 8;
|
||||
sourcePort |= 0xFF & pdu[index++];
|
||||
destinationPort = (0xFF & pdu[index++]) << 8;
|
||||
destinationPort |= 0xFF & pdu[index++];
|
||||
|
||||
// Lookup all other related parts
|
||||
StringBuilder where = new StringBuilder("reference_number =");
|
||||
where.append(referenceNumber);
|
||||
where.append(" AND address = ?");
|
||||
String[] whereArgs = new String[] {address};
|
||||
|
||||
Log.i(TAG, "Received WAP PDU. Type = " + msgType + ", originator = " + address
|
||||
+ ", src-port = " + sourcePort + ", dst-port = " + destinationPort
|
||||
+ ", ID = " + referenceNumber + ", segment# = " + segment + "/" + totalSegments);
|
||||
|
||||
byte[][] pdus = null;
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null);
|
||||
int cursorCount = cursor.getCount();
|
||||
if (cursorCount != totalSegments - 1) {
|
||||
// We don't have all the parts yet, store this one away
|
||||
ContentValues values = new ContentValues();
|
||||
values.put("date", new Long(0));
|
||||
values.put("pdu", HexDump.toHexString(pdu, index, pdu.length - index));
|
||||
values.put("address", address);
|
||||
values.put("reference_number", referenceNumber);
|
||||
values.put("count", totalSegments);
|
||||
values.put("sequence", segment);
|
||||
values.put("destination_port", destinationPort);
|
||||
|
||||
mResolver.insert(mRawUri, values);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// All the parts are in place, deal with them
|
||||
int pduColumn = cursor.getColumnIndex("pdu");
|
||||
int sequenceColumn = cursor.getColumnIndex("sequence");
|
||||
|
||||
pdus = new byte[totalSegments][];
|
||||
for (int i = 0; i < cursorCount; i++) {
|
||||
cursor.moveToNext();
|
||||
int cursorSequence = (int)cursor.getLong(sequenceColumn);
|
||||
pdus[cursorSequence] = HexDump.hexStringToByteArray(
|
||||
cursor.getString(pduColumn));
|
||||
}
|
||||
// The last part will be added later
|
||||
|
||||
// Remove the parts from the database
|
||||
mResolver.delete(mRawUri, where.toString(), whereArgs);
|
||||
} catch (SQLException e) {
|
||||
Log.e(TAG, "Can't access multipart SMS database", e);
|
||||
return; // TODO: NACK the message or something, don't just discard.
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
|
||||
// Build up the data stream
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
for (int i = 0; i < totalSegments-1; i++) {
|
||||
// reassemble the (WSP-)pdu
|
||||
output.write(pdus[i], 0, pdus[i].length);
|
||||
}
|
||||
|
||||
// This one isn't in the DB, so add it
|
||||
output.write(pdu, index, pdu.length - index);
|
||||
|
||||
byte[] datagram = output.toByteArray();
|
||||
// Dispatch the PDU to applications
|
||||
switch (destinationPort) {
|
||||
case SmsHeader.PORT_WAP_PUSH:
|
||||
// Handle the PUSH
|
||||
mWapPush.dispatchWapPdu(datagram);
|
||||
break;
|
||||
|
||||
default:{
|
||||
pdus = new byte[1][];
|
||||
pdus[0] = datagram;
|
||||
// The messages were sent to any other WAP port
|
||||
dispatchPortAddressedPdus(pdus, destinationPort);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void sendMultipartText(String destinationAddress, String scAddress,
|
||||
ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
|
||||
ArrayList<PendingIntent> deliveryIntents) {
|
||||
|
||||
int ref = ++sConcatenatedRef & 0xff;
|
||||
|
||||
for (int i = 0, count = parts.size(); i < count; i++) {
|
||||
// build SmsHeader data
|
||||
byte[] data = new byte[5];
|
||||
data[0] = (byte) SmsHeader.CONCATENATED_8_BIT_REFERENCE;
|
||||
data[1] = (byte) 3; // 3 bytes follow
|
||||
data[2] = (byte) ref; // reference #, unique per message
|
||||
data[3] = (byte) count; // total part count
|
||||
data[4] = (byte) (i + 1); // 1-based sequence
|
||||
|
||||
PendingIntent sentIntent = null;
|
||||
PendingIntent deliveryIntent = null;
|
||||
|
||||
if (sentIntents != null && sentIntents.size() > i) {
|
||||
sentIntent = sentIntents.get(i);
|
||||
}
|
||||
if (deliveryIntents != null && deliveryIntents.size() > i) {
|
||||
deliveryIntent = deliveryIntents.get(i);
|
||||
}
|
||||
|
||||
SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
|
||||
parts.get(i), deliveryIntent != null, data);
|
||||
|
||||
sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
|
||||
}
|
||||
}
|
||||
|
||||
protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
|
||||
PendingIntent deliveryIntent) {
|
||||
super.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void sendSms(SmsTracker tracker) {
|
||||
HashMap map = tracker.mData;
|
||||
|
||||
byte smsc[] = (byte[]) map.get("smsc");
|
||||
byte pdu[] = (byte[]) map.get("pdu");
|
||||
|
||||
Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
|
||||
|
||||
mCm.sendCdmaSms(pdu, reply);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void sendMultipartSms (SmsTracker tracker) {
|
||||
Log.d(TAG, "TODO: CdmaSMSDispatcher.sendMultipartSms not implemented");
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void acknowledgeLastIncomingSms(boolean success, Message response){
|
||||
// FIXME unit test leaves cm == null. this should change
|
||||
if (mCm != null) {
|
||||
mCm.acknowledgeLastIncomingCdmaSms(success, response);
|
||||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void activateCellBroadcastSms(int activate, Message response) {
|
||||
mCm.activateCdmaBroadcastSms(activate, response);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void getCellBroadcastSmsConfig(Message response) {
|
||||
mCm.getCdmaBroadcastConfig(response);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
protected void setCellBroadcastConfig(int[] configValuesArray, Message response) {
|
||||
mCm.setCdmaBroadcastConfig(configValuesArray, response);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.*;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.*;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
*
|
||||
* {@hide}
|
||||
*
|
||||
*/
|
||||
public final class FeatureCode extends Handler implements MmiCode {
|
||||
static final String LOG_TAG = "CDMA";
|
||||
|
||||
//***** Constants
|
||||
|
||||
// Call Forwarding
|
||||
static final String FC_CF_ACTIVATE = "72";
|
||||
static final String FC_CF_DEACTIVATE = "73";
|
||||
static final String FC_CF_FORWARD_TO_NUMBER = "56";
|
||||
|
||||
// Call Forwarding Busy Line
|
||||
static final String FC_CFBL_ACTIVATE = "90";
|
||||
static final String FC_CFBL_DEACTIVATE = "91";
|
||||
static final String FC_CFBL_FORWARD_TO_NUMBER = "40";
|
||||
|
||||
// Call Forwarding Don't Answer
|
||||
static final String FC_CFDA_ACTIVATE = "92";
|
||||
static final String FC_CFDA_DEACTIVATE = "93";
|
||||
static final String FC_CFDA_FORWARD_TO_NUMBER = "42";
|
||||
|
||||
// Cancel Call Waiting
|
||||
static final String FC_CCW = "70";
|
||||
|
||||
// Usage Sensitive Three-way Calling
|
||||
static final String FC_3WC = "71";
|
||||
|
||||
// Do Not Disturb
|
||||
static final String FC_DND_ACTIVATE = "78";
|
||||
static final String FC_DND_DEACTIVATE = "79";
|
||||
|
||||
// Who Called Me?
|
||||
static final String FC_WHO = "51";
|
||||
|
||||
// Rejection of Undesired Annoying Calls
|
||||
static final String FC_RUAC_ACTIVATE = "60";
|
||||
static final String FC_RUAC_DEACTIVATE = "80";
|
||||
|
||||
// Calling Number Delivery
|
||||
// Calling Number Identification Presentation
|
||||
static final String FC_CNIP = "65";
|
||||
// Calling Number Identification Restriction
|
||||
static final String FC_CNIR = "85";
|
||||
|
||||
|
||||
//***** Event Constants
|
||||
|
||||
static final int EVENT_SET_COMPLETE = 1;
|
||||
static final int EVENT_CDMA_FLASH_COMPLETED = 2;
|
||||
|
||||
|
||||
//***** Instance Variables
|
||||
|
||||
CDMAPhone phone;
|
||||
Context context;
|
||||
|
||||
String action; // '*' in CDMA
|
||||
String sc; // Service Code
|
||||
String poundString; // Entire Flash string
|
||||
String dialingNumber;
|
||||
|
||||
/** Set to true in processCode, not at newFromDialString time */
|
||||
|
||||
State state = State.PENDING;
|
||||
CharSequence message;
|
||||
|
||||
//***** Class Variables
|
||||
|
||||
|
||||
// Flash Code Pattern
|
||||
|
||||
static Pattern sPatternSuppService = Pattern.compile(
|
||||
"((\\*)(\\d{2,3})(#?)([^*#]*)?)(.*)");
|
||||
/* 1 2 3 4 5 6
|
||||
|
||||
1 = Full string up to and including #
|
||||
2 = action
|
||||
3 = service code
|
||||
4 = separator
|
||||
5 = dialing number
|
||||
*/
|
||||
|
||||
static final int MATCH_GROUP_POUND_STRING = 1;
|
||||
static final int MATCH_GROUP_ACTION_STRING = 2;
|
||||
static final int MATCH_GROUP_SERVICE_CODE = 3;
|
||||
static final int MATCH_GROUP_DIALING_NUMBER = 5;
|
||||
|
||||
|
||||
//***** Public Class methods
|
||||
|
||||
/**
|
||||
* Some dial strings in CDMA are defined to do non-call setup
|
||||
* things, such as set supplementary service settings (eg, call
|
||||
* forwarding). These are generally referred to as "Feature Codes".
|
||||
* We look to see if the dial string contains a valid Feature code (potentially
|
||||
* with a dial string at the end as well) and return info here.
|
||||
*
|
||||
* If the dial string contains no Feature code, we return an instance with
|
||||
* only "dialingNumber" set
|
||||
*
|
||||
* Please see also S.R0006-000-A v2.0 "Wireless Features Description"
|
||||
*/
|
||||
|
||||
static FeatureCode newFromDialString(String dialString, CDMAPhone phone) {
|
||||
Matcher m;
|
||||
FeatureCode ret = null;
|
||||
|
||||
m = sPatternSuppService.matcher(dialString);
|
||||
|
||||
// Is this formatted like a standard supplementary service code?
|
||||
if (m.matches()) {
|
||||
ret = new FeatureCode(phone);
|
||||
ret.poundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING));
|
||||
ret.action = makeEmptyNull(m.group(MATCH_GROUP_ACTION_STRING));
|
||||
ret.sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE));
|
||||
ret.dialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//***** Private Class methods
|
||||
|
||||
/** make empty strings be null.
|
||||
* Java regexp returns empty strings for empty groups
|
||||
*/
|
||||
private static String makeEmptyNull (String s) {
|
||||
if (s != null && s.length() == 0) return null;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/** returns true of the string is empty or null */
|
||||
private static boolean isEmptyOrNull(CharSequence s) {
|
||||
return s == null || (s.length() == 0);
|
||||
}
|
||||
|
||||
static boolean isServiceCodeCallForwarding(String sc) {
|
||||
return sc != null &&
|
||||
(sc.equals(FC_CF_ACTIVATE)
|
||||
|| sc.equals(FC_CF_DEACTIVATE) || sc.equals(FC_CF_FORWARD_TO_NUMBER)
|
||||
|| sc.equals(FC_CFBL_ACTIVATE) || sc.equals(FC_CFBL_DEACTIVATE)
|
||||
|| sc.equals(FC_CFBL_FORWARD_TO_NUMBER) || sc.equals(FC_CFDA_ACTIVATE)
|
||||
|| sc.equals(FC_CFDA_DEACTIVATE) || sc.equals(FC_CFDA_FORWARD_TO_NUMBER));
|
||||
}
|
||||
|
||||
static boolean isServiceCodeCallWaiting(String sc) {
|
||||
return sc != null && sc.equals(FC_CCW);
|
||||
}
|
||||
|
||||
static boolean isServiceCodeThreeWayCalling(String sc) {
|
||||
return sc != null && sc.equals(FC_3WC);
|
||||
}
|
||||
|
||||
static boolean isServiceCodeAnnoyingCalls(String sc) {
|
||||
return sc != null &&
|
||||
(sc.equals(FC_RUAC_ACTIVATE)
|
||||
|| sc.equals(FC_RUAC_DEACTIVATE));
|
||||
}
|
||||
|
||||
static boolean isServiceCodeCallingNumberDelivery(String sc) {
|
||||
return sc != null &&
|
||||
(sc.equals(FC_CNIP)
|
||||
|| sc.equals(FC_CNIR));
|
||||
}
|
||||
|
||||
static boolean isServiceCodeDoNotDisturb(String sc) {
|
||||
return sc != null &&
|
||||
(sc.equals(FC_DND_ACTIVATE)
|
||||
|| sc.equals(FC_DND_DEACTIVATE));
|
||||
}
|
||||
|
||||
|
||||
//***** Constructor
|
||||
|
||||
FeatureCode (CDMAPhone phone) {
|
||||
super(phone.getHandler().getLooper());
|
||||
this.phone = phone;
|
||||
this.context = phone.getContext();
|
||||
}
|
||||
|
||||
|
||||
//***** MmiCode implementation
|
||||
|
||||
public State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public CharSequence getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
// inherited javadoc suffices
|
||||
public void cancel() {
|
||||
//Not used here
|
||||
}
|
||||
|
||||
public boolean isCancelable() {
|
||||
Log.e(LOG_TAG, "isCancelable: not used in CDMA");
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isUssdRequest() {
|
||||
Log.e(LOG_TAG, "isUssdRequest: not used in CDMA");
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Process a Flash Code...anything that isn't a dialing number */
|
||||
void processCode () {
|
||||
Log.d(LOG_TAG, "send feature code...");
|
||||
phone.mCM.sendCDMAFeatureCode(this.poundString,
|
||||
obtainMessage(EVENT_CDMA_FLASH_COMPLETED));
|
||||
}
|
||||
|
||||
/** Called from CDMAPhone.handleMessage; not a Handler subclass */
|
||||
public void handleMessage (Message msg) {
|
||||
AsyncResult ar;
|
||||
|
||||
switch (msg.what) {
|
||||
case EVENT_SET_COMPLETE:
|
||||
ar = (AsyncResult) (msg.obj);
|
||||
onSetComplete(ar);
|
||||
break;
|
||||
case EVENT_CDMA_FLASH_COMPLETED:
|
||||
ar = (AsyncResult) (msg.obj);
|
||||
|
||||
if (ar.exception != null) {
|
||||
state = State.FAILED;
|
||||
message = context.getText(com.android.internal.R.string.mmiError);
|
||||
} else {
|
||||
state = State.COMPLETE;
|
||||
message = context.getText(com.android.internal.R.string.mmiComplete);
|
||||
}
|
||||
phone.onMMIDone(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//***** Private instance methods
|
||||
|
||||
private CharSequence getScString() {
|
||||
if (sc != null) {
|
||||
if (isServiceCodeCallForwarding(sc)) {
|
||||
return context.getText(com.android.internal.R.string.CfMmi);
|
||||
} else if (isServiceCodeCallWaiting(sc)) {
|
||||
return context.getText(com.android.internal.R.string.CwMmi);
|
||||
} else if (sc.equals(FC_CNIP)) {
|
||||
return context.getText(com.android.internal.R.string.CnipMmi);
|
||||
} else if (sc.equals(FC_CNIR)) {
|
||||
return context.getText(com.android.internal.R.string.CnirMmi);
|
||||
} else if (isServiceCodeThreeWayCalling(sc)) {
|
||||
return context.getText(com.android.internal.R.string.ThreeWCMmi);
|
||||
} else if (isServiceCodeAnnoyingCalls(sc)) {
|
||||
return context.getText(com.android.internal.R.string.RuacMmi);
|
||||
} else if (isServiceCodeCallingNumberDelivery(sc)) {
|
||||
return context.getText(com.android.internal.R.string.CndMmi);
|
||||
} else if (isServiceCodeDoNotDisturb(sc)) {
|
||||
return context.getText(com.android.internal.R.string.DndMmi);
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private void onSetComplete(AsyncResult ar){
|
||||
StringBuilder sb = new StringBuilder(getScString());
|
||||
sb.append("\n");
|
||||
|
||||
if (ar.exception != null) {
|
||||
state = State.FAILED;
|
||||
sb.append(context.getText(com.android.internal.R.string.mmiError));
|
||||
} else {
|
||||
state = State.FAILED;
|
||||
sb.append(context.getText(com.android.internal.R.string.mmiError));
|
||||
}
|
||||
|
||||
message = sb;
|
||||
phone.onMMIDone(this);
|
||||
}
|
||||
}
|
||||
522
telephony/java/com/android/internal/telephony/cdma/RuimCard.java
Normal file
522
telephony/java/com/android/internal/telephony/cdma/RuimCard.java
Normal file
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Registrant;
|
||||
import android.os.RegistrantList;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.CommandsInterface;
|
||||
import com.android.internal.telephony.IccCard;
|
||||
import com.android.internal.telephony.Phone;
|
||||
import com.android.internal.telephony.PhoneProxy;
|
||||
import com.android.internal.telephony.TelephonyIntents;
|
||||
import com.android.internal.telephony.TelephonyProperties;
|
||||
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
|
||||
import static android.Manifest.permission.READ_PHONE_STATE;
|
||||
|
||||
/**
|
||||
* Note: this class shares common code with SimCard, consider a base class to minimize code
|
||||
* duplication.
|
||||
* {@hide}
|
||||
*/
|
||||
public final class RuimCard extends Handler implements IccCard {
|
||||
static final String LOG_TAG="CDMA";
|
||||
|
||||
//***** Instance Variables
|
||||
private static final boolean DBG = true;
|
||||
|
||||
private CDMAPhone phone;
|
||||
|
||||
private CommandsInterface.IccStatus status = null;
|
||||
private boolean mDesiredPinLocked;
|
||||
private boolean mDesiredFdnEnabled;
|
||||
private boolean mRuimPinLocked = true; // default to locked
|
||||
private boolean mRuimFdnEnabled = false; // Default to disabled.
|
||||
// Will be updated when RUIM_READY.
|
||||
// //***** Constants
|
||||
|
||||
// // FIXME I hope this doesn't conflict with the Dialer's notifications
|
||||
// Nobody is using this at the moment
|
||||
// static final int NOTIFICATION_ID_ICC_STATUS = 33456;
|
||||
|
||||
//***** Event Constants
|
||||
|
||||
static final int EVENT_RUIM_LOCKED_OR_ABSENT = 1;
|
||||
static final int EVENT_GET_RUIM_STATUS_DONE = 2;
|
||||
static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 3;
|
||||
static final int EVENT_PINPUK_DONE = 4;
|
||||
static final int EVENT_REPOLL_STATUS_DONE = 5;
|
||||
static final int EVENT_RUIM_READY = 6;
|
||||
static final int EVENT_QUERY_FACILITY_LOCK_DONE = 7;
|
||||
static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 8;
|
||||
static final int EVENT_CHANGE_RUIM_PASSWORD_DONE = 9;
|
||||
static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
|
||||
static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
|
||||
|
||||
|
||||
//***** Constructor
|
||||
|
||||
RuimCard(CDMAPhone phone) {
|
||||
this.phone = phone;
|
||||
|
||||
phone.mCM.registerForRUIMLockedOrAbsent(
|
||||
this, EVENT_RUIM_LOCKED_OR_ABSENT, null);
|
||||
|
||||
phone.mCM.registerForOffOrNotAvailable(
|
||||
this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
|
||||
|
||||
phone.mCM.registerForRUIMReady(
|
||||
this, EVENT_RUIM_READY, null);
|
||||
|
||||
updateStateProperty();
|
||||
}
|
||||
|
||||
//***** RuimCard implementation
|
||||
|
||||
public State
|
||||
getState() {
|
||||
if (status == null) {
|
||||
switch(phone.mCM.getRadioState()) {
|
||||
/* This switch block must not return anything in
|
||||
* State.isLocked() or State.ABSENT.
|
||||
* If it does, handleSimStatus() may break
|
||||
*/
|
||||
case RADIO_OFF:
|
||||
case RADIO_UNAVAILABLE:
|
||||
case RUIM_NOT_READY:
|
||||
return State.UNKNOWN;
|
||||
case RUIM_LOCKED_OR_ABSENT:
|
||||
//this should be transient-only
|
||||
return State.UNKNOWN;
|
||||
case RUIM_READY:
|
||||
return State.READY;
|
||||
case NV_READY:
|
||||
case NV_NOT_READY:
|
||||
return State.ABSENT;
|
||||
}
|
||||
} else {
|
||||
switch (status) {
|
||||
case ICC_ABSENT: return State.ABSENT;
|
||||
case ICC_NOT_READY: return State.UNKNOWN;
|
||||
case ICC_READY: return State.READY;
|
||||
case ICC_PIN: return State.PIN_REQUIRED;
|
||||
case ICC_PUK: return State.PUK_REQUIRED;
|
||||
case ICC_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED;
|
||||
}
|
||||
}
|
||||
|
||||
Log.e(LOG_TAG, "RuimCard.getState(): case should never be reached");
|
||||
return State.UNKNOWN;
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
//Unregister for all events
|
||||
phone.mCM.unregisterForRUIMLockedOrAbsent(this);
|
||||
phone.mCM.unregisterForOffOrNotAvailable(this);
|
||||
phone.mCM.unregisterForRUIMReady(this);
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if(DBG) Log.d(LOG_TAG, "RuimCard finalized");
|
||||
}
|
||||
|
||||
private RegistrantList absentRegistrants = new RegistrantList();
|
||||
private RegistrantList pinLockedRegistrants = new RegistrantList();
|
||||
private RegistrantList networkLockedRegistrants = new RegistrantList();
|
||||
|
||||
|
||||
public void registerForAbsent(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
absentRegistrants.add(r);
|
||||
|
||||
if (getState() == State.ABSENT) {
|
||||
r.notifyRegistrant();
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForAbsent(Handler h) {
|
||||
absentRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void registerForNetworkLocked(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
networkLockedRegistrants.add(r);
|
||||
|
||||
if (getState() == State.NETWORK_LOCKED) {
|
||||
r.notifyRegistrant();
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForNetworkLocked(Handler h) {
|
||||
networkLockedRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void registerForLocked(Handler h, int what, Object obj) {
|
||||
Registrant r = new Registrant (h, what, obj);
|
||||
|
||||
pinLockedRegistrants.add(r);
|
||||
|
||||
if (getState().isPinLocked()) {
|
||||
r.notifyRegistrant();
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterForLocked(Handler h) {
|
||||
pinLockedRegistrants.remove(h);
|
||||
}
|
||||
|
||||
public void supplyPin (String pin, Message onComplete) {
|
||||
phone.mCM.supplyIccPin(pin, obtainMessage(EVENT_PINPUK_DONE, onComplete));
|
||||
}
|
||||
|
||||
public void supplyPuk (String puk, String newPin, Message onComplete) {
|
||||
phone.mCM.supplyIccPuk(puk, newPin, obtainMessage(EVENT_PINPUK_DONE, onComplete));
|
||||
}
|
||||
|
||||
public void supplyPin2 (String pin2, Message onComplete) {
|
||||
phone.mCM.supplyIccPin2(pin2, obtainMessage(EVENT_PINPUK_DONE, onComplete));
|
||||
}
|
||||
|
||||
public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
|
||||
phone.mCM.supplyIccPuk2(puk2, newPin2, obtainMessage(EVENT_PINPUK_DONE, onComplete));
|
||||
}
|
||||
|
||||
public void supplyNetworkDepersonalization (String pin, Message onComplete) {
|
||||
if(DBG) log("Network Despersonalization: " + pin);
|
||||
phone.mCM.supplyNetworkDepersonalization(pin,
|
||||
obtainMessage(EVENT_PINPUK_DONE, onComplete));
|
||||
}
|
||||
|
||||
public boolean getIccLockEnabled() {
|
||||
return mRuimPinLocked;
|
||||
}
|
||||
|
||||
public boolean getIccFdnEnabled() {
|
||||
return mRuimFdnEnabled;
|
||||
}
|
||||
|
||||
public void setIccLockEnabled (boolean enabled,
|
||||
String password, Message onComplete) {
|
||||
int serviceClassX;
|
||||
serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
|
||||
CommandsInterface.SERVICE_CLASS_DATA +
|
||||
CommandsInterface.SERVICE_CLASS_FAX;
|
||||
|
||||
mDesiredPinLocked = enabled;
|
||||
|
||||
phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_SIM,
|
||||
enabled, password, serviceClassX,
|
||||
obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
|
||||
}
|
||||
|
||||
public void setIccFdnEnabled (boolean enabled,
|
||||
String password, Message onComplete) {
|
||||
int serviceClassX;
|
||||
serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
|
||||
CommandsInterface.SERVICE_CLASS_DATA +
|
||||
CommandsInterface.SERVICE_CLASS_FAX +
|
||||
CommandsInterface.SERVICE_CLASS_SMS;
|
||||
|
||||
mDesiredFdnEnabled = enabled;
|
||||
|
||||
phone.mCM.setFacilityLock(CommandsInterface.CB_FACILITY_BA_FD,
|
||||
enabled, password, serviceClassX,
|
||||
obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
|
||||
}
|
||||
|
||||
public void changeIccLockPassword(String oldPassword, String newPassword,
|
||||
Message onComplete) {
|
||||
if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
|
||||
phone.mCM.changeIccPin(oldPassword, newPassword,
|
||||
obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete));
|
||||
}
|
||||
|
||||
public void changeIccFdnPassword(String oldPassword, String newPassword,
|
||||
Message onComplete) {
|
||||
if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
|
||||
phone.mCM.changeIccPin2(oldPassword, newPassword,
|
||||
obtainMessage(EVENT_CHANGE_RUIM_PASSWORD_DONE, onComplete));
|
||||
}
|
||||
|
||||
public String getServiceProviderName() {
|
||||
return phone.mRuimRecords.getServiceProviderName();
|
||||
}
|
||||
|
||||
//***** Handler implementation
|
||||
@Override
|
||||
public void handleMessage(Message msg){
|
||||
AsyncResult ar;
|
||||
int serviceClassX;
|
||||
|
||||
serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
|
||||
CommandsInterface.SERVICE_CLASS_DATA +
|
||||
CommandsInterface.SERVICE_CLASS_FAX;
|
||||
|
||||
switch (msg.what) {
|
||||
case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
|
||||
Log.d(LOG_TAG, "Event EVENT_RADIO_OFF_OR_NOT_AVAILABLE Received");
|
||||
status = null;
|
||||
updateStateProperty();
|
||||
broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_NOT_READY, null);
|
||||
break;
|
||||
case EVENT_RUIM_READY:
|
||||
Log.d(LOG_TAG, "Event EVENT_RUIM_READY Received");
|
||||
//TODO: put facility read in SIM_READY now, maybe in REG_NW
|
||||
phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE));
|
||||
phone.mCM.queryFacilityLock (
|
||||
CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
|
||||
obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
|
||||
phone.mCM.queryFacilityLock (
|
||||
CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
|
||||
obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
|
||||
break;
|
||||
case EVENT_RUIM_LOCKED_OR_ABSENT:
|
||||
Log.d(LOG_TAG, "Event EVENT_RUIM_LOCKED_OR_ABSENT Received");
|
||||
phone.mCM.getIccStatus(obtainMessage(EVENT_GET_RUIM_STATUS_DONE));
|
||||
phone.mCM.queryFacilityLock (
|
||||
CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
|
||||
obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
|
||||
break;
|
||||
case EVENT_GET_RUIM_STATUS_DONE:
|
||||
Log.d(LOG_TAG, "Event EVENT_GET_RUIM_STATUS_DONE Received");
|
||||
ar = (AsyncResult)msg.obj;
|
||||
|
||||
getRuimStatusDone(ar);
|
||||
break;
|
||||
case EVENT_PINPUK_DONE:
|
||||
Log.d(LOG_TAG, "Event EVENT_PINPUK_DONE Received");
|
||||
// a PIN/PUK/PIN2/PUK2/Network Personalization
|
||||
// request has completed. ar.userObj is the response Message
|
||||
// Repoll before returning
|
||||
ar = (AsyncResult)msg.obj;
|
||||
// TODO should abstract these exceptions
|
||||
AsyncResult.forMessage(((Message)ar.userObj)).exception
|
||||
= ar.exception;
|
||||
phone.mCM.getIccStatus(
|
||||
obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
|
||||
break;
|
||||
case EVENT_REPOLL_STATUS_DONE:
|
||||
Log.d(LOG_TAG, "Event EVENT_REPOLL_STATUS_DONE Received");
|
||||
// Finished repolling status after PIN operation
|
||||
// ar.userObj is the response messaeg
|
||||
// ar.userObj.obj is already an AsyncResult with an
|
||||
// appropriate exception filled in if applicable
|
||||
|
||||
ar = (AsyncResult)msg.obj;
|
||||
getRuimStatusDone(ar);
|
||||
((Message)ar.userObj).sendToTarget();
|
||||
break;
|
||||
case EVENT_QUERY_FACILITY_LOCK_DONE:
|
||||
Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_LOCK_DONE Received");
|
||||
ar = (AsyncResult)msg.obj;
|
||||
onQueryFacilityLock(ar);
|
||||
break;
|
||||
case EVENT_QUERY_FACILITY_FDN_DONE:
|
||||
Log.d(LOG_TAG, "Event EVENT_QUERY_FACILITY_FDN_DONE Received");
|
||||
ar = (AsyncResult)msg.obj;
|
||||
onQueryFdnEnabled(ar);
|
||||
break;
|
||||
case EVENT_CHANGE_FACILITY_LOCK_DONE:
|
||||
Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_LOCK_DONE Received");
|
||||
ar = (AsyncResult)msg.obj;
|
||||
if (ar.exception == null) {
|
||||
mRuimPinLocked = mDesiredPinLocked;
|
||||
if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
|
||||
"mRuimPinLocked= " + mRuimPinLocked);
|
||||
} else {
|
||||
Log.e(LOG_TAG, "Error change facility lock with exception "
|
||||
+ ar.exception);
|
||||
}
|
||||
AsyncResult.forMessage(((Message)ar.userObj)).exception
|
||||
= ar.exception;
|
||||
((Message)ar.userObj).sendToTarget();
|
||||
break;
|
||||
case EVENT_CHANGE_FACILITY_FDN_DONE:
|
||||
Log.d(LOG_TAG, "Event EVENT_CHANGE_FACILITY_FDN_DONE Received");
|
||||
ar = (AsyncResult)msg.obj;
|
||||
|
||||
if (ar.exception == null) {
|
||||
mRuimFdnEnabled = mDesiredFdnEnabled;
|
||||
if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
|
||||
"mRuimFdnEnabled=" + mRuimFdnEnabled);
|
||||
} else {
|
||||
Log.e(LOG_TAG, "Error change facility fdn with exception "
|
||||
+ ar.exception);
|
||||
}
|
||||
AsyncResult.forMessage(((Message)ar.userObj)).exception
|
||||
= ar.exception;
|
||||
((Message)ar.userObj).sendToTarget();
|
||||
break;
|
||||
case EVENT_CHANGE_RUIM_PASSWORD_DONE:
|
||||
Log.d(LOG_TAG, "Event EVENT_CHANGE_RUIM_PASSWORD_DONE Received");
|
||||
ar = (AsyncResult)msg.obj;
|
||||
if(ar.exception != null) {
|
||||
Log.e(LOG_TAG, "Error in change sim password with exception"
|
||||
+ ar.exception);
|
||||
}
|
||||
AsyncResult.forMessage(((Message)ar.userObj)).exception
|
||||
= ar.exception;
|
||||
((Message)ar.userObj).sendToTarget();
|
||||
break;
|
||||
default:
|
||||
Log.e(LOG_TAG, "[CdmaRuimCard] Unknown Event " + msg.what);
|
||||
}
|
||||
}
|
||||
|
||||
//***** Private methods
|
||||
|
||||
/**
|
||||
* Interpret EVENT_QUERY_FACILITY_LOCK_DONE
|
||||
* @param ar is asyncResult of Query_Facility_Locked
|
||||
*/
|
||||
private void onQueryFacilityLock(AsyncResult ar) {
|
||||
if(ar.exception != null) {
|
||||
if (DBG) log("Error in querying facility lock:" + ar.exception);
|
||||
return;
|
||||
}
|
||||
|
||||
int[] ints = (int[])ar.result;
|
||||
if(ints.length != 0) {
|
||||
mRuimPinLocked = (0!=ints[0]);
|
||||
if(DBG) log("Query facility lock : " + mRuimPinLocked);
|
||||
} else {
|
||||
Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interpret EVENT_QUERY_FACILITY_LOCK_DONE
|
||||
* @param ar is asyncResult of Query_Facility_Locked
|
||||
*/
|
||||
private void onQueryFdnEnabled(AsyncResult ar) {
|
||||
if(ar.exception != null) {
|
||||
if(DBG) log("Error in querying facility lock:" + ar.exception);
|
||||
return;
|
||||
}
|
||||
|
||||
int[] ints = (int[])ar.result;
|
||||
if(ints.length != 0) {
|
||||
mRuimFdnEnabled = (0!=ints[0]);
|
||||
if(DBG) log("Query facility lock : " + mRuimFdnEnabled);
|
||||
} else {
|
||||
Log.e(LOG_TAG, "[CdmaRuimCard] Bogus facility lock response");
|
||||
}
|
||||
}
|
||||
|
||||
private void
|
||||
getRuimStatusDone(AsyncResult ar) {
|
||||
if (ar.exception != null) {
|
||||
Log.e(LOG_TAG,"Error getting SIM status. "
|
||||
+ "RIL_REQUEST_GET_SIM_STATUS should "
|
||||
+ "never return an error", ar.exception);
|
||||
return;
|
||||
}
|
||||
|
||||
CommandsInterface.IccStatus newStatus
|
||||
= (CommandsInterface.IccStatus) ar.result;
|
||||
|
||||
handleRuimStatus(newStatus);
|
||||
}
|
||||
|
||||
private void
|
||||
handleRuimStatus(CommandsInterface.IccStatus newStatus) {
|
||||
boolean transitionedIntoPinLocked;
|
||||
boolean transitionedIntoAbsent;
|
||||
boolean transitionedIntoNetworkLocked;
|
||||
|
||||
RuimCard.State oldState, newState;
|
||||
|
||||
oldState = getState();
|
||||
status = newStatus;
|
||||
newState = getState();
|
||||
|
||||
updateStateProperty();
|
||||
|
||||
transitionedIntoPinLocked = (
|
||||
(oldState != State.PIN_REQUIRED && newState == State.PIN_REQUIRED)
|
||||
|| (oldState != State.PUK_REQUIRED && newState == State.PUK_REQUIRED));
|
||||
transitionedIntoAbsent = (oldState != State.ABSENT && newState == State.ABSENT);
|
||||
transitionedIntoNetworkLocked = (oldState != State.NETWORK_LOCKED
|
||||
&& newState == State.NETWORK_LOCKED);
|
||||
|
||||
if (transitionedIntoPinLocked) {
|
||||
if(DBG) log("Notify RUIM pin or puk locked.");
|
||||
pinLockedRegistrants.notifyRegistrants();
|
||||
broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED,
|
||||
(newState == State.PIN_REQUIRED) ?
|
||||
INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
|
||||
} else if (transitionedIntoAbsent) {
|
||||
if(DBG) log("Notify RUIM missing.");
|
||||
absentRegistrants.notifyRegistrants();
|
||||
broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_ABSENT, null);
|
||||
} else if (transitionedIntoNetworkLocked) {
|
||||
if(DBG) log("Notify RUIM network locked.");
|
||||
networkLockedRegistrants.notifyRegistrants();
|
||||
broadcastRuimStateChangedIntent(RuimCard.INTENT_VALUE_ICC_LOCKED,
|
||||
INTENT_VALUE_LOCKED_NETWORK);
|
||||
}
|
||||
}
|
||||
|
||||
public void broadcastRuimStateChangedIntent(String value, String reason) {
|
||||
Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
|
||||
intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName());
|
||||
intent.putExtra(RuimCard.INTENT_KEY_ICC_STATE, value);
|
||||
intent.putExtra(RuimCard.INTENT_KEY_LOCKED_REASON, reason);
|
||||
if(DBG) log("Broadcasting intent SIM_STATE_CHANGED_ACTION " + value
|
||||
+ " reason " + reason);
|
||||
ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE);
|
||||
}
|
||||
|
||||
public void updateImsiConfiguration(String imsi) {
|
||||
if (imsi.length() >= 6) {
|
||||
Configuration config = new Configuration();
|
||||
config.mcc = ((imsi.charAt(0)-'0')*100)
|
||||
+ ((imsi.charAt(1)-'0')*10)
|
||||
+ (imsi.charAt(2)-'0');
|
||||
config.mnc = ((imsi.charAt(3)-'0')*100)
|
||||
+ ((imsi.charAt(4)-'0')*10)
|
||||
+ (imsi.charAt(5)-'0');
|
||||
try {
|
||||
ActivityManagerNative.getDefault().updateConfiguration(config);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void
|
||||
updateStateProperty() {
|
||||
phone.setSystemProperty(
|
||||
TelephonyProperties.PROPERTY_SIM_STATE,
|
||||
getState().toString());
|
||||
}
|
||||
|
||||
private void log(String msg) {
|
||||
Log.d(LOG_TAG, "[RuimCard] " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.os.*;
|
||||
import android.os.AsyncResult;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.IccConstants;
|
||||
import com.android.internal.telephony.IccException;
|
||||
import com.android.internal.telephony.IccFileHandler;
|
||||
import com.android.internal.telephony.IccFileTypeMismatch;
|
||||
import com.android.internal.telephony.IccIoResult;
|
||||
import com.android.internal.telephony.IccUtils;
|
||||
import com.android.internal.telephony.PhoneProxy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public final class RuimFileHandler extends IccFileHandler {
|
||||
static final String LOG_TAG = "CDMA";
|
||||
|
||||
//***** Instance Variables
|
||||
|
||||
//***** Constructor
|
||||
RuimFileHandler(CDMAPhone phone) {
|
||||
super(phone);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
Log.d(LOG_TAG, "RuimFileHandler finalized");
|
||||
}
|
||||
|
||||
//***** Overridden from IccFileHandler
|
||||
|
||||
@Override
|
||||
public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset,
|
||||
int length, Message onLoaded) {
|
||||
Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
|
||||
onLoaded);
|
||||
|
||||
phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, "img", 0, 0,
|
||||
GET_RESPONSE_EF_IMG_SIZE_BYTES, null, null, response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
|
||||
super.handleMessage(msg);
|
||||
}
|
||||
|
||||
protected void logd(String msg) {
|
||||
Log.d(LOG_TAG, "[RuimFileHandler] " + msg);
|
||||
}
|
||||
|
||||
protected void loge(String msg) {
|
||||
Log.e(LOG_TAG, "[RuimFileHandler] " + msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
** Copyright 2007, The Android Open Source Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.ServiceManager;
|
||||
import android.telephony.PhoneNumberUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.AdnRecord;
|
||||
import com.android.internal.telephony.AdnRecordCache;
|
||||
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
|
||||
import com.android.internal.telephony.PhoneProxy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* RuimPhoneBookInterfaceManager to provide an inter-process communication to
|
||||
* access ADN-like SIM records.
|
||||
*/
|
||||
|
||||
|
||||
public class RuimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager {
|
||||
static final String LOG_TAG = "CDMA";
|
||||
|
||||
|
||||
Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
AsyncResult ar;
|
||||
|
||||
switch(msg.what) {
|
||||
default:
|
||||
mBaseHandler.handleMessage(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public RuimPhoneBookInterfaceManager(CDMAPhone phone) {
|
||||
super(phone);
|
||||
adnCache = phone.mRuimRecords.getAdnCache();
|
||||
//NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if(DBG) Log.d(LOG_TAG, "RuimPhoneBookInterfaceManager finalized");
|
||||
}
|
||||
|
||||
public int[] getAdnRecordsSize(int efid) {
|
||||
if (DBG) logd("getAdnRecordsSize: efid=" + efid);
|
||||
synchronized(mLock) {
|
||||
checkThread();
|
||||
recordSize = new int[3];
|
||||
|
||||
//Using mBaseHandler, no difference in EVENT_GET_SIZE_DONE handling
|
||||
Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE);
|
||||
|
||||
phone.getIccFileHandler().getEFLinearRecordSize(efid, response);
|
||||
try {
|
||||
mLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
logd("interrupted while trying to load from the RUIM");
|
||||
}
|
||||
}
|
||||
|
||||
return recordSize;
|
||||
}
|
||||
|
||||
protected void logd(String msg) {
|
||||
Log.d(LOG_TAG, "[RuimPbInterfaceManager] " + msg);
|
||||
}
|
||||
|
||||
protected void loge(String msg) {
|
||||
Log.e(LOG_TAG, "[RuimPbInterfaceManager] " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
|
||||
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.Registrant;
|
||||
import android.util.Log;
|
||||
|
||||
import static com.android.internal.telephony.TelephonyProperties.*;
|
||||
import com.android.internal.telephony.AdnRecord;
|
||||
import com.android.internal.telephony.AdnRecordCache;
|
||||
import com.android.internal.telephony.AdnRecordLoader;
|
||||
import com.android.internal.telephony.CommandsInterface;
|
||||
import com.android.internal.telephony.cdma.RuimCard;
|
||||
import com.android.internal.telephony.gsm.MccTable;
|
||||
|
||||
// can't be used since VoiceMailConstants is not public
|
||||
//import com.android.internal.telephony.gsm.VoiceMailConstants;
|
||||
import com.android.internal.telephony.IccException;
|
||||
import com.android.internal.telephony.IccRecords;
|
||||
import com.android.internal.telephony.IccUtils;
|
||||
import com.android.internal.telephony.PhoneProxy;
|
||||
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public final class RuimRecords extends IccRecords {
|
||||
static final String LOG_TAG = "CDMA";
|
||||
|
||||
private static final boolean DBG = true;
|
||||
|
||||
//***** Instance Variables
|
||||
String imsi_m;
|
||||
String mdn = null; // My mobile number
|
||||
String h_sid;
|
||||
String h_nid;
|
||||
|
||||
// is not initialized
|
||||
|
||||
//***** Event Constants
|
||||
|
||||
private static final int EVENT_RUIM_READY = 1;
|
||||
private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
|
||||
private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4;
|
||||
private static final int EVENT_GET_ICCID_DONE = 5;
|
||||
private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10;
|
||||
private static final int EVENT_UPDATE_DONE = 14;
|
||||
private static final int EVENT_GET_SST_DONE = 17;
|
||||
private static final int EVENT_GET_ALL_SMS_DONE = 18;
|
||||
private static final int EVENT_MARK_SMS_READ_DONE = 19;
|
||||
|
||||
private static final int EVENT_SMS_ON_RUIM = 21;
|
||||
private static final int EVENT_GET_SMS_DONE = 22;
|
||||
|
||||
private static final int EVENT_RUIM_REFRESH = 31;
|
||||
|
||||
//***** Constructor
|
||||
|
||||
RuimRecords(CDMAPhone p) {
|
||||
super(p);
|
||||
|
||||
adnCache = new AdnRecordCache(phone);
|
||||
|
||||
recordsRequested = false; // No load request is made till SIM ready
|
||||
|
||||
// recordsToLoad is set to 0 because no requests are made yet
|
||||
recordsToLoad = 0;
|
||||
|
||||
|
||||
p.mCM.registerForRUIMReady(this, EVENT_RUIM_READY, null);
|
||||
p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
|
||||
// NOTE the EVENT_SMS_ON_RUIM is not registered
|
||||
p.mCM.setOnIccRefresh(this, EVENT_RUIM_REFRESH, null);
|
||||
|
||||
// Start off by setting empty state
|
||||
onRadioOffOrNotAvailable();
|
||||
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
//Unregister for all events
|
||||
phone.mCM.unregisterForRUIMReady(this);
|
||||
phone.mCM.unregisterForOffOrNotAvailable( this);
|
||||
phone.mCM.unSetOnIccRefresh(this);
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if(DBG) Log.d(LOG_TAG, "RuimRecords finalized");
|
||||
}
|
||||
|
||||
protected void onRadioOffOrNotAvailable() {
|
||||
countVoiceMessages = 0;
|
||||
mncLength = 0;
|
||||
iccid = null;
|
||||
|
||||
adnCache.reset();
|
||||
|
||||
phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null);
|
||||
phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null);
|
||||
|
||||
// recordsRequested is set to false indicating that the SIM
|
||||
// read requests made so far are not valid. This is set to
|
||||
// true only when fresh set of read requests are made.
|
||||
recordsRequested = false;
|
||||
}
|
||||
|
||||
//***** Public Methods
|
||||
|
||||
/** Returns null if RUIM is not yet ready */
|
||||
public String getIMSI_M() {
|
||||
return imsi_m;
|
||||
}
|
||||
|
||||
public String getMdnNumber() {
|
||||
return mdn;
|
||||
}
|
||||
|
||||
public void setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete){
|
||||
// In CDMA this is Operator/OEM dependent
|
||||
AsyncResult.forMessage((onComplete)).exception =
|
||||
new IccException("setVoiceMailNumber not implemented");
|
||||
onComplete.sendToTarget();
|
||||
Log.e(LOG_TAG, "method setVoiceMailNumber is not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by CCAT Service when REFRESH is received.
|
||||
* @param fileChanged indicates whether any files changed
|
||||
* @param fileList if non-null, a list of EF files that changed
|
||||
*/
|
||||
public void onRefresh(boolean fileChanged, int[] fileList) {
|
||||
if (fileChanged) {
|
||||
// A future optimization would be to inspect fileList and
|
||||
// only reload those files that we care about. For now,
|
||||
// just re-fetch all RUIM records that we cache.
|
||||
fetchRuimRecords();
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the 5 or 6 digit MCC/MNC of the operator that
|
||||
* provided the RUIM card. Returns null of RUIM is not yet ready
|
||||
*/
|
||||
String getRUIMOperatorNumeric() {
|
||||
if (imsi_m == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (mncLength != 0) {
|
||||
// Length = length of MCC + length of MNC
|
||||
// TODO: change spec name
|
||||
// length of mcc = 3 (3GPP2 C.S0005 - Section 2.3)
|
||||
return imsi_m.substring(0, 3 + mncLength);
|
||||
}
|
||||
|
||||
// Guess the MNC length based on the MCC if we don't
|
||||
// have a valid value in ef[ad]
|
||||
|
||||
int mcc;
|
||||
|
||||
mcc = Integer.parseInt(imsi_m.substring(0,3));
|
||||
|
||||
return imsi_m.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
|
||||
}
|
||||
|
||||
//***** Overridden from Handler
|
||||
public void handleMessage(Message msg) {
|
||||
AsyncResult ar;
|
||||
|
||||
byte data[];
|
||||
|
||||
boolean isRecordLoadResponse = false;
|
||||
|
||||
try { switch (msg.what) {
|
||||
case EVENT_RUIM_READY:
|
||||
onRuimReady();
|
||||
break;
|
||||
|
||||
case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
|
||||
onRadioOffOrNotAvailable();
|
||||
break;
|
||||
|
||||
case EVENT_GET_DEVICE_IDENTITY_DONE:
|
||||
Log.d(LOG_TAG, "Event EVENT_GET_DEVICE_IDENTITY_DONE Received");
|
||||
break;
|
||||
|
||||
/* IO events */
|
||||
|
||||
case EVENT_GET_CDMA_SUBSCRIPTION_DONE:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
String localTemp[] = (String[])ar.result;
|
||||
if (ar.exception != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
mdn = localTemp[0];
|
||||
h_sid = localTemp[1];
|
||||
h_nid = localTemp[2];
|
||||
|
||||
Log.d(LOG_TAG, "MDN: " + mdn);
|
||||
|
||||
break;
|
||||
|
||||
case EVENT_GET_ICCID_DONE:
|
||||
isRecordLoadResponse = true;
|
||||
|
||||
ar = (AsyncResult)msg.obj;
|
||||
data = (byte[])ar.result;
|
||||
|
||||
if (ar.exception != null) {
|
||||
break;
|
||||
}
|
||||
|
||||
iccid = IccUtils.bcdToString(data, 0, data.length);
|
||||
|
||||
Log.d(LOG_TAG, "iccid: " + iccid);
|
||||
|
||||
break;
|
||||
|
||||
case EVENT_UPDATE_DONE:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
if (ar.exception != null) {
|
||||
Log.i(LOG_TAG, "RuimRecords update failed", ar.exception);
|
||||
}
|
||||
break;
|
||||
|
||||
case EVENT_GET_ALL_SMS_DONE:
|
||||
case EVENT_MARK_SMS_READ_DONE:
|
||||
case EVENT_SMS_ON_RUIM:
|
||||
case EVENT_GET_SMS_DONE:
|
||||
Log.w(LOG_TAG, "Event not supported: " + msg.what);
|
||||
break;
|
||||
|
||||
// TODO: probably EF_CST should be read instead
|
||||
case EVENT_GET_SST_DONE:
|
||||
Log.d(LOG_TAG, "Event EVENT_GET_SST_DONE Received");
|
||||
break;
|
||||
|
||||
case EVENT_RUIM_REFRESH:
|
||||
isRecordLoadResponse = false;
|
||||
ar = (AsyncResult)msg.obj;
|
||||
if (ar.exception == null) {
|
||||
handleRuimRefresh((int[])(ar.result));
|
||||
}
|
||||
break;
|
||||
|
||||
}}catch (RuntimeException exc) {
|
||||
// I don't want these exceptions to be fatal
|
||||
Log.w(LOG_TAG, "Exception parsing RUIM record", exc);
|
||||
} finally {
|
||||
// Count up record load responses even if they are fails
|
||||
if (isRecordLoadResponse) {
|
||||
onRecordLoaded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onRecordLoaded() {
|
||||
// One record loaded successfully or failed, In either case
|
||||
// we need to update the recordsToLoad count
|
||||
recordsToLoad -= 1;
|
||||
|
||||
if (recordsToLoad == 0 && recordsRequested == true) {
|
||||
onAllRecordsLoaded();
|
||||
} else if (recordsToLoad < 0) {
|
||||
Log.e(LOG_TAG, "RuimRecords: recordsToLoad <0, programmer error suspected");
|
||||
recordsToLoad = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected void onAllRecordsLoaded() {
|
||||
Log.d(LOG_TAG, "RuimRecords: record load complete");
|
||||
|
||||
// Further records that can be inserted are Operator/OEM dependent
|
||||
|
||||
recordsLoadedRegistrants.notifyRegistrants(
|
||||
new AsyncResult(null, null, null));
|
||||
((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent(
|
||||
RuimCard.INTENT_VALUE_ICC_LOADED, null);
|
||||
}
|
||||
|
||||
|
||||
//***** Private Methods
|
||||
|
||||
private void onRuimReady() {
|
||||
/* broadcast intent ICC_READY here so that we can make sure
|
||||
READY is sent before IMSI ready
|
||||
*/
|
||||
|
||||
((CDMAPhone) phone).mRuimCard.broadcastRuimStateChangedIntent(
|
||||
RuimCard.INTENT_VALUE_ICC_READY, null);
|
||||
|
||||
fetchRuimRecords();
|
||||
|
||||
phone.mCM.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE));
|
||||
|
||||
}
|
||||
|
||||
private void fetchRuimRecords() {
|
||||
recordsRequested = true;
|
||||
|
||||
Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad);
|
||||
|
||||
phone.getIccFileHandler().loadEFTransparent(EF_ICCID,
|
||||
obtainMessage(EVENT_GET_ICCID_DONE));
|
||||
recordsToLoad++;
|
||||
|
||||
// Further records that can be inserted are Operator/OEM dependent
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDisplayRule(String plmn) {
|
||||
// TODO together with spn
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVoiceMessageWaiting(int line, int countWaiting) {
|
||||
Log.i(LOG_TAG, "RuimRecords: setVoiceMessageWaiting not supported.");
|
||||
}
|
||||
|
||||
private void handleRuimRefresh(int[] result) {
|
||||
if (result == null || result.length == 0) {
|
||||
if (DBG) log("handleRuimRefresh without input");
|
||||
return;
|
||||
}
|
||||
|
||||
switch ((result[0])) {
|
||||
case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
|
||||
if (DBG) log("handleRuimRefresh with SIM_REFRESH_FILE_UPDATED");
|
||||
adnCache.reset();
|
||||
fetchRuimRecords();
|
||||
break;
|
||||
case CommandsInterface.SIM_REFRESH_INIT:
|
||||
if (DBG) log("handleRuimRefresh with SIM_REFRESH_INIT");
|
||||
// need to reload all files (that we care about)
|
||||
fetchRuimRecords();
|
||||
break;
|
||||
case CommandsInterface.SIM_REFRESH_RESET:
|
||||
if (DBG) log("handleRuimRefresh with SIM_REFRESH_RESET");
|
||||
phone.mCM.setRadioPower(false, null);
|
||||
/* Note: no need to call setRadioPower(true). Assuming the desired
|
||||
* radio power state is still ON (as tracked by ServiceStateTracker),
|
||||
* ServiceStateTracker will call setRadioPower when it receives the
|
||||
* RADIO_STATE_CHANGED notification for the power off. And if the
|
||||
* desired power state has changed in the interim, we don't want to
|
||||
* override it with an unconditional power on.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
// unknown refresh operation
|
||||
if (DBG) log("handleRuimRefresh with unknown operation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void log(String s) {
|
||||
Log.d(LOG_TAG, "[RuimRecords] " + s);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncResult;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.telephony.IccConstants;
|
||||
import com.android.internal.telephony.IccSmsInterfaceManager;
|
||||
import com.android.internal.telephony.IccUtils;
|
||||
import com.android.internal.telephony.PhoneProxy;
|
||||
import com.android.internal.telephony.SmsRawData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static android.telephony.SmsManager.STATUS_ON_ICC_FREE;
|
||||
|
||||
/**
|
||||
* RuimSmsInterfaceManager to provide an inter-process communication to
|
||||
* access Sms in Ruim.
|
||||
*/
|
||||
public class RuimSmsInterfaceManager extends IccSmsInterfaceManager {
|
||||
static final String LOG_TAG = "CDMA";
|
||||
static final boolean DBG = true;
|
||||
|
||||
private final Object mLock = new Object();
|
||||
private boolean mSuccess;
|
||||
private List<SmsRawData> mSms;
|
||||
|
||||
private static final int EVENT_LOAD_DONE = 1;
|
||||
private static final int EVENT_UPDATE_DONE = 2;
|
||||
|
||||
Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
AsyncResult ar;
|
||||
|
||||
switch (msg.what) {
|
||||
case EVENT_UPDATE_DONE:
|
||||
ar = (AsyncResult) msg.obj;
|
||||
synchronized (mLock) {
|
||||
mSuccess = (ar.exception == null);
|
||||
mLock.notifyAll();
|
||||
}
|
||||
break;
|
||||
case EVENT_LOAD_DONE:
|
||||
ar = (AsyncResult)msg.obj;
|
||||
synchronized (mLock) {
|
||||
if (ar.exception == null) {
|
||||
mSms = (List<SmsRawData>)
|
||||
buildValidRawData((ArrayList<byte[]>) ar.result);
|
||||
} else {
|
||||
if(DBG) log("Cannot load Sms records");
|
||||
if (mSms != null)
|
||||
mSms.clear();
|
||||
}
|
||||
mLock.notifyAll();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public RuimSmsInterfaceManager(CDMAPhone phone) {
|
||||
super(phone);
|
||||
mDispatcher = new CdmaSMSDispatcher(phone);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
}
|
||||
|
||||
protected void finalize() {
|
||||
if(DBG) Log.d(LOG_TAG, "RuimSmsInterfaceManager finalized");
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified message on the RUIM.
|
||||
*
|
||||
* @param index record index of message to update
|
||||
* @param status new message status (STATUS_ON_ICC_READ,
|
||||
* STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
|
||||
* STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
|
||||
* @param pdu the raw PDU to store
|
||||
* @return success or not
|
||||
*
|
||||
*/
|
||||
public boolean
|
||||
updateMessageOnIccEf(int index, int status, byte[] pdu) {
|
||||
if (DBG) log("updateMessageOnIccEf: index=" + index +
|
||||
" status=" + status + " ==> " +
|
||||
"("+ pdu + ")");
|
||||
enforceReceiveAndSend("Updating message on RUIM");
|
||||
synchronized(mLock) {
|
||||
mSuccess = false;
|
||||
Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
|
||||
|
||||
if (status == STATUS_ON_ICC_FREE) {
|
||||
// Special case FREE: call deleteSmsOnRuim instead of
|
||||
// manipulating the RUIM record
|
||||
mPhone.mCM.deleteSmsOnRuim(index, response);
|
||||
} else {
|
||||
byte[] record = makeSmsRecordData(status, pdu);
|
||||
mPhone.getIccFileHandler().updateEFLinearFixed(
|
||||
IccConstants.EF_SMS, index, record, null, response);
|
||||
}
|
||||
try {
|
||||
mLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
log("interrupted while trying to update by index");
|
||||
}
|
||||
}
|
||||
return mSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a raw SMS PDU to the RUIM.
|
||||
*
|
||||
* @param pdu the raw PDU to store
|
||||
* @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
|
||||
* STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
|
||||
* @return success or not
|
||||
*
|
||||
*/
|
||||
public boolean copyMessageToIccEf(int status, byte[] pdu, byte[] smsc) {
|
||||
//NOTE smsc not used in RUIM
|
||||
if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " +
|
||||
"pdu=("+ pdu + ")");
|
||||
enforceReceiveAndSend("Copying message to RUIM");
|
||||
synchronized(mLock) {
|
||||
mSuccess = false;
|
||||
Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
|
||||
|
||||
mPhone.mCM.writeSmsToRuim(status, IccUtils.bytesToHexString(pdu),
|
||||
response);
|
||||
|
||||
try {
|
||||
mLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
log("interrupted while trying to update by index");
|
||||
}
|
||||
}
|
||||
return mSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all messages currently stored on RUIM.
|
||||
*/
|
||||
public List<SmsRawData> getAllMessagesFromIccEf() {
|
||||
if (DBG) log("getAllMessagesFromEF");
|
||||
|
||||
Context context = mPhone.getContext();
|
||||
|
||||
context.enforceCallingPermission(
|
||||
"android.permission.RECEIVE_SMS",
|
||||
"Reading messages from RUIM");
|
||||
synchronized(mLock) {
|
||||
Message response = mHandler.obtainMessage(EVENT_LOAD_DONE);
|
||||
mPhone.getIccFileHandler().loadEFLinearFixedAll(IccConstants.EF_SMS, response);
|
||||
|
||||
try {
|
||||
mLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
log("interrupted while trying to load from the RUIM");
|
||||
}
|
||||
}
|
||||
return mSms;
|
||||
}
|
||||
|
||||
protected void log(String msg) {
|
||||
Log.d(LOG_TAG, "[RuimSmsInterfaceManager] " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,905 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.text.format.Time;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
import com.android.internal.telephony.EncodeException;
|
||||
import com.android.internal.telephony.GsmAlphabet;
|
||||
import com.android.internal.telephony.IccUtils;
|
||||
import com.android.internal.telephony.SmsHeader;
|
||||
import com.android.internal.telephony.SmsMessageBase;
|
||||
import com.android.internal.telephony.cdma.sms.BearerData;
|
||||
import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
|
||||
import com.android.internal.telephony.cdma.sms.SmsDataCoding;
|
||||
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
|
||||
import com.android.internal.telephony.cdma.sms.UserData;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Random;
|
||||
|
||||
import static android.telephony.SmsMessage.ENCODING_7BIT;
|
||||
import static android.telephony.SmsMessage.ENCODING_8BIT;
|
||||
import static android.telephony.SmsMessage.ENCODING_16BIT;
|
||||
import static android.telephony.SmsMessage.ENCODING_UNKNOWN;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
|
||||
import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER;
|
||||
import static android.telephony.SmsMessage.MessageClass;
|
||||
import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_NONE;
|
||||
import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_TEMPORARY;
|
||||
import static com.android.internal.telephony.cdma.sms.BearerData.ERROR_PERMANENT;
|
||||
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_DELIVER;
|
||||
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_SUBMIT;
|
||||
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_CANCELLATION;
|
||||
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_DELIVERY_ACK;
|
||||
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_USER_ACK;
|
||||
import static com.android.internal.telephony.cdma.sms.BearerData.MESSAGE_TYPE_READ_ACK;
|
||||
import static com.android.internal.telephony.cdma.sms.CdmaSmsAddress.SMS_ADDRESS_MAX;
|
||||
import static com.android.internal.telephony.cdma.sms.CdmaSmsAddress.SMS_SUBADDRESS_MAX;
|
||||
import static com.android.internal.telephony.cdma.sms.SmsEnvelope.SMS_BEARER_DATA_MAX;
|
||||
import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_7BIT_ASCII;
|
||||
import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_GSM_7BIT_ALPHABET;
|
||||
import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_IA5;
|
||||
import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_OCTET;
|
||||
import static com.android.internal.telephony.cdma.sms.UserData.UD_ENCODING_UNICODE_16;
|
||||
|
||||
/**
|
||||
* A Short Message Service message.
|
||||
*
|
||||
*/
|
||||
public class SmsMessage extends SmsMessageBase {
|
||||
static final String LOG_TAG = "CDMA";
|
||||
|
||||
/**
|
||||
* Status of a previously submitted SMS.
|
||||
* This field applies to SMS Delivery Acknowledge messages. 0 indicates success;
|
||||
* Here, the error class is defined by the bits from 9-8, the status code by the bits from 7-0.
|
||||
* See C.S0015-B, v2.0, 4.5.21 for a detailed description of possible values.
|
||||
*/
|
||||
private int status;
|
||||
|
||||
/** The next message ID for the BearerData. Shall be a random value on first use.
|
||||
* (See C.S0015-B, v2.0, 4.3.1.5)
|
||||
*/
|
||||
private static int nextMessageId = 0;
|
||||
|
||||
/** Specifies if this is the first SMS message submit */
|
||||
private static boolean firstSMS = true;
|
||||
|
||||
/** Specifies if a return of an acknowledgment is requested for send SMS */
|
||||
private static final int RETURN_NO_ACK = 0;
|
||||
private static final int RETURN_ACK = 1;
|
||||
|
||||
private SmsEnvelope mEnvelope;
|
||||
private BearerData mBearerData;
|
||||
|
||||
public static class SubmitPdu extends SubmitPduBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an SmsMessage from a raw PDU.
|
||||
* Note: In CDMA the PDU is just a byte representation of the received Sms.
|
||||
*/
|
||||
public static SmsMessage createFromPdu(byte[] pdu) {
|
||||
SmsMessage msg = new SmsMessage();
|
||||
|
||||
try {
|
||||
msg.parsePdu(pdu);
|
||||
return msg;
|
||||
} catch (RuntimeException ex) {
|
||||
Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public static SmsMessage newFromCMT(String[] lines) {
|
||||
Log.w(LOG_TAG, "newFromCMT: is not supported in CDMA mode.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public static SmsMessage newFromCMTI(String line) {
|
||||
Log.w(LOG_TAG, "newFromCMTI: is not supported in CDMA mode.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public static SmsMessage newFromCDS(String line) {
|
||||
Log.w(LOG_TAG, "newFromCDS: is not supported in CDMA mode.");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp.
|
||||
* Note: Only primitive fields are set.
|
||||
*/
|
||||
public static SmsMessage newFromParcel(Parcel p) {
|
||||
// Note: Parcel.readByte actually reads one Int and masks to byte
|
||||
SmsMessage msg = new SmsMessage();
|
||||
SmsEnvelope env = new SmsEnvelope();
|
||||
CdmaSmsAddress addr = new CdmaSmsAddress();
|
||||
byte[] data;
|
||||
byte count;
|
||||
int countInt;
|
||||
|
||||
//currently not supported by the modem-lib: env.mMessageType
|
||||
env.teleService = p.readInt(); //p_cur->uTeleserviceID
|
||||
|
||||
if (0 != p.readByte()) { //p_cur->bIsServicePresent
|
||||
env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST;
|
||||
}
|
||||
else {
|
||||
if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) {
|
||||
// assume type ACK
|
||||
env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE;
|
||||
} else {
|
||||
env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
|
||||
}
|
||||
}
|
||||
env.serviceCategory = p.readInt(); //p_cur->uServicecategory
|
||||
|
||||
// address
|
||||
addr.digitMode = (byte) (0xFF & p.readInt()); //p_cur->sAddress.digit_mode
|
||||
addr.numberMode = (byte) (0xFF & p.readInt()); //p_cur->sAddress.number_mode
|
||||
addr.ton = p.readInt(); //p_cur->sAddress.number_type
|
||||
addr.numberPlan = (byte) (0xFF & p.readInt()); //p_cur->sAddress.number_plan
|
||||
count = p.readByte(); //p_cur->sAddress.number_of_digits
|
||||
addr.numberOfDigits = count;
|
||||
data = new byte[count];
|
||||
//p_cur->sAddress.digits[digitCount]
|
||||
for (int index=0; index < count; index++) {
|
||||
data[index] = p.readByte();
|
||||
}
|
||||
addr.origBytes = data;
|
||||
|
||||
// ignore subaddress
|
||||
p.readInt(); //p_cur->sSubAddress.subaddressType
|
||||
p.readByte(); //p_cur->sSubAddress.odd
|
||||
count = p.readByte(); //p_cur->sSubAddress.number_of_digits
|
||||
//p_cur->sSubAddress.digits[digitCount] :
|
||||
for (int index=0; index < count; index++) {
|
||||
p.readByte();
|
||||
}
|
||||
|
||||
/* currently not supported by the modem-lib:
|
||||
env.bearerReply
|
||||
env.replySeqNo
|
||||
env.errorClass
|
||||
env.causeCode
|
||||
*/
|
||||
|
||||
// bearer data
|
||||
countInt = p.readInt(); //p_cur->uBearerDataLen
|
||||
if (countInt >0) {
|
||||
data = new byte[countInt];
|
||||
//p_cur->aBearerData[digitCount] :
|
||||
for (int index=0; index < countInt; index++) {
|
||||
data[index] = p.readByte();
|
||||
}
|
||||
env.bearerData = data;
|
||||
// BD gets further decoded when accessed in SMSDispatcher
|
||||
}
|
||||
|
||||
// link the the filled objects to the SMS
|
||||
env.origAddress = addr;
|
||||
msg.originatingAddress = addr;
|
||||
msg.mEnvelope = env;
|
||||
|
||||
// create byte stream representation for transportation through the layers.
|
||||
msg.createPdu();
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an SmsMessage from an SMS EF record.
|
||||
*
|
||||
* @param index Index of SMS record. This should be index in ArrayList
|
||||
* returned by RuimSmsInterfaceManager.getAllMessagesFromIcc + 1.
|
||||
* @param data Record data.
|
||||
* @return An SmsMessage representing the record.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static SmsMessage createFromEfRecord(int index, byte[] data) {
|
||||
try {
|
||||
SmsMessage msg = new SmsMessage();
|
||||
|
||||
msg.indexOnIcc = index;
|
||||
|
||||
// First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT,
|
||||
// or STORED_UNSENT
|
||||
// See 3GPP2 C.S0023 3.4.27
|
||||
if ((data[0] & 1) == 0) {
|
||||
Log.w(LOG_TAG, "SMS parsing failed: Trying to parse a free record");
|
||||
return null;
|
||||
} else {
|
||||
msg.statusOnIcc = data[0] & 0x07;
|
||||
}
|
||||
|
||||
// Second byte is the MSG_LEN, length of the message
|
||||
// See 3GPP2 C.S0023 3.4.27
|
||||
int size = data[1];
|
||||
|
||||
// Note: Data may include trailing FF's. That's OK; message
|
||||
// should still parse correctly.
|
||||
byte[] pdu = new byte[size];
|
||||
System.arraycopy(data, 2, pdu, 0, size);
|
||||
// the message has to be parsed before it can be displayed
|
||||
// see gsm.SmsMessage
|
||||
return msg;
|
||||
} catch (RuntimeException ex) {
|
||||
Log.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public static int getTPLayerLengthForPDU(String pdu) {
|
||||
Log.w(LOG_TAG, "getTPLayerLengthForPDU: is not supported in CDMA mode.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SMS-SUBMIT PDU for a destination address and a message
|
||||
*
|
||||
* @param scAddress Service Centre address. Null means use default.
|
||||
* @param destinationAddress Address of the recipient.
|
||||
* @param message String representation of the message payload.
|
||||
* @param statusReportRequested Indicates whether a report is requested for this message.
|
||||
* @param headerData Array containing the data for the User Data Header, preceded
|
||||
* by the Element Identifiers.
|
||||
* @return a <code>SubmitPdu</code> containing the encoded SC
|
||||
* address, if applicable, and the encoded message.
|
||||
* Returns null on encode error.
|
||||
* @hide
|
||||
*/
|
||||
public static SubmitPdu getSubmitPdu(String scAddress,
|
||||
String destinationAddress, String message,
|
||||
boolean statusReportRequested, byte[] headerData) {
|
||||
|
||||
SmsMessage sms = new SmsMessage();
|
||||
SubmitPdu ret = new SubmitPdu();
|
||||
UserData uData = new UserData();
|
||||
SmsHeader smsHeader;
|
||||
|
||||
// Perform null parameter checks.
|
||||
if (message == null || destinationAddress == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// ** Set UserData + SmsHeader **
|
||||
try {
|
||||
// First, try encoding it with the GSM alphabet
|
||||
int septetCount = GsmAlphabet.countGsmSeptets(message, true);
|
||||
// User Data (and length)
|
||||
|
||||
uData.userData = message.getBytes();
|
||||
|
||||
if (uData.userData.length > MAX_USER_DATA_SEPTETS) {
|
||||
// Message too long
|
||||
return null;
|
||||
}
|
||||
|
||||
// desired TP-Data-Coding-Scheme
|
||||
uData.userDataEncoding = UserData.UD_ENCODING_GSM_7BIT_ALPHABET;
|
||||
|
||||
// paddingBits not needed for UD_ENCODING_GSM_7BIT_ALPHABET
|
||||
|
||||
// sms header
|
||||
if(headerData != null) {
|
||||
smsHeader = SmsHeader.parse(headerData);
|
||||
uData.userDataHeader = smsHeader;
|
||||
} else {
|
||||
// no user data header available!
|
||||
}
|
||||
|
||||
} catch (EncodeException ex) {
|
||||
byte[] textPart;
|
||||
// Encoding to the 7-bit alphabet failed. Let's see if we can
|
||||
// send it as a UCS-2 encoded message
|
||||
|
||||
try {
|
||||
textPart = message.getBytes("utf-16be");
|
||||
} catch (UnsupportedEncodingException uex) {
|
||||
Log.e(LOG_TAG, "Implausible UnsupportedEncodingException ", uex);
|
||||
return null;
|
||||
}
|
||||
|
||||
uData.userData = textPart;
|
||||
|
||||
if (uData.userData.length > MAX_USER_DATA_BYTES) {
|
||||
// Message too long
|
||||
return null;
|
||||
}
|
||||
|
||||
// TP-Data-Coding-Scheme
|
||||
uData.userDataEncoding = UserData.UD_ENCODING_UNICODE_16;
|
||||
|
||||
// sms header
|
||||
if(headerData != null) {
|
||||
smsHeader = SmsHeader.parse(headerData);
|
||||
uData.userDataHeader = smsHeader;
|
||||
} else {
|
||||
// no user data header available!
|
||||
}
|
||||
}
|
||||
|
||||
byte[] data = sms.getEnvelope(destinationAddress, statusReportRequested, uData,
|
||||
(headerData != null), (null == headerData));
|
||||
|
||||
if (null == data) return null;
|
||||
|
||||
ret.encodedMessage = data;
|
||||
ret.encodedScAddress = null;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an SMS-SUBMIT PDU for a destination address and a message
|
||||
*
|
||||
* @param scAddress Service Centre address. Null means use default.
|
||||
* @return a <code>SubmitPdu</code> containing the encoded SC
|
||||
* address, if applicable, and the encoded message.
|
||||
* Returns null on encode error.
|
||||
*/
|
||||
public static SubmitPdu getSubmitPdu(String scAddress,
|
||||
String destinationAddress, String message,
|
||||
boolean statusReportRequested) {
|
||||
return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an SMS-SUBMIT PDU for a data message to a destination address & port
|
||||
*
|
||||
* @param scAddress Service Centre address. null == use default
|
||||
* @param destinationAddress the address of the destination for the message
|
||||
* @param destinationPort the port to deliver the message to at the
|
||||
* destination
|
||||
* @param data the data for the message
|
||||
* @return a <code>SubmitPdu</code> containing the encoded SC
|
||||
* address, if applicable, and the encoded message.
|
||||
* Returns null on encode error.
|
||||
*/
|
||||
public static SubmitPdu getSubmitPdu(String scAddress,
|
||||
String destinationAddress, short destinationPort, byte[] data,
|
||||
boolean statusReportRequested) {
|
||||
|
||||
SmsMessage sms = new SmsMessage();
|
||||
SubmitPdu ret = new SubmitPdu();
|
||||
UserData uData = new UserData();
|
||||
SmsHeader smsHeader = new SmsHeader();
|
||||
|
||||
if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) {
|
||||
Log.e(LOG_TAG, "SMS data message may only contain "
|
||||
+ (MAX_USER_DATA_BYTES - 7) + " bytes");
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] destPort = new byte[4];
|
||||
destPort[0] = (byte) ((destinationPort >> 8) & 0xFF); // MSB of destination port
|
||||
destPort[1] = (byte) (destinationPort & 0xFF); // LSB of destination port
|
||||
destPort[2] = 0x00; // MSB of originating port
|
||||
destPort[3] = 0x00; // LSB of originating port
|
||||
smsHeader.add(
|
||||
new SmsHeader.Element(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT, destPort));
|
||||
|
||||
smsHeader.nbrOfHeaders = smsHeader.getElements().size();
|
||||
uData.userDataHeader = smsHeader;
|
||||
|
||||
// TP-Data-Coding-Scheme
|
||||
// No class, 8 bit data
|
||||
uData.userDataEncoding = UserData.UD_ENCODING_OCTET;
|
||||
uData.userData = data;
|
||||
|
||||
byte[] msgData = sms.getEnvelope(destinationAddress, statusReportRequested, uData,
|
||||
true, true);
|
||||
|
||||
ret.encodedMessage = msgData;
|
||||
ret.encodedScAddress = null;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static class PduParser {
|
||||
|
||||
PduParser() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an SC timestamp and returns a currentTimeMillis()-style
|
||||
* timestamp
|
||||
*/
|
||||
static long getSCTimestampMillis(byte[] timestamp) {
|
||||
// TP-Service-Centre-Time-Stamp
|
||||
int year = IccUtils.beBcdByteToInt(timestamp[0]);
|
||||
int month = IccUtils.beBcdByteToInt(timestamp[1]);
|
||||
int day = IccUtils.beBcdByteToInt(timestamp[2]);
|
||||
int hour = IccUtils.beBcdByteToInt(timestamp[3]);
|
||||
int minute = IccUtils.beBcdByteToInt(timestamp[4]);
|
||||
int second = IccUtils.beBcdByteToInt(timestamp[5]);
|
||||
|
||||
Time time = new Time(Time.TIMEZONE_UTC);
|
||||
|
||||
// C.S0015-B v2.0, 4.5.4: range is 1996-2095
|
||||
time.year = year >= 96 ? year + 1900 : year + 2000;
|
||||
time.month = month - 1;
|
||||
time.monthDay = day;
|
||||
time.hour = hour;
|
||||
time.minute = minute;
|
||||
time.second = second;
|
||||
|
||||
return time.toMillis(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public int getProtocolIdentifier() {
|
||||
Log.w(LOG_TAG, "getProtocolIdentifier: is not supported in CDMA mode.");
|
||||
// (3GPP TS 23.040): "no interworking, but SME to SME protocol":
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public boolean isReplace() {
|
||||
Log.w(LOG_TAG, "isReplace: is not supported in CDMA mode.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public boolean isCphsMwiMessage() {
|
||||
Log.w(LOG_TAG, "isCphsMwiMessage: is not supported in CDMA mode.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean isMWIClearMessage() {
|
||||
if ((mBearerData != null) && (0 == mBearerData.numberOfMessages)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean isMWISetMessage() {
|
||||
if ((mBearerData != null) && (mBearerData.numberOfMessages >0)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public boolean isMwiDontStore() {
|
||||
if ((mBearerData != null) && (mBearerData.numberOfMessages >0)
|
||||
&& (null == mBearerData.userData)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status for a previously submitted message.
|
||||
* For not interfering with status codes from GSM, this status code is
|
||||
* shifted to the bits 31-16.
|
||||
*/
|
||||
public int getStatus() {
|
||||
return(status<<16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public boolean isStatusReportMessage() {
|
||||
Log.w(LOG_TAG, "isStatusReportMessage: is not supported in CDMA mode.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This function is a GSM specific functionality which is not supported in CDMA mode.
|
||||
*/
|
||||
public boolean isReplyPathPresent() {
|
||||
Log.w(LOG_TAG, "isReplyPathPresent: is not supported in CDMA mode.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the teleservice type of the message.
|
||||
* @return the teleservice:
|
||||
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET},
|
||||
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WMT},
|
||||
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WEMT},
|
||||
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN},
|
||||
* {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP}
|
||||
*/
|
||||
public int getTeleService() {
|
||||
return mEnvelope.teleService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes pdu to an empty SMS object.
|
||||
* In the CDMA case the pdu is just an internal byte stream representation
|
||||
* of the SMS Java-object.
|
||||
* @see #createPdu()
|
||||
*/
|
||||
private void parsePdu(byte[] pdu) {
|
||||
ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
|
||||
DataInputStream dis = new DataInputStream(new BufferedInputStream(bais));
|
||||
byte length;
|
||||
SmsEnvelope env = new SmsEnvelope();
|
||||
CdmaSmsAddress addr = new CdmaSmsAddress();
|
||||
|
||||
try {
|
||||
env.messageType = dis.readInt();
|
||||
env.teleService = dis.readInt();
|
||||
env.serviceCategory = dis.readInt();
|
||||
|
||||
addr.digitMode = dis.readByte();
|
||||
addr.numberMode = dis.readByte();
|
||||
addr.ton = dis.readByte();
|
||||
addr.numberPlan = dis.readByte();
|
||||
|
||||
length = dis.readByte();
|
||||
addr.numberOfDigits = length;
|
||||
addr.origBytes = new byte[length];
|
||||
dis.read(addr.origBytes, 0, length); // digits
|
||||
|
||||
env.bearerReply = dis.readInt();
|
||||
// CauseCode values:
|
||||
env.replySeqNo = dis.readByte();
|
||||
env.errorClass = dis.readByte();
|
||||
env.causeCode = dis.readByte();
|
||||
|
||||
//encoded BearerData:
|
||||
length = dis.readByte();
|
||||
env.bearerData = new byte[length];
|
||||
dis.read(env.bearerData, 0, length);
|
||||
dis.close();
|
||||
} catch (Exception ex) {
|
||||
Log.e(LOG_TAG, "createFromPdu: conversion from byte array to object failed: " + ex);
|
||||
}
|
||||
|
||||
// link the filled objects to this SMS
|
||||
originatingAddress = addr;
|
||||
env.origAddress = addr;
|
||||
mEnvelope = env;
|
||||
|
||||
parseSms();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a SMS message from its BearerData stream. (mobile-terminated only)
|
||||
*/
|
||||
protected void parseSms() {
|
||||
mBearerData = SmsDataCoding.decodeCdmaSms(mEnvelope.bearerData);
|
||||
messageRef = mBearerData.messageID;
|
||||
|
||||
// TP-Message-Type-Indicator
|
||||
// (See 3GPP2 C.S0015-B, v2, 4.5.1)
|
||||
int messageType = mBearerData.messageType;
|
||||
|
||||
switch (messageType) {
|
||||
case MESSAGE_TYPE_USER_ACK:
|
||||
case MESSAGE_TYPE_READ_ACK:
|
||||
case MESSAGE_TYPE_DELIVER:
|
||||
// Deliver (mobile-terminated only)
|
||||
parseSmsDeliver();
|
||||
break;
|
||||
case MESSAGE_TYPE_DELIVERY_ACK:
|
||||
parseSmsDeliveryAck();
|
||||
break;
|
||||
|
||||
default:
|
||||
// the rest of these
|
||||
throw new RuntimeException("Unsupported message type: " + messageType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a SMS-DELIVER message. (mobile-terminated only)
|
||||
* See 3GPP2 C.S0015-B, v2, 4.4.1
|
||||
*/
|
||||
private void parseSmsDeliver() {
|
||||
if (originatingAddress != null) {
|
||||
originatingAddress.address = new String(originatingAddress.origBytes);
|
||||
if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: "
|
||||
+ originatingAddress.address);
|
||||
}
|
||||
|
||||
if (mBearerData.timeStamp != null) {
|
||||
scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp);
|
||||
}
|
||||
|
||||
if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis);
|
||||
|
||||
parseUserData(mBearerData.userData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a SMS-DELIVER message. (mobile-terminated only)
|
||||
* See 3GPP2 C.S0015-B, v2, 4.4.1
|
||||
*/
|
||||
private void parseSmsDeliveryAck() {
|
||||
if (originatingAddress != null) {
|
||||
originatingAddress.address = new String(originatingAddress.origBytes);
|
||||
if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: "
|
||||
+ originatingAddress.address);
|
||||
}
|
||||
|
||||
if (mBearerData.timeStamp != null) {
|
||||
scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp);
|
||||
}
|
||||
|
||||
if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis);
|
||||
|
||||
if (mBearerData.errorClass != BearerData.ERROR_UNDEFINED) {
|
||||
status = mBearerData.errorClass << 8;
|
||||
status |= mBearerData.messageStatus;
|
||||
}
|
||||
|
||||
parseUserData(mBearerData.userData);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the User Data of an SMS.
|
||||
*/
|
||||
private void parseUserData(UserData uData) {
|
||||
int encodingType;
|
||||
|
||||
if (null == uData) {
|
||||
return;
|
||||
}
|
||||
|
||||
encodingType = uData.userDataEncoding;
|
||||
|
||||
// insert DCS-decoding here when type is supported by ril-library
|
||||
|
||||
userData = uData.userData;
|
||||
userDataHeader = uData.userDataHeader;
|
||||
|
||||
switch (encodingType) {
|
||||
case UD_ENCODING_GSM_7BIT_ALPHABET:
|
||||
case UD_ENCODING_UNICODE_16:
|
||||
// user data was already decoded by wmsts-library
|
||||
messageBody = new String(userData);
|
||||
break;
|
||||
|
||||
// data and unsupported encodings:
|
||||
case UD_ENCODING_OCTET:
|
||||
default:
|
||||
messageBody = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'");
|
||||
|
||||
if (messageBody != null) {
|
||||
parseMessageBody();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public MessageClass getMessageClass() {
|
||||
if (BearerData.DISPLAY_IMMEDIATE == mBearerData.displayMode ) {
|
||||
return MessageClass.CLASS_0;
|
||||
} else {
|
||||
return MessageClass.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates BearerData and Envelope from parameters for a Submit SMS.
|
||||
* @return byte stream for SubmitPdu.
|
||||
*/
|
||||
private byte[] getEnvelope(String destinationAddress, boolean statusReportRequested,
|
||||
UserData userData, boolean hasHeaders, boolean useNewId) {
|
||||
|
||||
BearerData mBearerData = new BearerData();
|
||||
SmsEnvelope env = new SmsEnvelope();
|
||||
CdmaSmsAddress mSmsAddress = new CdmaSmsAddress();
|
||||
|
||||
// ** set SmsAddress **
|
||||
mSmsAddress.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR;
|
||||
try {
|
||||
mSmsAddress.origBytes = destinationAddress.getBytes("UTF-8");
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "doGetSubmitPdu: conversion of destinationAddress from string to byte[]"
|
||||
+ " failed: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
mSmsAddress.numberOfDigits = (byte)mSmsAddress.origBytes.length;
|
||||
mSmsAddress.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK;
|
||||
// see C.S0015-B, v2.0, 3.4.3.3
|
||||
mSmsAddress.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY;
|
||||
mSmsAddress.ton = CdmaSmsAddress.TON_INTERNATIONAL_OR_IP;
|
||||
|
||||
// ** set BearerData **
|
||||
mBearerData.userData = userData;
|
||||
mBearerData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
|
||||
|
||||
if (useNewId) {
|
||||
setNextMessageId();
|
||||
}
|
||||
mBearerData.messageID = nextMessageId;
|
||||
|
||||
// Set the reply options (See C.S0015-B, v2.0, 4.5.11)
|
||||
if(statusReportRequested) {
|
||||
mBearerData.deliveryAckReq = true;
|
||||
} else {
|
||||
mBearerData.deliveryAckReq = false;
|
||||
}
|
||||
// Currently settings applications do not support this
|
||||
mBearerData.userAckReq = false;
|
||||
mBearerData.readAckReq = false;
|
||||
mBearerData.reportReq = false;
|
||||
|
||||
// Set the display mode (See C.S0015-B, v2.0, 4.5.16)
|
||||
mBearerData.displayMode = BearerData.DISPLAY_DEFAULT;
|
||||
|
||||
// number of messages: not needed for encoding!
|
||||
|
||||
// indicate whether a user data header is available
|
||||
mBearerData.hasUserDataHeader = hasHeaders;
|
||||
|
||||
// ** encode BearerData **
|
||||
byte[] encodedBearerData = null;
|
||||
try {
|
||||
encodedBearerData = SmsDataCoding.encodeCdmaSms(mBearerData);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "doGetSubmitPdu: EncodeCdmaSMS function in JNI interface failed: "
|
||||
+ e.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
// ** SmsEnvelope **
|
||||
env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
|
||||
env.teleService = SmsEnvelope.TELESERVICE_WEMT;
|
||||
env.destAddress = mSmsAddress;
|
||||
env.bearerReply = RETURN_ACK;
|
||||
env.bearerData = encodedBearerData;
|
||||
mEnvelope = env;
|
||||
|
||||
// get byte array output stream from SmsAddress object and SmsEnvelope member.
|
||||
return serialize(mSmsAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the nextMessageId to a random value between 0 and 65536
|
||||
* See C.S0015-B, v2.0, 4.3.1.5
|
||||
*/
|
||||
private void setNextMessageId() {
|
||||
// Message ID, modulo 65536
|
||||
if(firstSMS) {
|
||||
Random generator = new Random();
|
||||
nextMessageId = generator.nextInt(65536);
|
||||
firstSMS = false;
|
||||
} else {
|
||||
nextMessageId = ++nextMessageId & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates ByteArrayOutputStream from CdmaSmsAddress and SmsEnvelope objects
|
||||
*
|
||||
* @param address CdmaSmsAddress object
|
||||
* @return ByteArrayOutputStream
|
||||
*/
|
||||
private byte[] serialize(CdmaSmsAddress destAddress) {
|
||||
SmsEnvelope env = mEnvelope;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
|
||||
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
|
||||
|
||||
try {
|
||||
dos.writeInt(env.teleService);
|
||||
dos.writeInt(0); //servicePresent
|
||||
dos.writeInt(0); //serviceCategory
|
||||
dos.write(destAddress.digitMode);
|
||||
dos.write(destAddress.numberMode);
|
||||
dos.write(destAddress.ton); // number_type
|
||||
dos.write(destAddress.numberPlan);
|
||||
dos.write(destAddress.numberOfDigits);
|
||||
dos.write(destAddress.origBytes, 0, destAddress.origBytes.length); // digits
|
||||
// Subaddress is not supported.
|
||||
dos.write(0); //subaddressType
|
||||
dos.write(0); //subaddr_odd
|
||||
dos.write(0); //subaddr_nbr_of_digits
|
||||
dos.write(env.bearerData.length);
|
||||
dos.write(env.bearerData, 0, env.bearerData.length);
|
||||
dos.close();
|
||||
return baos.toByteArray();
|
||||
} catch(IOException ex) {
|
||||
Log.e(LOG_TAG, "serialize: conversion from object to data output stream failed: " + ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates byte array (pseudo pdu) from SMS object.
|
||||
* Note: Do not call this method more than once per object!
|
||||
*/
|
||||
private void createPdu() {
|
||||
SmsEnvelope env = mEnvelope;
|
||||
CdmaSmsAddress addr = env.origAddress;
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
|
||||
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
|
||||
|
||||
try {
|
||||
dos.writeInt(env.messageType);
|
||||
dos.writeInt(env.teleService);
|
||||
dos.writeInt(env.serviceCategory);
|
||||
|
||||
dos.writeByte(addr.digitMode);
|
||||
dos.writeByte(addr.numberMode);
|
||||
dos.writeByte(addr.ton);
|
||||
dos.writeByte(addr.numberPlan);
|
||||
dos.writeByte(addr.numberOfDigits);
|
||||
dos.write(addr.origBytes, 0, addr.origBytes.length); // digits
|
||||
|
||||
dos.writeInt(env.bearerReply);
|
||||
// CauseCode values:
|
||||
dos.writeByte(env.replySeqNo);
|
||||
dos.writeByte(env.errorClass);
|
||||
dos.writeByte(env.causeCode);
|
||||
//encoded BearerData:
|
||||
dos.writeByte(env.bearerData.length);
|
||||
dos.write(env.bearerData, 0, env.bearerData.length);
|
||||
dos.close();
|
||||
|
||||
mPdu = baos.toByteArray();
|
||||
} catch (IOException ex) {
|
||||
Log.e(LOG_TAG, "createPdu: conversion from object to byte array failed: " + ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma;
|
||||
|
||||
public class TtyIntent {
|
||||
|
||||
private static final String TAG = "TtyIntent";
|
||||
|
||||
|
||||
/** Event for TTY mode change */
|
||||
|
||||
/**
|
||||
* Broadcast intent action indicating that the TTY has either been
|
||||
* enabled or disabled. An intent extra provides this state as a boolean,
|
||||
* where {@code true} means enabled.
|
||||
* @see #TTY_ENABLED
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static final String TTY_ENABLED_CHANGE_ACTION =
|
||||
"com.android.internal.telephony.cdma.intent.action.TTY_ENABLED_CHANGE";
|
||||
|
||||
/**
|
||||
* The lookup key for a boolean that indicates whether TTY mode is enabled or
|
||||
* disabled. {@code true} means TTY mode is enabled. Retrieve it with
|
||||
* {@link android.content.Intent#getBooleanExtra(String,boolean)}.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public static final String TTY_ENABLED = "ttyEnabled";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<HTML>
|
||||
<BODY>
|
||||
Provides classes to control or read data from CDMA phones.
|
||||
@hide
|
||||
</BODY>
|
||||
</HTML>
|
||||
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma.sms;
|
||||
|
||||
public final class BearerData{
|
||||
|
||||
// For completeness the following fields are listed, though not used yet.
|
||||
/**
|
||||
* Supported priority modes for CDMA SMS messages
|
||||
* (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1)
|
||||
*/
|
||||
//public static final int PRIORITY_NORMAL = 0x0;
|
||||
//public static final int PRIORITY_INTERACTIVE = 0x1;
|
||||
//public static final int PRIORITY_URGENT = 0x2;
|
||||
//public static final int PRIORITY_EMERGENCY = 0x3;
|
||||
|
||||
/**
|
||||
* Supported privacy modes for CDMA SMS messages
|
||||
* (See 3GPP2 C.S0015-B, v2.0, table 4.5.10-1)
|
||||
*/
|
||||
//public static final int PRIVACY_NOT_RESTRICTED = 0x0;
|
||||
//public static final int PRIVACY_RESTRICTED = 0x1;
|
||||
//public static final int PRIVACY_CONFIDENTIAL = 0x2;
|
||||
//public static final int PRIVACY_SECRET = 0x3;
|
||||
|
||||
/**
|
||||
* Supported alert modes for CDMA SMS messages
|
||||
* (See 3GPP2 C.S0015-B, v2.0, table 4.5.13-1)
|
||||
*/
|
||||
//public static final int ALERT_DEFAULT = 0x0;
|
||||
//public static final int ALERT_LOW_PRIO = 0x1;
|
||||
//public static final int ALERT_MEDIUM_PRIO = 0x2;
|
||||
//public static final int ALERT_HIGH_PRIO = 0x3;
|
||||
|
||||
/**
|
||||
* Supported display modes for CDMA SMS messages
|
||||
* (See 3GPP2 C.S0015-B, v2.0, table 4.5.16-1)
|
||||
*/
|
||||
public static final int DISPLAY_IMMEDIATE = 0x0;
|
||||
public static final int DISPLAY_DEFAULT = 0x1;
|
||||
public static final int DISPLAY_USER = 0x2;
|
||||
|
||||
/**
|
||||
* Supported message types for CDMA SMS messages
|
||||
* (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1)
|
||||
*/
|
||||
public static final int MESSAGE_TYPE_DELIVER = 0x01;
|
||||
public static final int MESSAGE_TYPE_SUBMIT = 0x02;
|
||||
public static final int MESSAGE_TYPE_CANCELLATION = 0x03;
|
||||
public static final int MESSAGE_TYPE_DELIVERY_ACK = 0x04;
|
||||
public static final int MESSAGE_TYPE_USER_ACK = 0x05;
|
||||
public static final int MESSAGE_TYPE_READ_ACK = 0x06;
|
||||
public static final int MESSAGE_TYPE_DELIVER_REPORT = 0x07;
|
||||
public static final int MESSAGE_TYPE_SUBMIT_REPORT = 0x08;
|
||||
|
||||
/**
|
||||
* SMS Message Status Codes
|
||||
* (See 3GPP2 C.S0015-B, v2.0, table 4.5.21-1)
|
||||
*/
|
||||
/* no-error codes */
|
||||
public static final int ERROR_NONE = 0x00;
|
||||
public static final int STATUS_ACCEPTED = 0x00;
|
||||
public static final int STATUS_DEPOSITED_TO_INTERNET = 0x01;
|
||||
public static final int STATUS_DELIVERED = 0x02;
|
||||
public static final int STATUS_CANCELLED = 0x03;
|
||||
/* temporary-error and permanent-error codes */
|
||||
public static final int ERROR_TEMPORARY = 0x02;
|
||||
public static final int STATUS_NETWORK_CONGESTION = 0x04;
|
||||
public static final int STATUS_NETWORK_ERROR = 0x05;
|
||||
public static final int STATUS_UNKNOWN_ERROR = 0x1F;
|
||||
/* permanent-error codes */
|
||||
public static final int ERROR_PERMANENT = 0x03;
|
||||
public static final int STATUS_CANCEL_FAILED = 0x06;
|
||||
public static final int STATUS_BLOCKED_DESTINATION = 0x07;
|
||||
public static final int STATUS_TEXT_TOO_LONG = 0x08;
|
||||
public static final int STATUS_DUPLICATE_MESSAGE = 0x09;
|
||||
public static final int STATUS_INVALID_DESTINATION = 0x0A;
|
||||
public static final int STATUS_MESSAGE_EXPIRED = 0x0D;
|
||||
/* undefined-status codes */
|
||||
public static final int ERROR_UNDEFINED = 0xFF;
|
||||
public static final int STATUS_UNDEFINED = 0xFF;
|
||||
|
||||
/** Bit-mask indicating used fields for SmsDataCoding */
|
||||
public int mask;
|
||||
|
||||
/**
|
||||
* 4-bit value indicating the message type in accordance to
|
||||
* table 4.5.1-1
|
||||
* (See 3GPP2 C.S0015-B, v2, 4.5.1)
|
||||
*/
|
||||
public byte messageType;
|
||||
|
||||
/**
|
||||
* 16-bit value indicating the message ID, which increments modulo 65536.
|
||||
* (Special rules apply for WAP-messages.)
|
||||
* (See 3GPP2 C.S0015-B, v2, 4.5.1)
|
||||
*/
|
||||
public int messageID;
|
||||
|
||||
/**
|
||||
* 1-bit value that indicates whether a User Data Header is present.
|
||||
* (See 3GPP2 C.S0015-B, v2, 4.5.1)
|
||||
*/
|
||||
public boolean hasUserDataHeader;
|
||||
|
||||
/**
|
||||
* provides the information for the user data
|
||||
* (e.g. padding bits, user data, user data header, etc)
|
||||
* (See 3GPP2 C.S.0015-B, v2, 4.5.2)
|
||||
*/
|
||||
public UserData userData;
|
||||
|
||||
//public UserResponseCode userResponseCode;
|
||||
|
||||
/**
|
||||
* 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4
|
||||
* year, month, day, hours, minutes, seconds;
|
||||
*/
|
||||
public byte[] timeStamp;
|
||||
|
||||
//public SmsTime validityPeriodAbsolute;
|
||||
//public SmsRelTime validityPeriodRelative;
|
||||
//public SmsTime deferredDeliveryTimeAbsolute;
|
||||
//public SmsRelTime deferredDeliveryTimeRelative;
|
||||
//public byte priority;
|
||||
//public byte privacy;
|
||||
|
||||
/**
|
||||
* Reply Option
|
||||
* 1-bit values which indicate whether SMS acknowledgment is requested or not.
|
||||
* (See 3GPP2 C.S0015-B, v2, 4.5.11)
|
||||
*/
|
||||
public boolean userAckReq;
|
||||
public boolean deliveryAckReq;
|
||||
public boolean readAckReq;
|
||||
public boolean reportReq;
|
||||
|
||||
/**
|
||||
* The number of Messages element (8-bit value) is a decimal number in the 0 to 99 range
|
||||
* representing the number of messages stored at the Voice Mail System. This element is
|
||||
* used by the Voice Mail Notification service.
|
||||
* (See 3GPP2 C.S0015-B, v2, 4.5.12)
|
||||
*/
|
||||
public int numberOfMessages;
|
||||
|
||||
//public int alert;
|
||||
//public int language;
|
||||
|
||||
/**
|
||||
* 4-bit or 8-bit value that indicates the number to be dialed in reply to a
|
||||
* received SMS message.
|
||||
* (See 3GPP2 C.S0015-B, v2, 4.5.15)
|
||||
*/
|
||||
public CdmaSmsAddress callbackNumber;
|
||||
|
||||
/**
|
||||
* 2-bit value that is used to indicate to the mobile station when to display
|
||||
* the received message.
|
||||
* (See 3GPP2 C.S0015-B, v2, 4.5.16)
|
||||
*/
|
||||
public byte displayMode = DISPLAY_DEFAULT;
|
||||
|
||||
/**
|
||||
* First component of the Message status, that indicates if an error has occurred
|
||||
* and whether the error is considered permanent or temporary.
|
||||
* (See 3GPP2 C.S0015-B, v2, 4.5.21)
|
||||
*/
|
||||
public int errorClass = ERROR_UNDEFINED;
|
||||
|
||||
/**
|
||||
* Second component of the Message status, that indicates if an error has occurred
|
||||
* and the cause of the error.
|
||||
* (See 3GPP2 C.S0015-B, v2, 4.5.21)
|
||||
*/
|
||||
public int messageStatus = STATUS_UNDEFINED;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma.sms;
|
||||
|
||||
import com.android.internal.telephony.SmsAddress;
|
||||
|
||||
public class CdmaSmsAddress extends SmsAddress {
|
||||
/**
|
||||
* digit mode indicators
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
|
||||
*/
|
||||
static public final int DIGIT_MODE_4BIT_DTMF = 0x00;
|
||||
static public final int DIGIT_MODE_8BIT_CHAR = 0x01;
|
||||
|
||||
/**
|
||||
* number mode indicators
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
|
||||
*/
|
||||
static public final int NUMBER_MODE_NOT_DATA_NETWORK = 0x00;
|
||||
static public final int NUMBER_MODE_DATA_NETWORK = 0x01;
|
||||
|
||||
/**
|
||||
* number types for data networks
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
|
||||
*/
|
||||
static public final int TON_UNKNOWN = 0x00;
|
||||
static public final int TON_INTERNATIONAL_OR_IP = 0x01;
|
||||
static public final int TON_NATIONAL_OR_EMAIL = 0x02;
|
||||
static public final int TON_NETWORK = 0x03;
|
||||
static public final int TON_SUBSCRIBER = 0x04;
|
||||
static public final int TON_ALPHANUMERIC = 0x05;
|
||||
static public final int TON_ABBREVIATED = 0x06;
|
||||
static public final int TON_RESERVED = 0x07;
|
||||
|
||||
/**
|
||||
* maximum lengths for fields as defined in ril_cdma_sms.h
|
||||
*/
|
||||
static public final int SMS_ADDRESS_MAX = 36;
|
||||
static public final int SMS_SUBADDRESS_MAX = 36;
|
||||
|
||||
/**
|
||||
* Supported numbering plan identification
|
||||
* (See C.S005-D, v1.0, table 2.7.1.3.2.4-3)
|
||||
*/
|
||||
static public final int NUMBERING_PLAN_UNKNOWN = 0x0;
|
||||
static public final int NUMBERING_PLAN_ISDN_TELEPHONY = 0x1;
|
||||
//static protected final int NUMBERING_PLAN_DATA = 0x3;
|
||||
//static protected final int NUMBERING_PLAN_TELEX = 0x4;
|
||||
//static protected final int NUMBERING_PLAN_PRIVATE = 0x9;
|
||||
|
||||
/**
|
||||
* 1-bit value that indicates whether the address digits are 4-bit DTMF codes
|
||||
* or 8-bit codes.
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
|
||||
*/
|
||||
public byte digitMode;
|
||||
|
||||
/**
|
||||
* 1-bit value that indicates whether the address type is a data network address or not.
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
|
||||
*/
|
||||
public byte numberMode;
|
||||
|
||||
// use parent class member ton instead public byte numberType;
|
||||
|
||||
/**
|
||||
* 0 or 4-bit value that indicates which numbering plan identification is set.
|
||||
* (See 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3)
|
||||
*/
|
||||
public byte numberPlan;
|
||||
|
||||
/**
|
||||
* This field shall be set to the number of address digits
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
|
||||
*/
|
||||
public byte numberOfDigits;
|
||||
|
||||
// use parent class member orig_bytes instead of public byte[] digits;
|
||||
|
||||
// Constructor
|
||||
public CdmaSmsAddress(){
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma.sms;
|
||||
|
||||
import com.android.internal.telephony.SmsHeader;
|
||||
|
||||
/*
|
||||
* The SMSDataCoding class encodes and decodes CDMA SMS messages.
|
||||
*/
|
||||
public class SmsDataCoding {
|
||||
private final static String TAG = "CDMA_SMS_JNI";
|
||||
|
||||
private final static int CDMA_SMS_WMS_MASK_BD_NULL = 0x00000000;
|
||||
private final static int CDMA_SMS_WMS_MASK_BD_MSG_ID = 0x00000001;
|
||||
private final static int CDMA_SMS_WMS_MASK_BD_USER_DATA = 0x00000002;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_USER_RESP = 0x00000004;
|
||||
private final static int CDMA_SMS_WMS_MASK_BD_MC_TIME = 0x00000008;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_VALID_ABS = 0x00000010;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_VALID_REL = 0x00000020;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_DEFER_ABS = 0x00000040;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_DEFER_REL = 0x00000080;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_PRIORITY = 0x00000100;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_PRIVACY = 0x00000200;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_REPLY_OPTION = 0x00000400;
|
||||
private final static int CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS = 0x00000800;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_ALERT = 0x00001000;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_LANGUAGE = 0x00002000;
|
||||
private final static int CDMA_SMS_WMS_MASK_BD_CALLBACK = 0x00004000;
|
||||
private final static int CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE = 0x00008000;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_SCPT_DATA = 0x00010000;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_SCPT_RESULT = 0x00020000;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_DEPOSIT_INDEX = 0x00040000;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_DELIVERY_STATUS = 0x00080000;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_IP_ADDRESS = 0x10000000;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_RSN_NO_NOTIFY = 0x20000000;
|
||||
// private final static int CDMA_SMS_WMS_MASK_BD_OTHER = 0x40000000;
|
||||
|
||||
/**
|
||||
* Successful operation.
|
||||
*/
|
||||
private static final int JNI_CDMA_SMS_SUCCESS = 0;
|
||||
|
||||
/**
|
||||
* General failure.
|
||||
*/
|
||||
private static final int JNI_CDMA_SMS_FAILURE = 1;
|
||||
|
||||
/**
|
||||
* Data length is out of length.
|
||||
*/
|
||||
private static final int JNI_CDMA_SMS_DATA_LEN_OUT_OF_RANGE = 2;
|
||||
|
||||
/**
|
||||
* Class name unknown.
|
||||
*/
|
||||
private static final int JNI_CDMA_SMS_CLASS_UNKNOWN = 3;
|
||||
|
||||
/**
|
||||
* Field ID unknown.
|
||||
*/
|
||||
private static final int JNI_CDMA_SMS_FIELD_ID_UNKNOWN = 4;
|
||||
|
||||
/**
|
||||
* Memory allocation failed.
|
||||
*/
|
||||
private static final int JNI_CDMA_SMS_OUT_OF_MEMORY = 5;
|
||||
|
||||
/**
|
||||
* Encode SMS.
|
||||
*
|
||||
* @param bearerData an instance of BearerData.
|
||||
*
|
||||
* @return the encoded SMS as byte[].
|
||||
*/
|
||||
public static byte[] encodeCdmaSms(BearerData bearerData) {
|
||||
byte[] encodedSms;
|
||||
|
||||
if( nativeCdmaSmsConstructClientBD() == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
|
||||
// check bearer data and generate bit mask
|
||||
generateBearerDataBitMask(bearerData);
|
||||
encodedSms = startEncoding(bearerData);
|
||||
|
||||
if( nativeCdmaSmsDestructClientBD() == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
return encodedSms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode SMS.
|
||||
*
|
||||
* @param SmsData the encoded SMS.
|
||||
*
|
||||
* @return an instance of BearerData.
|
||||
*/
|
||||
public static BearerData decodeCdmaSms(byte[] SmsData) {
|
||||
BearerData bearerData;
|
||||
|
||||
if( nativeCdmaSmsConstructClientBD() == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
|
||||
bearerData = startDecoding(SmsData);
|
||||
|
||||
if( nativeCdmaSmsDestructClientBD() == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
return bearerData;
|
||||
}
|
||||
|
||||
private static void generateBearerDataBitMask(BearerData bearerData) {
|
||||
// initial
|
||||
bearerData.mask = CDMA_SMS_WMS_MASK_BD_NULL;
|
||||
|
||||
// check message type
|
||||
if (bearerData.messageType != 0){
|
||||
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_MSG_ID;
|
||||
}
|
||||
|
||||
// check mUserData
|
||||
if (bearerData.userData != null){
|
||||
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_USER_DATA;
|
||||
}
|
||||
|
||||
// check mTimeStamp
|
||||
if (bearerData.timeStamp != null){
|
||||
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_MC_TIME;
|
||||
}
|
||||
|
||||
// check mNumberOfMessages
|
||||
if (bearerData.numberOfMessages > 0){
|
||||
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS;
|
||||
}
|
||||
|
||||
// check mCallbackNumber
|
||||
if(bearerData.callbackNumber != null){
|
||||
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_CALLBACK;
|
||||
}
|
||||
|
||||
// check DisplayMode
|
||||
if(bearerData.displayMode == BearerData.DISPLAY_DEFAULT ||
|
||||
bearerData.displayMode == BearerData.DISPLAY_IMMEDIATE ||
|
||||
bearerData.displayMode == BearerData.DISPLAY_USER){
|
||||
bearerData.mask |= CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] startEncoding(BearerData bearerData) {
|
||||
int m_id;
|
||||
byte[] m_data;
|
||||
int dataLength;
|
||||
byte[] encodedSms;
|
||||
int nbrOfHeaders = 0;
|
||||
|
||||
if( nativeCdmaSmsSetBearerDataPrimitives(bearerData) == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((bearerData.mask & CDMA_SMS_WMS_MASK_BD_USER_DATA) == CDMA_SMS_WMS_MASK_BD_USER_DATA){
|
||||
if( nativeCdmaSmsSetUserData(bearerData.userData) == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
|
||||
if (bearerData.userData.userDataHeader != null){
|
||||
nbrOfHeaders = bearerData.userData.userDataHeader.nbrOfHeaders;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nbrOfHeaders; i++) {
|
||||
m_id = bearerData.userData.userDataHeader.getElements().get(i).getID();
|
||||
m_data = bearerData.userData.userDataHeader.getElements().get(i).getData();
|
||||
dataLength = m_data.length;
|
||||
if( nativeCdmaSmsSetUserDataHeader(m_id, m_data, dataLength, i)
|
||||
== JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((bearerData.mask & CDMA_SMS_WMS_MASK_BD_CALLBACK) == CDMA_SMS_WMS_MASK_BD_CALLBACK) {
|
||||
if( nativeCdmaSmsSetSmsAddress(bearerData.callbackNumber) == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* call native method to encode SMS */
|
||||
encodedSms = nativeCdmaSmsEncodeSms();
|
||||
|
||||
return encodedSms;
|
||||
}
|
||||
|
||||
private static BearerData startDecoding(byte[] SmsData) {
|
||||
BearerData bData = new BearerData();
|
||||
byte[] udhData;
|
||||
|
||||
/* call native method to decode SMS */
|
||||
if( nativeCdmaSmsDecodeSms(SmsData) == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
|
||||
if( nativeCdmaSmsGetBearerDataPrimitives(bData) == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((bData.mask & CDMA_SMS_WMS_MASK_BD_USER_DATA) == CDMA_SMS_WMS_MASK_BD_USER_DATA) {
|
||||
bData.userData = new UserData();
|
||||
if( nativeCdmaSmsGetUserData(bData.userData) == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
|
||||
udhData = nativeCdmaSmsGetUserDataHeader();
|
||||
if (udhData != null) {
|
||||
bData.userData.userDataHeader = SmsHeader.parse(udhData);
|
||||
}
|
||||
}
|
||||
|
||||
if ((bData.mask & CDMA_SMS_WMS_MASK_BD_CALLBACK) == CDMA_SMS_WMS_MASK_BD_CALLBACK) {
|
||||
bData.callbackNumber = new CdmaSmsAddress();
|
||||
if( nativeCdmaSmsGetSmsAddress(bData.callbackNumber) == JNI_CDMA_SMS_FAILURE){
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return bData;
|
||||
}
|
||||
|
||||
// native methods
|
||||
|
||||
/**
|
||||
* native method: Allocate memory for clientBD structure
|
||||
*
|
||||
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
|
||||
* #JNI_CDMA_SMS_FAILURE if fail.
|
||||
*/
|
||||
private static native int nativeCdmaSmsConstructClientBD();
|
||||
|
||||
/**
|
||||
* native method: Free memory used for clientBD structure
|
||||
*
|
||||
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
|
||||
* #JNI_CDMA_SMS_FAILURE if fail.
|
||||
*/
|
||||
private static native int nativeCdmaSmsDestructClientBD();
|
||||
|
||||
/**
|
||||
* native method: fill clientBD structure with bearerData primitives
|
||||
*
|
||||
* @param bearerData an instance of BearerData.
|
||||
*
|
||||
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
|
||||
* #JNI_CDMA_SMS_FAILURE if fail.
|
||||
*/
|
||||
private static native int nativeCdmaSmsSetBearerDataPrimitives(BearerData bearerData);
|
||||
|
||||
/**
|
||||
* native method: fill bearerData primitives with clientBD variables
|
||||
*
|
||||
* @param bearerData an instance of BearerData.
|
||||
*
|
||||
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
|
||||
* #JNI_CDMA_SMS_FAILURE if fail.
|
||||
*/
|
||||
private static native int nativeCdmaSmsGetBearerDataPrimitives(BearerData bearerData);
|
||||
|
||||
/**
|
||||
* native method: fill clientBD.user_data with UserData primitives
|
||||
*
|
||||
* @param userData an instance of UserData.
|
||||
*
|
||||
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
|
||||
* #JNI_CDMA_SMS_FAILURE if fail.
|
||||
*/
|
||||
private static native int nativeCdmaSmsSetUserData(UserData userData);
|
||||
|
||||
/**
|
||||
* native method: fill UserData primitives with clientBD.user_data
|
||||
*
|
||||
* @param userData an instance of UserData.
|
||||
*
|
||||
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
|
||||
* #JNI_CDMA_SMS_FAILURE if fail.
|
||||
*/
|
||||
private static native int nativeCdmaSmsGetUserData(UserData userData);
|
||||
|
||||
/**
|
||||
* native method: fill clientBD.user_data.headers with UserDataHeader primitives
|
||||
*
|
||||
* @param ID ID of element.
|
||||
* @param data element data.
|
||||
* @param dataLength data length
|
||||
* @param index index of element
|
||||
*
|
||||
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
|
||||
* #JNI_CDMA_SMS_FAILURE if fail.
|
||||
*/
|
||||
private static native int nativeCdmaSmsSetUserDataHeader(
|
||||
int ID, byte[] data, int dataLength, int index);
|
||||
|
||||
/**
|
||||
* native method: fill UserDataHeader primitives with clientBD.user_data.headers
|
||||
*
|
||||
* @return user data headers
|
||||
*/
|
||||
private static native byte[] nativeCdmaSmsGetUserDataHeader();
|
||||
|
||||
/**
|
||||
* native method: fill clientBD.callback with SmsAddress primitives
|
||||
*
|
||||
* @param smsAddr an instance of SmsAddress.
|
||||
*
|
||||
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
|
||||
* #JNI_CDMA_SMS_FAILURE if fail.
|
||||
*/
|
||||
private static native int nativeCdmaSmsSetSmsAddress(CdmaSmsAddress smsAddr);
|
||||
|
||||
/**
|
||||
* native method: fill SmsAddress primitives with clientBD.callback
|
||||
*
|
||||
* @param smsAddr an instance of SmsAddress.
|
||||
*
|
||||
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
|
||||
* #JNI_CDMA_SMS_FAILURE if fail.
|
||||
*/
|
||||
private static native int nativeCdmaSmsGetSmsAddress(CdmaSmsAddress smsAddr);
|
||||
|
||||
/**
|
||||
* native method: call encoding functions and get encoded SMS
|
||||
*
|
||||
* @return the encoded SMS
|
||||
*/
|
||||
private static native byte[] nativeCdmaSmsEncodeSms();
|
||||
|
||||
/**
|
||||
* native method: call decode functions
|
||||
*
|
||||
* @param encodedSMS encoded SMS.
|
||||
*
|
||||
* @return #JNI_CDMA_SMS_SUCCESS if succeed.
|
||||
* #JNI_CDMA_SMS_FAILURE if fail.
|
||||
*/
|
||||
private static native int nativeCdmaSmsDecodeSms(byte[] encodedSMS);
|
||||
|
||||
/**
|
||||
* Load the shared library to link the native methods.
|
||||
*/
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("cdma_sms_jni");
|
||||
}
|
||||
catch (UnsatisfiedLinkError ule) {
|
||||
System.err.println("WARNING: Could not load cdma_sms_jni.so");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.telephony.cdma.sms;
|
||||
|
||||
|
||||
public final class SmsEnvelope{
|
||||
/**
|
||||
* Message Types
|
||||
* (See 3GPP2 C.S0015-B 3.4.1)
|
||||
*/
|
||||
static public final int MESSAGE_TYPE_POINT_TO_POINT = 0x00;
|
||||
static public final int MESSAGE_TYPE_BROADCAST = 0x01;
|
||||
static public final int MESSAGE_TYPE_ACKNOWLEDGE = 0x02;
|
||||
|
||||
/**
|
||||
* Supported Teleservices
|
||||
* (See 3GPP2 N.S0005 and TIA-41)
|
||||
*/
|
||||
static public final int TELESERVICE_NOT_SET = 0x0000;
|
||||
static public final int TELESERVICE_WMT = 0x1002;
|
||||
static public final int TELESERVICE_VMN = 0x1003;
|
||||
static public final int TELESERVICE_WAP = 0x1004;
|
||||
static public final int TELESERVICE_WEMT = 0x1005;
|
||||
|
||||
// ServiceCategories for Cell Broadcast, see 3GPP2 C.R1001 table 9.3.1-1
|
||||
//static public final int SERVICECATEGORY_EMERGENCY = 0x0010;
|
||||
//...
|
||||
|
||||
/**
|
||||
* maximum lengths for fields as defined in ril_cdma_sms.h
|
||||
*/
|
||||
static public final int SMS_BEARER_DATA_MAX = 255;
|
||||
|
||||
/**
|
||||
* Provides the type of a SMS message like point to point, broadcast or acknowledge
|
||||
*/
|
||||
public int messageType;
|
||||
|
||||
/**
|
||||
* The 16-bit Teleservice parameter identifies which upper layer service access point is sending
|
||||
* or receiving the message.
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.1)
|
||||
*/
|
||||
public int teleService = TELESERVICE_NOT_SET;
|
||||
|
||||
/**
|
||||
* The 16-bit service category parameter identifies the type of service provided
|
||||
* by the SMS message.
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.2)
|
||||
*/
|
||||
public int serviceCategory;
|
||||
|
||||
/**
|
||||
* The origination address identifies the originator of the SMS message.
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.4)
|
||||
*/
|
||||
public CdmaSmsAddress origAddress;
|
||||
|
||||
/**
|
||||
* The destination address identifies the target of the SMS message.
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.4)
|
||||
*/
|
||||
public CdmaSmsAddress destAddress;
|
||||
|
||||
/**
|
||||
* The 6-bit bearer reply parameter is used to request the return of a
|
||||
* SMS Acknowledge Message.
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.5)
|
||||
*/
|
||||
public int bearerReply;
|
||||
|
||||
/**
|
||||
* Cause Code values:
|
||||
* The cause code parameters are an indication whether an SMS error has occurred and if so,
|
||||
* whether the condition is considered temporary or permanent.
|
||||
* ReplySeqNo 6-bit value,
|
||||
* ErrorClass 2-bit value,
|
||||
* CauseCode 0-bit or 8-bit value
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.6)
|
||||
*/
|
||||
public byte replySeqNo;
|
||||
public byte errorClass;
|
||||
public byte causeCode;
|
||||
|
||||
/**
|
||||
* encoded bearer data
|
||||
* (See 3GPP2 C.S0015-B, v2, 3.4.3.7)
|
||||
*/
|
||||
public byte[] bearerData;
|
||||
|
||||
public SmsEnvelope() {
|
||||
// nothing to see here
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user