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:
Wink Saville
2009-04-02 11:00:54 -07:00
committed by The Android Open Source Project
parent 3afdd56470
commit 04e71b3db8
189 changed files with 24484 additions and 8162 deletions

View File

@@ -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();
}
}
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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.
*/

View File

@@ -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;
}
}

View 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;
}

View 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: [&lt;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 &amp; 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();
}
}
}

View File

@@ -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) {

View 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);
}
}

View File

@@ -0,0 +1,5 @@
<HTML>
<BODY>
Provides APIs for utilizing CDMA-specific telephony features.
</BODY>
</HTML>

View File

@@ -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
*

View File

@@ -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

View File

@@ -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)

View File

@@ -14,6 +14,7 @@
** limitations under the License.
*/
package com.android.internal.telephony.gsm;
package com.android.internal.telephony;
parcelable AdnRecord;

View 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 = "";
}
}
}

View File

@@ -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;

View File

@@ -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&lt;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;
}
}
}

View 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() {
}
}

View File

@@ -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() {

View File

@@ -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

View 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);
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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();
}

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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).

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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 + "'");
}
}

View File

@@ -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(' ');
}
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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
*

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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));
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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.");
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View 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);
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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;
}
}
}

View 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();
}
}

View File

@@ -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);

View File

@@ -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();
}
/**

View File

@@ -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();
}
}

View File

@@ -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;
}

View File

@@ -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));
}
};
}
};
}

View File

@@ -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];
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -14,6 +14,6 @@
** limitations under the License.
*/
package com.android.internal.telephony.gsm;
package com.android.internal.telephony;
parcelable SmsRawData;

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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>,

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}

View 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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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);
}
}

View 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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 &amp; 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);
}
}
}

View File

@@ -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";
}

View File

@@ -0,0 +1,6 @@
<HTML>
<BODY>
Provides classes to control or read data from CDMA phones.
@hide
</BODY>
</HTML>

View File

@@ -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;
}

View File

@@ -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(){
}
}

View File

@@ -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");
}
}
}

View File

@@ -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