From 767a662ecde33c3979bf02b793d392aca0403162 Mon Sep 17 00:00:00 2001
From: Wink Saville <>
Date: Thu, 2 Apr 2009 01:37:02 -0700
Subject: AI 144185: Integrate cdma into the main code base.
Automated import of CL 144185
---
.../internal/telephony/ATResponseParser.java | 4 +-
.../com/android/internal/telephony/AdnRecord.aidl | 20 +
.../com/android/internal/telephony/AdnRecord.java | 283 ++
.../android/internal/telephony/AdnRecordCache.java | 339 +++
.../internal/telephony/AdnRecordLoader.java | 285 ++
.../android/internal/telephony/BaseCommands.java | 580 ++++
.../java/com/android/internal/telephony/Call.java | 49 +-
.../internal/telephony/CallForwardInfo.java | 42 +
.../android/internal/telephony/CallTracker.java | 123 +
.../internal/telephony/CallerInfoAsyncQuery.java | 2 +-
.../internal/telephony/CommandException.java | 83 +
.../internal/telephony/CommandsInterface.java | 1193 ++++++++
.../com/android/internal/telephony/Connection.java | 57 +-
.../android/internal/telephony/DataConnection.java | 299 ++
.../internal/telephony/DataConnectionTracker.java | 313 ++
.../com/android/internal/telephony/DataLink.java | 40 +
.../internal/telephony/DataLinkInterface.java | 77 +
.../internal/telephony/DefaultPhoneNotifier.java | 6 +-
.../com/android/internal/telephony/DriverCall.java | 155 +
.../internal/telephony/EncodeException.java | 35 +
.../android/internal/telephony/GsmAlphabet.java | 798 +++++
.../android/internal/telephony/IIccPhoneBook.aidl | 101 +
.../android/internal/telephony/IPhoneSubInfo.aidl | 16 +-
.../java/com/android/internal/telephony/ISms.aidl | 115 +
.../com/android/internal/telephony/ITelephony.aidl | 15 +-
.../com/android/internal/telephony/IccCard.java | 207 ++
.../internal/telephony/IccCardApplication.java | 178 ++
.../android/internal/telephony/IccCardStatus.java | 86 +
.../android/internal/telephony/IccConstants.java | 59 +
.../android/internal/telephony/IccException.java | 30 +
.../android/internal/telephony/IccFileHandler.java | 513 ++++
.../internal/telephony/IccFileNotFound.java | 34 +
.../internal/telephony/IccFileTypeMismatch.java | 30 +
.../android/internal/telephony/IccIoResult.java | 70 +
.../telephony/IccPhoneBookInterfaceManager.java | 266 ++
.../IccPhoneBookInterfaceManagerProxy.java | 75 +
.../android/internal/telephony/IccProvider.java | 456 +++
.../com/android/internal/telephony/IccRecords.java | 237 ++
.../internal/telephony/IccSmsInterfaceManager.java | 166 ++
.../telephony/IccSmsInterfaceManagerProxy.java | 66 +
.../com/android/internal/telephony/IccUtils.java | 487 ++++
.../internal/telephony/IccVmFixedException.java | 32 +
.../telephony/IccVmNotSupportedException.java | 32 +
.../com/android/internal/telephony/MmiCode.java | 4 +-
.../java/com/android/internal/telephony/Phone.java | 570 ++--
.../com/android/internal/telephony/PhoneBase.java | 326 ++-
.../android/internal/telephony/PhoneFactory.java | 144 +-
.../com/android/internal/telephony/PhoneProxy.java | 675 +++++
.../telephony/PhoneStateIntentReceiver.java | 6 +-
.../android/internal/telephony/PhoneSubInfo.java | 36 +-
.../internal/telephony/PhoneSubInfoProxy.java | 85 +
.../java/com/android/internal/telephony/RIL.java | 3050 ++++++++++++++++++++
.../android/internal/telephony/RILConstants.java | 236 ++
.../android/internal/telephony/SMSDispatcher.java | 744 +++++
.../internal/telephony/ServiceStateTracker.java | 244 ++
.../com/android/internal/telephony/SimCard.java | 208 --
.../com/android/internal/telephony/SmsAddress.java | 65 +
.../com/android/internal/telephony/SmsHeader.java | 242 ++
.../android/internal/telephony/SmsMessageBase.java | 388 +++
.../com/android/internal/telephony/SmsRawData.aidl | 19 +
.../com/android/internal/telephony/SmsRawData.java | 62 +
.../android/internal/telephony/SmsResponse.java | 34 +
.../internal/telephony/TelephonyEventLog.java | 33 +
.../internal/telephony/TelephonyIntents.java | 20 +-
.../internal/telephony/TelephonyProperties.java | 23 +-
.../android/internal/telephony/WapPushOverSms.java | 5 +-
.../android/internal/telephony/cdma/CDMAPhone.java | 916 ++++++
.../internal/telephony/cdma/CallFailCause.java | 50 +
.../android/internal/telephony/cdma/CdmaCall.java | 209 ++
.../internal/telephony/cdma/CdmaCallTracker.java | 860 ++++++
.../internal/telephony/cdma/CdmaConnection.java | 705 +++++
.../telephony/cdma/CdmaDataConnection.java | 318 ++
.../telephony/cdma/CdmaDataConnectionTracker.java | 929 ++++++
.../internal/telephony/cdma/CdmaSMSDispatcher.java | 394 +++
.../telephony/cdma/CdmaServiceStateTracker.java | 1016 +++++++
.../internal/telephony/cdma/FeatureCode.java | 312 ++
.../android/internal/telephony/cdma/RuimCard.java | 522 ++++
.../internal/telephony/cdma/RuimFileHandler.java | 79 +
.../cdma/RuimPhoneBookInterfaceManager.java | 101 +
.../internal/telephony/cdma/RuimRecords.java | 380 +++
.../telephony/cdma/RuimSmsInterfaceManager.java | 192 ++
.../internal/telephony/cdma/SmsMessage.java | 905 ++++++
.../android/internal/telephony/cdma/TtyIntent.java | 46 +
.../android/internal/telephony/cdma/package.html | 6 +
.../internal/telephony/cdma/sms/BearerData.java | 192 ++
.../telephony/cdma/sms/CdmaSmsAddress.java | 98 +
.../internal/telephony/cdma/sms/SmsDataCoding.java | 371 +++
.../internal/telephony/cdma/sms/SmsEnvelope.java | 110 +
.../internal/telephony/cdma/sms/UserData.java | 63 +
.../internal/telephony/cdma/sms/package.html | 6 +
.../android/internal/telephony/gsm/AdnRecord.aidl | 19 -
.../android/internal/telephony/gsm/AdnRecord.java | 570 ----
.../internal/telephony/gsm/AdnRecordCache.java | 346 ---
.../internal/telephony/gsm/BaseCommands.java | 367 ---
.../internal/telephony/gsm/CallForwardInfo.java | 44 -
.../internal/telephony/gsm/CallTracker.java | 984 -------
.../internal/telephony/gsm/CommandException.java | 85 -
.../internal/telephony/gsm/CommandsInterface.java | 926 ------
.../telephony/gsm/DataConnectionTracker.java | 1836 ------------
.../android/internal/telephony/gsm/DataLink.java | 41 -
.../internal/telephony/gsm/DataLinkInterface.java | 77 -
.../android/internal/telephony/gsm/DriverCall.java | 162 --
.../internal/telephony/gsm/EncodeException.java | 39 -
.../android/internal/telephony/gsm/GSMCall.java | 221 --
.../internal/telephony/gsm/GSMConnection.java | 767 -----
.../android/internal/telephony/gsm/GSMPhone.java | 732 +++--
.../internal/telephony/gsm/GsmAlphabet.java | 813 ------
.../android/internal/telephony/gsm/GsmCall.java | 208 ++
.../internal/telephony/gsm/GsmCallTracker.java | 908 ++++++
.../internal/telephony/gsm/GsmConnection.java | 732 +++++
.../telephony/gsm/GsmDataConnectionTracker.java | 1718 +++++++++++
.../android/internal/telephony/gsm/GsmMmiCode.java | 324 +--
.../internal/telephony/gsm/GsmSMSDispatcher.java | 379 +++
.../telephony/gsm/GsmServiceStateTracker.java | 1588 ++++++++++
.../android/internal/telephony/gsm/GsmSimCard.java | 506 ----
.../internal/telephony/gsm/GsmSmsAddress.java | 148 +
.../internal/telephony/gsm/ISimPhoneBook.aidl | 101 -
.../com/android/internal/telephony/gsm/ISms.aidl | 115 -
.../android/internal/telephony/gsm/MccTable.java | 6 +-
.../internal/telephony/gsm/NetworkInfo.aidl | 4 +-
.../internal/telephony/gsm/NetworkInfo.java | 63 +-
.../internal/telephony/gsm/PDPContextState.java | 3 +-
.../internal/telephony/gsm/PdpConnection.java | 418 +--
.../android/internal/telephony/gsm/PppLink.java | 50 +-
.../com/android/internal/telephony/gsm/RIL.java | 2586 -----------------
.../internal/telephony/gsm/RILConstants.java | 177 --
.../internal/telephony/gsm/SIMFileHandler.java | 500 +---
.../android/internal/telephony/gsm/SIMRecords.java | 399 ++-
.../internal/telephony/gsm/SMSDispatcher.java | 979 -------
.../telephony/gsm/ServiceStateTracker.java | 1696 -----------
.../android/internal/telephony/gsm/SimCard.java | 512 ++++
.../internal/telephony/gsm/SimConstants.java | 55 -
.../internal/telephony/gsm/SimException.java | 58 -
.../internal/telephony/gsm/SimFileNotFound.java | 38 -
.../telephony/gsm/SimFileTypeMismatch.java | 33 -
.../internal/telephony/gsm/SimIoResult.java | 75 -
.../gsm/SimPhoneBookInterfaceManager.java | 233 +-
.../internal/telephony/gsm/SimProvider.java | 455 ---
.../telephony/gsm/SimSmsInterfaceManager.java | 181 +-
.../com/android/internal/telephony/gsm/SimTlv.java | 31 +-
.../android/internal/telephony/gsm/SimUtils.java | 476 ---
.../android/internal/telephony/gsm/SmsHeader.java | 236 --
.../android/internal/telephony/gsm/SmsMessage.java | 1058 +++++++
.../android/internal/telephony/gsm/SmsRawData.aidl | 19 -
.../android/internal/telephony/gsm/SmsRawData.java | 62 -
.../internal/telephony/gsm/SmsResponse.java | 34 -
.../internal/telephony/gsm/TelephonyEventLog.java | 33 -
.../android/internal/telephony/gsm/stk/BerTlv.java | 12 +-
.../internal/telephony/gsm/stk/CommandParams.java | 2 +-
.../telephony/gsm/stk/CommandParamsFactory.java | 2 +-
.../telephony/gsm/stk/ComprehensionTlv.java | 10 +-
.../internal/telephony/gsm/stk/IconLoader.java | 28 +-
.../telephony/gsm/stk/ImageDescriptor.java | 5 +-
.../internal/telephony/gsm/stk/ResponseData.java | 4 +-
.../telephony/gsm/stk/RilMessageDecoder.java | 4 +-
.../internal/telephony/gsm/stk/StkService.java | 50 +-
.../internal/telephony/gsm/stk/ValueParser.java | 8 +-
.../internal/telephony/test/SimulatedCommands.java | 380 ++-
.../telephony/test/SimulatedGsmCallState.java | 104 +-
159 files changed, 32003 insertions(+), 17885 deletions(-)
create mode 100644 telephony/java/com/android/internal/telephony/AdnRecord.aidl
create mode 100644 telephony/java/com/android/internal/telephony/AdnRecord.java
create mode 100644 telephony/java/com/android/internal/telephony/AdnRecordCache.java
create mode 100644 telephony/java/com/android/internal/telephony/AdnRecordLoader.java
create mode 100644 telephony/java/com/android/internal/telephony/BaseCommands.java
create mode 100644 telephony/java/com/android/internal/telephony/CallForwardInfo.java
create mode 100644 telephony/java/com/android/internal/telephony/CallTracker.java
create mode 100644 telephony/java/com/android/internal/telephony/CommandException.java
create mode 100644 telephony/java/com/android/internal/telephony/CommandsInterface.java
create mode 100644 telephony/java/com/android/internal/telephony/DataConnection.java
create mode 100644 telephony/java/com/android/internal/telephony/DataConnectionTracker.java
create mode 100644 telephony/java/com/android/internal/telephony/DataLink.java
create mode 100644 telephony/java/com/android/internal/telephony/DataLinkInterface.java
create mode 100644 telephony/java/com/android/internal/telephony/DriverCall.java
create mode 100644 telephony/java/com/android/internal/telephony/EncodeException.java
create mode 100644 telephony/java/com/android/internal/telephony/GsmAlphabet.java
create mode 100644 telephony/java/com/android/internal/telephony/IIccPhoneBook.aidl
create mode 100644 telephony/java/com/android/internal/telephony/ISms.aidl
create mode 100644 telephony/java/com/android/internal/telephony/IccCard.java
create mode 100644 telephony/java/com/android/internal/telephony/IccCardApplication.java
create mode 100644 telephony/java/com/android/internal/telephony/IccCardStatus.java
create mode 100644 telephony/java/com/android/internal/telephony/IccConstants.java
create mode 100644 telephony/java/com/android/internal/telephony/IccException.java
create mode 100644 telephony/java/com/android/internal/telephony/IccFileHandler.java
create mode 100644 telephony/java/com/android/internal/telephony/IccFileNotFound.java
create mode 100644 telephony/java/com/android/internal/telephony/IccFileTypeMismatch.java
create mode 100644 telephony/java/com/android/internal/telephony/IccIoResult.java
create mode 100644 telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
create mode 100644 telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java
create mode 100644 telephony/java/com/android/internal/telephony/IccProvider.java
create mode 100644 telephony/java/com/android/internal/telephony/IccRecords.java
create mode 100644 telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
create mode 100644 telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java
create mode 100644 telephony/java/com/android/internal/telephony/IccUtils.java
create mode 100644 telephony/java/com/android/internal/telephony/IccVmFixedException.java
create mode 100644 telephony/java/com/android/internal/telephony/IccVmNotSupportedException.java
create mode 100644 telephony/java/com/android/internal/telephony/PhoneProxy.java
create mode 100644 telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
create mode 100644 telephony/java/com/android/internal/telephony/RIL.java
create mode 100644 telephony/java/com/android/internal/telephony/RILConstants.java
create mode 100644 telephony/java/com/android/internal/telephony/SMSDispatcher.java
create mode 100644 telephony/java/com/android/internal/telephony/ServiceStateTracker.java
delete mode 100644 telephony/java/com/android/internal/telephony/SimCard.java
create mode 100644 telephony/java/com/android/internal/telephony/SmsAddress.java
create mode 100644 telephony/java/com/android/internal/telephony/SmsHeader.java
create mode 100644 telephony/java/com/android/internal/telephony/SmsMessageBase.java
create mode 100644 telephony/java/com/android/internal/telephony/SmsRawData.aidl
create mode 100644 telephony/java/com/android/internal/telephony/SmsRawData.java
create mode 100644 telephony/java/com/android/internal/telephony/SmsResponse.java
create mode 100644 telephony/java/com/android/internal/telephony/TelephonyEventLog.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/CallFailCause.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/FeatureCode.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/RuimCard.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/TtyIntent.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/package.html
create mode 100644 telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
create mode 100644 telephony/java/com/android/internal/telephony/cdma/sms/package.html
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/AdnRecord.aidl
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/AdnRecord.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/AdnRecordCache.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/BaseCommands.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/CallForwardInfo.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/CallTracker.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/CommandException.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/DataLink.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/DriverCall.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/EncodeException.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/GSMCall.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/GSMConnection.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java
create mode 100644 telephony/java/com/android/internal/telephony/gsm/GsmCall.java
create mode 100644 telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
create mode 100644 telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
create mode 100644 telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
create mode 100644 telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
create mode 100644 telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java
create mode 100644 telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/ISimPhoneBook.aidl
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/ISms.aidl
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/RIL.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/RILConstants.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
create mode 100644 telephony/java/com/android/internal/telephony/gsm/SimCard.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SimConstants.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SimException.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SimFileNotFound.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SimFileTypeMismatch.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SimIoResult.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SimProvider.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SimUtils.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SmsHeader.java
create mode 100644 telephony/java/com/android/internal/telephony/gsm/SmsMessage.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SmsRawData.aidl
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SmsRawData.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/SmsResponse.java
delete mode 100644 telephony/java/com/android/internal/telephony/gsm/TelephonyEventLog.java
(limited to 'telephony/java/com')
diff --git a/telephony/java/com/android/internal/telephony/ATResponseParser.java b/telephony/java/com/android/internal/telephony/ATResponseParser.java
index 93ec455..fdb0526 100644
--- a/telephony/java/com/android/internal/telephony/ATResponseParser.java
+++ b/telephony/java/com/android/internal/telephony/ATResponseParser.java
@@ -34,7 +34,7 @@ public class ATResponseParser
{
this.line = line;
}
-
+
public boolean
nextBoolean()
{
@@ -147,7 +147,7 @@ public class ATResponseParser
}
}
-
+
/** Throws ATParseEx if whitespace extends to the end of string */
private char
skipWhiteSpace (char c)
diff --git a/telephony/java/com/android/internal/telephony/AdnRecord.aidl b/telephony/java/com/android/internal/telephony/AdnRecord.aidl
new file mode 100644
index 0000000..b4a1a29
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/AdnRecord.aidl
@@ -0,0 +1,20 @@
+/*
+** 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;
+
+parcelable AdnRecord;
+
diff --git a/telephony/java/com/android/internal/telephony/AdnRecord.java b/telephony/java/com/android/internal/telephony/AdnRecord.java
new file mode 100644
index 0000000..5f40579
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/AdnRecord.java
@@ -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.Creators
of the first character
+ * after limit
septets have been reached, starting at
+ * index start
. This is used when dividing messages
+ * into units within the SMS message size limit.
+ *
+ * @param s source string
+ * @param start index of where to start counting septets
+ * @param limit maximum septets to include,
+ * e.g. MAX_USER_DATA_SEPTETS
+ * @return index of first character that won't fit, or the length
+ * of the entire string if everything fits
+ */
+ public static int
+ findGsmSeptetLimitIndex(String s, int start, int limit) {
+ int accumulator = 0;
+ int size = s.length();
+
+ for (int i = start; i < size; i++) {
+ accumulator += countGsmSeptets(s.charAt(i));
+ if (accumulator > limit) {
+ return i;
+ }
+ }
+ return size;
+ }
+
+ /**
+ * Returns the index into s
of the first character
+ * after limit
octets have been reached, starting at
+ * index start
. This is used when dividing messages
+ * in UCS2 encoding into units within the SMS message size limit.
+ *
+ * @param s source string
+ * @param start index of where to start counting septets
+ * @param limit maximum septets to include,
+ * e.g. MAX_USER_DATA_BYTES
+ * @return index of first character that won't fit, or the length
+ * of the entire string if everything fits
+ */
+ public static int
+ findUCS2LimitIndex(String s, int start, int limit) {
+ int numCharToBeEncoded = s.length() - start;
+ return ((numCharToBeEncoded*2 > limit)? limit/2: numCharToBeEncoded) + start;
+ }
+
+ /**
+ * Returns the index into s
of the first character
+ * after limit
septets/octets have been reached
+ * according to the encodingType
, starting at
+ * index start
. This is used when dividing messages
+ * units within the SMS message size limit.
+ *
+ * @param s source string
+ * @param start index of where to start counting septets
+ * @param limit maximum septets to include,
+ * e.g. MAX_USER_DATA_BYTES
+ * @return index of first character that won't fit, or the length
+ * of the entire string if everything fits
+ */
+ public static int
+ findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException {
+ if (encodingType == SmsMessage.ENCODING_7BIT) {
+ return findGsmSeptetLimitIndex(s, start, limit);
+ }
+ else if (encodingType == SmsMessage.ENCODING_16BIT) {
+ return findUCS2LimitIndex(s, start, limit);
+ }
+ else {
+ throw new EncodeException("Unsupported encoding type: " + encodingType);
+ }
+ }
+
+ // Set in the static initializer
+ private static int sGsmSpaceChar;
+
+ private static final SparseIntArray charToGsm = new SparseIntArray();
+ 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++);
+ charToGsm.put('\u00a5', i++);
+ charToGsm.put('\u00e8', i++);
+ charToGsm.put('\u00e9', i++);
+ charToGsm.put('\u00f9', i++);
+ charToGsm.put('\u00ec', i++);
+ charToGsm.put('\u00f2', i++);
+ charToGsm.put('\u00c7', i++);
+ charToGsm.put('\n', i++);
+ charToGsm.put('\u00d8', i++);
+ charToGsm.put('\u00f8', i++);
+ charToGsm.put('\r', i++);
+ charToGsm.put('\u00c5', i++);
+ charToGsm.put('\u00e5', i++);
+
+ charToGsm.put('\u0394', i++);
+ charToGsm.put('_', i++);
+ charToGsm.put('\u03a6', i++);
+ charToGsm.put('\u0393', i++);
+ charToGsm.put('\u039b', i++);
+ charToGsm.put('\u03a9', i++);
+ charToGsm.put('\u03a0', i++);
+ charToGsm.put('\u03a8', i++);
+ charToGsm.put('\u03a3', i++);
+ charToGsm.put('\u0398', i++);
+ charToGsm.put('\u039e', i++);
+ charToGsm.put('\uffff', i++);
+ charToGsm.put('\u00c6', i++);
+ charToGsm.put('\u00e6', i++);
+ charToGsm.put('\u00df', i++);
+ charToGsm.put('\u00c9', i++);
+
+ charToGsm.put(' ', i++);
+ charToGsm.put('!', i++);
+ charToGsm.put('"', i++);
+ charToGsm.put('#', i++);
+ charToGsm.put('\u00a4', i++);
+ charToGsm.put('%', i++);
+ charToGsm.put('&', i++);
+ charToGsm.put('\'', i++);
+ charToGsm.put('(', i++);
+ charToGsm.put(')', i++);
+ charToGsm.put('*', i++);
+ charToGsm.put('+', i++);
+ charToGsm.put(',', i++);
+ charToGsm.put('-', i++);
+ charToGsm.put('.', i++);
+ charToGsm.put('/', i++);
+
+ charToGsm.put('0', i++);
+ charToGsm.put('1', i++);
+ charToGsm.put('2', i++);
+ charToGsm.put('3', i++);
+ charToGsm.put('4', i++);
+ charToGsm.put('5', i++);
+ charToGsm.put('6', i++);
+ charToGsm.put('7', i++);
+ charToGsm.put('8', i++);
+ charToGsm.put('9', i++);
+ charToGsm.put(':', i++);
+ charToGsm.put(';', i++);
+ charToGsm.put('<', i++);
+ charToGsm.put('=', i++);
+ charToGsm.put('>', i++);
+ charToGsm.put('?', i++);
+
+ charToGsm.put('\u00a1', i++);
+ charToGsm.put('A', i++);
+ charToGsm.put('B', i++);
+ charToGsm.put('C', i++);
+ charToGsm.put('D', i++);
+ charToGsm.put('E', i++);
+ charToGsm.put('F', i++);
+ charToGsm.put('G', i++);
+ charToGsm.put('H', i++);
+ charToGsm.put('I', i++);
+ charToGsm.put('J', i++);
+ charToGsm.put('K', i++);
+ charToGsm.put('L', i++);
+ charToGsm.put('M', i++);
+ charToGsm.put('N', i++);
+ charToGsm.put('O', i++);
+
+ charToGsm.put('P', i++);
+ charToGsm.put('Q', i++);
+ charToGsm.put('R', i++);
+ charToGsm.put('S', i++);
+ charToGsm.put('T', i++);
+ charToGsm.put('U', i++);
+ charToGsm.put('V', i++);
+ charToGsm.put('W', i++);
+ charToGsm.put('X', i++);
+ charToGsm.put('Y', i++);
+ charToGsm.put('Z', i++);
+ charToGsm.put('\u00c4', i++);
+ charToGsm.put('\u00d6', i++);
+ charToGsm.put('\u0147', i++);
+ charToGsm.put('\u00dc', i++);
+ charToGsm.put('\u00a7', i++);
+
+ charToGsm.put('\u00bf', i++);
+ charToGsm.put('a', i++);
+ charToGsm.put('b', i++);
+ charToGsm.put('c', i++);
+ charToGsm.put('d', i++);
+ charToGsm.put('e', i++);
+ charToGsm.put('f', i++);
+ charToGsm.put('g', i++);
+ charToGsm.put('h', i++);
+ charToGsm.put('i', i++);
+ charToGsm.put('j', i++);
+ charToGsm.put('k', i++);
+ charToGsm.put('l', i++);
+ charToGsm.put('m', i++);
+ charToGsm.put('n', i++);
+ charToGsm.put('o', i++);
+
+ charToGsm.put('p', i++);
+ charToGsm.put('q', i++);
+ charToGsm.put('r', i++);
+ charToGsm.put('s', i++);
+ charToGsm.put('t', i++);
+ charToGsm.put('u', i++);
+ charToGsm.put('v', i++);
+ charToGsm.put('w', i++);
+ charToGsm.put('x', i++);
+ charToGsm.put('y', i++);
+ charToGsm.put('z', i++);
+ charToGsm.put('\u00e4', i++);
+ charToGsm.put('\u00f6', i++);
+ charToGsm.put('\u00f1', i++);
+ charToGsm.put('\u00fc', i++);
+ charToGsm.put('\u00e0', i++);
+
+
+ charToGsmExtended.put('\f', 10);
+ charToGsmExtended.put('^', 20);
+ charToGsmExtended.put('{', 40);
+ charToGsmExtended.put('}', 41);
+ charToGsmExtended.put('\\', 47);
+ charToGsmExtended.put('[', 60);
+ charToGsmExtended.put('~', 61);
+ charToGsmExtended.put(']', 62);
+ charToGsmExtended.put('|', 64);
+ charToGsmExtended.put('\u20ac', 101);
+
+ int size = charToGsm.size();
+ for (int j=0; j
private static IIccPhoneBook getSimPhoneBookInterface() + throws DeadObjectException { + IServiceManager sm = ServiceManagerNative.getDefault(); + IIccPhoneBook spb; + spb = IIccPhoneBook.Stub.asInterface(sm.getService("iccphonebook")); + return spb; +} + *+ */ + +interface IIccPhoneBook { + + /** + * Loads the AdnRecords in efid and returns them as a + * List of AdnRecords + * + * @param efid the EF id of a ADN-like SIM + * @return List of AdnRecord + */ + List
The following code snippet demonstrates a static method to + * retrieve the ISms interface from Android:
+ *private static ISms getSmsInterface() + throws DeadObjectException { + IServiceManager sm = ServiceManagerNative.getDefault(); + ISms ss; + ss = ISms.Stub.asInterface(sm.getService("isms")); + return ss; +} + *+ */ + +interface ISms { + /** + * Retrieves all messages currently stored on ICC. + * + * @return list of SmsRawData of all sms on ICC + */ + List
Intent
is
+ * broadcast when the message is successfully sent, or failed.
+ * The result code will be Activity.RESULT_OK for success,
+ * or one of these errors:
+ * RESULT_ERROR_GENERIC_FAILURE
+ * RESULT_ERROR_RADIO_OFF
+ * RESULT_ERROR_NULL_PDU
.
+ * @param deliveryIntent if not NULL this Intent
is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ */
+ void sendRawPdu(in byte[] smsc, in byte[] pdu, in PendingIntent sentIntent,
+ in PendingIntent 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 ArrayList
of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an ArrayList
of
+ * PendingIntent
s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be Activity.RESULT_OK for success,
+ * or one of these errors:
+ * RESULT_ERROR_GENERIC_FAILURE
+ * RESULT_ERROR_RADIO_OFF
+ * RESULT_ERROR_NULL_PDU
.
+ * @param deliveryIntents if not null, an ArrayList
of
+ * PendingIntent
s (one for each message part) that is
+ * broadcast when the corresponding message part has been delivered
+ * to the recipient. The raw pdu of the status report is in the
+ * extended data ("pdu").
+ */
+ void sendMultipartText(in String destinationAddress, in String scAddress,
+ in List parts, in List sentIntents,
+ in List deliveryIntents);
+
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 2b4195b..bab0603 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -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 dial
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();
+
}
+
diff --git a/telephony/java/com/android/internal/telephony/IccCard.java b/telephony/java/com/android/internal/telephony/IccCard.java
new file mode 100644
index 0000000..d7ad492
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccCard.java
@@ -0,0 +1,207 @@
+/*
+ * 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.Message;
+import android.os.Handler;
+
+/**
+ * {@hide}
+ */
+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 ICC is locked on PIN1 */
+ static public final String INTENT_VALUE_LOCKED_ON_PIN = "PIN";
+ /* PUK means ICC is locked on PUK1 */
+ static public final String INTENT_VALUE_LOCKED_ON_PUK = "PUK";
+ /* 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 ICC pin under
+ PIN_REQUIRED state, the query for ICC status returns UNKNOWN before it
+ turns to READY
+ */
+ public enum State {
+ UNKNOWN,
+ ABSENT,
+ PIN_REQUIRED,
+ PUK_REQUIRED,
+ NETWORK_LOCKED,
+ READY;
+
+ public boolean isPinLocked() {
+ return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
+ }
+ }
+
+ State getState();
+
+
+ /**
+ * Notifies handler of any transition into State.ABSENT
+ */
+ void registerForAbsent(Handler h, int what, Object obj);
+ void unregisterForAbsent(Handler h);
+
+ /**
+ * Notifies handler of any transition into State.isPinLocked()
+ */
+ void registerForLocked(Handler h, int what, Object obj);
+ void unregisterForLocked(Handler h);
+
+ /**
+ * Notifies handler of any transition into State.NETWORK_LOCKED
+ */
+ void registerForNetworkLocked(Handler h, int what, Object obj);
+ void unregisterForNetworkLocked(Handler h);
+
+ /**
+ * Supply the ICC PIN to the ICC
+ *
+ * When the operation is complete, onComplete will be sent to it's
+ * Handler.
+ *
+ * onComplete.obj will be an AsyncResult
+ *
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ *
+ * If the supplied PIN is incorrect:
+ * ((AsyncResult)onComplete.obj).exception != null
+ * && ((AsyncResult)onComplete.obj).exception
+ * instanceof com.android.internal.telephony.gsm.CommandException)
+ * && ((CommandException)(((AsyncResult)onComplete.obj).exception))
+ * .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
+ *
+ *
+ */
+
+ void supplyPin (String pin, Message onComplete);
+ void supplyPuk (String puk, String newPin, Message onComplete);
+ void supplyPin2 (String pin2, Message onComplete);
+ void supplyPuk2 (String puk2, String newPin2, Message onComplete);
+
+ /**
+ * Check whether ICC pin lock is enabled
+ * This is a sync call which returns the cached pin enabled state
+ *
+ * @return true for ICC locked enabled
+ * false for ICC locked disabled
+ */
+ boolean getIccLockEnabled ();
+
+ /**
+ * 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 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 setIccLockEnabled(boolean enabled, String password, Message onComplete);
+
+
+ /**
+ * 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
+ * @param newPassword is the new password
+ * @param onComplete
+ * onComplete.obj will be an AsyncResult
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ */
+ void changeIccLockPassword(String oldPassword, String newPassword,
+ Message onComplete);
+
+ /**
+ * Check whether ICC fdn (fixed dialing number) is enabled
+ * This is a sync call which returns the cached pin enabled state
+ *
+ * @return true for ICC fdn enabled
+ * false for ICC fdn disabled
+ */
+ boolean getIccFdnEnabled ();
+
+ /**
+ * 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 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 setIccFdnEnabled(boolean enabled, String password, Message onComplete);
+
+ /**
+ * 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
+ * @param newPassword is the new password
+ * @param onComplete
+ * onComplete.obj will be an AsyncResult
+ * ((AsyncResult)onComplete.obj).exception == null on success
+ * ((AsyncResult)onComplete.obj).exception != null on fail
+ */
+ void changeIccFdnPassword(String oldPassword, String newPassword,
+ Message onComplete);
+
+ void supplyNetworkDepersonalization (String pin, Message onComplete);
+
+ /**
+ * 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
+ *
+ * Please use this value when display Service Provider Name in idle mode
+ *
+ * Usage of this provider name in the UI is a common carrier requirement.
+ *
+ * Also available via Android property "gsm.sim.operator.alpha"
+ *
+ * @return Service Provider Name stored in ICC card
+ * null if no service provider name associated or the record is not
+ * yet available
+ *
+ */
+ String getServiceProviderName();
+}
diff --git a/telephony/java/com/android/internal/telephony/IccCardApplication.java b/telephony/java/com/android/internal/telephony/IccCardApplication.java
new file mode 100644
index 0000000..9f60a6c
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccCardApplication.java
@@ -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;
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/IccCardStatus.java b/telephony/java/com/android/internal/telephony/IccCardStatus.java
new file mode 100644
index 0000000..b602b1c
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccCardStatus.java
@@ -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 application = new ArrayList(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;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IccConstants.java b/telephony/java/com/android/internal/telephony/IccConstants.java
new file mode 100644
index 0000000..59ce5bb
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccConstants.java
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+/**
+ * {@hide}
+ */
+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;
+ public static final int EF_EXT1 = 0x6F4A;
+ public static final int EF_EXT2 = 0x6F4B;
+ public static final int EF_EXT3 = 0x6F4C;
+ public static final int EF_EXT6 = 0x6fc8; // Ext record for EF[MBDN]
+ public static final int EF_MWIS = 0x6FCA;
+ public static final int EF_MBDN = 0x6fc7;
+ public static final int EF_PNN = 0x6fc5;
+ public static final int EF_SPN = 0x6F46;
+ public static final int EF_SMS = 0x6F3C;
+ public static final int EF_ICCID = 0x2fe2;
+ public static final int EF_AD = 0x6FAD;
+ public static final int EF_MBI = 0x6fc9;
+ public static final int EF_MSISDN = 0x6f40;
+ public static final int EF_SPDI = 0x6fcd;
+ public static final int EF_SST = 0x6f38;
+ public static final int EF_CFIS = 0x6FCB;
+ public static final int EF_IMG = 0x4f20;
+
+ // 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;
+ public static final int EF_SPN_CPHS = 0x6f14;
+ 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;
+}
diff --git a/telephony/java/com/android/internal/telephony/IccException.java b/telephony/java/com/android/internal/telephony/IccException.java
new file mode 100644
index 0000000..1659a4e
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccException.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+/**
+ * {@hide}
+ */
+public class IccException extends Exception {
+ public IccException() {
+
+ }
+
+ public IccException(String s) {
+ super(s);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IccFileHandler.java b/telephony/java/com/android/internal/telephony/IccFileHandler.java
new file mode 100644
index 0000000..e751c5e
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccFileHandler.java
@@ -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 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
+ *
+ */
+ 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(lc.countRecords);
+ }
+
+ phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null,
+ lc.recordNum,
+ READ_RECORD_MODE_ABSOLUTE,
+ lc.recordSize, null, null,
+ obtainMessage(EVENT_READ_RECORD_DONE, lc));
+ break;
+ case EVENT_GET_BINARY_SIZE_DONE:
+ ar = (AsyncResult)msg.obj;
+ response = (Message) ar.userObj;
+ result = (IccIoResult) ar.result;
+
+ if (ar.exception != null) {
+ sendResult(response, null, ar.exception);
+ break;
+ }
+
+ iccException = result.getException();
+
+ if (iccException != null) {
+ sendResult(response, null, iccException);
+ break;
+ }
+
+ data = result.payload;
+
+ fileid = msg.arg1;
+
+ if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
+ throw new IccFileTypeMismatch();
+ }
+
+ if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
+ throw new IccFileTypeMismatch();
+ }
+
+ size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
+ + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
+
+ phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, null,
+ 0, 0, size, null, null,
+ obtainMessage(EVENT_READ_BINARY_DONE,
+ fileid, 0, response));
+ break;
+
+ case EVENT_READ_RECORD_DONE:
+
+ ar = (AsyncResult)msg.obj;
+ lc = (LoadLinearFixedContext) ar.userObj;
+ result = (IccIoResult) ar.result;
+ response = lc.onLoaded;
+
+ if (ar.exception != null) {
+ sendResult(response, null, ar.exception);
+ break;
+ }
+
+ iccException = result.getException();
+
+ if (iccException != null) {
+ sendResult(response, null, iccException);
+ break;
+ }
+
+ if (!lc.loadAll) {
+ sendResult(response, result.payload, null);
+ } else {
+ lc.results.add(result.payload);
+
+ lc.recordNum++;
+
+ if (lc.recordNum > lc.countRecords) {
+ sendResult(response, lc.results, null);
+ } else {
+ phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, null,
+ lc.recordNum,
+ READ_RECORD_MODE_ABSOLUTE,
+ lc.recordSize, null, null,
+ obtainMessage(EVENT_READ_RECORD_DONE, lc));
+ }
+ }
+
+ break;
+
+ case EVENT_READ_BINARY_DONE:
+ ar = (AsyncResult)msg.obj;
+ response = (Message) ar.userObj;
+ result = (IccIoResult) ar.result;
+
+ if (ar.exception != null) {
+ sendResult(response, null, ar.exception);
+ break;
+ }
+
+ iccException = result.getException();
+
+ if (iccException != null) {
+ sendResult(response, null, iccException);
+ break;
+ }
+
+ sendResult(response, result.payload, null);
+ break;
+
+ }} catch (Exception exc) {
+ if (response != null) {
+ sendResult(response, null, exc);
+ } else {
+ loge("uncaught exception" + exc);
+ }
+ }
+ }
+
+ protected abstract void logd(String s);
+
+ protected abstract void loge(String s);
+
+}
diff --git a/telephony/java/com/android/internal/telephony/IccFileNotFound.java b/telephony/java/com/android/internal/telephony/IccFileNotFound.java
new file mode 100644
index 0000000..915cea6
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccFileNotFound.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * {@hide}
+ */
+public class IccFileNotFound extends IccException {
+ IccFileNotFound() {
+
+ }
+
+ IccFileNotFound(String s) {
+ super(s);
+ }
+
+ IccFileNotFound(int ef) {
+ super("ICC EF Not Found 0x" + Integer.toHexString(ef));
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IccFileTypeMismatch.java b/telephony/java/com/android/internal/telephony/IccFileTypeMismatch.java
new file mode 100644
index 0000000..66fcfa9
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccFileTypeMismatch.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+/**
+ * {@hide}
+ */
+public class IccFileTypeMismatch extends IccException {
+ public IccFileTypeMismatch() {
+
+ }
+
+ public IccFileTypeMismatch(String s) {
+ super(s);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IccIoResult.java b/telephony/java/com/android/internal/telephony/IccIoResult.java
new file mode 100644
index 0000000..a6e0ec3
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccIoResult.java
@@ -0,0 +1,70 @@
+/*
+ * 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;
+
+/**
+ * {@hide}
+ */
+public class
+IccIoResult {
+ int sw1;
+ int sw2;
+
+ public byte[] payload;
+
+ public IccIoResult(int sw1, int sw2, byte[] payload) {
+ this.sw1 = sw1;
+ this.sw2 = sw2;
+ this.payload = payload;
+ }
+
+ public IccIoResult(int sw1, int sw2, String hexString) {
+ this(sw1, sw2, IccUtils.hexStringToBytes(hexString));
+ }
+
+ public String toString() {
+ return "IccIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x"
+ + Integer.toHexString(sw2);
+ }
+
+ /**
+ * true if this operation was successful
+ * See GSM 11.11 Section 9.4
+ * (the fun stuff is absent in 51.011)
+ */
+ public boolean success() {
+ return sw1 == 0x90 || sw1 == 0x91 || sw1 == 0x9e || sw1 == 0x9f;
+ }
+
+ /**
+ * Returns exception on error or null if success
+ */
+ public IccException getException() {
+ if (success()) return null;
+
+ switch (sw1) {
+ case 0x94:
+ if (sw2 == 0x08) {
+ return new IccFileTypeMismatch();
+ } else {
+ return new IccFileNotFound();
+ }
+ default:
+ return new IccException("sw1:" + sw1 + " sw2:" + sw2);
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
new file mode 100644
index 0000000..0bcaaa6
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManager.java
@@ -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 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)
+ ((ArrayList) 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 getAdnRecordsInEf(int efid) {
+
+ if (phone.getContext().checkCallingOrSelfPermission(
+ android.Manifest.permission.READ_CONTACTS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Requires android.permission.READ_CONTACTS permission");
+ }
+
+ if (DBG) logd("getAdnRecordsInEF: efid=" + efid);
+
+ synchronized(mLock) {
+ checkThread();
+ Message response = mBaseHandler.obtainMessage(EVENT_LOAD_DONE);
+ adnCache.requestLoadAllAdnLike(efid, response);
+ try {
+ mLock.wait();
+ } catch (InterruptedException e) {
+ logd("interrupted while trying to load from the SIM");
+ }
+ }
+ return records;
+ }
+
+ protected void checkThread() {
+ if (!ALLOW_SIM_OP_IN_UI_THREAD) {
+ // Make sure this isn't the UI thread, since it will block
+ if (mBaseHandler.getLooper().equals(Looper.myLooper())) {
+ loge("query() called on the main UI thread!");
+ throw new IllegalStateException(
+ "You cannot call query on this provder from the main UI thread.");
+ }
+ }
+ }
+}
+
diff --git a/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java
new file mode 100644
index 0000000..1c0fc52
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccPhoneBookInterfaceManagerProxy.java
@@ -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 getAdnRecordsInEf(int efid) throws android.os.RemoteException {
+ return mIccPhoneBookInterfaceManager.getAdnRecordsInEf(efid);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IccProvider.java b/telephony/java/com/android/internal/telephony/IccProvider.java
new file mode 100644
index 0000000..4cbd779
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccProvider.java
@@ -0,0 +1,456 @@
+/*
+ * 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.ContentProvider;
+import android.content.UriMatcher;
+import android.content.ContentValues;
+import com.android.internal.database.ArrayListCursor;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.SystemProperties;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+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 IccProvider extends ContentProvider {
+ private static final String TAG = "IccProvider";
+ private static final boolean DBG = false;
+
+
+ private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
+ "name",
+ "number"
+ };
+
+ private static final int ADN = 1;
+ private static final int FDN = 2;
+ private static final int SDN = 3;
+
+ private static final String STR_TAG = "tag";
+ private static final String STR_NUMBER = "number";
+ private static final String STR_PIN2 = "pin2";
+
+ private static final UriMatcher URL_MATCHER =
+ new UriMatcher(UriMatcher.NO_MATCH);
+
+ static {
+ URL_MATCHER.addURI("icc", "adn", ADN);
+ URL_MATCHER.addURI("icc", "fdn", FDN);
+ URL_MATCHER.addURI("icc", "sdn", SDN);
+ }
+
+
+ private boolean mSimulator;
+
+ @Override
+ public boolean onCreate() {
+ String device = SystemProperties.get("ro.product.device");
+ if (!TextUtils.isEmpty(device)) {
+ mSimulator = false;
+ } else {
+ // simulator
+ mSimulator = true;
+ }
+
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri url, String[] projection, String selection,
+ String[] selectionArgs, String sort) {
+ ArrayList results;
+
+ if (!mSimulator) {
+ switch (URL_MATCHER.match(url)) {
+ case ADN:
+ results = loadFromEf(IccConstants.EF_ADN);
+ break;
+
+ case FDN:
+ results = loadFromEf(IccConstants.EF_FDN);
+ break;
+
+ case SDN:
+ results = loadFromEf(IccConstants.EF_SDN);
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown URL " + url);
+ }
+ } else {
+ // Fake up some data for the simulator
+ results = new ArrayList(4);
+ ArrayList contact;
+
+ contact = new ArrayList();
+ contact.add("Ron Stevens/H");
+ contact.add("512-555-5038");
+ results.add(contact);
+
+ contact = new ArrayList();
+ contact.add("Ron Stevens/M");
+ contact.add("512-555-8305");
+ results.add(contact);
+
+ contact = new ArrayList();
+ contact.add("Melissa Owens");
+ contact.add("512-555-8305");
+ results.add(contact);
+
+ contact = new ArrayList();
+ contact.add("Directory Assistence");
+ contact.add("411");
+ results.add(contact);
+ }
+
+ return new ArrayListCursor(ADDRESS_BOOK_COLUMN_NAMES, results);
+ }
+
+ @Override
+ public String getType(Uri url) {
+ switch (URL_MATCHER.match(url)) {
+ case ADN:
+ case FDN:
+ case SDN:
+ return "vnd.android.cursor.dir/sim-contact";
+
+ default:
+ throw new IllegalArgumentException("Unknown URL " + url);
+ }
+ }
+
+ @Override
+ public Uri insert(Uri url, ContentValues initialValues) {
+ Uri resultUri;
+ int efType;
+ String pin2 = null;
+
+ if (DBG) log("insert");
+
+ int match = URL_MATCHER.match(url);
+ switch (match) {
+ case ADN:
+ efType = IccConstants.EF_ADN;
+ break;
+
+ case FDN:
+ efType = IccConstants.EF_FDN;
+ pin2 = initialValues.getAsString("pin2");
+ break;
+
+ default:
+ throw new UnsupportedOperationException(
+ "Cannot insert into URL: " + url);
+ }
+
+ String tag = initialValues.getAsString("tag");
+ String number = initialValues.getAsString("number");
+ boolean success = addIccRecordToEf(efType, tag, number, pin2);
+
+ if (!success) {
+ return null;
+ }
+
+ StringBuilder buf = new StringBuilder("content://im/");
+ switch (match) {
+ case ADN:
+ buf.append("adn/");
+ break;
+
+ case FDN:
+ buf.append("fdn/");
+ break;
+ }
+
+ // TODO: we need to find out the rowId for the newly added record
+ buf.append(0);
+
+ resultUri = Uri.parse(buf.toString());
+
+ /*
+ // notify interested parties that an insertion happened
+ getContext().getContentResolver().notifyInsert(
+ resultUri, rowID, null);
+ */
+
+ return resultUri;
+ }
+
+ private String normalizeValue(String inVal) {
+ int len = inVal.length();
+ String retVal = inVal;
+
+ if (inVal.charAt(0) == '\'' && inVal.charAt(len-1) == '\'') {
+ retVal = inVal.substring(1, len-1);
+ }
+
+ return retVal;
+ }
+
+ @Override
+ public int delete(Uri url, String where, String[] whereArgs) {
+ int efType;
+
+ if (DBG) log("delete");
+
+ int match = URL_MATCHER.match(url);
+ switch (match) {
+ case ADN:
+ efType = IccConstants.EF_ADN;
+ break;
+
+ case FDN:
+ efType = IccConstants.EF_FDN;
+ break;
+
+ default:
+ throw new UnsupportedOperationException(
+ "Cannot insert into URL: " + url);
+ }
+
+ // parse where clause
+ String tag = null;
+ String number = null;
+ String pin2 = null;
+
+ String[] tokens = where.split("AND");
+ int n = tokens.length;
+
+ while (--n >= 0) {
+ String param = tokens[n];
+ if (DBG) log("parsing '" + param + "'");
+
+ String[] pair = param.split("=");
+
+ if (pair.length != 2) {
+ Log.e(TAG, "resolve: bad whereClause parameter: " + param);
+ continue;
+ }
+
+ String key = pair[0].trim();
+ String val = pair[1].trim();
+
+ if (STR_TAG.equals(key)) {
+ tag = normalizeValue(val);
+ } else if (STR_NUMBER.equals(key)) {
+ number = normalizeValue(val);
+ } else if (STR_PIN2.equals(key)) {
+ pin2 = normalizeValue(val);
+ }
+ }
+
+ if (TextUtils.isEmpty(tag)) {
+ return 0;
+ }
+
+ if (efType == FDN && TextUtils.isEmpty(pin2)) {
+ return 0;
+ }
+
+ boolean success = deleteIccRecordFromEf(efType, tag, number, pin2);
+ if (!success) {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ @Override
+ public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
+ int efType;
+ String pin2 = null;
+
+ if (DBG) log("update");
+
+ int match = URL_MATCHER.match(url);
+ switch (match) {
+ case ADN:
+ efType = IccConstants.EF_ADN;
+ break;
+
+ case FDN:
+ efType = IccConstants.EF_FDN;
+ pin2 = values.getAsString("pin2");
+ break;
+
+ default:
+ throw new UnsupportedOperationException(
+ "Cannot insert into URL: " + url);
+ }
+
+ String tag = values.getAsString("tag");
+ String number = values.getAsString("number");
+ String newTag = values.getAsString("newTag");
+ String newNumber = values.getAsString("newNumber");
+
+ boolean success = updateIccRecordInEf(efType, tag, number,
+ newTag, newNumber, pin2);
+
+ if (!success) {
+ return 0;
+ }
+
+ return 1;
+ }
+
+ private ArrayList loadFromEf(int efType) {
+ ArrayList results = new ArrayList();
+ List adnRecords = null;
+
+ if (DBG) log("loadFromEf: efType=" + efType);
+
+ try {
+ IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+ ServiceManager.getService("simphonebook"));
+ 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
+
+ int N = adnRecords.size();
+ if (DBG) log("adnRecords.size=" + N);
+ for (int i = 0; i < N ; i++) {
+ loadRecord(adnRecords.get(i), results);
+ }
+ } else {
+ // No results to load
+ Log.w(TAG, "Cannot load ADN records");
+ results.clear();
+ }
+ if (DBG) log("loadFromEf: return results");
+ return results;
+ }
+
+ private boolean
+ addIccRecordToEf(int efType, String name, String number, String pin2) {
+ if (DBG) log("addIccRecordToEf: efType=" + efType + ", name=" + name +
+ ", number=" + number);
+
+ boolean success = false;
+
+ // TODO: do we need to call getAdnRecordsInEf() before calling
+ // 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 {
+ IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+ ServiceManager.getService("simphonebook"));
+ 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("addIccRecordToEf: " + success);
+ return success;
+ }
+
+ private boolean
+ updateIccRecordInEf(int efType, String oldName, String oldNumber,
+ String newName, String newNumber,String pin2) {
+ if (DBG) log("updateIccRecordInEf: efType=" + efType +
+ ", oldname=" + oldName + ", oldnumber=" + oldNumber +
+ ", newname=" + newName + ", newnumber=" + newNumber);
+ boolean success = false;
+
+ try {
+ IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+ ServiceManager.getService("simphonebook"));
+ if (iccIpb != null) {
+ success = iccIpb.updateAdnRecordsInEfBySearch(efType,
+ oldName, oldNumber, newName, newNumber, pin2);
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ } catch (SecurityException ex) {
+ if (DBG) log(ex.toString());
+ }
+ if (DBG) log("updateIccRecordInEf: " + success);
+ return success;
+ }
+
+
+ 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 {
+ IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+ ServiceManager.getService("simphonebook"));
+ 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("deleteIccRecordFromEf: " + success);
+ return success;
+ }
+
+ /**
+ * Loads an AdnRecord into an ArrayList. Must be called with mLock held.
+ *
+ * @param record the ADN record to load from
+ * @param results the array list to put the results in
+ */
+ private void loadRecord(AdnRecord record,
+ ArrayList results) {
+ if (!record.isEmpty()) {
+ ArrayList contact = new ArrayList(2);
+ String alphaTag = record.getAlphaTag();
+ String number = record.getNumber();
+
+ if (DBG) log("loadRecord: " + alphaTag + ", " + number);
+ contact.add(alphaTag);
+ contact.add(number);
+ results.add(contact);
+ }
+ }
+
+ private void log(String msg) {
+ Log.d(TAG, "[IccProvider] " + msg);
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/IccRecords.java b/telephony/java/com/android/internal/telephony/IccRecords.java
new file mode 100644
index 0000000..114094b
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccRecords.java
@@ -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);
+}
+
diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
new file mode 100644
index 0000000..620f2de
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -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 Intent
is
+ * broadcast when the message is sucessfully sent, or failed.
+ * The result code will be Activity.RESULT_OK for success,
+ * or one of these errors:
+ * RESULT_ERROR_GENERIC_FAILURE
+ * RESULT_ERROR_RADIO_OFF
+ * RESULT_ERROR_NULL_PDU
.
+ * @param deliveryIntent if not NULL this Intent
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 ArrayList
of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an ArrayList
of
+ * PendingIntent
s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be Activity.RESULT_OK for success,
+ * or one of these errors:
+ * RESULT_ERROR_GENERIC_FAILURE
+ * RESULT_ERROR_RADIO_OFF
+ * RESULT_ERROR_NULL_PDU
.
+ * @param deliveryIntents if not null, an ArrayList
of
+ * PendingIntent
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 parts,
+ List sentIntents, List deliveryIntents) {
+ Context context = mPhone.getContext();
+
+ context.enforceCallingPermission(
+ "android.permission.SEND_SMS",
+ "Sending SMS message");
+ if (DBG) log("sendMultipartText");
+ mDispatcher.sendMultipartText(destinationAddress, scAddress, (ArrayList) parts,
+ (ArrayList) sentIntents, (ArrayList) 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 buildValidRawData(ArrayList messages) {
+ int count = messages.size();
+ ArrayList ret;
+
+ ret = new ArrayList(count);
+
+ for (int i = 0; i < count; i++) {
+ byte[] ba = messages.get(i);
+ if (ba[0] == STATUS_ON_ICC_FREE) {
+ ret.add(null);
+ } else {
+ ret.add(new SmsRawData(messages.get(i)));
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * Generates an EF_SMS record from status and raw PDU.
+ *
+ * @param status Message status. See TS 51.011 10.5.3.
+ * @param pdu Raw message PDU.
+ * @return byte array for the record.
+ */
+ protected byte[] makeSmsRecordData(int status, byte[] pdu) {
+ byte[] data = new byte[IccConstants.SMS_RECORD_LENGTH];
+
+ // Status bits for this record. See TS 51.011 10.5.3
+ data[0] = (byte)(status & 7);
+
+ System.arraycopy(pdu, 0, data, 1, pdu.length);
+
+ // Pad out with 0xFF's.
+ for (int j = pdu.length+1; j < IccConstants.SMS_RECORD_LENGTH; j++) {
+ data[j] = -1;
+ }
+
+ return data;
+ }
+
+ protected abstract void log(String msg);
+
+}
+
diff --git a/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java
new file mode 100644
index 0000000..a51d074
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java
@@ -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 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 parts, List sentIntents,
+ List deliveryIntents) throws android.os.RemoteException {
+ mIccSmsInterfaceManager.sendMultipartText(destinationAddress, scAddress,
+ parts, sentIntents, deliveryIntents);
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java
new file mode 100644
index 0000000..881ed2d
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccUtils.java
@@ -0,0 +1,487 @@
+/*
+ * 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.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 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
+ * values.
+ *
+ * Stops on invalid BCD value, returning string so far
+ */
+ public static String
+ bcdToString(byte[] data, int offset, int length) {
+ StringBuilder ret = new StringBuilder(length*2);
+
+ for (int i = offset ; i < offset + length ; i++) {
+ byte b;
+ int v;
+
+ v = data[i] & 0xf;
+ if (v > 9) break;
+ ret.append((char)('0' + v));
+
+ v = (data[i] >> 4) & 0xf;
+ if (v > 9) break;
+ ret.append((char)('0' + v));
+ }
+
+ return ret.toString();
+ }
+
+
+ /**
+ * Decodes a GSM-style BCD byte, returning an int ranging from 0-99.
+ *
+ * In GSM land, the least significant BCD digit is stored in the most
+ * significant nibble.
+ *
+ * Out-of-range digits are treated as 0 for the sake of the time stamp,
+ * because of this:
+ *
+ * TS 23.040 section 9.2.3.11
+ * "if the MS receives a non-integer value in the SCTS, it shall
+ * assume the digit is set to 0 but shall store the entire field
+ * exactly as received"
+ */
+ public static int
+ bcdByteToInt(byte b) {
+ int ret = 0;
+
+ // treat out-of-range BCD values as 0
+ if ((b & 0xf0) <= 0x90) {
+ ret = (b >> 4) & 0xf;
+ }
+
+ if ((b & 0x0f) <= 0x09) {
+ ret += (b & 0xf) * 10;
+ }
+
+ return ret;
+ }
+
+ /** Decodes 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
+ * identifier
+ *
+ * From TS 51.011 10.5.1:
+ * Coding:
+ * this alpha tagging shall use either
+ * - the SMS default 7 bit coded alphabet as defined in
+ * TS 23.038 [12] with bit 8 set to 0. The alpha identifier
+ * shall be left justified. Unused bytes shall be set to 'FF'; or
+ * - one of the UCS2 coded options as defined in annex B.
+ *
+ * Annex B from TS 11.11 V8.13.0:
+ * 1) If the first octet in the alpha string is '80', then the
+ * remaining octets are 16 bit UCS2 characters ...
+ * 2) if the first octet in the alpha string is '81', then the
+ * second octet contains a value indicating the number of
+ * characters in the string, and the third octet contains an
+ * 8 bit number which defines bits 15 to 8 of a 16 bit
+ * base pointer, where bit 16 is set to zero and bits 7 to 1
+ * are also set to zero. These sixteen bits constitute a
+ * base pointer to a "half page" in the UCS2 code space, to be
+ * used with some or all of the remaining octets in the string.
+ * The fourth and subsequent octets contain codings as follows:
+ * If bit 8 of the octet is set to zero, the remaining 7 bits
+ * of the octet contain a GSM Default Alphabet character,
+ * whereas if bit 8 of the octet is set to one, then the
+ * remaining seven bits are an offset value added to the
+ * 16 bit base pointer defined earlier...
+ * 3) If the first octet of the alpha string is set to '82', then
+ * the second octet contains a value indicating the number of
+ * characters in the string, and the third and fourth octets
+ * contain a 16 bit number which defines the complete 16 bit
+ * base pointer to a "half page" in the UCS2 code space...
+ */
+ public static String
+ adnStringFieldToString(byte[] data, int offset, int length) {
+ if (length >= 1) {
+ if (data[offset] == (byte) 0x80) {
+ int ucslen = (length - 1) / 2;
+ String ret = null;
+
+ try {
+ ret = new String(data, offset + 1, ucslen * 2, "utf-16be");
+ } catch (UnsupportedEncodingException ex) {
+ Log.e(LOG_TAG, "implausible UnsupportedEncodingException",
+ ex);
+ }
+
+ if (ret != null) {
+ // trim off trailing FFFF characters
+
+ ucslen = ret.length();
+ while (ucslen > 0 && ret.charAt(ucslen - 1) == '\uFFFF')
+ ucslen--;
+
+ return ret.substring(0, ucslen);
+ }
+ }
+ }
+
+ boolean isucs2 = false;
+ char base = '\0';
+ int len = 0;
+
+ if (length >= 3 && data[offset] == (byte) 0x81) {
+ len = data[offset + 1] & 0xFF;
+ if (len > length - 3)
+ len = length - 3;
+
+ base = (char) ((data[offset + 2] & 0xFF) << 7);
+ offset += 3;
+ isucs2 = true;
+ } else if (length >= 4 && data[offset] == (byte) 0x82) {
+ len = data[offset + 1] & 0xFF;
+ if (len > length - 4)
+ len = length - 4;
+
+ base = (char) (((data[offset + 2] & 0xFF) << 8) |
+ (data[offset + 3] & 0xFF));
+ offset += 4;
+ isucs2 = true;
+ }
+
+ if (isucs2) {
+ StringBuilder ret = new StringBuilder();
+
+ while (len > 0) {
+ // UCS2 subset case
+
+ if (data[offset] < 0) {
+ ret.append((char) (base + (data[offset] & 0x7F)));
+ offset++;
+ len--;
+ }
+
+ // GSM character set case
+
+ int count = 0;
+ while (count < len && data[offset + count] >= 0)
+ count++;
+
+ ret.append(GsmAlphabet.gsm8BitUnpackedToString(data,
+ offset, count));
+
+ offset += count;
+ len -= count;
+ }
+
+ return ret.toString();
+ }
+
+ return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length);
+ }
+
+ static int
+ hexCharToInt(char c) {
+ if (c >= '0' && c <= '9') return (c - '0');
+ if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
+ if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
+
+ throw new RuntimeException ("invalid hex char '" + c + "'");
+ }
+
+ /**
+ * Converts a hex String to a byte array.
+ *
+ * @param s A string of hexadecimal characters, must be an even number of
+ * chars long
+ *
+ * @return byte array representation
+ *
+ * @throws RuntimeException on invalid format
+ */
+ public static byte[]
+ hexStringToBytes(String s) {
+ byte[] ret;
+
+ if (s == null) return null;
+
+ int sz = s.length();
+
+ ret = new byte[sz/2];
+
+ for (int i=0 ; i > 4);
+
+ ret.append("0123456789abcdef".charAt(b));
+
+ b = 0x0f & bytes[i];
+
+ ret.append("0123456789abcdef".charAt(b));
+ }
+
+ return ret.toString();
+ }
+
+
+ /**
+ * Convert a TS 24.008 Section 10.5.3.5a Network Name field to a string
+ * "offset" points to "octet 3", the coding scheme byte
+ * empty string returned on decode error
+ */
+ public static String
+ networkNameToString(byte[] data, int offset, int length) {
+ String ret;
+
+ if ((data[offset] & 0x80) != 0x80 || length < 1) {
+ return "";
+ }
+
+ switch ((data[offset] >>> 4) & 0x7) {
+ case 0:
+ // SMS character set
+ int countSeptets;
+ int unusedBits = data[offset] & 7;
+ countSeptets = (((length - 1) * 8) - unusedBits) / 7 ;
+ ret = GsmAlphabet.gsm7BitPackedToString(data, offset + 1, countSeptets);
+ break;
+ case 1:
+ // UCS2
+ try {
+ ret = new String(data,
+ offset + 1, length - 1, "utf-16");
+ } catch (UnsupportedEncodingException ex) {
+ ret = "";
+ Log.e(LOG_TAG,"implausible UnsupportedEncodingException", ex);
+ }
+ break;
+
+ // unsupported encoding
+ default:
+ ret = "";
+ break;
+ }
+
+ // "Add CI"
+ // "The MS should add the letters for the Country's Initials and
+ // a separator (e.g. a space) to the text string"
+
+ if ((data[offset] & 0x40) != 0) {
+ // FIXME(mkf) add country initials here
+
+ }
+
+ return ret;
+ }
+
+ /**
+ * Convert a TS 131.102 image instance of code scheme '11' into Bitmap
+ * @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;
+ int height = data[valueIndex++] & 0xFF;
+ int numOfPixels = width*height;
+
+ int[] pixels = new int[numOfPixels];
+
+ int pixelIndex = 0;
+ int bitIndex = 7;
+ byte currentByte = 0x00;
+ while (pixelIndex < numOfPixels) {
+ // reassign data and index for every byte (8 bits).
+ if (pixelIndex % 8 == 0) {
+ currentByte = data[valueIndex++];
+ bitIndex = 7;
+ }
+ pixels[pixelIndex++] = bitToRGB((currentByte >> bitIndex-- ) & 0x01);
+ };
+
+ if (pixelIndex != numOfPixels) {
+ Log.e(LOG_TAG, "parse end and size error");
+ }
+ return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
+ }
+
+ private static int bitToRGB(int bit){
+ if(bit == 1){
+ return Color.WHITE;
+ } else {
+ return Color.BLACK;
+ }
+ }
+
+ /**
+ * 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
+ * @return The color bitmap
+ */
+ public static Bitmap parseToRGB(byte[] data, int length,
+ boolean transparency) {
+ int valueIndex = 0;
+ int width = data[valueIndex++] & 0xFF;
+ int height = data[valueIndex++] & 0xFF;
+ int bits = data[valueIndex++] & 0xFF;
+ int colorNumber = data[valueIndex++] & 0xFF;
+ int clutOffset = ((data[valueIndex++] & 0xFF) << 8)
+ | data[valueIndex++];
+ length = length - 6;
+
+ int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber);
+ if (true == transparency) {
+ colorIndexArray[colorNumber - 1] = Color.TRANSPARENT;
+ }
+
+ int[] resultArray = null;
+ if (0 == (8 % bits)) {
+ resultArray = mapTo2OrderBitColor(data, valueIndex,
+ (width * height), colorIndexArray, bits);
+ } else {
+ resultArray = mapToNon2OrderBitColor(data, valueIndex,
+ (width * height), colorIndexArray, bits);
+ }
+
+ return Bitmap.createBitmap(resultArray, width, height,
+ Bitmap.Config.RGB_565);
+ }
+
+ private static int[] mapTo2OrderBitColor(byte[] data, int valueIndex,
+ int length, int[] colorArray, int bits) {
+ if (0 != (8 % bits)) {
+ Log.e(LOG_TAG, "not event number of color");
+ return mapToNon2OrderBitColor(data, valueIndex, length, colorArray,
+ bits);
+ }
+
+ int mask = 0x01;
+ switch (bits) {
+ case 1:
+ mask = 0x01;
+ break;
+ case 2:
+ mask = 0x03;
+ break;
+ case 4:
+ mask = 0x0F;
+ break;
+ case 8:
+ mask = 0xFF;
+ break;
+ }
+
+ int[] resultArray = new int[length];
+ int resultIndex = 0;
+ int run = 8 / bits;
+ while (resultIndex < length) {
+ byte tempByte = data[valueIndex++];
+ for (int runIndex = 0; runIndex < run; ++runIndex) {
+ int offset = run - runIndex - 1;
+ resultArray[resultIndex++] = colorArray[(tempByte >> (offset * bits))
+ & mask];
+ }
+ }
+ return resultArray;
+ }
+
+ private static int[] mapToNon2OrderBitColor(byte[] data, int valueIndex,
+ int length, int[] colorArray, int bits) {
+ if (0 == (8 % bits)) {
+ Log.e(LOG_TAG, "not odd number of color");
+ return mapTo2OrderBitColor(data, valueIndex, length, colorArray,
+ bits);
+ }
+
+ int[] resultArray = new int[length];
+ // TODO fix me:
+ return resultArray;
+ }
+
+ private static int[] getCLUT(byte[] rawData, int offset, int number) {
+ if (null == rawData) {
+ return null;
+ }
+
+ int[] result = new int[number];
+ int endIndex = offset + (number * 3); // 1 color use 3 bytes
+ int valueIndex = offset;
+ int colorIndex = 0;
+ int alpha = 0xff << 24;
+ do {
+ result[colorIndex++] = alpha
+ | ((rawData[valueIndex++] & 0xFF) << 16)
+ | ((rawData[valueIndex++] & 0xFF) << 8)
+ | ((rawData[valueIndex++] & 0xFF));
+ } while (valueIndex < endIndex);
+ return result;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IccVmFixedException.java b/telephony/java/com/android/internal/telephony/IccVmFixedException.java
new file mode 100644
index 0000000..45679c1
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccVmFixedException.java
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/internal/telephony/IccVmNotSupportedException.java b/telephony/java/com/android/internal/telephony/IccVmNotSupportedException.java
new file mode 100644
index 0000000..7e90d24
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/IccVmNotSupportedException.java
@@ -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);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/MmiCode.java b/telephony/java/com/android/internal/telephony/MmiCode.java
index 925b06f..c71ff77 100644
--- a/telephony/java/com/android/internal/telephony/MmiCode.java
+++ b/telephony/java/com/android/internal/telephony/MmiCode.java
@@ -41,14 +41,14 @@ public interface MmiCode
* @return Localized message for UI display, valid only in COMPLETE
* or FAILED states. null otherwise
*/
-
+
public CharSequence getMessage();
/**
* Cancels pending MMI request.
* State becomes CANCELLED unless already COMPLETE or FAILED
*/
- public void cancel();
+ public void cancel();
/**
* @return true if the network response is a REQUEST for more user input.
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 05e61f2..ed90d32 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -17,10 +17,14 @@
package com.android.internal.telephony;
import android.content.Context;
+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 com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.gsm.NetworkInfo;
import com.android.internal.telephony.gsm.PdpConnection;
import com.android.internal.telephony.test.SimulatedRadioControl;
@@ -38,13 +42,13 @@ public interface Phone {
/** used to enable additional debug messages */
static final boolean DEBUG_PHONE = true;
-
- /**
+
+ /**
* The phone state. One of the following:
*
* - IDLE = no phone activity
- * - RINGING = a phone call is ringing or call waiting.
+ *
- RINGING = a phone call is ringing or call waiting.
* In the latter case, another call is active as well
* - OFFHOOK = The phone is off hook. At least one call
* exists that is dialing, active or holding and no calls are
@@ -70,7 +74,7 @@ public interface Phone {
CONNECTED, CONNECTING, DISCONNECTED, SUSPENDED;
};
- enum DataActivityState {
+ public enum DataActivityState {
/**
* The state of a data activity.
*
@@ -131,6 +135,8 @@ public interface Phone {
static final String REASON_DATA_ENABLED = "dataEnabled";
static final String REASON_GPRS_ATTACHED = "gprsAttached";
static final String REASON_GPRS_DETACHED = "gprsDetached";
+ static final String REASON_CDMA_DATA_ATTACHED = "cdmaDataAttached";
+ static final String REASON_CDMA_DATA_DETACHED = "cdmaDataDetached";
static final String REASON_APN_CHANGED = "apnChanged";
static final String REASON_APN_SWITCHED = "apnSwitched";
static final String REASON_RESTORE_DEFAULT_APN = "restoreDefaultApn";
@@ -152,12 +158,32 @@ public interface Phone {
static final int BM_BOUNDARY = 6; // upper band boundary
// Used for preferred network type
- static final int NT_AUTO_TYPE = 0; // WCDMA preferred (auto mode)
- static final int NT_GSM_TYPE = 1; // GSM only
- static final int NT_WCDMA_TYPE = 2; // WCDMA only
-
- /**
- * Get the current ServiceState. Use
+ // Note NT_* substitute RILConstants.NETWORK_MODE_* above the Phone
+ int NT_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */
+ int NT_MODE_GSM_ONLY = 1; /* GSM only */
+ int NT_MODE_WCDMA_ONLY = 2; /* WCDMA only */
+ int NT_MODE_GSM_UMTS = 3; /* GSM/WCDMA (auto mode, according to PRL)
+ AVAILABLE Application Settings menu*/
+ int NT_MODE_CDMA = 4; /* CDMA and EvDo (auto mode, according to PRL)
+ AVAILABLE Application Settings menu*/
+ int NT_MODE_CDMA_NO_EVDO = 5; /* CDMA only */
+ int NT_MODE_EVDO_NO_CDMA = 6; /* EvDo only */
+ int NT_MODE_GLOBAL = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL)
+ AVAILABLE Application Settings menu*/
+ int PREFERRED_NT_MODE = NT_MODE_GLOBAL;
+
+
+ // Used for CDMA roaming mode
+ static final int CDMA_RM_HOME = 0; //Home Networks only, as defined in PRL
+ static final int CDMA_RM_AFFILIATED = 1; //Roaming an Affiliated networks, as defined in PRL
+ static final int CDMA_RM_ANY = 2; //Roaming on Any Network, as defined in PRL
+
+ // Used for CDMA subscription mode
+ static final int CDMA_SUBSCRIPTION_RUIM_SIM = 0; //RUIM/SIM (default)
+ static final int CDMA_SUBSCRIPTION_NV = 1; //NV -> non-volatile memory
+
+ /**
+ * Get the current ServiceState. Use
* registerForServiceStateChanged
to be informed of
* updates.
*/
@@ -167,11 +193,12 @@ public interface Phone {
* Get the current CellLocation.
*/
CellLocation getCellLocation();
-
+
/**
* Get the current DataState. No change notification exists at this
- * interface -- use
- * {@link com.android.internal.telephony.PhoneStateIntentReceiver PhoneStateIntentReceiver} instead.
+ * interface -- use
+ * {@link com.android.internal.telephony.PhoneStateIntentReceiver PhoneStateIntentReceiver}
+ * instead.
*/
DataState getDataConnectionState();
@@ -181,58 +208,70 @@ public interface Phone {
* {@link TelephonyManager} instead.
*/
DataActivityState getDataActivityState();
-
+
/**
* Gets the context for the phone, as set at initialization time.
*/
Context getContext();
- /**
+ /**
+ * Disables the DNS check (i.e., allows "0.0.0.0").
+ * Useful for lab testing environment.
+ * @param b true disables the check, false enables.
+ */
+ void disableDnsCheck(boolean b);
+
+ /**
+ * Returns true if the DNS check is currently disabled.
+ */
+ boolean isDnsCheckDisabled();
+
+ /**
* Get current coarse-grained voice call state.
- * Use {@link #registerForPhoneStateChanged(Handler, int, Object)
+ * Use {@link #registerForPhoneStateChanged(Handler, int, Object)
* registerForPhoneStateChanged()} for change notification.
* If the phone has an active call and call waiting occurs,
* then the phone state is RINGING not OFFHOOK
- * Note:
+ * Note:
* This registration point provides notification of finer-grained
* changes.
*
*/
State getState();
- /**
+ /**
* Returns a string identifier for this phone interface for parties
* outside the phone app process.
* @return The string name.
*/
String getPhoneName();
- /**
+ /**
* Returns an array of string identifiers for the APN types serviced by the
* currently active or last connected APN.
* @return The string array.
*/
String[] getActiveApnTypes();
-
- /**
+
+ /**
* Returns a string identifier for currently active or last connected APN.
* @return The string name.
*/
String getActiveApn();
-
- /**
+
+ /**
* Get current signal strength. No change notification available on this
* interface. Use PhoneStateNotifier
or an equivalent.
- * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu).
+ * An ASU is 0-31 or -1 if unknown (for GSM, dBm = -113 - 2 * asu).
* The following special values are defined:
* - 0 means "-113 dBm or less".
* - 31 means "-51 dBm or greater".
- *
+ *
* @return Current signal strength in ASU's.
*/
int getSignalStrengthASU();
-
- /**
+
+ /**
* Notifies when a previously untracked non-ringing/waiting connection has appeared.
* This is likely due to some other entity (eg, SIM card application) initiating a call.
*/
@@ -243,7 +282,7 @@ public interface Phone {
*/
void unregisterForUnknownConnection(Handler h);
- /**
+ /**
* Notifies when any aspect of the voice call state changes.
* Resulting events will have an AsyncResult in Message.obj
.
* AsyncResult.userData will be set to the obj argument here.
@@ -252,13 +291,13 @@ public interface Phone {
void registerForPhoneStateChanged(Handler h, int what, Object obj);
/**
- * Unregisters for voice call state change notifications.
+ * Unregisters for voice call state change notifications.
* Extraneous calls are tolerated silently.
*/
void unregisterForPhoneStateChanged(Handler h);
- /**
+ /**
* Notifies when a new ringing or waiting connection has appeared.
*
* Messages received from this:
@@ -267,19 +306,19 @@ public interface Phone {
* AsyncResult.result = a Connection.
* Please check Connection.isRinging() to make sure the Connection
* has not dropped since this message was posted.
- * If Connection.isRinging() is true, then
+ * If Connection.isRinging() is true, then
* Connection.getCall() == Phone.getRingingCall()
*/
void registerForNewRingingConnection(Handler h, int what, Object obj);
/**
- * Unregisters for new ringing connection notification.
+ * Unregisters for new ringing connection notification.
* Extraneous calls are tolerated silently
*/
void unregisterForNewRingingConnection(Handler h);
- /**
+ /**
* Notifies when an incoming call rings.
*
* Messages received from this:
@@ -288,29 +327,29 @@ public interface Phone {
* AsyncResult.result = a Connection.
*/
void registerForIncomingRing(Handler h, int what, Object obj);
-
+
/**
- * Unregisters for ring notification.
+ * Unregisters for ring notification.
* Extraneous calls are tolerated silently
*/
-
+
void unregisterForIncomingRing(Handler h);
-
-
- /**
+
+
+ /**
* Notifies when a voice connection has disconnected, either due to local
* or remote hangup or error.
- *
+ *
* Messages received from this will have the following members:
*
- Message.obj will be an AsyncResult
* - AsyncResult.userObj = obj
- * - AsyncResult.result = a Connection object that is
+ *
- AsyncResult.result = a Connection object that is
* no longer connected.
*/
void registerForDisconnect(Handler h, int what, Object obj);
/**
- * Unregisters for voice disconnection notification.
+ * Unregisters for voice disconnection notification.
* Extraneous calls are tolerated silently
*/
void unregisterForDisconnect(Handler h);
@@ -330,7 +369,7 @@ public interface Phone {
void registerForMmiInitiate(Handler h, int what, Object obj);
/**
- * Unregisters for new MMI initiate notification.
+ * Unregisters for new MMI initiate notification.
* Extraneous calls are tolerated silently
*/
void unregisterForMmiInitiate(Handler h);
@@ -346,7 +385,7 @@ public interface Phone {
void registerForMmiComplete(Handler h, int what, Object obj);
/**
- * Unregisters for MMI complete notification.
+ * Unregisters for MMI complete notification.
* Extraneous calls are tolerated silently
*/
void unregisterForMmiComplete(Handler h);
@@ -355,7 +394,7 @@ public interface Phone {
* Returns a list of MMI codes that are pending. (They have initiated
* but have not yet completed).
* Presently there is only ever one.
- * Use registerForMmiInitiate
+ * Use registerForMmiInitiate
* and registerForMmiComplete
for change notification.
*/
public List extends MmiCode> getPendingMmiCodes();
@@ -370,14 +409,14 @@ public interface Phone {
public void sendUssdResponse(String ussdMessge);
/**
- * Register for ServiceState changed.
+ * Register for ServiceState changed.
* Message.obj will contain an AsyncResult.
* AsyncResult.result will be a ServiceState instance
*/
void registerForServiceStateChanged(Handler h, int what, Object obj);
/**
- * Unregisters for ServiceStateChange notification.
+ * Unregisters for ServiceStateChange notification.
* Extraneous calls are tolerated silently
*/
void unregisterForServiceStateChanged(Handler h);
@@ -394,9 +433,9 @@ public interface Phone {
void registerForSuppServiceNotification(Handler h, int what, Object obj);
/**
- * Unregisters for Supplementary Service notifications.
+ * Unregisters for Supplementary Service notifications.
* Extraneous calls are tolerated silently
- *
+ *
* @param h Handler to be removed from the registrant list.
*/
void unregisterForSuppServiceNotification(Handler h);
@@ -414,53 +453,85 @@ public interface Phone {
/**
* Unregister for notifications when a supplementary service attempt fails.
* Extraneous calls are tolerated silently
- *
+ *
* @param h Handler to be removed from the registrant list.
*/
void unregisterForSuppServiceFailed(Handler h);
- /**
- * Returns SIM record load state. Use
+ /**
+ * Register for notifications when a sInCall VoicePrivacy is enabled
+ *
+ * @param h Handler that receives the notification message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+ void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj);
+
+ /**
+ * Unegister for notifications when a sInCall VoicePrivacy is enabled
+ *
+ * @param h Handler to be removed from the registrant list.
+ */
+ void unregisterForInCallVoicePrivacyOn(Handler h);
+
+ /**
+ * Register for notifications when a sInCall VoicePrivacy is disabled
+ *
+ * @param h Handler that receives the notification message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+ void registerForInCallVoicePrivacyOff(Handler h, int what, Object obj);
+
+ /**
+ * Unegister for notifications when a sInCall VoicePrivacy is disabled
+ *
+ * @param h Handler to be removed from the registrant list.
+ */
+ void unregisterForInCallVoicePrivacyOff(Handler h);
+
+ /**
+ * Returns SIM record load state. Use
* getSimCard().registerForReady()
for change notification.
*
- * @return true if records from the SIM have been loaded and are
+ * @return true if records from the SIM have been loaded and are
* available (if applicable). If not applicable to the underlying
* technology, returns true as well.
*/
- boolean getSimRecordsLoaded();
+ boolean getIccRecordsLoaded();
/**
- * Returns the SIM card interface for this phone, or null
+ * Returns the ICC card interface for this phone, or null
* if not applicable to underlying technology.
*/
- SimCard getSimCard();
+ IccCard getIccCard();
/**
- * Answers a ringing or waiting call. Active calls, if any, go on hold.
+ * Answers a ringing or waiting call. Active calls, if any, go on hold.
* Answering occurs asynchronously, and final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
+ * {@link #registerForPhoneStateChanged(android.os.Handler, int,
* java.lang.Object) registerForPhoneStateChanged()}.
*
* @exception CallStateException when no call is ringing or waiting
*/
void acceptCall() throws CallStateException;
- /**
- * Reject (ignore) a ringing call. In GSM, this means UDUB
- * (User Determined User Busy). Reject occurs asynchronously,
- * and final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
+ /**
+ * Reject (ignore) a ringing call. In GSM, this means UDUB
+ * (User Determined User Busy). Reject occurs asynchronously,
+ * and final notification occurs via
+ * {@link #registerForPhoneStateChanged(android.os.Handler, int,
* java.lang.Object) registerForPhoneStateChanged()}.
*
* @exception CallStateException when no call is ringing or waiting
*/
void rejectCall() throws CallStateException;
- /**
+ /**
* Places any active calls on hold, and makes any held calls
* active. Switch occurs asynchronously and may fail.
- * Final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
+ * Final notification occurs via
+ * {@link #registerForPhoneStateChanged(android.os.Handler, int,
* java.lang.Object) registerForPhoneStateChanged()}.
*
* @exception CallStateException if a call is ringing, waiting, or
@@ -469,24 +540,40 @@ public interface Phone {
void switchHoldingAndActive() throws CallStateException;
/**
- * Whether or not the phone can conference in the current phone
+ * Whether or not the phone can conference in the current phone
* state--that is, one call holding and one call active.
- * @return true if the phone can conference; false otherwise.
+ * @return true if the phone can conference; false otherwise.
*/
boolean canConference();
/**
- * Conferences holding and active. Conference occurs asynchronously
- * and may fail. Final notification occurs via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
- * java.lang.Object) registerForPhoneStateChanged()}.
- *
+ * Conferences holding and active. Conference occurs asynchronously
+ * and may fail. Final notification occurs via
+ * {@link #registerForPhoneStateChanged(android.os.Handler, int,
+ * java.lang.Object) registerForPhoneStateChanged()}.
+ *
* @exception CallStateException if canConference() would return false.
* In these cases, this operation may not be performed.
*/
void conference() throws CallStateException;
/**
+ * Enable or disable enhanced Voice Privacy (VP). If enhanced VP is
+ * disabled, normal VP is enabled.
+ *
+ * @param enable whether true or false to enable or disable.
+ * @param onComplete a callback message when the action is completed.
+ */
+ void enableEnhancedVoicePrivacy(boolean enable, Message onComplete);
+
+ /**
+ * Get the currently set Voice Privacy (VP) mode.
+ *
+ * @param onComplete a callback message when the action is completed.
+ */
+ void getEnhancedVoicePrivacy(Message onComplete);
+
+ /**
* Whether or not the phone can do explicit call transfer in the current
* phone state--that is, one call holding and one call active.
* @return true if the phone can do explicit call transfer; false otherwise.
@@ -513,65 +600,65 @@ public interface Phone {
void clearDisconnected();
- /**
- * Gets the foreground call object, which represents all connections that
- * are dialing or active (all connections
+ /**
+ * Gets the foreground call object, which represents all connections that
+ * are dialing or active (all connections
* that have their audio path connected).
*
* The foreground call is a singleton object. It is constant for the life
* of this phone. It is never null.
- *
+ *
* The foreground call will only ever be in one of these states:
- * IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED.
+ * IDLE, ACTIVE, DIALING, ALERTING, or DISCONNECTED.
*
* State change notification is available via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
+ * {@link #registerForPhoneStateChanged(android.os.Handler, int,
* java.lang.Object) registerForPhoneStateChanged()}.
*/
Call getForegroundCall();
- /**
+ /**
* Gets the background call object, which represents all connections that
* are holding (all connections that have been accepted or connected, but
* do not have their audio path connected).
*
* The background call is a singleton object. It is constant for the life
* of this phone object . It is never null.
- *
+ *
* The background call will only ever be in one of these states:
* IDLE, HOLDING or DISCONNECTED.
*
* State change notification is available via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
+ * {@link #registerForPhoneStateChanged(android.os.Handler, int,
* java.lang.Object) registerForPhoneStateChanged()}.
*/
Call getBackgroundCall();
- /**
- * Gets the ringing call object, which represents an incoming
+ /**
+ * Gets the ringing call object, which represents an incoming
* connection (if present) that is pending answer/accept. (This connection
* may be RINGING or WAITING, and there may be only one.)
* The ringing call is a singleton object. It is constant for the life
* of this phone. It is never null.
- *
+ *
* The ringing call will only ever be in one of these states:
* IDLE, INCOMING, WAITING or DISCONNECTED.
*
* State change notification is available via
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
+ * {@link #registerForPhoneStateChanged(android.os.Handler, int,
* java.lang.Object) registerForPhoneStateChanged()}.
*/
Call getRingingCall();
- /**
+ /**
* Initiate a new voice connection. This happens asynchronously, so you
* cannot assume the audio path is connected (or a call index has been
* assigned) until PhoneStateChanged notification has occurred.
*
* @exception CallStateException if a new outgoing call is not currently
- * possible because no more call slots exist or a call exists that is
- * dialing, alerting, ringing, or waiting. Other errors are
+ * possible because no more call slots exist or a call exists that is
+ * dialing, alerting, ringing, or waiting. Other errors are
* handled asynchronously.
*/
Connection dial(String dialString) throws CallStateException;
@@ -579,7 +666,7 @@ public interface Phone {
/**
* Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
* without SEND (so dial
is not appropriate).
- *
+ *
* @param dialString the MMI command to be executed.
* @return true if MMI command is executed.
*/
@@ -597,7 +684,7 @@ public interface Phone {
boolean handleInCallMmiCommands(String command) throws CallStateException;
/**
- * Play a DTMF tone on the active call. Ignored if there is no active call.
+ * Play a DTMF tone on the active call. Ignored if there is no active call.
* @param c should be one of 0-9, '*' or '#'. Other values will be
* silently ignored.
*/
@@ -619,20 +706,20 @@ public interface Phone {
/**
- * Sets the radio power on/off state (off is sometimes
- * called "airplane mode"). Current state can be gotten via
- * {@link #getServiceState()}.{@link
+ * Sets the radio power on/off state (off is sometimes
+ * called "airplane mode"). Current state can be gotten via
+ * {@link #getServiceState()}.{@link
* android.telephony.ServiceState#getState() getState()}.
- * Note: This request is asynchronous.
+ * Note: This request is asynchronous.
* getServiceState().getState() will not change immediately after this call.
- * registerForServiceStateChanged() to find out when the
+ * registerForServiceStateChanged() to find out when the
* request is complete.
*
- * @param power true means "on", false means "off".
+ * @param power true means "on", false means "off".
*/
void setRadioPower(boolean power);
- /**
+ /**
* Get voice message waiting indicator status. No change notification
* available on this interface. Use PhoneStateNotifier or similar instead.
*
@@ -674,8 +761,8 @@ public interface Phone {
void setLine1Number(String alphaTag, String number, Message onComplete);
/**
- * Get the voice mail access phone number. Typically dialed when the
- * user holds the "1" key in the phone app. May return null if not
+ * Get the voice mail access phone number. Typically dialed when the
+ * user holds the "1" key in the phone app. May return null if not
* available or the SIM is not ready.
*/
String getVoiceMailNumber();
@@ -684,8 +771,8 @@ public interface Phone {
* Returns the alpha tag associated with the voice mail number.
* If there is no alpha tag associated or the record is not yet available,
* returns a default localized string.
- *
- * Please use this value instead of some other localized string when
+ *
+ * Please use this value instead of some other localized string when
* showing a name for this number in the UI. For example, call log
* entries should show this alpha tag.
*
@@ -708,29 +795,29 @@ public interface Phone {
/**
* getCallForwardingOptions
- * gets a call forwarding option. The return value of
- * ((AsyncResult)onComplete.obj) is an array of CallForwardInfo.
- *
- * @param commandInterfaceCFReason is one of the valid call forwarding
- * CF_REASONS, as defined in
- * com.android.internal.telephony.gsm.CommandsInterface
+ * gets a call forwarding option. The return value of
+ * ((AsyncResult)onComplete.obj) is an array of CallForwardInfo.
+ *
+ * @param commandInterfaceCFReason is one of the valid call forwarding
+ * CF_REASONS, as defined in
+ * com.android.internal.telephony.CommandsInterface./code>
* @param onComplete a callback message when the action is completed.
- * @see com.android.internal.telephony.gsm.CallForwardInfo for details.
+ * @see com.android.internal.telephony.CallForwardInfo for details.
*/
void getCallForwardingOption(int commandInterfaceCFReason,
Message onComplete);
-
+
/**
* setCallForwardingOptions
* sets a call forwarding option.
- *
- * @param commandInterfaceCFReason is one of the valid call forwarding
- * CF_REASONS, as defined in
- * com.android.internal.telephony.gsm.CommandsInterface
- * @param commandInterfaceCFAction is one of the valid call forwarding
- * CF_ACTIONS, as defined in
- * com.android.internal.telephony.gsm.CommandsInterface
- * @param dialingNumber is the target phone number to forward calls to
+ *
+ * @param commandInterfaceCFReason is one of the valid call forwarding
+ * CF_REASONS, as defined in
+ * com.android.internal.telephony.CommandsInterface./code>
+ * @param commandInterfaceCFAction is one of the valid call forwarding
+ * CF_ACTIONS, as defined in
+ * com.android.internal.telephony.CommandsInterface./code>
+ * @param dialingNumber is the target phone number to forward calls to
* @param timerSeconds is used by CFNRy to indicate the timeout before
* forwarding is attempted.
* @param onComplete a callback message when the action is completed.
@@ -740,83 +827,83 @@ public interface Phone {
String dialingNumber,
int timerSeconds,
Message onComplete);
-
+
/**
* getOutgoingCallerIdDisplay
- * gets outgoing caller id display. The return value of
+ * gets outgoing caller id display. The return value of
* ((AsyncResult)onComplete.obj) is an array of int, with a length of 2.
- *
+ *
* @param onComplete a callback message when the action is completed.
- * @see com.android.internal.telephony.gsm.CommandsInterface.getCLIR for details.
+ * @see com.android.internal.telephony.CommandsInterface.getCLIR for details.
*/
void getOutgoingCallerIdDisplay(Message onComplete);
-
+
/**
* setOutgoingCallerIdDisplay
- * sets a call forwarding option.
- *
- * @param commandInterfaceCLIRMode is one of the valid call CLIR
- * modes, as defined in
- * com.android.internal.telephony.gsm.CommandsInterface
+ * sets a call forwarding option.
+ *
+ * @param commandInterfaceCLIRMode is one of the valid call CLIR
+ * modes, as defined in
+ * com.android.internal.telephony.CommandsInterface./code>
* @param onComplete a callback message when the action is completed.
*/
void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
Message onComplete);
-
+
/**
* getCallWaiting
- * gets call waiting activation state. The return value of
+ * gets call waiting activation state. The return value of
* ((AsyncResult)onComplete.obj) is an array of int, with a length of 1.
- *
+ *
* @param onComplete a callback message when the action is completed.
- * @see com.android.internal.telephony.gsm.CommandsInterface.queryCallWaiting for details.
+ * @see com.android.internal.telephony.CommandsInterface.queryCallWaiting for details.
*/
void getCallWaiting(Message onComplete);
-
+
/**
* setCallWaiting
- * sets a call forwarding option.
- *
- * @param enable is a boolean representing the state that you are
+ * sets a call forwarding option.
+ *
+ * @param enable is a boolean representing the state that you are
* requesting, true for enabled, false for disabled.
* @param onComplete a callback message when the action is completed.
*/
void setCallWaiting(boolean enable, Message onComplete);
-
+
/**
* Scan available networks. This method is asynchronous; .
* On completion, response.obj
is set to an AsyncResult with
* one of the following members:.
*
- * response.obj.result
will be a List
of
- * com.android.internal.telephony.gsm.NetworkInfo
objects, or
- * response.obj.exception
will be set with an exception
+ * response.obj.result
will be a List
of
+ * com.android.internal.telephony.gsm.NetworkInfo
objects, or
+ * response.obj.exception
will be set with an exception
* on failure.
*
*/
- void getAvailableNetworks(Message response);
+ void getAvailableNetworks(Message response);
/**
* Switches network selection mode to "automatic", re-scanning and
* re-selecting a network if appropriate.
- *
- * @param response The message to dispatch when the network selection
+ *
+ * @param response The message to dispatch when the network selection
* is complete.
- *
- * @see #selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo,
+ *
+ * @see #selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo,
* android.os.Message )
*/
void setNetworkSelectionModeAutomatic(Message response);
/**
- * Manually selects a network. response
is
+ * Manually selects a network. response
is
* dispatched when this is complete. response.obj
will be
* an AsyncResult, and response.obj.exception
will be non-null
* on failure.
- *
+ *
* @see #setNetworkSelectionModeAutomatic(Message)
*/
- void selectNetworkManually(NetworkInfo network,
+ void selectNetworkManually(NetworkInfo network,
Message response);
/**
@@ -843,7 +930,7 @@ public interface Phone {
* of available cell IDs. Cell IDs are in hexadecimal format.
*
* @param response callback message that is dispatched when the query
- * completes.
+ * completes.
*/
void getNeighboringCids(Message response);
@@ -856,28 +943,28 @@ public interface Phone {
* AsyncResult
. Message.obj.result
will be
* a Connection object.
*
- * Message.arg1 will be the post dial character being processed,
+ * Message.arg1 will be the post dial character being processed,
* or 0 ('\0') if end of string.
*
- * If Connection.getPostDialState() == WAIT,
- * the application must call
- * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
- * Connection.proceedAfterWaitChar()} or
- * {@link com.android.internal.telephony.Connection#cancelPostDial()
+ * If Connection.getPostDialState() == WAIT,
+ * the application must call
+ * {@link com.android.internal.telephony.Connection#proceedAfterWaitChar()
+ * Connection.proceedAfterWaitChar()} or
+ * {@link com.android.internal.telephony.Connection#cancelPostDial()
* Connection.cancelPostDial()}
- * for the telephony system to continue playing the post-dial
+ * for the telephony system to continue playing the post-dial
* DTMF sequence.
*
- * If Connection.getPostDialState() == WILD,
- * the application must call
+ * If Connection.getPostDialState() == WILD,
+ * the application must call
* {@link com.android.internal.telephony.Connection#proceedAfterWildChar
* Connection.proceedAfterWildChar()}
- * or
- * {@link com.android.internal.telephony.Connection#cancelPostDial()
+ * or
+ * {@link com.android.internal.telephony.Connection#cancelPostDial()
* Connection.cancelPostDial()}
- * for the telephony system to continue playing the
+ * for the telephony system to continue playing the
* post-dial DTMF sequence.
- *
+ *
* Only one post dial character handler may be set.
* Calling this method with "h" equal to null unsets this handler.
*/
@@ -885,19 +972,19 @@ public interface Phone {
/**
- * Mutes or unmutes the microphone for the active call. The microphone
- * is automatically unmuted if a call is answered, dialed, or resumed
+ * Mutes or unmutes the microphone for the active call. The microphone
+ * is automatically unmuted if a call is answered, dialed, or resumed
* from a holding state.
- *
- * @param muted true to mute the microphone,
+ *
+ * @param muted true to mute the microphone,
* false to activate the microphone.
*/
void setMute(boolean muted);
/**
- * Gets current mute status. Use
- * {@link #registerForPhoneStateChanged(android.os.Handler, int,
+ * Gets current mute status. Use
+ * {@link #registerForPhoneStateChanged(android.os.Handler, int,
* java.lang.Object) registerForPhoneStateChanged()}
* as a change notifcation, although presently phone state changed is not
* fired when setMute() is called.
@@ -908,12 +995,12 @@ public interface Phone {
/**
* Invokes RIL_REQUEST_OEM_HOOK_RAW on RIL implementation.
- *
+ *
* @param data The data for the request.
- * @param response On success,
+ * @param response On success,
* (byte[])(((AsyncResult)response.obj).result)
- * On failure,
- * (((AsyncResult)response.obj).result) == null and
+ * On failure,
+ * (((AsyncResult)response.obj).result) == null and
* (((AsyncResult)response.obj).exception) being an instance of
* com.android.internal.telephony.gsm.CommandException
*
@@ -923,13 +1010,13 @@ public interface Phone {
/**
* Invokes RIL_REQUEST_OEM_HOOK_Strings on RIL implementation.
- *
+ *
* @param strings The strings to make available as the request data.
- * @param response On success, "response" bytes is
+ * @param response On success, "response" bytes is
* made available as:
* (String[])(((AsyncResult)response.obj).result).
- * On failure,
- * (((AsyncResult)response.obj).result) == null and
+ * On failure,
+ * (((AsyncResult)response.obj).result) == null and
* (((AsyncResult)response.obj).exception) being an instance of
* com.android.internal.telephony.gsm.CommandException
*
@@ -940,6 +1027,7 @@ public interface Phone {
/**
* Get the current active PDP context list
*
+ * @deprecated
* @param response On success, "response" bytes is
* made available as:
* (String[])(((AsyncResult)response.obj).result).
@@ -951,13 +1039,34 @@ public interface Phone {
void getPdpContextList(Message response);
/**
+ * Get the current active Data Call list, substitutes getPdpContextList
+ *
+ * @param response On success, "response" bytes is
+ * made available as:
+ * (String[])(((AsyncResult)response.obj).result).
+ * On failure,
+ * (((AsyncResult)response.obj).result) == null and
+ * (((AsyncResult)response.obj).exception) being an instance of
+ * com.android.internal.telephony.gsm.CommandException
+ */
+ void getDataCallList(Message response);
+
+ /**
* Get current mutiple PDP link status
- *
+ *
+ * @deprecated
* @return list of pdp link connections
*/
List getCurrentPdpList ();
/**
+ * Get current mutiple data connection status
+ *
+ * @return list of data connections
+ */
+ List getCurrentDataConnectionList ();
+
+ /**
* Udpate LAC and CID in service state for currnet GSM netowrk registration
*
* If get different LAC and/or CID, notifyServiceState will be sent
@@ -981,11 +1090,11 @@ public interface Phone {
void disableLocationUpdates();
/**
- * For unit tests; don't send notifications to "Phone"
+ * For unit tests; don't send notifications to "Phone"
* mailbox registrants if true.
*/
void setUnitTestMode(boolean f);
-
+
/**
* @return true If unit test mode is enabled
*/
@@ -1019,8 +1128,29 @@ public interface Phone {
void setDataRoamingEnabled(boolean enable);
/**
+ * 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);
+
+ /**
* If this is a simulated phone interface, returns a SimulatedRadioControl.
- * @ return A SimulatedRadioControl if this is a simulated interface;
+ * @ return A SimulatedRadioControl if this is a simulated interface;
* otherwise, null.
*/
SimulatedRadioControl getSimulatedRadioControl();
@@ -1109,7 +1239,7 @@ public interface Phone {
public String[] getDnsServers(String apnType);
/**
- * Retrieves the unique device ID, e.g., IMEI for GSM phones.
+ * Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones.
*/
String getDeviceId();
@@ -1125,7 +1255,81 @@ public interface Phone {
String getSubscriberId();
/**
- * Retrieves the serial number of the SIM, if applicable.
+ * Retrieves the serial number of the ICC, if applicable.
+ */
+ String getIccSerialNumber();
+
+ //***** CDMA support methods
+
+
+ /**
+ * Retrieves the ESN for CDMA phones.
*/
- String getSimSerialNumber();
+ String getEsn();
+
+ /**
+ * Retrieves MEID for CDMA phones.
+ */
+ String getMeid();
+
+ /**
+ * Retrieves the PhoneSubInfo of the Phone
+ */
+ public PhoneSubInfo getPhoneSubInfo();
+
+ /**
+ * Retrieves the IccSmsInterfaceManager of the Phone
+ */
+ public IccSmsInterfaceManager getIccSmsInterfaceManager();
+
+ /**
+ * Retrieves the IccPhoneBookInterfaceManager of the Phone
+ */
+ public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager();
+
+ /**
+ * setTTYModeEnabled
+ * sets a TTY mode option.
+ *
+ * @param enable is a boolean representing the state that you are
+ * requesting, true for enabled, false for disabled.
+ * @param onComplete a callback message when the action is completed
+ */
+ void setTTYModeEnabled(boolean enable, Message onComplete);
+
+ /**
+ * queryTTYModeEnabled
+ * query the status of the TTY mode
+ *
+ * @param onComplete a callback message when the action is completed.
+ */
+ void queryTTYModeEnabled(Message onComplete);
+
+ /**
+ * Activate or deactivate cell broadcast SMS.
+ *
+ * @param activate
+ * 0 = activate, 1 = deactivate
+ * @param response
+ * Callback message is empty on completion
+ */
+ void activateCellBroadcastSms(int activate, Message response);
+
+ /**
+ * Query the current configuration of cdma cell broadcast SMS.
+ *
+ * @param response
+ * Callback message is empty on completion
+ */
+ void getCellBroadcastSmsConfig(Message response);
+
+ /**
+ * Configure cell broadcast SMS.
+ *
+ * @param response
+ * Callback message is empty on completion
+ */
+ public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response);
+
+ public void notifyDataActivity();
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 4fb5f61..259de62 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -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;
+
/**
- * (Not for SDK use)
+ * (Not for SDK use)
* 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;
+
+ // 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
+
+ protected final RegistrantList mPhoneStateRegistrants
= new RegistrantList();
- protected final RegistrantList mNewRingingConnectionRegistrants
+ protected final RegistrantList mNewRingingConnectionRegistrants
= new RegistrantList();
- protected final RegistrantList mIncomingRingRegistrants
+ protected final RegistrantList mIncomingRingRegistrants
= new RegistrantList();
-
- protected final RegistrantList mDisconnectRegistrants
+
+ protected final RegistrantList mDisconnectRegistrants
= new RegistrantList();
- protected final RegistrantList mServiceStateRegistrants
+ protected final RegistrantList mServiceStateRegistrants
= new RegistrantList();
-
- protected final RegistrantList mMmiCompleteRegistrants
+
+ protected final RegistrantList mMmiCompleteRegistrants
= new RegistrantList();
- protected final RegistrantList mMmiRegistrants
+ protected final RegistrantList mMmiRegistrants
= new RegistrantList();
- protected final RegistrantList mUnknownConnectionRegistrants
+ protected final RegistrantList mUnknownConnectionRegistrants
= new RegistrantList();
-
- protected final RegistrantList mSuppServiceFailedRegistrants
+
+ protected final RegistrantList mSuppServiceFailedRegistrants
= new RegistrantList();
-
+
protected Looper mLooper; /* to insure registrants are in correct thread*/
protected Context mContext;
- /**
- * PhoneNotifier is an abstraction for all system-wide
- * state change notification. DefaultPhoneNotifier is
+ /**
+ * PhoneNotifier is an abstraction for all system-wide
+ * state change notification. DefaultPhoneNotifier is
* used here unless running we're inside a unit test.
*/
protected PhoneNotifier mNotifier;
@@ -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 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();
+
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java
index 0ca5f45..3db0499 100644
--- a/telephony/java/com/android/internal/telephony/PhoneFactory.java
+++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java
@@ -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 sPhones = new ArrayList();
+ 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;
-
- //***** Class Methods
+ static final int preferredNetworkMode = RILConstants.PREFERRED_NETWORK_MODE;
- private static void
- useNewRIL(Context context)
- {
- ModelInterpreter mi = null;
- GSMPhone phone;
+ static final int preferredCdmaSubscription = RILConstants.PREFERRED_CDMA_SUBSCRIPTION;
- try {
- if (false) {
- mi = new ModelInterpreter(new InetSocketAddress("127.0.0.1", 6502));
- }
-
- phone = new GSMPhone(context, new RIL(context), sPhoneNotifier);
+ //***** Class Methods
- 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()
- {
- if (!sMadeDefaults) {
- throw new IllegalStateException("Default phones haven't been made yet!");
- }
-
+ public static Phone getDefaultPhone() {
if (sLooper != Looper.myLooper()) {
throw new RuntimeException(
"PhoneFactory.getDefaultPhone must be called from Looper thread");
}
- synchronized (sPhones) {
- return sPhones.isEmpty() ? null : sPhones.get(0);
+ if (!sMadeDefaults) {
+ throw new IllegalStateException("Default phones haven't been made yet!");
}
+ return sProxyPhone;
}
-
- public static void registerPhone(Phone p)
- {
- if (sLooper != Looper.myLooper()) {
- throw new RuntimeException(
- "PhoneFactory.getDefaultPhone must be called from Looper thread");
+
+ public static Phone getCdmaPhone() {
+ synchronized(PhoneProxy.lockForRadioTechnologyChange) {
+ Phone phone = new CDMAPhone(sContext, sCommandsInterface, sPhoneNotifier);
+ return phone;
}
- synchronized (sPhones) {
- sPhones.add(p);
+ }
+
+ public static Phone getGsmPhone() {
+ synchronized(PhoneProxy.lockForRadioTechnologyChange) {
+ Phone phone = new GSMPhone(sContext, sCommandsInterface, sPhoneNotifier);
+ return phone;
}
}
}
+
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
new file mode 100644
index 0000000..dd36f0b
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -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 getCurrentPdpList() {
+ return mActivePhone.getCurrentPdpList();
+ }
+
+ public List 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();
+ }
+}
+
diff --git a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java
index 61d4c9f..fd822cd 100644
--- a/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java
+++ b/telephony/java/com/android/internal/telephony/PhoneStateIntentReceiver.java
@@ -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);
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
index 644d1f4..4d1f7e5 100644
--- a/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfo.java
@@ -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();
}
/**
diff --git a/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
new file mode 100644
index 0000000..450b3a7
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/PhoneSubInfoProxy.java
@@ -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();
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
new file mode 100644
index 0000000..f5d3b32
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -0,0 +1,3050 @@
+/*
+ * 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.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.NeighboringCellInfo;
+import android.telephony.SmsManager;
+import android.telephony.SmsMessage;
+import android.util.Log;
+import android.util.Config;
+
+import static com.android.internal.telephony.RILConstants.*;
+
+import com.android.internal.telephony.CallForwardInfo;
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.gsm.NetworkInfo;
+import com.android.internal.telephony.gsm.PDPContextState;
+import com.android.internal.telephony.gsm.SuppServiceNotification;
+import com.android.internal.telephony.IccCardApplication;
+import com.android.internal.telephony.IccCardStatus;
+import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.SmsResponse;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * {@hide}
+ */
+class RILRequest {
+ static final String LOG_TAG = "RILJ";
+
+ //***** Class Variables
+ static int sNextSerial = 0;
+ static Object sSerialMonitor = new Object();
+ private static Object sPoolSync = new Object();
+ private static RILRequest sPool = null;
+ private static int sPoolSize = 0;
+ private static final int MAX_POOL_SIZE = 4;
+
+ //***** Instance Variables
+ int mSerial;
+ int mRequest;
+ Message mResult;
+ Parcel mp;
+ RILRequest mNext;
+
+ /**
+ * Retrieves a new RILRequest instance from the pool.
+ *
+ * @param request RIL_REQUEST_*
+ * @param result sent when operation completes
+ * @return a RILRequest instance from the pool.
+ */
+ static RILRequest obtain(int request, Message result) {
+ RILRequest rr = null;
+
+ synchronized(sPoolSync) {
+ if (sPool != null) {
+ rr = sPool;
+ sPool = rr.mNext;
+ rr.mNext = null;
+ sPoolSize--;
+ }
+ }
+
+ if (rr == null) {
+ rr = new RILRequest();
+ }
+
+ synchronized(sSerialMonitor) {
+ rr.mSerial = sNextSerial++;
+ }
+ rr.mRequest = request;
+ rr.mResult = result;
+ rr.mp = Parcel.obtain();
+
+ if (result != null && result.getTarget() == null) {
+ throw new NullPointerException("Message target must not be null");
+ }
+
+ // first elements in any RIL Parcel
+ rr.mp.writeInt(request);
+ rr.mp.writeInt(rr.mSerial);
+
+ return rr;
+ }
+
+ /**
+ * Returns a RILRequest instance to the pool.
+ *
+ * Note: This should only be called once per use.
+ */
+ void release() {
+ synchronized (sPoolSync) {
+ if (sPoolSize < MAX_POOL_SIZE) {
+ this.mNext = sPool;
+ sPool = this;
+ sPoolSize++;
+ }
+ }
+ }
+
+ private RILRequest() {
+ }
+
+ static void
+ resetSerial() {
+ synchronized(sSerialMonitor) {
+ sNextSerial = 0;
+ }
+ }
+
+ String
+ serialString() {
+ //Cheesy way to do %04d
+ StringBuilder sb = new StringBuilder(8);
+ String sn;
+
+ sn = Integer.toString(mSerial);
+
+ //sb.append("J[");
+ sb.append('[');
+ for (int i = 0, s = sn.length() ; i < 4 - s; i++) {
+ sb.append('0');
+ }
+
+ sb.append(sn);
+ sb.append(']');
+ return sb.toString();
+ }
+
+ void
+ onError(int error) {
+ CommandException ex;
+
+ ex = CommandException.fromRilErrno(error);
+
+ if (RIL.RILJ_LOGD) Log.d(LOG_TAG, serialString() + "< "
+ + RIL.requestToString(mRequest)
+ + " error: " + ex);
+
+ if (mResult != null) {
+ AsyncResult.forMessage(mResult, null, ex);
+ mResult.sendToTarget();
+ }
+
+ if (mp != null) {
+ mp.recycle();
+ mp = null;
+ }
+ }
+}
+
+
+/**
+ * RIL implementation of the CommandsInterface.
+ * FIXME public only for testing
+ *
+ * {@hide}
+ */
+public final class RIL extends BaseCommands implements CommandsInterface {
+ static final String LOG_TAG = "RILJ";
+ private static final boolean DBG = false;
+ static final boolean RILJ_LOGD = Config.LOGD;
+ static final boolean RILJ_LOGV = DBG ? Config.LOGD : Config.LOGV;
+ static int WAKE_LOCK_TIMEOUT = 5000;
+
+ //***** Instance Variables
+
+ LocalSocket mSocket;
+ HandlerThread mSenderThread;
+ RILSender mSender;
+ Thread mReceiverThread;
+ RILReceiver mReceiver;
+ private Context mContext;
+ WakeLock mWakeLock;
+ int mRequestMessagesPending;
+
+ // Is this the first radio state change?
+ private boolean mInitialRadioStateChange = true;
+
+ //I'd rather this be LinkedList or something
+ ArrayList mRequestsList = new ArrayList();
+
+ Object mLastNITZTimeInfo;
+
+ //***** Events
+
+ static final int EVENT_SEND = 1;
+ static final int EVENT_WAKE_LOCK_TIMEOUT = 2;
+
+ //***** Constants
+
+ // match with constant in ril.cpp
+ static final int RIL_MAX_COMMAND_BYTES = (8 * 1024);
+ static final int RESPONSE_SOLICITED = 0;
+ static final int RESPONSE_UNSOLICITED = 1;
+
+ static final String SOCKET_NAME_RIL = "rild";
+
+ static final int SOCKET_OPEN_RETRY_MILLIS = 4 * 1000;
+
+
+ BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
+ sendScreenState(true);
+ } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+ sendScreenState(false);
+ } else {
+ Log.w(LOG_TAG, "RIL received unexpected Intent: " + intent.getAction());
+ }
+ }
+ };
+
+ class RILSender extends Handler implements Runnable {
+ public RILSender(Looper looper) {
+ super(looper);
+ }
+
+ // Only allocated once
+ byte[] dataLength = new byte[4];
+
+ //***** Runnable implementation
+ public void
+ run() {
+ //setup if needed
+ }
+
+
+ //***** Handler implemementation
+
+ public void
+ handleMessage(Message msg) {
+ RILRequest rr = (RILRequest)(msg.obj);
+ RILRequest req = null;
+
+ switch (msg.what) {
+ case EVENT_SEND:
+ /**
+ * mRequestMessagePending++ already happened for every
+ * EVENT_SEND, thus we must make sure
+ * mRequestMessagePending-- happens once and only once
+ */
+ boolean alreadySubtracted = false;
+ try {
+ LocalSocket s;
+
+ s = mSocket;
+
+ if (s == null) {
+ rr.onError(RADIO_NOT_AVAILABLE);
+ rr.release();
+ mRequestMessagesPending--;
+ alreadySubtracted = true;
+ return;
+ }
+
+ synchronized (mRequestsList) {
+ mRequestsList.add(rr);
+ }
+
+ mRequestMessagesPending--;
+ alreadySubtracted = true;
+
+ byte[] data;
+
+ data = rr.mp.marshall();
+ rr.mp.recycle();
+ rr.mp = null;
+
+ if (data.length > RIL_MAX_COMMAND_BYTES) {
+ throw new RuntimeException(
+ "Parcel larger than max bytes allowed! "
+ + data.length);
+ }
+
+ // parcel length in big endian
+ dataLength[0] = dataLength[1] = 0;
+ dataLength[2] = (byte)((data.length >> 8) & 0xff);
+ dataLength[3] = (byte)((data.length) & 0xff);
+
+ //Log.v(LOG_TAG, "writing packet: " + data.length + " bytes");
+
+ s.getOutputStream().write(dataLength);
+ s.getOutputStream().write(data);
+ } catch (IOException ex) {
+ Log.e(LOG_TAG, "IOException", ex);
+ req = findAndRemoveRequestFromList(rr.mSerial);
+ // make sure this request has not already been handled,
+ // eg, if RILReceiver cleared the list.
+ if (req != null || !alreadySubtracted) {
+ rr.onError(RADIO_NOT_AVAILABLE);
+ rr.release();
+ }
+ } catch (RuntimeException exc) {
+ Log.e(LOG_TAG, "Uncaught exception ", exc);
+ req = findAndRemoveRequestFromList(rr.mSerial);
+ // make sure this request has not already been handled,
+ // eg, if RILReceiver cleared the list.
+ if (req != null || !alreadySubtracted) {
+ rr.onError(GENERIC_FAILURE);
+ rr.release();
+ }
+ }
+
+ if (!alreadySubtracted) {
+ mRequestMessagesPending--;
+ }
+
+ break;
+
+ case EVENT_WAKE_LOCK_TIMEOUT:
+ // Haven't heard back from the last request. Assume we're
+ // not getting a response and release the wake lock.
+ // TODO should we clean up mRequestList and mRequestPending
+ synchronized (mWakeLock) {
+ if (mWakeLock.isHeld()) {
+ if (RILJ_LOGD) {
+ synchronized (mRequestsList) {
+ int count = mRequestsList.size();
+ Log.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " +
+ " mReqPending=" + mRequestMessagesPending +
+ " mRequestList=" + count);
+
+ for (int i = 0; i < count; i++) {
+ rr = mRequestsList.get(i);
+ Log.d(LOG_TAG, i + ": [" + rr.mSerial + "] " +
+ requestToString(rr.mRequest));
+
+ }
+ }
+ }
+ mWakeLock.release();
+ }
+ }
+
+ break;
+ }
+ }
+ }
+
+ /**
+ * Reads in a single RIL message off the wire. A RIL message consists
+ * of a 4-byte little-endian length and a subsequent series of bytes.
+ * The final message (length header omitted) is read into
+ * buffer
and the length of the final message (less header)
+ * is returned. A return value of -1 indicates end-of-stream.
+ *
+ * @param is non-null; Stream to read from
+ * @param buffer Buffer to fill in. Must be as large as maximum
+ * message size, or an ArrayOutOfBounds exception will be thrown.
+ * @return Length of message less header, or -1 on end of stream.
+ * @throws IOException
+ */
+ private static int readRilMessage(InputStream is, byte[] buffer)
+ throws IOException {
+ int countRead;
+ int offset;
+ int remaining;
+ int messageLength;
+
+ // First, read in the length of the message
+ offset = 0;
+ remaining = 4;
+ do {
+ countRead = is.read(buffer, offset, remaining);
+
+ if (countRead < 0 ) {
+ Log.e(LOG_TAG, "Hit EOS reading message length");
+ return -1;
+ }
+
+ offset += countRead;
+ remaining -= countRead;
+ } while (remaining > 0);
+
+ messageLength = ((buffer[0] & 0xff) << 24)
+ | ((buffer[1] & 0xff) << 16)
+ | ((buffer[2] & 0xff) << 8)
+ | (buffer[3] & 0xff);
+
+ // Then, re-use the buffer and read in the message itself
+ offset = 0;
+ remaining = messageLength;
+ do {
+ countRead = is.read(buffer, offset, remaining);
+
+ if (countRead < 0 ) {
+ Log.e(LOG_TAG, "Hit EOS reading message. messageLength=" + messageLength
+ + " remaining=" + remaining);
+ return -1;
+ }
+
+ offset += countRead;
+ remaining -= countRead;
+ } while (remaining > 0);
+
+ return messageLength;
+ }
+
+ class RILReceiver implements Runnable {
+ byte[] buffer;
+
+ RILReceiver() {
+ buffer = new byte[RIL_MAX_COMMAND_BYTES];
+ }
+
+ public void
+ run() {
+ int retryCount = 0;
+
+ try {for (;;) {
+ LocalSocket s = null;
+ LocalSocketAddress l;
+
+ try {
+ s = new LocalSocket();
+ l = new LocalSocketAddress(SOCKET_NAME_RIL,
+ LocalSocketAddress.Namespace.RESERVED);
+ s.connect(l);
+ } catch (IOException ex){
+ try {
+ if (s != null) {
+ s.close();
+ }
+ } catch (IOException ex2) {
+ //ignore failure to close after failure to connect
+ }
+
+ // don't print an error message after the the first time
+ // or after the 8th time
+
+ if (retryCount == 8) {
+ Log.e (LOG_TAG,
+ "Couldn't find '" + SOCKET_NAME_RIL
+ + "' socket after " + retryCount
+ + " times, continuing to retry silently");
+ } else if (retryCount > 0 && retryCount < 8) {
+ Log.i (LOG_TAG,
+ "Couldn't find '" + SOCKET_NAME_RIL
+ + "' socket; retrying after timeout");
+ }
+
+ try {
+ Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
+ } catch (InterruptedException er) {
+ }
+
+ retryCount++;
+ continue;
+ }
+
+ retryCount = 0;
+
+ mSocket = s;
+ Log.i(LOG_TAG, "Connected to '" + SOCKET_NAME_RIL + "' socket");
+
+ int length = 0;
+ try {
+ InputStream is = mSocket.getInputStream();
+
+ for (;;) {
+ Parcel p;
+
+ length = readRilMessage(is, buffer);
+
+ if (length < 0) {
+ // End-of-stream reached
+ break;
+ }
+
+ p = Parcel.obtain();
+ p.unmarshall(buffer, 0, length);
+ p.setDataPosition(0);
+
+ //Log.v(LOG_TAG, "Read packet: " + length + " bytes");
+
+ processResponse(p);
+ p.recycle();
+ }
+ } catch (java.io.IOException ex) {
+ Log.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed",
+ ex);
+ } catch (Throwable tr) {
+ Log.e(LOG_TAG, "Uncaught exception read length=" + length +
+ "Exception:" + tr.toString());
+ }
+
+ Log.i(LOG_TAG, "Disconnected from '" + SOCKET_NAME_RIL
+ + "' socket");
+
+ setRadioState (RadioState.RADIO_UNAVAILABLE);
+
+ try {
+ mSocket.close();
+ } catch (IOException ex) {
+ }
+
+ mSocket = null;
+ RILRequest.resetSerial();
+
+ // Clear request list on close
+ synchronized (mRequestsList) {
+ for (int i = 0, sz = mRequestsList.size() ; i < sz ; i++) {
+ RILRequest rr = mRequestsList.get(i);
+ rr.onError(RADIO_NOT_AVAILABLE);
+ rr.release();
+ }
+
+ mRequestsList.clear();
+ }
+ }} catch (Throwable tr) {
+ Log.e(LOG_TAG,"Uncaught exception", tr);
+ }
+ }
+ }
+
+
+
+ //***** Constructors
+ public
+ RIL(Context context) {
+ this(context, RILConstants.PREFERRED_NETWORK_MODE,
+ RILConstants.PREFERRED_CDMA_SUBSCRIPTION);
+ }
+
+ public RIL(Context context, int networkMode, int cdmaSubscription) {
+ super(context);
+ mCdmaSubscription = cdmaSubscription;
+ mNetworkMode = networkMode;
+ //At startup mPhoneType is first set from networkMode
+ switch(networkMode) {
+ case RILConstants.NETWORK_MODE_WCDMA_PREF:
+ case RILConstants.NETWORK_MODE_GSM_ONLY:
+ case RILConstants.NETWORK_MODE_WCDMA_ONLY:
+ case RILConstants.NETWORK_MODE_GSM_UMTS:
+ mPhoneType = RILConstants.GSM_PHONE;
+ break;
+ case RILConstants.NETWORK_MODE_CDMA:
+ case RILConstants.NETWORK_MODE_CDMA_NO_EVDO:
+ case RILConstants.NETWORK_MODE_EVDO_NO_CDMA:
+ mPhoneType = RILConstants.CDMA_PHONE;
+ break;
+ case RILConstants.NETWORK_MODE_GLOBAL:
+ mPhoneType = RILConstants.CDMA_PHONE;
+ break;
+ default:
+ mPhoneType = RILConstants.CDMA_PHONE;
+ }
+
+ PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
+ mWakeLock.setReferenceCounted(false);
+ mRequestMessagesPending = 0;
+
+ mContext = context;
+
+ mSenderThread = new HandlerThread("RILSender");
+ mSenderThread.start();
+
+ Looper looper = mSenderThread.getLooper();
+ mSender = new RILSender(looper);
+
+ mReceiver = new RILReceiver();
+ mReceiverThread = new Thread(mReceiver, "RILReceiver");
+ mReceiverThread.start();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_SCREEN_ON);
+ filter.addAction(Intent.ACTION_SCREEN_OFF);
+ context.registerReceiver(mIntentReceiver, filter);
+ }
+
+ //***** CommandsInterface implementation
+
+ @Override public void
+ setOnNITZTime(Handler h, int what, Object obj) {
+ super.setOnNITZTime(h, what, obj);
+
+ // Send the last NITZ time if we have it
+ if (mLastNITZTimeInfo != null) {
+ mNITZTimeRegistrant
+ .notifyRegistrant(
+ new AsyncResult (null, mLastNITZTimeInfo, null));
+ mLastNITZTimeInfo = null;
+ }
+ }
+
+ public void
+ getIccStatus(Message result) {
+ //Note: This RIL request has not been renamed to ICC,
+ // but this request is also valid for SIM and RUIM
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ supplyIccPin(String pin, Message result) {
+ //Note: This RIL request has not been renamed to ICC,
+ // but this request is also valid for SIM and RUIM
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeInt(1);
+ rr.mp.writeString(pin);
+
+ send(rr);
+ }
+
+ public void
+ supplyIccPuk(String puk, String newPin, Message result) {
+ //Note: This RIL request has not been renamed to ICC,
+ // but this request is also valid for SIM and RUIM
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeInt(2);
+ rr.mp.writeString(puk);
+ rr.mp.writeString(newPin);
+
+ send(rr);
+ }
+
+ public void
+ supplyIccPin2(String pin, Message result) {
+ //Note: This RIL request has not been renamed to ICC,
+ // but this request is also valid for SIM and RUIM
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN2, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeInt(1);
+ rr.mp.writeString(pin);
+
+ send(rr);
+ }
+
+ public void
+ supplyIccPuk2(String puk, String newPin2, Message result) {
+ //Note: This RIL request has not been renamed to ICC,
+ // but this request is also valid for SIM and RUIM
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK2, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeInt(2);
+ rr.mp.writeString(puk);
+ rr.mp.writeString(newPin2);
+
+ send(rr);
+ }
+
+ public void
+ changeIccPin(String oldPin, String newPin, Message result) {
+ //Note: This RIL request has not been renamed to ICC,
+ // but this request is also valid for SIM and RUIM
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeInt(2);
+ rr.mp.writeString(oldPin);
+ rr.mp.writeString(newPin);
+
+ send(rr);
+ }
+
+ public void
+ changeIccPin2(String oldPin2, String newPin2, Message result) {
+ //Note: This RIL request has not been renamed to ICC,
+ // but this request is also valid for SIM and RUIM
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN2, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeInt(2);
+ rr.mp.writeString(oldPin2);
+ rr.mp.writeString(newPin2);
+
+ send(rr);
+ }
+
+ public void
+ changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_BARRING_PASSWORD, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeInt(3);
+ rr.mp.writeString(facility);
+ rr.mp.writeString(oldPwd);
+ rr.mp.writeString(newPwd);
+
+ send(rr);
+ }
+
+ public void
+ supplyNetworkDepersonalization(String netpin, Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeInt(1);
+ rr.mp.writeString(netpin);
+
+ send(rr);
+ }
+
+ public void
+ getCurrentCalls (Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getPDPContextList(Message result) {
+ getDataCallList(result);
+ }
+
+ public void
+ getDataCallList(Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_DATA_CALL_LIST, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ dial (String address, int clirMode, Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
+
+ rr.mp.writeString(address);
+ rr.mp.writeInt(clirMode);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getIMSI(Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() +
+ "> getIMSI:RIL_REQUEST_GET_IMSI " +
+ RIL_REQUEST_GET_IMSI +
+ " " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getIMEI(Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEI, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getIMEISV(Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEISV, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+
+ public void
+ hangupConnection (int gsmIndex, Message result) {
+ if (RILJ_LOGD) riljLog("hangupConnection: gsmIndex=" + gsmIndex);
+
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " +
+ gsmIndex);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(gsmIndex);
+
+ send(rr);
+ }
+
+ public void
+ hangupWaitingOrBackground (Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
+ result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ hangupForegroundResumeBackground (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(
+ RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
+ result);
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ switchWaitingOrHoldingAndActive (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(
+ RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE,
+ result);
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ conference (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_CONFERENCE, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+
+ public void setPreferredVoicePrivacy(boolean enable, Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE,
+ result);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(enable ? 1:0);
+
+ send(rr);
+ }
+
+ public void getPreferredVoicePrivacy(Message result) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE,
+ result);
+ send(rr);
+ }
+
+ public void
+ separateConnection (int gsmIndex, Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SEPARATE_CONNECTION, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " " + gsmIndex);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(gsmIndex);
+
+ send(rr);
+ }
+
+ public void
+ acceptCall (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_ANSWER, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ rejectCall (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_UDUB, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ explicitCallTransfer (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_EXPLICIT_CALL_TRANSFER, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getLastCallFailCause (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ /**
+ * @deprecated
+ */
+ public void
+ getLastPdpFailCause (Message result) {
+ getLastDataCallFailCause (result);
+ }
+
+ /**
+ * The preferred new alternative to getLastPdpFailCause
+ */
+ public void
+ getLastDataCallFailCause (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ setMute (boolean enableMute, Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SET_MUTE, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " " + enableMute);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(enableMute ? 1 : 0);
+
+ send(rr);
+ }
+
+ public void
+ getMute (Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_GET_MUTE, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getSignalStrength (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SIGNAL_STRENGTH, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getRegistrationState (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_REGISTRATION_STATE, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getGPRSRegistrationState (Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_GPRS_REGISTRATION_STATE, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getOperator(Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_OPERATOR, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ sendDtmf(char c, Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_DTMF, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeString(Character.toString(c));
+
+ send(rr);
+ }
+
+ public void
+ startDtmf(char c, Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_DTMF_START, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeString(Character.toString(c));
+
+ send(rr);
+ }
+
+ public void
+ stopDtmf(Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_DTMF_STOP, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+
+ public void
+ sendSMS (String smscPDU, String pdu, Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result);
+
+ rr.mp.writeInt(2);
+ rr.mp.writeString(smscPDU);
+ rr.mp.writeString(pdu);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ sendCdmaSms(byte[] pdu, Message result) {
+ int address_nbr_of_digits;
+ int subaddr_nbr_of_digits;
+ int bearerDataLength;
+ ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
+ DataInputStream dis = new DataInputStream(bais);
+
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_CDMA_SEND_SMS, result);
+
+ try {
+ rr.mp.writeInt(dis.readInt()); //teleServiceId
+ rr.mp.writeByte((byte) dis.readInt()); //servicePresent
+ rr.mp.writeInt(dis.readInt()); //serviceCategory
+ rr.mp.writeInt(dis.read()); //address_digit_mode
+ rr.mp.writeInt(dis.read()); //address_nbr_mode
+ rr.mp.writeInt(dis.read()); //address_ton
+ rr.mp.writeInt(dis.read()); //address_nbr_plan
+ address_nbr_of_digits = (byte) dis.read();
+ rr.mp.writeByte((byte) address_nbr_of_digits);
+ for(int i=0; i < address_nbr_of_digits; i++){
+ rr.mp.writeByte(dis.readByte()); // address_orig_bytes[i]
+ }
+ rr.mp.writeInt(dis.read()); //subaddressType
+ rr.mp.writeByte((byte) dis.read()); //subaddr_odd
+ subaddr_nbr_of_digits = (byte) dis.read();
+ rr.mp.writeByte((byte) subaddr_nbr_of_digits);
+ for(int i=0; i < subaddr_nbr_of_digits; i++){
+ rr.mp.writeByte(dis.readByte()); //subaddr_orig_bytes[i]
+ }
+
+ bearerDataLength = dis.read();
+ rr.mp.writeInt(bearerDataLength);
+ for(int i=0; i < bearerDataLength; i++){
+ rr.mp.writeByte(dis.readByte()); //bearerData[i]
+ }
+ }catch (IOException ex){
+ if (RILJ_LOGD) riljLog("sendSmsCdma: conversion from input stream to object failed: "
+ + ex);
+ }
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void deleteSmsOnSim(int index, Message response) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_DELETE_SMS_ON_SIM,
+ response);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(index);
+
+ if (Config.LOGD) {
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ + requestToString(rr.mRequest)
+ + " " + index);
+ }
+
+ send(rr);
+ }
+
+ public void deleteSmsOnRuim(int index, Message response) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM,
+ response);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(index);
+
+ if (Config.LOGD) {
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ + requestToString(rr.mRequest)
+ + " " + index);
+ }
+
+ send(rr);
+ }
+
+ public void writeSmsToSim(int status, String smsc, String pdu, Message response) {
+ status = translateStatus(status);
+
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_WRITE_SMS_TO_SIM,
+ response);
+
+ rr.mp.writeInt(status);
+ rr.mp.writeString(pdu);
+ rr.mp.writeString(smsc);
+
+ if (Config.LOGD) {
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ + requestToString(rr.mRequest)
+ + " " + status);
+ }
+
+ send(rr);
+ }
+
+ public void writeSmsToRuim(int status, String pdu, Message response) {
+ status = translateStatus(status);
+
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM,
+ response);
+
+ rr.mp.writeInt(status);
+ rr.mp.writeString(pdu);
+
+ if (Config.LOGD) {
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ + requestToString(rr.mRequest)
+ + " " + status);
+ }
+
+ send(rr);
+ }
+
+ /**
+ * Translates EF_SMS status bits to a status value compatible with
+ * SMS AT commands. See TS 27.005 3.1.
+ */
+ private int translateStatus(int status) {
+ switch(status & 0x7) {
+ case SmsManager.STATUS_ON_ICC_READ:
+ return 1;
+ case SmsManager.STATUS_ON_ICC_UNREAD:
+ return 0;
+ case SmsManager.STATUS_ON_ICC_SENT:
+ return 3;
+ case SmsManager.STATUS_ON_ICC_UNSENT:
+ return 2;
+ }
+
+ // Default to READ.
+ return 1;
+ }
+
+ /**
+ * @deprecated
+ */
+ public void
+ setupDefaultPDP(String apn, String user, String password, Message result) {
+ String radioTechnology = "1"; //0 for CDMA, 1 for GSM/UMTS
+ String profile = ""; //profile number, NULL for GSM/UMTS
+ setupDataCall(radioTechnology, profile, apn, user,
+ password, result);
+
+ }
+
+ /**
+ * @deprecated
+ */
+ public void
+ deactivateDefaultPDP(int cid, Message result) {
+ deactivateDataCall(cid, result);
+ }
+
+ /**
+ * The preferred new alternative to setupDefaultPDP that is
+ * CDMA-compatible.
+ *
+ */
+ public void
+ setupDataCall(String radioTechnology, String profile, String apn,
+ String user, String password, Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
+
+ rr.mp.writeInt(5);
+
+ rr.mp.writeString(radioTechnology);
+ rr.mp.writeString(profile);
+ rr.mp.writeString(apn);
+ rr.mp.writeString(user);
+ rr.mp.writeString(password);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " "
+ + apn);
+
+ send(rr);
+ }
+
+ public void
+ deactivateDataCall(int cid, Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_DEACTIVATE_DATA_CALL, result);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeString(Integer.toString(cid));
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " +
+ requestToString(rr.mRequest) + " " + cid);
+
+ send(rr);
+ }
+
+ public void
+ setRadioPower(boolean on, Message result) {
+ //if radio is OFF set preferred NW type and cmda subscription
+ if(mInitialRadioStateChange) {
+ synchronized (mStateMonitor) {
+ if (!mState.isOn()) {
+ RILRequest rrPnt = RILRequest.obtain(
+ RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, null);
+
+ rrPnt.mp.writeInt(1);
+ rrPnt.mp.writeInt(mNetworkMode);
+ if (RILJ_LOGD) riljLog(rrPnt.serialString() + "> "
+ + requestToString(rrPnt.mRequest) + " : " + mNetworkMode);
+
+ send(rrPnt);
+
+ RILRequest rrCs = RILRequest.obtain(
+ RIL_REQUEST_CDMA_SET_SUBSCRIPTION, null);
+ rrCs.mp.writeInt(1);
+ rrCs.mp.writeInt(mCdmaSubscription);
+ if (RILJ_LOGD) riljLog(rrCs.serialString() + "> "
+ + requestToString(rrCs.mRequest) + " : " + mCdmaSubscription);
+ send(rrCs);
+ }
+ }
+ }
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(on ? 1 : 0);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ setSuppServiceNotifications(boolean enable, Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, result);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(enable ? 1 : 0);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ acknowledgeLastIncomingSMS(boolean success, Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SMS_ACKNOWLEDGE, result);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(success ? 1 : 0);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ acknowledgeLastIncomingCdmaSms(boolean success, Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE, result);
+
+ rr.mp.writeInt(success ? 0 : 1); //RIL_CDMA_SMS_ErrorClass
+ // cause code according to X.S004-550E
+ rr.mp.writeInt(39); //39 means other terminal problem; is not interpreted for success.
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+
+ public void
+ iccIO (int command, int fileid, String path, int p1, int p2, int p3,
+ String data, String pin2, Message result) {
+ //Note: This RIL request has not been renamed to ICC,
+ // but this request is also valid for SIM and RUIM
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SIM_IO, result);
+
+ rr.mp.writeInt(command);
+ rr.mp.writeInt(fileid);
+ rr.mp.writeString(path);
+ rr.mp.writeInt(p1);
+ rr.mp.writeInt(p2);
+ rr.mp.writeInt(p3);
+ rr.mp.writeString(data);
+ rr.mp.writeString(pin2);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> iccIO: " + requestToString(rr.mRequest)
+ + " 0x" + Integer.toHexString(command)
+ + " 0x" + Integer.toHexString(fileid) + " "
+ + p1 + "," + p2 + "," + p3);
+
+ send(rr);
+ }
+
+ public void
+ getCLIR(Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_GET_CLIR, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ setCLIR(int clirMode, Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SET_CLIR, result);
+
+ // count ints
+ rr.mp.writeInt(1);
+
+ rr.mp.writeInt(clirMode);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " " + clirMode);
+
+ send(rr);
+ }
+
+ public void
+ queryCallWaiting(int serviceClass, Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_QUERY_CALL_WAITING, response);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(serviceClass);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " " + serviceClass);
+
+ send(rr);
+ }
+
+ public void
+ setCallWaiting(boolean enable, int serviceClass, Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SET_CALL_WAITING, response);
+
+ rr.mp.writeInt(2);
+ rr.mp.writeInt(enable ? 1 : 0);
+ rr.mp.writeInt(serviceClass);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " " + enable + ", " + serviceClass);
+
+ send(rr);
+ }
+
+ public void
+ setNetworkSelectionModeAutomatic(Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
+ response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ setNetworkSelectionModeManual(String operatorNumeric, Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
+ response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " " + operatorNumeric);
+
+ rr.mp.writeString(operatorNumeric);
+
+ send(rr);
+ }
+
+ public void
+ getNetworkSelectionMode(Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE,
+ response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getAvailableNetworks(Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS,
+ response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ setCallForward(int action, int cfReason, int serviceClass,
+ String number, int timeSeconds, Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SET_CALL_FORWARD, response);
+
+ rr.mp.writeInt(action);
+ rr.mp.writeInt(cfReason);
+ rr.mp.writeInt(serviceClass);
+ rr.mp.writeInt(PhoneNumberUtils.toaFromString(number));
+ rr.mp.writeString(number);
+ rr.mp.writeInt (timeSeconds);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " " + action + " " + cfReason + " " + serviceClass
+ + timeSeconds);
+
+ send(rr);
+ }
+
+ public void
+ queryCallForwardStatus(int cfReason, int serviceClass,
+ String number, Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, response);
+
+ rr.mp.writeInt(2); // 2 is for query action, not in used anyway
+ rr.mp.writeInt(cfReason);
+ rr.mp.writeInt(serviceClass);
+ rr.mp.writeInt(PhoneNumberUtils.toaFromString(number));
+ rr.mp.writeString(number);
+ rr.mp.writeInt (0);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " " + cfReason + " " + serviceClass);
+
+ send(rr);
+ }
+
+ public void
+ queryCLIP(Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_QUERY_CLIP, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+
+ public void
+ getBasebandVersion (Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_BASEBAND_VERSION, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ queryFacilityLock (String facility, String password, int serviceClass,
+ Message response) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_FACILITY_LOCK, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ // count strings
+ rr.mp.writeInt(3);
+
+ rr.mp.writeString(facility);
+ rr.mp.writeString(password);
+
+ rr.mp.writeString(Integer.toString(serviceClass));
+
+ send(rr);
+ }
+
+ public void
+ setFacilityLock (String facility, boolean lockState, String password,
+ int serviceClass, Message response) {
+ String lockString;
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ // count strings
+ rr.mp.writeInt(4);
+
+ rr.mp.writeString(facility);
+ lockString = (lockState)?"1":"0";
+ rr.mp.writeString(lockString);
+ rr.mp.writeString(password);
+ rr.mp.writeString(Integer.toString(serviceClass));
+
+ send(rr);
+
+ }
+
+ public void
+ sendUSSD (String ussdString, Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SEND_USSD, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " " + ussdString);
+
+ rr.mp.writeString(ussdString);
+
+ send(rr);
+ }
+
+ // inherited javadoc suffices
+ public void cancelPendingUssd (Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_CANCEL_USSD, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString()
+ + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+
+ public void resetRadio(Message result) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_RESET_RADIO, result);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void invokeOemRilRequestRaw(byte[] data, Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_RAW, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + "[" + IccUtils.bytesToHexString(data) + "]");
+
+ rr.mp.writeByteArray(data);
+
+ send(rr);
+
+ }
+
+ public void invokeOemRilRequestStrings(String[] strings, Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_STRINGS, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeStringArray(strings);
+
+ send(rr);
+ }
+
+ /**
+ * Assign a specified band for RF configuration.
+ *
+ * @param bandMode one of BM_*_BAND
+ * @param response is callback message
+ */
+ public void setBandMode (int bandMode, Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_SET_BAND_MODE, response);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(bandMode);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " " + bandMode);
+
+ send(rr);
+ }
+
+ /**
+ * 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
+ */
+ public void queryAvailableBandMode (Message response) {
+ RILRequest rr
+ = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE,
+ response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void sendTerminalResponse(String contents, Message response) {
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeString(contents);
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void sendEnvelope(String contents, Message response) {
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ rr.mp.writeString(contents);
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void handleCallSetupRequestFromSim(
+ boolean accept, Message response) {
+
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM,
+ response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ int[] param = new int[1];
+ param[0] = accept ? 1 : 0;
+ rr.mp.writeIntArray(param);
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setPreferredNetworkType(int networkType , Message response) {
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, response);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(networkType);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " : " + networkType);
+
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void getPreferredNetworkType(Message response) {
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void getNeighboringCids(Message response) {
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setLocationUpdates(boolean enable, Message response) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_LOCATION_UPDATES, response);
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(enable ? 1 : 0);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ + requestToString(rr.mRequest) + ": " + enable);
+
+ send(rr);
+ }
+
+ //***** Private Methods
+
+ private void sendScreenState(boolean on) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_SCREEN_STATE, null);
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(on ? 1 : 0);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + on);
+
+ send(rr);
+ }
+
+ protected void
+ onRadioAvailable() {
+ // In case screen state was lost (due to process crash),
+ // this ensures that the RIL knows the correct screen state.
+
+ // TODO: Should query Power Manager and send the actual
+ // screen state. Just send true for now.
+ sendScreenState(true);
+ }
+
+ private void setRadioStateFromRILInt(int state) {
+ RadioState newState;
+
+ /* RIL_RadioState ril.h */
+ switch(state) {
+ case 0: newState = RadioState.RADIO_OFF; break;
+ case 1: newState = RadioState.RADIO_UNAVAILABLE; break;
+ case 2: newState = RadioState.SIM_NOT_READY; break;
+ case 3: newState = RadioState.SIM_LOCKED_OR_ABSENT; break;
+ case 4: newState = RadioState.SIM_READY; break;
+ case 5: newState = RadioState.RUIM_NOT_READY; break;
+ case 6: newState = RadioState.RUIM_READY; break;
+ case 7: newState = RadioState.RUIM_LOCKED_OR_ABSENT; break;
+ case 8: newState = RadioState.NV_NOT_READY; break;
+ case 9: newState = RadioState.NV_READY; break;
+
+ default:
+ throw new RuntimeException(
+ "Unrecognized RIL_RadioState: " +state);
+ }
+
+ if (mInitialRadioStateChange) {
+ if (newState.isOn()) {
+ /* If this is our first notification, make sure the radio
+ * is powered off. This gets the radio into a known state,
+ * since it's possible for the phone proc to have restarted
+ * (eg, if it or the runtime crashed) without the RIL
+ * and/or radio knowing.
+ */
+ if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF");
+ setRadioPower(false, null);
+ } else {
+ if (DBG) Log.d(LOG_TAG, "Radio OFF @ init");
+ setRadioState(newState);
+ }
+ mInitialRadioStateChange = false;
+ } else {
+ setRadioState(newState);
+ }
+ }
+
+ /**
+ * Holds a PARTIAL_WAKE_LOCK whenever
+ * a) There is outstanding RIL request sent to RIL deamon and no replied
+ * b) There is a request waiting to be sent out.
+ *
+ * There is a WAKE_LOCK_TIMEOUT to release the lock, though it shouldn't
+ * happen often.
+ */
+
+ private void
+ acquireWakeLock() {
+ synchronized (mWakeLock) {
+ mWakeLock.acquire();
+ mRequestMessagesPending++;
+
+ mSender.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
+ Message msg = mSender.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);
+ mSender.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT);
+ }
+ }
+
+ private void
+ releaseWakeLockIfDone() {
+ synchronized (mWakeLock) {
+ if (mWakeLock.isHeld() &&
+ (mRequestMessagesPending == 0) &&
+ (mRequestsList.size() == 0)) {
+ mSender.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
+ mWakeLock.release();
+ }
+ }
+ }
+
+ private void
+ send(RILRequest rr) {
+ Message msg;
+
+ msg = mSender.obtainMessage(EVENT_SEND, rr);
+
+ acquireWakeLock();
+
+ msg.sendToTarget();
+ }
+
+ private void
+ processResponse (Parcel p) {
+ int type;
+
+ type = p.readInt();
+
+ if (type == RESPONSE_UNSOLICITED) {
+ processUnsolicited (p);
+ } else if (type == RESPONSE_SOLICITED) {
+ processSolicited (p);
+ }
+
+ releaseWakeLockIfDone();
+ }
+
+ private RILRequest findAndRemoveRequestFromList(int serial) {
+ synchronized (mRequestsList) {
+ for (int i = 0, s = mRequestsList.size() ; i < s ; i++) {
+ RILRequest rr = mRequestsList.get(i);
+
+ if (rr.mSerial == serial) {
+ mRequestsList.remove(i);
+ return rr;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private void
+ processSolicited (Parcel p) {
+ int serial, error;
+ boolean found = false;
+
+ serial = p.readInt();
+ error = p.readInt();
+
+ RILRequest rr;
+
+ rr = findAndRemoveRequestFromList(serial);
+
+ if (rr == null) {
+ Log.w(LOG_TAG, "Unexpected solicited response! sn: "
+ + serial + " error: " + error);
+ return;
+ }
+
+ if (error != 0) {
+ rr.onError(error);
+ rr.release();
+ return;
+ }
+
+ Object ret;
+
+ try {switch (rr.mRequest) {
+/*
+ cat libs/telephony/ril_commands.h \
+ | egrep "^ *{RIL_" \
+ | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/'
+*/
+ case RIL_REQUEST_GET_SIM_STATUS: ret = responseIccCardStatus(p); break;
+ case RIL_REQUEST_ENTER_SIM_PIN: ret = responseVoid(p); break;
+ case RIL_REQUEST_ENTER_SIM_PUK: ret = responseVoid(p); break;
+ case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseVoid(p); break;
+ case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseVoid(p); break;
+ case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseVoid(p); break;
+ case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseVoid(p); break;
+ case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseVoid(p); break;
+ case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break;
+ case RIL_REQUEST_DIAL: ret = responseVoid(p); break;
+ case RIL_REQUEST_GET_IMSI: ret = responseString(p); break;
+ case RIL_REQUEST_HANGUP: ret = responseVoid(p); break;
+ case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: ret = responseVoid(p); break;
+ case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: ret = responseVoid(p); break;
+ case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: ret = responseVoid(p); break;
+ case RIL_REQUEST_CONFERENCE: ret = responseVoid(p); break;
+ case RIL_REQUEST_UDUB: ret = responseVoid(p); break;
+ case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: ret = responseInts(p); break;
+ case RIL_REQUEST_SIGNAL_STRENGTH: ret = responseInts(p); break;
+ case RIL_REQUEST_REGISTRATION_STATE: ret = responseStrings(p); break;
+ case RIL_REQUEST_GPRS_REGISTRATION_STATE: ret = responseStrings(p); break;
+ case RIL_REQUEST_OPERATOR: ret = responseStrings(p); break;
+ case RIL_REQUEST_RADIO_POWER: ret = responseVoid(p); break;
+ case RIL_REQUEST_DTMF: ret = responseVoid(p); break;
+ case RIL_REQUEST_SEND_SMS: ret = responseSMS(p); break;
+ case RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret = responseSMS(p); break;
+ case RIL_REQUEST_SETUP_DATA_CALL: ret = responseStrings(p); break;
+ case RIL_REQUEST_SIM_IO: ret = responseICC_IO(p); break;
+ case RIL_REQUEST_SEND_USSD: ret = responseVoid(p); break;
+ case RIL_REQUEST_CANCEL_USSD: ret = responseVoid(p); break;
+ case RIL_REQUEST_GET_CLIR: ret = responseInts(p); break;
+ case RIL_REQUEST_SET_CLIR: ret = responseVoid(p); break;
+ case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: ret = responseCallForward(p); break;
+ case RIL_REQUEST_SET_CALL_FORWARD: ret = responseVoid(p); break;
+ case RIL_REQUEST_QUERY_CALL_WAITING: ret = responseInts(p); break;
+ case RIL_REQUEST_SET_CALL_WAITING: ret = responseVoid(p); break;
+ case RIL_REQUEST_SMS_ACKNOWLEDGE: ret = responseVoid(p); break;
+ case RIL_REQUEST_GET_IMEI: ret = responseString(p); break;
+ case RIL_REQUEST_GET_IMEISV: ret = responseString(p); break;
+ case RIL_REQUEST_ANSWER: ret = responseVoid(p); break;
+ case RIL_REQUEST_DEACTIVATE_DATA_CALL: ret = responseVoid(p); break;
+ case RIL_REQUEST_QUERY_FACILITY_LOCK: ret = responseInts(p); break;
+ case RIL_REQUEST_SET_FACILITY_LOCK: ret = responseVoid(p); break;
+ case RIL_REQUEST_CHANGE_BARRING_PASSWORD: ret = responseVoid(p); break;
+ case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: ret = responseInts(p); break;
+ case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: ret = responseVoid(p); break;
+ case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: ret = responseVoid(p); break;
+ case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS : ret = responseNetworkInfos(p); break;
+ case RIL_REQUEST_DTMF_START: ret = responseVoid(p); break;
+ case RIL_REQUEST_DTMF_STOP: ret = responseVoid(p); break;
+ case RIL_REQUEST_BASEBAND_VERSION: ret = responseString(p); break;
+ case RIL_REQUEST_SEPARATE_CONNECTION: ret = responseVoid(p); break;
+ case RIL_REQUEST_SET_MUTE: ret = responseVoid(p); break;
+ case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break;
+ case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break;
+ case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: ret = responseInts(p); break;
+ case RIL_REQUEST_DATA_CALL_LIST: ret = responseDataCallList(p); break;
+ case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break;
+ case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break;
+ case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break;
+ case RIL_REQUEST_SCREEN_STATE: ret = responseVoid(p); break;
+ case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break;
+ case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break;
+ case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break;
+ case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break;
+ case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break;
+ case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break;
+ case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break;
+ case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break;
+ case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break;
+ case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break;
+ case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break;
+ case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break;
+ case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseInts(p); break;
+ case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseCellList(p); break;
+ case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_SET_SUBSCRIPTION: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: ret = responseInts(p); break;
+ case RIL_REQUEST_SET_TTY_MODE: ret = responseVoid(p); break;
+ case RIL_REQUEST_QUERY_TTY_MODE: ret = responseInts(p); break;
+ case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: ret = responseInts(p); break;
+ case RIL_REQUEST_CDMA_FLASH: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_BURST_DTMF: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_SEND_SMS: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: ret = responseVoid(p); break;
+ case RIL_REQUEST_GET_BROADCAST_CONFIG: ret = responseBR_SMS_CNF(p); break;
+ case RIL_REQUEST_SET_BROADCAST_CONFIG: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: ret = responseCDMA_BR_CNF(p); break;
+ case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: ret = responseVoid(p); break;
+ case RIL_REQUEST_BROADCAST_ACTIVATION: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_VALIDATE_AKEY: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: ret = responseVoid(p); break;
+ case RIL_REQUEST_CDMA_SUBSCRIPTION: ret = responseStrings(p); break;
+ case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: ret = responseInts(p); break;
+ case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: ret = responseVoid(p); break;
+ case RIL_REQUEST_DEVICE_IDENTITY: ret = responseStrings(p); break;
+ default:
+ throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest);
+ //break;
+ }} catch (Throwable tr) {
+ // Exceptions here usually mean invalid RIL responses
+
+ Log.w(LOG_TAG, rr.serialString() + "< "
+ + requestToString(rr.mRequest)
+ + " exception, possible invalid RIL response", tr);
+
+ if (rr.mResult != null) {
+ AsyncResult.forMessage(rr.mResult, null, tr);
+ rr.mResult.sendToTarget();
+ }
+ rr.release();
+ return;
+ }
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest)
+ + " " + retToString(rr.mRequest, ret));
+
+ if (rr.mResult != null) {
+ AsyncResult.forMessage(rr.mResult, ret, null);
+ rr.mResult.sendToTarget();
+ }
+
+ rr.release();
+ }
+
+ private String
+ retToString(int req, Object ret) {
+ if (ret == null) return "";
+ switch (req) {
+ // Don't log these return values, for privacy's sake.
+ case RIL_REQUEST_GET_IMSI:
+ case RIL_REQUEST_GET_IMEI:
+ case RIL_REQUEST_GET_IMEISV:
+ return "";
+ }
+
+ StringBuilder sb;
+ String s;
+ int length;
+ if (ret instanceof int[]){
+ int[] intArray = (int[]) ret;
+ length = intArray.length;
+ sb = new StringBuilder("{");
+ if (length > 0) {
+ int i = 0;
+ sb.append(intArray[i++]);
+ while ( i < length) {
+ sb.append(", ").append(intArray[i++]);
+ }
+ }
+ sb.append("}");
+ s = sb.toString();
+ } else if (ret instanceof String[]) {
+ String[] strings = (String[]) ret;
+ length = strings.length;
+ sb = new StringBuilder("{");
+ if (length > 0) {
+ int i = 0;
+ sb.append(strings[i++]);
+ while ( i < length) {
+ sb.append(", ").append(strings[i++]);
+ }
+ }
+ sb.append("}");
+ s = sb.toString();
+ }else if (req == RIL_REQUEST_GET_CURRENT_CALLS) {
+ ArrayList calls = (ArrayList) ret;
+ sb = new StringBuilder(" ");
+ for (DriverCall dc : calls) {
+ sb.append("[").append(dc).append("] ");
+ }
+ s = sb.toString();
+ } else if (req == RIL_REQUEST_GET_NEIGHBORING_CELL_IDS) {
+ ArrayList cells;
+ cells = (ArrayList) ret;
+ sb = new StringBuilder(" ");
+ for (NeighboringCellInfo cell : cells) {
+ sb.append(cell).append(" ");
+ }
+ s = sb.toString();
+ } else {
+ s = ret.toString();
+ }
+ return s;
+ }
+
+ private void
+ processUnsolicited (Parcel p) {
+ int response;
+ Object ret;
+
+ response = p.readInt();
+
+ try {switch(response) {
+/*
+ cat libs/telephony/ril_unsol_commands.h \
+ | egrep "^ *{RIL_" \
+ | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: \2(rr, p); break;/'
+*/
+
+ case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: ret = responseVoid(p); break;
+ case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret = responseVoid(p); break;
+ case RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED: ret = responseVoid(p); break;
+ case RIL_UNSOL_RESPONSE_NEW_SMS: ret = responseString(p); break;
+ case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: ret = responseString(p); break;
+ case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: ret = responseInts(p); break;
+ case RIL_UNSOL_ON_USSD: ret = responseStrings(p); break;
+ case RIL_UNSOL_NITZ_TIME_RECEIVED: ret = responseString(p); break;
+ case RIL_UNSOL_SIGNAL_STRENGTH: ret = responseInts(p); break;
+ case RIL_UNSOL_DATA_CALL_LIST_CHANGED: ret = responseDataCallList(p);break;
+ case RIL_UNSOL_SUPP_SVC_NOTIFICATION: ret = responseSuppServiceNotification(p); break;
+ case RIL_UNSOL_STK_SESSION_END: ret = responseVoid(p); break;
+ case RIL_UNSOL_STK_PROACTIVE_COMMAND: ret = responseString(p); break;
+ case RIL_UNSOL_STK_EVENT_NOTIFY: ret = responseString(p); break;
+ case RIL_UNSOL_STK_CALL_SETUP: ret = responseInts(p); break;
+ case RIL_UNSOL_SIM_SMS_STORAGE_FULL: ret = responseVoid(p); break;
+ case RIL_UNSOL_SIM_REFRESH: ret = responseInts(p); break;
+ case RIL_UNSOL_CALL_RING: ret = responseVoid(p); break;
+ case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break;
+ case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED: ret = responseVoid(p); break;
+ case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS: ret = responseCdmaSms(p); break;
+ case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS: ret = responseString(p); break;
+ case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL: ret = responseVoid(p); break;
+ default:
+ throw new RuntimeException("Unrecognized unsol response: " + response);
+ //break; (implied)
+ }} catch (Throwable tr) {
+ Log.e(LOG_TAG, "Exception processing unsol response: " + response +
+ "Exception:" + tr.toString());
+ return;
+ }
+
+ switch(response) {
+ case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
+ /* has bonus radio state int */
+ setRadioStateFromRILInt(p.readInt());
+
+ if (RILJ_LOGD) unsljLogMore(response, mState.toString());
+ break;
+ case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
+ if (RILJ_LOGD) unsljLog(response);
+
+ mCallStateRegistrants
+ .notifyRegistrants(new AsyncResult(null, null, null));
+ break;
+ case RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED:
+ if (RILJ_LOGD) unsljLog(response);
+
+ mNetworkStateRegistrants
+ .notifyRegistrants(new AsyncResult(null, null, null));
+ break;
+ case RIL_UNSOL_RESPONSE_NEW_SMS: {
+ if (RILJ_LOGD) unsljLog(response);
+
+ // FIXME this should move up a layer
+ String a[] = new String[2];
+
+ a[1] = (String)ret;
+
+ SmsMessage sms;
+
+ sms = SmsMessage.newFromCMT(a);
+ if (mSMSRegistrant != null) {
+ mSMSRegistrant
+ .notifyRegistrant(new AsyncResult(null, sms, null));
+ }
+ break;
+ }
+ case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT:
+ if (RILJ_LOGD) unsljLogRet(response, ret);
+
+ if (mSmsStatusRegistrant != null) {
+ mSmsStatusRegistrant.notifyRegistrant(
+ new AsyncResult(null, ret, null));
+ }
+ break;
+ case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM:
+ if (RILJ_LOGD) unsljLogRet(response, ret);
+
+ int[] smsIndex = (int[])ret;
+
+ if(smsIndex.length == 1) {
+ if (mSmsOnSimRegistrant != null) {
+ mSmsOnSimRegistrant.
+ notifyRegistrant(new AsyncResult(null, smsIndex, null));
+ }
+ } else {
+ if (RILJ_LOGD) riljLog(" NEW_SMS_ON_SIM ERROR with wrong length "
+ + smsIndex.length);
+ }
+ break;
+ case RIL_UNSOL_ON_USSD:
+ String[] resp = (String[])ret;
+
+ if (resp.length < 2) {
+ resp = new String[2];
+ resp[0] = ((String[])ret)[0];
+ resp[1] = null;
+ }
+ if (RILJ_LOGD) unsljLogMore(response, resp[0]);
+ if (mUSSDRegistrant != null) {
+ mUSSDRegistrant.notifyRegistrant(
+ new AsyncResult (null, resp, null));
+ }
+ break;
+ case RIL_UNSOL_NITZ_TIME_RECEIVED:
+ if (RILJ_LOGD) unsljLogRet(response, ret);
+
+ // has bonus long containing milliseconds since boot that the NITZ
+ // time was received
+ long nitzReceiveTime = p.readLong();
+
+ Object[] result = new Object[2];
+
+ result[0] = ret;
+ result[1] = Long.valueOf(nitzReceiveTime);
+
+ if (mNITZTimeRegistrant != null) {
+
+ mNITZTimeRegistrant
+ .notifyRegistrant(new AsyncResult (null, result, null));
+ } else {
+ // in case NITZ time registrant isnt registered yet
+ mLastNITZTimeInfo = result;
+ }
+ break;
+
+ case RIL_UNSOL_SIGNAL_STRENGTH:
+ // Note this is set to "verbose" because it happens
+ // frequently
+ if (RILJ_LOGV) unsljLogvRet(response, ret);
+
+ if (mSignalStrengthRegistrant != null) {
+ mSignalStrengthRegistrant.notifyRegistrant(
+ new AsyncResult (null, ret, null));
+ }
+ break;
+ case RIL_UNSOL_DATA_CALL_LIST_CHANGED:
+ if (RILJ_LOGD) unsljLogRet(response, ret);
+
+ mDataConnectionRegistrants.notifyRegistrants(new AsyncResult(null, ret, null));
+ break;
+
+ case RIL_UNSOL_SUPP_SVC_NOTIFICATION:
+ if (RILJ_LOGD) unsljLogRet(response, ret);
+
+ if (mSsnRegistrant != null) {
+ mSsnRegistrant.notifyRegistrant(
+ new AsyncResult (null, ret, null));
+ }
+ break;
+
+ case RIL_UNSOL_STK_SESSION_END:
+ if (RILJ_LOGD) unsljLog(response);
+
+ if (mStkSessionEndRegistrant != null) {
+ mStkSessionEndRegistrant.notifyRegistrant(
+ new AsyncResult (null, ret, null));
+ }
+ break;
+
+ case RIL_UNSOL_STK_PROACTIVE_COMMAND:
+ if (RILJ_LOGD) unsljLogRet(response, ret);
+
+ if (mStkProCmdRegistrant != null) {
+ mStkProCmdRegistrant.notifyRegistrant(
+ new AsyncResult (null, ret, null));
+ }
+ break;
+
+ case RIL_UNSOL_STK_EVENT_NOTIFY:
+ if (RILJ_LOGD) unsljLogRet(response, ret);
+
+ if (mStkEventRegistrant != null) {
+ mStkEventRegistrant.notifyRegistrant(
+ new AsyncResult (null, ret, null));
+ }
+ break;
+
+ case RIL_UNSOL_STK_CALL_SETUP:
+ if (RILJ_LOGD) unsljLogRet(response, ret);
+
+ if (mStkCallSetUpRegistrant != null) {
+ mStkCallSetUpRegistrant.notifyRegistrant(
+ new AsyncResult (null, ret, null));
+ }
+ break;
+
+ case RIL_UNSOL_SIM_SMS_STORAGE_FULL:
+ if (RILJ_LOGD) unsljLog(response);
+
+ if (mIccSmsFullRegistrant != null) {
+ mIccSmsFullRegistrant.notifyRegistrant();
+ }
+ break;
+
+ case RIL_UNSOL_SIM_REFRESH:
+ if (RILJ_LOGD) unsljLogRet(response, ret);
+
+ if (mIccRefreshRegistrant != null) {
+ mIccRefreshRegistrant.notifyRegistrant(
+ new AsyncResult (null, ret, null));
+ }
+ break;
+
+ case RIL_UNSOL_CALL_RING:
+ if (RILJ_LOGD) unsljLog(response);
+
+ if (mRingRegistrant != null) {
+ mRingRegistrant.notifyRegistrant();
+ }
+ break;
+
+ case RIL_UNSOL_RESTRICTED_STATE_CHANGED:
+ if (RILJ_LOGD) unsljLogvRet(response, ret);
+ if (mRestrictedStateRegistrant != null) {
+ mRestrictedStateRegistrant.notifyRegistrant(
+ new AsyncResult (null, ret, null));
+ }
+
+ case RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED:
+ if (mIccStatusChangedRegistrants != null) {
+ mIccStatusChangedRegistrants.notifyRegistrants();
+ }
+ break;
+
+ case RIL_UNSOL_RESPONSE_CDMA_NEW_SMS:
+ SmsMessage sms = (SmsMessage) ret;
+
+ if (mSMSRegistrant != null) {
+ mSMSRegistrant
+ .notifyRegistrant(new AsyncResult(null, sms, null));
+ }
+ break;
+
+ case RIL_UNSOL_RESPONSE_NEW_BROADCAST_SMS:
+ // TODO T: waiting for SMS BC feature
+ break;
+
+ case RIL_UNSOL_CDMA_RUIM_SMS_STORAGE_FULL:
+ if (Config.LOGD) {
+ if (RILJ_LOGD) riljLog("[UNSL]< RUIM_SMS_STORAGE_FULL");
+ }
+
+ if (mIccSmsFullRegistrant != null) {
+ mIccSmsFullRegistrant.notifyRegistrant();
+ }
+ break;
+ }
+ }
+
+ private Object
+ responseInts(Parcel p) {
+ int numInts;
+ int response[];
+
+ numInts = p.readInt();
+
+ response = new int[numInts];
+
+ for (int i = 0 ; i < numInts ; i++) {
+ response[i] = p.readInt();
+ }
+
+ return response;
+ }
+
+
+ private Object
+ responseVoid(Parcel p) {
+ return null;
+ }
+
+ private Object
+ responseCallForward(Parcel p) {
+ int numInfos;
+ CallForwardInfo infos[];
+
+ numInfos = p.readInt();
+
+ infos = new CallForwardInfo[numInfos];
+
+ for (int i = 0 ; i < numInfos ; i++) {
+ infos[i] = new CallForwardInfo();
+
+ infos[i].status = p.readInt();
+ infos[i].reason = p.readInt();
+ infos[i].serviceClass = p.readInt();
+ infos[i].toa = p.readInt();
+ infos[i].number = p.readString();
+ infos[i].timeSeconds = p.readInt();
+ }
+
+ return infos;
+ }
+
+ private Object
+ responseSuppServiceNotification(Parcel p) {
+ SuppServiceNotification notification = new SuppServiceNotification();
+
+ notification.notificationType = p.readInt();
+ notification.code = p.readInt();
+ notification.index = p.readInt();
+ notification.type = p.readInt();
+ notification.number = p.readString();
+
+ return notification;
+ }
+
+ private Object
+ responseCdmaSms(Parcel p) {
+ SmsMessage sms;
+ sms = SmsMessage.newFromParcel(p);
+
+ return sms;
+ }
+
+ private Object
+ responseString(Parcel p) {
+ String response;
+
+ response = p.readString();
+
+ return response;
+ }
+
+ private Object
+ responseStrings(Parcel p) {
+ int num;
+ String response[];
+
+ response = p.readStringArray();
+
+ if (false) {
+ num = p.readInt();
+
+ response = new String[num];
+ for (int i = 0; i < num; i++) {
+ response[i] = p.readString();
+ }
+ }
+
+ return response;
+ }
+
+ private Object
+ responseRaw(Parcel p) {
+ int num;
+ byte response[];
+
+ response = p.createByteArray();
+
+ return response;
+ }
+
+ private Object
+ responseSMS(Parcel p) {
+ int messageRef;
+ String ackPDU;
+
+ messageRef = p.readInt();
+ ackPDU = p.readString();
+
+ SmsResponse response = new SmsResponse(messageRef, ackPDU);
+
+ return response;
+ }
+
+
+ private Object
+ responseICC_IO(Parcel p) {
+ int sw1, sw2;
+ byte data[] = null;
+ Message ret;
+
+ sw1 = p.readInt();
+ sw2 = p.readInt();
+
+ String s = p.readString();
+
+ return new IccIoResult(sw1, sw2, s);
+ }
+
+ private Object
+ responseIccCardStatus(Parcel p) {
+ RadioState currentRadioState;
+ IccCardApplication ca;
+
+ currentRadioState = getRadioState();
+
+ IccCardStatus status = new IccCardStatus();
+ status.card_state = status.CardStateFromRILInt(p.readInt());
+ status.universal_pin_state = status.PinStateFromRILInt(p.readInt());
+ status.gsm_umts_subscription_app_index = p.readInt();
+ status.cdma_subscription_app_index = p.readInt();
+ status.num_applications = p.readInt();
+
+ // limit to maximum allowed applications
+ if (status.num_applications > IccCardStatus.CARD_MAX_APPS) {
+ status.num_applications = IccCardStatus.CARD_MAX_APPS;
+ }
+
+ for (int i = 0 ; i < status.num_applications ; i++) {
+ ca = new IccCardApplication();
+ ca.app_type = ca.AppTypeFromRILInt(p.readInt());
+ ca.app_state = ca.AppStateFromRILInt(p.readInt());
+ ca.perso_substate = ca.PersoSubstateFromRILInt(p.readInt());
+ ca.aid = p.readString();
+ ca.app_label = p.readString();
+ ca.pin1_replaced = p.readInt();
+ ca.pin1 = p.readInt();
+ ca.pin2 = p.readInt();
+ status.application.add(ca);
+ }
+
+ // this is common for all radio technologies
+ if (!status.card_state.isCardPresent()) {
+ return IccStatus.ICC_ABSENT;
+ }
+
+ // check radio technology
+ if( currentRadioState == RadioState.RADIO_OFF ||
+ currentRadioState == RadioState.RADIO_UNAVAILABLE ||
+ currentRadioState == RadioState.SIM_NOT_READY ||
+ currentRadioState == RadioState.RUIM_NOT_READY ||
+ currentRadioState == RadioState.NV_NOT_READY ||
+ currentRadioState == RadioState.NV_READY ) {
+ return IccStatus.ICC_NOT_READY;
+ }
+
+ if( currentRadioState == RadioState.SIM_LOCKED_OR_ABSENT ||
+ currentRadioState == RadioState.SIM_READY ||
+ currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
+ currentRadioState == RadioState.RUIM_READY) {
+
+ int index;
+
+ // check for CDMA radio technology
+ if (currentRadioState == RadioState.RUIM_LOCKED_OR_ABSENT ||
+ currentRadioState == RadioState.RUIM_READY) {
+ index = status.cdma_subscription_app_index;
+ }
+ else {
+ index = status.gsm_umts_subscription_app_index;
+ }
+
+ // check if PIN required
+ if (status.application.get(index).app_state.isPinRequired()) {
+ return IccStatus.ICC_PIN;
+ }
+ if (status.application.get(index).app_state.isPukRequired()) {
+ return IccStatus.ICC_PUK;
+ }
+ if (status.application.get(index).app_state.isSubscriptionPersoEnabled()) {
+ return IccStatus.ICC_NETWORK_PERSONALIZATION;
+ }
+ if (status.application.get(index).app_state.isAppReady()) {
+ return IccStatus.ICC_READY;
+ }
+ if (status.application.get(index).app_state.isAppNotReady()) {
+ return IccStatus.ICC_NOT_READY;
+ }
+ return IccStatus.ICC_NOT_READY;
+ }
+
+ // Unrecognized ICC status. Treat it like a missing ICC.
+ Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status);
+ return IccStatus.ICC_ABSENT;
+ }
+
+ private Object
+ responseCallList(Parcel p) {
+ int num;
+ int voiceSettings;
+ ArrayList response;
+ DriverCall dc;
+
+ num = p.readInt();
+ response = new ArrayList(num);
+
+ for (int i = 0 ; i < num ; i++) {
+ dc = new DriverCall();
+
+ dc.state = DriverCall.stateFromCLCC(p.readInt());
+ dc.index = p.readInt();
+ dc.TOA = p.readInt();
+ dc.isMpty = (0 != p.readInt());
+ dc.isMT = (0 != p.readInt());
+ dc.als = p.readInt();
+ voiceSettings = p.readInt();
+ dc.isVoice = (0 == voiceSettings) ? false : true;
+ dc.number = p.readString();
+ dc.numberPresentation = DriverCall.presentationFromCLIP(p.readInt());
+
+ // Make sure there's a leading + on addresses with a TOA
+ // of 145
+
+ dc.number = PhoneNumberUtils.stringFromStringAndTOA(
+ dc.number, dc.TOA);
+
+ response.add(dc);
+
+ if ( RILConstants.CDMA_VOICE_PRIVACY == voiceSettings ) {
+ mVoicePrivacyOnRegistrants.notifyRegistrants();
+ Log.d(LOG_TAG, "InCall VoicePrivacy is enabled: " +
+ Integer.toString(voiceSettings));
+ } else {
+ mVoicePrivacyOffRegistrants.notifyRegistrants();
+ Log.d(LOG_TAG, "InCall VoicePrivacy is disabled: " +
+ Integer.toString(voiceSettings));
+ }
+ }
+
+ Collections.sort(response);
+
+ return response;
+ }
+
+ private Object
+ responseDataCallList(Parcel p) {
+ int num;
+ ArrayList response;
+
+ num = p.readInt();
+ response = new ArrayList(num);
+
+ for (int i = 0; i < num; i++) {
+ PDPContextState pdp = new PDPContextState();
+
+ pdp.cid = p.readInt();
+ pdp.active = p.readInt() == 0 ? false : true;
+ pdp.type = p.readString();
+ pdp.apn = p.readString();
+ pdp.address = p.readString();
+
+ response.add(pdp);
+ }
+
+ return response;
+ }
+
+ private Object
+ responseNetworkInfos(Parcel p) {
+ String strings[] = (String [])responseStrings(p);
+ ArrayList ret;
+
+ if (strings.length % 4 != 0) {
+ throw new RuntimeException(
+ "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got "
+ + strings.length + " strings, expected multible of 4");
+ }
+
+ ret = new ArrayList(strings.length / 4);
+
+ for (int i = 0 ; i < strings.length ; i += 4) {
+ ret.add (
+ new NetworkInfo(
+ strings[i+0],
+ strings[i+1],
+ strings[i+2],
+ strings[i+3]));
+ }
+
+ return ret;
+ }
+
+ private Object
+ responseCellList(Parcel p) {
+ int num;
+ ArrayList response;
+ NeighboringCellInfo cell;
+
+ num = p.readInt();
+ response = new ArrayList(num);
+
+ for (int i = 0 ; i < num ; i++) {
+ try {
+ int rssi = p.readInt();
+ int cid = Integer.valueOf(p.readString(), 16);
+ cell = new NeighboringCellInfo(rssi, cid);
+ response.add(cell);
+ } catch ( Exception e) {
+ }
+ }
+
+ return response;
+ }
+
+ private Object
+ responseBR_SMS_CNF(Parcel p) {
+ // TODO
+ return null;
+ }
+
+ private Object
+ responseCDMA_BR_CNF(Parcel p) {
+ int numInts;
+ int response[];
+
+ numInts = p.readInt();
+
+ response = new int[numInts];
+
+ response[0] = numInts;
+ for (int i = 1 ; i < numInts; i++) {
+ response[i] = p.readInt();
+ }
+
+ return response;
+ }
+
+ static String
+ requestToString(int request) {
+/*
+ cat libs/telephony/ril_commands.h \
+ | egrep "^ *{RIL_" \
+ | sed -re 's/\{RIL_([^,]+),[^,]+,([^}]+).+/case RIL_\1: return "\1";/'
+*/
+ switch(request) {
+ case RIL_REQUEST_GET_SIM_STATUS: return "GET_SIM_STATUS";
+ case RIL_REQUEST_ENTER_SIM_PIN: return "ENTER_SIM_PIN";
+ case RIL_REQUEST_ENTER_SIM_PUK: return "ENTER_SIM_PUK";
+ case RIL_REQUEST_ENTER_SIM_PIN2: return "ENTER_SIM_PIN2";
+ case RIL_REQUEST_ENTER_SIM_PUK2: return "ENTER_SIM_PUK2";
+ case RIL_REQUEST_CHANGE_SIM_PIN: return "CHANGE_SIM_PIN";
+ case RIL_REQUEST_CHANGE_SIM_PIN2: return "CHANGE_SIM_PIN2";
+ case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: return "ENTER_NETWORK_DEPERSONALIZATION";
+ case RIL_REQUEST_GET_CURRENT_CALLS: return "GET_CURRENT_CALLS";
+ case RIL_REQUEST_DIAL: return "DIAL";
+ case RIL_REQUEST_GET_IMSI: return "GET_IMSI";
+ case RIL_REQUEST_HANGUP: return "HANGUP";
+ case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: return "HANGUP_WAITING_OR_BACKGROUND";
+ case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: return "HANGUP_FOREGROUND_RESUME_BACKGROUND";
+ case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: return "REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE";
+ case RIL_REQUEST_CONFERENCE: return "CONFERENCE";
+ case RIL_REQUEST_UDUB: return "UDUB";
+ case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: return "LAST_CALL_FAIL_CAUSE";
+ case RIL_REQUEST_SIGNAL_STRENGTH: return "SIGNAL_STRENGTH";
+ case RIL_REQUEST_REGISTRATION_STATE: return "REGISTRATION_STATE";
+ case RIL_REQUEST_GPRS_REGISTRATION_STATE: return "GPRS_REGISTRATION_STATE";
+ case RIL_REQUEST_OPERATOR: return "OPERATOR";
+ case RIL_REQUEST_RADIO_POWER: return "RADIO_POWER";
+ case RIL_REQUEST_DTMF: return "DTMF";
+ case RIL_REQUEST_SEND_SMS: return "SEND_SMS";
+ case RIL_REQUEST_SEND_SMS_EXPECT_MORE: return "SEND_SMS_EXPECT_MORE";
+ case RIL_REQUEST_SETUP_DATA_CALL: return "SETUP_DATA_CALL";
+ case RIL_REQUEST_SIM_IO: return "SIM_IO";
+ case RIL_REQUEST_SEND_USSD: return "SEND_USSD";
+ case RIL_REQUEST_CANCEL_USSD: return "CANCEL_USSD";
+ case RIL_REQUEST_GET_CLIR: return "GET_CLIR";
+ case RIL_REQUEST_SET_CLIR: return "SET_CLIR";
+ case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: return "QUERY_CALL_FORWARD_STATUS";
+ case RIL_REQUEST_SET_CALL_FORWARD: return "SET_CALL_FORWARD";
+ case RIL_REQUEST_QUERY_CALL_WAITING: return "QUERY_CALL_WAITING";
+ case RIL_REQUEST_SET_CALL_WAITING: return "SET_CALL_WAITING";
+ case RIL_REQUEST_SMS_ACKNOWLEDGE: return "SMS_ACKNOWLEDGE";
+ case RIL_REQUEST_GET_IMEI: return "GET_IMEI";
+ case RIL_REQUEST_GET_IMEISV: return "GET_IMEISV";
+ case RIL_REQUEST_ANSWER: return "ANSWER";
+ case RIL_REQUEST_DEACTIVATE_DATA_CALL: return "DEACTIVATE_DATA_CALL";
+ case RIL_REQUEST_QUERY_FACILITY_LOCK: return "QUERY_FACILITY_LOCK";
+ case RIL_REQUEST_SET_FACILITY_LOCK: return "SET_FACILITY_LOCK";
+ case RIL_REQUEST_CHANGE_BARRING_PASSWORD: return "CHANGE_BARRING_PASSWORD";
+ case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: return "QUERY_NETWORK_SELECTION_MODE";
+ case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: return "SET_NETWORK_SELECTION_AUTOMATIC";
+ case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: return "SET_NETWORK_SELECTION_MANUAL";
+ case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS : return "QUERY_AVAILABLE_NETWORKS ";
+ case RIL_REQUEST_DTMF_START: return "DTMF_START";
+ case RIL_REQUEST_DTMF_STOP: return "DTMF_STOP";
+ case RIL_REQUEST_BASEBAND_VERSION: return "BASEBAND_VERSION";
+ case RIL_REQUEST_SEPARATE_CONNECTION: return "SEPARATE_CONNECTION";
+ case RIL_REQUEST_SET_MUTE: return "SET_MUTE";
+ case RIL_REQUEST_GET_MUTE: return "GET_MUTE";
+ case RIL_REQUEST_QUERY_CLIP: return "QUERY_CLIP";
+ case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE: return "LAST_DATA_CALL_FAIL_CAUSE";
+ case RIL_REQUEST_DATA_CALL_LIST: return "DATA_CALL_LIST";
+ case RIL_REQUEST_RESET_RADIO: return "RESET_RADIO";
+ case RIL_REQUEST_OEM_HOOK_RAW: return "OEM_HOOK_RAW";
+ case RIL_REQUEST_OEM_HOOK_STRINGS: return "OEM_HOOK_STRINGS";
+ case RIL_REQUEST_SCREEN_STATE: return "SCREEN_STATE";
+ case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: return "SET_SUPP_SVC_NOTIFICATION";
+ case RIL_REQUEST_WRITE_SMS_TO_SIM: return "WRITE_SMS_TO_SIM";
+ case RIL_REQUEST_DELETE_SMS_ON_SIM: return "DELETE_SMS_ON_SIM";
+ case RIL_REQUEST_SET_BAND_MODE: return "SET_BAND_MODE";
+ case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: return "QUERY_AVAILABLE_BAND_MODE";
+ case RIL_REQUEST_STK_GET_PROFILE: return "REQUEST_STK_GET_PROFILE";
+ case RIL_REQUEST_STK_SET_PROFILE: return "REQUEST_STK_SET_PROFILE";
+ case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: return "REQUEST_STK_SEND_ENVELOPE_COMMAND";
+ case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: return "REQUEST_STK_SEND_TERMINAL_RESPONSE";
+ case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: return "REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM";
+ case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: return "REQUEST_EXPLICIT_CALL_TRANSFER";
+ case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: return "REQUEST_SET_PREFERRED_NETWORK_TYPE";
+ case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: return "REQUEST_GET_PREFERRED_NETWORK_TYPE";
+ case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: return "REQUEST_GET_NEIGHBORING_CELL_IDS";
+ case RIL_REQUEST_SET_LOCATION_UPDATES: return "REQUEST_SET_LOCATION_UPDATES";
+ case RIL_REQUEST_CDMA_SET_SUBSCRIPTION: return "RIL_REQUEST_CDMA_SET_SUBSCRIPTION";
+ case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE: return "RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE";
+ case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE: return "RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE";
+ case RIL_REQUEST_SET_TTY_MODE: return "RIL_REQUEST_SET_TTY_MODE";
+ case RIL_REQUEST_QUERY_TTY_MODE: return "RIL_REQUEST_QUERY_TTY_MODE";
+ case RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE: return "RIL_REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE";
+ case RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE: return "RIL_REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE";
+ case RIL_REQUEST_CDMA_FLASH: return "RIL_REQUEST_CDMA_FLASH";
+ case RIL_REQUEST_CDMA_BURST_DTMF: return "RIL_REQUEST_CDMA_BURST_DTMF";
+ case RIL_REQUEST_CDMA_SEND_SMS: return "RIL_REQUEST_CDMA_SEND_SMS";
+ case RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE: return "RIL_REQUEST_CDMA_SMS_ACKNOWLEDGE";
+ case RIL_REQUEST_GET_BROADCAST_CONFIG: return "RIL_REQUEST_GET_BROADCAST_CONFIG";
+ case RIL_REQUEST_SET_BROADCAST_CONFIG: return "RIL_REQUEST_SET_BROADCAST_CONFIG";
+ case RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG: return "RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG";
+ case RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG: return "RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG";
+ case RIL_REQUEST_BROADCAST_ACTIVATION: return "RIL_REQUEST_BROADCAST_ACTIVATION";
+ case RIL_REQUEST_CDMA_VALIDATE_AKEY: return "RIL_REQUEST_CDMA_VALIDATE_AKEY";
+ case RIL_REQUEST_CDMA_BROADCAST_ACTIVATION: return "RIL_REQUEST_CDMA_BROADCAST_ACTIVATION";
+ case RIL_REQUEST_CDMA_SUBSCRIPTION: return "RIL_REQUEST_CDMA_SUBSCRIPTION";
+ case RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM: return "RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM";
+ case RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM: return "RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM";
+ case RIL_REQUEST_DEVICE_IDENTITY: return "RIL_REQUEST_DEVICE_IDENTITY";
+ default: return "";
+ }
+ }
+
+ static String
+ responseToString(int request)
+ {
+/*
+ cat libs/telephony/ril_unsol_commands.h \
+ | egrep "^ *{RIL_" \
+ | sed -re 's/\{RIL_([^,]+),[^,]+,([^}]+).+/case RIL_\1: return "\1";/'
+*/
+ switch(request) {
+ case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: return "UNSOL_RESPONSE_RADIO_STATE_CHANGED";
+ case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: return "UNSOL_RESPONSE_CALL_STATE_CHANGED";
+ case RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED: return "UNSOL_RESPONSE_NETWORK_STATE_CHANGED";
+ case RIL_UNSOL_RESPONSE_NEW_SMS: return "UNSOL_RESPONSE_NEW_SMS";
+ case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: return "UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT";
+ case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: return "UNSOL_RESPONSE_NEW_SMS_ON_SIM";
+ case RIL_UNSOL_ON_USSD: return "UNSOL_ON_USSD";
+ case RIL_UNSOL_ON_USSD_REQUEST: return "UNSOL_ON_USSD_REQUEST";
+ case RIL_UNSOL_NITZ_TIME_RECEIVED: return "UNSOL_NITZ_TIME_RECEIVED";
+ case RIL_UNSOL_SIGNAL_STRENGTH: return "UNSOL_SIGNAL_STRENGTH";
+ case RIL_UNSOL_DATA_CALL_LIST_CHANGED: return "UNSOL_DATA_CALL_LIST_CHANGED";
+ case RIL_UNSOL_SUPP_SVC_NOTIFICATION: return "UNSOL_SUPP_SVC_NOTIFICATION";
+ case RIL_UNSOL_STK_SESSION_END: return "UNSOL_STK_SESSION_END";
+ case RIL_UNSOL_STK_PROACTIVE_COMMAND: return "UNSOL_STK_PROACTIVE_COMMAND";
+ case RIL_UNSOL_STK_EVENT_NOTIFY: return "UNSOL_STK_EVENT_NOTIFY";
+ case RIL_UNSOL_STK_CALL_SETUP: return "UNSOL_STK_CALL_SETUP";
+ case RIL_UNSOL_SIM_SMS_STORAGE_FULL: return "UNSOL_SIM_SMS_STORAGE_FULL";
+ case RIL_UNSOL_SIM_REFRESH: return "UNSOL_SIM_REFRESH";
+ case RIL_UNSOL_CALL_RING: return "UNSOL_CALL_RING";
+ case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "RIL_UNSOL_RESTRICTED_STATE_CHANGED";
+ default: return "";
+ }
+ }
+
+ private void riljLog(String msg) {
+ Log.d(LOG_TAG, msg);
+ }
+
+ private void riljLogv(String msg) {
+ Log.v(LOG_TAG, msg);
+ }
+
+ private void unsljLog(int response) {
+ riljLog("[UNSL]< " + responseToString(response));
+ }
+
+ private void unsljLogMore(int response, String more) {
+ riljLog("[UNSL]< " + responseToString(response) + " " + more);
+ }
+
+ private void unsljLogRet(int response, Object ret) {
+ riljLog("[UNSL]< " + responseToString(response) + " " + retToString(response, ret));
+ }
+
+ private void unsljLogvRet(int response, Object ret) {
+ riljLogv("[UNSL]< " + responseToString(response) + " " + retToString(response, ret));
+ }
+
+
+ // ***** Methods for CDMA support
+ public void
+ getDeviceIdentity(Message response) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_DEVICE_IDENTITY, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void
+ getCDMASubscription(Message response) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SUBSCRIPTION, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ public void setPhoneType(int phoneType) { //Set by CDMAPhone and GSMPhone constructor
+ mPhoneType = phoneType;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void queryCdmaRoamingPreference(Message response) {
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, response);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setCdmaRoamingPreference(int cdmaRoamingType, Message response) {
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE, response);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(cdmaRoamingType);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " : " + cdmaRoamingType);
+
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setCdmaSubscription(int cdmaSubscription , Message response) {
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_CDMA_SET_SUBSCRIPTION, response);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(cdmaSubscription);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " : " + cdmaSubscription);
+
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void queryTTYModeEnabled(Message response) {
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_QUERY_TTY_MODE, response);
+
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setTTYModeEnabled(boolean enable, Message response) {
+ RILRequest rr = RILRequest.obtain(
+ RILConstants.RIL_REQUEST_SET_TTY_MODE, response);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(enable ? 1 : 0);
+
+ send(rr);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void
+ sendCDMAFeatureCode(String FeatureCode, Message response) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_FLASH, response);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeString(FeatureCode);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " : " + FeatureCode);
+
+ send(rr);
+ }
+
+ public void getCdmaBroadcastConfig(Message response) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_GET_BROADCAST_CONFIG, response);
+
+ send(rr);
+ }
+
+ public void setCdmaBroadcastConfig(int[] configValuesArray, Message response) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG, response);
+
+ for(int i = 0; i < configValuesArray.length; i++) {
+ rr.mp.writeInt(configValuesArray[i]);
+ }
+
+ send(rr);
+ }
+
+ public void activateCdmaBroadcastSms(int activate, Message response) {
+ RILRequest rr = RILRequest.obtain(RIL_REQUEST_CDMA_BROADCAST_ACTIVATION, response);
+
+ rr.mp.writeInt(1);
+ rr.mp.writeInt(activate);
+
+ send(rr);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
new file mode 100644
index 0000000..ba3b754
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -0,0 +1,236 @@
+/*
+ * 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;
+
+
+/**
+ * {@hide}
+ */
+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 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 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 */
+
+ /* 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' | \
+ sed -re 's/^#define +([^ ]+)* +([^ ]+)/ int \1 = \2;/' \
+ >>java/android/com.android.internal.telephony/gsm/RILConstants.java
+*/
+
+
+ int RIL_SIM_ABSENT = 0;
+ int RIL_SIM_NOT_READY = 1;
+ int RIL_SIM_READY = 2;
+ int RIL_SIM_PIN = 3;
+ int RIL_SIM_PUK = 4;
+ int RIL_SIM_NETWORK_PERSONALIZATION = 5;
+
+ /**
+ * No restriction at all including voice/SMS/USSD/SS/AV64
+ * and packet data.
+ */
+ int RIL_RESTRICTED_STATE_NONE = 0x00;
+ /**
+ * Block emergency call due to restriction.
+ * But allow all normal voice/SMS/USSD/SS/AV64.
+ */
+ int RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01;
+ /**
+ * Block all normal voice/SMS/USSD/SS/AV64 due to restriction.
+ * Only Emergency call allowed.
+ */
+ int RIL_RESTRICTED_STATE_CS_NORMAL = 0x02;
+ /**
+ * Block all voice/SMS/USSD/SS/AV64
+ * including emergency call due to restriction.
+ */
+ int RIL_RESTRICTED_STATE_CS_ALL = 0x04;
+ /**
+ * 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;
+ int RIL_REQUEST_ENTER_SIM_PIN2 = 4;
+ int RIL_REQUEST_ENTER_SIM_PUK2 = 5;
+ int RIL_REQUEST_CHANGE_SIM_PIN = 6;
+ int RIL_REQUEST_CHANGE_SIM_PIN2 = 7;
+ int RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION = 8;
+ int RIL_REQUEST_GET_CURRENT_CALLS = 9;
+ int RIL_REQUEST_DIAL = 10;
+ int RIL_REQUEST_GET_IMSI = 11;
+ int RIL_REQUEST_HANGUP = 12;
+ int RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND = 13;
+ int RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND = 14;
+ int RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE = 15;
+ int RIL_REQUEST_CONFERENCE = 16;
+ int RIL_REQUEST_UDUB = 17;
+ int RIL_REQUEST_LAST_CALL_FAIL_CAUSE = 18;
+ int RIL_REQUEST_SIGNAL_STRENGTH = 19;
+ int RIL_REQUEST_REGISTRATION_STATE = 20;
+ int RIL_REQUEST_GPRS_REGISTRATION_STATE = 21;
+ int RIL_REQUEST_OPERATOR = 22;
+ int RIL_REQUEST_RADIO_POWER = 23;
+ int RIL_REQUEST_DTMF = 24;
+ int RIL_REQUEST_SEND_SMS = 25;
+ int RIL_REQUEST_SEND_SMS_EXPECT_MORE = 26;
+ 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;
+ int RIL_REQUEST_GET_CLIR = 31;
+ int RIL_REQUEST_SET_CLIR = 32;
+ int RIL_REQUEST_QUERY_CALL_FORWARD_STATUS = 33;
+ int RIL_REQUEST_SET_CALL_FORWARD = 34;
+ int RIL_REQUEST_QUERY_CALL_WAITING = 35;
+ int RIL_REQUEST_SET_CALL_WAITING = 36;
+ int RIL_REQUEST_SMS_ACKNOWLEDGE = 37;
+ int RIL_REQUEST_GET_IMEI = 38;
+ int RIL_REQUEST_GET_IMEISV = 39;
+ int RIL_REQUEST_ANSWER = 40;
+ 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;
+ int RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE = 45;
+ int RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC = 46;
+ int RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL = 47;
+ int RIL_REQUEST_QUERY_AVAILABLE_NETWORKS = 48;
+ int RIL_REQUEST_DTMF_START = 49;
+ int RIL_REQUEST_DTMF_STOP = 50;
+ int RIL_REQUEST_BASEBAND_VERSION = 51;
+ int RIL_REQUEST_SEPARATE_CONNECTION = 52;
+ int RIL_REQUEST_SET_MUTE = 53;
+ int RIL_REQUEST_GET_MUTE = 54;
+ int RIL_REQUEST_QUERY_CLIP = 55;
+ 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;
+ int RIL_REQUEST_SCREEN_STATE = 61;
+ int RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION = 62;
+ int RIL_REQUEST_WRITE_SMS_TO_SIM = 63;
+ int RIL_REQUEST_DELETE_SMS_ON_SIM = 64;
+ int RIL_REQUEST_SET_BAND_MODE = 65;
+ int RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE = 66;
+ int RIL_REQUEST_STK_GET_PROFILE = 67;
+ int RIL_REQUEST_STK_SET_PROFILE = 68;
+ int RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND = 69;
+ int RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE = 70;
+ int RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM = 71;
+ int RIL_REQUEST_EXPLICIT_CALL_TRANSFER = 72;
+ int RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE = 73;
+ 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;
+ int RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED = 1002;
+ int RIL_UNSOL_RESPONSE_NEW_SMS = 1003;
+ int RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT = 1004;
+ int RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM = 1005;
+ int RIL_UNSOL_ON_USSD = 1006;
+ int RIL_UNSOL_ON_USSD_REQUEST = 1007;
+ int RIL_UNSOL_NITZ_TIME_RECEIVED = 1008;
+ int RIL_UNSOL_SIGNAL_STRENGTH = 1009;
+ 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;
+ int RIL_UNSOL_STK_EVENT_NOTIFY = 1014;
+ int RIL_UNSOL_STK_CALL_SETUP = 1015;
+ 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;
+}
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
new file mode 100644
index 0000000..f2bd361
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -0,0 +1,744 @@
+/*
+ * 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.Activity;
+import android.app.PendingIntent;
+import android.app.AlertDialog;
+import android.app.PendingIntent.CanceledException;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.content.DialogInterface;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.net.Uri;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.Telephony;
+import android.provider.Telephony.Sms.Intents;
+import android.provider.Settings;
+import android.telephony.SmsMessage;
+import android.telephony.ServiceState;
+import android.util.Config;
+import android.util.Log;
+import android.view.WindowManager;
+
+import com.android.internal.telephony.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;
+import java.util.Random;
+
+import com.android.internal.R;
+
+import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;
+import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
+import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
+import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
+
+
+public abstract class SMSDispatcher extends Handler {
+ private static final String TAG = "SMS";
+
+ /** Default checking period for SMS sent without user permit */
+ private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000;
+
+ /** 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;
+
+ protected static final String[] RAW_PROJECTION = new String[] {
+ "pdu",
+ "sequence",
+ };
+
+ static final int MAIL_SEND_SMS = 1;
+
+ static final protected int EVENT_NEW_SMS = 1;
+
+ static final protected int EVENT_SEND_SMS_COMPLETE = 2;
+
+ /** Retry sending a previously failed SMS message */
+ static final protected int EVENT_SEND_RETRY = 3;
+
+ /** Status report received */
+ static final protected int EVENT_NEW_SMS_STATUS_REPORT = 5;
+
+ /** SIM/RUIM storage is full */
+ static final protected int EVENT_ICC_FULL = 6;
+
+ /** SMS confirm required */
+ static final protected int EVENT_POST_ALERT = 7;
+
+ /** Send the user confirmed SMS */
+ static final protected int EVENT_SEND_CONFIRMED_SMS = 8;
+
+ /** Alert is timeout */
+ static final protected int EVENT_ALERT_TIMEOUT = 9;
+
+ protected Phone mPhone;
+ protected Context mContext;
+ protected ContentResolver mResolver;
+ protected CommandsInterface mCm;
+
+ protected final WapPushOverSms mWapPush;
+
+ 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;
+ /** Delay before next send attempt on a failed SMS, in milliseconds. */
+ private static final int SEND_RETRY_DELAY = 2000;
+ /** single part SMS */
+ private static final int SINGLE_PART_SMS = 1;
+
+ /**
+ * Message reference for a CONCATENATED_8_BIT_REFERENCE or
+ * CONCATENATED_16_BIT_REFERENCE message set. Should be
+ * incremented for each set of concatenated messages.
+ */
+ protected static int sConcatenatedRef;
+
+ private SmsCounter mCounter;
+
+ private SmsTracker mSTracker;
+
+ private static SmsMessage mSmsMessage;
+ private static SmsMessageBase mSmsMessageBase;
+ private SmsMessageBase.SubmitPduBase mSubmitPduBase;
+
+ /**
+ * Implement the per-application based SMS control, which only allows
+ * a limit on the number of SMS/MMS messages an app can send in checking
+ * period.
+ */
+ private class SmsCounter {
+ private int mCheckPeriod;
+ private int mMaxAllowed;
+ private HashMap> mSmsStamp;
+
+ /**
+ * Create SmsCounter
+ * @param mMax is the number of SMS allowed without user permit
+ * @param mPeriod is the checking period
+ */
+ SmsCounter(int mMax, int mPeriod) {
+ mMaxAllowed = mMax;
+ mCheckPeriod = mPeriod;
+ mSmsStamp = new HashMap> ();
+ }
+
+ /**
+ * Check to see if an application allow to send new SMS messages
+ *
+ * @param appName is the application sending sms
+ * @param smsWaiting is the number of new sms wants to be sent
+ * @return true if application is allowed to send the requested number
+ * of new sms messages
+ */
+ boolean check(String appName, int smsWaiting) {
+ if (!mSmsStamp.containsKey(appName)) {
+ mSmsStamp.put(appName, new ArrayList());
+ }
+
+ return isUnderLimit(mSmsStamp.get(appName), smsWaiting);
+ }
+
+ private boolean isUnderLimit(ArrayList sent, int smsWaiting) {
+ Long ct = System.currentTimeMillis();
+
+ Log.d(TAG, "SMS send size=" + sent.size() + "time=" + ct);
+
+ while (sent.size() > 0 && (ct - sent.get(0)) > mCheckPeriod ) {
+ sent.remove(0);
+ }
+
+
+ if ( (sent.size() + smsWaiting) <= mMaxAllowed) {
+ for (int i = 0; i < smsWaiting; i++ ) {
+ sent.add(ct);
+ }
+ return true;
+ }
+ return false;
+ }
+ }
+
+ protected SMSDispatcher(PhoneBase phone) {
+ mPhone = phone;
+ mWapPush = new WapPushOverSms(phone);
+ mContext = phone.getContext();
+ mResolver = mContext.getContentResolver();
+ mCm = phone.mCM;
+ mSTracker = null;
+
+ int check_period = Settings.Gservices.getInt(mResolver,
+ Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS,
+ DEFAULT_SMS_CHECK_PERIOD);
+ int max_count = Settings.Gservices.getInt(mResolver,
+ Settings.Gservices.SMS_OUTGOING_CEHCK_MAX_COUNT,
+ DEFAULT_SMS_MAX_COUNT);
+ mCounter = new SmsCounter(max_count, check_period);
+
+ mCm.setOnNewSMS(this, EVENT_NEW_SMS, null);
+ mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, 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. */
+ protected final ArrayList deliveryPendingList = new ArrayList();
+
+ /**
+ * Handles events coming from the phone stack. Overridden from handler.
+ *
+ * @param msg the message to handle
+ */
+ @Override
+ public void handleMessage(Message msg) {
+ AsyncResult ar;
+
+ switch (msg.what) {
+ case EVENT_NEW_SMS:
+ // A new SMS has been received by the device
+ if (Config.LOGD) {
+ Log.d(TAG, "New SMS Message Received");
+ }
+
+ SmsMessage sms;
+
+ ar = (AsyncResult) msg.obj;
+
+ // FIXME only acknowledge on store
+ acknowledgeLastIncomingSms(true, null);
+
+ if (ar.exception != null) {
+ Log.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception);
+ return;
+ }
+
+ sms = (SmsMessage) ar.result;
+ dispatchMessage(sms.mWrappedSmsMessage);
+
+ break;
+
+ case EVENT_SEND_SMS_COMPLETE:
+ // An outbound SMS has been successfully transferred, or failed.
+ handleSendComplete((AsyncResult) msg.obj);
+ break;
+
+ case EVENT_SEND_RETRY:
+ sendSms((SmsTracker) msg.obj);
+ break;
+
+ case EVENT_NEW_SMS_STATUS_REPORT:
+ handleStatusReport((AsyncResult)msg.obj);
+ break;
+
+ case EVENT_ICC_FULL:
+ handleIccFull();
+ break;
+
+ case EVENT_POST_ALERT:
+ handleReachSentLimit((SmsTracker)(msg.obj));
+ break;
+
+ case EVENT_ALERT_TIMEOUT:
+ ((AlertDialog)(msg.obj)).dismiss();
+ msg.obj = null;
+ mSTracker = null;
+ break;
+
+ case EVENT_SEND_CONFIRMED_SMS:
+ if (mSTracker!=null) {
+ if (isMultipartTracker(mSTracker)) {
+ sendMultipartSms(mSTracker);
+ } else {
+ sendSms(mSTracker);
+ }
+ mSTracker = null;
+ }
+ break;
+ }
+ }
+
+ /**
+ * Called when SIM_FULL message is received from the RIL. Notifies interested
+ * parties that SIM storage for SMS messages is full.
+ */
+ private void handleIccFull(){
+ // broadcast SIM_FULL intent
+ Intent intent = new Intent(Intents.SIM_FULL_ACTION);
+ mPhone.getContext().sendBroadcast(intent, "android.permission.RECEIVE_SMS");
+ }
+
+ /**
+ * Called when a status report is received. This should correspond to
+ * a previously successful SEND.
+ *
+ * @param ar AsyncResult passed into the message handler. ar.result should
+ * be a String representing the status report PDU, as ASCII hex.
+ */
+ protected abstract void handleStatusReport(AsyncResult ar);
+
+ /**
+ * Called when SMS send completes. Broadcasts a sentIntent on success.
+ * On failure, either sets up retries or broadcasts a sentIntent with
+ * the failure in the result code.
+ *
+ * @param ar AsyncResult passed into the message handler. ar.result should
+ * an SmsResponse instance if send was successful. ar.userObj
+ * should be an SmsTracker instance.
+ */
+ protected void handleSendComplete(AsyncResult ar) {
+ SmsTracker tracker = (SmsTracker) ar.userObj;
+ PendingIntent sentIntent = tracker.mSentIntent;
+
+ if (ar.exception == null) {
+ if (Config.LOGD) {
+ Log.d(TAG, "SMS send complete. Broadcasting "
+ + "intent: " + sentIntent);
+ }
+
+ if (tracker.mDeliveryIntent != null) {
+ // Expecting a status report. Add it to the list.
+ int messageRef = ((SmsResponse)ar.result).messageRef;
+ tracker.mMessageRef = messageRef;
+ deliveryPendingList.add(tracker);
+ }
+
+ if (sentIntent != null) {
+ try {
+ sentIntent.send(Activity.RESULT_OK);
+ } catch (CanceledException ex) {}
+ }
+ } else {
+ if (Config.LOGD) {
+ Log.d(TAG, "SMS send failed");
+ }
+
+ int ss = mPhone.getServiceState().getState();
+
+ if (ss != ServiceState.STATE_IN_SERVICE) {
+ handleNotInService(ss, tracker);
+ } else if ((((CommandException)(ar.exception)).getCommandError()
+ == CommandException.Error.SMS_FAIL_RETRY) &&
+ tracker.mRetryCount < MAX_SEND_RETRIES) {
+ // Retry after a delay if needed.
+ // TODO: According to TS 23.040, 9.2.3.6, we should resend
+ // with the same TP-MR as the failed message, and
+ // TP-RD set to 1. However, we don't have a means of
+ // knowing the MR for the failed message (EF_SMSstatus
+ // may or may not have the MR corresponding to this
+ // message, depending on the failure). Also, in some
+ // implementations this retry is handled by the baseband.
+ tracker.mRetryCount++;
+ Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
+ sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
+ } else if (tracker.mSentIntent != null) {
+ // Done retrying; return an error to the app.
+ try {
+ tracker.mSentIntent.send(RESULT_ERROR_GENERIC_FAILURE);
+ } catch (CanceledException ex) {}
+ }
+ }
+ }
+
+ /**
+ * Handles outbound message when the phone is not in service.
+ *
+ * @param ss Current service state. Valid values are:
+ * OUT_OF_SERVICE
+ * EMERGENCY_ONLY
+ * POWER_OFF
+ * @param tracker An SmsTracker for the current message.
+ */
+ protected void handleNotInService(int ss, SmsTracker tracker) {
+ if (tracker.mSentIntent != null) {
+ try {
+ if (ss == ServiceState.STATE_POWER_OFF) {
+ tracker.mSentIntent.send(RESULT_ERROR_RADIO_OFF);
+ } else {
+ tracker.mSentIntent.send(RESULT_ERROR_NO_SERVICE);
+ }
+ } catch (CanceledException ex) {}
+ }
+ }
+
+ /**
+ * Dispatches an incoming SMS messages.
+ *
+ * @param sms the incoming message from the phone
+ */
+ protected abstract void dispatchMessage(SmsMessageBase sms);
+
+
+ /**
+ * If this is the last part send the parts out to the application, otherwise
+ * the part is stored for later processing.
+ */
+ protected void processMessagePart(SmsMessageBase sms, int referenceNumber,
+ int sequence, int count, int destinationPort) {
+ // Lookup all other related parts
+ StringBuilder where = new StringBuilder("reference_number =");
+ where.append(referenceNumber);
+ where.append(" AND address = ?");
+ String[] whereArgs = new String[] {sms.getOriginatingAddress()};
+
+ byte[][] pdus = null;
+ Cursor cursor = null;
+ try {
+ cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null);
+ int cursorCount = cursor.getCount();
+ if (cursorCount != count - 1) {
+ // We don't have all the parts yet, store this one away
+ ContentValues values = new ContentValues();
+ values.put("date", new Long(sms.getTimestampMillis()));
+ values.put("pdu", HexDump.toHexString(sms.getPdu()));
+ values.put("address", sms.getOriginatingAddress());
+ values.put("reference_number", referenceNumber);
+ values.put("count", count);
+ values.put("sequence", sequence);
+ if (destinationPort != -1) {
+ values.put("destination_port", destinationPort);
+ }
+ mResolver.insert(mRawUri, values);
+
+ return;
+ }
+
+ // All the parts are in place, deal with them
+ int pduColumn = cursor.getColumnIndex("pdu");
+ int sequenceColumn = cursor.getColumnIndex("sequence");
+
+ pdus = new byte[count][];
+ for (int i = 0; i < cursorCount; i++) {
+ cursor.moveToNext();
+ int cursorSequence = (int)cursor.getLong(sequenceColumn);
+ pdus[cursorSequence - 1] = HexDump.hexStringToByteArray(
+ cursor.getString(pduColumn));
+ }
+ // This one isn't in the DB, so add it
+ pdus[sequence - 1] = sms.getPdu();
+
+ // Remove the parts from the database
+ mResolver.delete(mRawUri, where.toString(), whereArgs);
+ } catch (SQLException e) {
+ Log.e(TAG, "Can't access multipart SMS database", e);
+ return; // TODO: NACK the message or something, don't just discard.
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+
+ // Dispatch the PDUs to applications
+ switch (destinationPort) {
+ case SmsHeader.PORT_WAP_PUSH: {
+ // Build up the data stream
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ for (int i = 0; i < count; i++) {
+ SmsMessage msg = SmsMessage.createFromPdu(pdus[i]);
+ byte[] data = msg.getUserData();
+ output.write(data, 0, data.length);
+ }
+
+ // Handle the PUSH
+ mWapPush.dispatchWapPdu(output.toByteArray());
+ break;
+ }
+
+ case -1:
+ // The messages were not sent to a port
+ dispatchPdus(pdus);
+ break;
+
+ default:
+ // The messages were sent to a port, so concoct a URI for it
+ dispatchPortAddressedPdus(pdus, destinationPort);
+ break;
+ }
+ }
+
+ /**
+ * Dispatches standard PDUs to interested applications
+ *
+ * @param pdus The raw PDUs making up the message
+ */
+ protected void dispatchPdus(byte[][] pdus) {
+ Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
+ intent.putExtra("pdus", pdus);
+ mPhone.getContext().sendBroadcast(
+ intent, "android.permission.RECEIVE_SMS");
+ }
+
+ /**
+ * Dispatches port addressed PDUs to interested applications
+ *
+ * @param pdus The raw PDUs making up the message
+ * @param port The destination port of the messages
+ */
+ 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);
+ mPhone.getContext().sendBroadcast(
+ intent, "android.permission.RECEIVE_SMS");
+ }
+
+
+ /**
+ * 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 ArrayList
of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an ArrayList
of
+ * PendingIntent
s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be Activity.RESULT_OK for success,
+ * or one of these errors:
+ * RESULT_ERROR_GENERIC_FAILURE
+ * RESULT_ERROR_RADIO_OFF
+ * RESULT_ERROR_NULL_PDU
.
+ * 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 ArrayList
of
+ * PendingIntent
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").
+ */
+ protected abstract void sendMultipartText(String destinationAddress, String scAddress,
+ ArrayList parts, ArrayList sentIntents,
+ ArrayList deliveryIntents);
+
+ /**
+ * Send a SMS
+ *
+ * @param smsc the SMSC to send the message through, or NULL for the
+ * defatult SMSC
+ * @param pdu the raw PDU to send
+ * @param sentIntent if not NULL this Intent
is
+ * broadcast when the message is sucessfully sent, or failed.
+ * The result code will be Activity.RESULT_OK for success,
+ * or one of these errors:
+ * RESULT_ERROR_GENERIC_FAILURE
+ * RESULT_ERROR_RADIO_OFF
+ * RESULT_ERROR_NULL_PDU
.
+ * 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 Intent
is
+ * broadcast when the message is delivered to the recipient. The
+ * raw pdu of the status report is in the extended data ("pdu").
+ */
+ protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
+ PendingIntent deliveryIntent) {
+ if (pdu == null) {
+ if (sentIntent != null) {
+ try {
+ sentIntent.send(RESULT_ERROR_NULL_PDU);
+ } catch (CanceledException ex) {}
+ }
+ return;
+ }
+
+ HashMap map = new HashMap();
+ map.put("smsc", smsc);
+ map.put("pdu", pdu);
+
+ SmsTracker tracker = new SmsTracker(map, sentIntent,
+ deliveryIntent);
+ int ss = mPhone.getServiceState().getState();
+
+ if (ss != ServiceState.STATE_IN_SERVICE) {
+ handleNotInService(ss, tracker);
+ } else {
+ String appName = getAppNameByIntent(sentIntent);
+ if (mCounter.check(appName, SINGLE_PART_SMS)) {
+ sendSms(tracker);
+ } else {
+ sendMessage(obtainMessage(EVENT_POST_ALERT, tracker));
+ }
+ }
+ }
+
+ /**
+ * Post an alert while SMS needs user confirm.
+ *
+ * An SmsTracker for the current message.
+ */
+ protected void handleReachSentLimit(SmsTracker tracker) {
+
+ Resources r = Resources.getSystem();
+
+ String appName = getAppNameByIntent(tracker.mSentIntent);
+
+ AlertDialog d = new AlertDialog.Builder(mContext)
+ .setTitle(r.getString(R.string.sms_control_title))
+ .setMessage(appName + " " + r.getString(R.string.sms_control_message))
+ .setPositiveButton(r.getString(R.string.sms_control_yes), mListener)
+ .setNegativeButton(r.getString(R.string.sms_control_no), null)
+ .create();
+
+ d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ d.show();
+
+ mSTracker = tracker;
+ sendMessageDelayed ( obtainMessage(EVENT_ALERT_TIMEOUT, d),
+ DEFAULT_SMS_TIMOUEOUT);
+ }
+
+ protected String getAppNameByIntent(PendingIntent intent) {
+ Resources r = Resources.getSystem();
+ return (intent != null) ? intent.getTargetPackage()
+ : r.getString(R.string.sms_control_default_app_name);
+ }
+
+ /**
+ * Send the message along to the radio.
+ *
+ * @param tracker holds the SMS message to send
+ */
+ 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
+ */
+ 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
+ *
+ * @param tracker a SmsTracker could hold a multi-part Sms
+ * @return true for tracker holds Multi-parts Sms
+ */
+ private boolean isMultipartTracker (SmsTracker tracker) {
+ 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 protected class SmsTracker {
+ // fields need to be public for derived SmsDispatchers
+ public HashMap mData;
+ public int mRetryCount;
+ public int mMessageRef;
+
+ public PendingIntent mSentIntent;
+ public PendingIntent mDeliveryIntent;
+
+ SmsTracker(HashMap data, PendingIntent sentIntent,
+ PendingIntent deliveryIntent) {
+ mData = data;
+ mSentIntent = sentIntent;
+ 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() {
+
+ 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));
+ }
+ }
+ };
+}
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
new file mode 100644
index 0000000..a4bf0dd
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -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];
+ }
+}
+
diff --git a/telephony/java/com/android/internal/telephony/SimCard.java b/telephony/java/com/android/internal/telephony/SimCard.java
deleted file mode 100644
index 03b366f..0000000
--- a/telephony/java/com/android/internal/telephony/SimCard.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import android.os.Message;
-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 */
- static public final String INTENT_KEY_LOCKED_REASON = "reason";
- /* PIN means SIM is locked on PIN1 */
- static public final String INTENT_VALUE_LOCKED_ON_PIN = "PIN";
- /* PUK means SIM is locked on PUK1 */
- static public final String INTENT_VALUE_LOCKED_ON_PUK = "PUK";
- /* NETWORK means SIM 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
- turns to READY
- */
- public enum State {
- UNKNOWN,
- ABSENT,
- PIN_REQUIRED,
- PUK_REQUIRED,
- NETWORK_LOCKED,
- READY;
-
- public boolean isPinLocked() {
- return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
- }
- }
-
- State getState();
-
-
- /**
- * Notifies handler of any transition into State.ABSENT
- */
- void registerForAbsent(Handler h, int what, Object obj);
- void unregisterForAbsent(Handler h);
-
- /**
- * Notifies handler of any transition into State.isPinLocked()
- */
- void registerForLocked(Handler h, int what, Object obj);
- void unregisterForLocked(Handler h);
-
- /**
- * Notifies handler of any transition into State.NETWORK_LOCKED
- */
- void registerForNetworkLocked(Handler h, int what, Object obj);
- void unregisterForNetworkLocked(Handler h);
-
- /**
- * Supply the SIM PIN to the SIM
- *
- * When the operation is complete, onComplete will be sent to it's
- * Handler.
- *
- * onComplete.obj will be an AsyncResult
- *
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- *
- * If the supplied PIN is incorrect:
- * ((AsyncResult)onComplete.obj).exception != null
- * && ((AsyncResult)onComplete.obj).exception
- * instanceof com.android.internal.telephony.gsm.CommandException)
- * && ((CommandException)(((AsyncResult)onComplete.obj).exception))
- * .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
- *
- *
- */
-
- void supplyPin (String pin, Message onComplete);
- void supplyPuk (String puk, String newPin, Message onComplete);
- void supplyPin2 (String pin2, Message onComplete);
- void supplyPuk2 (String puk2, String newPin2, Message onComplete);
-
- /**
- * Check whether sim 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
- */
- boolean getSimLockEnabled ();
-
- /**
- * Set the sim 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 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);
-
-
- /**
- * Change the sim password used in sim pin lock
- * When the operation is complete, onComplete will be sent to its handler
- *
- * @param oldPassword is the old password
- * @param newPassword is the new password
- * @param onComplete
- * onComplete.obj will be an AsyncResult
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- */
- void changeSimLockPassword(String oldPassword, String newPassword,
- Message onComplete);
-
- /**
- * Check whether sim 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
- */
- boolean getSimFdnEnabled ();
-
- /**
- * Set the sim 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 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);
-
- /**
- * Change the sim password used in sim fdn enable
- * When the operation is complete, onComplete will be sent to its handler
- *
- * @param oldPassword is the old password
- * @param newPassword is the new password
- * @param onComplete
- * onComplete.obj will be an AsyncResult
- * ((AsyncResult)onComplete.obj).exception == null on success
- * ((AsyncResult)onComplete.obj).exception != null on fail
- */
- void changeSimFdnPassword(String oldPassword, String newPassword,
- Message onComplete);
-
- void supplyNetworkDepersonalization (String pin, Message onComplete);
-
- /**
- * Returns service provider name stored in SIM card.
- * If there is no service provider name associated or the record is not
- * yet available, null will be returned
- *
- * Please use this value when display Service Provider Name in idle mode
- *
- * Usage of this provider name in the UI is a common carrier requirement.
- *
- * Also available via Android property "gsm.sim.operator.alpha"
- *
- * @return Service Provider Name stored in SIM card
- * null if no service provider name associated or the record is not
- * yet available
- *
- */
- String getServiceProviderName();
-}
diff --git a/telephony/java/com/android/internal/telephony/SmsAddress.java b/telephony/java/com/android/internal/telephony/SmsAddress.java
new file mode 100644
index 0000000..b3892cb
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SmsAddress.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+public abstract class SmsAddress {
+ // From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118
+ // and C.S0005-D table 2.7.1.3.2.4-2
+ public static final int TON_UNKNOWN = 0;
+ public static final int TON_INTERNATIONAL = 1;
+ public static final int TON_NATIONAL = 2;
+ public static final int TON_NETWORK = 3;
+ public static final int TON_SUBSCRIBER = 4;
+ public static final int TON_ALPHANUMERIC = 5;
+ public static final int TON_ABBREVIATED = 6;
+
+ public int ton;
+ public String address;
+ public byte[] origBytes;
+
+ /**
+ * Returns the address of the SMS message in String form or null if unavailable
+ */
+ public String getAddressString() {
+ return address;
+ }
+
+ /**
+ * Returns true if this is an alphanumeric address
+ */
+ public boolean isAlphanumeric() {
+ return ton == TON_ALPHANUMERIC;
+ }
+
+ /**
+ * Returns true if this is a network address
+ */
+ public boolean isNetworkSpecific() {
+ return ton == TON_NETWORK;
+ }
+
+ public boolean couldBeEmailGateway() {
+ // Some carriers seems to send email gateway messages in this form:
+ // from: an UNKNOWN TON, 3 or 4 digits long, beginning with a 5
+ // PID: 0x00, Data coding scheme 0x03
+ // So we just attempt to treat any message from an address length <= 4
+ // as an email gateway
+
+ return address.length() <= 4;
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java
new file mode 100644
index 0000000..64b884e
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SmsHeader.java
@@ -0,0 +1,242 @@
+/*
+ * 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 com.android.internal.util.HexDump;
+
+import java.util.ArrayList;
+
+/**
+ * This class represents a SMS user data header.
+ *
+ */
+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. */
+ public static final int SPECIAL_SMS_MESSAGE_INDICATION = 0x01;
+ /** See TS 23.040 9.2.3.24 for description of this element ID. */
+ public static final int APPLICATION_PORT_ADDRESSING_8_BIT = 0x04;
+ /** See TS 23.040 9.2.3.24 for description of this element ID. */
+ public static final int APPLICATION_PORT_ADDRESSING_16_BIT= 0x05;
+ /** See TS 23.040 9.2.3.24 for description of this element ID. */
+ public static final int CONCATENATED_16_BIT_REFERENCE = 0x08;
+
+ public static final int PORT_WAP_PUSH = 2948;
+ public static final int PORT_WAP_WSP = 9200;
+
+ private byte[] m_data;
+ private ArrayList m_elements = new ArrayList();
+ public int nbrOfHeaders;
+
+ /**
+ * Creates an SmsHeader object from raw user data header bytes.
+ *
+ * @param data is user data header bytes
+ * @return an SmsHeader object
+ */
+ public static SmsHeader parse(byte[] data) {
+ SmsHeader header = new SmsHeader();
+ header.m_data = data;
+
+ int index = 0;
+ 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() { }
+
+ /**
+ * Returns the list of SmsHeader Elements that make up the header.
+ *
+ * @return the list of SmsHeader Elements.
+ */
+ public ArrayList getElements() {
+ return m_elements;
+ }
+
+ /**
+ * Add an element to the SmsHeader.
+ *
+ * @param element to add.
+ */
+ public void add(Element element) {
+ m_elements.add(element);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("UDH LENGTH: " + m_data.length + " octets");
+ builder.append("UDH: ");
+ builder.append(HexDump.toHexString(m_data));
+ builder.append("\n");
+
+ for (Element e : getElements()) {
+ builder.append(" 0x" + HexDump.toHexString((byte)e.getID()) + " - ");
+ 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(" " + 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: {
+ 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(" " + data[2] + " : number of messages\n");
+ builder.append(" " + data[3] + " : this SM sequence number\n");
+ break;
+ }
+
+ 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");
+
+ int source = (data[0] & 0xff) << 8;
+ source |= (data[1] & 0xff);
+ builder.append(" " + source + " : DESTINATION port\n");
+
+ int dest = (data[2] & 0xff) << 8;
+ dest |= (data[3] & 0xff);
+ builder.append(" " + dest + " : SOURCE port\n");
+ break;
+ }
+
+ default: {
+ builder.append("Unknown element\n");
+ break;
+ }
+ }
+ }
+
+ return builder.toString();
+ }
+
+ private int calcSize() {
+ int size = 1; // +1 for the UDHL field
+ for (Element e : m_elements) {
+ size += e.getData().length;
+ size += 2; // 1 byte ID, 1 byte length
+ }
+
+ return size;
+ }
+
+ /**
+ * Converts SmsHeader object to a byte array as specified in TS 23.040 9.2.3.24.
+ * @return Byte array representing the SmsHeader
+ */
+ public byte[] toByteArray() {
+ if (m_elements.size() == 0) return null;
+
+ if (m_data == null) {
+ int size = calcSize();
+ int cur = 1;
+ m_data = new byte[size];
+
+ m_data[0] = (byte) (size-1); // UDHL does not include itself
+
+ for (Element e : m_elements) {
+ int length = e.getData().length;
+ m_data[cur++] = (byte) e.getID();
+ m_data[cur++] = (byte) length;
+ System.arraycopy(e.getData(), 0, m_data, cur, length);
+ cur += length;
+ }
+ }
+
+ return m_data;
+ }
+
+ /**
+ * A single Element in the SMS User Data Header.
+ *
+ * See TS 23.040 9.2.3.24.
+ *
+ */
+ public static class Element {
+ private byte[] m_data;
+ private int m_id;
+
+ public Element(int id, byte[] data) {
+ m_id = id;
+ m_data = data;
+ }
+
+ /**
+ * Returns the Information Element Identifier for this element.
+ *
+ * @return the IE identifier.
+ */
+ public int getID() {
+ return m_id;
+ }
+
+ /**
+ * Returns the data portion of this element.
+ *
+ * @return element data.
+ */
+ public byte[] getData() {
+ return m_data;
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
new file mode 100644
index 0000000..7c32451
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.util.Log;
+import com.android.internal.telephony.SmsHeader;
+import java.util.Arrays;
+
+import static android.telephony.SmsMessage.ENCODING_7BIT;
+import static android.telephony.SmsMessage.ENCODING_16BIT;
+import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES;
+import static android.telephony.SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER;
+import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS;
+import static android.telephony.SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER;
+import static android.telephony.SmsMessage.MessageClass;
+import static com.android.internal.telephony.SmsAddress.TON_ABBREVIATED;
+import static com.android.internal.telephony.SmsAddress.TON_ALPHANUMERIC;
+import static com.android.internal.telephony.SmsAddress.TON_INTERNATIONAL;
+import static com.android.internal.telephony.SmsAddress.TON_NATIONAL;
+import static com.android.internal.telephony.SmsAddress.TON_NETWORK;
+import static com.android.internal.telephony.SmsAddress.TON_SUBSCRIBER;
+import static com.android.internal.telephony.SmsAddress.TON_UNKNOWN;
+
+/**
+ * Base class declaring the specific methods and members for SmsMessage.
+ * {@hide}
+ */
+public abstract class SmsMessageBase {
+ private static final String LOG_TAG = "SMS";
+
+ /** {@hide} The address of the SMSC. May be null */
+ protected String scAddress;
+
+ /** {@hide} The address of the sender */
+ protected SmsAddress originatingAddress;
+
+ /** {@hide} The message body as a string. May be null if the message isn't text */
+ protected String messageBody;
+
+ /** {@hide} */
+ protected String pseudoSubject;
+
+ /** {@hide} Non-null if this is an email gateway message */
+ protected String emailFrom;
+
+ /** {@hide} Non-null if this is an email gateway message */
+ protected String emailBody;
+
+ /** {@hide} */
+ protected boolean isEmail;
+
+ /** {@hide} */
+ protected long scTimeMillis;
+
+ /** {@hide} The raw PDU of the message */
+ protected byte[] mPdu;
+
+ /** {@hide} The raw bytes for the user data section of the message */
+ protected byte[] userData;
+
+ /** {@hide} */
+ protected SmsHeader userDataHeader;
+
+ // "Message Waiting Indication Group"
+ // 23.038 Section 4
+ /** {@hide} */
+ protected boolean isMwi;
+
+ /** {@hide} */
+ protected boolean mwiSense;
+
+ /** {@hide} */
+ protected boolean mwiDontStore;
+
+ /**
+ * Indicates status for messages stored on the ICC.
+ */
+ protected int statusOnIcc = -1;
+
+ /**
+ * Record index of message in the EF.
+ */
+ protected int indexOnIcc = -1;
+
+ /** TP-Message-Reference - Message Reference of sent message. @hide */
+ public int messageRef;
+
+ public static abstract class SubmitPduBase {
+ public byte[] encodedScAddress; // Null if not applicable.
+ public byte[] encodedMessage;
+
+ public String toString() {
+ return "SubmitPdu: encodedScAddress = "
+ + Arrays.toString(encodedScAddress)
+ + ", encodedMessage = "
+ + Arrays.toString(encodedMessage);
+ }
+ }
+
+ /**
+ * Returns the address of the SMS service center that relayed this message
+ * or null if there is none.
+ */
+ public String getServiceCenterAddress() {
+ return scAddress;
+ }
+
+ /**
+ * Returns the originating address (sender) of this SMS message in String
+ * form or null if unavailable
+ */
+ public String getOriginatingAddress() {
+ if (originatingAddress == null) {
+ return null;
+ }
+
+ return originatingAddress.getAddressString();
+ }
+
+ /**
+ * Returns the originating address, or email from address if this message
+ * was from an email gateway. Returns null if originating address
+ * unavailable.
+ */
+ public String getDisplayOriginatingAddress() {
+ if (isEmail) {
+ return emailFrom;
+ } else {
+ return getOriginatingAddress();
+ }
+ }
+
+ /**
+ * Returns the message body as a String, if it exists and is text based.
+ * @return message body is there is one, otherwise null
+ */
+ public String getMessageBody() {
+ return messageBody;
+ }
+
+ /**
+ * Returns the class of this message.
+ */
+ public abstract MessageClass getMessageClass();
+
+ /**
+ * Returns the message body, or email message body if this message was from
+ * an email gateway. Returns null if message body unavailable.
+ */
+ public String getDisplayMessageBody() {
+ if (isEmail) {
+ return emailBody;
+ } else {
+ return getMessageBody();
+ }
+ }
+
+ /**
+ * Unofficial convention of a subject line enclosed in parens empty string
+ * if not present
+ */
+ public String getPseudoSubject() {
+ return pseudoSubject == null ? "" : pseudoSubject;
+ }
+
+ /**
+ * Returns the service centre timestamp in currentTimeMillis() format
+ */
+ public long getTimestampMillis() {
+ return scTimeMillis;
+ }
+
+ /**
+ * Returns true if message is an email.
+ *
+ * @return true if this message came through an email gateway and email
+ * sender / subject / parsed body are available
+ */
+ public boolean isEmail() {
+ return isEmail;
+ }
+
+ /**
+ * @return if isEmail() is true, body of the email sent through the gateway.
+ * null otherwise
+ */
+ public String getEmailBody() {
+ return emailBody;
+ }
+
+ /**
+ * @return if isEmail() is true, email from address of email sent through
+ * the gateway. null otherwise
+ */
+ public String getEmailFrom() {
+ return emailFrom;
+ }
+
+ /**
+ * Get protocol identifier.
+ */
+ public abstract int getProtocolIdentifier();
+
+ /**
+ * See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
+ * SMS
+ */
+ public abstract boolean isReplace();
+
+ /**
+ * Returns true for CPHS MWI toggle message.
+ *
+ * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section
+ * B.4.2
+ */
+ public abstract boolean isCphsMwiMessage();
+
+ /**
+ * returns true if this message is a CPHS voicemail / message waiting
+ * indicator (MWI) clear message
+ */
+ public abstract boolean isMWIClearMessage();
+
+ /**
+ * returns true if this message is a CPHS voicemail / message waiting
+ * indicator (MWI) set message
+ */
+ public abstract boolean isMWISetMessage();
+
+ /**
+ * returns true if this message is a "Message Waiting Indication Group:
+ * Discard Message" notification and should not be stored.
+ */
+ public abstract boolean isMwiDontStore();
+
+ /**
+ * returns the user data section minus the user data header if one was
+ * present.
+ */
+ public byte[] getUserData() {
+ return userData;
+ }
+
+ /**
+ * Returns an object representing the user data header
+ *
+ * @return an object representing the user data header
+ *
+ * {@hide}
+ */
+ public SmsHeader getUserDataHeader() {
+ return userDataHeader;
+ }
+
+ /**
+ * Returns the raw PDU for the message.
+ *
+ * @return the raw PDU for the message.
+ */
+ public byte[] getPdu() {
+ return mPdu;
+ }
+
+ /**
+ * For an SMS-STATUS-REPORT message, this returns the status field from
+ * the status report. This field indicates the status of a previously
+ * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a
+ * description of values.
+ *
+ * @return 0 indicates the previously sent message was received.
+ * See TS 23.040, 9.9.2.3.15 for a description of other possible
+ * values.
+ */
+ public abstract int getStatus();
+
+ /**
+ * Return true iff the message is a SMS-STATUS-REPORT message.
+ */
+ public abstract boolean isStatusReportMessage();
+
+ /**
+ * Returns true iff the TP-Reply-Path
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: [] - "Depending on the
+ * nature of the gateway, the destination/origination address is either
+ * derived from the content of the SMS TP-OA or TP-DA field, or the
+ * TP-OA/TP-DA field contains a generic gateway address and the to/from
+ * address is added at the beginning as shown above." - multiple addreses
+ * separated by commas, no spaces - subject field delimited by '()' or '##'
+ * and '#' Section 9.2.3.24.11
+ */
+ protected void extractEmailAddressFromMessageBody() {
+
+ /*
+ * a little guesswork here. I haven't found doc for this.
+ * the format could be either
+ *
+ * 1. [x@y][ ]/[subject][ ]/[body]
+ * -or-
+ * 2. [x@y][ ]/[body]
+ */
+ int slash = 0, slash2 = 0, atSymbol = 0;
+
+ try {
+ slash = messageBody.indexOf(" /");
+ if (slash == -1) {
+ return;
+ }
+
+ atSymbol = messageBody.indexOf('@');
+ if (atSymbol == -1 || atSymbol > slash) {
+ return;
+ }
+
+ emailFrom = messageBody.substring(0, slash);
+
+ slash2 = messageBody.indexOf(" /", slash + 2);
+
+ if (slash2 == -1) {
+ pseudoSubject = null;
+ emailBody = messageBody.substring(slash + 2);
+ } else {
+ pseudoSubject = messageBody.substring(slash + 2, slash2);
+ emailBody = messageBody.substring(slash2 + 2);
+ }
+
+ isEmail = true;
+ } catch (Exception ex) {
+ Log.w(LOG_TAG,
+ "extractEmailAddressFromMessageBody: exception slash="
+ + slash + ", atSymbol=" + atSymbol + ", slash2="
+ + slash2, ex);
+ }
+ }
+
+}
+
diff --git a/telephony/java/com/android/internal/telephony/SmsRawData.aidl b/telephony/java/com/android/internal/telephony/SmsRawData.aidl
new file mode 100644
index 0000000..b0b3e4f
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SmsRawData.aidl
@@ -0,0 +1,19 @@
+/*
+** 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;
+
+parcelable SmsRawData;
diff --git a/telephony/java/com/android/internal/telephony/SmsRawData.java b/telephony/java/com/android/internal/telephony/SmsRawData.java
new file mode 100644
index 0000000..891d942
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SmsRawData.java
@@ -0,0 +1,62 @@
+/*
+** 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;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A parcelable holder class of byte[] for ISms aidl implementation
+ */
+public class SmsRawData implements Parcelable {
+ byte[] data;
+
+ //Static Methods
+ public static final Parcelable.Creator CREATOR
+ = new Parcelable.Creator (){
+ public SmsRawData createFromParcel(Parcel source) {
+ int size;
+ size = source.readInt();
+ byte[] data = new byte[size];
+ source.readByteArray(data);
+ return new SmsRawData(data);
+ }
+
+ public SmsRawData[] newArray(int size) {
+ return new SmsRawData[size];
+ }
+ };
+
+ // Constructor
+ public SmsRawData(byte[] data) {
+ this.data = data;
+ }
+
+ public byte[] getBytes() {
+ return data;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(data.length);
+ dest.writeByteArray(data);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/SmsResponse.java b/telephony/java/com/android/internal/telephony/SmsResponse.java
new file mode 100644
index 0000000..3c4df56
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/SmsResponse.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * Object returned by the RIL upon successful completion of sendSMS.
+ * Contains message reference and ackPdu.
+ *
+ */
+public class SmsResponse {
+ /** Message reference of the just-sent SMS. */
+ int messageRef;
+ /** ackPdu for the just-sent SMS. */
+ String ackPdu;
+
+ public SmsResponse(int messageRef, String ackPdu) {
+ this.messageRef = messageRef;
+ this.ackPdu = ackPdu;
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEventLog.java b/telephony/java/com/android/internal/telephony/TelephonyEventLog.java
new file mode 100644
index 0000000..1ef3c6c
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyEventLog.java
@@ -0,0 +1,33 @@
+/*
+ * 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;
+
+/* This class contains the details related to Telephony Event Logging */
+public final class TelephonyEventLog {
+
+ /* Event log tags */
+ public static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
+ public static final int EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED = 50101;
+ public static final int EVENT_LOG_RADIO_RESET = 50102;
+ public static final int EVENT_LOG_PDP_RESET = 50103;
+ public static final int EVENT_LOG_REREGISTER_NETWORK = 50104;
+ public static final int EVENT_LOG_RADIO_PDP_SETUP_FAIL = 50105;
+ public static final int EVENT_LOG_CALL_DROP = 50106;
+ public static final int EVENT_LOG_CGREG_FAIL = 50107;
+ public static final int EVENT_DATA_STATE_RADIO_OFF = 50108;
+ public static final int EVENT_LOG_PDP_NETWORK_DROP = 50109;
+}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 9219e7a..c342233 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -35,6 +35,24 @@ public class TelephonyIntents {
*/
public static final String ACTION_SERVICE_STATE_CHANGED = "android.intent.action.SERVICE_STATE";
+ /**
+ * Broadcast Action: The radio technology has changed. The intent will have the following
+ * extra values:
+ *
+ * - phoneName - A string version of the new phone name.
+ *
+ *
+ *
+ * You can not 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()}.
+ *
+ *
+ * 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 {
*
- 0 means "-113 dBm or less".
- 31 means "-51 dBm or greater".
*
*
- *
+ *
*
* You can not receive this through components declared
* in manifests, only by exlicitly registering for it with
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 6aa90f1..396b42d 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -26,8 +26,11 @@ public interface TelephonyProperties
{
//****** Baseband and Radio Interface version
- /**
- * Baseband version
+ //TODO T: property strings do not have to be gsm specific
+ // change gsm.*operator.*" properties to "operator.*" properties
+
+ /**
+ * Baseband version
* Availability: property is available any time radio is on
*/
static final String PROPERTY_BASEBAND_VERSION = "gsm.version.baseband";
@@ -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 "UNKNOWN"
"ABSENT"
"PIN_REQUIRED"
* "PUK_REQUIRED"
"NETWORK_LOCKED"
or "READY"
*/
@@ -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: "unknown"
,
diff --git a/telephony/java/com/android/internal/telephony/WapPushOverSms.java b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
index 2b70162..98899c9 100644
--- a/telephony/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/telephony/java/com/android/internal/telephony/WapPushOverSms.java
@@ -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);
}
}
+
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
new file mode 100644
index 0000000..ef2f548
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -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 mPendingMMIs = new ArrayList();
+ 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 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);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java
new file mode 100644
index 0000000..ea557b2
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CallFailCause.java
@@ -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;
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
new file mode 100644
index 0000000..34514d9
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCall.java
@@ -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 connections = new ArrayList();
+ /*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
+ 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;
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
new file mode 100644
index 0000000..a1d362f
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -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 droppedDuringPoll
+ = new ArrayList(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 connCopy;
+
+ // We need to make a copy here, since fakeHoldBeforeDial()
+ // modifies the lists, and we don't want to reverse the order
+ connCopy = (List) 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);
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
new file mode 100644
index 0000000..cdad4a7
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -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");
+ }
+
+ /**
+ * 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);
+ }
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
new file mode 100644
index 0000000..84febf3
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -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 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.
+ * 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();
+ 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 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);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
new file mode 100644
index 0000000..42c0583
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -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 parts, ArrayList sentIntents,
+ ArrayList 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);
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
new file mode 100644
index 0000000..ca40e76
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -0,0 +1,1016 @@
+/*
+ * 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.AlarmManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.provider.Checkin;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.provider.Telephony.Intents;
+import android.telephony.ServiceState;
+import android.telephony.cdma.CdmaCellLocation;
+import android.text.TextUtils;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.TimeUtils;
+
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.DataConnectionTracker;
+// pretty sure importing stuff from GSM is bad:
+import com.android.internal.telephony.gsm.MccTable;
+import com.android.internal.telephony.PhoneProxy;
+import com.android.internal.telephony.ServiceStateTracker;
+import com.android.internal.telephony.TelephonyEventLog;
+import com.android.internal.telephony.TelephonyIntents;
+
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ALPHA;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISMANUAL;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * {@hide}
+ */
+final class CdmaServiceStateTracker extends ServiceStateTracker {
+ //***** Instance Variables
+ CDMAPhone phone;
+ CdmaCellLocation cellLoc;
+ CdmaCellLocation newCellLoc;
+
+ int rssi = 99; // signal strength 0-31, 99=unknown
+ // That's "received signal strength indication" fyi
+
+ /**
+ * The access technology currently in use: DATA_ACCESS_
+ */
+ private int networkType = 0;
+ private int newNetworkType = 0;
+
+ private boolean mCdmaRoaming = false;
+
+ private int cdmaDataConnectionState = -1;//Initial we assume no data connection
+ private int newCdmaDataConnectionState = -1;//Initial we assume no data connection
+ private int mRegistrationState = -1;
+ private RegistrantList cdmaDataConnectionAttachedRegistrants = new RegistrantList();
+ private RegistrantList cdmaDataConnectionDetachedRegistrants = new RegistrantList();
+
+ private boolean mGotCountryCode = false;
+
+ // We can't register for SIM_RECORDS_LOADED immediately because the
+ // SIMRecords object may not be instantiated yet.
+ private boolean mNeedToRegForRuimLoaded;
+
+ // Keep track of SPN display rules, so we only broadcast intent if something changes.
+ private String curSpn = null;
+ private String curPlmn = null;
+ private int curSpnRule = 0;
+
+ //***** Constants
+ static final String LOG_TAG = "CDMA";
+ static final String TMUK = "23430";
+
+ private ContentResolver cr;
+
+ private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ Log.i("CdmaServiceStateTracker", "Auto time state called ...");
+ //NOTE in CDMA NITZ is not used
+ }
+ };
+
+
+ //***** Constructors
+
+ public CdmaServiceStateTracker(CDMAPhone phone) {
+ super();
+
+ this.phone = phone;
+ cm = phone.mCM;
+ ss = new ServiceState();
+ newSS = new ServiceState();
+ cellLoc = new CdmaCellLocation();
+ newCellLoc = new CdmaCellLocation();
+
+ cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+ cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
+
+ cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED_CDMA, null);
+ cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
+
+ cm.registerForRUIMReady(this, EVENT_RUIM_READY, null);
+
+ phone.registerForNvLoaded(this, EVENT_NV_LOADED,null);
+
+ // system setting property AIRPLANE_MODE_ON is set in Settings.
+ int airplaneMode = Settings.System.getInt(
+ phone.getContext().getContentResolver(),
+ Settings.System.AIRPLANE_MODE_ON, 0);
+ mDesiredPowerState = ! (airplaneMode > 0);
+
+ cr = phone.getContext().getContentResolver();
+ cr.registerContentObserver(
+ Settings.System.getUriFor(Settings.System.AUTO_TIME), true,
+ mAutoTimeObserver);
+ setRssiDefaultValues();
+
+ mNeedToRegForRuimLoaded = true;
+ }
+
+ public void dispose() {
+ //Unregister for all events
+ cm.unregisterForAvailable(this);
+ cm.unregisterForRadioStateChanged(this);
+ cm.unregisterForNetworkStateChanged(this);
+ cm.unregisterForRUIMReady(this);
+ phone.unregisterForNvLoaded(this);
+ phone.mRuimRecords.unregisterForRecordsLoaded(this);
+ cm.unSetOnSignalStrengthUpdate(this);
+ cr.unregisterContentObserver(this.mAutoTimeObserver);
+ }
+
+ protected void finalize() {
+ if(DBG) Log.d(LOG_TAG, "CdmaServiceStateTracker finalized");
+ }
+
+ void registerForNetworkAttach(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ networkAttachedRegistrants.add(r);
+
+ if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
+ r.notifyRegistrant();
+ }
+ }
+
+ void unregisterForNetworkAttach(Handler h) {
+ networkAttachedRegistrants.remove(h);
+ }
+
+ /**
+ * Registration point for transition into Data attached.
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ /*protected*/ void
+ registerForCdmaDataConnectionAttached(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ cdmaDataConnectionAttachedRegistrants.add(r);
+
+ if (cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT
+ || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0
+ || cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A) {
+ r.notifyRegistrant();
+ }
+ }
+ void unregisterForCdmaDataConnectionAttached(Handler h) {
+ cdmaDataConnectionAttachedRegistrants.remove(h);
+ }
+
+ /**
+ * Registration point for transition into Data detached.
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ /*protected*/ void
+ registerForCdmaDataConnectionDetached(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ cdmaDataConnectionDetachedRegistrants.add(r);
+
+ if (cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT
+ && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0
+ && cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A) {
+ r.notifyRegistrant();
+ }
+ }
+ void unregisterForCdmaDataConnectionDetached(Handler h) {
+ cdmaDataConnectionDetachedRegistrants.remove(h);
+ }
+
+ //***** Called from CDMAPhone
+ public void
+ getLacAndCid(Message onComplete) {
+ cm.getRegistrationState(obtainMessage(
+ EVENT_GET_LOC_DONE_CDMA, onComplete));
+ }
+
+
+ //***** Overridden from ServiceStateTracker
+ public void
+ handleMessage (Message msg) {
+ AsyncResult ar;
+ int[] ints;
+ String[] strings;
+
+ switch (msg.what) {
+ case EVENT_RADIO_AVAILABLE:
+ //this is unnecessary
+ //setPowerStateToDesired();
+ break;
+
+ case EVENT_RUIM_READY:
+ // The RUIM is now ready i.e if it was locked
+ // it has been unlocked. At this stage, the radio is already
+ // powered on.
+ if (mNeedToRegForRuimLoaded) {
+ phone.mRuimRecords.registerForRecordsLoaded(this,
+ EVENT_RUIM_RECORDS_LOADED, null);
+ mNeedToRegForRuimLoaded = false;
+ }
+ // restore the previous network selection.
+ phone.restoreSavedNetworkSelection(null);
+ pollState();
+ // Signal strength polling stops when radio is off
+ queueNextSignalStrengthPoll();
+ break;
+
+ case EVENT_RADIO_STATE_CHANGED:
+ // This will do nothing in the radio not
+ // available case
+ setPowerStateToDesired();
+ pollState();
+ break;
+
+ case EVENT_NETWORK_STATE_CHANGED_CDMA:
+ pollState();
+ break;
+
+ case EVENT_GET_SIGNAL_STRENGTH:
+ // This callback is called when signal strength is polled
+ // all by itself
+
+ if (!(cm.getRadioState().isOn()) || (cm.getRadioState().isGsm())) {
+ // Polling will continue when radio turns back on
+ return;
+ }
+ ar = (AsyncResult) msg.obj;
+ onSignalStrengthResult(ar);
+ queueNextSignalStrengthPoll();
+
+ break;
+
+ case EVENT_GET_LOC_DONE_CDMA:
+ ar = (AsyncResult) msg.obj;
+
+ if (ar.exception == null) {
+ String states[] = (String[])ar.result;
+ int baseStationId = -1;
+ int baseStationLongitude = -1;
+ int baseStationLatitude = -1;
+
+ int baseStationData[] = {
+ -1, // baseStationId
+ -1, // baseStationLatitude
+ -1 // baseStationLongitude
+ };
+
+ if (states.length == 3) {
+ for(int i = 0; i < states.length; i++) {
+ try {
+ if (states[i] != null && states[i].length() > 0) {
+ baseStationData[i] = Integer.parseInt(states[i], 16);
+ }
+ } catch (NumberFormatException ex) {
+ Log.w(LOG_TAG, "error parsing cell location data: " + ex);
+ }
+ }
+ }
+
+ // only update if cell location really changed
+ if (cellLoc.getBaseStationId() != baseStationData[0]
+ || cellLoc.getBaseStationLatitude() != baseStationData[1]
+ || cellLoc.getBaseStationLongitude() != baseStationData[2]) {
+ cellLoc.setCellLocationData(baseStationData[0],
+ baseStationData[1],
+ baseStationData[2]);
+ phone.notifyLocationChanged();
+ }
+ }
+
+ if (ar.userObj != null) {
+ AsyncResult.forMessage(((Message) ar.userObj)).exception
+ = ar.exception;
+ ((Message) ar.userObj).sendToTarget();
+ }
+ break;
+
+ case EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA: //Fall through
+ case EVENT_POLL_STATE_REGISTRATION_CDMA: //Fall through
+ case EVENT_POLL_STATE_OPERATOR_CDMA:
+ ar = (AsyncResult) msg.obj;
+ handlePollStateResult(msg.what, ar);
+ break;
+
+ case EVENT_POLL_SIGNAL_STRENGTH:
+ // Just poll signal strength...not part of pollState()
+
+ cm.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
+ break;
+
+ case EVENT_SIGNAL_STRENGTH_UPDATE:
+ // This is a notification from
+ // CommandsInterface.setOnSignalStrengthUpdate
+
+ ar = (AsyncResult) msg.obj;
+
+ // The radio is telling us about signal strength changes
+ // we don't have to ask it
+ dontPollSignalStrength = true;
+
+ onSignalStrengthResult(ar);
+ break;
+
+ case EVENT_RUIM_RECORDS_LOADED:
+ case EVENT_NV_LOADED:
+ updateSpnDisplay();
+ break;
+
+ case EVENT_LOCATION_UPDATES_ENABLED:
+ ar = (AsyncResult) msg.obj;
+
+ if (ar.exception == null) {
+ getLacAndCid(null);
+ }
+ break;
+
+ default:
+ Log.e(LOG_TAG, "Unhandled message with number: " + msg.what);
+ break;
+ }
+ }
+
+ //***** Private Instance Methods
+
+ protected void setPowerStateToDesired()
+ {
+ // If we want it on and it's off, turn it on
+ if (mDesiredPowerState
+ && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
+ cm.setRadioPower(true, null);
+ } else if (!mDesiredPowerState && cm.getRadioState().isOn()) {
+ DataConnectionTracker dcTracker = phone.mDataConnection;
+ if (! dcTracker.isDataConnectionAsDesired()) {
+
+ EventLog.List val = new EventLog.List(
+ dcTracker.getStateInString(),
+ (dcTracker.getAnyDataEnabled() ? 1 : 0) );
+ EventLog.writeEvent(TelephonyEventLog.EVENT_DATA_STATE_RADIO_OFF, val);
+ }
+ dcTracker.cleanConnectionBeforeRadioOff();
+
+ // poll data state up to 15 times, with a 100ms delay
+ // totaling 1.5 sec. Normal data disable action will finish in 100ms.
+ for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) {
+ if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED
+ && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) {
+ Log.d(LOG_TAG, "Data shutdown complete.");
+ break;
+ }
+ SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS);
+ }
+ // If it's on and available and we want it off..
+ cm.setRadioPower(false, null);
+ } // Otherwise, we're in the desired state
+ }
+
+ protected void updateSpnDisplay() {
+
+ // TODO Check this method again, because it is not sure at the moment how
+ // the RUIM handles the SIM stuff
+
+ //int rule = phone.mRuimRecords.getDisplayRule(ss.getOperatorNumeric());
+ String spn = null; //phone.mRuimRecords.getServiceProviderName();
+ String plmn = ss.getOperatorAlphaLong();
+
+ if (!TextUtils.equals(this.curPlmn, plmn)) {
+ //TODO (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN;
+ boolean showSpn = false;
+ //TODO (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN;
+ boolean showPlmn = true;
+ Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION);
+ intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn);
+ intent.putExtra(Intents.EXTRA_SPN, spn);
+ intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn);
+ intent.putExtra(Intents.EXTRA_PLMN, plmn);
+ phone.getContext().sendStickyBroadcast(intent);
+ }
+
+ //curSpnRule = rule;
+ //curSpn = spn;
+ this.curPlmn = plmn;
+ }
+
+ /**
+ * Handle the result of one of the pollState()-related requests
+ */
+
+ protected void
+ handlePollStateResult (int what, AsyncResult ar) {
+ int ints[];
+ String states[];
+
+ // Ignore stale requests from last poll
+ if (ar.userObj != pollingContext) return;
+
+ if (ar.exception != null) {
+ CommandException.Error err=null;
+
+ if (ar.exception instanceof CommandException) {
+ err = ((CommandException)(ar.exception)).getCommandError();
+ }
+
+ if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
+ // Radio has crashed or turned off
+ cancelPollState();
+ return;
+ }
+
+ if (!cm.getRadioState().isOn()) {
+ // Radio has crashed or turned off
+ cancelPollState();
+ return;
+ }
+
+ if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW &&
+ err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
+ Log.e(LOG_TAG,
+ "RIL implementation has returned an error where it must succeed",
+ ar.exception);
+ }
+ } else try {
+ switch (what) {
+ case EVENT_POLL_STATE_REGISTRATION_CDMA:
+ //offset, because we don't want the first 3 values in the int-array
+ final int offset = 3;
+ states = (String[])ar.result;
+
+ int responseValuesRegistrationState[] = {
+ -1, //[0] radioTechnology
+ -1, //[1] baseStationId
+ -1, //[2] baseStationLatitude
+ -1, //[3] baseStationLongitude
+ 0, //[4] cssIndicator; init with 0, because it is treated as a boolean
+ -1, //[5] systemId
+ -1 //[6] networkId
+ };
+
+ if (states.length > 0) {
+ try {
+ this.mRegistrationState = Integer.parseInt(states[0]);
+ if (states.length == 10) {
+ for(int i = 0; i < states.length - offset; i++) {
+ if (states[i + offset] != null
+ && states[i + offset].length() > 0) {
+ try {
+ responseValuesRegistrationState[i] =
+ Integer.parseInt(states[i + offset], 16);
+ }
+ catch(NumberFormatException ex) {
+ Log.w(LOG_TAG, "Warning! There is an unexpected value"
+ + "returned as response from "
+ + "RIL_REQUEST_REGISTRATION_STATE.");
+ }
+ }
+ }
+ }
+ else {
+ Log.e(LOG_TAG, "Too less parameters returned from"
+ + " RIL_REQUEST_REGISTRATION_STATE");
+ }
+ } catch (NumberFormatException ex) {
+ Log.w(LOG_TAG, "error parsing RegistrationState: " + ex);
+ }
+ }
+
+ mCdmaRoaming = regCodeIsRoaming(this.mRegistrationState);
+ this.newCdmaDataConnectionState =
+ radioTechnologyToServiceState(responseValuesRegistrationState[0]);
+ newSS.setState (regCodeToServiceState(this.mRegistrationState));
+ newSS.setRadioTechnology(responseValuesRegistrationState[0]);
+ newSS.setCssIndicator(responseValuesRegistrationState[4]);
+ newSS.setSystemAndNetworkId(responseValuesRegistrationState[5],
+ responseValuesRegistrationState[6]);
+
+ newNetworkType = responseValuesRegistrationState[0];
+
+ // values are -1 if not available
+ newCellLoc.setCellLocationData(responseValuesRegistrationState[1],
+ responseValuesRegistrationState[2],
+ responseValuesRegistrationState[3]);
+ break;
+
+ case EVENT_POLL_STATE_OPERATOR_CDMA:
+ String opNames[] = (String[])ar.result;
+
+ if (opNames != null && opNames.length >= 4) {
+ newSS.setOperatorName (opNames[0], opNames[1], opNames[2]);
+ }
+ break;
+
+ case EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA:
+ ints = (int[])ar.result;
+ newSS.setIsManualSelection(ints[0] == 1);
+ break;
+ default:
+ Log.e(LOG_TAG, "RIL response handle in wrong phone!"
+ + " Expected CDMA RIL request and get GSM RIL request.");
+ break;
+ }
+
+ } catch (RuntimeException ex) {
+ Log.e(LOG_TAG, "Exception while polling service state. "
+ + "Probably malformed RIL response.", ex);
+ }
+
+ pollingContext[0]--;
+
+ if (pollingContext[0] == 0) {
+ newSS.setRoaming(isRoamingBetweenOperators(mCdmaRoaming, newSS));
+
+ switch(this.mRegistrationState) {
+ case ServiceState.REGISTRATION_STATE_HOME_NETWORK:
+ newSS.setExtendedCdmaRoaming(ServiceState.REGISTRATION_STATE_HOME_NETWORK);
+ break;
+ case ServiceState.REGISTRATION_STATE_ROAMING:
+ newSS.setExtendedCdmaRoaming(ServiceState.REGISTRATION_STATE_ROAMING);
+ break;
+ case ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE:
+ newSS.setExtendedCdmaRoaming(ServiceState.REGISTRATION_STATE_ROAMING_AFFILIATE);
+ break;
+ default:
+ Log.w(LOG_TAG, "Received a different registration state, "
+ + "but don't changed the extended cdma roaming mode.");
+ }
+ pollStateDone();
+ }
+
+ }
+
+ private void setRssiDefaultValues() {
+ rssi = 99;
+ }
+
+ /**
+ * A complete "service state" from our perspective is
+ * composed of a handful of separate requests to the radio.
+ *
+ * We make all of these requests at once, but then abandon them
+ * and start over again if the radio notifies us that some
+ * event has changed
+ */
+
+ private void
+ pollState() {
+ pollingContext = new int[1];
+ pollingContext[0] = 0;
+
+ switch (cm.getRadioState()) {
+ case RADIO_UNAVAILABLE:
+ newSS.setStateOutOfService();
+ newCellLoc.setStateInvalid();
+ setRssiDefaultValues();
+ mGotCountryCode = false;
+
+ pollStateDone();
+ break;
+
+ case RADIO_OFF:
+ newSS.setStateOff();
+ newCellLoc.setStateInvalid();
+ setRssiDefaultValues();
+ mGotCountryCode = false;
+
+ pollStateDone();
+ break;
+
+ case SIM_NOT_READY:
+ case SIM_LOCKED_OR_ABSENT:
+ case SIM_READY:
+ log("Radio Technology Change ongoing, setting SS to off");
+ newSS.setStateOff();
+ newCellLoc.setStateInvalid();
+ setRssiDefaultValues();
+ mGotCountryCode = false;
+
+ pollStateDone();
+ break;
+
+ default:
+ // Issue all poll-related commands at once
+ // then count down the responses, which
+ // are allowed to arrive out-of-order
+
+ pollingContext[0]++;
+ //RIL_REQUEST_OPERATOR is necessary for CDMA
+ cm.getOperator(
+ obtainMessage(EVENT_POLL_STATE_OPERATOR_CDMA, pollingContext));
+
+ pollingContext[0]++;
+ //RIL_REQUEST_REGISTRATION_STATE is necessary for CDMA
+ cm.getRegistrationState(
+ obtainMessage(EVENT_POLL_STATE_REGISTRATION_CDMA, pollingContext));
+
+ pollingContext[0]++;
+ //RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE necessary for CDMA
+ cm.getNetworkSelectionMode(
+ obtainMessage(EVENT_POLL_STATE_NETWORK_SELECTION_MODE_CDMA, pollingContext));
+ break;
+ }
+ }
+
+ private static String networkTypeToString(int type) {
+ String ret = "unknown";
+
+ switch (type) {
+ case DATA_ACCESS_CDMA_IS95A:
+ case DATA_ACCESS_CDMA_IS95B:
+ ret = "CDMA";
+ break;
+ case DATA_ACCESS_CDMA_1xRTT:
+ ret = "CDMA - 1xRTT";
+ break;
+ case DATA_ACCESS_CDMA_EvDo_0:
+ ret = "CDMA - EvDo rev. 0";
+ break;
+ case DATA_ACCESS_CDMA_EvDo_A:
+ ret = "CDMA - EvDo rev. A";
+ break;
+ default:
+ if (DBG) {
+ Log.e(LOG_TAG, "Wrong network. Can not return a string.");
+ }
+ break;
+ }
+
+ return ret;
+ }
+
+ private void
+ pollStateDone() {
+ if (DBG) {
+ Log.d(LOG_TAG, "Poll ServiceState done: " +
+ " oldSS=[" + ss );
+ Log.d(LOG_TAG, "Poll ServiceState done: " +
+ " newSS=[" + newSS);
+ }
+
+ boolean hasRegistered =
+ ss.getState() != ServiceState.STATE_IN_SERVICE
+ && newSS.getState() == ServiceState.STATE_IN_SERVICE;
+
+ boolean hasDeregistered =
+ ss.getState() == ServiceState.STATE_IN_SERVICE
+ && newSS.getState() != ServiceState.STATE_IN_SERVICE;
+
+ boolean hasCdmaDataConnectionAttached =
+ (this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT
+ && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0
+ && this.cdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A)
+ && (this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT
+ || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0
+ || this.newCdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A);
+
+ boolean hasCdmaDataConnectionDetached =
+ (this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_1xRTT
+ || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_0
+ || this.cdmaDataConnectionState == ServiceState.RADIO_TECHNOLOGY_EVDO_A)
+ && (this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_1xRTT
+ && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_0
+ && this.newCdmaDataConnectionState != ServiceState.RADIO_TECHNOLOGY_EVDO_A);
+
+ boolean hasCdmaDataConnectionChanged =
+ cdmaDataConnectionState != newCdmaDataConnectionState;
+
+ boolean hasNetworkTypeChanged = networkType != newNetworkType;
+
+ boolean hasChanged = !newSS.equals(ss);
+
+ boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming();
+
+ boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming();
+
+ boolean hasLocationChanged = !newCellLoc.equals(cellLoc);
+
+ ServiceState tss;
+ tss = ss;
+ ss = newSS;
+ newSS = tss;
+ // clean slate for next time
+ newSS.setStateOutOfService();
+
+ CdmaCellLocation tcl = cellLoc;
+ cellLoc = newCellLoc;
+ newCellLoc = tcl;
+
+ cdmaDataConnectionState = newCdmaDataConnectionState;
+ networkType = newNetworkType;
+
+ newSS.setStateOutOfService(); // clean slate for next time
+
+ if (hasNetworkTypeChanged) {
+ phone.setSystemProperty(PROPERTY_DATA_NETWORK_TYPE,
+ networkTypeToString(networkType));
+ }
+
+ if (hasRegistered) {
+ Checkin.updateStats(phone.getContext().getContentResolver(),
+ Checkin.Stats.Tag.PHONE_CDMA_REGISTERED, 1, 0.0);
+ networkAttachedRegistrants.notifyRegistrants();
+ }
+
+ if (hasChanged) {
+ String operatorNumeric;
+
+ phone.setSystemProperty(PROPERTY_OPERATOR_ALPHA,
+ ss.getOperatorAlphaLong());
+
+ operatorNumeric = ss.getOperatorNumeric();
+ phone.setSystemProperty(PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
+
+ if (operatorNumeric == null) {
+ phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, "");
+ } else {
+ String iso = "";
+ try{
+ iso = MccTable.countryCodeForMcc(Integer.parseInt(
+ operatorNumeric.substring(0,3)));
+ } catch ( NumberFormatException ex){
+ Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
+ } catch ( StringIndexOutOfBoundsException ex) {
+ Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
+ }
+
+ phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, iso);
+ mGotCountryCode = true;
+ }
+
+ phone.setSystemProperty(PROPERTY_OPERATOR_ISROAMING,
+ ss.getRoaming() ? "true" : "false");
+ phone.setSystemProperty(PROPERTY_OPERATOR_ISMANUAL,
+ ss.getIsManualSelection() ? "true" : "false");
+
+ updateSpnDisplay();
+ phone.notifyServiceStateChanged(ss);
+ }
+
+ if (hasCdmaDataConnectionAttached) {
+ cdmaDataConnectionAttachedRegistrants.notifyRegistrants();
+ }
+
+ if (hasCdmaDataConnectionDetached) {
+ cdmaDataConnectionDetachedRegistrants.notifyRegistrants();
+ }
+
+ if (hasCdmaDataConnectionChanged) {
+ phone.notifyDataConnection(null);
+ }
+
+ if (hasRoamingOn) {
+ roamingOnRegistrants.notifyRegistrants();
+ }
+
+ if (hasRoamingOff) {
+ roamingOffRegistrants.notifyRegistrants();
+ }
+
+ if (hasLocationChanged) {
+ phone.notifyLocationChanged();
+ }
+ }
+
+ /**
+ * Returns a TimeZone object based only on parameters from the NITZ string.
+ */
+ private TimeZone getNitzTimeZone(int offset, boolean dst, long when) {
+ TimeZone guess = findTimeZone(offset, dst, when);
+ if (guess == null) {
+ // Couldn't find a proper timezone. Perhaps the DST data is wrong.
+ guess = findTimeZone(offset, !dst, when);
+ }
+ if (DBG) {
+ Log.d(LOG_TAG, "getNitzTimeZone returning "
+ + (guess == null ? guess : guess.getID()));
+ }
+ return guess;
+ }
+
+ private TimeZone findTimeZone(int offset, boolean dst, long when) {
+ int rawOffset = offset;
+ if (dst) {
+ rawOffset -= 3600000;
+ }
+ String[] zones = TimeZone.getAvailableIDs(rawOffset);
+ TimeZone guess = null;
+ Date d = new Date(when);
+ for (String zone : zones) {
+ TimeZone tz = TimeZone.getTimeZone(zone);
+ if (tz.getOffset(when) == offset &&
+ tz.inDaylightTime(d) == dst) {
+ guess = tz;
+ break;
+ }
+ }
+
+ return guess;
+ }
+
+ private void
+ queueNextSignalStrengthPoll() {
+ if (dontPollSignalStrength || (cm.getRadioState().isGsm())) {
+ // The radio is telling us about signal strength changes
+ // we don't have to ask it
+ return;
+ }
+
+ Message msg;
+
+ msg = obtainMessage();
+ msg.what = EVENT_POLL_SIGNAL_STRENGTH;
+
+ // TODO Done't poll signal strength if screen is off
+ sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
+ }
+
+ /**
+ * send signal-strength-changed notification if rssi changed
+ * Called both for solicited and unsolicited signal stength updates
+ */
+ private void
+ onSignalStrengthResult(AsyncResult ar) {
+ int oldRSSI = rssi;
+
+ if (ar.exception != null) {
+ // 99 = unknown
+ // most likely radio is resetting/disconnected
+ rssi = 99;
+ } else {
+ int[] ints = (int[])ar.result;
+
+ // bug 658816 seems to be a case where the result is 0-length
+ if (ints.length != 0) {
+ rssi = ints[0];
+ } else {
+ Log.e(LOG_TAG, "Bogus signal strength response");
+ rssi = 99;
+ }
+ }
+
+ if (rssi != oldRSSI) {
+ try { // This takes care of delayed EVENT_POLL_SIGNAL_STRENGTH (scheduled after
+ // POLL_PERIOD_MILLIS) during Radio Technology Change)
+ phone.notifySignalStrength();
+ } catch (NullPointerException ex) {
+ log("onSignalStrengthResult() Phone already destroyed: " + ex
+ + "Signal Stranth not notified");
+ }
+ }
+ }
+
+
+ private int radioTechnologyToServiceState(int code) {
+ int retVal = ServiceState.RADIO_TECHNOLOGY_UNKNOWN;
+ switch(code) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ break;
+ case 6:
+ retVal = ServiceState.RADIO_TECHNOLOGY_1xRTT;
+ break;
+ case 7:
+ retVal = ServiceState.RADIO_TECHNOLOGY_EVDO_0;
+ break;
+ case 8:
+ retVal = ServiceState.RADIO_TECHNOLOGY_EVDO_A;
+ break;
+ default:
+ Log.e(LOG_TAG, "Wrong radioTechnology code.");
+ break;
+ }
+ return(retVal);
+ }
+
+ /** code is registration state 0-5 from TS 27.007 7.2 */
+ private int
+ regCodeToServiceState(int code) {
+ switch (code) {
+ case 0: // Not searching and not registered
+ return ServiceState.STATE_OUT_OF_SERVICE;
+ case 1:
+ return ServiceState.STATE_IN_SERVICE;
+ case 2: // 2 is "searching", fall through
+ case 3: // 3 is "registration denied", fall through
+ case 4: // 4 is "unknown" no vaild in current baseband
+ return ServiceState.STATE_OUT_OF_SERVICE;
+ case 5:// fall through
+ case 6:
+ // Registered and: roaming (5) or roaming affiliates (6)
+ return ServiceState.STATE_IN_SERVICE;
+
+ default:
+ Log.w(LOG_TAG, "unexpected service state " + code);
+ return ServiceState.STATE_OUT_OF_SERVICE;
+ }
+ }
+
+ /**
+ * @return The current CDMA data connection state. ServiceState.RADIO_TECHNOLOGY_1xRTT or
+ * ServiceState.RADIO_TECHNOLOGY_EVDO is the same as "attached" and
+ * ServiceState.RADIO_TECHNOLOGY_UNKNOWN is the same as detached.
+ */
+ /*package*/ int getCurrentCdmaDataConnectionState() {
+ return cdmaDataConnectionState;
+ }
+
+ /**
+ * code is registration state 0-5 from TS 27.007 7.2
+ * returns true if registered roam, false otherwise
+ */
+ private boolean
+ regCodeIsRoaming (int code) {
+ // 5 is "in service -- roam"
+ return 5 == code;
+ }
+
+ /**
+ * Set roaming state when cdmaRoaming is true and ons is different from spn
+ * @param cdmaRoaming TS 27.007 7.2 CREG registered roaming
+ * @param s ServiceState hold current ons
+ * @return true for roaming state set
+ */
+ private
+ boolean isRoamingBetweenOperators(boolean cdmaRoaming, ServiceState s) {
+ String spn = SystemProperties.get(PROPERTY_ICC_OPERATOR_ALPHA, "empty");
+
+ String onsl = s.getOperatorAlphaLong();
+ String onss = s.getOperatorAlphaShort();
+
+ boolean equalsOnsl = onsl != null && spn.equals(onsl);
+ boolean equalsOnss = onss != null && spn.equals(onss);
+
+ return cdmaRoaming && !(equalsOnsl || equalsOnss);
+ }
+
+ private boolean getAutoTime() {
+ try {
+ return Settings.System.getInt(phone.getContext().getContentResolver(),
+ Settings.System.AUTO_TIME) > 0;
+ } catch (SettingNotFoundException snfe) {
+ return true;
+ }
+ }
+
+ /**
+ * @return true if phone is camping on a technology
+ * that could support voice and data simultaneously.
+ */
+ boolean isConcurrentVoiceAndData() {
+
+ // Note: it needs to be confirmed which CDMA network types
+ // can support voice and data calls concurrently.
+ // For the time-being, the return value will be false.
+ return false;
+ }
+
+ protected void log(String s) {
+ Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s);
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java
new file mode 100644
index 0000000..65b7336
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/FeatureCode.java
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.cdma;
+
+import android.content.Context;
+import android.os.*;
+import android.util.Log;
+
+import com.android.internal.telephony.*;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ *
+ * {@hide}
+ *
+ */
+public final class FeatureCode extends Handler implements MmiCode {
+ static final String LOG_TAG = "CDMA";
+
+ //***** Constants
+
+ // Call Forwarding
+ static final String FC_CF_ACTIVATE = "72";
+ static final String FC_CF_DEACTIVATE = "73";
+ static final String FC_CF_FORWARD_TO_NUMBER = "56";
+
+ // Call Forwarding Busy Line
+ static final String FC_CFBL_ACTIVATE = "90";
+ static final String FC_CFBL_DEACTIVATE = "91";
+ static final String FC_CFBL_FORWARD_TO_NUMBER = "40";
+
+ // Call Forwarding Don't Answer
+ static final String FC_CFDA_ACTIVATE = "92";
+ static final String FC_CFDA_DEACTIVATE = "93";
+ static final String FC_CFDA_FORWARD_TO_NUMBER = "42";
+
+ // Cancel Call Waiting
+ static final String FC_CCW = "70";
+
+ // Usage Sensitive Three-way Calling
+ static final String FC_3WC = "71";
+
+ // Do Not Disturb
+ static final String FC_DND_ACTIVATE = "78";
+ static final String FC_DND_DEACTIVATE = "79";
+
+ // Who Called Me?
+ static final String FC_WHO = "51";
+
+ // Rejection of Undesired Annoying Calls
+ static final String FC_RUAC_ACTIVATE = "60";
+ static final String FC_RUAC_DEACTIVATE = "80";
+
+ // Calling Number Delivery
+ // Calling Number Identification Presentation
+ static final String FC_CNIP = "65";
+ // Calling Number Identification Restriction
+ static final String FC_CNIR = "85";
+
+
+ //***** Event Constants
+
+ static final int EVENT_SET_COMPLETE = 1;
+ static final int EVENT_CDMA_FLASH_COMPLETED = 2;
+
+
+ //***** Instance Variables
+
+ CDMAPhone phone;
+ Context context;
+
+ String action; // '*' in CDMA
+ String sc; // Service Code
+ String poundString; // Entire Flash string
+ String dialingNumber;
+
+ /** Set to true in processCode, not at newFromDialString time */
+
+ State state = State.PENDING;
+ CharSequence message;
+
+ //***** Class Variables
+
+
+ // Flash Code Pattern
+
+ static Pattern sPatternSuppService = Pattern.compile(
+ "((\\*)(\\d{2,3})(#?)([^*#]*)?)(.*)");
+/* 1 2 3 4 5 6
+
+ 1 = Full string up to and including #
+ 2 = action
+ 3 = service code
+ 4 = separator
+ 5 = dialing number
+*/
+
+ static final int MATCH_GROUP_POUND_STRING = 1;
+ static final int MATCH_GROUP_ACTION_STRING = 2;
+ static final int MATCH_GROUP_SERVICE_CODE = 3;
+ static final int MATCH_GROUP_DIALING_NUMBER = 5;
+
+
+ //***** Public Class methods
+
+ /**
+ * Some dial strings in CDMA are defined to do non-call setup
+ * things, such as set supplementary service settings (eg, call
+ * forwarding). These are generally referred to as "Feature Codes".
+ * We look to see if the dial string contains a valid Feature code (potentially
+ * with a dial string at the end as well) and return info here.
+ *
+ * If the dial string contains no Feature code, we return an instance with
+ * only "dialingNumber" set
+ *
+ * Please see also S.R0006-000-A v2.0 "Wireless Features Description"
+ */
+
+ static FeatureCode newFromDialString(String dialString, CDMAPhone phone) {
+ Matcher m;
+ FeatureCode ret = null;
+
+ m = sPatternSuppService.matcher(dialString);
+
+ // Is this formatted like a standard supplementary service code?
+ if (m.matches()) {
+ ret = new FeatureCode(phone);
+ ret.poundString = makeEmptyNull(m.group(MATCH_GROUP_POUND_STRING));
+ ret.action = makeEmptyNull(m.group(MATCH_GROUP_ACTION_STRING));
+ ret.sc = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE));
+ ret.dialingNumber = makeEmptyNull(m.group(MATCH_GROUP_DIALING_NUMBER));
+ }
+
+ return ret;
+ }
+
+ //***** Private Class methods
+
+ /** make empty strings be null.
+ * Java regexp returns empty strings for empty groups
+ */
+ private static String makeEmptyNull (String s) {
+ if (s != null && s.length() == 0) return null;
+
+ return s;
+ }
+
+ /** returns true of the string is empty or null */
+ private static boolean isEmptyOrNull(CharSequence s) {
+ return s == null || (s.length() == 0);
+ }
+
+ static boolean isServiceCodeCallForwarding(String sc) {
+ return sc != null &&
+ (sc.equals(FC_CF_ACTIVATE)
+ || sc.equals(FC_CF_DEACTIVATE) || sc.equals(FC_CF_FORWARD_TO_NUMBER)
+ || sc.equals(FC_CFBL_ACTIVATE) || sc.equals(FC_CFBL_DEACTIVATE)
+ || sc.equals(FC_CFBL_FORWARD_TO_NUMBER) || sc.equals(FC_CFDA_ACTIVATE)
+ || sc.equals(FC_CFDA_DEACTIVATE) || sc.equals(FC_CFDA_FORWARD_TO_NUMBER));
+ }
+
+ static boolean isServiceCodeCallWaiting(String sc) {
+ return sc != null && sc.equals(FC_CCW);
+ }
+
+ static boolean isServiceCodeThreeWayCalling(String sc) {
+ return sc != null && sc.equals(FC_3WC);
+ }
+
+ static boolean isServiceCodeAnnoyingCalls(String sc) {
+ return sc != null &&
+ (sc.equals(FC_RUAC_ACTIVATE)
+ || sc.equals(FC_RUAC_DEACTIVATE));
+ }
+
+ static boolean isServiceCodeCallingNumberDelivery(String sc) {
+ return sc != null &&
+ (sc.equals(FC_CNIP)
+ || sc.equals(FC_CNIR));
+ }
+
+ static boolean isServiceCodeDoNotDisturb(String sc) {
+ return sc != null &&
+ (sc.equals(FC_DND_ACTIVATE)
+ || sc.equals(FC_DND_DEACTIVATE));
+ }
+
+
+ //***** Constructor
+
+ FeatureCode (CDMAPhone phone) {
+ super(phone.getHandler().getLooper());
+ this.phone = phone;
+ this.context = phone.getContext();
+ }
+
+
+ //***** MmiCode implementation
+
+ public State getState() {
+ return state;
+ }
+
+ public CharSequence getMessage() {
+ return message;
+ }
+
+ // inherited javadoc suffices
+ public void cancel() {
+ //Not used here
+ }
+
+ public boolean isCancelable() {
+ Log.e(LOG_TAG, "isCancelable: not used in CDMA");
+ return false;
+ }
+
+ public boolean isUssdRequest() {
+ Log.e(LOG_TAG, "isUssdRequest: not used in CDMA");
+ return false;
+ }
+
+ /** Process a Flash Code...anything that isn't a dialing number */
+ void processCode () {
+ Log.d(LOG_TAG, "send feature code...");
+ phone.mCM.sendCDMAFeatureCode(this.poundString,
+ obtainMessage(EVENT_CDMA_FLASH_COMPLETED));
+ }
+
+ /** Called from CDMAPhone.handleMessage; not a Handler subclass */
+ public void handleMessage (Message msg) {
+ AsyncResult ar;
+
+ switch (msg.what) {
+ case EVENT_SET_COMPLETE:
+ ar = (AsyncResult) (msg.obj);
+ onSetComplete(ar);
+ break;
+ case EVENT_CDMA_FLASH_COMPLETED:
+ ar = (AsyncResult) (msg.obj);
+
+ if (ar.exception != null) {
+ state = State.FAILED;
+ message = context.getText(com.android.internal.R.string.mmiError);
+ } else {
+ state = State.COMPLETE;
+ message = context.getText(com.android.internal.R.string.mmiComplete);
+ }
+ phone.onMMIDone(this);
+ break;
+ }
+ }
+
+
+ //***** Private instance methods
+
+ private CharSequence getScString() {
+ if (sc != null) {
+ if (isServiceCodeCallForwarding(sc)) {
+ return context.getText(com.android.internal.R.string.CfMmi);
+ } else if (isServiceCodeCallWaiting(sc)) {
+ return context.getText(com.android.internal.R.string.CwMmi);
+ } else if (sc.equals(FC_CNIP)) {
+ return context.getText(com.android.internal.R.string.CnipMmi);
+ } else if (sc.equals(FC_CNIR)) {
+ return context.getText(com.android.internal.R.string.CnirMmi);
+ } else if (isServiceCodeThreeWayCalling(sc)) {
+ return context.getText(com.android.internal.R.string.ThreeWCMmi);
+ } else if (isServiceCodeAnnoyingCalls(sc)) {
+ return context.getText(com.android.internal.R.string.RuacMmi);
+ } else if (isServiceCodeCallingNumberDelivery(sc)) {
+ return context.getText(com.android.internal.R.string.CndMmi);
+ } else if (isServiceCodeDoNotDisturb(sc)) {
+ return context.getText(com.android.internal.R.string.DndMmi);
+ }
+ }
+
+ return "";
+ }
+
+ private void onSetComplete(AsyncResult ar){
+ StringBuilder sb = new StringBuilder(getScString());
+ sb.append("\n");
+
+ if (ar.exception != null) {
+ state = State.FAILED;
+ sb.append(context.getText(com.android.internal.R.string.mmiError));
+ } else {
+ state = State.FAILED;
+ sb.append(context.getText(com.android.internal.R.string.mmiError));
+ }
+
+ message = sb;
+ phone.onMMIDone(this);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimCard.java b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
new file mode 100644
index 0000000..9d9f479
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimCard.java
@@ -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);
+ }
+}
+
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
new file mode 100644
index 0000000..7d392f0
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimFileHandler.java
@@ -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);
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
new file mode 100644
index 0000000..78e89d5
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimPhoneBookInterfaceManager.java
@@ -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);
+ }
+}
+
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
new file mode 100644
index 0000000..7776f8b
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -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);
+ }
+
+}
+
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
new file mode 100644
index 0000000..9439359
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimSmsInterfaceManager.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.internal.telephony.cdma;
+
+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 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)
+ buildValidRawData((ArrayList) 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 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);
+ }
+}
+
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
new file mode 100644
index 0000000..e4b474a
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -0,0 +1,905 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.cdma;
+
+import android.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 SubmitPdu
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 SubmitPdu
containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, String message,
+ boolean statusReportRequested) {
+ return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null);
+ }
+
+ /**
+ * Get an SMS-SUBMIT PDU for a data message to a destination address & port
+ *
+ * @param scAddress Service Centre address. null == use default
+ * @param destinationAddress the address of the destination for the message
+ * @param destinationPort the port to deliver the message to at the
+ * destination
+ * @param data the data for the message
+ * @return a SubmitPdu
containing the encoded SC
+ * address, if applicable, and the encoded message.
+ * Returns null on encode error.
+ */
+ public static SubmitPdu getSubmitPdu(String scAddress,
+ String destinationAddress, short destinationPort, byte[] data,
+ boolean statusReportRequested) {
+
+ SmsMessage sms = new SmsMessage();
+ SubmitPdu ret = new SubmitPdu();
+ UserData uData = new UserData();
+ SmsHeader smsHeader = new SmsHeader();
+
+ if (data.length > (MAX_USER_DATA_BYTES - 7 /* UDH size */)) {
+ Log.e(LOG_TAG, "SMS data message may only contain "
+ + (MAX_USER_DATA_BYTES - 7) + " bytes");
+ return null;
+ }
+
+ byte[] destPort = new byte[4];
+ destPort[0] = (byte) ((destinationPort >> 8) & 0xFF); // MSB of destination port
+ destPort[1] = (byte) (destinationPort & 0xFF); // LSB of destination port
+ destPort[2] = 0x00; // MSB of originating port
+ destPort[3] = 0x00; // LSB of originating port
+ smsHeader.add(
+ new SmsHeader.Element(SmsHeader.APPLICATION_PORT_ADDRESSING_16_BIT, destPort));
+
+ smsHeader.nbrOfHeaders = smsHeader.getElements().size();
+ uData.userDataHeader = smsHeader;
+
+ // TP-Data-Coding-Scheme
+ // No class, 8 bit data
+ uData.userDataEncoding = UserData.UD_ENCODING_OCTET;
+ uData.userData = data;
+
+ byte[] msgData = sms.getEnvelope(destinationAddress, statusReportRequested, uData,
+ true, true);
+
+ ret.encodedMessage = msgData;
+ ret.encodedScAddress = null;
+ return ret;
+ }
+
+ static class PduParser {
+
+ PduParser() {
+ }
+
+ /**
+ * Parses an SC timestamp and returns a currentTimeMillis()-style
+ * timestamp
+ */
+ static long getSCTimestampMillis(byte[] timestamp) {
+ // TP-Service-Centre-Time-Stamp
+ int year = IccUtils.beBcdByteToInt(timestamp[0]);
+ int month = IccUtils.beBcdByteToInt(timestamp[1]);
+ int day = IccUtils.beBcdByteToInt(timestamp[2]);
+ int hour = IccUtils.beBcdByteToInt(timestamp[3]);
+ int minute = IccUtils.beBcdByteToInt(timestamp[4]);
+ int second = IccUtils.beBcdByteToInt(timestamp[5]);
+
+ Time time = new Time(Time.TIMEZONE_UTC);
+
+ // C.S0015-B v2.0, 4.5.4: range is 1996-2095
+ time.year = year >= 96 ? year + 1900 : year + 2000;
+ time.month = month - 1;
+ time.monthDay = day;
+ time.hour = hour;
+ time.minute = minute;
+ time.second = second;
+
+ return time.toMillis(true);
+ }
+
+ }
+
+ /**
+ * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
+ */
+ public int getProtocolIdentifier() {
+ Log.w(LOG_TAG, "getProtocolIdentifier: is not supported in CDMA mode.");
+ // (3GPP TS 23.040): "no interworking, but SME to SME protocol":
+ return 0;
+ }
+
+ /**
+ * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
+ */
+ public boolean isReplace() {
+ Log.w(LOG_TAG, "isReplace: is not supported in CDMA mode.");
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
+ */
+ public boolean isCphsMwiMessage() {
+ Log.w(LOG_TAG, "isCphsMwiMessage: is not supported in CDMA mode.");
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isMWIClearMessage() {
+ if ((mBearerData != null) && (0 == mBearerData.numberOfMessages)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isMWISetMessage() {
+ if ((mBearerData != null) && (mBearerData.numberOfMessages >0)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isMwiDontStore() {
+ if ((mBearerData != null) && (mBearerData.numberOfMessages >0)
+ && (null == mBearerData.userData)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the status for a previously submitted message.
+ * For not interfering with status codes from GSM, this status code is
+ * shifted to the bits 31-16.
+ */
+ public int getStatus() {
+ return(status<<16);
+ }
+
+ /**
+ * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
+ */
+ public boolean isStatusReportMessage() {
+ Log.w(LOG_TAG, "isStatusReportMessage: is not supported in CDMA mode.");
+ return false;
+ }
+
+ /**
+ * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
+ */
+ public boolean isReplyPathPresent() {
+ Log.w(LOG_TAG, "isReplyPathPresent: is not supported in CDMA mode.");
+ return false;
+ }
+
+ /**
+ * Returns the teleservice type of the message.
+ * @return the teleservice:
+ * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET},
+ * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WMT},
+ * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WEMT},
+ * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN},
+ * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP}
+ */
+ public int getTeleService() {
+ return mEnvelope.teleService;
+ }
+
+ /**
+ * Decodes pdu to an empty SMS object.
+ * In the CDMA case the pdu is just an internal byte stream representation
+ * of the SMS Java-object.
+ * @see #createPdu()
+ */
+ private void parsePdu(byte[] pdu) {
+ ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
+ DataInputStream dis = new DataInputStream(new BufferedInputStream(bais));
+ byte length;
+ SmsEnvelope env = new SmsEnvelope();
+ CdmaSmsAddress addr = new CdmaSmsAddress();
+
+ try {
+ env.messageType = dis.readInt();
+ env.teleService = dis.readInt();
+ env.serviceCategory = dis.readInt();
+
+ addr.digitMode = dis.readByte();
+ addr.numberMode = dis.readByte();
+ addr.ton = dis.readByte();
+ addr.numberPlan = dis.readByte();
+
+ length = dis.readByte();
+ addr.numberOfDigits = length;
+ addr.origBytes = new byte[length];
+ dis.read(addr.origBytes, 0, length); // digits
+
+ env.bearerReply = dis.readInt();
+ // CauseCode values:
+ env.replySeqNo = dis.readByte();
+ env.errorClass = dis.readByte();
+ env.causeCode = dis.readByte();
+
+ //encoded BearerData:
+ length = dis.readByte();
+ env.bearerData = new byte[length];
+ dis.read(env.bearerData, 0, length);
+ dis.close();
+ } catch (Exception ex) {
+ Log.e(LOG_TAG, "createFromPdu: conversion from byte array to object failed: " + ex);
+ }
+
+ // link the filled objects to this SMS
+ originatingAddress = addr;
+ env.origAddress = addr;
+ mEnvelope = env;
+
+ parseSms();
+ }
+
+ /**
+ * Parses a SMS message from its BearerData stream. (mobile-terminated only)
+ */
+ protected void parseSms() {
+ mBearerData = SmsDataCoding.decodeCdmaSms(mEnvelope.bearerData);
+ messageRef = mBearerData.messageID;
+
+ // TP-Message-Type-Indicator
+ // (See 3GPP2 C.S0015-B, v2, 4.5.1)
+ int messageType = mBearerData.messageType;
+
+ switch (messageType) {
+ case MESSAGE_TYPE_USER_ACK:
+ case MESSAGE_TYPE_READ_ACK:
+ case MESSAGE_TYPE_DELIVER:
+ // Deliver (mobile-terminated only)
+ parseSmsDeliver();
+ break;
+ case MESSAGE_TYPE_DELIVERY_ACK:
+ parseSmsDeliveryAck();
+ break;
+
+ default:
+ // the rest of these
+ throw new RuntimeException("Unsupported message type: " + messageType);
+ }
+ }
+
+ /**
+ * Parses a SMS-DELIVER message. (mobile-terminated only)
+ * See 3GPP2 C.S0015-B, v2, 4.4.1
+ */
+ private void parseSmsDeliver() {
+ if (originatingAddress != null) {
+ originatingAddress.address = new String(originatingAddress.origBytes);
+ if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: "
+ + originatingAddress.address);
+ }
+
+ if (mBearerData.timeStamp != null) {
+ scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp);
+ }
+
+ if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis);
+
+ parseUserData(mBearerData.userData);
+ }
+
+ /**
+ * Parses a SMS-DELIVER message. (mobile-terminated only)
+ * See 3GPP2 C.S0015-B, v2, 4.4.1
+ */
+ private void parseSmsDeliveryAck() {
+ if (originatingAddress != null) {
+ originatingAddress.address = new String(originatingAddress.origBytes);
+ if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: "
+ + originatingAddress.address);
+ }
+
+ if (mBearerData.timeStamp != null) {
+ scTimeMillis = PduParser.getSCTimestampMillis(mBearerData.timeStamp);
+ }
+
+ if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis);
+
+ if (mBearerData.errorClass != BearerData.ERROR_UNDEFINED) {
+ status = mBearerData.errorClass << 8;
+ status |= mBearerData.messageStatus;
+ }
+
+ parseUserData(mBearerData.userData);
+
+ }
+
+ /**
+ * Parses the User Data of an SMS.
+ */
+ private void parseUserData(UserData uData) {
+ int encodingType;
+
+ if (null == uData) {
+ return;
+ }
+
+ encodingType = uData.userDataEncoding;
+
+ // insert DCS-decoding here when type is supported by ril-library
+
+ userData = uData.userData;
+ userDataHeader = uData.userDataHeader;
+
+ switch (encodingType) {
+ case UD_ENCODING_GSM_7BIT_ALPHABET:
+ case UD_ENCODING_UNICODE_16:
+ // user data was already decoded by wmsts-library
+ messageBody = new String(userData);
+ break;
+
+ // data and unsupported encodings:
+ case UD_ENCODING_OCTET:
+ default:
+ messageBody = null;
+ break;
+ }
+
+ if (Config.LOGV) Log.v(LOG_TAG, "SMS message body (raw): '" + messageBody + "'");
+
+ if (messageBody != null) {
+ parseMessageBody();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public MessageClass getMessageClass() {
+ if (BearerData.DISPLAY_IMMEDIATE == mBearerData.displayMode ) {
+ return MessageClass.CLASS_0;
+ } else {
+ return MessageClass.UNKNOWN;
+ }
+ }
+
+ /**
+ * Creates BearerData and Envelope from parameters for a Submit SMS.
+ * @return byte stream for SubmitPdu.
+ */
+ private byte[] getEnvelope(String destinationAddress, boolean statusReportRequested,
+ UserData userData, boolean hasHeaders, boolean useNewId) {
+
+ BearerData mBearerData = new BearerData();
+ SmsEnvelope env = new SmsEnvelope();
+ CdmaSmsAddress mSmsAddress = new CdmaSmsAddress();
+
+ // ** set SmsAddress **
+ mSmsAddress.digitMode = CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR;
+ try {
+ mSmsAddress.origBytes = destinationAddress.getBytes("UTF-8");
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "doGetSubmitPdu: conversion of destinationAddress from string to byte[]"
+ + " failed: " + e.getMessage());
+ return null;
+ }
+ mSmsAddress.numberOfDigits = (byte)mSmsAddress.origBytes.length;
+ mSmsAddress.numberMode = CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK;
+ // see C.S0015-B, v2.0, 3.4.3.3
+ mSmsAddress.numberPlan = CdmaSmsAddress.NUMBERING_PLAN_ISDN_TELEPHONY;
+ mSmsAddress.ton = CdmaSmsAddress.TON_INTERNATIONAL_OR_IP;
+
+ // ** set BearerData **
+ mBearerData.userData = userData;
+ mBearerData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
+
+ if (useNewId) {
+ setNextMessageId();
+ }
+ mBearerData.messageID = nextMessageId;
+
+ // Set the reply options (See C.S0015-B, v2.0, 4.5.11)
+ if(statusReportRequested) {
+ mBearerData.deliveryAckReq = true;
+ } else {
+ mBearerData.deliveryAckReq = false;
+ }
+ // Currently settings applications do not support this
+ mBearerData.userAckReq = false;
+ mBearerData.readAckReq = false;
+ mBearerData.reportReq = false;
+
+ // Set the display mode (See C.S0015-B, v2.0, 4.5.16)
+ mBearerData.displayMode = BearerData.DISPLAY_DEFAULT;
+
+ // number of messages: not needed for encoding!
+
+ // indicate whether a user data header is available
+ mBearerData.hasUserDataHeader = hasHeaders;
+
+ // ** encode BearerData **
+ byte[] encodedBearerData = null;
+ try {
+ encodedBearerData = SmsDataCoding.encodeCdmaSms(mBearerData);
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "doGetSubmitPdu: EncodeCdmaSMS function in JNI interface failed: "
+ + e.getMessage());
+ return null;
+ }
+
+ // ** SmsEnvelope **
+ env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
+ env.teleService = SmsEnvelope.TELESERVICE_WEMT;
+ env.destAddress = mSmsAddress;
+ env.bearerReply = RETURN_ACK;
+ env.bearerData = encodedBearerData;
+ mEnvelope = env;
+
+ // get byte array output stream from SmsAddress object and SmsEnvelope member.
+ return serialize(mSmsAddress);
+ }
+
+ /**
+ * Set the nextMessageId to a random value between 0 and 65536
+ * See C.S0015-B, v2.0, 4.3.1.5
+ */
+ private void setNextMessageId() {
+ // Message ID, modulo 65536
+ if(firstSMS) {
+ Random generator = new Random();
+ nextMessageId = generator.nextInt(65536);
+ firstSMS = false;
+ } else {
+ nextMessageId = ++nextMessageId & 0xFFFF;
+ }
+ }
+
+ /**
+ * Creates ByteArrayOutputStream from CdmaSmsAddress and SmsEnvelope objects
+ *
+ * @param address CdmaSmsAddress object
+ * @return ByteArrayOutputStream
+ */
+ private byte[] serialize(CdmaSmsAddress destAddress) {
+ SmsEnvelope env = mEnvelope;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
+ DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
+
+ try {
+ dos.writeInt(env.teleService);
+ dos.writeInt(0); //servicePresent
+ dos.writeInt(0); //serviceCategory
+ dos.write(destAddress.digitMode);
+ dos.write(destAddress.numberMode);
+ dos.write(destAddress.ton); // number_type
+ dos.write(destAddress.numberPlan);
+ dos.write(destAddress.numberOfDigits);
+ dos.write(destAddress.origBytes, 0, destAddress.origBytes.length); // digits
+ // Subaddress is not supported.
+ dos.write(0); //subaddressType
+ dos.write(0); //subaddr_odd
+ dos.write(0); //subaddr_nbr_of_digits
+ dos.write(env.bearerData.length);
+ dos.write(env.bearerData, 0, env.bearerData.length);
+ dos.close();
+ return baos.toByteArray();
+ } catch(IOException ex) {
+ Log.e(LOG_TAG, "serialize: conversion from object to data output stream failed: " + ex);
+ return null;
+ }
+ }
+
+ /**
+ * Creates byte array (pseudo pdu) from SMS object.
+ * Note: Do not call this method more than once per object!
+ */
+ private void createPdu() {
+ SmsEnvelope env = mEnvelope;
+ CdmaSmsAddress addr = env.origAddress;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
+ DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
+
+ try {
+ dos.writeInt(env.messageType);
+ dos.writeInt(env.teleService);
+ dos.writeInt(env.serviceCategory);
+
+ dos.writeByte(addr.digitMode);
+ dos.writeByte(addr.numberMode);
+ dos.writeByte(addr.ton);
+ dos.writeByte(addr.numberPlan);
+ dos.writeByte(addr.numberOfDigits);
+ dos.write(addr.origBytes, 0, addr.origBytes.length); // digits
+
+ dos.writeInt(env.bearerReply);
+ // CauseCode values:
+ dos.writeByte(env.replySeqNo);
+ dos.writeByte(env.errorClass);
+ dos.writeByte(env.causeCode);
+ //encoded BearerData:
+ dos.writeByte(env.bearerData.length);
+ dos.write(env.bearerData, 0, env.bearerData.length);
+ dos.close();
+
+ mPdu = baos.toByteArray();
+ } catch (IOException ex) {
+ Log.e(LOG_TAG, "createPdu: conversion from object to byte array failed: " + ex);
+ }
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java b/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java
new file mode 100644
index 0000000..f27f79c
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/TtyIntent.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.cdma;
+
+public class TtyIntent {
+
+ private static final String TAG = "TtyIntent";
+
+
+ /** Event for TTY mode change */
+
+ /**
+ * Broadcast intent action indicating that the TTY has either been
+ * enabled or disabled. An intent extra provides this state as a boolean,
+ * where {@code true} means enabled.
+ * @see #TTY_ENABLED
+ *
+ * {@hide}
+ */
+ public static final String TTY_ENABLED_CHANGE_ACTION =
+ "com.android.internal.telephony.cdma.intent.action.TTY_ENABLED_CHANGE";
+
+ /**
+ * The lookup key for a boolean that indicates whether TTY mode is enabled or
+ * disabled. {@code true} means TTY mode is enabled. Retrieve it with
+ * {@link android.content.Intent#getBooleanExtra(String,boolean)}.
+ *
+ * {@hide}
+ */
+ public static final String TTY_ENABLED = "ttyEnabled";
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/package.html b/telephony/java/com/android/internal/telephony/cdma/package.html
new file mode 100644
index 0000000..cf1ad4a
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/package.html
@@ -0,0 +1,6 @@
+
+
+Provides classes to control or read data from CDMA phones.
+@hide
+
+
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
new file mode 100644
index 0000000..fec9529
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.cdma.sms;
+
+public final class BearerData{
+
+ // For completeness the following fields are listed, though not used yet.
+ /**
+ * Supported priority modes for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1)
+ */
+ //public static final int PRIORITY_NORMAL = 0x0;
+ //public static final int PRIORITY_INTERACTIVE = 0x1;
+ //public static final int PRIORITY_URGENT = 0x2;
+ //public static final int PRIORITY_EMERGENCY = 0x3;
+
+ /**
+ * Supported privacy modes for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.10-1)
+ */
+ //public static final int PRIVACY_NOT_RESTRICTED = 0x0;
+ //public static final int PRIVACY_RESTRICTED = 0x1;
+ //public static final int PRIVACY_CONFIDENTIAL = 0x2;
+ //public static final int PRIVACY_SECRET = 0x3;
+
+ /**
+ * Supported alert modes for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.13-1)
+ */
+ //public static final int ALERT_DEFAULT = 0x0;
+ //public static final int ALERT_LOW_PRIO = 0x1;
+ //public static final int ALERT_MEDIUM_PRIO = 0x2;
+ //public static final int ALERT_HIGH_PRIO = 0x3;
+
+ /**
+ * Supported display modes for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.16-1)
+ */
+ public static final int DISPLAY_IMMEDIATE = 0x0;
+ public static final int DISPLAY_DEFAULT = 0x1;
+ public static final int DISPLAY_USER = 0x2;
+
+ /**
+ * Supported message types for CDMA SMS messages
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1)
+ */
+ public static final int MESSAGE_TYPE_DELIVER = 0x01;
+ public static final int MESSAGE_TYPE_SUBMIT = 0x02;
+ public static final int MESSAGE_TYPE_CANCELLATION = 0x03;
+ public static final int MESSAGE_TYPE_DELIVERY_ACK = 0x04;
+ public static final int MESSAGE_TYPE_USER_ACK = 0x05;
+ public static final int MESSAGE_TYPE_READ_ACK = 0x06;
+ public static final int MESSAGE_TYPE_DELIVER_REPORT = 0x07;
+ public static final int MESSAGE_TYPE_SUBMIT_REPORT = 0x08;
+
+ /**
+ * SMS Message Status Codes
+ * (See 3GPP2 C.S0015-B, v2.0, table 4.5.21-1)
+ */
+ /* no-error codes */
+ public static final int ERROR_NONE = 0x00;
+ public static final int STATUS_ACCEPTED = 0x00;
+ public static final int STATUS_DEPOSITED_TO_INTERNET = 0x01;
+ public static final int STATUS_DELIVERED = 0x02;
+ public static final int STATUS_CANCELLED = 0x03;
+ /* temporary-error and permanent-error codes */
+ public static final int ERROR_TEMPORARY = 0x02;
+ public static final int STATUS_NETWORK_CONGESTION = 0x04;
+ public static final int STATUS_NETWORK_ERROR = 0x05;
+ public static final int STATUS_UNKNOWN_ERROR = 0x1F;
+ /* permanent-error codes */
+ public static final int ERROR_PERMANENT = 0x03;
+ public static final int STATUS_CANCEL_FAILED = 0x06;
+ public static final int STATUS_BLOCKED_DESTINATION = 0x07;
+ public static final int STATUS_TEXT_TOO_LONG = 0x08;
+ public static final int STATUS_DUPLICATE_MESSAGE = 0x09;
+ public static final int STATUS_INVALID_DESTINATION = 0x0A;
+ public static final int STATUS_MESSAGE_EXPIRED = 0x0D;
+ /* undefined-status codes */
+ public static final int ERROR_UNDEFINED = 0xFF;
+ public static final int STATUS_UNDEFINED = 0xFF;
+
+ /** Bit-mask indicating used fields for SmsDataCoding */
+ public int mask;
+
+ /**
+ * 4-bit value indicating the message type in accordance to
+ * table 4.5.1-1
+ * (See 3GPP2 C.S0015-B, v2, 4.5.1)
+ */
+ public byte messageType;
+
+ /**
+ * 16-bit value indicating the message ID, which increments modulo 65536.
+ * (Special rules apply for WAP-messages.)
+ * (See 3GPP2 C.S0015-B, v2, 4.5.1)
+ */
+ public int messageID;
+
+ /**
+ * 1-bit value that indicates whether a User Data Header is present.
+ * (See 3GPP2 C.S0015-B, v2, 4.5.1)
+ */
+ public boolean hasUserDataHeader;
+
+ /**
+ * provides the information for the user data
+ * (e.g. padding bits, user data, user data header, etc)
+ * (See 3GPP2 C.S.0015-B, v2, 4.5.2)
+ */
+ public UserData userData;
+
+ //public UserResponseCode userResponseCode;
+
+ /**
+ * 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4
+ * year, month, day, hours, minutes, seconds;
+ */
+ public byte[] timeStamp;
+
+ //public SmsTime validityPeriodAbsolute;
+ //public SmsRelTime validityPeriodRelative;
+ //public SmsTime deferredDeliveryTimeAbsolute;
+ //public SmsRelTime deferredDeliveryTimeRelative;
+ //public byte priority;
+ //public byte privacy;
+
+ /**
+ * Reply Option
+ * 1-bit values which indicate whether SMS acknowledgment is requested or not.
+ * (See 3GPP2 C.S0015-B, v2, 4.5.11)
+ */
+ public boolean userAckReq;
+ public boolean deliveryAckReq;
+ public boolean readAckReq;
+ public boolean reportReq;
+
+ /**
+ * The number of Messages element (8-bit value) is a decimal number in the 0 to 99 range
+ * representing the number of messages stored at the Voice Mail System. This element is
+ * used by the Voice Mail Notification service.
+ * (See 3GPP2 C.S0015-B, v2, 4.5.12)
+ */
+ public int numberOfMessages;
+
+ //public int alert;
+ //public int language;
+
+ /**
+ * 4-bit or 8-bit value that indicates the number to be dialed in reply to a
+ * received SMS message.
+ * (See 3GPP2 C.S0015-B, v2, 4.5.15)
+ */
+ public CdmaSmsAddress callbackNumber;
+
+ /**
+ * 2-bit value that is used to indicate to the mobile station when to display
+ * the received message.
+ * (See 3GPP2 C.S0015-B, v2, 4.5.16)
+ */
+ public byte displayMode = DISPLAY_DEFAULT;
+
+ /**
+ * First component of the Message status, that indicates if an error has occurred
+ * and whether the error is considered permanent or temporary.
+ * (See 3GPP2 C.S0015-B, v2, 4.5.21)
+ */
+ public int errorClass = ERROR_UNDEFINED;
+
+ /**
+ * Second component of the Message status, that indicates if an error has occurred
+ * and the cause of the error.
+ * (See 3GPP2 C.S0015-B, v2, 4.5.21)
+ */
+ public int messageStatus = STATUS_UNDEFINED;
+
+}
+
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
new file mode 100644
index 0000000..1643cab
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.cdma.sms;
+
+import com.android.internal.telephony.SmsAddress;
+
+public class CdmaSmsAddress extends SmsAddress {
+ /**
+ * digit mode indicators
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+ */
+ static public final int DIGIT_MODE_4BIT_DTMF = 0x00;
+ static public final int DIGIT_MODE_8BIT_CHAR = 0x01;
+
+ /**
+ * number mode indicators
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+ */
+ static public final int NUMBER_MODE_NOT_DATA_NETWORK = 0x00;
+ static public final int NUMBER_MODE_DATA_NETWORK = 0x01;
+
+ /**
+ * number types for data networks
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+ */
+ static public final int TON_UNKNOWN = 0x00;
+ static public final int TON_INTERNATIONAL_OR_IP = 0x01;
+ static public final int TON_NATIONAL_OR_EMAIL = 0x02;
+ static public final int TON_NETWORK = 0x03;
+ static public final int TON_SUBSCRIBER = 0x04;
+ static public final int TON_ALPHANUMERIC = 0x05;
+ static public final int TON_ABBREVIATED = 0x06;
+ static public final int TON_RESERVED = 0x07;
+
+ /**
+ * maximum lengths for fields as defined in ril_cdma_sms.h
+ */
+ static public final int SMS_ADDRESS_MAX = 36;
+ static public final int SMS_SUBADDRESS_MAX = 36;
+
+ /**
+ * Supported numbering plan identification
+ * (See C.S005-D, v1.0, table 2.7.1.3.2.4-3)
+ */
+ static public final int NUMBERING_PLAN_UNKNOWN = 0x0;
+ static public final int NUMBERING_PLAN_ISDN_TELEPHONY = 0x1;
+ //static protected final int NUMBERING_PLAN_DATA = 0x3;
+ //static protected final int NUMBERING_PLAN_TELEX = 0x4;
+ //static protected final int NUMBERING_PLAN_PRIVATE = 0x9;
+
+ /**
+ * 1-bit value that indicates whether the address digits are 4-bit DTMF codes
+ * or 8-bit codes.
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+ */
+ public byte digitMode;
+
+ /**
+ * 1-bit value that indicates whether the address type is a data network address or not.
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+ */
+ public byte numberMode;
+
+ // use parent class member ton instead public byte numberType;
+
+ /**
+ * 0 or 4-bit value that indicates which numbering plan identification is set.
+ * (See 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3)
+ */
+ public byte numberPlan;
+
+ /**
+ * This field shall be set to the number of address digits
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
+ */
+ public byte numberOfDigits;
+
+ // use parent class member orig_bytes instead of public byte[] digits;
+
+ // Constructor
+ public CdmaSmsAddress(){
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java
new file mode 100644
index 0000000..6ba7463
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsDataCoding.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.cdma.sms;
+
+import com.android.internal.telephony.SmsHeader;
+
+/*
+ * The SMSDataCoding class encodes and decodes CDMA SMS messages.
+ */
+public class SmsDataCoding {
+ private final static String TAG = "CDMA_SMS_JNI";
+
+ private final static int CDMA_SMS_WMS_MASK_BD_NULL = 0x00000000;
+ private final static int CDMA_SMS_WMS_MASK_BD_MSG_ID = 0x00000001;
+ private final static int CDMA_SMS_WMS_MASK_BD_USER_DATA = 0x00000002;
+// private final static int CDMA_SMS_WMS_MASK_BD_USER_RESP = 0x00000004;
+ private final static int CDMA_SMS_WMS_MASK_BD_MC_TIME = 0x00000008;
+// private final static int CDMA_SMS_WMS_MASK_BD_VALID_ABS = 0x00000010;
+// private final static int CDMA_SMS_WMS_MASK_BD_VALID_REL = 0x00000020;
+// private final static int CDMA_SMS_WMS_MASK_BD_DEFER_ABS = 0x00000040;
+// private final static int CDMA_SMS_WMS_MASK_BD_DEFER_REL = 0x00000080;
+// private final static int CDMA_SMS_WMS_MASK_BD_PRIORITY = 0x00000100;
+// private final static int CDMA_SMS_WMS_MASK_BD_PRIVACY = 0x00000200;
+// private final static int CDMA_SMS_WMS_MASK_BD_REPLY_OPTION = 0x00000400;
+ private final static int CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS = 0x00000800;
+// private final static int CDMA_SMS_WMS_MASK_BD_ALERT = 0x00001000;
+// private final static int CDMA_SMS_WMS_MASK_BD_LANGUAGE = 0x00002000;
+ private final static int CDMA_SMS_WMS_MASK_BD_CALLBACK = 0x00004000;
+ private final static int CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE = 0x00008000;
+// private final static int CDMA_SMS_WMS_MASK_BD_SCPT_DATA = 0x00010000;
+// private final static int CDMA_SMS_WMS_MASK_BD_SCPT_RESULT = 0x00020000;
+// private final static int CDMA_SMS_WMS_MASK_BD_DEPOSIT_INDEX = 0x00040000;
+// private final static int CDMA_SMS_WMS_MASK_BD_DELIVERY_STATUS = 0x00080000;
+// private final static int CDMA_SMS_WMS_MASK_BD_IP_ADDRESS = 0x10000000;
+// private final static int CDMA_SMS_WMS_MASK_BD_RSN_NO_NOTIFY = 0x20000000;
+// private final static int CDMA_SMS_WMS_MASK_BD_OTHER = 0x40000000;
+
+ /**
+ * Successful operation.
+ */
+ private static final int JNI_CDMA_SMS_SUCCESS = 0;
+
+ /**
+ * General failure.
+ */
+ private static final int JNI_CDMA_SMS_FAILURE = 1;
+
+ /**
+ * Data length is out of length.
+ */
+ private static final int JNI_CDMA_SMS_DATA_LEN_OUT_OF_RANGE = 2;
+
+ /**
+ * Class name unknown.
+ */
+ private static final int JNI_CDMA_SMS_CLASS_UNKNOWN = 3;
+
+ /**
+ * Field ID unknown.
+ */
+ private static final int JNI_CDMA_SMS_FIELD_ID_UNKNOWN = 4;
+
+ /**
+ * Memory allocation failed.
+ */
+ private static final int JNI_CDMA_SMS_OUT_OF_MEMORY = 5;
+
+ /**
+ * Encode SMS.
+ *
+ * @param bearerData an instance of BearerData.
+ *
+ * @return the encoded SMS as byte[].
+ */
+ public static byte[] encodeCdmaSms(BearerData bearerData) {
+ byte[] encodedSms;
+
+ if( nativeCdmaSmsConstructClientBD() == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+
+ // check bearer data and generate bit mask
+ generateBearerDataBitMask(bearerData);
+ encodedSms = startEncoding(bearerData);
+
+ if( nativeCdmaSmsDestructClientBD() == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+ return encodedSms;
+ }
+
+ /**
+ * Decode SMS.
+ *
+ * @param SmsData the encoded SMS.
+ *
+ * @return an instance of BearerData.
+ */
+ public static BearerData decodeCdmaSms(byte[] SmsData) {
+ BearerData bearerData;
+
+ if( nativeCdmaSmsConstructClientBD() == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+
+ bearerData = startDecoding(SmsData);
+
+ if( nativeCdmaSmsDestructClientBD() == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+ return bearerData;
+ }
+
+ private static void generateBearerDataBitMask(BearerData bearerData) {
+ // initial
+ bearerData.mask = CDMA_SMS_WMS_MASK_BD_NULL;
+
+ // check message type
+ if (bearerData.messageType != 0){
+ bearerData.mask |= CDMA_SMS_WMS_MASK_BD_MSG_ID;
+ }
+
+ // check mUserData
+ if (bearerData.userData != null){
+ bearerData.mask |= CDMA_SMS_WMS_MASK_BD_USER_DATA;
+ }
+
+ // check mTimeStamp
+ if (bearerData.timeStamp != null){
+ bearerData.mask |= CDMA_SMS_WMS_MASK_BD_MC_TIME;
+ }
+
+ // check mNumberOfMessages
+ if (bearerData.numberOfMessages > 0){
+ bearerData.mask |= CDMA_SMS_WMS_MASK_BD_NUM_OF_MSGS;
+ }
+
+ // check mCallbackNumber
+ if(bearerData.callbackNumber != null){
+ bearerData.mask |= CDMA_SMS_WMS_MASK_BD_CALLBACK;
+ }
+
+ // check DisplayMode
+ if(bearerData.displayMode == BearerData.DISPLAY_DEFAULT ||
+ bearerData.displayMode == BearerData.DISPLAY_IMMEDIATE ||
+ bearerData.displayMode == BearerData.DISPLAY_USER){
+ bearerData.mask |= CDMA_SMS_WMS_MASK_BD_DISPLAY_MODE;
+ }
+ }
+
+ private static byte[] startEncoding(BearerData bearerData) {
+ int m_id;
+ byte[] m_data;
+ int dataLength;
+ byte[] encodedSms;
+ int nbrOfHeaders = 0;
+
+ if( nativeCdmaSmsSetBearerDataPrimitives(bearerData) == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+
+ if ((bearerData.mask & CDMA_SMS_WMS_MASK_BD_USER_DATA) == CDMA_SMS_WMS_MASK_BD_USER_DATA){
+ if( nativeCdmaSmsSetUserData(bearerData.userData) == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+
+ if (bearerData.userData.userDataHeader != null){
+ nbrOfHeaders = bearerData.userData.userDataHeader.nbrOfHeaders;
+ }
+
+ for (int i = 0; i < nbrOfHeaders; i++) {
+ m_id = bearerData.userData.userDataHeader.getElements().get(i).getID();
+ m_data = bearerData.userData.userDataHeader.getElements().get(i).getData();
+ dataLength = m_data.length;
+ if( nativeCdmaSmsSetUserDataHeader(m_id, m_data, dataLength, i)
+ == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+ }
+ }
+
+ if ((bearerData.mask & CDMA_SMS_WMS_MASK_BD_CALLBACK) == CDMA_SMS_WMS_MASK_BD_CALLBACK) {
+ if( nativeCdmaSmsSetSmsAddress(bearerData.callbackNumber) == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+ }
+
+ /* call native method to encode SMS */
+ encodedSms = nativeCdmaSmsEncodeSms();
+
+ return encodedSms;
+ }
+
+ private static BearerData startDecoding(byte[] SmsData) {
+ BearerData bData = new BearerData();
+ byte[] udhData;
+
+ /* call native method to decode SMS */
+ if( nativeCdmaSmsDecodeSms(SmsData) == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+
+ if( nativeCdmaSmsGetBearerDataPrimitives(bData) == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+
+ if ((bData.mask & CDMA_SMS_WMS_MASK_BD_USER_DATA) == CDMA_SMS_WMS_MASK_BD_USER_DATA) {
+ bData.userData = new UserData();
+ if( nativeCdmaSmsGetUserData(bData.userData) == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+
+ udhData = nativeCdmaSmsGetUserDataHeader();
+ if (udhData != null) {
+ bData.userData.userDataHeader = SmsHeader.parse(udhData);
+ }
+ }
+
+ if ((bData.mask & CDMA_SMS_WMS_MASK_BD_CALLBACK) == CDMA_SMS_WMS_MASK_BD_CALLBACK) {
+ bData.callbackNumber = new CdmaSmsAddress();
+ if( nativeCdmaSmsGetSmsAddress(bData.callbackNumber) == JNI_CDMA_SMS_FAILURE){
+ return null;
+ }
+ }
+
+ return bData;
+ }
+
+ // native methods
+
+ /**
+ * native method: Allocate memory for clientBD structure
+ *
+ * @return #JNI_CDMA_SMS_SUCCESS if succeed.
+ * #JNI_CDMA_SMS_FAILURE if fail.
+ */
+ private static native int nativeCdmaSmsConstructClientBD();
+
+ /**
+ * native method: Free memory used for clientBD structure
+ *
+ * @return #JNI_CDMA_SMS_SUCCESS if succeed.
+ * #JNI_CDMA_SMS_FAILURE if fail.
+ */
+ private static native int nativeCdmaSmsDestructClientBD();
+
+ /**
+ * native method: fill clientBD structure with bearerData primitives
+ *
+ * @param bearerData an instance of BearerData.
+ *
+ * @return #JNI_CDMA_SMS_SUCCESS if succeed.
+ * #JNI_CDMA_SMS_FAILURE if fail.
+ */
+ private static native int nativeCdmaSmsSetBearerDataPrimitives(BearerData bearerData);
+
+ /**
+ * native method: fill bearerData primitives with clientBD variables
+ *
+ * @param bearerData an instance of BearerData.
+ *
+ * @return #JNI_CDMA_SMS_SUCCESS if succeed.
+ * #JNI_CDMA_SMS_FAILURE if fail.
+ */
+ private static native int nativeCdmaSmsGetBearerDataPrimitives(BearerData bearerData);
+
+ /**
+ * native method: fill clientBD.user_data with UserData primitives
+ *
+ * @param userData an instance of UserData.
+ *
+ * @return #JNI_CDMA_SMS_SUCCESS if succeed.
+ * #JNI_CDMA_SMS_FAILURE if fail.
+ */
+ private static native int nativeCdmaSmsSetUserData(UserData userData);
+
+ /**
+ * native method: fill UserData primitives with clientBD.user_data
+ *
+ * @param userData an instance of UserData.
+ *
+ * @return #JNI_CDMA_SMS_SUCCESS if succeed.
+ * #JNI_CDMA_SMS_FAILURE if fail.
+ */
+ private static native int nativeCdmaSmsGetUserData(UserData userData);
+
+ /**
+ * native method: fill clientBD.user_data.headers with UserDataHeader primitives
+ *
+ * @param ID ID of element.
+ * @param data element data.
+ * @param dataLength data length
+ * @param index index of element
+ *
+ * @return #JNI_CDMA_SMS_SUCCESS if succeed.
+ * #JNI_CDMA_SMS_FAILURE if fail.
+ */
+ private static native int nativeCdmaSmsSetUserDataHeader(
+ int ID, byte[] data, int dataLength, int index);
+
+ /**
+ * native method: fill UserDataHeader primitives with clientBD.user_data.headers
+ *
+ * @return user data headers
+ */
+ private static native byte[] nativeCdmaSmsGetUserDataHeader();
+
+ /**
+ * native method: fill clientBD.callback with SmsAddress primitives
+ *
+ * @param smsAddr an instance of SmsAddress.
+ *
+ * @return #JNI_CDMA_SMS_SUCCESS if succeed.
+ * #JNI_CDMA_SMS_FAILURE if fail.
+ */
+ private static native int nativeCdmaSmsSetSmsAddress(CdmaSmsAddress smsAddr);
+
+ /**
+ * native method: fill SmsAddress primitives with clientBD.callback
+ *
+ * @param smsAddr an instance of SmsAddress.
+ *
+ * @return #JNI_CDMA_SMS_SUCCESS if succeed.
+ * #JNI_CDMA_SMS_FAILURE if fail.
+ */
+ private static native int nativeCdmaSmsGetSmsAddress(CdmaSmsAddress smsAddr);
+
+ /**
+ * native method: call encoding functions and get encoded SMS
+ *
+ * @return the encoded SMS
+ */
+ private static native byte[] nativeCdmaSmsEncodeSms();
+
+ /**
+ * native method: call decode functions
+ *
+ * @param encodedSMS encoded SMS.
+ *
+ * @return #JNI_CDMA_SMS_SUCCESS if succeed.
+ * #JNI_CDMA_SMS_FAILURE if fail.
+ */
+ private static native int nativeCdmaSmsDecodeSms(byte[] encodedSMS);
+
+ /**
+ * Load the shared library to link the native methods.
+ */
+ static {
+ try {
+ System.loadLibrary("cdma_sms_jni");
+ }
+ catch (UnsatisfiedLinkError ule) {
+ System.err.println("WARNING: Could not load cdma_sms_jni.so");
+ }
+ }
+}
+
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
new file mode 100644
index 0000000..f80e8c0
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.cdma.sms;
+
+
+public final class SmsEnvelope{
+ /**
+ * Message Types
+ * (See 3GPP2 C.S0015-B 3.4.1)
+ */
+ static public final int MESSAGE_TYPE_POINT_TO_POINT = 0x00;
+ static public final int MESSAGE_TYPE_BROADCAST = 0x01;
+ static public final int MESSAGE_TYPE_ACKNOWLEDGE = 0x02;
+
+ /**
+ * Supported Teleservices
+ * (See 3GPP2 N.S0005 and TIA-41)
+ */
+ static public final int TELESERVICE_NOT_SET = 0x0000;
+ static public final int TELESERVICE_WMT = 0x1002;
+ static public final int TELESERVICE_VMN = 0x1003;
+ static public final int TELESERVICE_WAP = 0x1004;
+ static public final int TELESERVICE_WEMT = 0x1005;
+
+ // ServiceCategories for Cell Broadcast, see 3GPP2 C.R1001 table 9.3.1-1
+ //static public final int SERVICECATEGORY_EMERGENCY = 0x0010;
+ //...
+
+ /**
+ * maximum lengths for fields as defined in ril_cdma_sms.h
+ */
+ static public final int SMS_BEARER_DATA_MAX = 255;
+
+ /**
+ * Provides the type of a SMS message like point to point, broadcast or acknowledge
+ */
+ public int messageType;
+
+ /**
+ * The 16-bit Teleservice parameter identifies which upper layer service access point is sending
+ * or receiving the message.
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.1)
+ */
+ public int teleService = TELESERVICE_NOT_SET;
+
+ /**
+ * The 16-bit service category parameter identifies the type of service provided
+ * by the SMS message.
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.2)
+ */
+ public int serviceCategory;
+
+ /**
+ * The origination address identifies the originator of the SMS message.
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.4)
+ */
+ public CdmaSmsAddress origAddress;
+
+ /**
+ * The destination address identifies the target of the SMS message.
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.4)
+ */
+ public CdmaSmsAddress destAddress;
+
+ /**
+ * The 6-bit bearer reply parameter is used to request the return of a
+ * SMS Acknowledge Message.
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.5)
+ */
+ public int bearerReply;
+
+ /**
+ * Cause Code values:
+ * The cause code parameters are an indication whether an SMS error has occurred and if so,
+ * whether the condition is considered temporary or permanent.
+ * ReplySeqNo 6-bit value,
+ * ErrorClass 2-bit value,
+ * CauseCode 0-bit or 8-bit value
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.6)
+ */
+ public byte replySeqNo;
+ public byte errorClass;
+ public byte causeCode;
+
+ /**
+ * encoded bearer data
+ * (See 3GPP2 C.S0015-B, v2, 3.4.3.7)
+ */
+ public byte[] bearerData;
+
+ public SmsEnvelope() {
+ // nothing to see here
+ }
+
+}
+
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
new file mode 100644
index 0000000..e761469
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/UserData.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.cdma.sms;
+
+import com.android.internal.telephony.SmsHeader;
+
+public class UserData{
+
+ /**
+ * Supported user data encoding types
+ * (See 3GPP2 C.R1001-F, v1.0, table 9.1-1)
+ */
+ public static final int UD_ENCODING_OCTET = 0x00;
+ //public static final int UD_ENCODING_EXTENDED_PROTOCOL = 0x01;
+ public static final int UD_ENCODING_7BIT_ASCII = 0x02;
+ public static final int UD_ENCODING_IA5 = 0x03;
+ public static final int UD_ENCODING_UNICODE_16 = 0x04;
+ //public static final int UD_ENCODING_SHIFT_JIS = 0x05;
+ //public static final int UD_ENCODING_KOREAN = 0x06;
+ //public static final int UD_ENCODING_LATIN_HEBREW = 0x07;
+ //public static final int UD_ENCODING_LATIN = 0x08;
+ public static final int UD_ENCODING_GSM_7BIT_ALPHABET = 0x09;
+ //public static final int UD_ENCODING_GSM_DCS = 0x0A;
+
+ /**
+ * Contains the data header of the user data
+ */
+ public SmsHeader userDataHeader;
+
+ /**
+ * Contains the data encoding type for the SMS message
+ */
+ public int userDataEncoding;
+
+ // needed when encoding is IS91 or DCS (not supported yet):
+ //public int messageType;
+
+ /**
+ * Number of invalid bits in the last byte of data.
+ */
+ public int paddingBits;
+
+ /**
+ * Contains the user data of a SMS message
+ * (See 3GPP2 C.S0015-B, v2, 4.5.2)
+ */
+ public byte[] userData;
+
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/package.html b/telephony/java/com/android/internal/telephony/cdma/sms/package.html
new file mode 100644
index 0000000..48e1034
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/package.html
@@ -0,0 +1,6 @@
+
+
+Provides CDMA-specific features for text/data/PDU SMS messages
+@hide
+
+
diff --git a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.aidl b/telephony/java/com/android/internal/telephony/gsm/AdnRecord.aidl
deleted file mode 100644
index 68d9a7c..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
-** 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.gsm;
-
-parcelable AdnRecord;
diff --git a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.java b/telephony/java/com/android/internal/telephony/gsm/AdnRecord.java
deleted file mode 100644
index 30df699..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/AdnRecord.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import com.android.internal.telephony.*;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.Message;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.AsyncResult;
-import android.util.Log;
-import android.telephony.PhoneNumberUtils;
-import java.util.ArrayList;
-
-class AdnRecordLoader extends Handler
-{
- static final String LOG_TAG = "GSM";
-
- //***** Instance Variables
-
- GSMPhone phone;
- int ef;
- int extensionEF;
- int pendingExtLoads;
- Message userResponse;
- String pin2;
-
- // For "load one"
- int recordNumber;
-
- // for "load all"
- ArrayList 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
-
- AdnRecordLoader(GSMPhone phone)
- {
- // The telephony unit-test cases may create AdnRecords
- // in secondary threads
- super(phone.h.getLooper());
-
- this.phone = phone;
- }
-
- /**
- * Resulting AdnRecord is placed in response.obj.result
- * or response.obj.exception is set
- */
- void
- loadFromEF(int ef, int extensionEF, int recordNumber,
- Message response)
- {
- this.ef = ef;
- this.extensionEF = extensionEF;
- this.recordNumber = recordNumber;
- this.userResponse = response;
-
- phone.mSIMFileHandler.loadEFLinearFixed(
- ef, recordNumber,
- obtainMessage(EVENT_ADN_LOAD_DONE));
-
- }
-
-
- /**
- * Resulting ArrayList<adnRecord> is placed in response.obj.result
- * or response.obj.exception is set
- */
- void
- loadAllFromEF(int ef, int extensionEF,
- Message response)
- {
- this.ef = ef;
- this.extensionEF = extensionEF;
- this.userResponse = response;
-
- phone.mSIMFileHandler.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
- */
- 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.mSIMFileHandler.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.mSIMFileHandler.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" + SimUtils.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.mSIMFileHandler.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" + SimUtils.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 datas = (ArrayList)(ar.result);
-
- if (ar.exception != null) {
- throw new RuntimeException("load failed", ar.exception);
- }
-
- adns = new ArrayList(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.mSIMFileHandler.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;
- }
- }
-
-
-}
-
-/**
- *
- * 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 CREATOR
- = new Parcelable.Creator()
- {
- 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 = SimUtils.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 = "";
- }
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/AdnRecordCache.java b/telephony/java/com/android/internal/telephony/gsm/AdnRecordCache.java
deleted file mode 100644
index 9da18e3..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/AdnRecordCache.java
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.util.SparseArray;
-import android.util.Log;
-import android.os.Message;
-import android.os.Handler;
-import android.os.AsyncResult;
-import java.util.ArrayList;
-import java.util.Iterator;
-
-/**
- * {@hide}
- */
-public final class AdnRecordCache extends Handler implements SimConstants
-{
- //***** Instance Variables
-
- GSMPhone phone;
-
- // Indexed by EF ID
- SparseArray> adnLikeFiles
- = new SparseArray>();
-
- // People waiting for ADN-like files to be loaded
- SparseArray> adnLikeWaiters
- = new SparseArray>();
-
- // People waiting for adn record to be updated
- SparseArray userWriteResponse = new SparseArray();
-
- //***** Event Constants
-
- static final int EVENT_LOAD_ALL_ADN_LIKE_DONE = 1;
- static final int EVENT_UPDATE_ADN_DONE = 2;
-
- //***** Constructor
-
-
- /*package*/
- AdnRecordCache(GSMPhone phone)
- {
- this.phone = phone;
- }
-
- //***** Called from SIMRecords
-
- /**
- * Called from SIMRecords.onRadioNotAvailable and SIMRecords.handleSimRefresh.
- */
- /*package*/ void
- reset()
- {
- adnLikeFiles.clear();
-
- clearWaiters();
- clearUserWriters();
-
- }
-
- private void clearWaiters() {
- int size = adnLikeWaiters.size();
- for (int i = 0; i < size; i++) {
- ArrayList waiters = adnLikeWaiters.valueAt(i);
- AsyncResult ar = new AsyncResult(null, null, new RuntimeException("AdnCache reset"));
- notifyWaiters(waiters, ar);
- }
- adnLikeWaiters.clear();
- }
-
- private void clearUserWriters() {
- int size = userWriteResponse.size();
- for (int i = 0; i < size; i++) {
- sendErrorResponse(userWriteResponse.valueAt(i), "AdnCace reset");
- }
- userWriteResponse.clear();
- }
-
- /**
- * @return List of AdnRecords for efid if we've already loaded them this
- * radio session, or null if we haven't
- */
- /*package*/ ArrayList
- getRecordsIfLoaded(int efid)
- {
- return adnLikeFiles.get(efid);
- }
-
- /**
- * 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)
- {
- 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;
- default: return -1;
- }
- }
-
- private void sendErrorResponse(Message response, String errString) {
- if (response != null) {
- Exception e = new RuntimeException(errString);
- AsyncResult.forMessage(response).exception = e;
- response.sendToTarget();
- }
- }
-
- /**
- * Update an ADN-like record in EF by record index
- *
- * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
- * @param adn is the new adn to be stored
- * @param recordIndex is the 1-based adn record index
- * @param pin2 is required to update EF_FDN, otherwise must be null
- * @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,
- Message response) {
-
- int extensionEF = extensionEfForEf(efid);
- if (extensionEF < 0) {
- sendErrorResponse(response, "EF is not known ADN-like EF:" + efid);
- return;
- }
-
- Message pendingResponse = userWriteResponse.get(efid);
- if (pendingResponse != null) {
- sendErrorResponse(response, "Have pending update for EF:" + efid);
- return;
- }
-
- userWriteResponse.put(efid, response);
-
- new AdnRecordLoader(phone).updateEF(adn, efid, extensionEF,
- recordIndex, pin2,
- obtainMessage(EVENT_UPDATE_ADN_DONE, efid, recordIndex, adn));
- }
-
- /**
- * Replace oldAdn with newAdn in ADN-like record in EF
- *
- * The ADN-like records must be read through requestLoadAllAdnLike() before
- *
- * @param efid must be one of EF_ADN, EF_FDN, and EF_SDN
- * @param oldAdn is the adn to be replaced
- * If oldAdn.isEmpty() is ture, it insert the newAdn
- * @param newAdn is the adn to be stored
- * If newAdn.isEmpty() is true, it delete the oldAdn
- * @param pin2 is required to update EF_FDN, otherwise must be null
- * @param response message to be posted when done
- * response.exception hold the exception in error
- */
- void updateAdnBySearch(int efid, AdnRecord oldAdn, AdnRecord newAdn,
- String pin2, Message response) {
-
- int extensionEF;
- extensionEF = extensionEfForEf(efid);
-
- if (extensionEF < 0) {
- sendErrorResponse(response, "EF is not known ADN-like EF:" + efid);
- return;
- }
-
- ArrayList oldAdnList;
- oldAdnList = getRecordsIfLoaded(efid);
-
- if (oldAdnList == null) {
- sendErrorResponse(response, "Adn list not exist for EF:" + efid);
- return;
- }
-
- int index = -1;
- int count = 1;
- for (Iterator it = oldAdnList.iterator(); it.hasNext(); ) {
- if (oldAdn.isEqual(it.next())) {
- index = count;
- break;
- }
- count++;
- }
-
- if (index == -1) {
- sendErrorResponse(response, "Adn record don't exist for " + oldAdn);
- return;
- }
-
- Message pendingResponse = userWriteResponse.get(efid);
-
- if (pendingResponse != null) {
- sendErrorResponse(response, "Have pending update for EF:" + efid);
- return;
- }
-
- userWriteResponse.put(efid, response);
-
- new AdnRecordLoader(phone).updateEF(newAdn, efid, extensionEF,
- index, pin2,
- obtainMessage(EVENT_UPDATE_ADN_DONE, efid, index, newAdn));
- }
-
-
- /**
- * Responds with exception (in response) if efid is not a known ADN-like
- * record
- */
- /*package*/ void
- requestLoadAllAdnLike (int efid, Message response)
- {
- ArrayList waiters;
- ArrayList result;
-
- result = getRecordsIfLoaded(efid);
-
- // Have we already loaded this efid?
- if (result != null) {
- if (response != null) {
- AsyncResult.forMessage(response).result = result;
- response.sendToTarget();
- }
-
- return;
- }
-
- // Have we already *started* loading this efid?
-
- waiters = adnLikeWaiters.get(efid);
-
- if (waiters != null) {
- // There's a pending request for this EF already
- // just add ourselves to it
-
- waiters.add(response);
- return;
- }
-
- // Start loading efid
-
- waiters = new ArrayList();
- 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
- = new RuntimeException("EF is not known ADN-like EF:" + efid);
- response.sendToTarget();
- }
-
- return;
- }
-
- new AdnRecordLoader(phone).loadAllFromEF(efid, extensionEF,
- obtainMessage(EVENT_LOAD_ALL_ADN_LIKE_DONE, efid, 0));
- }
-
- //***** Private methods
-
- private void
- notifyWaiters(ArrayList waiters, AsyncResult ar)
- {
-
- if (waiters == null) {
- return;
- }
-
- for (int i = 0, s = waiters.size() ; i < s ; i++) {
- Message waiter = waiters.get(i);
-
- AsyncResult.forMessage(waiter, ar.result, ar.exception);
- waiter.sendToTarget();
- }
- }
-
- //***** Overridden from Handler
-
- public void
- handleMessage(Message msg) {
- AsyncResult ar;
- int efid;
-
- switch(msg.what) {
- case EVENT_LOAD_ALL_ADN_LIKE_DONE:
- /* arg1 is efid, obj.result is ArrayList*/
- ar = (AsyncResult) msg.obj;
- efid = msg.arg1;
- ArrayList waiters;
-
- waiters = adnLikeWaiters.get(efid);
- adnLikeWaiters.delete(efid);
-
- if (ar.exception == null) {
- adnLikeFiles.put(efid, (ArrayList) (ar.result));
- }
- notifyWaiters(waiters, ar);
- break;
- case EVENT_UPDATE_ADN_DONE:
- ar = (AsyncResult)msg.obj;
- efid = msg.arg1;
- int index = msg.arg2;
- AdnRecord adn = (AdnRecord) (ar.userObj);
-
- if (ar.exception == null) {
- adnLikeFiles.get(efid).set(index - 1, adn);
- }
-
- Message response = userWriteResponse.get(efid);
- userWriteResponse.delete(efid);
-
- AsyncResult.forMessage(response, null, ar.exception);
- response.sendToTarget();
- break;
- }
-
- }
-
-
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java b/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java
deleted file mode 100644
index 8e14b43..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/BaseCommands.java
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.content.Context;
-import android.os.RegistrantList;
-import android.os.Registrant;
-import android.os.Handler;
-import android.os.AsyncResult;
-import android.os.SystemProperties;
-import android.provider.Checkin;
-import android.util.Config;
-import android.util.Log;
-
-/**
- * {@hide}
- */
-public abstract class BaseCommands implements CommandsInterface
-{
- static final String LOG_TAG = "GSM";
-
- //***** 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 mCallStateRegistrants = new RegistrantList();
- protected RegistrantList mNetworkStateRegistrants = new RegistrantList();
- protected RegistrantList mPDPRegistrants = 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 SMS storage full messages */
- protected Registrant mSimSmsFullRegistrant;
- /** Registrant for handling SIM Refresh notifications */
- protected Registrant mSimRefreshRegistrant;
- /** Registrant for handling RING notifications */
- protected Registrant mRingRegistrant;
- /** Registrant for handling RESTRICTED STATE changed notification */
- protected Registrant mRestrictedStateRegistrant;
-
- 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
- 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
- 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
- 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
- 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));
- }
- }
- }
-
-
- /** 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
- 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
- registerForCallStateChanged(Handler h, int what, Object obj)
- {
- Registrant r = new Registrant (h, what, obj);
-
- mCallStateRegistrants.add(r);
- }
-
- public void
- registerForNetworkStateChanged(Handler h, int what, Object obj)
- {
- Registrant r = new Registrant (h, what, obj);
-
- mNetworkStateRegistrants.add(r);
- }
-
- public void
- registerForPDPStateChanged(Handler h, int what, Object obj)
- {
- Registrant r = new Registrant (h, what, obj);
-
- mPDPRegistrants.add(r);
- }
-
- public void
- setOnNewSMS(Handler h, int what, Object obj)
- {
- mSMSRegistrant = new Registrant (h, what, obj);
- }
-
- public void
- setOnSmsOnSim(Handler h, int what, Object obj)
- {
- mSmsOnSimRegistrant = new Registrant (h, what, obj);
- }
-
- public void setOnSmsStatus(Handler h, int what, Object obj) {
- mSmsStatusRegistrant = new Registrant (h, what, obj);
- }
-
- public void
- setOnSignalStrengthUpdate(Handler h, int what, Object obj)
- {
- mSignalStrengthRegistrant = new Registrant (h, what, obj);
- }
-
- public void
- setOnNITZTime(Handler h, int what, Object obj)
- {
- mNITZTimeRegistrant = new Registrant (h, what, obj);
- }
-
- public void
- setOnUSSD(Handler h, int what, Object obj)
- {
- mUSSDRegistrant = new Registrant (h, what, obj);
- }
-
- public void
- setOnSuppServiceNotification(Handler h, int what, Object obj)
- {
- mSsnRegistrant = new Registrant (h, what, obj);
- }
-
- public void
- setOnStkSessionEnd(Handler h, int what, Object obj)
- {
- mStkSessionEndRegistrant = new Registrant (h, what, obj);
- }
-
- public void
- setOnStkProactiveCmd(Handler h, int what, Object obj)
- {
- mStkProCmdRegistrant = new Registrant (h, what, obj);
- }
-
- public void
- setOnStkEvent(Handler h, int what, Object obj)
- {
- mStkEventRegistrant = new Registrant (h, what, obj);
- }
-
- public void
- setOnStkCallSetUp(Handler h, int what, Object obj)
- {
- mStkCallSetUpRegistrant = new Registrant (h, what, obj);
- }
-
- public void setOnSimSmsFull(Handler h, int what, Object obj) {
- mSimSmsFullRegistrant = new Registrant (h, what, obj);
- }
-
- public void setOnSimRefresh(Handler h, int what, Object obj) {
- mSimRefreshRegistrant = new Registrant (h, what, obj);
- }
-
- public void setOnCallRing(Handler h, int what, Object obj) {
- mRingRegistrant = new Registrant (h, what, obj);
- }
-
- public void
- setOnRestrictedStateChanged(Handler h, int what, Object obj)
- {
- mRestrictedStateRegistrant = new Registrant (h, what, obj);
- }
-
- //***** 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.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();
- }
- }
- }
-
- protected void
- onRadioAvailable()
- {
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/CallForwardInfo.java b/telephony/java/com/android/internal/telephony/gsm/CallForwardInfo.java
deleted file mode 100644
index bf31b13..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/CallForwardInfo.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.telephony.PhoneNumberUtils;
-
-/**
- * See also RIL_CallForwardInfo in include/telephony/ril.h
- *
- * {@hide}
- */
-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 */
- public int toa; /* "type" from TS 27.007 7.11 */
- public String number; /* "number" from TS 27.007 7.11 */
- public int timeSeconds; /* for CF no reply only */
-
- public String toString()
- {
- return super.toString() + (status == 0 ? " not active " : " active ")
- + " reason: " + reason
- + " serviceClass: " + serviceClass
- + " \"" + PhoneNumberUtils.stringFromStringAndTOA(number, toa) + "\" "
- + timeSeconds + " seconds";
-
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/CallTracker.java b/telephony/java/com/android/internal/telephony/gsm/CallTracker.java
deleted file mode 100644
index 2d716bb..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/CallTracker.java
+++ /dev/null
@@ -1,984 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE;
-import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_EDGE;
-import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_GPRS;
-import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_UMTS;
-import static com.android.internal.telephony.gsm.ServiceStateTracker.DATA_ACCESS_UNKNOWN;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
-import android.os.SystemProperties;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.ServiceState;
-import android.telephony.TelephonyManager;
-import android.telephony.gsm.GsmCellLocation;
-import android.util.EventLog;
-import android.util.Log;
-
-import com.android.internal.telephony.Call;
-import com.android.internal.telephony.CallStateException;
-import com.android.internal.telephony.Connection;
-import com.android.internal.telephony.Phone;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * {@hide}
- */
-public final class CallTracker extends Handler
-{
- static final String LOG_TAG = "GSM";
- private static final boolean REPEAT_POLLING = false;
-
- private static final boolean DBG_POLL = false;
-
- //***** Constants
-
- static final int POLL_DELAY_MSEC = 250;
- static final int MAX_CONNECTIONS = 7; // only 7 connections allowed in GSM
- static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call
-
- //***** Instance Variables
-
- GSMConnection connections[] = new GSMConnection[MAX_CONNECTIONS];
- RegistrantList voiceCallEndedRegistrants = new RegistrantList();
- RegistrantList voiceCallStartedRegistrants = new RegistrantList();
-
-
- // connections dropped durin last poll
- ArrayList droppedDuringPoll
- = new ArrayList(MAX_CONNECTIONS);
-
- GSMCall ringingCall = new GSMCall(this);
- // A call that is ringing or (call) waiting
- GSMCall foregroundCall = new GSMCall(this);
- GSMCall backgroundCall = new GSMCall(this);
-
- GSMConnection pendingMO;
- boolean hangupPendingMO;
-
- GSMPhone phone;
- CommandsInterface cm;
- boolean desiredMute = false; // false = mute off
-
- Phone.State state = Phone.State.IDLE;
-
- int pendingOperations;
- boolean needsPoll;
- Message lastRelevantPoll;
-
-
- //***** Events
-
- static final int EVENT_POLL_CALLS_RESULT = 1;
- static final int EVENT_CALL_STATE_CHANGE = 2;
- static final int EVENT_REPOLL_AFTER_DELAY = 3;
- static final int EVENT_OPERATION_COMPLETE = 4;
- static final int EVENT_GET_LAST_CALL_FAIL_CAUSE = 5;
-
- static final int EVENT_SWITCH_RESULT = 8;
- static final int EVENT_RADIO_AVAILABLE = 9;
- static final int EVENT_RADIO_NOT_AVAILABLE = 10;
- static final int EVENT_CONFERENCE_RESULT = 11;
- static final int EVENT_SEPARATE_RESULT = 12;
- static final int EVENT_ECT_RESULT = 13;
-
- //***** Constructors
-
- CallTracker (GSMPhone 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);
- }
-
- //***** 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 registerForVoiceCallEnded(Handler h, int what, Object obj)
- {
- Registrant r = new Registrant(h, what, obj);
- voiceCallEndedRegistrants.add(r);
- }
-
- private void
- fakeHoldForegroundBeforeDial()
- {
- List connCopy;
-
- // We need to make a copy here, since fakeHoldBeforeDial()
- // modifies the lists, and we don't want to reverse the order
- connCopy = (List) foregroundCall.connections.clone();
-
- for (int i = 0, s = connCopy.size() ; i < s ; i++) {
- GSMConnection conn = (GSMConnection)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() == Call.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() != Call.State.IDLE) {
- //we should have failed in !canDial() above before we get here
- throw new CallStateException("cannot dial in current state");
- }
-
- pendingMO = new GSMConnection(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() == Call.State.INCOMING) {
- Log.i("phone", "acceptCall: incoming...");
- // Always unmute when answering a new call
- setMute(false);
- cm.acceptCall(obtainCompleteMessage());
- } else if (ringingCall.getState() == Call.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() == Call.State.INCOMING) {
- throw new CallStateException("cannot be in the incoming state");
- } else {
- cm.switchWaitingOrHoldingAndActive(
- obtainCompleteMessage(EVENT_SWITCH_RESULT));
- }
- }
-
- void
- conference() throws CallStateException
- {
- cm.conference(obtainCompleteMessage(EVENT_CONFERENCE_RESULT));
- }
-
- void
- explicitCallTransfer() throws CallStateException
- {
- cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT));
- }
-
- void
- clearDisconnected()
- {
- internalClearDisconnected();
-
- updatePhoneState();
- phone.notifyCallStateChanged();
- }
-
- boolean
- canConference()
- {
- return foregroundCall.getState() == Call.State.ACTIVE
- && backgroundCall.getState() == Call.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()
- {
- return foregroundCall.getState() == Call.State.ACTIVE
- && backgroundCall.getState() == Call.State.HOLDING;
- }
-
- //***** Private Instance Methods
-
- private void
- internalClearDisconnected()
- {
- ringingCall.clearDisconnected();
- foregroundCall.clearDisconnected();
- backgroundCall.clearDisconnected();
- }
-
- /**
- * @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;
- }
-
-
- /**
- * 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);
- }
-
- /**
- * Obtain a complete message that indicates that this operation
- * does not require polling of getCurrentCalls(). However, if other
- * operations that do need getCurrentCalls() are pending or are
- * scheduled while this operation is pending, the invocatoin
- * of getCurrentCalls() will be postponed until this
- * operation is also complete.
- */
- private Message
- obtainNoPollCompleteMessage(int what)
- {
- pendingOperations++;
- lastRelevantPoll = null;
- 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,"CallTracker.pendingOperations < 0");
- pendingOperations = 0;
- }
- }
-
- private void
- pollCallsWhenSafe()
- {
- needsPoll = true;
-
- if (checkNoOperationsPending()) {
- lastRelevantPoll = obtainMessage(EVENT_POLL_CALLS_RESULT);
- cm.getCurrentCalls(lastRelevantPoll);
- }
- }
-
- private void
- pollCallsAfterDelay()
- {
- Message msg = obtainMessage();
-
- msg.what = EVENT_REPOLL_AFTER_DELAY;
- sendMessageDelayed(msg, POLL_DELAY_MSEC);
- }
-
- private boolean
- isCommandExceptionRadioNotAvailable(Throwable e)
- {
- return e != null && e instanceof CommandException
- && ((CommandException)e).getCommandError()
- == CommandException.Error.RADIO_NOT_AVAILABLE;
- }
-
- 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();
- }
- }
-
- private 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++) {
- GSMConnection 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 GSMConnection(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 GSMCall 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 GSMConnection (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--) {
- GSMConnection 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();
- }
-
- private void
- handleRadioAvailable()
- {
- pollCallsWhenSafe();
- }
-
- private void
- handleRadioNotAvailable()
- {
- // handlePollCalls will clear out its
- // call list when it gets the CommandException
- // error result from this
- pollCallsWhenSafe();
- }
-
- private void
- dumpState()
- {
- List l;
-
- Log.i(LOG_TAG,"Phone State:" + state);
-
- Log.i(LOG_TAG,"Ringing call: " + ringingCall.toString());
-
- l = ringingCall.getConnections();
- for (int i = 0, s = l.size(); i < s; i++) {
- Log.i(LOG_TAG,l.get(i).toString());
- }
-
- Log.i(LOG_TAG,"Foreground call: " + foregroundCall.toString());
-
- l = foregroundCall.getConnections();
- for (int i = 0, s = l.size(); i < s; i++) {
- Log.i(LOG_TAG,l.get(i).toString());
- }
-
- Log.i(LOG_TAG,"Background call: " + backgroundCall.toString());
-
- l = backgroundCall.getConnections();
- for (int i = 0, s = l.size(); i < s; i++) {
- Log.i(LOG_TAG,l.get(i).toString());
- }
-
- }
-
- //***** Called from GSMConnection
-
- /*package*/ void
- hangup (GSMConnection conn) throws CallStateException
- {
- if (conn.owner != this) {
- throw new CallStateException ("Connection " + conn
- + "does not belong to CallTracker " + 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.getGSMIndex(), obtainCompleteMessage());
- } catch (CallStateException ex) {
- // Ignore "connection not found"
- // Call may have hung up already
- Log.w(LOG_TAG,"CallTracker WARN: hangup() on absent connection "
- + conn);
- }
- }
-
- conn.onHangupLocal();
- }
-
- /*package*/ void
- separate (GSMConnection conn) throws CallStateException
- {
- if (conn.owner != this) {
- throw new CallStateException ("Connection " + conn
- + "does not belong to CallTracker " + this);
- }
- try {
- cm.separateConnection (conn.getGSMIndex(),
- obtainCompleteMessage(EVENT_SEPARATE_RESULT));
- } catch (CallStateException ex) {
- // Ignore "connection not found"
- // Call may have hung up already
- Log.w(LOG_TAG,"CallTracker WARN: separate() on absent connection "
- + conn);
- }
- }
-
- //***** Called from GSMPhone
-
- /*package*/ void
- setMute(boolean mute)
- {
- desiredMute = mute;
- cm.setMute(desiredMute, null);
- }
-
- /*package*/ boolean
- getMute()
- {
- return desiredMute;
- }
-
-
- //***** Called from GSMCall
-
- /* package */ void
- hangup (GSMCall 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((GSMConnection)(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 ("Call " + call +
- "does not belong to CallTracker " + 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(GSMCall call, int index)
- throws CallStateException {
- int count = call.connections.size();
- for (int i = 0; i < count; i++) {
- GSMConnection cn = (GSMConnection)call.connections.get(i);
- if (cn.getGSMIndex() == index) {
- cm.hangupConnection(index, obtainCompleteMessage());
- return;
- }
- }
-
- throw new CallStateException("no gsm index found");
- }
-
- void hangupAllConnections(GSMCall call) throws CallStateException{
- try {
- int count = call.connections.size();
- for (int i = 0; i < count; i++) {
- GSMConnection cn = (GSMConnection)call.connections.get(i);
- cm.hangupConnection(cn.getGSMIndex(), obtainCompleteMessage());
- }
- } catch (CallStateException ex) {
- Log.e(LOG_TAG, "hangupConnectionByIndex caught " + ex);
- }
- }
-
- /* package */
- GSMConnection getConnectionByIndex(GSMCall call, int index)
- throws CallStateException {
- int count = call.connections.size();
- for (int i = 0; i < count; i++) {
- GSMConnection cn = (GSMConnection)call.connections.get(i);
- if (cn.getGSMIndex() == 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;
- }
-
- //****** Overridden from Handler
-
- public void
- handleMessage (Message msg)
- {
- AsyncResult ar;
-
- switch (msg.what) {
- case EVENT_POLL_CALLS_RESULT:
- 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:
- case EVENT_CONFERENCE_RESULT:
- case EVENT_SEPARATE_RESULT:
- case EVENT_ECT_RESULT:
- ar = (AsyncResult)msg.obj;
- if (ar.exception != null) {
- phone.notifySuppServiceFailed(getFailedService(msg.what));
- }
- 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];
- }
- // Log the causeCode if its not normal
- if (causeCode == CallFailCause.NO_CIRCUIT_AVAIL ||
- causeCode == CallFailCause.TEMPORARY_FAILURE ||
- causeCode == CallFailCause.SWITCHING_CONGESTION ||
- causeCode == CallFailCause.CHANNEL_NOT_AVAIL ||
- causeCode == CallFailCause.QOS_NOT_AVAIL ||
- causeCode == CallFailCause.BEARER_NOT_AVAIL ||
- causeCode == CallFailCause.ERROR_UNSPECIFIED) {
- int cid = -1;
- GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
- if (loc != null) cid = loc.getCid();
-
- EventLog.List val = new EventLog.List(causeCode, cid,
- TelephonyManager.getDefault().getNetworkType());
- EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CALL_DROP, val);
- }
-
- for (int i = 0, s = droppedDuringPoll.size()
- ; i < s ; i++
- ) {
- GSMConnection conn = droppedDuringPoll.get(i);
-
- conn.onRemoteDisconnect(causeCode);
- }
-
- updatePhoneState();
-
- phone.notifyCallStateChanged();
- droppedDuringPoll.clear();
- break;
-
- case EVENT_REPOLL_AFTER_DELAY:
- case EVENT_CALL_STATE_CHANGE:
- pollCallsWhenSafe();
- break;
-
- case EVENT_RADIO_AVAILABLE:
- handleRadioAvailable();
- break;
-
- case EVENT_RADIO_NOT_AVAILABLE:
- handleRadioNotAvailable();
- break;
- }
- }
-
- private void log(String msg) {
- Log.d(LOG_TAG, "[CallTracker] " + msg);
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/CommandException.java b/telephony/java/com/android/internal/telephony/gsm/CommandException.java
deleted file mode 100644
index 5cf48f3..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/CommandException.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.gsm;
-
-import android.util.Log;
-
-/**
- * {@hide}
- */
-public class CommandException extends RuntimeException
-{
- private Error e;
-
- public enum Error {
- INVALID_RESPONSE,
- RADIO_NOT_AVAILABLE,
- GENERIC_FAILURE,
- PASSWORD_INCORRECT,
- SIM_PIN2,
- SIM_PUK2,
- REQUEST_NOT_SUPPORTED,
- OP_NOT_ALLOWED_DURING_VOICE_CALL,
- OP_NOT_ALLOWED_BEFORE_REG_NW,
- SMS_FAIL_RETRY,
- }
-
- public CommandException(Error e)
- {
- super(e.toString());
- this.e = e;
- }
-
- public static CommandException
- fromRilErrno(int ril_errno)
- {
- switch(ril_errno) {
- case RILConstants.SUCCESS: return null;
- case RILConstants.RIL_ERRNO_INVALID_RESPONSE:
- return new CommandException(Error.INVALID_RESPONSE);
- case RILConstants.RADIO_NOT_AVAILABLE:
- return new CommandException(Error.RADIO_NOT_AVAILABLE);
- case RILConstants.GENERIC_FAILURE:
- return new CommandException(Error.GENERIC_FAILURE);
- case RILConstants.PASSWORD_INCORRECT:
- return new CommandException(Error.PASSWORD_INCORRECT);
- case RILConstants.SIM_PIN2:
- return new CommandException(Error.SIM_PIN2);
- case RILConstants.SIM_PUK2:
- return new CommandException(Error.SIM_PUK2);
- 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);
- case RILConstants.OP_NOT_ALLOWED_BEFORE_REG_NW:
- return new CommandException(Error.OP_NOT_ALLOWED_BEFORE_REG_NW);
- case RILConstants.SMS_SEND_FAIL_RETRY:
- return new CommandException(Error.SMS_FAIL_RETRY);
- default:
- Log.e("GSM", "Unrecognized RIL errno " + ril_errno);
- return new CommandException(Error.INVALID_RESPONSE);
- }
- }
-
- public Error getCommandError()
- {
- return e;
- }
-
-
-
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java b/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java
deleted file mode 100644
index 7915798..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/CommandsInterface.java
+++ /dev/null
@@ -1,926 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-import com.android.internal.telephony.*;
-import android.os.Message;
-import android.os.Handler;
-
-/**
- * {@hide}
- */
-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
- personalization, or SIM absent */
- SIM_READY; /* Radio is on and SIM interface is available */
-
- boolean isOn() /* and available...*/
- {
- 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;
- }
- }
-
- enum SimStatus {
- SIM_ABSENT,
- SIM_NOT_READY,
- SIM_READY,
- SIM_PIN,
- SIM_PUK,
- SIM_NETWORK_PERSONALIZATION
- }
-
- //***** Constants
-
- // Used as parameter to dial() and setCLIR() below
- static final int CLIR_DEFAULT = 0; // "use subscription default value"
- static final int CLIR_INVOCATION = 1; // (restrict CLI presentation)
- static final int CLIR_SUPPRESSION = 2; // (allow CLI presentation)
-
-
- // Used as parameters for call forward methods below
- static final int CF_ACTION_DISABLE = 0;
- static final int CF_ACTION_ENABLE = 1;
-// static final int CF_ACTION_UNUSED = 2;
- static final int CF_ACTION_REGISTRATION = 3;
- static final int CF_ACTION_ERASURE = 4;
-
- static final int CF_REASON_UNCONDITIONAL = 0;
- static final int CF_REASON_BUSY = 1;
- static final int CF_REASON_NO_REPLY = 2;
- static final int CF_REASON_NOT_REACHABLE = 3;
- static final int CF_REASON_ALL = 4;
- static final int CF_REASON_ALL_CONDITIONAL = 5;
-
- // Used for call barring methods below
- static final String CB_FACILITY_BAOC = "AO";
- static final String CB_FACILITY_BAOIC = "OI";
- static final String CB_FACILITY_BAOICxH = "OX";
- static final String CB_FACILITY_BAIC = "AI";
- static final String CB_FACILITY_BAICr = "IR";
- static final String CB_FACILITY_BA_ALL = "AB";
- static final String CB_FACILITY_BA_MO = "AG";
- 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
- static final int SERVICE_CLASS_NONE = 0; // no user input
- static final int SERVICE_CLASS_VOICE = (1 << 0);
- 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_ASYNC = (1 << 5);
- static final int SERVICE_CLASS_PACKET = (1 << 6);
- static final int SERVICE_CLASS_PAD = (1 << 7);
- static final int SERVICE_CLASS_MAX = (1 << 7); // Max SERVICE_CLASS value
-
- // Numeric representation of string values returned
- // by messages sent to setOnUSSD handler
- static final int USSD_MODE_NOTIFY = 0;
- static final int USSD_MODE_REQUEST = 1;
-
- // SIM Refresh results, passed up from RIL.
- static final int SIM_REFRESH_FILE_UPDATED = 0; // Single file updated
- static final int SIM_REFRESH_INIT = 1; // SIM initialized; reload all
- static final int SIM_REFRESH_RESET = 2; // SIM reset; may be locked
-
- //***** Methods
-
- RadioState getRadioState();
-
- /**
- * Fires on any RadioState transition
- * Always fires immediately as well
- *
- * do not attempt to calculate transitions by storing getRadioState() values
- * on previous invocations of this notification. Instead, use the other
- * registration methods
- */
- void registerForRadioStateChanged(Handler h, int what, Object obj);
-
- /**
- * 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);
-
- /**
- * 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);
- /**
- * 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);
- /**
- * 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);
-
- /**
- * 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);
- /** Any transition into SIM_LOCKED_OR_ABSENT */
- void registerForSIMLockedOrAbsent(Handler h, int what, Object obj);
- //void unregisterForSIMLockedOrAbsent(Handler h);
-
- void registerForCallStateChanged(Handler h, int what, Object obj);
- //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);
-
- /**
- * unlike the register* methods, there's only one new SMS handler
- * if you need to unregister, you should also tell the radio to stop
- * sending SMS's to you (via AT+CNMI)
- *
- * AsyncResult.result is a String containing the SMS PDU
- */
- void setOnNewSMS(Handler h, int what, Object obj);
-
- /**
- * 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);
-
- /**
- * 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);
-
- /**
- * unlike the register* methods, there's only one NITZ time handler
- *
- * AsyncResult.result is an Object[]
- * ((Object[])AsyncResult.result)[0] is a String containing the NITZ time string
- * ((Object[])AsyncResult.result)[1] is a Long containing the milliseconds since boot as
- * returned by elapsedRealtime() when this NITZ time
- * was posted.
- *
- * Please note that the delivery of this message may be delayed several
- * seconds on system startup
- */
- void setOnNITZTime(Handler h, int what, Object obj);
-
- /**
- * 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]
- * "1" USSD-Request -- text in ((const char **)data)[1]
- * "2" Session terminated by network
- * "3" other local client (eg, SIM Toolkit) has responded
- * "4" Operation not supported
- * "5" Network timeout
- *
- * ((String[])(AsyncResult.result))[1] contains the USSD message
- * The numeric representations of these are in USSD_MODE_*
- */
-
- void setOnUSSD(Handler h, int what, Object obj);
-
- /**
- * 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)
- * as defined in TS 27.007 8.5
- */
-
- void setOnSignalStrengthUpdate(Handler h, int what, Object obj);
-
- /**
- * Sets the handler for SIM 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);
-
- /**
- * Sets the handler for SIM Refresh notifications.
- * 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 setOnSimRefresh(Handler h, int what, Object obj);
-
- /**
- * Sets the handler for RING notifications.
- * 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 setOnCallRing(Handler h, int what, Object obj);
-
- /**
- * Sets the handler for RESTRICTED_STATE changed notification,
- * eg, for Domain Specific Access Control
- * unlike the register* methods, there's only one signal strength handler
- *
- * AsyncResult.result is an int[1]
- * response.obj.result[0] is a bitmask of RIL_RESTRICTED_STATE_* values
- */
-
- void setOnRestrictedStateChanged(Handler h, int what, Object obj);
-
- /**
- * Sets the handler for Supplementary Service Notifications.
- * 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 setOnSuppServiceNotification(Handler h, int what, Object obj);
-
- /**
- * Sets the handler for Session End Notifications for STK.
- * 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 setOnStkSessionEnd(Handler h, int what, Object obj);
-
- /**
- * Sets the handler for Proactive Commands for STK.
- * 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 setOnStkProactiveCmd(Handler h, int what, Object obj);
-
- /**
- * Sets the handler for Event Notifications for STK.
- * 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 setOnStkEvent(Handler h, int what, Object obj);
-
- /**
- * Sets the handler for Call Set Up Notifications for STK.
- * 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 setOnStkCallSetUp(Handler h, int what, Object obj);
-
- /**
- * Enables/disbables supplementary service related notifications from
- * the network.
- *
- * @param enable true to enable notifications, false to disable.
- * @param result Message to be posted when command completes.
- */
- void setSuppServiceNotifications(boolean enable, Message result);
-
- /**
- * Returns current SIM status.
- *
- * AsyncResult.result is SimStatus
- *
- */
-
- void getSimStatus(Message result);
-
- /**
- * Supply the SIM PIN to the SIM card
- *
- * returned message
- * retMsg.obj = AsyncResult ar
- * ar.exception carries exception on failure
- * This exception is CommandException with an error of PASSWORD_INCORRECT
- * if the password is incorrect
- *
- * ar.exception and ar.result are null on success
- */
-
- void supplySimPin(String pin, Message result);
-
- /**
- * Supply the SIM PUK to the SIM card
- *
- * returned message
- * retMsg.obj = AsyncResult ar
- * ar.exception carries exception on failure
- * This exception is CommandException with an error of PASSWORD_INCORRECT
- * if the password is incorrect
- *
- * ar.exception and ar.result are null on success
- */
-
- void supplySimPuk(String puk, String newPin, Message result);
-
- /**
- * Supply the SIM PIN2 to the SIM card
- * Only called following operation where SIM_PIN2 was
- * returned as a a failure from a previous operation
- *
- * returned message
- * retMsg.obj = AsyncResult ar
- * ar.exception carries exception on failure
- * This exception is CommandException with an error of PASSWORD_INCORRECT
- * if the password is incorrect
- *
- * ar.exception and ar.result are null on success
- */
-
- void supplySimPin2(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
- * This exception is CommandException with an error of PASSWORD_INCORRECT
- * if the password is incorrect
- *
- * ar.exception and ar.result are null on success
- */
-
- void supplySimPuk2(String puk2, String newPin2, Message result);
-
- void changeSimPin(String oldPin, String newPin, Message result);
- void changeSimPin2(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
- * ar.userObject contains the orignal value of result.obj
- * ar.result contains a List of DriverCall
- * The ar.result List is sorted by DriverCall.index
- */
- 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
- */
- 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 is null on success and failure
- *
- * CLIR_DEFAULT == on "use subscription default value"
- * CLIR_SUPPRESSION == on "CLIR suppression" (allow CLI presentation)
- * CLIR_INVOCATION == on "CLIR invocation" (restrict CLI presentation)
- */
- void dial (String address, int clirMode, Message result);
-
- /**
- * returned message
- * retMsg.obj = AsyncResult ar
- * ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
- * ar.result is String containing IMSI on success
- */
- void getIMSI(Message result);
-
- /**
- * returned message
- * retMsg.obj = AsyncResult ar
- * ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
- * ar.result is String containing IMEI on success
- */
- void getIMEI(Message result);
-
- /**
- * returned message
- * retMsg.obj = AsyncResult ar
- * ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
- * ar.result is String containing IMEISV on success
- */
- void getIMEISV(Message result);
-
- /**
- * Hang up one individual connection.
- * returned message
- * retMsg.obj = AsyncResult ar
- * ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
- * ar.result is null on success and failure
- *
- * 3GPP 22.030 6.5.5
- * "Releases a specific active call X"
- */
- void hangupConnection (int gsmIndex, Message result);
-
- /**
- * 3GPP 22.030 6.5.5
- * "Releases all held calls or sets User Determined User Busy (UDUB)
- * for a waiting call."
- * ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
- * ar.result is null on success and failure
- */
- void hangupWaitingOrBackground (Message result);
-
- /**
- * 3GPP 22.030 6.5.5
- * "Releases all active calls (if any exist) and accepts
- * the other (held or waiting) call."
- *
- * ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
- * ar.result is null on success and failure
- */
- void hangupForegroundResumeBackground (Message result);
-
- /**
- * 3GPP 22.030 6.5.5
- * "Places all active calls (if any exist) on hold and accepts
- * the other (held or waiting) call."
- *
- * ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
- * ar.result is null on success and failure
- */
- void switchWaitingOrHoldingAndActive (Message result);
-
- /**
- * 3GPP 22.030 6.5.5
- * "Adds a held call to the conversation"
- *
- * 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);
-
- /**
- * 3GPP 22.030 6.5.5
- * "Places all active calls on hold except call X with which
- * communication shall be supported."
- */
- void separateConnection (int gsmIndex, Message result);
-
- /**
- *
- * 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);
-
- /**
- * 3GPP 22.030 6.5.5
- * "Connects the two calls and disconnects the subscriber from both calls"
- *
- * ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
- * ar.result is null on success and failure
- */
- void explicitCallTransfer (Message result);
-
- /**
- * cause code returned as int[0] in Message.obj.response
- * Returns integer cause code defined in TS 24.008
- * Annex H or closest approximation.
- * Most significant codes:
- * - Any defined in 22.001 F.4 (for generating busy/congestion)
- * - Cause 68: ACM >= ACMMax
- */
- 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
- */
- void getLastPdpFailCause (Message result);
-
- void setMute (boolean enableMute, Message response);
-
- void getMute (Message response);
-
- /**
- * 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)
- * as defined in TS 27.007 8.5
- */
- void getSignalStrength (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
- * 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
- * valid LAC and CIDs are 0x0000 - 0xffff
- *
- * Please note that registration state 4 ("unknown") is treated
- * as "out of service" above
- */
- void getGPRSRegistrationState (Message response);
-
- /**
- * response.obj.result is a String[3]
- * 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);
-
-
- /**
- * ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
- * ar.result is null on success and failure
- */
- void startDtmf(char c, Message result);
-
- /**
- * ar.exception carries exception on failure
- * ar.userObject contains the orignal value of result.obj
- * ar.result is null on success and failure
- */
- void stopDtmf(Message result);
-
-
- /**
- * 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
- */
- void sendSMS (String smscPDU, String 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);
-
- /**
- * 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
- * @param pdu message PDU, as hex string
- * @param response sent when operation completes.
- * response.obj will be an AsyncResult, and will indicate
- * any error that may have occurred (eg, out of memory).
- */
- void writeSmsToSim(int status, String smsc, String pdu, Message response);
-
- void setupDefaultPDP(String apn, String user, String password, Message 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
- * response.obj will be an AsyncResult
- * response.obj.userObj will be a SimIoResult on success
- */
- void simIO (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".
- *
- * @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
- *
- * 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
- */
-
- 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.
- *
- * @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_*
- */
- 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,
- String number, Message response);
-
- void setNetworkSelectionModeAutomatic(Message response);
-
- void setNetworkSelectionModeManual(String operatorNumeric, Message response);
-
- /**
- * Queries whether the current network selection mode is automatic
- * or manual
- *
- * ((AsyncResult)response.obj).result is an int[] with element [0] being
- * a 0 for automatic selection and a 1 for manual selection
- */
-
- void getNetworkSelectionMode(Message response);
-
- /**
- * Queries the currently available networks
- *
- * ((AsyncResult)response.obj).result is a List of NetworkInfo objects
- */
- void getAvailableNetworks(Message response);
-
- void getBasebandVersion (Message response);
-
-
- /**
- * (AsyncResult)response.obj).result will be an Integer representing
- * the sum of enabled serivice classes (sum of SERVICE_CLASS_*)
- *
- * @param facility one of CB_FACILTY_*
- * @param password password or "" if not required
- * @param serviceClass is a sum of SERVICE_CLASS_*
- * @param response is callback message
- */
-
- void queryFacilityLock (String facility, String password, int serviceClass,
- Message response);
-
- /**
- * @param facility one of CB_FACILTY_*
- * @param lockState true means lock, false means unlock
- * @param password password or "" if not required
- * @param serviceClass is a sum of SERVICE_CLASS_*
- * @param response is callback message
- */
- void setFacilityLock (String facility, boolean lockState, String password,
- int serviceClass, Message response);
-
-
- void sendUSSD (String ussdString, Message response);
-
- /**
- * Cancels a pending USSD session if one exists.
- * @param response callback message
- */
- void cancelPendingUssd (Message response);
-
- void resetRadio(Message result);
-
- /**
- * Assign a specified band for RF configuration.
- *
- * @param bandMode one of BM_*_BAND
- * @param response is callback message
- */
- void setBandMode (int bandMode, Message response);
-
- /**
- * 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
- */
- void queryAvailableBandMode (Message response);
-
- /**
- * Requests to set the preferred network type for searching and registering
- * (CS/PS domain, RAT, and operation mode)
- * @param networkType one of NT_*_TYPE
- * @param response is callback message
- */
- void setPreferredNetworkType(int networkType , Message response);
-
- /**
- * Query the preferred network type setting
- *
- * @param response is callback message to report one of NT_*_TYPE
- */
- void getPreferredNetworkType(Message response);
-
- /**
- * Query neighboring cell ids
- *
- * @param response s callback message to cell ids
- */
- void getNeighboringCids(Message response);
-
- /**
- * Request to enable/disable network state change notifications when
- * location informateion (lac and/or cid) has changed.
- *
- * @param enable true to enable, false to disable
- * @param response callback message
- */
- void setLocationUpdates(boolean enable, Message response);
-
-
- void invokeOemRilRequestRaw(byte[] data, Message response);
-
- void invokeOemRilRequestStrings(String[] strings, Message response);
-
-
- /**
- * Send TERMINAL RESPONSE to the SIM, after processing a proactive command
- * sent by the SIM.
- *
- * @param contents String containing SAT/USAT response in hexadecimal
- * format starting with first byte of response data. See
- * TS 102 223 for details.
- * @param response Callback message
- */
- public void sendTerminalResponse(String contents, Message response);
-
- /**
- * Send ENVELOPE to the SIM, after processing a proactive command sent by
- * the SIM.
- *
- * @param contents String containing SAT/USAT response in hexadecimal
- * format starting with command tag. See TS 102 223 for
- * details.
- * @param response Callback message
- */
- public void sendEnvelope(String contents, Message response);
-
- /**
- * Accept or reject the call setup request from SIM.
- *
- * @param accept true if the call is to be accepted, false otherwise.
- * @param response Callback message
- */
- public void handleCallSetupRequestFromSim(boolean accept, Message response);
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java
deleted file mode 100644
index 02a6841..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/DataConnectionTracker.java
+++ /dev/null
@@ -1,1836 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiManager;
-import android.net.Uri;
-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.Telephony;
-import android.provider.Settings.SettingNotFoundException;
-import android.telephony.ServiceState;
-import android.telephony.TelephonyManager;
-import android.telephony.gsm.GsmCellLocation;
-import android.text.TextUtils;
-import android.util.EventLog;
-import android.util.Log;
-
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.gsm.PdpConnection.PdpFailCause;
-
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * {@hide}
- */
-final class DataConnectionTracker extends Handler
-{
- private static final String LOG_TAG = "GSM";
- private static final boolean DBG = true;
-
- /**
- * IDLE: ready to start data connection setup, default state
- * INITING: state of issued setupDefaultPDP() but not finish yet
- * CONNECTING: state of issued startPppd() but not finish yet
- * SCANNING: data connection fails with one apn but other apns are available
- * ready to start data connection on other apns (before INITING)
- * CONNECTED: IP connection is setup
- * DISCONNECTING: PdpConnection.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
- */
- enum State {
- IDLE,
- INITING,
- CONNECTING,
- SCANNING,
- CONNECTED,
- DISCONNECTING,
- FAILED
- }
-
- enum Activity {
- NONE,
- DATAIN,
- DATAOUT,
- DATAINANDOUT
- }
-
- /**
- * Handles changes to the APN db.
- */
- private class ApnChangeObserver extends ContentObserver {
- public ApnChangeObserver () {
- super(mDataConnectionTracker);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- sendMessage(obtainMessage(EVENT_APN_CHANGED));
- }
- }
-
- //***** Instance Variables
-
- GSMPhone phone;
- INetStatService netstat;
- State state = State.IDLE;
- Activity activity = Activity.NONE;
- boolean netStatPollEnabled = false;
- // Indicates baseband will not auto-attach
- private boolean noAutoAttach = false;
- long nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- Handler mDataConnectionTracker = null;
- private ContentResolver mResolver;
-
- long txPkts, rxPkts, sentSinceLastRecv;
- int netStatPollPeriod;
- private int mNoRecvPollCount = 0;
- private boolean mPingTestActive = false;
- // Count of PDP reset attempts; reset when we see incoming,
- // call reRegisterNetwork, or pingTest succeeds.
- private int mPdpResetCount = 0;
- private boolean mIsScreenOn = true;
-
- //useful for debugging
- boolean failNextConnect = false;
-
- /**
- * allApns holds all apns for this sim spn, retrieved from
- * the Carrier DB.
- *
- * Create once after simcard info is loaded
- */
- private ArrayList allApns = null;
-
- /**
- * waitingApns holds all apns that are waiting to be connected
- *
- * It is a subset of allApns and has the same format
- */
- private ArrayList waitingApns = null;
-
- private ApnSetting preferredApn = null;
-
- /**
- * pdpList holds all the PDP connection, i.e. IP Link in GPRS
- */
- private ArrayList pdpList;
-
- /** CID of active PDP */
- int cidActive;
-
- /** Currently requested APN type */
- private String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
-
- /** Currently active APN */
- private ApnSetting mActiveApn;
-
- /** Currently active PdpConnection */
- private PdpConnection mActivePdp;
-
- private static int APN_DEFAULT_ID = 0;
- private static int APN_MMS_ID = 1;
- private static int APN_NUM_TYPES = 2;
-
- private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
-
- /** wifi connection status will be updated by sticky intent */
- private boolean mIsWifiConnected = false;
-
- /** Intent sent when the reconnect alarm fires. */
- private PendingIntent mReconnectIntent = null;
-
- /** Is packet service restricted by network */
- private boolean mIsPsRestricted = false;
-
- //***** Constants
-
- // TODO: Increase this to match the max number of simultaneous
- // PDP contexts we plan to support.
- /**
- * Pool size of PdpConnection objects.
- */
- private static final int PDP_CONNECTION_POOL_SIZE = 1;
-
- private static final int POLL_PDP_MILLIS = 5 * 1000;
- private static final int RECONNECT_DELAY_INITIAL_MILLIS = 5 * 1000;
- /** Cap out with 1 hour retry interval. */
- private static final int RECONNECT_DELAY_MAX_MILLIS = 60 * 60 * 1000;
-
- /** Slow poll when attempting connection recovery. */
- private static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
-
- /** Default ping deadline, in seconds. */
- private static final int DEFAULT_PING_DEADLINE = 5;
- /** Default max failure count before attempting to network re-registration. */
- private static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
-
- /**
- * After detecting a potential connection problem, this is the max number
- * of subsequent polls before attempting a radio reset. At this point,
- * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to
- * poll for about 2 more minutes.
- */
- private static final int NO_RECV_POLL_LIMIT = 24;
-
- // 1 sec. default polling interval when screen is on.
- private static final int POLL_NETSTAT_MILLIS = 1000;
- // 10 min. default polling interval when screen is off.
- private static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
- // 2 min for round trip time
- private static final int POLL_LONGEST_RTT = 120 * 1000;
- // 10 for packets without ack
- private static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
- // how long to wait before switching back to default APN
- private static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
- // system property that can override the above value
- private static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
- // represents an invalid IP address
- private static final String NULL_IP = "0.0.0.0";
-
- private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect";
- private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
-
-
- //***** Event Codes
- static final int EVENT_DATA_SETUP_COMPLETE = 1;
- static final int EVENT_RADIO_AVAILABLE = 3;
- static final int EVENT_RECORDS_LOADED = 4;
- static final int EVENT_TRY_SETUP_DATA = 5;
- static final int EVENT_PDP_STATE_CHANGED = 6;
- static final int EVENT_POLL_PDP = 7;
- static final int EVENT_GET_PDP_LIST_COMPLETE = 11;
- static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12;
- static final int EVENT_VOICE_CALL_STARTED = 14;
- static final int EVENT_VOICE_CALL_ENDED = 15;
- static final int EVENT_GPRS_DETACHED = 19;
- static final int EVENT_LINK_STATE_CHANGED = 20;
- static final int EVENT_ROAMING_ON = 21;
- static final int EVENT_ROAMING_OFF = 22;
- static final int EVENT_ENABLE_NEW_APN = 23;
- static final int EVENT_RESTORE_DEFAULT_APN = 24;
- static final int EVENT_DISCONNECT_DONE = 25;
- static final int EVENT_GPRS_ATTACHED = 26;
- static final int EVENT_START_NETSTAT_POLL = 27;
- static final int EVENT_START_RECOVERY = 28;
- static final int EVENT_APN_CHANGED = 29;
- static final int EVENT_PS_RESTRICT_ENABLED = 30;
- static final int EVENT_PS_RESTRICT_DISABLED = 31;
-
- static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn");
- static final String APN_ID = "apn_id";
- private boolean canSetPreferApn = false;
-
- 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, "GPRS 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;
- }
- }
- }
- };
-
- /** Watches for changes to the APN db. */
- private ApnChangeObserver apnObserver;
-
- //***** Constructor
-
- DataConnectionTracker(GSMPhone phone)
- {
- this.phone = phone;
- phone.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
- phone.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
- phone.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
- phone.mCM.registerForPDPStateChanged (this, EVENT_PDP_STATE_CHANGED, null);
- phone.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
- phone.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
- phone.mSST.registerForGprsAttached(this, EVENT_GPRS_ATTACHED, null);
- phone.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null);
- phone.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null);
- phone.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
- phone.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null);
- phone.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, 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);
-
- phone.getContext().registerReceiver(mIntentReceiver, filter, null, phone.h);
-
-
- mDataConnectionTracker = this;
- mResolver = phone.getContext().getContentResolver();
-
- apnObserver = new ApnChangeObserver();
- phone.getContext().getContentResolver().registerContentObserver(
- Telephony.Carriers.CONTENT_URI, true, apnObserver);
-
- createAllPdpList();
-
- // 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[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
- noAutoAttach = !dataEnabled[APN_DEFAULT_ID];
- }
-
- void setState(State s) {
- if (DBG) log ("setState: " + s);
- if (state != s) {
- if (s == State.INITING) { // request PDP context
- Checkin.updateStats(
- phone.getContext().getContentResolver(),
- Checkin.Stats.Tag.PHONE_GPRS_ATTEMPTED, 1, 0.0);
- }
-
- if (s == State.CONNECTED) { // pppd is up
- Checkin.updateStats(
- phone.getContext().getContentResolver(),
- Checkin.Stats.Tag.PHONE_GPRS_CONNECTED, 1, 0.0);
- }
- }
-
- state = s;
-
- if (state == State.FAILED) {
- if (waitingApns != null)
- waitingApns.clear(); // when teardown the connection and set to IDLE
- }
- }
-
- 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";
- }
- }
-
- String[] getActiveApnTypes() {
- String[] result;
- if (mActiveApn != null) {
- result = mActiveApn.types;
- } else {
- result = new String[1];
- result[0] = Phone.APN_TYPE_DEFAULT;
- }
- return result;
- }
-
- String getActiveApnString() {
- String result = null;
- if (mActiveApn != null) {
- result = mActiveApn.apn;
- }
- return result;
- }
-
- /**
- * Ensure that we are connected to an APN of the specified type.
- * @param type the APN type (currently the only valid value
- * is {@link Phone#APN_TYPE_MMS})
- * @return the result of the operation. Success is indicated by
- * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or
- * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast
- * will be sent by the ConnectivityManager when a connection to
- * the APN has been established.
- */
- int enableApnType(String type) {
- if (!TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- return Phone.APN_REQUEST_FAILED;
- }
- // If already active, return
- Log.d(LOG_TAG, "enableApnType("+type+")");
- if (isApnTypeActive(type)) {
- setEnabled(type, true);
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- /**
- * We're being asked to enable a non-default APN that's already in use.
- * This means we should restart the timer that will automatically
- * switch back to the default APN and disable the non-default APN
- * when it expires.
- */
- sendMessageDelayed(
- obtainMessage(EVENT_RESTORE_DEFAULT_APN),
- getRestoreDefaultApnDelay());
- if (state == State.INITING) return Phone.APN_REQUEST_STARTED;
- else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE;
- }
-
- if (!isApnTypeAvailable(type)) {
- return Phone.APN_TYPE_NOT_AVAILABLE;
- }
-
- setEnabled(type, true);
- mRequestedApnType = type;
- sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN));
- return Phone.APN_REQUEST_STARTED;
- }
-
- /**
- * The APN of the specified type is no longer needed. Ensure that if
- * use of the default APN has not been explicitly disabled, we are connected
- * to the default APN.
- * @param type the APN type. The only valid value currently is {@link Phone#APN_TYPE_MMS}.
- * @return
- */
- int disableApnType(String type) {
- Log.d(LOG_TAG, "disableApnType("+type+")");
- if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- setEnabled(type, false);
- if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
- if (dataEnabled[APN_DEFAULT_ID]) {
- return Phone.APN_ALREADY_ACTIVE;
- } else {
- cleanUpConnection(true, Phone.REASON_DATA_DISABLED);
- return Phone.APN_REQUEST_STARTED;
- }
- } else {
- /*
- * Note that if default data is disabled, the following
- * has the effect of disabling the MMS APN, and then
- * ignoring the request to enable the default APN.
- * The net result is that data is completely disabled.
- */
- sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN));
- return Phone.APN_REQUEST_STARTED;
- }
- } else {
- return Phone.APN_REQUEST_FAILED;
- }
- }
-
- /**
- * The data connection is expected to be setup while device
- * 1. has sim card
- * 2. registered to gprs service
- * 3. user doesn't explicitly disable data service
- * 4. wifi is not on
- * 5. packet service is not restricted
- *
- * @return false while no data connection if all above requirements are met.
- */
- boolean isDataConnectionAsDesired() {
- boolean roaming = phone.getServiceState().getRoaming();
-
- if (phone.mSIMRecords.getRecordsLoaded() &&
- phone.mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE &&
- (!roaming || getDataOnRoamingEnabled()) &&
- !mIsWifiConnected &&
- !mIsPsRestricted ) {
- return (state == State.CONNECTED);
- }
- return true;
- }
-
- private boolean isApnTypeActive(String type) {
- // TODO: to support simultaneous, mActiveApn can be a List instead.
- return mActiveApn != null && mActiveApn.canHandleType(type);
- }
-
- private boolean isApnTypeAvailable(String type) {
- if (allApns != null) {
- for (ApnSetting apn : allApns) {
- if (apn.canHandleType(type)) {
- return true;
- }
- }
- }
- return false;
- }
-
- private boolean isEnabled(String apnType) {
- if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) {
- return dataEnabled[APN_DEFAULT_ID];
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) {
- return dataEnabled[APN_MMS_ID];
- } else {
- return false;
- }
- }
-
- private void setEnabled(String apnType, boolean enable) {
- Log.d(LOG_TAG, "setEnabled(" + apnType + ", " + enable + ')');
- if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) {
- dataEnabled[APN_DEFAULT_ID] = enable;
- } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) {
- dataEnabled[APN_MMS_ID] = enable;
- }
- Log.d(LOG_TAG, "dataEnabled[DEFAULT_APN]=" + dataEnabled[APN_DEFAULT_ID] +
- " dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID]);
- }
-
- /**
- * Prevent mobile data connections from being established,
- * or once again allow mobile data connections. If the state
- * toggles, then either tear down or set up data, as
- * appropriate to match the new state.
- * This operation only affects the default APN, and if the same APN is
- * currently being used for MMS traffic, the teardown will not happen
- * even when {@code enable} is {@code false}.
- * @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(Phone.APN_TYPE_DEFAULT);
- Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled);
- if (!isEnabled && enable) {
- setEnabled(Phone.APN_TYPE_DEFAULT, true);
- // trySetupData() will be a no-op if we are currently
- // connected to the MMS APN
- return trySetupData(Phone.REASON_DATA_ENABLED);
- } else if (!enable) {
- setEnabled(Phone.APN_TYPE_DEFAULT, false);
- // Don't tear down if there is an active APN and it handles MMS.
- // TODO: This isn't very general.
- if (!isApnTypeActive(Phone.APN_TYPE_MMS) || !isEnabled(Phone.APN_TYPE_MMS)) {
- cleanUpConnection(true, Phone.REASON_DATA_DISABLED);
- return true;
- }
- return false;
- } else // isEnabled && enable
- return true;
- }
-
- /**
- * Simply tear down data connections due to radio off
- * and don't setup again.
- */
- public void cleanConnectionBeforeRadioOff() {
- cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
- }
-
- /**
- * Report the current state of data connectivity (enabled or disabled) for
- * the default APN.
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getDataEnabled() {
- return dataEnabled[APN_DEFAULT_ID];
- }
-
- /**
- * Report on whether data connectivity is enabled for any APN.
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getAnyDataEnabled() {
- return dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID];
- }
-
- //The data roaming setting is now located in the shared preferences.
- // See if the requested preference value is the same as that stored in
- // the shared values. If it is not, then update it.
- public void setDataOnRoamingEnabled(boolean enabled) {
- if (getDataOnRoamingEnabled() != enabled) {
- Settings.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;
- }
- }
-
- public ArrayList getAllPdps() {
- ArrayList pdps = (ArrayList)pdpList.clone();
- return pdps;
- }
-
- private boolean isDataAllowed() {
- boolean roaming = phone.getServiceState().getRoaming();
- return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled());
- }
-
- //****** Called from ServiceStateTracker
- /**
- * Invoked when ServiceStateTracker observes a transition from GPRS
- * attach to detach.
- */
- private void onGprsDetached()
- {
- /*
- * We presently believe it is unnecessary to tear down the PDP context
- * when GPRS detaches, but we should stop the network polling.
- */
- stopNetStatPoll();
- phone.notifyDataConnection(Phone.REASON_GPRS_DETACHED);
- }
-
- private void onGprsAttached() {
- if (state == State.CONNECTED) {
- startNetStatPoll();
- phone.notifyDataConnection(Phone.REASON_GPRS_ATTACHED);
- } else {
- if (state == State.FAILED) {
- cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- }
- trySetupData(Phone.REASON_GPRS_ATTACHED);
- }
- }
-
- private boolean trySetupData(String reason)
- {
- if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason));
-
- Log.d(LOG_TAG, "[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted);
-
- 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 gprsState = phone.mSST.getCurrentGprsState();
- boolean roaming = phone.getServiceState().getRoaming();
-
- if ((state == State.IDLE || state == State.SCANNING)
- && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach)
- && phone.mSIMRecords.getRecordsLoaded()
- && phone.getState() == Phone.State.IDLE
- && isDataAllowed()
- && !mIsPsRestricted ) {
-
- if (state == State.IDLE) {
- waitingApns = buildWaitingApns();
- if (waitingApns.isEmpty()) {
- if (DBG) log("No APN found");
- notifyNoData(PdpConnection.PdpFailCause.BAD_APN);
- return false;
- } else {
- log ("Create from allApns : " + apnListToString(allApns));
- }
- }
-
- if (DBG) {
- log ("Setup watingApns : " + apnListToString(waitingApns));
- }
- return setupData(reason);
- } else {
- if (DBG)
- log("trySetupData: Not ready for data: " +
- " dataState=" + state +
- " gprsState=" + gprsState +
- " sim=" + phone.mSIMRecords.getRecordsLoaded() +
- " UMTS=" + phone.mSST.isConcurrentVoiceAndData() +
- " phoneState=" + phone.getState() +
- " dataEnabled=" + getAnyDataEnabled() +
- " roaming=" + roaming +
- " dataOnRoamingEnable=" + getDataOnRoamingEnabled() +
- " ps restricted=" + mIsPsRestricted);
- 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 PdpConnection 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 (PdpConnection pdp : pdpList) {
- if (tearDown) {
- Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
- pdp.disconnect(msg);
- } else {
- pdp.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 pdp.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);
- mActiveApn = null;
- } else if (state != State.IDLE) {
- setState(State.DISCONNECTING);
- }
- }
-
- /**
- * @param types comma delimited list of APN types
- * @return array of APN types
- */
- private String[] parseTypes(String types) {
- String[] result;
- // If unset, set to DEFAULT.
- if (types == null || types.equals("")) {
- result = new String[1];
- result[0] = Phone.APN_TYPE_ALL;
- } else {
- result = types.split(",");
- }
- return result;
- }
-
- private ArrayList createApnList(Cursor cursor) {
- ArrayList result = new ArrayList();
- if (cursor.moveToFirst()) {
- do {
- String[] types = parseTypes(
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
- ApnSetting apn = new ApnSetting(
- cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
- cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
- types);
- result.add(apn);
- } while (cursor.moveToNext());
- }
- return result;
- }
-
- private PdpConnection findFreePdp() {
- for (PdpConnection pdp : pdpList) {
- if (pdp.getState() == PdpConnection.PdpState.INACTIVE) {
- return pdp;
- }
- }
- return null;
- }
-
- private boolean setupData(String reason) {
- ApnSetting apn;
- PdpConnection pdp;
-
- apn = getNextApn();
- if (apn == null) return false;
- pdp = findFreePdp();
- if (pdp == null) {
- if (DBG) log("setupData: No free PdpConnection found!");
- return false;
- }
- mActiveApn = apn;
- mActivePdp = pdp;
-
- Message msg = obtainMessage();
- msg.what = EVENT_DATA_SETUP_COMPLETE;
- msg.obj = reason;
- pdp.connect(apn, msg);
-
- setState(State.INITING);
- phone.notifyDataConnection(reason);
- return true;
- }
-
- String getInterfaceName(String apnType) {
- if (mActivePdp != null
- && (apnType == null || mActiveApn.canHandleType(apnType))) {
- return mActivePdp.getInterface();
- }
- return null;
- }
-
- String getIpAddress(String apnType) {
- if (mActivePdp != null
- && (apnType == null || mActiveApn.canHandleType(apnType))) {
- return mActivePdp.getIpAddress();
- }
- return null;
- }
-
- String getGateway(String apnType) {
- if (mActivePdp != null
- && (apnType == null || mActiveApn.canHandleType(apnType))) {
- return mActivePdp.getGatewayAddress();
- }
- return null;
- }
-
- String[] getDnsServers(String apnType) {
- if (mActivePdp != null
- && (apnType == null || mActiveApn.canHandleType(apnType))) {
- return mActivePdp.getDnsServers();
- }
- return null;
- }
-
- private boolean
- pdpStatesHasCID (ArrayList states, int cid)
- {
- for (int i = 0, s = states.size() ; i < s ; i++) {
- if (states.get(i).cid == cid) return true;
- }
-
- return false;
- }
-
- private boolean
- pdpStatesHasActiveCID (ArrayList states, int cid)
- {
- for (int i = 0, s = states.size() ; i < s ; i++) {
- if (states.get(i).cid == cid) return states.get(i).active;
- }
-
- return false;
- }
-
- /**
- * Handles changes to the APN database.
- */
- private void onApnChanged() {
- boolean isConnected;
-
- isConnected = (state != State.IDLE && state != State.FAILED);
-
- // The "current" may no longer be valid. MMS depends on this to send properly.
- phone.updateCurrentCarrierInProvider();
-
- // TODO: It'd be nice to only do this if the changed entrie(s)
- // match the current operator.
- createAllApnList();
- if (state != State.DISCONNECTING) {
- cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED);
- if (!isConnected) {
- trySetupData(Phone.REASON_APN_CHANGED);
- }
- }
- }
-
- /**
- * @param explicitPoll if true, indicates that *we* polled for this
- * update while state == CONNECTED rather than having it delivered
- * via an unsolicited response (which could have happened at any
- * previous state
- */
- private void
- onPdpStateChanged (AsyncResult ar, boolean explicitPoll)
- {
- ArrayList pdpStates;
-
- pdpStates = (ArrayList)(ar.result);
-
- 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;
- }
-
-
- // This is how things are supposed to work:
- // The PDP list is supposed to be empty of the CID
- // when it disconnects
-
- if (state == State.CONNECTED
- && !pdpStatesHasCID(pdpStates, cidActive)) {
-
- // It looks like the PDP context has deactivated
- // Tear everything down and try to reconnect
-
- Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting");
-
- // Add an event log when the network drops PDP
- int cid = -1;
- GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
- if (loc != null) cid = loc.getCid();
-
- EventLog.List val = new EventLog.List(cid,
- TelephonyManager.getDefault().getNetworkType());
-
- EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
-
- cleanUpConnection(true, null);
-
- return;
- }
-
- if (true) {
- //
- // Workaround for issue #655426
- //
-
- // --------------------------
-
- // This is how some things work now: the PDP context is still
- // listed with active = false, which makes it hard to
- // distinguish an activating context from an activated-and-then
- // deactivated one.
- //
- // Here, we only consider this authoritative if we asked for the
- // PDP list. If it was an unsolicited response, we poll again
- // to make sure everyone agrees on the initial state
-
- if (state == State.CONNECTED
- && !pdpStatesHasActiveCID(pdpStates, cidActive)) {
-
- if (!explicitPoll) {
- // We think it disconnected but aren't sure...poll from our side
- phone.mCM.getPDPContextList(
- this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
- } else {
- Log.i(LOG_TAG, "PDP connection has dropped (active=false case). "
- + " Reconnecting");
-
- // Log the network drop on the event log.
- int cid = -1;
- GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
- if (loc != null) cid = loc.getCid();
-
- EventLog.List val = new EventLog.List(cid,
- TelephonyManager.getDefault().getNetworkType());
-
- EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
-
- cleanUpConnection(true, null);
- }
- }
- }
- }
-
- private void notifyDefaultData(String reason) {
- setupDnsProperties();
- setState(State.CONNECTED);
- phone.notifyDataConnection(reason);
- startNetStatPoll();
- // reset reconnect timer
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- }
-
- private void setupDnsProperties() {
- int mypid = android.os.Process.myPid();
- String[] servers = getDnsServers(null);
- String propName;
- String propVal;
- int count;
-
- count = 0;
- for (int i = 0; i < servers.length; i++) {
- String serverAddr = servers[i];
- if (!TextUtils.equals(serverAddr, "0.0.0.0")) {
- SystemProperties.set("net.dns" + (i+1) + "." + mypid, serverAddr);
- count++;
- }
- }
- for (int i = count+1; i <= 4; i++) {
- propName = "net.dns" + i + "." + mypid;
- propVal = SystemProperties.get(propName);
- if (propVal.length() != 0) {
- SystemProperties.set(propName, "");
- }
- }
- /*
- * Bump the property that tells the name resolver library
- * to reread the DNS server list from the properties.
- */
- propVal = SystemProperties.get("net.dnschange");
- if (propVal.length() != 0) {
- try {
- int n = Integer.parseInt(propVal);
- SystemProperties.set("net.dnschange", "" + (n+1));
- } catch (NumberFormatException e) {
- }
- }
- }
-
- /**
- * This is a kludge to deal with the fact that
- * the PDP state change notification doesn't always work
- * with certain RIL impl's/basebands
- *
- */
- private void
- startPeriodicPdpPoll()
- {
- removeMessages(EVENT_POLL_PDP);
-
- sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS);
- }
-
- private void resetPollStats() {
- txPkts = -1;
- rxPkts = -1;
- sentSinceLastRecv = 0;
- mNoRecvPollCount = 0;
- }
-
- private void doRecovery() {
- if (state == State.CONNECTED) {
- int maxPdpReset = Settings.Gservices.getInt(mResolver,
- Settings.Gservices.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT,
- DEFAULT_MAX_PDP_RESET_FAIL);
- if (mPdpResetCount < maxPdpReset) {
- mPdpResetCount++;
- EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_RESET, sentSinceLastRecv);
- cleanUpConnection(true, Phone.REASON_PDP_RESET);
- } else {
- mPdpResetCount = 0;
- EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv);
- phone.mSST.reRegisterNetwork(null);
- }
- // TODO: Add increasingly drastic recovery steps, eg,
- // reset the radio, reset the device.
- }
- }
-
- private void
- startNetStatPoll()
- {
- if (state == State.CONNECTED && mPingTestActive == false && netStatPollEnabled == false) {
- Log.d(LOG_TAG, "[DataConnection] Start poll NetStat");
- resetPollStats();
- netStatPollEnabled = true;
- mPollNetStat.run();
- }
- }
-
- private void
- stopNetStatPoll()
- {
- netStatPollEnabled = false;
- removeCallbacks(mPollNetStat);
- Log.d(LOG_TAG, "[DataConnection] Stop poll NetStat");
- }
-
- private 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.
- */
-
- int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0"));
- SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1));
- }
-
- Runnable mPollNetStat = new Runnable()
- {
-
- public void run() {
- long sent, received;
- long preTxPkts = -1, preRxPkts = -1;
-
- Activity newActivity;
-
- preTxPkts = txPkts;
- preRxPkts = rxPkts;
-
- 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;
- mPdpResetCount = 0;
- } else if (sent > 0 && received == 0) {
- if (phone.mCT.state == Phone.State.IDLE) {
- sentSinceLastRecv += sent;
- } else {
- sentSinceLastRecv = 0;
- }
- newActivity = Activity.DATAOUT;
- } else if (sent == 0 && received > 0) {
- sentSinceLastRecv = 0;
- newActivity = Activity.DATAIN;
- mPdpResetCount = 0;
- } else if (sent == 0 && received == 0) {
- newActivity = Activity.NONE;
- } else {
- sentSinceLastRecv = 0;
- newActivity = Activity.NONE;
- }
-
- if (activity != newActivity && mIsScreenOn) {
- activity = newActivity;
- phone.notifyDataActivity();
- }
- }
-
- int watchdogTrigger = Settings.Gservices.getInt(mResolver,
- Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT, NUMBER_SENT_PACKETS_OF_HANG);
-
- if (sentSinceLastRecv >= watchdogTrigger) {
- // we already have NUMBER_SENT_PACKETS sent without ack
- if (mNoRecvPollCount == 0) {
- EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED,
- sentSinceLastRecv);
- }
-
- int noRecvPollLimit = Settings.Gservices.getInt(mResolver,
- Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_COUNT, NO_RECV_POLL_LIMIT);
-
- if (mNoRecvPollCount < noRecvPollLimit) {
- // It's possible the PDP context went down and we weren't notified.
- // Start polling the context list in an attempt to recover.
- if (DBG) log("no DATAIN in a while; polling PDP");
- phone.mCM.getPDPContextList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
-
- mNoRecvPollCount++;
-
- // Slow down the poll interval to let things happen
- netStatPollPeriod = Settings.Gservices.getInt(mResolver,
- Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS, POLL_NETSTAT_SLOW_MILLIS);
- } else {
- if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) +
- " pkts since last received");
- // We've exceeded the threshold. Run ping test as a final check;
- // it will proceed with recovery if ping fails.
- stopNetStatPoll();
- Thread pingTest = new Thread() {
- public void run() {
- runPingTest();
- }
- };
- mPingTestActive = true;
- pingTest.start();
- }
- } else {
- mNoRecvPollCount = 0;
- if (mIsScreenOn) {
- netStatPollPeriod = Settings.Gservices.getInt(mResolver,
- Settings.Gservices.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS);
- } else {
- netStatPollPeriod = Settings.Gservices.getInt(mResolver,
- Settings.Gservices.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
- POLL_NETSTAT_SCREEN_OFF_MILLIS);
- }
- }
-
- if (netStatPollEnabled) {
- mDataConnectionTracker.postDelayed(this, netStatPollPeriod);
- }
- }
- };
-
- private void runPingTest () {
- int status = -1;
- try {
- String address = Settings.Gservices.getString(mResolver,
- Settings.Gservices.PDP_WATCHDOG_PING_ADDRESS);
- int deadline = Settings.Gservices.getInt(mResolver,
- Settings.Gservices.PDP_WATCHDOG_PING_DEADLINE, DEFAULT_PING_DEADLINE);
- if (DBG) log("pinging " + address + " for " + deadline + "s");
- if (address != null && !NULL_IP.equals(address)) {
- Process p = Runtime.getRuntime()
- .exec("ping -c 1 -i 1 -w "+ deadline + " " + address);
- status = p.waitFor();
- }
- } catch (IOException e) {
- Log.w(LOG_TAG, "ping failed: IOException");
- } catch (Exception e) {
- Log.w(LOG_TAG, "exception trying to ping");
- }
-
- if (status == 0) {
- // ping succeeded. False alarm. Reset netStatPoll.
- // ("-1" for this event indicates a false alarm)
- EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_RESET, -1);
- mPdpResetCount = 0;
- sendMessage(obtainMessage(EVENT_START_NETSTAT_POLL));
- } else {
- // ping failed. Proceed with recovery.
- sendMessage(obtainMessage(EVENT_START_RECOVERY));
- }
- }
-
- /**
- * Returns true if the last fail cause is something that
- * seems like it deserves an error notification.
- * Transient errors are ignored
- */
- private boolean
- shouldPostNotification(PdpConnection.PdpFailCause cause)
- {
- boolean shouldPost = true;
- // TODO CHECK
- // if (dataLink != null) {
- // shouldPost = dataLink.getLastLinkExitCode() != DataLink.EXIT_OPEN_FAILED;
- //}
- return (shouldPost && cause != PdpConnection.PdpFailCause.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) ||
- Phone.REASON_PS_RESTRICT_ENABLED.equals(reason)) {
- retry = false;
- }
- return retry;
- }
-
- private void reconnectAfterFail(PdpFailCause lastFailCauseCode, String reason) {
- if (state == State.FAILED) {
- Log.d(LOG_TAG, "PDP 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 GPRS Unavailable notification "
- + "-- likely transient error");
- } else {
- notifyNoData(lastFailCauseCode);
- }
- }
- }
-
- private void notifyNoData(PdpConnection.PdpFailCause lastFailCauseCode) {
- setState(State.FAILED);
- }
-
-
- private void log(String s) {
- Log.d(LOG_TAG, "[DataConnectionTracker] " + s);
- }
-
- //***** Overridden from Handler
- public void
- handleMessage (Message msg)
- {
- AsyncResult ar;
- String reason = null;
-
- switch (msg.what) {
- case EVENT_RECORDS_LOADED:
- createAllApnList();
- if (state == State.FAILED) {
- cleanUpConnection(false, null);
- }
- sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
- break;
-
- case EVENT_ENABLE_NEW_APN:
- // TODO: To support simultaneous PDP contexts, this should really only call
- // cleanUpConnection if it needs to free up a PdpConnection.
- reason = Phone.REASON_APN_SWITCHED;
- cleanUpConnection(true, reason);
- break;
-
- case EVENT_TRY_SETUP_DATA:
- if (msg.obj instanceof String) {
- reason = (String)msg.obj;
- }
-
- trySetupData(reason);
- break;
-
- case EVENT_RESTORE_DEFAULT_APN:
- if (DBG) Log.d(LOG_TAG, "Restore default APN");
- setEnabled(Phone.APN_TYPE_MMS, false);
- if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
- cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN);
- mRequestedApnType = Phone.APN_TYPE_DEFAULT;
- }
- break;
-
- case EVENT_ROAMING_OFF:
- trySetupData(Phone.REASON_ROAMING_OFF);
- break;
-
- case EVENT_GPRS_DETACHED:
- onGprsDetached();
- break;
-
- case EVENT_GPRS_ATTACHED:
- onGprsAttached();
- break;
-
- case EVENT_ROAMING_ON:
- if (getDataOnRoamingEnabled()) {
- trySetupData(Phone.REASON_ROAMING_ON);
- } else {
- if (DBG) log("Tear down data connection on roaming.");
- cleanUpConnection(true, Phone.REASON_ROAMING_ON);
- }
- break;
-
- case EVENT_RADIO_AVAILABLE:
- if (phone.getSimulatedRadioControl() != null) {
- // Assume data is connected on the simulator
- // FIXME this can be improved
- setState(State.CONNECTED);
- phone.notifyDataConnection(null);
-
-
- Log.i(LOG_TAG, "We're on the simulator; assuming data is connected");
- }
-
- if (state != State.IDLE) {
- cleanUpConnection(true, null);
- }
- break;
-
- case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
- // Make sure our reconnect delay starts at the initial value
- // next time the radio comes on
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
-
- if (phone.getSimulatedRadioControl() != null) {
- // Assume data is connected on the simulator
- // FIXME this can be improved
- Log.i(LOG_TAG, "We're on the simulator; assuming radio off is meaningless");
- } else {
- if (DBG) log("Radio is off and clean up all connection");
- // TODO: Should we reset mRequestedApnType to "default"?
- cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF);
- }
- break;
-
- case EVENT_DATA_SETUP_COMPLETE:
- ar = (AsyncResult) msg.obj;
- if (ar.userObj instanceof String) {
- reason = (String) ar.userObj;
- }
-
- if (ar.exception == null) {
- // everything is setup
-
- // arg1 contains CID for this PDP context
- cidActive = msg.arg1;
- /*
- * We may have switched away from the default PDP context
- * in order to enable a "special" APN (e.g., for MMS
- * traffic). Set a timer to switch back and/or disable the
- * special APN, so that a negligient application doesn't
- * permanently prevent data connectivity. What we are
- * protecting against here is not malicious apps, but
- * rather an app that inadvertantly fails to reset to the
- * default APN, or that dies before doing so.
- */
- if (dataEnabled[APN_MMS_ID]) {
- removeMessages(EVENT_RESTORE_DEFAULT_APN);
- sendMessageDelayed(
- obtainMessage(EVENT_RESTORE_DEFAULT_APN),
- getRestoreDefaultApnDelay());
- }
- if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
- SystemProperties.set("gsm.defaultpdpcontext.active", "true");
- if (canSetPreferApn && preferredApn == null) {
- Log.d(LOG_TAG, "PREFERED APN is null");
- preferredApn = mActiveApn;
- setPreferredApn(preferredApn.id);
- }
- } else {
- SystemProperties.set("gsm.defaultpdpcontext.active", "false");
- }
- notifyDefaultData(reason);
-
- // TODO: For simultaneous PDP support, we need to build another
- // trigger another TRY_SETUP_DATA for the next APN type. (Note
- // that the existing connection may service that type, in which
- // case we should try the next type, etc.
- } else {
- PdpConnection.PdpFailCause cause;
- cause = (PdpConnection.PdpFailCause) (ar.result);
- if(DBG)
- log("PDP setup failed " + cause);
- // Log this failure to the Event Logs.
- if (cause == PdpConnection.PdpFailCause.BAD_APN ||
- cause == PdpConnection.PdpFailCause.BAD_PAP_SECRET ||
- cause == PdpConnection.PdpFailCause.BARRED ||
- cause == PdpConnection.PdpFailCause.RADIO_ERROR_RETRY ||
- cause == PdpConnection.PdpFailCause.SUSPENED_TEMPORARY ||
- cause == PdpConnection.PdpFailCause.UNKNOWN ||
- cause == PdpConnection.PdpFailCause.USER_AUTHENTICATION) {
- int cid = -1;
- GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
- if (loc != null) cid = loc.getCid();
-
- EventLog.List val = new EventLog.List(
- cause.ordinal(), cid,
- TelephonyManager.getDefault().getNetworkType());
- EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val);
- }
- // No try for permanent failure
- if (cause.isPermanentFail()) {
- notifyNoData(cause);
- }
-
- if (tryNextApn(cause)) {
- waitingApns.remove(0);
- if (waitingApns.isEmpty()) {
- // No more to try, start delayed retry
- startDelayedRetry(cause, reason);
- } else {
- // we still have more apns to try
- setState(State.SCANNING);
- // Wait a bit before trying the next APN, so that
- // we're not tying up the RIL command channel
- sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason),
- RECONNECT_DELAY_INITIAL_MILLIS);
- }
- } else {
- startDelayedRetry(cause, reason);
- }
- }
- break;
-
- case EVENT_DISCONNECT_DONE:
- if(DBG) log("EVENT_DISCONNECT_DONE");
- ar = (AsyncResult) msg.obj;
- if (ar.userObj instanceof String) {
- reason = (String) ar.userObj;
- }
- setState(State.IDLE);
- phone.notifyDataConnection(reason);
- mActiveApn = null;
- if ( retryAfterDisconnected(reason) ) {
- trySetupData(reason);
- }
- break;
-
- case EVENT_PDP_STATE_CHANGED:
- ar = (AsyncResult) msg.obj;
-
- onPdpStateChanged(ar, false);
- break;
-
- case EVENT_GET_PDP_LIST_COMPLETE:
- ar = (AsyncResult) msg.obj;
-
- onPdpStateChanged(ar, true);
- break;
-
- case EVENT_POLL_PDP:
- /* See comment in startPeriodicPdpPoll */
- ar = (AsyncResult) msg.obj;
-
- if (!(state == State.CONNECTED)) {
- // not connected; don't poll anymore
- break;
- }
-
- phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
-
- sendMessageDelayed(obtainMessage(EVENT_POLL_PDP),
- POLL_PDP_MILLIS);
- break;
-
- case EVENT_VOICE_CALL_STARTED:
- if (state == State.CONNECTED &&
- !phone.mSST.isConcurrentVoiceAndData()) {
- stopNetStatPoll();
- phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
- }
- break;
-
- case EVENT_VOICE_CALL_ENDED:
- if (state == State.CONNECTED) {
- if (!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);
- }
- break;
-
- case EVENT_START_NETSTAT_POLL:
- mPingTestActive = false;
- startNetStatPoll();
- break;
-
- case EVENT_START_RECOVERY:
- mPingTestActive = false;
- doRecovery();
- break;
-
- case EVENT_APN_CHANGED:
- onApnChanged();
- break;
-
- case EVENT_PS_RESTRICT_ENABLED:
- /**
- * We don't need to explicitly to tear down the PDP context
- * when PS restricted is enabled. The base band will deactive
- * PDP context and notify us with PDP_CONTEXT_CHANGED.
- * But we should stop the network polling and prevent reset PDP.
- */
- Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
- stopNetStatPoll();
- mIsPsRestricted = true;
- break;
-
- case EVENT_PS_RESTRICT_DISABLED:
- /**
- * When PS restrict is removed, we need setup PDP connection if
- * PDP connection is down.
- */
- Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
- mIsPsRestricted = false;
- if (state == State.CONNECTED) {
- startNetStatPoll();
- } else {
- if (state == State.FAILED) {
- cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED);
- nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
- }
- trySetupData(Phone.REASON_PS_RESTRICT_ENABLED);
- }
- break;
-
- }
- }
-
- private boolean tryNextApn(PdpFailCause cause) {
- return (cause != PdpFailCause.RADIO_NOT_AVIALABLE)
- && (cause != PdpFailCause.RADIO_OFF)
- && (cause != PdpFailCause.RADIO_ERROR_RETRY)
- && (cause != PdpFailCause.NO_SIGNAL)
- && (cause != PdpFailCause.SIM_LOCKED);
- }
-
- private int getRestoreDefaultApnDelay() {
- String restoreApnDelayStr = SystemProperties.get(APN_RESTORE_DELAY_PROP_NAME);
-
- if (restoreApnDelayStr != null && restoreApnDelayStr.length() != 0) {
- try {
- return Integer.valueOf(restoreApnDelayStr);
- } catch (NumberFormatException e) {
- }
- }
- return RESTORE_DEFAULT_APN_DELAY;
- }
-
- /**
- * Based on the sim operator numeric, create a list for all possible pdps
- * with all apns associated with that pdp
- *
- *
- */
- private void createAllApnList() {
- allApns = new ArrayList();
- String operator = phone.mSIMRecords.getSIMOperatorNumeric();
-
- if (operator != null) {
- String selection = "numeric = '" + operator + "'";
-
- Cursor cursor = phone.getContext().getContentResolver().query(
- Telephony.Carriers.CONTENT_URI, null, selection, null, null);
-
- if (cursor != null) {
- if (cursor.getCount() > 0) {
- allApns = createApnList(cursor);
- // TODO: Figure out where this fits in. This basically just
- // writes the pap-secrets file. No longer tied to PdpConnection
- // object. Not used on current platform (no ppp).
- //PdpConnection pdp = pdpList.get(pdp_name);
- //if (pdp != null && pdp.dataLink != null) {
- // pdp.dataLink.setPasswordInfo(cursor);
- //}
- }
- cursor.close();
- }
- }
-
- if (allApns.isEmpty()) {
- if (DBG) log("No APN found for carrier: " + operator);
- preferredApn = null;
- notifyNoData(PdpConnection.PdpFailCause.BAD_APN);
- } else {
- preferredApn = getPreferredApn();
- Log.d(LOG_TAG, "Get PreferredAPN");
- if (preferredApn != null && !preferredApn.numeric.equals(operator)) {
- preferredApn = null;
- setPreferredApn(-1);
- }
- }
- }
-
- private void createAllPdpList() {
- pdpList = new ArrayList();
- PdpConnection pdp;
-
- for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) {
- pdp = new PdpConnection(phone);
- pdpList.add(pdp);
- }
- }
-
- /**
- *
- * @return waitingApns list to be used to create PDP
- * error when waitingApns.isEmpty()
- */
- private ArrayList buildWaitingApns() {
- ArrayList apnList = new ArrayList();
- String operator = phone.mSIMRecords.getSIMOperatorNumeric();
-
- if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
- if (canSetPreferApn && preferredApn != null) {
- Log.i(LOG_TAG, "Preferred APN:" + operator + ":"
- + preferredApn.numeric + ":" + preferredApn);
- if (preferredApn.numeric.equals(operator)) {
- Log.i(LOG_TAG, "Waiting APN set to preferred APN");
- apnList.add(preferredApn);
- return apnList;
- } else {
- setPreferredApn(-1);
- preferredApn = null;
- }
- }
- }
-
- if (allApns != null) {
- for (ApnSetting apn : allApns) {
- if (apn.canHandleType(mRequestedApnType)) {
- apnList.add(apn);
- }
- }
- }
- return apnList;
- }
-
- /**
- * Get next apn in waitingApns
- * @return the first apn found in waitingApns, null if none
- */
- private ApnSetting getNextApn() {
- ArrayList list = waitingApns;
- ApnSetting apn = null;
-
- if (list != null) {
- if (!list.isEmpty()) {
- apn = list.get(0);
- }
- }
- return apn;
- }
-
- private String apnListToString (ArrayList apns) {
- StringBuilder result = new StringBuilder();
- for (int i = 0, size = apns.size(); i < size; i++) {
- result.append('[')
- .append(apns.get(i).toString())
- .append(']');
- }
- return result.toString();
- }
-
- private void startDelayedRetry(PdpConnection.PdpFailCause cause, String reason) {
- notifyNoData(cause);
- if (mRequestedApnType != Phone.APN_TYPE_DEFAULT) {
- sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN));
- }
- else {
- reconnectAfterFail(cause, reason);
- }
- }
-
- private void setPreferredApn(int pos) {
- if (!canSetPreferApn) {
- return;
- }
-
- ContentResolver resolver = phone.getContext().getContentResolver();
- resolver.delete(PREFERAPN_URI, null, null);
-
- if (pos >= 0) {
- ContentValues values = new ContentValues();
- values.put(APN_ID, pos);
- resolver.insert(PREFERAPN_URI, values);
- }
- }
-
- private ApnSetting getPreferredApn() {
- if (allApns.isEmpty()) {
- return null;
- }
-
- Cursor cursor = phone.getContext().getContentResolver().query(
- PREFERAPN_URI, new String[] { "_id", "name", "apn" },
- null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
-
- if (cursor != null) {
- canSetPreferApn = true;
- } else {
- canSetPreferApn = false;
- }
-
- if (canSetPreferApn && cursor.getCount() > 0) {
- int pos;
- cursor.moveToFirst();
- pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
- for(ApnSetting p:allApns) {
- if (p.id == pos && p.canHandleType(mRequestedApnType)) {
- cursor.close();
- return p;
- }
- }
- }
-
- if (cursor != null) {
- cursor.close();
- }
-
- return null;
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/DataLink.java b/telephony/java/com/android/internal/telephony/gsm/DataLink.java
deleted file mode 100644
index b822ab4..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/DataLink.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.os.Handler;
-import android.os.Registrant;
-
-/**
- * Base class representing the data link layer (eg, PPP).
- *
- * {@hide}
- */
-abstract class DataLink extends Handler implements DataLinkInterface {
-
- /** Registrant for link status change notifications. */
- Registrant mLinkChangeRegistrant;
-
- protected DataConnectionTracker dataConnection;
-
- DataLink(DataConnectionTracker dc) {
- dataConnection = dc;
- }
-
- public void setOnLinkChange(Handler h, int what, Object obj) {
- mLinkChangeRegistrant = new Registrant(h, what, obj);
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java b/telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java
deleted file mode 100644
index bca63f2..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/DataLinkInterface.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.database.Cursor;
-import android.os.Handler;
-
-/**
- * Data link interface.
- *
- * {@hide}
- */
-interface DataLinkInterface {
- /**
- * Link state enumeration.
- *
- */
- enum LinkState {
- LINK_UNKNOWN,
- LINK_UP,
- 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.
- */
- void connect();
-
- /**
- * Tears down the data link.
- */
- void disconnect();
-
- /**
- * 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).
- *
- * @param cursor cursor to carriers table
- */
- void setPasswordInfo(Cursor cursor);
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/DriverCall.java b/telephony/java/com/android/internal/telephony/gsm/DriverCall.java
deleted file mode 100644
index aab885a..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/DriverCall.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-import com.android.internal.telephony.*;
-
-import android.util.Log;
-import java.lang.Comparable;
-import android.telephony.PhoneNumberUtils;
-
-/**
- * {@hide}
- */
-public class DriverCall implements Comparable
-{
- static final String LOG_TAG = "GSM";
-
- public enum State {
- ACTIVE,
- HOLDING,
- DIALING, // MO call only
- ALERTING, // MO call only
- INCOMING, // MT call only
- WAITING; // MT call only
- // If you add a state, make sure to look for the switch()
- // statements that use this enum
- }
-
- public int index;
- public boolean isMT;
- public State state; // May be null if unavail
- public boolean isMpty;
- public String number;
- public int TOA;
- public boolean isVoice;
- public int als;
- public int numberPresentation;
-
- /** returns null on error */
- static DriverCall
- fromCLCCLine(String line)
- {
- DriverCall ret = new DriverCall();
-
- //+CLCC: 1,0,2,0,0,\"+18005551212\",145
- // index,isMT,state,mode,isMpty(,number,TOA)?
- ATResponseParser p = new ATResponseParser(line);
-
- try {
- ret.index = p.nextInt();
- ret.isMT = p.nextBoolean();
- ret.state = stateFromCLCC(p.nextInt());
-
- 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
- ret.number = PhoneNumberUtils.extractNetworkPortion(
- p.nextString());
-
- if (ret.number.length() == 0) {
- ret.number = null;
- }
-
- ret.TOA = p.nextInt();
-
- // Make sure there's a leading + on addresses with a TOA
- // of 145
-
- ret.number = PhoneNumberUtils.stringFromStringAndTOA(
- ret.number, ret.TOA);
-
- }
- } catch (ATParseEx ex) {
- Log.e(LOG_TAG,"Invalid CLCC line: '" + line + "'");
- return null;
- }
-
- return ret;
- }
-
- public
- DriverCall()
- {
- }
-
- public String
- toString()
- {
- return "id=" + index + ","
- + (isMT ? "mt" : "mo") + ","
- + state + ","
- + (isVoice ? "voice" : "no_voc") + ","
- + (isMpty ? "conf" : "norm") + ","
- + TOA + "," + als + ",cli " + numberPresentation;
- }
-
- public static State
- stateFromCLCC(int state) throws ATParseEx
- {
- switch(state) {
- case 0: return State.ACTIVE;
- case 1: return State.HOLDING;
- case 2: return State.DIALING;
- case 3: return State.ALERTING;
- case 4: return State.INCOMING;
- case 5: return State.WAITING;
- default:
- throw new ATParseEx("illegal call state " + state);
- }
- }
-
- public static int
- presentationFromCLIP(int cli) throws ATParseEx
- {
- switch(cli) {
- case 0: return Connection.PRESENTATION_ALLOWED;
- case 1: return Connection.PRESENTATION_RESTRICTED;
- case 2: return Connection.PRESENTATION_UNKNOWN;
- case 3: return Connection.PRESENTATION_PAYPHONE;
- default:
- throw new ATParseEx("illegal presentation " + cli);
- }
- }
-
- //***** Comparable Implementation
-
- /** For sorting by index */
- public int
- compareTo (Object o)
- {
- DriverCall dc;
-
- dc = (DriverCall)o;
-
- if (index < dc.index) {
- return -1;
- } else if (index == dc.index) {
- return 0;
- } else { /*index > dc.index*/
- return 1;
- }
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/EncodeException.java b/telephony/java/com/android/internal/telephony/gsm/EncodeException.java
deleted file mode 100644
index d546cef..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/EncodeException.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-/**
- * {@hide}
- */
-public class EncodeException extends Exception
-{
- public EncodeException()
- {
- super();
- }
-
- public EncodeException(String s)
- {
- super(s);
- }
-
- public EncodeException(char c)
- {
- super("Unencodable char: '" + c + "'");
- }
-}
-
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMCall.java b/telephony/java/com/android/internal/telephony/gsm/GSMCall.java
deleted file mode 100644
index 4feaf21..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/GSMCall.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-import com.android.internal.telephony.*;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * {@hide}
- */
-class GSMCall extends Call
-{
- /*************************** Instance Variables **************************/
-
- /*package*/ ArrayList connections = new ArrayList();
- /*package*/ State state = State.IDLE;
- /*package*/ CallTracker 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*/
- GSMCall (CallTracker owner)
- {
- this.owner = owner;
- }
-
- /************************** Overridden from Call *************************/
-
- public List
- getConnections()
- {
- // FIXME should return Collections.unmodifiableList();
- return connections;
- }
-
- public State
- getState()
- {
- return state;
- }
-
- public Phone
- getPhone()
- {
- //TODO
- 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 GSMConnection
-
- /*package*/ void
- attach(GSMConnection conn, DriverCall dc)
- {
- connections.add(conn);
-
- state = stateFromDCState (dc.state);
- }
-
- /*package*/ void
- attachFake(GSMConnection conn, State state)
- {
- connections.add(conn);
-
- this.state = state;
- }
-
- /**
- * Called by GSMConnection when it has disconnected
- */
- void
- connectionDisconnected(GSMConnection 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(GSMConnection conn)
- {
- connections.remove(conn);
-
- if (connections.size() == 0) {
- state = State.IDLE;
- }
- }
-
- /*package*/ boolean
- update (GSMConnection 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() == CallTracker.MAX_CONNECTIONS_PER_CALL;
- }
-
- //***** Called from CallTracker
-
-
- /**
- * 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++
- ) {
- GSMConnection cn = (GSMConnection)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--) {
- GSMConnection cn = (GSMConnection)connections.get(i);
-
- if (cn.getState() == State.DISCONNECTED) {
- connections.remove(i);
- }
- }
-
- if (connections.size() == 0) {
- state = State.IDLE;
- }
- }
-}
-
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java b/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java
deleted file mode 100644
index 4777892..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/GSMConnection.java
+++ /dev/null
@@ -1,767 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-import com.android.internal.telephony.*;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.PowerManager;
-import android.os.Registrant;
-import android.os.Looper;
-import android.os.Message;
-import android.os.AsyncResult;
-import android.os.SystemClock;
-import android.util.Log;
-import android.util.Config;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.ServiceState;
-
-/**
- * {@hide}
- */
-public class GSMConnection extends Connection {
- static final String LOG_TAG = "GSM";
-
- //***** Instance Variables
-
- CallTracker owner;
- GSMCall parent;
-
- String address; // MAY BE NULL!!!
- String dialString; // outgoing calls only
- String postDialString; // outgoing calls only
- boolean isIncoming;
- boolean disconnected;
-
- int index; // index in CallTracker.connections[], -1 if unassigned
- // The GSM index is 1 + this
-
- /*
- * 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*/
- GSMConnection (Context context, DriverCall dc, CallTracker 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*/
- GSMConnection (Context context, String dialString, CallTracker ct, GSMCall 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, Call.State.DIALING);
- }
-
- 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 Call 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() != Call.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 Call.State getState()
- {
- if (disconnected) {
- return Call.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, "Connection.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, "Connection.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 mPendingMMIs = new ArrayList();
SimPhoneBookInterfaceManager mSimPhoneBookIntManager;
SimSmsInterfaceManager mSimSmsIntManager;
PhoneSubInfo mSubInfo;
- boolean mDnsCheckDisabled = false;
Registrant mPostDialHandler;
@@ -129,44 +126,17 @@ public class GSMPhone extends PhoneBase {
private String mImeiSv;
private String mVmNumber;
- //***** Event Constants
-
- static final int EVENT_RADIO_AVAILABLE = 1;
- /** Supplemnetary Service Notification received. */
- static final int EVENT_SSN = 2;
- static final int EVENT_SIM_RECORDS_LOADED = 3;
- static final int EVENT_MMI_DONE = 4;
- static final int EVENT_RADIO_ON = 5;
- static final int EVENT_GET_BASEBAND_VERSION_DONE = 6;
- static final int EVENT_USSD = 7;
- static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 8;
- static final int EVENT_GET_IMEI_DONE = 9;
- static final int EVENT_GET_IMEISV_DONE = 10;
- static final int EVENT_GET_SIM_STATUS_DONE = 11;
- static final int EVENT_SET_CALL_FORWARD_DONE = 12;
- static final int EVENT_GET_CALL_FORWARD_DONE = 13;
- static final int EVENT_CALL_RING = 14;
- // Used to intercept the carriere selection calls so that
- // we can save the values.
- static final int EVENT_SET_NETWORK_MANUAL_COMPLETE = 15;
- static final int EVENT_SET_NETWORK_AUTOMATIC_COMPLETE = 16;
- static final int EVENT_SET_CLIR_COMPLETE = 17;
- static final int EVENT_REGISTERED_TO_NETWORK = 18;
- static final int EVENT_SET_VM_NUMBER_DONE = 19;
//***** Constructors
public
- GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier)
- {
+ GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier) {
this(context,ci,notifier, false);
}
public
- GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode)
- {
+ GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {
super(notifier, context, unitTestMode);
-
h = new MyHandler();
mCM = ci;
@@ -174,34 +144,31 @@ public class GSMPhone extends PhoneBase {
mSimulatedRadioControl = (SimulatedRadioControl) ci;
}
- mCT = new CallTracker(this);
- mSST = new ServiceStateTracker (this);
- mSMS = new SMSDispatcher(this);
- mSIMFileHandler = new SIMFileHandler(this);
+ mCM.setPhoneType(RILConstants.GSM_PHONE);
+ mCT = new GsmCallTracker(this);
+ mSST = new GsmServiceStateTracker (this);
+ mSMS = new GsmSMSDispatcher(this);
+ mIccFileHandler = new SIMFileHandler(this);
mSIMRecords = new SIMRecords(this);
- mDataConnection = new DataConnectionTracker (this);
- mSimCard = new GsmSimCard(this);
+ mDataConnection = new GsmDataConnectionTracker (this);
+ mSimCard = new SimCard(this);
if (!unitTestMode) {
mSimPhoneBookIntManager = new SimPhoneBookInterfaceManager(this);
mSimSmsIntManager = new SimSmsInterfaceManager(this);
mSubInfo = new PhoneSubInfo(this);
}
mStkService = StkService.getInstance(mCM, mSIMRecords, mContext,
- mSIMFileHandler, mSimCard);
-
+ (SIMFileHandler)mIccFileHandler, mSimCard);
+
mCM.registerForAvailable(h, EVENT_RADIO_AVAILABLE, null);
mSIMRecords.registerForRecordsLoaded(h, EVENT_SIM_RECORDS_LOADED, null);
- mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE,
- null);
+ mCM.registerForOffOrNotAvailable(h, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
mCM.registerForOn(h, EVENT_RADIO_ON, null);
mCM.setOnUSSD(h, EVENT_USSD, null);
mCM.setOnSuppServiceNotification(h, EVENT_SSN, null);
mCM.setOnCallRing(h, EVENT_CALL_RING, null);
mSST.registerForNetworkAttach(h, EVENT_REGISTERED_TO_NETWORK, null);
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- mDnsCheckDisabled = sp.getBoolean(DNS_SERVER_CHECK_DISABLED_KEY, false);
-
if (false) {
try {
//debugSocket = new LocalServerSocket("com.android.internal.telephony.debug");
@@ -221,7 +188,7 @@ public class GSMPhone extends PhoneBase {
mCM.resetRadio(null);
sock.close();
} catch (IOException ex) {
- Log.w(LOG_TAG,
+ Log.w(LOG_TAG,
"Exception accepting socket", ex);
}
}
@@ -235,13 +202,64 @@ public class GSMPhone extends PhoneBase {
Log.w(LOG_TAG, "Failure to open com.android.internal.telephony.debug socket", ex);
}
}
+
+ //Change the system setting
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.CURRENT_ACTIVE_PHONE, RILConstants.GSM_PHONE);
+ }
+
+ public void dispose() {
+ synchronized(PhoneProxy.lockForRadioTechnologyChange) {
+ //Unregister from all former registered events
+ mCM.unregisterForAvailable(h); //EVENT_RADIO_AVAILABLE
+ mSIMRecords.unregisterForRecordsLoaded(h); //EVENT_SIM_RECORDS_LOADED
+ mCM.unregisterForOffOrNotAvailable(h); //EVENT_RADIO_OFF_OR_NOT_AVAILABLE
+ mCM.unregisterForOn(h); //EVENT_RADIO_ON
+ mSST.unregisterForNetworkAttach(h); //EVENT_REGISTERED_TO_NETWORK
+ mCM.unSetOnUSSD(h);
+ mCM.unSetOnSuppServiceNotification(h);
+ mCM.unSetOnCallRing(h);
+
+ mPendingMMIs.clear();
+
+ //Force all referenced classes to unregister their former registered events
+ mStkService.dispose();
+ mCT.dispose();
+ mDataConnection.dispose();
+ mSST.dispose();
+ mIccFileHandler.dispose(); // instance of SimFileHandler
+ mSIMRecords.dispose();
+ mSimCard.dispose();
+ mSimPhoneBookIntManager.dispose();
+ mSimSmsIntManager.dispose();
+ mSubInfo.dispose();
+ }
}
-
+
+ public void removeReferences() {
+ this.mSimulatedRadioControl = null;
+ this.mStkService = null;
+ this.mSimPhoneBookIntManager = null;
+ this.mSimSmsIntManager = null;
+ this.mSMS = null;
+ this.mSubInfo = null;
+ this.mSIMRecords = null;
+ this.mIccFileHandler = null;
+ this.mSimCard = null;
+ this.mDataConnection = null;
+ this.mCT = null;
+ this.mSST = null;
+ }
+
+ protected void finalize() {
+ if(LOCAL_DEBUG) Log.d(LOG_TAG, "GSMPhone finalized");
+ }
+
+
//***** Overridden from Phone
- public ServiceState
- getServiceState()
- {
+ public ServiceState
+ getServiceState() {
return mSST.ss;
}
@@ -249,15 +267,13 @@ public class GSMPhone extends PhoneBase {
return mSST.cellLoc;
}
- public Phone.State
- getState()
- {
+ public Phone.State
+ getState() {
return mCT.state;
}
public String
- getPhoneName()
- {
+ getPhoneName() {
return "GSM";
}
@@ -270,14 +286,12 @@ public class GSMPhone extends PhoneBase {
}
public int
- getSignalStrengthASU()
- {
+ getSignalStrengthASU() {
return mSST.rssi == 99 ? -1 : mSST.rssi;
}
public boolean
- getMessageWaitingIndicator()
- {
+ getMessageWaitingIndicator() {
return mSIMRecords.getVoiceMessageWaiting();
}
@@ -287,8 +301,7 @@ public class GSMPhone extends PhoneBase {
}
public List extends MmiCode>
- getPendingMmiCodes()
- {
+ getPendingMmiCodes() {
return mPendingMMIs;
}
@@ -309,27 +322,27 @@ public class GSMPhone extends PhoneBase {
// but no data will flow
ret = DataState.DISCONNECTED;
} else { /* mSST.gprsState == ServiceState.STATE_IN_SERVICE */
- switch (mDataConnection.state) {
- case FAILED:
- case IDLE:
- ret = DataState.DISCONNECTED;
- break;
+ switch (mDataConnection.getState()) {
+ case FAILED:
+ case IDLE:
+ ret = DataState.DISCONNECTED;
+ break;
- case CONNECTED:
- case DISCONNECTING:
- if ( mCT.state != Phone.State.IDLE
- && !mSST.isConcurrentVoiceAndData()) {
- ret = DataState.SUSPENDED;
- } else {
- ret = DataState.CONNECTED;
- }
- 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;
+ case INITING:
+ case CONNECTING:
+ case SCANNING:
+ ret = DataState.CONNECTING;
+ break;
}
}
@@ -340,19 +353,18 @@ public class GSMPhone extends PhoneBase {
DataActivityState ret = DataActivityState.NONE;
if (mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE) {
- switch (mDataConnection.activity) {
-
- case DATAIN:
- ret = DataActivityState.DATAIN;
- break;
+ switch (mDataConnection.getActivity()) {
+ case DATAIN:
+ ret = DataActivityState.DATAIN;
+ break;
- case DATAOUT:
- ret = DataActivityState.DATAOUT;
- break;
+ case DATAOUT:
+ ret = DataActivityState.DATAOUT;
+ break;
- case DATAINANDOUT:
- ret = DataActivityState.DATAINANDOUT;
- break;
+ case DATAINANDOUT:
+ ret = DataActivityState.DATAINANDOUT;
+ break;
}
}
@@ -371,15 +383,13 @@ public class GSMPhone extends PhoneBase {
* changes to call state (including Phone and Connection changes).
*/
/*package*/ void
- notifyCallStateChanged()
- {
+ notifyCallStateChanged() {
/* we'd love it if this was package-scoped*/
super.notifyCallStateChangedP();
}
/*package*/ void
- notifyNewRingingConnection(Connection c)
- {
+ notifyNewRingingConnection(Connection c) {
/* we'd love it if this was package-scoped*/
super.notifyNewRingingConnectionP(c);
}
@@ -387,28 +397,26 @@ public class GSMPhone extends PhoneBase {
/**
* Notifiy registrants of a RING event.
*/
- void notifyIncomingRing() {
+ void notifyIncomingRing() {
AsyncResult ar = new AsyncResult(null, this, null);
mIncomingRingRegistrants.notifyRegistrants(ar);
}
-
+
/*package*/ void
- notifyDisconnect(Connection cn)
- {
+ notifyDisconnect(Connection cn) {
mDisconnectRegistrants.notifyResult(cn);
}
void notifyUnknownConnection() {
mUnknownConnectionRegistrants.notifyResult(this);
}
-
+
void notifySuppServiceFailed(SuppService code) {
mSuppServiceFailedRegistrants.notifyResult(code);
}
/*package*/ void
- notifyServiceStateChanged(ServiceState ss)
- {
+ notifyServiceStateChanged(ServiceState ss) {
super.notifyServiceStateChangedP(ss);
}
@@ -418,55 +426,38 @@ public class GSMPhone extends PhoneBase {
}
/*package*/ void
- notifySignalStrength()
- {
+ notifySignalStrength() {
mNotifier.notifySignalStrength(this);
}
/*package*/ void
- notifyDataConnection(String reason) {
- mNotifier.notifyDataConnection(this, reason);
- }
-
- /*package*/ void
notifyDataConnectionFailed(String reason) {
mNotifier.notifyDataConnectionFailed(this, reason);
}
/*package*/ void
- notifyDataActivity() {
- mNotifier.notifyDataActivity(this);
- }
-
- /*package*/ void
- updateMessageWaitingIndicator(boolean mwi)
- {
+ updateMessageWaitingIndicator(boolean mwi) {
// this also calls notifyMessageWaitingIndicator()
mSIMRecords.setVoiceMessageWaiting(1, mwi ? -1 : 0);
}
- /*package*/ void
- notifyMessageWaitingIndicator()
- {
+ public void
+ notifyMessageWaitingIndicator() {
mNotifier.notifyMessageWaitingChanged(this);
}
- /*package*/ void
+ public void
notifyCallForwardingIndicator() {
mNotifier.notifyCallForwardingChanged(this);
}
+ // override for allowing access from other classes of this package
/**
- * Set a system property, unless we're in unit test mode
+ * {@inheritDoc}
*/
-
- /*package*/ void
- setSystemProperty(String property, String value)
- {
- if(getUnitTestMode()) {
- return;
- }
- SystemProperties.set(property, value);
+ public final void
+ setSystemProperty(String property, String value) {
+ super.setSystemProperty(property, value);
}
public void registerForSuppServiceNotification(
@@ -480,71 +471,57 @@ public class GSMPhone extends PhoneBase {
if (mSsnRegistrants.size() == 0) mCM.setSuppServiceNotifications(false, null);
}
- public void
- acceptCall() throws CallStateException
- {
+ public void
+ acceptCall() throws CallStateException {
mCT.acceptCall();
}
- public void
- rejectCall() throws CallStateException
- {
+ public void
+ rejectCall() throws CallStateException {
mCT.rejectCall();
}
public void
- switchHoldingAndActive() throws CallStateException
- {
+ switchHoldingAndActive() throws CallStateException {
mCT.switchWaitingOrHoldingAndActive();
}
-
- public boolean canConference()
- {
+ public boolean canConference() {
return mCT.canConference();
}
- public boolean canDial()
- {
+ public boolean canDial() {
return mCT.canDial();
}
- public void conference() throws CallStateException
- {
+ public void conference() throws CallStateException {
mCT.conference();
}
- public void clearDisconnected()
- {
-
+ public void clearDisconnected() {
mCT.clearDisconnected();
}
- public boolean canTransfer()
- {
+ public boolean canTransfer() {
return mCT.canTransfer();
}
- public void explicitCallTransfer() throws CallStateException
- {
+ public void explicitCallTransfer() throws CallStateException {
mCT.explicitCallTransfer();
}
- public Call
- getForegroundCall()
- {
+ public GsmCall
+ getForegroundCall() {
return mCT.foregroundCall;
}
- public Call
- getBackgroundCall()
- {
+ public GsmCall
+ getBackgroundCall() {
return mCT.backgroundCall;
}
- public Call
- getRingingCall()
- {
+ public GsmCall
+ getRingingCall() {
return mCT.ringingCall;
}
@@ -554,7 +531,7 @@ public class GSMPhone extends PhoneBase {
return false;
}
- if (getRingingCall().getState() != Call.State.IDLE) {
+ if (getRingingCall().getState() != GsmCall.State.IDLE) {
if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 0: rejectCall");
try {
mCT.rejectCall();
@@ -563,7 +540,7 @@ public class GSMPhone extends PhoneBase {
"reject failed", e);
notifySuppServiceFailed(Phone.SuppService.REJECT);
}
- } else if (getBackgroundCall().getState() != Call.State.IDLE) {
+ } else if (getBackgroundCall().getState() != GsmCall.State.IDLE) {
if (LOCAL_DEBUG) Log.d(LOG_TAG,
"MmiCode 0: hangupWaitingOrBackground");
mCT.hangupWaitingOrBackground();
@@ -580,21 +557,21 @@ public class GSMPhone extends PhoneBase {
return false;
}
- GSMCall call = (GSMCall) getForegroundCall();
+ GsmCall call = (GsmCall) getForegroundCall();
try {
if (len > 1) {
char ch = dialString.charAt(1);
int callIndex = ch - '0';
- if (callIndex >= 1 && callIndex <= CallTracker.MAX_CONNECTIONS) {
+ if (callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) {
if (LOCAL_DEBUG) Log.d(LOG_TAG,
"MmiCode 1: hangupConnectionByIndex " +
callIndex);
mCT.hangupConnectionByIndex(call, callIndex);
}
} else {
- if (call.getState() != Call.State.IDLE) {
+ if (call.getState() != GsmCall.State.IDLE) {
if (LOCAL_DEBUG) Log.d(LOG_TAG,
"MmiCode 1: hangup foreground");
//mCT.hangupForegroundResumeBackground();
@@ -622,16 +599,16 @@ public class GSMPhone extends PhoneBase {
return false;
}
- GSMCall call = (GSMCall) getForegroundCall();
+ GsmCall call = (GsmCall) getForegroundCall();
if (len > 1) {
try {
char ch = dialString.charAt(1);
int callIndex = ch - '0';
- GSMConnection conn = mCT.getConnectionByIndex(call, callIndex);
-
+ GsmConnection conn = mCT.getConnectionByIndex(call, callIndex);
+
// gsm index starts at 1, up to 5 connections in a call,
- if (conn != null && callIndex >= 1 && callIndex <= CallTracker.MAX_CONNECTIONS) {
+ if (conn != null && callIndex >= 1 && callIndex <= GsmCallTracker.MAX_CONNECTIONS) {
if (LOCAL_DEBUG) Log.d(LOG_TAG, "MmiCode 2: separate call "+
callIndex);
mCT.separate(conn);
@@ -647,7 +624,7 @@ public class GSMPhone extends PhoneBase {
}
} else {
try {
- if (getRingingCall().getState() != Call.State.IDLE) {
+ if (getRingingCall().getState() != GsmCall.State.IDLE) {
if (LOCAL_DEBUG) Log.d(LOG_TAG,
"MmiCode 2: accept ringing call");
mCT.acceptCall();
@@ -756,9 +733,9 @@ public class GSMPhone extends PhoneBase {
}
boolean isInCall() {
- Call.State foregroundCallState = getForegroundCall().getState();
- Call.State backgroundCallState = getBackgroundCall().getState();
- Call.State ringingCallState = getRingingCall().getState();
+ GsmCall.State foregroundCallState = getForegroundCall().getState();
+ GsmCall.State backgroundCallState = getBackgroundCall().getState();
+ GsmCall.State ringingCallState = getRingingCall().getState();
return (foregroundCallState.isAlive() ||
backgroundCallState.isAlive() ||
@@ -797,15 +774,15 @@ public class GSMPhone extends PhoneBase {
public boolean handlePinMmi(String dialString) {
GsmMmiCode mmi = GsmMmiCode.newFromDialString(dialString, this);
-
+
if (mmi != null && mmi.isPinCommand()) {
mPendingMMIs.add(mmi);
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
mmi.processCode();
return true;
}
-
- return false;
+
+ return false;
}
public void sendUssdResponse(String ussdMessge) {
@@ -814,11 +791,11 @@ public class GSMPhone extends PhoneBase {
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
mmi.sendUssd(ussdMessge);
}
-
+
public void
sendDtmf(char c) {
if (!PhoneNumberUtils.is12Key(c)) {
- Log.e(LOG_TAG,
+ Log.e(LOG_TAG,
"sendDtmf called with invalid character '" + c + "'");
} else {
if (mCT.state == Phone.State.OFFHOOK) {
@@ -887,7 +864,7 @@ public class GSMPhone extends PhoneBase {
com.android.internal.R.string.defaultVoiceMailAlphaTag).toString();
}
- return ret;
+ return ret;
}
public String getDeviceId() {
@@ -898,11 +875,21 @@ public class GSMPhone extends PhoneBase {
return mImeiSv;
}
+ public String getEsn() {
+ Log.e(LOG_TAG, "[GSMPhone] getEsn() is a CDMA method");
+ return "0";
+ }
+
+ public String getMeid() {
+ Log.e(LOG_TAG, "[GSMPhone] getMeid() is a CDMA method");
+ return "0";
+ }
+
public String getSubscriberId() {
return mSIMRecords.imsi;
}
- public String getSimSerialNumber() {
+ public String getIccSerialNumber() {
return mSIMRecords.iccid;
}
@@ -939,37 +926,35 @@ public class GSMPhone extends PhoneBase {
private boolean isValidCommandInterfaceCFReason (int commandInterfaceCFReason) {
switch (commandInterfaceCFReason) {
- case CF_REASON_UNCONDITIONAL:
- case CF_REASON_BUSY:
- case CF_REASON_NO_REPLY:
- case CF_REASON_NOT_REACHABLE:
- case CF_REASON_ALL:
- case CF_REASON_ALL_CONDITIONAL:
- return true;
- default:
- return false;
+ case CF_REASON_UNCONDITIONAL:
+ case CF_REASON_BUSY:
+ case CF_REASON_NO_REPLY:
+ case CF_REASON_NOT_REACHABLE:
+ case CF_REASON_ALL:
+ case CF_REASON_ALL_CONDITIONAL:
+ return true;
+ default:
+ return false;
}
}
private boolean isValidCommandInterfaceCFAction (int commandInterfaceCFAction) {
switch (commandInterfaceCFAction) {
- case CF_ACTION_DISABLE:
- case CF_ACTION_ENABLE:
- case CF_ACTION_REGISTRATION:
- case CF_ACTION_ERASURE:
- return true;
- default:
- return false;
+ case CF_ACTION_DISABLE:
+ case CF_ACTION_ENABLE:
+ case CF_ACTION_REGISTRATION:
+ case CF_ACTION_ERASURE:
+ return true;
+ default:
+ return false;
}
}
-
- private boolean isCfEnable(int action) {
+
+ protected boolean isCfEnable(int action) {
return (action == CF_ACTION_ENABLE) || (action == CF_ACTION_REGISTRATION);
}
-
- public void getCallForwardingOption(int commandInterfaceCFReason,
- Message onComplete) {
-
+
+ public void getCallForwardingOption(int commandInterfaceCFReason, Message onComplete) {
if (isValidCommandInterfaceCFReason(commandInterfaceCFReason)) {
if (LOCAL_DEBUG) Log.d(LOG_TAG, "requesting call forwarding query.");
Message resp;
@@ -983,14 +968,13 @@ public class GSMPhone extends PhoneBase {
}
public void setCallForwardingOption(int commandInterfaceCFAction,
- int commandInterfaceCFReason,
- String dialingNumber,
- int timerSeconds,
- Message onComplete) {
-
- if ((isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
- (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
-
+ int commandInterfaceCFReason,
+ String dialingNumber,
+ int timerSeconds,
+ Message onComplete) {
+ if ( (isValidCommandInterfaceCFAction(commandInterfaceCFAction)) &&
+ (isValidCommandInterfaceCFReason(commandInterfaceCFReason))) {
+
Message resp;
if (commandInterfaceCFReason == CF_REASON_UNCONDITIONAL) {
resp = h.obtainMessage(EVENT_SET_CALL_FORWARD_DONE,
@@ -1006,12 +990,12 @@ public class GSMPhone extends PhoneBase {
resp);
}
}
-
+
public void getOutgoingCallerIdDisplay(Message onComplete) {
mCM.getCLIR(onComplete);
}
-
- public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
+
+ public void setOutgoingCallerIdDisplay(int commandInterfaceCLIRMode,
Message onComplete) {
mCM.setCLIR(commandInterfaceCLIRMode,
h.obtainMessage(EVENT_SET_CLIR_COMPLETE, commandInterfaceCLIRMode, 0, onComplete));
@@ -1020,162 +1004,111 @@ public class GSMPhone extends PhoneBase {
public void getCallWaiting(Message onComplete) {
mCM.queryCallWaiting(CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
}
-
+
public void setCallWaiting(boolean enable, Message onComplete) {
mCM.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
}
-
+
public boolean
- getSimRecordsLoaded() {
+ getIccRecordsLoaded() {
return mSIMRecords.getRecordsLoaded();
}
- public SimCard
- getSimCard() {
+ public IccCard getIccCard() {
return mSimCard;
}
- public void
+ public void
getAvailableNetworks(Message response) {
mCM.getAvailableNetworks(response);
}
/**
- * Small container class used to hold information relevant to
+ * Small container class used to hold information relevant to
* the carrier selection process. operatorNumeric can be ""
- * if we are looking for automatic selection.
+ * if we are looking for automatic selection.
*/
private static class NetworkSelectMessage {
public Message message;
public String operatorNumeric;
}
-
- public void
+
+ public void
setNetworkSelectionModeAutomatic(Message response) {
// wrap the response message in our own message along with
- // an empty string (to indicate automatic selection) for the
+ // an empty string (to indicate automatic selection) for the
// operator's id.
NetworkSelectMessage nsm = new NetworkSelectMessage();
nsm.message = response;
nsm.operatorNumeric = "";
-
+
// get the message
Message msg = h.obtainMessage(EVENT_SET_NETWORK_AUTOMATIC_COMPLETE, nsm);
- if (LOCAL_DEBUG)
+ if (LOCAL_DEBUG)
Log.d(LOG_TAG, "wrapping and sending message to connect automatically");
mCM.setNetworkSelectionModeAutomatic(msg);
}
- public void
+ public void
selectNetworkManually(com.android.internal.telephony.gsm.NetworkInfo network,
- Message response) {
+ Message response) {
// wrap the response message in our own message along with
// the operator's id.
NetworkSelectMessage nsm = new NetworkSelectMessage();
nsm.message = response;
nsm.operatorNumeric = network.operatorNumeric;
-
+
// get the message
Message msg = h.obtainMessage(EVENT_SET_NETWORK_MANUAL_COMPLETE, nsm);
mCM.setNetworkSelectionModeManual(network.operatorNumeric, msg);
}
-
- /**
- * Method to retrieve the saved operator id from the Shared Preferences
- */
- 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.
- */
- 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);
- }
- }
-
- public void
- setPreferredNetworkType(int networkType, Message response) {
- mCM.setPreferredNetworkType(networkType, response);
- }
-
- public void
- getPreferredNetworkType(Message response) {
- mCM.getPreferredNetworkType(response);
- }
public void
getNeighboringCids(Message response) {
mCM.getNeighboringCids(response);
}
-
- public void setOnPostDialCharacter(Handler h, int what, Object obj)
- {
+
+ public void setOnPostDialCharacter(Handler h, int what, Object obj) {
mPostDialHandler = new Registrant(h, what, obj);
}
-
- public void setMute(boolean muted)
- {
+ public void setMute(boolean muted) {
mCT.setMute(muted);
}
-
- public boolean getMute()
- {
- return mCT.getMute();
- }
-
- public void invokeOemRilRequestRaw(byte[] data, Message response)
- {
- mCM.invokeOemRilRequestRaw(data, response);
- }
-
- public void invokeOemRilRequestStrings(String[] strings, Message response)
- {
- mCM.invokeOemRilRequestStrings(strings, response);
+ public boolean getMute() {
+ return mCT.getMute();
}
+ /**
+ * @deprecated
+ */
public void getPdpContextList(Message response) {
- mCM.getPDPContextList(response);
+ getDataCallList(response);
}
- public List getCurrentPdpList () {
- return mDataConnection.getAllPdps();
+ public void getDataCallList(Message response) {
+ mCM.getDataCallList(response);
}
/**
- * Disables the DNS check (i.e., allows "0.0.0.0").
- * Useful for lab testing environment.
- * @param b true disables the check, false enables.
+ * @deprecated
*/
- 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();
+ public List getCurrentPdpList() {
+ ArrayList connections = new ArrayList();
+ ArrayList pdp_list = new ArrayList();
+
+ for(int n = 0; n < connections.size(); n++) {
+ pdp_list.add((PdpConnection) connections.get(n));
+ }
+
+ return pdp_list;
}
- /**
- * Returns true if the DNS check is currently disabled.
- */
- public boolean isDnsCheckDisabled() {
- return mDnsCheckDisabled;
+ public List getCurrentDataConnectionList () {
+ return mDataConnection.getAllDataConnections();
}
public void updateServiceLocation(Message response) {
@@ -1190,14 +1123,6 @@ public class GSMPhone extends PhoneBase {
mSST.disableLocationUpdates();
}
- public void setBandMode(int bandMode, Message response) {
- mCM.setBandMode(bandMode, response);
- }
-
- public void queryAvailableBandMode(Message response) {
- mCM.queryAvailableBandMode(response);
- }
-
public boolean getDataRoamingEnabled() {
return mDataConnection.getDataOnRoamingEnabled();
}
@@ -1254,7 +1179,7 @@ public class GSMPhone extends PhoneBase {
// check for "default"?
boolean noData = mDataConnection.getDataEnabled() &&
getDataConnectionState() == DataState.DISCONNECTED;
- return !noData && getSimCard().getState() == SimCard.State.READY &&
+ return !noData && getIccCard().getState() == SimCard.State.READY &&
getServiceState().getState() == ServiceState.STATE_IN_SERVICE &&
(mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming());
}
@@ -1265,9 +1190,8 @@ public class GSMPhone extends PhoneBase {
* @param mmi MMI that is done
*/
/*package*/ void
- onMMIDone(GsmMmiCode mmi)
- {
- /* Only notify complete if it's on the pending list.
+ onMMIDone(GsmMmiCode mmi) {
+ /* 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.
@@ -1279,9 +1203,8 @@ public class GSMPhone extends PhoneBase {
}
- private void
- onNetworkInitiatedUssd(GsmMmiCode mmi)
- {
+ private void
+ onNetworkInitiatedUssd(GsmMmiCode mmi) {
mMmiCompleteRegistrants.notifyRegistrants(
new AsyncResult(null, mmi, null));
}
@@ -1289,18 +1212,17 @@ public class GSMPhone extends PhoneBase {
/** ussdMode is one of CommandsInterface.USSD_MODE_* */
private void
- onIncomingUSSD (int ussdMode, String ussdMessage)
- {
+ onIncomingUSSD (int ussdMode, String ussdMessage) {
boolean isUssdError;
boolean isUssdRequest;
-
- isUssdRequest
+
+ isUssdRequest
= (ussdMode == CommandsInterface.USSD_MODE_REQUEST);
- isUssdError
+ isUssdError
= (ussdMode != CommandsInterface.USSD_MODE_NOTIFY
&& ussdMode != CommandsInterface.USSD_MODE_REQUEST);
-
+
// See comments in GsmMmiCode.java
// USSD requests aren't finished until one
// of these two events happen
@@ -1327,7 +1249,7 @@ public class GSMPhone extends PhoneBase {
// also, discard if there is no message to present
if (!isUssdError && ussdMessage != null) {
GsmMmiCode mmi;
- mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
+ mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
isUssdRequest,
GSMPhone.this);
onNetworkInitiatedUssd(mmi);
@@ -1338,7 +1260,7 @@ public class GSMPhone extends PhoneBase {
/**
* Make sure the network knows our preferred setting.
*/
- private void syncClirSetting() {
+ protected void syncClirSetting() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
int clirSetting = sp.getInt(CLIR_KEY, -1);
if (clirSetting >= 0) {
@@ -1348,20 +1270,16 @@ public class GSMPhone extends PhoneBase {
//***** Inner Classes
- class MyHandler extends Handler
- {
- MyHandler()
- {
+ class MyHandler extends Handler {
+ MyHandler() {
}
- MyHandler(Looper l)
- {
+ MyHandler(Looper l) {
super(l);
}
public void
- handleMessage (Message msg)
- {
+ handleMessage (Message msg) {
AsyncResult ar;
Message onComplete;
@@ -1422,11 +1340,10 @@ public class GSMPhone extends PhoneBase {
if (ar.exception != null) {
break;
}
-
+
mImeiSv = (String)ar.result;
break;
-
case EVENT_USSD:
ar = (AsyncResult)msg.obj;
@@ -1441,7 +1358,7 @@ public class GSMPhone extends PhoneBase {
}
break;
- case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
+ case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
// Some MMI requests (eg USSD) are not completed
// within the course of a CommandsInterface request
// If the radio shuts off or resets while one of these
@@ -1450,10 +1367,10 @@ public class GSMPhone extends PhoneBase {
for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
if (mPendingMMIs.get(i).isPendingUSSD()) {
mPendingMMIs.get(i).onUssdFinishedError();
- }
+ }
}
break;
-
+
case EVENT_SSN:
ar = (AsyncResult)msg.obj;
SuppServiceNotification not = (SuppServiceNotification) ar.result;
@@ -1474,7 +1391,7 @@ public class GSMPhone extends PhoneBase {
case EVENT_SET_VM_NUMBER_DONE:
ar = (AsyncResult)msg.obj;
- if (SimVmNotSupportedException.class.isInstance(ar.exception)) {
+ if (IccVmNotSupportedException.class.isInstance(ar.exception)) {
storeVoiceMailNumber(mVmNumber);
ar.exception = null;
}
@@ -1497,15 +1414,15 @@ public class GSMPhone extends PhoneBase {
onComplete.sendToTarget();
}
break;
-
+
case EVENT_CALL_RING:
ar = (AsyncResult)msg.obj;
if (ar.exception == null) {
notifyIncomingRing();
}
break;
-
- // handle the select network completion callbacks.
+
+ // handle the select network completion callbacks.
case EVENT_SET_NETWORK_MANUAL_COMPLETE:
case EVENT_SET_NETWORK_AUTOMATIC_COMPLETE:
handleSetSelectNetwork((AsyncResult) msg.obj);
@@ -1550,29 +1467,29 @@ public class GSMPhone extends PhoneBase {
* Used to track the settings upon completion of the network change.
*/
private void handleSetSelectNetwork(AsyncResult ar) {
- // look for our wrapper within the asyncresult, skip the rest if it
- // is null.
+ // look for our wrapper within the asyncresult, skip the rest if it
+ // is null.
if (!(ar.userObj instanceof NetworkSelectMessage)) {
if (LOCAL_DEBUG) Log.d(LOG_TAG, "unexpected result from user object.");
return;
}
-
+
NetworkSelectMessage nsm = (NetworkSelectMessage) ar.userObj;
-
+
// found the object, now we send off the message we had originally
- // attached to the request.
+ // attached to the request.
if (nsm.message != null) {
if (LOCAL_DEBUG) Log.d(LOG_TAG, "sending original message to recipient");
AsyncResult.forMessage(nsm.message, ar.result, ar.exception);
nsm.message.sendToTarget();
}
-
+
// open the shared preferences editor, and write the value.
// nsm.operatorNumeric is "" if we're in automatic.selection.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putString(NETWORK_SELECTION_KEY, nsm.operatorNumeric);
-
+
// commit and log the result.
if (! editor.commit()) {
Log.e(LOG_TAG, "failed to commit network selection preference");
@@ -1584,17 +1501,16 @@ public class GSMPhone extends PhoneBase {
* Saves CLIR setting so that we can re-apply it as necessary
* (in case the RIL resets it across reboots).
*/
- /* package */ void saveClirSetting(int commandInterfaceCLIRMode) {
+ public void saveClirSetting(int commandInterfaceCLIRMode) {
// open the shared preferences editor, and write the value.
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putInt(CLIR_KEY, commandInterfaceCLIRMode);
-
+
// commit and log the result.
if (! editor.commit()) {
Log.e(LOG_TAG, "failed to commit CLIR preference");
}
-
}
private void handleCfuQueryResult(CallForwardInfo[] infos) {
@@ -1618,7 +1534,7 @@ public class GSMPhone extends PhoneBase {
* simulates various data connection states. This messes with
* DataConnectionTracker's internal states, but doesn't actually change
* the underlying radio connection states.
- *
+ *
* @param state Phone.DataState enum.
*/
public void simulateDataConnection(Phone.DataState state) {
@@ -1642,4 +1558,52 @@ public class GSMPhone extends PhoneBase {
mDataConnection.setState(dcState);
notifyDataConnection(null);
}
+
+ /**
+ * Retrieves the PhoneSubInfo of the GSMPhone
+ */
+ public PhoneSubInfo getPhoneSubInfo(){
+ return mSubInfo;
+ }
+
+ /**
+ * Retrieves the IccSmsInterfaceManager of the GSMPhone
+ */
+ public IccSmsInterfaceManager getIccSmsInterfaceManager(){
+ return mSimSmsIntManager;
+ }
+
+ /**
+ * Retrieves the IccPhoneBookInterfaceManager of the GSMPhone
+ */
+ public IccPhoneBookInterfaceManager getIccPhoneBookInterfaceManager(){
+ return mSimPhoneBookIntManager;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public Handler getHandler(){
+ return h;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public IccFileHandler getIccFileHandler(){
+ return this.mIccFileHandler;
+ }
+
+ public void activateCellBroadcastSms(int activate, Message response) {
+ Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM.");
+ }
+
+ public void getCellBroadcastSmsConfig(Message response) {
+ Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM.");
+ }
+
+ public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response){
+ Log.e(LOG_TAG, "Error! This functionality is not implemented for GSM.");
+ }
+
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java
deleted file mode 100644
index df34897..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/GsmAlphabet.java
+++ /dev/null
@@ -1,813 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.telephony.gsm.SmsMessage;
-import android.util.SparseIntArray;
-
-import android.util.Log;
-
-/**
- * This class implements the character set mapping between
- * the GSM SMS 7-bit alphabet specifed in TS 23.038 6.2.1
- * and UTF-16
- *
- * {@hide}
- */
-public class GsmAlphabet
-{
- static final String LOG_TAG = "GSM";
-
-
-
- //***** Constants
-
- /**
- * This escapes extended characters, and when present indicates that the
- * following character should
- * be looked up in the "extended" table
- *
- * gsmToChar(GSM_EXTENDED_ESCAPE) returns 0xffff
- */
-
- public static final byte GSM_EXTENDED_ESCAPE = 0x1B;
-
-
- /**
- * char to GSM alphabet char
- * Returns ' ' in GSM alphabet if there's no possible match
- * Returns GSM_EXTENDED_ESCAPE if this character is in the extended table
- * In this case, you must call charToGsmExtended() for the value that
- * should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string
- */
- public static int
- charToGsm(char c)
- {
- try {
- return charToGsm(c, false);
- } catch (EncodeException ex) {
- // this should never happen
- return sGsmSpaceChar;
- }
- }
-
- /**
- * char to GSM alphabet 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
- * In this case, you must call charToGsmExtended() for the value that
- * should follow GSM_EXTENDED_ESCAPE in the GSM alphabet string
- */
-
- public static int
- charToGsm(char c, boolean throwException) throws EncodeException
- {
- int ret;
-
- ret = charToGsm.get(c, -1);
-
- if (ret == -1) {
- ret = charToGsmExtended.get(c, -1);
-
- if (ret == -1) {
- if (throwException) {
- throw new EncodeException(c);
- } else {
- return sGsmSpaceChar;
- }
- } else {
- return GSM_EXTENDED_ESCAPE;
- }
- }
-
- return ret;
-
- }
-
-
- /**
- * char to extended GSM alphabet char
- *
- * Extended chars should be escaped with GSM_EXTENDED_ESCAPE
- *
- * Returns ' ' in GSM alphabet if there's no possible match
- *
- */
- public static int
- charToGsmExtended(char c)
- {
- int ret;
-
- ret = charToGsmExtended.get(c, -1);
-
- if (ret == -1) {
- return sGsmSpaceChar;
- }
-
- return ret;
- }
-
- /**
- * 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
- * gsmExtendedToChar()
- *
- * If an unmappable value is passed (one greater than 127), ' ' is returned
- */
-
- public static char
- gsmToChar(int gsmChar)
- {
- return (char)gsmToChar.get(gsmChar, ' ');
- }
-
- /**
- * 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)
- {
- int ret;
-
- ret = gsmExtendedToChar.get(gsmChar, -1);
-
- if (ret == -1) {
- return ' ';
- }
-
- return (char)ret;
- }
-
- /**
- * Converts a String into a byte array containing the 7-bit packed
- * GSM Alphabet representation of the string. If a header is provided,
- * this is included in the returned byte array and padded to a septet
- * boundary.
- *
- * Unencodable chars are encoded as spaces
- *
- * Byte 0 in the returned byte array is the count of septets used,
- * including the header and header padding. The returned byte array is
- * the minimum size required to store the packed septets. The returned
- * array cannot contain more than 255 septets.
- *
- * @param data The text string to encode.
- * @param header Optional header (includeing length byte) that precedes
- * the encoded data, padded to septet boundary.
- * @return Byte array containing header and encoded data.
- */
- public static byte[] stringToGsm7BitPackedWithHeader(String data, byte[] header)
- throws EncodeException {
-
- if (header == null || header.length == 0) {
- return stringToGsm7BitPacked(data);
- }
-
- int headerBits = header.length * 8;
- int headerSeptets = headerBits / 7;
- headerSeptets += (headerBits % 7) > 0 ? 1 : 0;
-
- int sz = data.length();
- int septetCount;
- septetCount = countGsmSeptets(data, true) + headerSeptets;
-
- byte[] ret = stringToGsm7BitPacked(data, 0, septetCount,
- (headerSeptets*7), true);
-
- // Paste in the header
- System.arraycopy(header, 0, ret, 1, header.length);
- return ret;
- }
-
- /**
- * Converts a String into a byte array containing
- * the 7-bit packed GSM Alphabet representation of the string.
- *
- * Unencodable chars are encoded as spaces
- *
- * Byte 0 in the returned byte array is the count of septets used
- * The returned byte array is the minimum size required to store
- * the packed septets. The returned array cannot contain more than 255
- * septets.
- *
- * @param data the data string to endcode
- * @throws EncodeException if String is too large to encode
- */
- public static byte[] stringToGsm7BitPacked(String data)
- throws EncodeException {
- return stringToGsm7BitPacked(data, 0, -1, 0, true);
- }
-
- /**
- * 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
- * The returned byte array is the minimum size required to store
- * the packed septets. The returned array cannot contain more than 255
- * septets.
- *
- * @param data the text to convert to septets
- * @param dataOffset the character offset in data to start the encoding from
- * @param maxSeptets the maximum number of septets to convert, or -1 for no
- * 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.
- * If false, replaces unencodable char with GSM alphabet space char.
- *
- * @throws EncodeException if String is too large to encode
- */
- public static byte[] stringToGsm7BitPacked(String data, int dataOffset,
- int maxSeptets, int startingBitOffset, boolean throwException)
- throws EncodeException {
-
- int sz = data.length();
- int septetCount;
- if (maxSeptets == -1) {
- septetCount = countGsmSeptets(data, true);
- } else {
- septetCount = maxSeptets;
- }
-
- if(septetCount > 0xff) {
- throw new EncodeException("Payload cannot exceed " + Short.MAX_VALUE
- + " septets");
- }
-
- // Enough for all the septets and the length 2 byte prefix
- byte[] ret = new byte[1 + (((septetCount * 7) + 7) / 8)];
-
- int bitOffset = startingBitOffset;
- int septets = startingBitOffset/7;
- for (int i = dataOffset; i < sz && septets < septetCount; i++, bitOffset += 7) {
- char c = data.charAt(i);
-
- int v = GsmAlphabet.charToGsm(c, throwException);
- if (v == GSM_EXTENDED_ESCAPE) {
- // Lookup the extended char
- v = GsmAlphabet.charToGsmExtended(c);
-
- packSmsChar(ret, bitOffset, GSM_EXTENDED_ESCAPE);
- bitOffset += 7;
- septets++;
- }
-
- packSmsChar(ret, bitOffset, v);
- septets++;
- }
-
- // See check for > 0xff above
- ret[0] = (byte)septets;
-
- return ret;
- }
-
- /**
- * Pack a 7-bit char into its appropirate place in a byte array
- *
- * @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)
- {
- int byteOffset = bitOffset / 8;
- int shift = bitOffset % 8;
-
- packedChars[++byteOffset] |= value << shift;
-
- if (shift > 1) {
- packedChars[++byteOffset] = (byte)(value >> (8 - shift));
- }
- }
-
- /**
- * 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 lengthSeptets string length in septets, not bytes
- * @return String representation or null on decoding exception
- */
- public static String gsm7BitPackedToString(byte[] pdu, int offset,
- int lengthSeptets) {
- return gsm7BitPackedToString(pdu, offset, lengthSeptets, 0);
- }
-
- /**
- * 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 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)
- {
- StringBuilder ret = new StringBuilder(lengthSeptets);
- boolean prevCharWasEscape;
-
- try {
- prevCharWasEscape = false;
-
- for (int i = 0 ; i < lengthSeptets ; i++) {
- int bitOffset = (7 * i) + numPaddingBits;
-
- int byteOffset = bitOffset / 8;
- int shift = bitOffset % 8;
- int gsmVal;
-
- gsmVal = (0x7f & (pdu[offset + byteOffset] >> shift));
-
- // if it crosses a byte boundry
- if (shift > 1) {
- // set msb bits to 0
- gsmVal &= 0x7f >> (shift - 1);
-
- gsmVal |= 0x7f & (pdu[offset + byteOffset + 1] << (8 - shift));
- }
-
- if (prevCharWasEscape) {
- ret.append(GsmAlphabet.gsmExtendedToChar(gsmVal));
- prevCharWasEscape = false;
- } else if (gsmVal == GSM_EXTENDED_ESCAPE) {
- prevCharWasEscape = true;
- } else {
- ret.append(GsmAlphabet.gsmToChar(gsmVal));
- }
- }
- } catch (RuntimeException ex) {
- Log.e(LOG_TAG, "Error GSM 7 bit packed: ", ex);
- return null;
- }
-
- return ret.toString();
- }
-
-
- /**
- * 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)
- {
- boolean prevWasEscape;
- StringBuilder ret = new StringBuilder(length);
-
- prevWasEscape = false;
- for (int i = offset ; i < offset + length ; i++) {
- // Never underestimate the pain that can be caused
- // by signed bytes
- int c = data[i] & 0xff;
-
- if (c == 0xff) {
- break;
- } else if (c == GSM_EXTENDED_ESCAPE) {
- if (prevWasEscape) {
- // Two escape chars in a row
- // We treat this as a space
- // See Note 1 in table 6.2.1.1 of TS 23.038 v7.00
- ret.append(' ');
- prevWasEscape = false;
- } else {
- prevWasEscape = true;
- }
- } else {
- if (prevWasEscape) {
- ret.append((char)gsmExtendedToChar.get(c, ' '));
- } else {
- ret.append((char)gsmToChar.get(c, ' '));
- }
- prevWasEscape = false;
- }
- }
-
- return ret.toString();
- }
-
- /**
- * Convert a string into an 8-bit unpacked GSM alphabet byte
- * array
- */
- public static byte[]
- stringToGsm8BitPacked(String s)
- {
- byte[] ret;
-
- int septets = 0;
-
- septets = countGsmSeptets(s);
-
- // Enough for all the septets and the length byte prefix
- ret = new byte[septets];
-
- stringToGsm8BitUnpackedField(s, ret, 0, ret.length);
-
- return ret;
- }
-
-
- /**
- * Write a String into a GSM 8-bit unpacked field of
- * @param length size at @param offset in @param dest
- *
- * Field is padded with 0xff's, string is truncated if necessary
- */
-
- public static void
- 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++
- ) {
- char c = s.charAt(i);
-
- int v = GsmAlphabet.charToGsm(c);
-
- if (v == GSM_EXTENDED_ESCAPE) {
- // make sure we can fit an escaped char
- if (! (outByteIndex + 1 - offset < length)) {
- break;
- }
-
- dest[outByteIndex++] = GSM_EXTENDED_ESCAPE;
-
- v = GsmAlphabet.charToGsmExtended(c);
- }
-
- dest[outByteIndex++] = (byte)v;
- }
-
- // pad with 0xff's
- while((outByteIndex - offset) < length) {
- dest[outByteIndex++] = (byte)0xff;
- }
- }
-
- /**
- * Returns the count of 7-bit GSM alphabet characters
- * needed to represent this character. Counts unencodable char as 1 septet.
- */
- public static int
- countGsmSeptets(char c)
- {
- try {
- return countGsmSeptets(c, false);
- } catch (EncodeException ex) {
- // This should never happen.
- return 0;
- }
- }
-
- /**
- * Returns the count of 7-bit GSM alphabet characters
- * needed to represent this character
- * @param throwsException If true, throws EncodeException if unencodable
- * 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;
- }
-
- if (throwsException) {
- throw new EncodeException(c);
- } else {
- // count as a space char
- return 1;
- }
- }
-
- /**
- * Returns the count of 7-bit GSM alphabet characters
- * needed to represent this string. Counts unencodable char as 1 septet.
- */
- public static int
- countGsmSeptets(CharSequence s)
- {
- try {
- return countGsmSeptets(s, false);
- } catch (EncodeException ex) {
- // this should never happen
- return 0;
- }
- }
-
- /**
- * Returns the count of 7-bit GSM alphabet characters
- * needed to represent this string.
- * @param throwsException If true, throws EncodeException if unencodable
- * char. Otherwise, counts invalid char as 1 septet
- */
- public static int
- countGsmSeptets(CharSequence s, boolean throwsException) throws EncodeException
- {
- int charIndex = 0;
- int sz = s.length();
- int count = 0;
-
- while (charIndex < sz) {
- count += countGsmSeptets(s.charAt(charIndex), throwsException);
- charIndex++;
- }
-
- return count;
- }
-
- /**
- * Returns the index into s
of the first character
- * after limit
septets have been reached, starting at
- * index start
. This is used when dividing messages
- * into units within the SMS message size limit.
- *
- * @param s source string
- * @param start index of where to start counting septets
- * @param limit maximum septets to include,
- * e.g. MAX_USER_DATA_SEPTETS
- * @return index of first character that won't fit, or the length
- * of the entire string if everything fits
- */
- public static int
- findGsmSeptetLimitIndex(String s, int start, int limit) {
- int accumulator = 0;
- int size = s.length();
-
- for (int i = start; i < size; i++) {
- accumulator += countGsmSeptets(s.charAt(i));
- if (accumulator > limit) {
- return i;
- }
- }
- return size;
- }
-
- /**
- * Returns the index into s
of the first character
- * after limit
octets have been reached, starting at
- * index start
. This is used when dividing messages
- * in UCS2 encoding into units within the SMS message size limit.
- *
- * @param s source string
- * @param start index of where to start counting septets
- * @param limit maximum septets to include,
- * e.g. MAX_USER_DATA_BYTES
- * @return index of first character that won't fit, or the length
- * of the entire string if everything fits
- */
- public static int
- findUCS2LimitIndex(String s, int start, int limit) {
- int numCharToBeEncoded = s.length() - start;
- return ((numCharToBeEncoded*2 > limit)? limit/2: numCharToBeEncoded) + start;
- }
-
- /**
- * Returns the index into s
of the first character
- * after limit
septets/octets have been reached
- * according to the encodingType
, starting at
- * index start
. This is used when dividing messages
- * units within the SMS message size limit.
- *
- * @param s source string
- * @param start index of where to start counting septets
- * @param limit maximum septets to include,
- * e.g. MAX_USER_DATA_BYTES
- * @return index of first character that won't fit, or the length
- * of the entire string if everything fits
- */
- public static int
- findLimitIndex(String s, int start, int limit, int encodingType) throws EncodeException {
- if (encodingType == SmsMessage.ENCODING_7BIT) {
- return findGsmSeptetLimitIndex(s, start, limit);
- }
- else if (encodingType == SmsMessage.ENCODING_16BIT) {
- return findUCS2LimitIndex(s, start, limit);
- }
- else {
- throw new EncodeException("Unsupported encoding type: " + encodingType);
- }
- }
-
- // Set in the static initializer
- private static int sGsmSpaceChar;
-
- private static final SparseIntArray charToGsm = new SparseIntArray();
- 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++);
- charToGsm.put('\u00a5', i++);
- charToGsm.put('\u00e8', i++);
- charToGsm.put('\u00e9', i++);
- charToGsm.put('\u00f9', i++);
- charToGsm.put('\u00ec', i++);
- charToGsm.put('\u00f2', i++);
- charToGsm.put('\u00c7', i++);
- charToGsm.put('\n', i++);
- charToGsm.put('\u00d8', i++);
- charToGsm.put('\u00f8', i++);
- charToGsm.put('\r', i++);
- charToGsm.put('\u00c5', i++);
- charToGsm.put('\u00e5', i++);
-
- charToGsm.put('\u0394', i++);
- charToGsm.put('_', i++);
- charToGsm.put('\u03a6', i++);
- charToGsm.put('\u0393', i++);
- charToGsm.put('\u039b', i++);
- charToGsm.put('\u03a9', i++);
- charToGsm.put('\u03a0', i++);
- charToGsm.put('\u03a8', i++);
- charToGsm.put('\u03a3', i++);
- charToGsm.put('\u0398', i++);
- charToGsm.put('\u039e', i++);
- charToGsm.put('\uffff', i++);
- charToGsm.put('\u00c6', i++);
- charToGsm.put('\u00e6', i++);
- charToGsm.put('\u00df', i++);
- charToGsm.put('\u00c9', i++);
-
- charToGsm.put(' ', i++);
- charToGsm.put('!', i++);
- charToGsm.put('"', i++);
- charToGsm.put('#', i++);
- charToGsm.put('\u00a4', i++);
- charToGsm.put('%', i++);
- charToGsm.put('&', i++);
- charToGsm.put('\'', i++);
- charToGsm.put('(', i++);
- charToGsm.put(')', i++);
- charToGsm.put('*', i++);
- charToGsm.put('+', i++);
- charToGsm.put(',', i++);
- charToGsm.put('-', i++);
- charToGsm.put('.', i++);
- charToGsm.put('/', i++);
-
- charToGsm.put('0', i++);
- charToGsm.put('1', i++);
- charToGsm.put('2', i++);
- charToGsm.put('3', i++);
- charToGsm.put('4', i++);
- charToGsm.put('5', i++);
- charToGsm.put('6', i++);
- charToGsm.put('7', i++);
- charToGsm.put('8', i++);
- charToGsm.put('9', i++);
- charToGsm.put(':', i++);
- charToGsm.put(';', i++);
- charToGsm.put('<', i++);
- charToGsm.put('=', i++);
- charToGsm.put('>', i++);
- charToGsm.put('?', i++);
-
- charToGsm.put('\u00a1', i++);
- charToGsm.put('A', i++);
- charToGsm.put('B', i++);
- charToGsm.put('C', i++);
- charToGsm.put('D', i++);
- charToGsm.put('E', i++);
- charToGsm.put('F', i++);
- charToGsm.put('G', i++);
- charToGsm.put('H', i++);
- charToGsm.put('I', i++);
- charToGsm.put('J', i++);
- charToGsm.put('K', i++);
- charToGsm.put('L', i++);
- charToGsm.put('M', i++);
- charToGsm.put('N', i++);
- charToGsm.put('O', i++);
-
- charToGsm.put('P', i++);
- charToGsm.put('Q', i++);
- charToGsm.put('R', i++);
- charToGsm.put('S', i++);
- charToGsm.put('T', i++);
- charToGsm.put('U', i++);
- charToGsm.put('V', i++);
- charToGsm.put('W', i++);
- charToGsm.put('X', i++);
- charToGsm.put('Y', i++);
- charToGsm.put('Z', i++);
- charToGsm.put('\u00c4', i++);
- charToGsm.put('\u00d6', i++);
- charToGsm.put('\u0147', i++);
- charToGsm.put('\u00dc', i++);
- charToGsm.put('\u00a7', i++);
-
- charToGsm.put('\u00bf', i++);
- charToGsm.put('a', i++);
- charToGsm.put('b', i++);
- charToGsm.put('c', i++);
- charToGsm.put('d', i++);
- charToGsm.put('e', i++);
- charToGsm.put('f', i++);
- charToGsm.put('g', i++);
- charToGsm.put('h', i++);
- charToGsm.put('i', i++);
- charToGsm.put('j', i++);
- charToGsm.put('k', i++);
- charToGsm.put('l', i++);
- charToGsm.put('m', i++);
- charToGsm.put('n', i++);
- charToGsm.put('o', i++);
-
- charToGsm.put('p', i++);
- charToGsm.put('q', i++);
- charToGsm.put('r', i++);
- charToGsm.put('s', i++);
- charToGsm.put('t', i++);
- charToGsm.put('u', i++);
- charToGsm.put('v', i++);
- charToGsm.put('w', i++);
- charToGsm.put('x', i++);
- charToGsm.put('y', i++);
- charToGsm.put('z', i++);
- charToGsm.put('\u00e4', i++);
- charToGsm.put('\u00f6', i++);
- charToGsm.put('\u00f1', i++);
- charToGsm.put('\u00fc', i++);
- charToGsm.put('\u00e0', i++);
-
-
- charToGsmExtended.put('\f', 10);
- charToGsmExtended.put('^', 20);
- charToGsmExtended.put('{', 40);
- charToGsmExtended.put('}', 41);
- charToGsmExtended.put('\\', 47);
- charToGsmExtended.put('[', 60);
- charToGsmExtended.put('~', 61);
- charToGsmExtended.put(']', 62);
- charToGsmExtended.put('|', 64);
- charToGsmExtended.put('\u20ac', 101);
-
- int size = charToGsm.size();
- for (int j=0; j connections = new ArrayList();
+ /*package*/ GsmCallTracker 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*/
+ GsmCall (GsmCallTracker owner) {
+ this.owner = owner;
+ }
+
+ public void dispose() {
+ }
+
+ /************************** Overridden from Call *************************/
+
+ public List
+ getConnections() {
+ // FIXME should return Collections.unmodifiableList();
+ return connections;
+ }
+
+ public Phone
+ getPhone() {
+ //TODO
+ 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 GsmConnection
+
+ /*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 GsmConnection when it has disconnected
+ */
+ void
+ connectionDisconnected(GsmConnection 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(GsmConnection conn) {
+ connections.remove(conn);
+
+ if (connections.size() == 0) {
+ state = State.IDLE;
+ }
+ }
+
+ /*package*/ boolean
+ update (GsmConnection 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() == GsmCallTracker.MAX_CONNECTIONS_PER_CALL;
+ }
+
+ //***** Called from GsmCallTracker
+
+
+ /**
+ * Called when this Call is being hung up locally (eg, user pressed "end")
+ * Note that at this point, the hangup request has been dispatched to the radio
+ * but no response has yet been received so update() has not yet been called
+ */
+ void
+ onHangupLocal() {
+ for (int i = 0, s = connections.size()
+ ; i < s; i++
+ ) {
+ GsmConnection cn = (GsmConnection)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--) {
+ GsmConnection cn = (GsmConnection)connections.get(i);
+
+ if (cn.getState() == State.DISCONNECTED) {
+ connections.remove(i);
+ }
+ }
+
+ if (connections.size() == 0) {
+ state = State.IDLE;
+ }
+ }
+}
+
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
new file mode 100644
index 0000000..5c5090f
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmCallTracker.java
@@ -0,0 +1,908 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.os.*;
+import android.telephony.gsm.GsmCellLocation;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyManager;
+import android.util.EventLog;
+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.gsm.CallFailCause;
+import com.android.internal.telephony.gsm.GsmCall;
+import com.android.internal.telephony.gsm.GsmConnection;
+import com.android.internal.telephony.gsm.GSMPhone;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.TelephonyEventLog;
+import com.android.internal.telephony.*;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * {@hide}
+ */
+public final class GsmCallTracker extends CallTracker {
+ static final String LOG_TAG = "GSM";
+ private static final boolean REPEAT_POLLING = false;
+
+ private static final boolean DBG_POLL = false;
+
+ //***** Constants
+
+ static final int MAX_CONNECTIONS = 7; // only 7 connections allowed in GSM
+ static final int MAX_CONNECTIONS_PER_CALL = 5; // only 5 connections allowed per call
+
+ //***** Instance Variables
+ GsmConnection connections[] = new GsmConnection[MAX_CONNECTIONS];
+ RegistrantList voiceCallEndedRegistrants = new RegistrantList();
+ RegistrantList voiceCallStartedRegistrants = new RegistrantList();
+
+
+ // connections dropped durin last poll
+ ArrayList droppedDuringPoll
+ = new ArrayList(MAX_CONNECTIONS);
+
+ GsmCall ringingCall = new GsmCall(this);
+ // A call that is ringing or (call) waiting
+ GsmCall foregroundCall = new GsmCall(this);
+ GsmCall backgroundCall = new GsmCall(this);
+
+ GsmConnection pendingMO;
+ boolean hangupPendingMO;
+
+ GSMPhone phone;
+
+ boolean desiredMute = false; // false = mute off
+
+ Phone.State state = Phone.State.IDLE;
+
+
+
+ //***** Events
+
+
+ //***** Constructors
+
+ GsmCallTracker (GSMPhone 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() {
+ //Unregister for all events
+ cm.unregisterForCallStateChanged(this);
+ cm.unregisterForOn(this);
+ cm.unregisterForNotAvailable(this);
+
+ for(GsmConnection c : connections) {
+ try {
+ if(c != null) hangup(c);
+ } catch (CallStateException ex) {
+ Log.e(LOG_TAG, "unexpected error on hangup during dispose");
+ }
+ }
+
+ try {
+ if(pendingMO != null) hangup(pendingMO);
+ } catch (CallStateException ex) {
+ Log.e(LOG_TAG, "unexpected error on hangup during dispose");
+ }
+
+ clearDisconnected();
+ }
+
+ protected void finalize() {
+ Log.d(LOG_TAG, "GsmCallTracker finalized");
+ }
+
+ //***** Instance Methods
+
+ //***** Public Methods
+ 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 connCopy;
+
+ // We need to make a copy here, since fakeHoldBeforeDial()
+ // modifies the lists, and we don't want to reverse the order
+ connCopy = (List) foregroundCall.connections.clone();
+
+ for (int i = 0, s = connCopy.size() ; i < s ; i++) {
+ GsmConnection conn = (GsmConnection)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() == GsmCall.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() != GsmCall.State.IDLE) {
+ //we should have failed in !canDial() above before we get here
+ throw new CallStateException("cannot dial in current state");
+ }
+
+ pendingMO = new GsmConnection(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() == GsmCall.State.INCOMING) {
+ Log.i("phone", "acceptCall: incoming...");
+ // Always unmute when answering a new call
+ setMute(false);
+ cm.acceptCall(obtainCompleteMessage());
+ } else if (ringingCall.getState() == GsmCall.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() == GsmCall.State.INCOMING) {
+ throw new CallStateException("cannot be in the incoming state");
+ } else {
+ cm.switchWaitingOrHoldingAndActive(
+ obtainCompleteMessage(EVENT_SWITCH_RESULT));
+ }
+ }
+
+ void
+ conference() throws CallStateException {
+ cm.conference(obtainCompleteMessage(EVENT_CONFERENCE_RESULT));
+ }
+
+ void
+ explicitCallTransfer() throws CallStateException {
+ cm.explicitCallTransfer(obtainCompleteMessage(EVENT_ECT_RESULT));
+ }
+
+ void
+ clearDisconnected() {
+ internalClearDisconnected();
+
+ updatePhoneState();
+ phone.notifyCallStateChanged();
+ }
+
+ boolean
+ canConference() {
+ return foregroundCall.getState() == GsmCall.State.ACTIVE
+ && backgroundCall.getState() == GsmCall.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() {
+ return foregroundCall.getState() == GsmCall.State.ACTIVE
+ && backgroundCall.getState() == GsmCall.State.HOLDING;
+ }
+
+ //***** 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,"GsmCallTracker.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();
+ }
+ }
+
+ 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++) {
+ GsmConnection 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 GsmConnection(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 GsmCall 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 GsmConnection (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--) {
+ GsmConnection 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();
+ }
+
+ private void
+ handleRadioNotAvailable() {
+ // handlePollCalls will clear out its
+ // call list when it gets the CommandException
+ // error result from this
+ pollCallsWhenSafe();
+ }
+
+ private void
+ dumpState() {
+ List l;
+
+ Log.i(LOG_TAG,"Phone State:" + state);
+
+ Log.i(LOG_TAG,"Ringing call: " + ringingCall.toString());
+
+ l = ringingCall.getConnections();
+ for (int i = 0, s = l.size(); i < s; i++) {
+ Log.i(LOG_TAG,l.get(i).toString());
+ }
+
+ Log.i(LOG_TAG,"Foreground call: " + foregroundCall.toString());
+
+ l = foregroundCall.getConnections();
+ for (int i = 0, s = l.size(); i < s; i++) {
+ Log.i(LOG_TAG,l.get(i).toString());
+ }
+
+ Log.i(LOG_TAG,"Background call: " + backgroundCall.toString());
+
+ l = backgroundCall.getConnections();
+ for (int i = 0, s = l.size(); i < s; i++) {
+ Log.i(LOG_TAG,l.get(i).toString());
+ }
+
+ }
+
+ //***** Called from GsmConnection
+
+ /*package*/ void
+ hangup (GsmConnection conn) throws CallStateException {
+ if (conn.owner != this) {
+ throw new CallStateException ("GsmConnection " + conn
+ + "does not belong to GsmCallTracker " + 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.getGSMIndex(), obtainCompleteMessage());
+ } catch (CallStateException ex) {
+ // Ignore "connection not found"
+ // Call may have hung up already
+ Log.w(LOG_TAG,"GsmCallTracker WARN: hangup() on absent connection "
+ + conn);
+ }
+ }
+
+ conn.onHangupLocal();
+ }
+
+ /*package*/ void
+ separate (GsmConnection conn) throws CallStateException {
+ if (conn.owner != this) {
+ throw new CallStateException ("GsmConnection " + conn
+ + "does not belong to GsmCallTracker " + this);
+ }
+ try {
+ cm.separateConnection (conn.getGSMIndex(),
+ obtainCompleteMessage(EVENT_SEPARATE_RESULT));
+ } catch (CallStateException ex) {
+ // Ignore "connection not found"
+ // Call may have hung up already
+ Log.w(LOG_TAG,"GsmCallTracker WARN: separate() on absent connection "
+ + conn);
+ }
+ }
+
+ //***** Called from GSMPhone
+
+ /*package*/ void
+ setMute(boolean mute) {
+ desiredMute = mute;
+ cm.setMute(desiredMute, null);
+ }
+
+ /*package*/ boolean
+ getMute() {
+ return desiredMute;
+ }
+
+
+ //***** Called from GsmCall
+
+ /* package */ void
+ hangup (GsmCall 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((GsmConnection)(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 ("GsmCall " + call +
+ "does not belong to GsmCallTracker " + 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(GsmCall call, int index)
+ throws CallStateException {
+ int count = call.connections.size();
+ for (int i = 0; i < count; i++) {
+ GsmConnection cn = (GsmConnection)call.connections.get(i);
+ if (cn.getGSMIndex() == index) {
+ cm.hangupConnection(index, obtainCompleteMessage());
+ return;
+ }
+ }
+
+ throw new CallStateException("no gsm index found");
+ }
+
+ void hangupAllConnections(GsmCall call) throws CallStateException{
+ try {
+ int count = call.connections.size();
+ for (int i = 0; i < count; i++) {
+ GsmConnection cn = (GsmConnection)call.connections.get(i);
+ cm.hangupConnection(cn.getGSMIndex(), obtainCompleteMessage());
+ }
+ } catch (CallStateException ex) {
+ Log.e(LOG_TAG, "hangupConnectionByIndex caught " + ex);
+ }
+ }
+
+ /* package */
+ GsmConnection getConnectionByIndex(GsmCall call, int index)
+ throws CallStateException {
+ int count = call.connections.size();
+ for (int i = 0; i < count; i++) {
+ GsmConnection cn = (GsmConnection)call.connections.get(i);
+ if (cn.getGSMIndex() == 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;
+ }
+
+ //****** Overridden from Handler
+
+ public void
+ handleMessage (Message msg) {
+ AsyncResult ar;
+
+ switch (msg.what) {
+ case EVENT_POLL_CALLS_RESULT:
+ 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:
+ case EVENT_CONFERENCE_RESULT:
+ case EVENT_SEPARATE_RESULT:
+ case EVENT_ECT_RESULT:
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception != null) {
+ phone.notifySuppServiceFailed(getFailedService(msg.what));
+ }
+ 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];
+ }
+ // Log the causeCode if its not normal
+ if (causeCode == CallFailCause.NO_CIRCUIT_AVAIL ||
+ causeCode == CallFailCause.TEMPORARY_FAILURE ||
+ causeCode == CallFailCause.SWITCHING_CONGESTION ||
+ causeCode == CallFailCause.CHANNEL_NOT_AVAIL ||
+ causeCode == CallFailCause.QOS_NOT_AVAIL ||
+ causeCode == CallFailCause.BEARER_NOT_AVAIL ||
+ causeCode == CallFailCause.ERROR_UNSPECIFIED) {
+ int cid = -1;
+ GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
+ if (loc != null) cid = loc.getCid();
+
+ EventLog.List val = new EventLog.List(causeCode, cid,
+ TelephonyManager.getDefault().getNetworkType());
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CALL_DROP, val);
+ }
+
+ for (int i = 0, s = droppedDuringPoll.size()
+ ; i < s ; i++
+ ) {
+ GsmConnection conn = droppedDuringPoll.get(i);
+
+ conn.onRemoteDisconnect(causeCode);
+ }
+
+ updatePhoneState();
+
+ phone.notifyCallStateChanged();
+ droppedDuringPoll.clear();
+ break;
+
+ case EVENT_REPOLL_AFTER_DELAY:
+ case EVENT_CALL_STATE_CHANGE:
+ pollCallsWhenSafe();
+ break;
+
+ case EVENT_RADIO_AVAILABLE:
+ handleRadioAvailable();
+ break;
+
+ case EVENT_RADIO_NOT_AVAILABLE:
+ handleRadioNotAvailable();
+ break;
+ }
+ }
+
+ protected void log(String msg) {
+ Log.d(LOG_TAG, "[GsmCallTracker] " + msg);
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
new file mode 100644
index 0000000..2b2f077
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
@@ -0,0 +1,732 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+import android.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;
+
+import com.android.internal.telephony.*;
+
+/**
+ * {@hide}
+ */
+public class GsmConnection extends Connection {
+ static final String LOG_TAG = "GSM";
+
+ //***** Instance Variables
+
+ GsmCallTracker owner;
+ GsmCall parent;
+
+ String address; // MAY BE NULL!!!
+ String dialString; // outgoing calls only
+ String postDialString; // outgoing calls only
+ boolean isIncoming;
+ boolean disconnected;
+
+ int index; // index in GsmCallTracker.connections[], -1 if unassigned
+ // The GSM index is 1 + this
+
+ /*
+ * 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*/
+ GsmConnection (Context context, DriverCall dc, GsmCallTracker 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*/
+ GsmConnection (Context context, String dialString, GsmCallTracker ct, GsmCall 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, GsmCall.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 GsmCall 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() != GsmCall.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 GsmCall.State getState() {
+ if (disconnected) {
+ return GsmCall.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, "GsmConnection.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, "GsmConnection.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 allApns = null;
+
+ /**
+ * waitingApns holds all apns that are waiting to be connected
+ *
+ * It is a subset of allApns and has the same format
+ */
+ private ArrayList waitingApns = null;
+
+ private ApnSetting preferredApn = null;
+
+ /**
+ * pdpList holds all the PDP connection, i.e. IP Link in GPRS
+ */
+ private ArrayList pdpList;
+
+ /** Currently requested APN type */
+ private String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
+
+ /** Currently active APN */
+ private ApnSetting mActiveApn;
+
+ /** Currently active PdpConnection */
+ private PdpConnection mActivePdp;
+
+ private static int APN_DEFAULT_ID = 0;
+ private static int APN_MMS_ID = 1;
+ private static int APN_NUM_TYPES = 2;
+
+ private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
+
+ /** Is packet service restricted by network */
+ private boolean mIsPsRestricted = false;
+
+ //***** Constants
+
+ // TODO: Increase this to match the max number of simultaneous
+ // PDP contexts we plan to support.
+ /**
+ * Pool size of PdpConnection objects.
+ */
+ private static final int PDP_CONNECTION_POOL_SIZE = 1;
+
+ private static final int POLL_PDP_MILLIS = 5 * 1000;
+
+ //WINK:TODO: Teleca, is this really gsm specific, what about CDMA?
+ private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect";
+ private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
+
+ //***** Tag IDs for EventLog
+ private static final int EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED = 50101;
+ private static final int EVENT_LOG_RADIO_RESET = 50102;
+ private static final int EVENT_LOG_PDP_RESET = 50103;
+ private static final int EVENT_LOG_REREGISTER_NETWORK = 50104;
+ private static final int EVENT_LOG_RADIO_PDP_SETUP_FAIL = 50105;
+
+ static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn");
+ static final String APN_ID = "apn_id";
+ private boolean canSetPreferApn = false;
+
+ 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, "GPRS 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;
+ }
+ }
+ }
+ };
+
+ /** Watches for changes to the APN db. */
+ private ApnChangeObserver apnObserver;
+
+ //***** Constructor
+
+ GsmDataConnectionTracker(GSMPhone p) {
+ super(p);
+
+ p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
+ p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+ p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
+ p.mCM.registerForDataStateChanged (this, EVENT_DATA_STATE_CHANGED, null);
+ p.mCT.registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
+ p.mCT.registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
+ p.mSST.registerForGprsAttached(this, EVENT_GPRS_ATTACHED, null);
+ p.mSST.registerForGprsDetached(this, EVENT_GPRS_DETACHED, null);
+ p.mSST.registerForRoamingOn(this, EVENT_ROAMING_ON, null);
+ p.mSST.registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
+ p.mSST.registerForPsRestrictedEnabled(this, EVENT_PS_RESTRICT_ENABLED, null);
+ p.mSST.registerForPsRestrictedDisabled(this, EVENT_PS_RESTRICT_DISABLED, 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;
+ mResolver = phone.getContext().getContentResolver();
+
+ apnObserver = new ApnChangeObserver();
+ p.getContext().getContentResolver().registerContentObserver(
+ Telephony.Carriers.CONTENT_URI, true, apnObserver);
+
+ createAllPdpList();
+
+ // 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[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false);
+ noAutoAttach = !dataEnabled[APN_DEFAULT_ID];
+ }
+
+ public void dispose() {
+ //Unregister for all events
+ phone.mCM.unregisterForAvailable(this);
+ phone.mCM.unregisterForOffOrNotAvailable(this);
+ ((GSMPhone) phone).mSIMRecords.unregisterForRecordsLoaded(this);
+ phone.mCM.unregisterForDataStateChanged(this);
+ ((GSMPhone) phone).mCT.unregisterForVoiceCallEnded(this);
+ ((GSMPhone) phone).mCT.unregisterForVoiceCallStarted(this);
+ ((GSMPhone) phone).mSST.unregisterForGprsAttached(this);
+ ((GSMPhone) phone).mSST.unregisterForGprsDetached(this);
+ ((GSMPhone) phone).mSST.unregisterForRoamingOn(this);
+ ((GSMPhone) phone).mSST.unregisterForRoamingOff(this);
+ ((GSMPhone) phone).mSST.unregisterForPsRestrictedEnabled(this);
+ ((GSMPhone) phone).mSST.unregisterForPsRestrictedDisabled(this);
+
+ phone.getContext().unregisterReceiver(this.mIntentReceiver);
+ phone.getContext().getContentResolver().unregisterContentObserver(this.apnObserver);
+
+ destroyAllPdpList();
+ }
+
+ protected void finalize() {
+ if(DBG) Log.d(LOG_TAG, "GsmDataConnectionTracker finalized");
+ }
+
+ void setState(State s) {
+ if (DBG) log ("setState: " + s);
+ if (state != s) {
+ if (s == State.INITING) { // request PDP context
+ Checkin.updateStats(
+ phone.getContext().getContentResolver(),
+ Checkin.Stats.Tag.PHONE_GPRS_ATTEMPTED, 1, 0.0);
+ }
+
+ if (s == State.CONNECTED) { // pppd is up
+ Checkin.updateStats(
+ phone.getContext().getContentResolver(),
+ Checkin.Stats.Tag.PHONE_GPRS_CONNECTED, 1, 0.0);
+ }
+ }
+
+ state = s;
+
+ if (state == State.FAILED) {
+ if (waitingApns != null)
+ waitingApns.clear(); // when teardown the connection and set to IDLE
+ }
+ }
+
+ String[] getActiveApnTypes() {
+ String[] result;
+ if (mActiveApn != null) {
+ result = mActiveApn.types;
+ } else {
+ result = new String[1];
+ result[0] = Phone.APN_TYPE_DEFAULT;
+ }
+ return result;
+ }
+
+ protected String getActiveApnString() {
+ String result = null;
+ if (mActiveApn != null) {
+ result = mActiveApn.apn;
+ }
+ return result;
+ }
+
+ /**
+ * Ensure that we are connected to an APN of the specified type.
+ * @param type the APN type (currently the only valid value
+ * is {@link Phone#APN_TYPE_MMS})
+ * @return the result of the operation. Success is indicated by
+ * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or
+ * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast
+ * will be sent by the ConnectivityManager when a connection to
+ * the APN has been established.
+ */
+ protected int enableApnType(String type) {
+ if (!TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
+ return Phone.APN_REQUEST_FAILED;
+ }
+ // If already active, return
+ Log.d(LOG_TAG, "enableApnType("+type+")");
+ if (isApnTypeActive(type)) {
+ setEnabled(type, true);
+ removeMessages(EVENT_RESTORE_DEFAULT_APN);
+ /**
+ * We're being asked to enable a non-default APN that's already in use.
+ * This means we should restart the timer that will automatically
+ * switch back to the default APN and disable the non-default APN
+ * when it expires.
+ */
+ sendMessageDelayed(
+ obtainMessage(EVENT_RESTORE_DEFAULT_APN),
+ getRestoreDefaultApnDelay());
+ if (state == State.INITING) return Phone.APN_REQUEST_STARTED;
+ else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE;
+ }
+
+ if (!isApnTypeAvailable(type)) {
+ return Phone.APN_TYPE_NOT_AVAILABLE;
+ }
+
+ setEnabled(type, true);
+ mRequestedApnType = type;
+ sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN));
+ return Phone.APN_REQUEST_STARTED;
+ }
+
+ /**
+ * The APN of the specified type is no longer needed. Ensure that if
+ * use of the default APN has not been explicitly disabled, we are connected
+ * to the default APN.
+ * @param type the APN type. The only valid value currently is {@link Phone#APN_TYPE_MMS}.
+ * @return
+ */
+ protected int disableApnType(String type) {
+ Log.d(LOG_TAG, "disableApnType("+type+")");
+ if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
+ removeMessages(EVENT_RESTORE_DEFAULT_APN);
+ setEnabled(type, false);
+ if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
+ if (dataEnabled[APN_DEFAULT_ID]) {
+ return Phone.APN_ALREADY_ACTIVE;
+ } else {
+ cleanUpConnection(true, Phone.REASON_DATA_DISABLED);
+ return Phone.APN_REQUEST_STARTED;
+ }
+ } else {
+ /*
+ * Note that if default data is disabled, the following
+ * has the effect of disabling the MMS APN, and then
+ * ignoring the request to enable the default APN.
+ * The net result is that data is completely disabled.
+ */
+ sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN));
+ return Phone.APN_REQUEST_STARTED;
+ }
+ } else {
+ return Phone.APN_REQUEST_FAILED;
+ }
+ }
+
+ /**
+ * The data connection is expected to be setup while device
+ * 1. has sim card
+ * 2. registered to gprs 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 (((GSMPhone) phone).mSIMRecords.getRecordsLoaded() &&
+ ((GSMPhone) phone).mSST.getCurrentGprsState() == ServiceState.STATE_IN_SERVICE &&
+ (!roaming || getDataOnRoamingEnabled()) &&
+ !mIsWifiConnected &&
+ !mIsPsRestricted ) {
+ return (state == State.CONNECTED);
+ }
+ return true;
+ }
+
+ private boolean isApnTypeActive(String type) {
+ // TODO: to support simultaneous, mActiveApn can be a List instead.
+ return mActiveApn != null && mActiveApn.canHandleType(type);
+ }
+
+ private boolean isApnTypeAvailable(String type) {
+ if (allApns != null) {
+ for (ApnSetting apn : allApns) {
+ if (apn.canHandleType(type)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean isEnabled(String apnType) {
+ if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) {
+ return dataEnabled[APN_DEFAULT_ID];
+ } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) {
+ return dataEnabled[APN_MMS_ID];
+ } else {
+ return false;
+ }
+ }
+
+ private void setEnabled(String apnType, boolean enable) {
+ Log.d(LOG_TAG, "setEnabled(" + apnType + ", " + enable + ')');
+ if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) {
+ dataEnabled[APN_DEFAULT_ID] = enable;
+ } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) {
+ dataEnabled[APN_MMS_ID] = enable;
+ }
+ Log.d(LOG_TAG, "dataEnabled[DEFAULT_APN]=" + dataEnabled[APN_DEFAULT_ID] +
+ " dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID]);
+ }
+
+ /**
+ * Prevent mobile data connections from being established,
+ * or once again allow mobile data connections. If the state
+ * toggles, then either tear down or set up data, as
+ * appropriate to match the new state.
+ * This operation only affects the default APN, and if the same APN is
+ * currently being used for MMS traffic, the teardown will not happen
+ * even when {@code enable} is {@code false}.
+ * @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(Phone.APN_TYPE_DEFAULT);
+ Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled);
+ if (!isEnabled && enable) {
+ setEnabled(Phone.APN_TYPE_DEFAULT, true);
+ // trySetupData() will be a no-op if we are currently
+ // connected to the MMS APN
+ return trySetupData(Phone.REASON_DATA_ENABLED);
+ } else if (!enable) {
+ setEnabled(Phone.APN_TYPE_DEFAULT, false);
+ // Don't tear down if there is an active APN and it handles MMS.
+ // TODO: This isn't very general.
+ if (!isApnTypeActive(Phone.APN_TYPE_MMS) || !isEnabled(Phone.APN_TYPE_MMS)) {
+ cleanUpConnection(true, Phone.REASON_DATA_DISABLED);
+ return true;
+ }
+ return false;
+ } else {
+ // isEnabled && enable
+ return true;
+ }
+ }
+
+ /**
+ * Simply tear down data connections due to radio off
+ * and don't setup again.
+ */
+ public void cleanConnectionBeforeRadioOff() {
+ cleanUpConnection(true, Phone.REASON_RADIO_TURNED_OFF);
+ }
+
+ /**
+ * Report the current state of data connectivity (enabled or disabled) for
+ * the default APN.
+ * @return {@code false} if data connectivity has been explicitly disabled,
+ * {@code true} otherwise.
+ */
+ public boolean getDataEnabled() {
+ return dataEnabled[APN_DEFAULT_ID];
+ }
+
+ /**
+ * Report on whether data connectivity is enabled for any APN.
+ * @return {@code false} if data connectivity has been explicitly disabled,
+ * {@code true} otherwise.
+ */
+ public boolean getAnyDataEnabled() {
+ return dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID];
+ }
+
+ /**
+ * Formerly this method was ArrayList getAllPdps()
+ */
+ public ArrayList getAllDataConnections() {
+ ArrayList pdps = (ArrayList)pdpList.clone();
+ return pdps;
+ }
+
+ private boolean isDataAllowed() {
+ boolean roaming = phone.getServiceState().getRoaming();
+ return getAnyDataEnabled() && (!roaming || getDataOnRoamingEnabled());
+ }
+
+ //****** Called from ServiceStateTracker
+ /**
+ * Invoked when ServiceStateTracker observes a transition from GPRS
+ * attach to detach.
+ */
+ protected void onGprsDetached() {
+ /*
+ * We presently believe it is unnecessary to tear down the PDP context
+ * when GPRS detaches, but we should stop the network polling.
+ */
+ stopNetStatPoll();
+ phone.notifyDataConnection(Phone.REASON_GPRS_DETACHED);
+ }
+
+ private void onGprsAttached() {
+ if (state == State.CONNECTED) {
+ startNetStatPoll();
+ phone.notifyDataConnection(Phone.REASON_GPRS_ATTACHED);
+ } else {
+ if (state == State.FAILED) {
+ cleanUpConnection(false, Phone.REASON_GPRS_ATTACHED);
+ nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ }
+ trySetupData(Phone.REASON_GPRS_ATTACHED);
+ }
+ }
+
+ private boolean trySetupData(String reason) {
+ if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason));
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted);
+
+ 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 gprsState = ((GSMPhone) phone).mSST.getCurrentGprsState();
+ boolean roaming = phone.getServiceState().getRoaming();
+
+ if ((state == State.IDLE || state == State.SCANNING)
+ && (gprsState == ServiceState.STATE_IN_SERVICE || noAutoAttach)
+ && ((GSMPhone) phone).mSIMRecords.getRecordsLoaded()
+ && ( ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() ||
+ phone.getState() == Phone.State.IDLE )
+ && isDataAllowed()
+ && !mIsPsRestricted ) {
+
+ if (state == State.IDLE) {
+ waitingApns = buildWaitingApns();
+ if (waitingApns.isEmpty()) {
+ if (DBG) log("No APN found");
+ notifyNoData(PdpConnection.FailCause.BAD_APN);
+ return false;
+ } else {
+ log ("Create from allApns : " + apnListToString(allApns));
+ }
+ }
+
+ if (DBG) {
+ log ("Setup watingApns : " + apnListToString(waitingApns));
+ }
+ return setupData(reason);
+ } else {
+ if (DBG)
+ log("trySetupData: Not ready for data: " +
+ " dataState=" + state +
+ " gprsState=" + gprsState +
+ " sim=" + ((GSMPhone) phone).mSIMRecords.getRecordsLoaded() +
+ " UMTS=" + ((GSMPhone) phone).mSST.isConcurrentVoiceAndData() +
+ " phoneState=" + phone.getState() +
+ " dataEnabled=" + getAnyDataEnabled() +
+ " roaming=" + roaming +
+ " dataOnRoamingEnable=" + getDataOnRoamingEnabled() +
+ " ps restricted=" + mIsPsRestricted);
+ 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 PdpConnection 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 conn : pdpList) {
+ PdpConnection pdp = (PdpConnection) conn;
+ if (tearDown) {
+ Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
+ pdp.disconnect(msg);
+ } else {
+ pdp.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 pdp.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);
+ mActiveApn = null;
+ } else if (state != State.IDLE) {
+ setState(State.DISCONNECTING);
+ }
+ }
+
+ /**
+ * @param types comma delimited list of APN types
+ * @return array of APN types
+ */
+ private String[] parseTypes(String types) {
+ String[] result;
+ // If unset, set to DEFAULT.
+ if (types == null || types.equals("")) {
+ result = new String[1];
+ result[0] = Phone.APN_TYPE_ALL;
+ } else {
+ result = types.split(",");
+ }
+ return result;
+ }
+
+ private ArrayList createApnList(Cursor cursor) {
+ ArrayList result = new ArrayList();
+ if (cursor.moveToFirst()) {
+ do {
+ String[] types = parseTypes(
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
+ ApnSetting apn = new ApnSetting(
+ cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
+ types);
+ result.add(apn);
+ } while (cursor.moveToNext());
+ }
+ return result;
+ }
+
+ private PdpConnection findFreePdp() {
+ for (DataConnection conn : pdpList) {
+ PdpConnection pdp = (PdpConnection) conn;
+ if (pdp.getState() == DataConnection.State.INACTIVE) {
+ return pdp;
+ }
+ }
+ return null;
+ }
+
+ private boolean setupData(String reason) {
+ ApnSetting apn;
+ PdpConnection pdp;
+
+ apn = getNextApn();
+ if (apn == null) return false;
+ pdp = findFreePdp();
+ if (pdp == null) {
+ if (DBG) log("setupData: No free PdpConnection found!");
+ return false;
+ }
+ mActiveApn = apn;
+ mActivePdp = pdp;
+
+ Message msg = obtainMessage();
+ msg.what = EVENT_DATA_SETUP_COMPLETE;
+ msg.obj = reason;
+ pdp.connect(apn, msg);
+
+ setState(State.INITING);
+ phone.notifyDataConnection(reason);
+ return true;
+ }
+
+ String getInterfaceName(String apnType) {
+ if (mActivePdp != null
+ && (apnType == null || mActiveApn.canHandleType(apnType))) {
+ return mActivePdp.getInterface();
+ }
+ return null;
+ }
+
+ protected String getIpAddress(String apnType) {
+ if (mActivePdp != null
+ && (apnType == null || mActiveApn.canHandleType(apnType))) {
+ return mActivePdp.getIpAddress();
+ }
+ return null;
+ }
+
+ String getGateway(String apnType) {
+ if (mActivePdp != null
+ && (apnType == null || mActiveApn.canHandleType(apnType))) {
+ return mActivePdp.getGatewayAddress();
+ }
+ return null;
+ }
+
+ protected String[] getDnsServers(String apnType) {
+ if (mActivePdp != null
+ && (apnType == null || mActiveApn.canHandleType(apnType))) {
+ return mActivePdp.getDnsServers();
+ }
+ return null;
+ }
+
+ private boolean
+ pdpStatesHasCID (ArrayList states, int cid) {
+ for (int i = 0, s = states.size() ; i < s ; i++) {
+ if (states.get(i).cid == cid) return true;
+ }
+
+ return false;
+ }
+
+ private boolean
+ pdpStatesHasActiveCID (ArrayList states, int cid) {
+ for (int i = 0, s = states.size() ; i < s ; i++) {
+ if (states.get(i).cid == cid) return states.get(i).active;
+ }
+
+ return false;
+ }
+
+ /**
+ * Handles changes to the APN database.
+ */
+ private void onApnChanged() {
+ boolean isConnected;
+
+ isConnected = (state != State.IDLE && state != State.FAILED);
+
+ // The "current" may no longer be valid. MMS depends on this to send properly.
+ ((GSMPhone) phone).updateCurrentCarrierInProvider();
+
+ // TODO: It'd be nice to only do this if the changed entrie(s)
+ // match the current operator.
+ createAllApnList();
+ if (state != State.DISCONNECTING) {
+ cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED);
+ if (!isConnected) {
+ trySetupData(Phone.REASON_APN_CHANGED);
+ }
+ }
+ }
+
+ /**
+ * @param explicitPoll if true, indicates that *we* polled for this
+ * update while state == CONNECTED rather than having it delivered
+ * via an unsolicited response (which could have happened at any
+ * previous state
+ */
+ protected void onPdpStateChanged (AsyncResult ar, boolean explicitPoll) {
+ ArrayList pdpStates;
+
+ pdpStates = (ArrayList)(ar.result);
+
+ 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;
+ }
+
+
+ // This is how things are supposed to work:
+ // The PDP list is supposed to be empty of the CID
+ // when it disconnects
+
+ if (state == State.CONNECTED
+ && !pdpStatesHasCID(pdpStates, cidActive)) {
+
+ // It looks like the PDP context has deactivated
+ // Tear everything down and try to reconnect
+
+ Log.i(LOG_TAG, "PDP connection has dropped. Reconnecting");
+
+ // Add an event log when the network drops PDP
+ int cid = -1;
+ GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
+ if (loc != null) cid = loc.getCid();
+
+ EventLog.List val = new EventLog.List(cid,
+ TelephonyManager.getDefault().getNetworkType());
+
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
+
+ cleanUpConnection(true, null);
+
+ return;
+ }
+
+ if (true) {
+ //
+ // Workaround for issue #655426
+ //
+
+ // --------------------------
+
+ // This is how some things work now: the PDP context is still
+ // listed with active = false, which makes it hard to
+ // distinguish an activating context from an activated-and-then
+ // deactivated one.
+ //
+ // Here, we only consider this authoritative if we asked for the
+ // PDP list. If it was an unsolicited response, we poll again
+ // to make sure everyone agrees on the initial state
+
+ if (state == State.CONNECTED
+ && !pdpStatesHasActiveCID(pdpStates, cidActive)) {
+
+ if (!explicitPoll) {
+ // We think it disconnected but aren't sure...poll from our side
+ phone.mCM.getPDPContextList(
+ this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
+ } else {
+ Log.i(LOG_TAG, "PDP connection has dropped (active=false case). "
+ + " Reconnecting");
+
+ // Log the network drop on the event log.
+ int cid = -1;
+ GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
+ if (loc != null) cid = loc.getCid();
+
+ EventLog.List val = new EventLog.List(cid,
+ TelephonyManager.getDefault().getNetworkType());
+
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_NETWORK_DROP, val);
+
+ cleanUpConnection(true, null);
+ }
+ }
+ }
+ }
+
+ private void notifyDefaultData(String reason) {
+ setupDnsProperties();
+ setState(State.CONNECTED);
+ phone.notifyDataConnection(reason);
+ startNetStatPoll();
+ // reset reconnect timer
+ nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ }
+
+ private void setupDnsProperties() {
+ int mypid = android.os.Process.myPid();
+ String[] servers = getDnsServers(null);
+ String propName;
+ String propVal;
+ int count;
+
+ count = 0;
+ for (int i = 0; i < servers.length; i++) {
+ String serverAddr = servers[i];
+ if (!TextUtils.equals(serverAddr, "0.0.0.0")) {
+ SystemProperties.set("net.dns" + (i+1) + "." + mypid, serverAddr);
+ count++;
+ }
+ }
+ for (int i = count+1; i <= 4; i++) {
+ propName = "net.dns" + i + "." + mypid;
+ propVal = SystemProperties.get(propName);
+ if (propVal.length() != 0) {
+ SystemProperties.set(propName, "");
+ }
+ }
+ /*
+ * Bump the property that tells the name resolver library
+ * to reread the DNS server list from the properties.
+ */
+ propVal = SystemProperties.get("net.dnschange");
+ if (propVal.length() != 0) {
+ try {
+ int n = Integer.parseInt(propVal);
+ SystemProperties.set("net.dnschange", "" + (n+1));
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+
+ /**
+ * This is a kludge to deal with the fact that
+ * the PDP state change notification doesn't always work
+ * with certain RIL impl's/basebands
+ *
+ */
+ private void startPeriodicPdpPoll() {
+ removeMessages(EVENT_POLL_PDP);
+
+ sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS);
+ }
+
+ private void resetPollStats() {
+ txPkts = -1;
+ rxPkts = -1;
+ sentSinceLastRecv = 0;
+ netStatPollPeriod = POLL_NETSTAT_MILLIS;
+ mNoRecvPollCount = 0;
+ }
+
+ private void doRecovery() {
+ if (state == State.CONNECTED) {
+ int maxPdpReset = Settings.Gservices.getInt(mResolver,
+ Settings.Gservices.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT,
+ DEFAULT_MAX_PDP_RESET_FAIL);
+ if (mPdpResetCount < maxPdpReset) {
+ mPdpResetCount++;
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_RESET, sentSinceLastRecv);
+ cleanUpConnection(true, Phone.REASON_PDP_RESET);
+ } else {
+ mPdpResetCount = 0;
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_REREGISTER_NETWORK, sentSinceLastRecv);
+ ((GSMPhone) phone).mSST.reRegisterNetwork(null);
+ }
+ // TODO: Add increasingly drastic recovery steps, eg,
+ // reset the radio, reset the device.
+ }
+ }
+
+ protected void startNetStatPoll() {
+ if (state == State.CONNECTED && mPingTestActive == false && 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.
+ */
+
+ int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0"));
+ SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1));
+ }
+
+ private Runnable mPollNetStat = new Runnable()
+ {
+
+ public void run() {
+ long sent, received;
+ long preTxPkts = -1, preRxPkts = -1;
+
+ Activity newActivity;
+
+ preTxPkts = txPkts;
+ preRxPkts = rxPkts;
+
+ 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;
+ mPdpResetCount = 0;
+ } 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;
+ mPdpResetCount = 0;
+ } else if (sent == 0 && received == 0) {
+ newActivity = Activity.NONE;
+ } else {
+ sentSinceLastRecv = 0;
+ newActivity = Activity.NONE;
+ }
+
+ if (activity != newActivity && mIsScreenOn) {
+ activity = newActivity;
+ phone.notifyDataActivity();
+ }
+ }
+
+ int watchdogTrigger = Settings.Gservices.getInt(mResolver,
+ Settings.Gservices.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
+ NUMBER_SENT_PACKETS_OF_HANG);
+
+ if (sentSinceLastRecv >= watchdogTrigger) {
+ // we already have NUMBER_SENT_PACKETS sent without ack
+ if (mNoRecvPollCount == 0) {
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_RESET_COUNTDOWN_TRIGGERED,
+ sentSinceLastRecv);
+ }
+
+ int noRecvPollLimit = Settings.Gservices.getInt(mResolver,
+ Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_COUNT, NO_RECV_POLL_LIMIT);
+
+ if (mNoRecvPollCount < noRecvPollLimit) {
+ // It's possible the PDP context went down and we weren't notified.
+ // Start polling the context list in an attempt to recover.
+ if (DBG) log("no DATAIN in a while; polling PDP");
+ phone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
+
+ mNoRecvPollCount++;
+
+ // Slow down the poll interval to let things happen
+ netStatPollPeriod = Settings.Gservices.getInt(mResolver,
+ Settings.Gservices.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS,
+ POLL_NETSTAT_SLOW_MILLIS);
+ } else {
+ if (DBG) log("Sent " + String.valueOf(sentSinceLastRecv) +
+ " pkts since last received");
+ // We've exceeded the threshold. Run ping test as a final check;
+ // it will proceed with recovery if ping fails.
+ stopNetStatPoll();
+ Thread pingTest = new Thread() {
+ public void run() {
+ runPingTest();
+ }
+ };
+ mPingTestActive = true;
+ pingTest.start();
+ }
+ } else {
+ mNoRecvPollCount = 0;
+ if (mIsScreenOn) {
+ netStatPollPeriod = Settings.Gservices.getInt(mResolver,
+ Settings.Gservices.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS);
+ } else {
+ netStatPollPeriod = Settings.Gservices.getInt(mResolver,
+ Settings.Gservices.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
+ POLL_NETSTAT_SCREEN_OFF_MILLIS);
+ }
+ }
+
+ if (netStatPollEnabled) {
+ mDataConnectionTracker.postDelayed(this, netStatPollPeriod);
+ }
+ }
+ };
+
+ private void runPingTest () {
+ int status = -1;
+ try {
+ String address = Settings.Gservices.getString(mResolver,
+ Settings.Gservices.PDP_WATCHDOG_PING_ADDRESS);
+ int deadline = Settings.Gservices.getInt(mResolver,
+ Settings.Gservices.PDP_WATCHDOG_PING_DEADLINE, DEFAULT_PING_DEADLINE);
+ if (DBG) log("pinging " + address + " for " + deadline + "s");
+ if (address != null && !NULL_IP.equals(address)) {
+ Process p = Runtime.getRuntime()
+ .exec("ping -c 1 -i 1 -w "+ deadline + " " + address);
+ status = p.waitFor();
+ }
+ } catch (IOException e) {
+ Log.w(LOG_TAG, "ping failed: IOException");
+ } catch (Exception e) {
+ Log.w(LOG_TAG, "exception trying to ping");
+ }
+
+ if (status == 0) {
+ // ping succeeded. False alarm. Reset netStatPoll.
+ // ("-1" for this event indicates a false alarm)
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_PDP_RESET, -1);
+ mPdpResetCount = 0;
+ sendMessage(obtainMessage(EVENT_START_NETSTAT_POLL));
+ } else {
+ // ping failed. Proceed with recovery.
+ sendMessage(obtainMessage(EVENT_START_RECOVERY));
+ }
+ }
+
+ /**
+ * Returns true if the last fail cause is something that
+ * seems like it deserves an error notification.
+ * Transient errors are ignored
+ */
+ private boolean shouldPostNotification(PdpConnection.FailCause cause) {
+ boolean shouldPost = true;
+ // TODO CHECK
+ // if (dataLink != null) {
+ // shouldPost = dataLink.getLastLinkExitCode() != DataLink.EXIT_OPEN_FAILED;
+ //}
+ return (shouldPost && cause != PdpConnection.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, "PDP 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 GPRS Unavailable notification "
+ + "-- likely transient error");
+ } else {
+ notifyNoData(lastFailCauseCode);
+ }
+ }
+ }
+
+ private void notifyNoData(PdpConnection.FailCause lastFailCauseCode) {
+ setState(State.FAILED);
+ }
+
+ protected void onRecordsLoaded() {
+ createAllApnList();
+ if (state == State.FAILED) {
+ cleanUpConnection(false, null);
+ }
+ sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
+ }
+
+ protected void onEnableNewApn() {
+ // TODO: To support simultaneous PDP contexts, this should really only call
+ // cleanUpConnection if it needs to free up a PdpConnection.
+ cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
+ }
+
+ protected void onTrySetupData() {
+ trySetupData(null);
+ }
+
+ protected void onRestoreDefaultApn() {
+ if (DBG) Log.d(LOG_TAG, "Restore default APN");
+ setEnabled(Phone.APN_TYPE_MMS, false);
+
+ if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
+ cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN);
+ mRequestedApnType = Phone.APN_TYPE_DEFAULT;
+ }
+ }
+
+ protected void onRoamingOff() {
+ trySetupData(Phone.REASON_ROAMING_OFF);
+ }
+
+ 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);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ 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");
+ // TODO: Should we reset mRequestedApnType to "default"?
+ cleanUpConnection(false, Phone.REASON_RADIO_TURNED_OFF);
+ }
+ }
+
+ protected void onDataSetupComplete(AsyncResult ar) {
+ String reason = null;
+ if (ar.userObj instanceof String) {
+ reason = (String) ar.userObj;
+ }
+
+ if (ar.exception == null) {
+ // everything is setup
+
+ /*
+ * We may have switched away from the default PDP context
+ * in order to enable a "special" APN (e.g., for MMS
+ * traffic). Set a timer to switch back and/or disable the
+ * special APN, so that a negligient application doesn't
+ * permanently prevent data connectivity. What we are
+ * protecting against here is not malicious apps, but
+ * rather an app that inadvertantly fails to reset to the
+ * default APN, or that dies before doing so.
+ */
+ if (dataEnabled[APN_MMS_ID]) {
+ removeMessages(EVENT_RESTORE_DEFAULT_APN);
+ sendMessageDelayed(obtainMessage(EVENT_RESTORE_DEFAULT_APN),
+ getRestoreDefaultApnDelay());
+ }
+ if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
+ SystemProperties.set("gsm.defaultpdpcontext.active", "true");
+ if (canSetPreferApn && preferredApn == null) {
+ Log.d(LOG_TAG, "PREFERED APN is null");
+ preferredApn = mActiveApn;
+ setPreferredApn(preferredApn.id);
+ }
+ } else {
+ SystemProperties.set("gsm.defaultpdpcontext.active", "false");
+ }
+ notifyDefaultData(reason);
+
+ // TODO: For simultaneous PDP support, we need to build another
+ // trigger another TRY_SETUP_DATA for the next APN type. (Note
+ // that the existing connection may service that type, in which
+ // case we should try the next type, etc.
+ } else {
+ PdpConnection.FailCause cause;
+ cause = (PdpConnection.FailCause) (ar.result);
+ if(DBG) log("PDP setup failed " + cause);
+ // Log this failure to the Event Logs.
+ if (cause == PdpConnection.FailCause.BAD_APN ||
+ cause == PdpConnection.FailCause.BAD_PAP_SECRET ||
+ cause == PdpConnection.FailCause.BARRED ||
+ cause == PdpConnection.FailCause.RADIO_ERROR_RETRY ||
+ cause == PdpConnection.FailCause.SUSPENED_TEMPORARY ||
+ cause == PdpConnection.FailCause.UNKNOWN ||
+ cause == PdpConnection.FailCause.USER_AUTHENTICATION) {
+ int cid = -1;
+ GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
+ if (loc != null) cid = loc.getCid();
+
+ EventLog.List val = new EventLog.List(
+ cause.ordinal(), cid,
+ TelephonyManager.getDefault().getNetworkType());
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_RADIO_PDP_SETUP_FAIL, val);
+ }
+
+ // No try for permanent failure
+ if (cause.isPermanentFail()) {
+ notifyNoData(cause);
+ }
+
+ if (tryNextApn(cause)) {
+ waitingApns.remove(0);
+ if (waitingApns.isEmpty()) {
+ // No more to try, start delayed retry
+ startDelayedRetry(cause, reason);
+ } else {
+ // we still have more apns to try
+ setState(State.SCANNING);
+ trySetupData(reason);
+ }
+ } else {
+ startDelayedRetry(cause, reason);
+ }
+ }
+ }
+
+ protected void onDisconnectDone(AsyncResult ar) {
+ String reason = null;
+ if(DBG) log("EVENT_DISCONNECT_DONE");
+ if (ar.userObj instanceof String) {
+ reason = (String) ar.userObj;
+ }
+ setState(State.IDLE);
+ phone.notifyDataConnection(reason);
+ mActiveApn = null;
+ if (retryAfterDisconnected(reason)) {
+ trySetupData(reason);
+ }
+ }
+
+ protected void onPollPdp() {
+ if (state == State.CONNECTED) {
+ // only poll when connected
+ phone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
+ sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS);
+ }
+ }
+
+ protected void onVoiceCallStarted() {
+ if (state == State.CONNECTED && !((GSMPhone) phone).mSST.isConcurrentVoiceAndData()) {
+ stopNetStatPoll();
+ phone.notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
+ }
+ }
+
+ protected void onVoiceCallEnded() {
+ if (state == State.CONNECTED) {
+ if (!((GSMPhone) 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 tryNextApn(FailCause cause) {
+ return (cause != FailCause.RADIO_NOT_AVAILABLE)
+ && (cause != FailCause.RADIO_OFF)
+ && (cause != FailCause.RADIO_ERROR_RETRY)
+ && (cause != FailCause.NO_SIGNAL)
+ && (cause != FailCause.SIM_LOCKED);
+ }
+
+ private int getRestoreDefaultApnDelay() {
+ String restoreApnDelayStr = SystemProperties.get(APN_RESTORE_DELAY_PROP_NAME);
+
+ if (restoreApnDelayStr != null && restoreApnDelayStr.length() != 0) {
+ try {
+ return Integer.valueOf(restoreApnDelayStr);
+ } catch (NumberFormatException e) {
+ }
+ }
+ return RESTORE_DEFAULT_APN_DELAY;
+ }
+
+ /**
+ * Based on the sim operator numeric, create a list for all possible pdps
+ * with all apns associated with that pdp
+ *
+ *
+ */
+ private void createAllApnList() {
+ allApns = new ArrayList();
+ String operator = ((GSMPhone) phone).mSIMRecords.getSIMOperatorNumeric();
+
+ if (operator != null) {
+ String selection = "numeric = '" + operator + "'";
+
+ Cursor cursor = phone.getContext().getContentResolver().query(
+ Telephony.Carriers.CONTENT_URI, null, selection, null, null);
+
+ if (cursor != null) {
+ if (cursor.getCount() > 0) {
+ allApns = createApnList(cursor);
+ // TODO: Figure out where this fits in. This basically just
+ // writes the pap-secrets file. No longer tied to PdpConnection
+ // object. Not used on current platform (no ppp).
+ //PdpConnection pdp = pdpList.get(pdp_name);
+ //if (pdp != null && pdp.dataLink != null) {
+ // pdp.dataLink.setPasswordInfo(cursor);
+ //}
+ }
+ cursor.close();
+ }
+ }
+
+ if (allApns.isEmpty()) {
+ if (DBG) log("No APN found for carrier: " + operator);
+ preferredApn = null;
+ notifyNoData(PdpConnection.FailCause.BAD_APN);
+ } else {
+ preferredApn = getPreferredApn();
+ Log.d(LOG_TAG, "Get PreferredAPN");
+ if (preferredApn != null && !preferredApn.numeric.equals(operator)) {
+ preferredApn = null;
+ setPreferredApn(-1);
+ }
+ }
+ }
+
+ private void createAllPdpList() {
+ pdpList = new ArrayList();
+ DataConnection pdp;
+
+ for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) {
+ pdp = new PdpConnection((GSMPhone) phone);
+ pdpList.add(pdp);
+ }
+ }
+
+ private void destroyAllPdpList() {
+ if(pdpList != null) {
+ PdpConnection pdp;
+ pdpList.removeAll(pdpList);
+ }
+ }
+
+ /**
+ *
+ * @return waitingApns list to be used to create PDP
+ * error when waitingApns.isEmpty()
+ */
+ private ArrayList buildWaitingApns() {
+ ArrayList apnList = new ArrayList();
+ String operator = ((GSMPhone )phone).mSIMRecords.getSIMOperatorNumeric();
+
+ if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
+ if (canSetPreferApn && preferredApn != null) {
+ Log.i(LOG_TAG, "Preferred APN:" + operator + ":"
+ + preferredApn.numeric + ":" + preferredApn);
+ if (preferredApn.numeric.equals(operator)) {
+ Log.i(LOG_TAG, "Waiting APN set to preferred APN");
+ apnList.add(preferredApn);
+ return apnList;
+ } else {
+ setPreferredApn(-1);
+ preferredApn = null;
+ }
+ }
+ }
+
+ if (allApns != null) {
+ for (ApnSetting apn : allApns) {
+ if (apn.canHandleType(mRequestedApnType)) {
+ apnList.add(apn);
+ }
+ }
+ }
+ return apnList;
+ }
+
+ /**
+ * Get next apn in waitingApns
+ * @return the first apn found in waitingApns, null if none
+ */
+ private ApnSetting getNextApn() {
+ ArrayList list = waitingApns;
+ ApnSetting apn = null;
+
+ if (list != null) {
+ if (!list.isEmpty()) {
+ apn = list.get(0);
+ }
+ }
+ return apn;
+ }
+
+ private String apnListToString (ArrayList apns) {
+ StringBuilder result = new StringBuilder();
+ for (int i = 0, size = apns.size(); i < size; i++) {
+ result.append('[')
+ .append(apns.get(i).toString())
+ .append(']');
+ }
+ return result.toString();
+ }
+
+ private void startDelayedRetry(PdpConnection.FailCause cause, String reason) {
+ notifyNoData(cause);
+ if (mRequestedApnType != Phone.APN_TYPE_DEFAULT) {
+ sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN));
+ }
+ else {
+ reconnectAfterFail(cause, reason);
+ }
+ }
+
+ private void setPreferredApn(int pos) {
+ if (!canSetPreferApn) {
+ return;
+ }
+
+ ContentResolver resolver = phone.getContext().getContentResolver();
+ resolver.delete(PREFERAPN_URI, null, null);
+
+ if (pos >= 0) {
+ ContentValues values = new ContentValues();
+ values.put(APN_ID, pos);
+ resolver.insert(PREFERAPN_URI, values);
+ }
+ }
+
+ private ApnSetting getPreferredApn() {
+ if (allApns.isEmpty()) {
+ return null;
+ }
+
+ Cursor cursor = phone.getContext().getContentResolver().query(
+ PREFERAPN_URI, new String[] { "_id", "name", "apn" },
+ null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
+
+ if (cursor != null) {
+ canSetPreferApn = true;
+ } else {
+ canSetPreferApn = false;
+ }
+
+ if (canSetPreferApn && cursor.getCount() > 0) {
+ int pos;
+ cursor.moveToFirst();
+ pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
+ for(ApnSetting p:allApns) {
+ if (p.id == pos && p.canHandleType(mRequestedApnType)) {
+ cursor.close();
+ return p;
+ }
+ }
+ }
+
+ if (cursor != null) {
+ cursor.close();
+ }
+
+ return null;
+ }
+
+ public void handleMessage (Message msg) {
+
+ switch (msg.what) {
+ case EVENT_RECORDS_LOADED:
+ onRecordsLoaded();
+ break;
+
+ case EVENT_ENABLE_NEW_APN:
+ onEnableNewApn();
+ break;
+
+ case EVENT_RESTORE_DEFAULT_APN:
+ onRestoreDefaultApn();
+ break;
+
+ case EVENT_GPRS_DETACHED:
+ onGprsDetached();
+ break;
+
+ case EVENT_GPRS_ATTACHED:
+ onGprsAttached();
+ break;
+
+ case EVENT_DATA_STATE_CHANGED:
+ onPdpStateChanged((AsyncResult) msg.obj, false);
+ break;
+
+ case EVENT_GET_PDP_LIST_COMPLETE:
+ onPdpStateChanged((AsyncResult) msg.obj, true);
+ break;
+
+ case EVENT_POLL_PDP:
+ onPollPdp();
+ break;
+
+ case EVENT_START_NETSTAT_POLL:
+ mPingTestActive = false;
+ startNetStatPoll();
+ break;
+
+ case EVENT_START_RECOVERY:
+ mPingTestActive = false;
+ doRecovery();
+ break;
+
+ case EVENT_APN_CHANGED:
+ onApnChanged();
+ break;
+
+ case EVENT_PS_RESTRICT_ENABLED:
+ /**
+ * We don't need to explicitly to tear down the PDP context
+ * when PS restricted is enabled. The base band will deactive
+ * PDP context and notify us with PDP_CONTEXT_CHANGED.
+ * But we should stop the network polling and prevent reset PDP.
+ */
+ Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
+ stopNetStatPoll();
+ mIsPsRestricted = true;
+ break;
+
+ case EVENT_PS_RESTRICT_DISABLED:
+ /**
+ * When PS restrict is removed, we need setup PDP connection if
+ * PDP connection is down.
+ */
+ Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
+ mIsPsRestricted = false;
+ if (state == State.CONNECTED) {
+ startNetStatPoll();
+ } else {
+ if (state == State.FAILED) {
+ cleanUpConnection(false, Phone.REASON_PS_RESTRICT_ENABLED);
+ nextReconnectDelay = RECONNECT_DELAY_INITIAL_MILLIS;
+ }
+ trySetupData(Phone.REASON_PS_RESTRICT_ENABLED);
+ }
+ break;
+
+ default:
+ // handle the message in the super class DataConnectionTracker
+ super.handleMessage(msg);
+ break;
+ }
+ }
+
+ protected void log(String s) {
+ Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s);
+ }
+
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 04f8332..4db8fc6 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -18,39 +18,40 @@ package com.android.internal.telephony.gsm;
import android.content.Context;
import com.android.internal.telephony.*;
+
import android.os.*;
-import android.os.AsyncResult;
+import android.telephony.PhoneNumberUtils;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
import android.util.Log;
+
+import static com.android.internal.telephony.CommandsInterface.*;
+
import java.util.regex.Pattern;
import java.util.regex.Matcher;
-import android.text.SpannableStringBuilder;
-import android.text.TextUtils;
-import android.telephony.PhoneNumberUtils;
-import static com.android.internal.telephony.gsm.CommandsInterface.*;
/**
* The motto for this file is:
*
- * "NOTE: By using the # as a separator, most cases are expected to be unambiguous."
+ * "NOTE: By using the # as a separator, most cases are expected to be unambiguous."
* -- TS 22.030 6.5.2
*
* {@hide}
*
*/
-public final class GsmMmiCode extends Handler implements MmiCode
-{
+public final class GsmMmiCode extends Handler implements MmiCode {
static final String LOG_TAG = "GSM";
//***** Constants
-
+
// From TS 22.030 6.5.2
static final String ACTION_ACTIVATE = "*";
static final String ACTION_DEACTIVATE = "#";
static final String ACTION_INTERROGATE = "*#";
static final String ACTION_REGISTER = "**";
static final String ACTION_ERASURE = "##";
-
- // Supp Service cocdes from TS 22.030 Annex B
+
+ // Supp Service cocdes from TS 22.030 Annex B
//Called line presentation
static final String SC_CLIP = "30";
@@ -102,25 +103,24 @@ public final class GsmMmiCode extends Handler implements MmiCode
GSMPhone phone;
Context context;
-
+
String action; // One of ACTION_*
String sc; // Service Code
String sia, sib, sic; // Service Info a,b,c
String poundString; // Entire MMI string up to and including #
String dialingNumber;
String pwd; // For password registration
-
- /** Set to true in processCode, not at newFromDialString time */
+ /** Set to true in processCode, not at newFromDialString time */
private boolean isPendingUSSD;
private boolean isUssdRequest;
- State state = State.PENDING;
+ State state = State.PENDING;
CharSequence message;
-
+
//***** Class Variables
-
+
// See TS 22.030 6.5.2 "Structure of the MMI"
@@ -137,9 +137,9 @@ public final class GsmMmiCode extends Handler implements MmiCode
10 = dialing number
*/
- static final int MATCH_GROUP_POUND_STRING = 1;
+ static final int MATCH_GROUP_POUND_STRING = 1;
- static final int MATCH_GROUP_ACTION = 2;
+ static final int MATCH_GROUP_ACTION = 2;
//(activation/interrogation/registration/erasure)
static final int MATCH_GROUP_SERVICE_CODE = 3;
@@ -151,7 +151,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
//***** Public Class methods
-
+
/**
* Some dial strings in GSM are defined to do non-call setup
* things, such as modify or query supplementry service settings (eg, call
@@ -165,9 +165,8 @@ public final class GsmMmiCode extends Handler implements MmiCode
* Please see flow chart in TS 22.030 6.5.3.2
*/
- static GsmMmiCode
- newFromDialString(String dialString, GSMPhone phone)
- {
+ static GsmMmiCode
+ newFromDialString(String dialString, GSMPhone phone) {
Matcher m;
GsmMmiCode ret = null;
@@ -187,7 +186,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
} else if (dialString.endsWith("#")) {
// TS 22.030 sec 6.5.3.2
- // "Entry of any characters defined in the 3GPP TS 23.038 [8] Default Alphabet
+ // "Entry of any characters defined in the 3GPP TS 23.038 [8] Default Alphabet
// (up to the maximum defined in 3GPP TS 24.080 [10]), followed by #SEND".
ret = new GsmMmiCode(phone);
@@ -202,16 +201,15 @@ public final class GsmMmiCode extends Handler implements MmiCode
}
static GsmMmiCode
- newNetworkInitiatedUssd (String ussdMessage,
- boolean isUssdRequest, GSMPhone phone)
- {
+ newNetworkInitiatedUssd (String ussdMessage,
+ boolean isUssdRequest, GSMPhone phone) {
GsmMmiCode ret;
ret = new GsmMmiCode(phone);
ret.message = ussdMessage;
ret.isUssdRequest = isUssdRequest;
-
+
// If it's a request, set to PENDING so that it's cancelable.
if (isUssdRequest) {
ret.isPendingUSSD = true;
@@ -225,42 +223,39 @@ public final class GsmMmiCode extends Handler implements MmiCode
static GsmMmiCode newFromUssdUserInput(String ussdMessge, GSMPhone phone) {
GsmMmiCode ret = new GsmMmiCode(phone);
-
+
ret.message = ussdMessge;
ret.state = State.PENDING;
ret.isPendingUSSD = true;
-
+
return ret;
}
//***** Private Class methods
- /** make empty strings be null.
- * Regexp returns empty strings for empty groups
+ /** make empty strings be null.
+ * Regexp returns empty strings for empty groups
*/
private static String
- makeEmptyNull (String s)
- {
+ 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)
- {
+ private static boolean
+ isEmptyOrNull(CharSequence s) {
return s == null || (s.length() == 0);
}
private static int
- scToCallForwardReason(String sc)
- {
- if (sc == null) {
+ scToCallForwardReason(String sc) {
+ if (sc == null) {
throw new RuntimeException ("invalid call forward sc");
}
-
+
if (sc.equals(SC_CF_All)) {
return CommandsInterface.CF_REASON_ALL;
} else if (sc.equals(SC_CFU)) {
@@ -279,8 +274,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
}
private static int
- siToServiceClass(String si)
- {
+ siToServiceClass(String si) {
if (si == null || si.length() == 0) {
return SERVICE_CLASS_NONE;
} else {
@@ -299,7 +293,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
/*
Note for code 20:
From TS 22.030 Annex C:
- "All GPRS bearer services" are not included in "All tele and bearer services"
+ "All GPRS bearer services" are not included in "All tele and bearer services"
and "All bearer services"."
....so SERVICE_CLASS_DATA, which (according to 27.007) includes GPRS
*/
@@ -319,8 +313,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
}
private static int
- siToTime (String si)
- {
+ siToTime (String si) {
if (si == null || si.length() == 0) {
return 0;
} else {
@@ -330,33 +323,30 @@ public final class GsmMmiCode extends Handler implements MmiCode
}
static boolean
- isServiceCodeCallForwarding(String sc)
- {
- return sc != null &&
- (sc.equals(SC_CFU)
- || sc.equals(SC_CFB) || sc.equals(SC_CFNRy)
- || sc.equals(SC_CFNR) || sc.equals(SC_CF_All)
+ isServiceCodeCallForwarding(String sc) {
+ return sc != null &&
+ (sc.equals(SC_CFU)
+ || sc.equals(SC_CFB) || sc.equals(SC_CFNRy)
+ || sc.equals(SC_CFNR) || sc.equals(SC_CF_All)
|| sc.equals(SC_CF_All_Conditional));
}
static boolean
- isServiceCodeCallBarring(String sc)
- {
+ isServiceCodeCallBarring(String sc) {
return sc != null &&
- (sc.equals(SC_BAOC)
+ (sc.equals(SC_BAOC)
|| sc.equals(SC_BAOIC)
|| sc.equals(SC_BAOICxH)
|| sc.equals(SC_BAIC)
|| sc.equals(SC_BAICr)
|| sc.equals(SC_BA_ALL)
|| sc.equals(SC_BA_MO)
- || sc.equals(SC_BA_MT));
+ || sc.equals(SC_BA_MT));
}
static String
- scToBarringFacility(String sc)
- {
- if (sc == null) {
+ scToBarringFacility(String sc) {
+ if (sc == null) {
throw new RuntimeException ("invalid call barring sc");
}
@@ -383,11 +373,10 @@ public final class GsmMmiCode extends Handler implements MmiCode
//***** Constructor
- GsmMmiCode (GSMPhone phone)
- {
+ GsmMmiCode (GSMPhone phone) {
// The telephony unit-test cases may create GsmMmiCode's
// in secondary threads
- super(phone.h.getLooper());
+ super(phone.getHandler().getLooper());
this.phone = phone;
this.context = phone.getContext();
}
@@ -395,21 +384,18 @@ public final class GsmMmiCode extends Handler implements MmiCode
//***** MmiCode implementation
public State
- getState()
- {
+ getState() {
return state;
}
public CharSequence
- getMessage()
- {
+ getMessage() {
return message;
}
// inherited javadoc suffices
public void
- cancel()
- {
+ cancel() {
// Complete or failed cannot be cancelled
if (state == State.COMPLETE || state == State.FAILED) {
return;
@@ -423,7 +409,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
* cancel it.
*/
phone.mCM.cancelPendingUssd(obtainMessage(EVENT_USSD_CANCEL_COMPLETE, this));
-
+
/*
* Don't call phone.onMMIDone here; wait for CANCEL_COMPLETE notice
* from RIL.
@@ -436,7 +422,6 @@ public final class GsmMmiCode extends Handler implements MmiCode
phone.onMMIDone (this);
}
-
}
public boolean isCancelable() {
@@ -445,20 +430,17 @@ public final class GsmMmiCode extends Handler implements MmiCode
}
//***** Instance Methods
-
/** Does this dial string contain a structured or unstructured MMI code? */
boolean
- isMMI()
- {
+ isMMI() {
return poundString != null;
}
/* Is this a 1 or 2 digit "short code" as defined in TS 22.030 sec 6.5.3.2? */
boolean
- isShortCode()
- {
- return poundString == null
+ isShortCode() {
+ return poundString == null
&& dialingNumber != null && dialingNumber.length() <= 2;
}
@@ -479,7 +461,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
* for treating "0" and "00" as call setup strings.
*/
|| dialString.equals("0")
- || dialString.equals("00"))));
+ || dialString.equals("00"))));
}
/**
* @return true if the Service Code is PIN/PIN2/PUK/PUK2-related
@@ -489,17 +471,16 @@ public final class GsmMmiCode extends Handler implements MmiCode
|| sc.equals(SC_PUK) || sc.equals(SC_PUK2));
}
- /**
+ /**
* *See TS 22.030 Annex B
- * In temporary mode, to suppress CLIR for a single call, enter:
+ * In temporary mode, to suppress CLIR for a single call, enter:
* " * 31 # SEND "
- * In temporary mode, to invoke CLIR for a single call enter:
+ * In temporary mode, to invoke CLIR for a single call enter:
* " # 31 # SEND "
*/
-
- boolean
- isTemporaryModeCLIR()
- {
+
+ boolean
+ isTemporaryModeCLIR() {
return sc != null && sc.equals(SC_CLIR) && dialingNumber != null
&& (isActivate() || isDeactivate());
}
@@ -509,50 +490,43 @@ public final class GsmMmiCode extends Handler implements MmiCode
* See also isTemporaryModeCLIR()
*/
int
- getCLIRMode()
- {
+ getCLIRMode() {
if (sc != null && sc.equals(SC_CLIR)) {
if (isActivate()) {
return CommandsInterface.CLIR_SUPPRESSION;
} else if (isDeactivate()) {
- return CommandsInterface.CLIR_INVOCATION;
+ return CommandsInterface.CLIR_INVOCATION;
}
}
-
+
return CommandsInterface.CLIR_DEFAULT;
}
-
- boolean isActivate()
- {
+
+ boolean isActivate() {
return action != null && action.equals(ACTION_ACTIVATE);
}
- boolean isDeactivate()
- {
+ boolean isDeactivate() {
return action != null && action.equals(ACTION_DEACTIVATE);
}
-
- boolean isInterrogate()
- {
+
+ boolean isInterrogate() {
return action != null && action.equals(ACTION_INTERROGATE);
}
- boolean isRegister()
- {
+ boolean isRegister() {
return action != null && action.equals(ACTION_REGISTER);
}
- boolean isErasure()
- {
+ boolean isErasure() {
return action != null && action.equals(ACTION_ERASURE);
}
- /**
+ /**
* Returns true if this is a USSD code that's been submitted to the
* network...eg, after processCode() is called
*/
- public boolean isPendingUSSD()
- {
+ public boolean isPendingUSSD() {
return isPendingUSSD;
}
@@ -562,8 +536,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
/** Process a MMI code or short code...anything that isn't a dialing number */
void
- processCode ()
- {
+ processCode () {
try {
if (isShortCode()) {
Log.d(LOG_TAG, "isShortCode");
@@ -573,7 +546,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
// We should have no dialing numbers here
throw new RuntimeException ("Invalid or Unsupported MMI Code");
} else if (sc != null && sc.equals(SC_CLIP)) {
- Log.d(LOG_TAG, "is CLIP");
+ Log.d(LOG_TAG, "is CLIP");
if (isInterrogate()) {
phone.mCM.queryCLIP(
obtainMessage(EVENT_QUERY_COMPLETE, this));
@@ -581,7 +554,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
throw new RuntimeException ("Invalid or Unsupported MMI Code");
}
} else if (sc != null && sc.equals(SC_CLIR)) {
- Log.d(LOG_TAG, "is CLIR");
+ Log.d(LOG_TAG, "is CLIR");
if (isActivate()) {
phone.mCM.setCLIR(CommandsInterface.CLIR_INVOCATION,
obtainMessage(EVENT_SET_COMPLETE, this));
@@ -688,13 +661,13 @@ public final class GsmMmiCode extends Handler implements MmiCode
// sia = basic service group
int serviceClass = siToServiceClass(sia);
- if (isActivate() || isDeactivate()) {
+ if (isActivate() || isDeactivate()) {
phone.mCM.setCallWaiting(isActivate(), serviceClass,
obtainMessage(EVENT_SET_COMPLETE, this));
- } else if (isInterrogate()) {
+ } else if (isInterrogate()) {
phone.mCM.queryCallWaiting(serviceClass,
obtainMessage(EVENT_QUERY_COMPLETE, this));
- } else {
+ } else {
throw new RuntimeException ("Invalid or Unsupported MMI Code");
}
} else if (isPinCommand()) {
@@ -718,16 +691,16 @@ public final class GsmMmiCode extends Handler implements MmiCode
} else {
// pre-checks OK
if (sc.equals(SC_PIN)) {
- phone.mCM.changeSimPin(oldPinOrPuk, newPin,
+ phone.mCM.changeIccPin(oldPinOrPuk, newPin,
obtainMessage(EVENT_SET_COMPLETE, this));
} else if (sc.equals(SC_PIN2)) {
- phone.mCM.changeSimPin2(oldPinOrPuk, newPin,
+ phone.mCM.changeIccPin2(oldPinOrPuk, newPin,
obtainMessage(EVENT_SET_COMPLETE, this));
} else if (sc.equals(SC_PUK)) {
- phone.mCM.supplySimPuk(oldPinOrPuk, newPin,
+ phone.mCM.supplyIccPuk(oldPinOrPuk, newPin,
obtainMessage(EVENT_SET_COMPLETE, this));
} else if (sc.equals(SC_PUK2)) {
- phone.mCM.supplySimPuk2(oldPinOrPuk, newPin,
+ phone.mCM.supplyIccPuk2(oldPinOrPuk, newPin,
obtainMessage(EVENT_SET_COMPLETE, this));
}
}
@@ -743,7 +716,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
state = State.FAILED;
message = context.getText(com.android.internal.R.string.mmiError);
phone.onMMIDone(this);
- }
+ }
}
private void handlePasswordError(int res) {
@@ -755,8 +728,8 @@ public final class GsmMmiCode extends Handler implements MmiCode
phone.onMMIDone(this);
}
- /**
- * Called from GSMPhone
+ /**
+ * Called from GSMPhone
*
* An unsolicited USSD NOTIFY or REQUEST has come in matching
* up with this pending USSD request
@@ -765,8 +738,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
* active (ie, the network expects user input).
*/
void
- onUssdFinished(String ussdMessage, boolean isUssdRequest)
- {
+ onUssdFinished(String ussdMessage, boolean isUssdRequest) {
if (state == State.PENDING) {
if (ussdMessage == null) {
message = context.getText(com.android.internal.R.string.mmiComplete);
@@ -783,15 +755,14 @@ public final class GsmMmiCode extends Handler implements MmiCode
}
}
- /**
- * Called from GSMPhone
+ /**
+ * Called from GSMPhone
*
* The radio has reset, and this is still pending
*/
void
- onUssdFinishedError()
- {
+ onUssdFinishedError() {
if (state == State.PENDING) {
state = State.FAILED;
message = context.getText(com.android.internal.R.string.mmiError);
@@ -808,15 +779,14 @@ public final class GsmMmiCode extends Handler implements MmiCode
// response does not complete this MMI code...we wait for
// an unsolicited USSD "Notify" or "Request".
// The matching up of this is doene in GSMPhone.
-
- phone.mCM.sendUSSD(ussdMessage,
+
+ phone.mCM.sendUSSD(ussdMessage,
obtainMessage(EVENT_USSD_COMPLETE, this));
}
/** Called from GSMPhone.handleMessage; not a Handler subclass */
public void
- handleMessage (Message msg)
- {
+ handleMessage (Message msg) {
AsyncResult ar;
switch (msg.what) {
@@ -865,13 +835,13 @@ public final class GsmMmiCode extends Handler implements MmiCode
com.android.internal.R.string.mmiError);
phone.onMMIDone(this);
- }
+ }
// Note that unlike most everything else, the USSD complete
// response does not complete this MMI code...we wait for
// an unsolicited USSD "Notify" or "Request".
// The matching up of this is done in GSMPhone.
-
+
break;
case EVENT_USSD_CANCEL_COMPLETE:
@@ -976,8 +946,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
}
private void
- onGetClirComplete(AsyncResult ar)
- {
+ onGetClirComplete(AsyncResult ar) {
StringBuilder sb = new StringBuilder(getScString());
sb.append("\n");
@@ -996,35 +965,35 @@ public final class GsmMmiCode extends Handler implements MmiCode
com.android.internal.R.string.serviceNotProvisioned));
state = State.COMPLETE;
break;
-
+
case 1: // CLIR provisioned in permanent mode
sb.append(context.getText(
com.android.internal.R.string.CLIRPermanent));
state = State.COMPLETE;
break;
- case 2: // unknown (e.g. no network, etc.)
+ case 2: // unknown (e.g. no network, etc.)
sb.append(context.getText(
com.android.internal.R.string.mmiError));
state = State.FAILED;
break;
- case 3: // CLIR temporary mode presentation restricted
+ case 3: // CLIR temporary mode presentation restricted
// the 'n' parameter from TS 27.007 7.7
switch (clirArgs[0]) {
default:
case 0: // Default
sb.append(context.getText(
- com.android.internal.R.string.CLIRDefaultOnNextCallOn));
+ com.android.internal.R.string.CLIRDefaultOnNextCallOn));
break;
case 1: // CLIR invocation
sb.append(context.getText(
- com.android.internal.R.string.CLIRDefaultOnNextCallOn));
+ com.android.internal.R.string.CLIRDefaultOnNextCallOn));
break;
case 2: // CLIR suppression
sb.append(context.getText(
- com.android.internal.R.string.CLIRDefaultOnNextCallOff));
+ com.android.internal.R.string.CLIRDefaultOnNextCallOff));
break;
}
state = State.COMPLETE;
@@ -1036,21 +1005,21 @@ public final class GsmMmiCode extends Handler implements MmiCode
default:
case 0: // Default
sb.append(context.getText(
- com.android.internal.R.string.CLIRDefaultOffNextCallOff));
+ com.android.internal.R.string.CLIRDefaultOffNextCallOff));
break;
case 1: // CLIR invocation
sb.append(context.getText(
- com.android.internal.R.string.CLIRDefaultOffNextCallOn));
+ com.android.internal.R.string.CLIRDefaultOffNextCallOn));
break;
case 2: // CLIR suppression
sb.append(context.getText(
- com.android.internal.R.string.CLIRDefaultOffNextCallOff));
+ com.android.internal.R.string.CLIRDefaultOffNextCallOff));
break;
}
state = State.COMPLETE;
break;
- }
+ }
}
message = sb;
@@ -1059,23 +1028,29 @@ public final class GsmMmiCode extends Handler implements MmiCode
/**
* @param serviceClass 1 bit of the service class bit vectory
- * @return String to be used for call forward query MMI response text.
+ * @return String to be used for call forward query MMI response text.
* Returns null if unrecognized
*/
private CharSequence
- serviceClassToCFString (int serviceClass)
- {
+ serviceClassToCFString (int serviceClass) {
switch (serviceClass) {
- case SERVICE_CLASS_VOICE: return context.getText(com.android.internal.R.string.serviceClassVoice);
- case SERVICE_CLASS_DATA: return context.getText(com.android.internal.R.string.serviceClassData);
- case SERVICE_CLASS_FAX: return context.getText(com.android.internal.R.string.serviceClassFAX);
- case SERVICE_CLASS_SMS: return context.getText(com.android.internal.R.string.serviceClassSMS);
- case SERVICE_CLASS_DATA_SYNC: return context.getText(com.android.internal.R.string.serviceClassDataSync);
- case SERVICE_CLASS_DATA_ASYNC: return context.getText(com.android.internal.R.string.serviceClassDataAsync);
- case SERVICE_CLASS_PACKET: return context.getText(com.android.internal.R.string.serviceClassPacket);
- case SERVICE_CLASS_PAD: return context.getText(com.android.internal.R.string.serviceClassPAD);
-
+ case SERVICE_CLASS_VOICE:
+ return context.getText(com.android.internal.R.string.serviceClassVoice);
+ case SERVICE_CLASS_DATA:
+ return context.getText(com.android.internal.R.string.serviceClassData);
+ case SERVICE_CLASS_FAX:
+ return context.getText(com.android.internal.R.string.serviceClassFAX);
+ case SERVICE_CLASS_SMS:
+ return context.getText(com.android.internal.R.string.serviceClassSMS);
+ case SERVICE_CLASS_DATA_SYNC:
+ return context.getText(com.android.internal.R.string.serviceClassDataSync);
+ case SERVICE_CLASS_DATA_ASYNC:
+ return context.getText(com.android.internal.R.string.serviceClassDataAsync);
+ case SERVICE_CLASS_PACKET:
+ return context.getText(com.android.internal.R.string.serviceClassPacket);
+ case SERVICE_CLASS_PAD:
+ return context.getText(com.android.internal.R.string.serviceClassPAD);
default:
return null;
}
@@ -1084,8 +1059,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
/** one CallForwardInfo + serviceClassMask -> one line of text */
private CharSequence
- makeCFQueryResultMessage(CallForwardInfo info, int serviceClassMask)
- {
+ makeCFQueryResultMessage(CallForwardInfo info, int serviceClassMask) {
CharSequence template;
String sources[] = {"{0}", "{1}", "{2}"};
CharSequence destinations[] = new CharSequence[3];
@@ -1094,7 +1068,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
// CF_REASON_NO_REPLY also has a time value associated with
// it. All others don't.
- needTimeTemplate =
+ needTimeTemplate =
(info.reason == CommandsInterface.CF_REASON_NO_REPLY);
if (info.status == 1) {
@@ -1122,8 +1096,8 @@ public final class GsmMmiCode extends Handler implements MmiCode
}
// In the template (from strings.xmls)
- // {0} is one of "bearerServiceCode*"
- // {1} is dialing number
+ // {0} is one of "bearerServiceCode*"
+ // {1} is dialing number
// {2} is time in seconds
destinations[0] = serviceClassToCFString(info.serviceClass & serviceClassMask);
@@ -1142,8 +1116,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
private void
- onQueryCfComplete(AsyncResult ar)
- {
+ onQueryCfComplete(AsyncResult ar) {
StringBuilder sb = new StringBuilder(getScString());
sb.append("\n");
@@ -1152,7 +1125,7 @@ public final class GsmMmiCode extends Handler implements MmiCode
sb.append(context.getText(com.android.internal.R.string.mmiError));
} else {
CallForwardInfo infos[];
-
+
infos = (CallForwardInfo[]) ar.result;
if (infos.length == 0) {
@@ -1166,18 +1139,18 @@ public final class GsmMmiCode extends Handler implements MmiCode
SpannableStringBuilder tb = new SpannableStringBuilder();
// Each bit in the service class gets its own result line
- // The service classes may be split up over multiple
+ // The service classes may be split up over multiple
// CallForwardInfos. So, for each service classs, find out
// which CallForwardInfo represents it and then build
// the response text based on that
- for (int serviceClassMask = 1
+ for (int serviceClassMask = 1
; serviceClassMask <= SERVICE_CLASS_MAX
- ; serviceClassMask <<= 1
+ ; serviceClassMask <<= 1
) {
for (int i = 0, s = infos.length; i < s ; i++) {
if ((serviceClassMask & infos[i].serviceClass) != 0) {
- tb.append(makeCFQueryResultMessage(infos[i],
+ tb.append(makeCFQueryResultMessage(infos[i],
serviceClassMask));
tb.append("\n");
}
@@ -1191,12 +1164,11 @@ public final class GsmMmiCode extends Handler implements MmiCode
message = sb;
phone.onMMIDone(this);
-
+
}
private void
- onQueryComplete(AsyncResult ar)
- {
+ onQueryComplete(AsyncResult ar) {
StringBuilder sb = new StringBuilder(getScString());
sb.append("\n");
@@ -1230,15 +1202,15 @@ public final class GsmMmiCode extends Handler implements MmiCode
message = sb;
phone.onMMIDone(this);
}
-
+
private CharSequence
- createQueryCallWaitingResultMessage(int serviceClass)
- {
- StringBuilder sb = new StringBuilder(context.getText(com.android.internal.R.string.serviceEnabledFor));
+ createQueryCallWaitingResultMessage(int serviceClass) {
+ StringBuilder sb =
+ new StringBuilder(context.getText(com.android.internal.R.string.serviceEnabledFor));
- for (int classMask = 1
+ for (int classMask = 1
; classMask <= SERVICE_CLASS_MAX
- ; classMask <<= 1
+ ; classMask <<= 1
) {
if ((classMask & serviceClass) != 0) {
sb.append("\n");
@@ -1267,8 +1239,8 @@ public final class GsmMmiCode extends Handler implements MmiCode
/***
* TODO: It would be nice to have a method here that can take in a dialstring and
* figure out if there is an MMI code embedded within it. This code would replace
- * some of the string parsing functionality in the Phone App's
- * SpecialCharSequenceMgr class.
+ * some of the string parsing functionality in the Phone App's
+ * SpecialCharSequenceMgr class.
*/
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
new file mode 100644
index 0000000..3e73caf
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
+import android.content.Intent;
+import android.os.AsyncResult;
+import android.os.Message;
+import android.telephony.ServiceState;
+import android.util.Config;
+import android.util.Log;
+
+import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.gsm.SmsMessage;
+import com.android.internal.telephony.SMSDispatcher;
+import com.android.internal.telephony.SmsHeader;
+import com.android.internal.telephony.SmsMessageBase;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+
+final class GsmSMSDispatcher extends SMSDispatcher {
+ private static final String TAG = "GSM";
+
+ GsmSMSDispatcher(GSMPhone phone) {
+ super(phone);
+ }
+
+ /**
+ * Called when a status report is received. This should correspond to
+ * a previously successful SEND.
+ *
+ * @param ar AsyncResult passed into the message handler. ar.result should
+ * be a String representing the status report PDU, as ASCII hex.
+ */
+ protected void handleStatusReport(AsyncResult ar) {
+ String pduString = (String) ar.result;
+ SmsMessage sms = SmsMessage.newFromCDS(pduString);
+
+ if (sms != null) {
+ int messageRef = sms.messageRef;
+ for (int i = 0, count = deliveryPendingList.size(); i < count; i++) {
+ SmsTracker tracker = deliveryPendingList.get(i);
+ if (tracker.mMessageRef == messageRef) {
+ // Found it. Remove from list and broadcast.
+ deliveryPendingList.remove(i);
+ PendingIntent intent = tracker.mDeliveryIntent;
+ Intent fillIn = new Intent();
+ fillIn.putExtra("pdu", IccUtils.hexStringToBytes(pduString));
+ try {
+ intent.send(mContext, Activity.RESULT_OK, fillIn);
+ } catch (CanceledException ex) {}
+
+ // Only expect to see one tracker matching this messageref
+ break;
+ }
+ }
+ }
+
+ if (mCm != null) {
+ mCm.acknowledgeLastIncomingSMS(true, null);
+ }
+ }
+
+
+ /**
+ * Dispatches an incoming SMS messages.
+ *
+ * @param sms the incoming message from the phone
+ */
+ protected void dispatchMessage(SmsMessageBase smsb) {
+
+ // If sms is null, means there was a parsing error.
+ // TODO: Should NAK this.
+ if (smsb == null) {
+ return;
+ }
+ SmsMessage sms = (SmsMessage) smsb;
+ boolean handled = false;
+
+ // Special case the message waiting indicator messages
+ if (sms.isMWISetMessage()) {
+ ((GSMPhone) mPhone).updateMessageWaitingIndicator(true);
+
+ if (sms.isMwiDontStore()) {
+ handled = true;
+ }
+
+ if (Config.LOGD) {
+ Log.d(TAG,
+ "Received voice mail indicator set SMS shouldStore="
+ + !handled);
+ }
+ } else if (sms.isMWIClearMessage()) {
+ ((GSMPhone) mPhone).updateMessageWaitingIndicator(false);
+
+ if (sms.isMwiDontStore()) {
+ handled = true;
+ }
+
+ if (Config.LOGD) {
+ Log.d(TAG,
+ "Received voice mail indicator clear SMS shouldStore="
+ + !handled);
+ }
+ }
+
+ if (handled) {
+ return;
+ }
+
+ // Parse the headers to see if this is partial, or port addressed
+ int referenceNumber = -1;
+ int count = 0;
+ int sequence = 0;
+ int destPort = -1;
+
+ SmsHeader header = sms.getUserDataHeader();
+ if (header != null) {
+ for (SmsHeader.Element element : header.getElements()) {
+ 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);
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void sendMultipartText(String destinationAddress, String scAddress,
+ ArrayList parts, ArrayList sentIntents,
+ ArrayList deliveryIntents) {
+ int ref = ++sConcatenatedRef & 0xff;
+
+ for (int i = 0, count = parts.size(); i < count; i++) {
+ // build SmsHeader
+ byte[] data = new byte[3];
+ data[0] = (byte) ref; // reference #, unique per message
+ data[1] = (byte) count; // total part count
+ data[2] = (byte) (i + 1); // 1-based sequence
+ SmsHeader header = new SmsHeader();
+ header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data));
+ PendingIntent sentIntent = null;
+ PendingIntent deliveryIntent = null;
+
+ if (sentIntents != null && sentIntents.size() > i) {
+ sentIntent = sentIntents.get(i);
+ }
+ if (deliveryIntents != null && deliveryIntents.size() > i) {
+ deliveryIntent = deliveryIntents.get(i);
+ }
+
+ SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
+ parts.get(i), deliveryIntent != null, header.toByteArray());
+
+ sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent);
+ }
+ }
+
+ /**
+ * 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 ArrayList
of strings that, in order,
+ * comprise the original message
+ * @param sentIntents if not null, an ArrayList
of
+ * PendingIntent
s (one for each message part) that is
+ * broadcast when the corresponding message part has been sent.
+ * The result code will be Activity.RESULT_OK for success,
+ * or one of these errors:
+ * RESULT_ERROR_GENERIC_FAILURE
+ * RESULT_ERROR_RADIO_OFF
+ * RESULT_ERROR_NULL_PDU
.
+ * @param deliveryIntents if not null, an ArrayList
of
+ * PendingIntent
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 parts,
+ ArrayList sentIntents,
+ ArrayList 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 = SmsTrackerFactory(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 map = new HashMap();
+ map.put("smsc", pdus.encodedScAddress);
+ map.put("pdu", pdus.encodedMessage);
+
+ SmsTracker tracker = SmsTrackerFactory(map, sentIntent, deliveryIntent);
+ sendSms(tracker);
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void sendSms(SmsTracker tracker) {
+ HashMap map = tracker.mData;
+
+ byte smsc[] = (byte[]) map.get("smsc");
+ byte pdu[] = (byte[]) map.get("pdu");
+
+ Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
+ mCm.sendSMS(IccUtils.bytesToHexString(smsc),
+ IccUtils.bytesToHexString(pdu), reply);
+ }
+
+ /**
+ * Send the multi-part SMS based on multipart Sms tracker
+ *
+ * @param tracker holds the multipart Sms tracker ready to be sent
+ */
+ protected void sendMultipartSms (SmsTracker tracker) {
+ ArrayList parts;
+ ArrayList sentIntents;
+ ArrayList deliveryIntents;
+
+ HashMap map = tracker.mData;
+
+ String destinationAddress = (String) map.get("destination");
+ String scAddress = (String) map.get("scaddress");
+
+ parts = (ArrayList) map.get("parts");
+ sentIntents = (ArrayList) map.get("sentIntents");
+ deliveryIntents = (ArrayList) map.get("deliveryIntents");
+
+ sendMultipartTextWithPermit(destinationAddress,
+ scAddress, parts, sentIntents, deliveryIntents);
+
+ }
+
+ /** {@inheritDoc} */
+ protected void acknowledgeLastIncomingSms(boolean success, Message response){
+ // FIXME unit test leaves cm == null. this should change
+ if (mCm != null) {
+ mCm.acknowledgeLastIncomingSMS(success, response);
+ }
+ }
+
+ /** {@inheritDoc} */
+ protected void activateCellBroadcastSms(int activate, Message response) {
+ // Unless CBS is implemented for GSM, this point should be unreachable.
+ Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
+ response.recycle();
+ }
+
+ /** {@inheritDoc} */
+ protected void getCellBroadcastSmsConfig(Message response){
+ // Unless CBS is implemented for GSM, this point should be unreachable.
+ Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
+ response.recycle();
+ }
+
+ /** {@inheritDoc} */
+ protected void setCellBroadcastConfig(int[] configValuesArray, Message response) {
+ // Unless CBS is implemented for GSM, this point should be unreachable.
+ Log.e(TAG, "Error! The functionality cell broadcast sms is not implemented for GSM.");
+ response.recycle();
+ }
+
+}
+
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
new file mode 100644
index 0000000..3c0b603
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -0,0 +1,1588 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import com.android.internal.telephony.Phone;
+import android.app.AlarmManager;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.provider.Checkin;
+import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
+import android.provider.Telephony.Intents;
+import android.telephony.ServiceState;
+import android.telephony.gsm.GsmCellLocation;
+import android.text.TextUtils;
+import android.util.Config;
+import android.util.EventLog;
+import android.util.Log;
+import android.util.TimeUtils;
+
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.DataConnectionTracker;
+import com.android.internal.telephony.IccCard;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneProxy;
+import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.ServiceStateTracker;
+import com.android.internal.telephony.TelephonyEventLog;
+import com.android.internal.telephony.TelephonyIntents;
+
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ALPHA;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC;
+
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+/**
+ * {@hide}
+ */
+final class GsmServiceStateTracker extends ServiceStateTracker {
+ //***** Instance Variables
+ GSMPhone phone;
+ GsmCellLocation cellLoc;
+ GsmCellLocation newCellLoc;
+ int mPreferredNetworkType;
+ RestrictedState rs;
+
+ int rssi = 99; // signal strength 0-31, 99=unknown
+ // That's "received signal strength indication" fyi
+
+ private int gprsState = ServiceState.STATE_OUT_OF_SERVICE;
+ private int newGPRSState = ServiceState.STATE_OUT_OF_SERVICE;
+
+ /**
+ * The access technology currently in use: DATA_ACCESS_
+ */
+ private int networkType = 0;
+ private int newNetworkType = 0;
+ /* gsm roaming status solely based on TS 27.007 7.2 CREG */
+ private boolean mGsmRoaming = false;
+
+ private RegistrantList gprsAttachedRegistrants = new RegistrantList();
+ private RegistrantList gprsDetachedRegistrants = new RegistrantList();
+ private RegistrantList psRestrictEnabledRegistrants = new RegistrantList();
+ private RegistrantList psRestrictDisabledRegistrants = new RegistrantList();
+
+ // Sometimes we get the NITZ time before we know what country we are in.
+ // Keep the time zone information from the NITZ string so we can fix
+ // the time zone once know the country.
+ private boolean mNeedFixZone = false;
+ private int mZoneOffset;
+ private boolean mZoneDst;
+ private long mZoneTime;
+ private boolean mGotCountryCode = false;
+ private ContentResolver cr;
+
+ String mSavedTimeZone;
+ long mSavedTime;
+ long mSavedAtTime;
+
+ // We can't register for SIM_RECORDS_LOADED immediately because the
+ // SIMRecords object may not be instantiated yet.
+ private boolean mNeedToRegForSimLoaded;
+
+ // Started the recheck process after finding gprs should registerd but not
+ private boolean mStartedGprsRegCheck = false;
+ // Already sent the event-log for no gprs register
+ private boolean mReportedGprsNoReg = false;
+
+ /**
+ * The Notification object given to the NotificationManager.
+ */
+ private Notification mNotification;
+
+ // Wake lock used while setting time of day.
+ private PowerManager.WakeLock mWakeLock;
+ private static final String WAKELOCK_TAG = "ServiceStateTracker";
+
+ // Keep track of SPN display rules, so we only broadcast intent if something changes.
+ private String curSpn = null;
+ private String curPlmn = null;
+ private int curSpnRule = 0;
+
+ //***** Constants
+
+ static final boolean DBG = true;
+ static final String LOG_TAG = "GSM";
+
+ // waiting period before recheck gprs and voice registration
+ static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
+
+ // notification type
+ static final int PS_ENABLED = 1001; // Access Control blocks data service
+ static final int PS_DISABLED = 1002; // Access Control enables data service
+ static final int CS_ENABLED = 1003; // Access Control blocks all voice/sms service
+ static final int CS_DISABLED = 1004; // Access Control enables all voice/sms service
+ static final int CS_NORMAL_ENABLED = 1005; // Access Control blocks normal voice/sms service
+ static final int CS_EMERGENCY_ENABLED = 1006; // Access Control blocks emergency call service
+
+ // notification id
+ static final int PS_NOTIFICATION = 888; //id to update and cancel PS restricted
+ static final int CS_NOTIFICATION = 999; //id to update and cancel CS restricted
+
+ private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ Log.i("GsmServiceStateTracker", "Auto time state changed");
+ revertToNitz();
+ }
+ };
+
+
+ //***** Constructors
+
+ public GsmServiceStateTracker(GSMPhone phone) {
+ super();
+
+ this.phone = phone;
+ cm = phone.mCM;
+ ss = new ServiceState();
+ newSS = new ServiceState();
+ cellLoc = new GsmCellLocation();
+ newCellLoc = new GsmCellLocation();
+ rs = new RestrictedState();
+
+ PowerManager powerManager =
+ (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
+ mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+
+ cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+ cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
+
+ cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
+ cm.setOnNITZTime(this, EVENT_NITZ_TIME, null);
+ cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
+ cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
+ cm.registerForSIMReady(this, EVENT_SIM_READY, null);
+
+ // system setting property AIRPLANE_MODE_ON is set in Settings.
+ int airplaneMode = Settings.System.getInt(
+ phone.getContext().getContentResolver(),
+ Settings.System.AIRPLANE_MODE_ON, 0);
+ mDesiredPowerState = ! (airplaneMode > 0);
+
+ cr = phone.getContext().getContentResolver();
+ cr.registerContentObserver(
+ Settings.System.getUriFor(Settings.System.AUTO_TIME), true,
+ mAutoTimeObserver);
+ setRssiDefaultValues();
+ mNeedToRegForSimLoaded = true;
+ }
+
+ public void dispose() {
+ //Unregister for all events
+ cm.unregisterForAvailable(this);
+ cm.unregisterForRadioStateChanged(this);
+ cm.unregisterForNetworkStateChanged(this);
+ cm.unregisterForSIMReady(this);
+
+ phone.mSIMRecords.unregisterForRecordsLoaded(this);
+ cm.unSetOnSignalStrengthUpdate(this);
+ cm.unSetOnRestrictedStateChanged(this);
+ cm.unSetOnNITZTime(this);
+ cr.unregisterContentObserver(this.mAutoTimeObserver);
+ }
+
+ protected void finalize() {
+ if(DBG) Log.d(LOG_TAG, "GsmServiceStateTracker finalized");
+ }
+
+ /**
+ * Registration point for transition into GPRS attached.
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ /*protected*/ void registerForGprsAttached(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ gprsAttachedRegistrants.add(r);
+
+ if (gprsState == ServiceState.STATE_IN_SERVICE) {
+ r.notifyRegistrant();
+ }
+ }
+
+ /*protected*/ void unregisterForGprsAttached(Handler h) {
+ gprsAttachedRegistrants.remove(h);
+ }
+
+ /*protected*/ void registerForNetworkAttach(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ networkAttachedRegistrants.add(r);
+
+ if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
+ r.notifyRegistrant();
+ }
+ }
+
+ /*protected*/ void unregisterForNetworkAttach(Handler h) {
+ networkAttachedRegistrants.remove(h);
+ }
+ /**
+ * Registration point for transition into GPRS detached.
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ /*protected*/ void registerForGprsDetached(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ gprsDetachedRegistrants.add(r);
+
+ if (gprsState == ServiceState.STATE_OUT_OF_SERVICE) {
+ r.notifyRegistrant();
+ }
+ }
+
+ /*protected*/ void unregisterForGprsDetached(Handler h) {
+ gprsDetachedRegistrants.remove(h);
+ }
+
+ /**
+ * Registration point for transition into packet service restricted zone.
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ /*protected*/ void registerForPsRestrictedEnabled(Handler h, int what, Object obj) {
+ Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedEnabled ");
+ Registrant r = new Registrant(h, what, obj);
+ psRestrictEnabledRegistrants.add(r);
+
+ if (rs.isPsRestricted()) {
+ r.notifyRegistrant();
+ }
+ }
+
+ /*protected*/ void unregisterForPsRestrictedEnabled(Handler h) {
+ psRestrictEnabledRegistrants.remove(h);
+ }
+
+ /**
+ * Registration point for transition out of packet service restricted zone.
+ * @param h handler to notify
+ * @param what what code of message when delivered
+ * @param obj placed in Message.obj
+ */
+ /*protected*/ void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
+ Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedDisabled ");
+ Registrant r = new Registrant(h, what, obj);
+ psRestrictDisabledRegistrants.add(r);
+
+ if (rs.isPsRestricted()) {
+ r.notifyRegistrant();
+ }
+ }
+
+ /*protected*/ void unregisterForPsRestrictedDisabled(Handler h) {
+ psRestrictDisabledRegistrants.remove(h);
+ }
+
+ //***** Called from GSMPhone
+ public void
+ getLacAndCid(Message onComplete) {
+ cm.getRegistrationState(obtainMessage(
+ EVENT_GET_LOC_DONE, onComplete));
+ }
+
+
+ //***** Overridden from ServiceStateTracker
+ public void
+ handleMessage (Message msg) {
+ AsyncResult ar;
+ int[] ints;
+ String[] strings;
+ Message message;
+
+ switch (msg.what) {
+ case EVENT_RADIO_AVAILABLE:
+ //this is unnecessary
+ //setPowerStateToDesired();
+ break;
+
+ case EVENT_SIM_READY:
+ // The SIM is now ready i.e if it was locked
+ // it has been unlocked. At this stage, the radio is already
+ // powered on.
+ if (mNeedToRegForSimLoaded) {
+ phone.mSIMRecords.registerForRecordsLoaded(this,
+ EVENT_SIM_RECORDS_LOADED, null);
+ mNeedToRegForSimLoaded = false;
+ }
+ // restore the previous network selection.
+ phone.restoreSavedNetworkSelection(null);
+ pollState();
+ // Signal strength polling stops when radio is off
+ queueNextSignalStrengthPoll();
+ break;
+
+ case EVENT_RADIO_STATE_CHANGED:
+ // This will do nothing in the radio not
+ // available case
+ setPowerStateToDesired();
+ pollState();
+ break;
+
+ case EVENT_NETWORK_STATE_CHANGED:
+ pollState();
+ break;
+
+ case EVENT_GET_SIGNAL_STRENGTH:
+ // This callback is called when signal strength is polled
+ // all by itself
+
+ if (!(cm.getRadioState().isOn()) || (cm.getRadioState().isCdma())) {
+ // Polling will continue when radio turns back on and not CDMA
+ return;
+ }
+ ar = (AsyncResult) msg.obj;
+ onSignalStrengthResult(ar);
+ queueNextSignalStrengthPoll();
+
+ break;
+
+ case EVENT_GET_LOC_DONE:
+ ar = (AsyncResult) msg.obj;
+
+ if (ar.exception == null) {
+ String states[] = (String[])ar.result;
+ int lac = -1;
+ int cid = -1;
+ if (states.length == 3) {
+ try {
+ if (states[1] != null && states[1].length() > 0) {
+ lac = Integer.parseInt(states[1], 16);
+ }
+ if (states[2] != null && states[2].length() > 0) {
+ cid = Integer.parseInt(states[2], 16);
+ }
+ } catch (NumberFormatException ex) {
+ Log.w(LOG_TAG, "error parsing location: " + ex);
+ }
+ }
+
+ // only update if lac or cid changed
+ if (cellLoc.getCid() != cid || cellLoc.getLac() != lac) {
+ cellLoc.setLacAndCid(lac, cid);
+ phone.notifyLocationChanged();
+ }
+ }
+
+ if (ar.userObj != null) {
+ AsyncResult.forMessage(((Message) ar.userObj)).exception
+ = ar.exception;
+ ((Message) ar.userObj).sendToTarget();
+ }
+ break;
+
+ case EVENT_POLL_STATE_REGISTRATION:
+ case EVENT_POLL_STATE_GPRS:
+ case EVENT_POLL_STATE_OPERATOR:
+ case EVENT_POLL_STATE_NETWORK_SELECTION_MODE:
+ ar = (AsyncResult) msg.obj;
+
+ handlePollStateResult(msg.what, ar);
+ break;
+
+ case EVENT_POLL_SIGNAL_STRENGTH:
+ // Just poll signal strength...not part of pollState()
+
+ cm.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
+ break;
+
+ case EVENT_NITZ_TIME:
+ ar = (AsyncResult) msg.obj;
+
+ String nitzString = (String)((Object[])ar.result)[0];
+ long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
+
+ setTimeFromNITZString(nitzString, nitzReceiveTime);
+ break;
+
+ case EVENT_SIGNAL_STRENGTH_UPDATE:
+ // This is a notification from
+ // CommandsInterface.setOnSignalStrengthUpdate
+
+ ar = (AsyncResult) msg.obj;
+
+ // The radio is telling us about signal strength changes
+ // we don't have to ask it
+ dontPollSignalStrength = true;
+
+ onSignalStrengthResult(ar);
+ break;
+
+ case EVENT_SIM_RECORDS_LOADED:
+ updateSpnDisplay();
+ break;
+
+ case EVENT_LOCATION_UPDATES_ENABLED:
+ ar = (AsyncResult) msg.obj;
+
+ if (ar.exception == null) {
+ getLacAndCid(null);
+ }
+ break;
+
+ case EVENT_SET_PREFERRED_NETWORK_TYPE:
+ ar = (AsyncResult) msg.obj;
+ // Don't care the result, only use for dereg network (COPS=2)
+ message = obtainMessage(EVENT_RESET_PREFERRED_NETWORK_TYPE, ar.userObj);
+ cm.setPreferredNetworkType(mPreferredNetworkType, message);
+ break;
+
+ case EVENT_RESET_PREFERRED_NETWORK_TYPE:
+ ar = (AsyncResult) msg.obj;
+ if (ar.userObj != null) {
+ AsyncResult.forMessage(((Message) ar.userObj)).exception
+ = ar.exception;
+ ((Message) ar.userObj).sendToTarget();
+ }
+ break;
+
+ case EVENT_GET_PREFERRED_NETWORK_TYPE:
+ ar = (AsyncResult) msg.obj;
+
+ if (ar.exception == null) {
+ mPreferredNetworkType = ((int[])ar.result)[0];
+ } else {
+ mPreferredNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
+ }
+
+ message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj);
+ int toggledNetworkType = RILConstants.NETWORK_MODE_GLOBAL;
+
+ cm.setPreferredNetworkType(toggledNetworkType, message);
+ break;
+
+ case EVENT_CHECK_REPORT_GPRS:
+ if (ss != null && !isGprsConsistant(gprsState, ss.getState())) {
+
+ // Can't register data sevice while voice service is ok
+ // i.e. CREG is ok while CGREG is not
+ // possible a network or baseband side error
+ int cid = -1;
+ GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
+ if (loc != null) cid = loc.getCid();
+
+ EventLog.List val = new EventLog.List(ss.getOperatorNumeric(), cid);
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CGREG_FAIL, val);
+ mReportedGprsNoReg = true;
+ }
+ mStartedGprsRegCheck = false;
+ break;
+
+ case EVENT_RESTRICTED_STATE_CHANGED:
+ // This is a notification from
+ // CommandsInterface.setOnRestrictedStateChanged
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_RESTRICTED_STATE_CHANGED");
+
+ ar = (AsyncResult) msg.obj;
+
+ onRestrictedStateChanged(ar);
+ break;
+
+ default:
+ Log.e(LOG_TAG, "Unhandled message with number: " + msg.what);
+ break;
+ }
+ }
+
+ //***** Private Instance Methods
+
+ protected void setPowerStateToDesired()
+ {
+ // If we want it on and it's off, turn it on
+ if (mDesiredPowerState
+ && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF) {
+ cm.setRadioPower(true, null);
+ } else if (!mDesiredPowerState && cm.getRadioState().isOn()) {
+ DataConnectionTracker dcTracker = phone.mDataConnection;
+ if (! dcTracker.isDataConnectionAsDesired()) {
+
+ EventLog.List val = new EventLog.List(
+ dcTracker.getStateInString(),
+ (dcTracker.getAnyDataEnabled() ? 1 : 0) );
+ EventLog.writeEvent(TelephonyEventLog.EVENT_DATA_STATE_RADIO_OFF, val);
+ }
+ dcTracker.cleanConnectionBeforeRadioOff();
+
+ // poll data state up to 15 times, with a 100ms delay
+ // totaling 1.5 sec. Normal data disable action will finish in 100ms.
+ for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) {
+ if (dcTracker.getState() != DataConnectionTracker.State.CONNECTED
+ && dcTracker.getState() != DataConnectionTracker.State.DISCONNECTING) {
+ Log.d(LOG_TAG, "Data shutdown complete.");
+ break;
+ }
+ SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS);
+ }
+ // If it's on and available and we want it off..
+ cm.setRadioPower(false, null);
+ } // Otherwise, we're in the desired state
+ }
+
+ protected void updateSpnDisplay() {
+ int rule = phone.mSIMRecords.getDisplayRule(ss.getOperatorNumeric());
+ String spn = phone.mSIMRecords.getServiceProviderName();
+ String plmn = ss.getOperatorAlphaLong();
+
+ if (rule != curSpnRule
+ || !TextUtils.equals(spn, curSpn)
+ || !TextUtils.equals(plmn, curPlmn)) {
+ boolean showSpn =
+ (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN;
+ boolean showPlmn =
+ (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN;
+ Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION);
+ intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn);
+ intent.putExtra(Intents.EXTRA_SPN, spn);
+ intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn);
+ intent.putExtra(Intents.EXTRA_PLMN, plmn);
+ phone.getContext().sendStickyBroadcast(intent);
+ }
+ curSpnRule = rule;
+ curSpn = spn;
+ curPlmn = plmn;
+ }
+
+ /**
+ * Handle the result of one of the pollState()-related requests
+ */
+
+ protected void
+ handlePollStateResult (int what, AsyncResult ar) {
+ int ints[];
+ String states[];
+
+ // Ignore stale requests from last poll
+ if (ar.userObj != pollingContext) return;
+
+ if (ar.exception != null) {
+ CommandException.Error err=null;
+
+ if (ar.exception instanceof CommandException) {
+ err = ((CommandException)(ar.exception)).getCommandError();
+ }
+
+ if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
+ // Radio has crashed or turned off
+ cancelPollState();
+ return;
+ }
+
+ if (!cm.getRadioState().isOn()) {
+ // Radio has crashed or turned off
+ cancelPollState();
+ return;
+ }
+
+ if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW &&
+ err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
+ Log.e(LOG_TAG,
+ "RIL implementation has returned an error where it must succeed" +
+ ar.exception);
+ }
+ } else try {
+ switch (what) {
+ case EVENT_POLL_STATE_REGISTRATION:
+ states = (String[])ar.result;
+ int lac = -1;
+ int cid = -1;
+ int regState = -1;
+ if (states.length > 0) {
+ try {
+ regState = Integer.parseInt(states[0]);
+ if (states.length == 3) {
+ if (states[1] != null && states[1].length() > 0) {
+ lac = Integer.parseInt(states[1], 16);
+ }
+ if (states[2] != null && states[2].length() > 0) {
+ cid = Integer.parseInt(states[2], 16);
+ }
+ }
+ } catch (NumberFormatException ex) {
+ Log.w(LOG_TAG, "error parsing RegistrationState: " + ex);
+ }
+ }
+
+ mGsmRoaming = regCodeIsRoaming(regState);
+ newSS.setState (regCodeToServiceState(regState));
+
+ // LAC and CID are -1 if not avail
+ newCellLoc.setLacAndCid(lac, cid);
+ break;
+
+ case EVENT_POLL_STATE_GPRS:
+ states = (String[])ar.result;
+
+ int type = 0;
+ regState = -1;
+ if (states.length > 0) {
+ try {
+ regState = Integer.parseInt(states[0]);
+
+ // states[3] (if present) is the current radio technology
+ if (states.length >= 4 && states[3] != null) {
+ type = Integer.parseInt(states[3]);
+ }
+ } catch (NumberFormatException ex) {
+ Log.w(LOG_TAG, "error parsing GprsRegistrationState: " + ex);
+ }
+ }
+ newGPRSState = regCodeToServiceState(regState);
+ newNetworkType = type;
+ break;
+
+ case EVENT_POLL_STATE_OPERATOR:
+ String opNames[] = (String[])ar.result;
+
+ if (opNames != null && opNames.length >= 3) {
+ newSS.setOperatorName (
+ opNames[0], opNames[1], opNames[2]);
+ }
+ break;
+
+ case EVENT_POLL_STATE_NETWORK_SELECTION_MODE:
+ ints = (int[])ar.result;
+ newSS.setIsManualSelection(ints[0] == 1);
+ break;
+ }
+
+ } catch (RuntimeException ex) {
+ Log.e(LOG_TAG, "Exception while polling service state. "
+ + "Probably malformed RIL response.", ex);
+ }
+
+ pollingContext[0]--;
+
+ if (pollingContext[0] == 0) {
+ newSS.setRoaming(isRoamingBetweenOperators(mGsmRoaming, newSS));
+ pollStateDone();
+ }
+
+ }
+
+ private void
+ setRssiDefaultValues() {
+ rssi = 99;
+ }
+
+ /**
+ * A complete "service state" from our perspective is
+ * composed of a handful of separate requests to the radio.
+ *
+ * We make all of these requests at once, but then abandon them
+ * and start over again if the radio notifies us that some
+ * event has changed
+ */
+
+ private void
+ pollState() {
+ pollingContext = new int[1];
+ pollingContext[0] = 0;
+
+ switch (cm.getRadioState()) {
+ case RADIO_UNAVAILABLE:
+ newSS.setStateOutOfService();
+ newCellLoc.setStateInvalid();
+ setRssiDefaultValues();
+ mGotCountryCode = false;
+
+ pollStateDone();
+ break;
+
+ case RADIO_OFF:
+ newSS.setStateOff();
+ newCellLoc.setStateInvalid();
+ setRssiDefaultValues();
+ mGotCountryCode = false;
+
+ pollStateDone();
+ break;
+
+ case RUIM_NOT_READY:
+ case RUIM_READY:
+ case RUIM_LOCKED_OR_ABSENT:
+ case NV_NOT_READY:
+ case NV_READY:
+ Log.d(LOG_TAG, "Radio Technology Change ongoing, setting SS to off");
+ newSS.setStateOff();
+ newCellLoc.setStateInvalid();
+ setRssiDefaultValues();
+ mGotCountryCode = false;
+
+ pollStateDone();
+ break;
+
+ default:
+ // Issue all poll-related commands at once
+ // then count down the responses, which
+ // are allowed to arrive out-of-order
+
+ pollingContext[0]++;
+ cm.getOperator(
+ obtainMessage(
+ EVENT_POLL_STATE_OPERATOR, pollingContext));
+
+ pollingContext[0]++;
+ cm.getGPRSRegistrationState(
+ obtainMessage(
+ EVENT_POLL_STATE_GPRS, pollingContext));
+
+ pollingContext[0]++;
+ cm.getRegistrationState(
+ obtainMessage(
+ EVENT_POLL_STATE_REGISTRATION, pollingContext));
+
+ pollingContext[0]++;
+ cm.getNetworkSelectionMode(
+ obtainMessage(
+ EVENT_POLL_STATE_NETWORK_SELECTION_MODE, pollingContext));
+ break;
+ }
+ }
+
+ private static String networkTypeToString(int type) {
+ //Network Type from GPRS_REGISTRATION_STATE
+ String ret = "unknown";
+
+ switch (type) {
+ case DATA_ACCESS_GPRS:
+ ret = "GPRS";
+ break;
+ case DATA_ACCESS_EDGE:
+ ret = "EDGE";
+ break;
+ case DATA_ACCESS_UMTS:
+ ret = "UMTS";
+ break;
+ default:
+ Log.e(LOG_TAG, "Wrong network type: " + Integer.toString(type));
+ break;
+ }
+
+ return ret;
+ }
+
+ private void
+ pollStateDone() {
+ if (DBG) {
+ Log.d(LOG_TAG, "Poll ServiceState done: " +
+ " oldSS=[" + ss + "] newSS=[" + newSS +
+ "] oldGprs=" + gprsState + " newGprs=" + newGPRSState +
+ " oldType=" + networkTypeToString(networkType) +
+ " newType=" + networkTypeToString(newNetworkType));
+ }
+
+ boolean hasRegistered =
+ ss.getState() != ServiceState.STATE_IN_SERVICE
+ && newSS.getState() == ServiceState.STATE_IN_SERVICE;
+
+ boolean hasDeregistered =
+ ss.getState() == ServiceState.STATE_IN_SERVICE
+ && newSS.getState() != ServiceState.STATE_IN_SERVICE;
+
+ boolean hasGprsAttached =
+ gprsState != ServiceState.STATE_IN_SERVICE
+ && newGPRSState == ServiceState.STATE_IN_SERVICE;
+
+ boolean hasGprsDetached =
+ gprsState == ServiceState.STATE_IN_SERVICE
+ && newGPRSState != ServiceState.STATE_IN_SERVICE;
+
+ boolean hasNetworkTypeChanged = networkType != newNetworkType;
+
+ boolean hasChanged = !newSS.equals(ss);
+
+ boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming();
+
+ boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming();
+
+ boolean hasLocationChanged = !newCellLoc.equals(cellLoc);
+
+ ServiceState tss;
+ tss = ss;
+ ss = newSS;
+ newSS = tss;
+ // clean slate for next time
+ newSS.setStateOutOfService();
+
+ GsmCellLocation tcl = cellLoc;
+ cellLoc = newCellLoc;
+ newCellLoc = tcl;
+
+ gprsState = newGPRSState;
+ networkType = newNetworkType;
+
+ newSS.setStateOutOfService(); // clean slate for next time
+
+ if (hasNetworkTypeChanged) {
+ phone.setSystemProperty(PROPERTY_DATA_NETWORK_TYPE,
+ networkTypeToString(networkType));
+ }
+
+ if (hasRegistered) {
+ Checkin.updateStats(phone.getContext().getContentResolver(),
+ Checkin.Stats.Tag.PHONE_GSM_REGISTERED, 1, 0.0);
+ networkAttachedRegistrants.notifyRegistrants();
+ }
+
+ if (hasChanged) {
+ String operatorNumeric;
+
+ phone.setSystemProperty(PROPERTY_OPERATOR_ALPHA,
+ ss.getOperatorAlphaLong());
+
+ operatorNumeric = ss.getOperatorNumeric();
+ phone.setSystemProperty(PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
+
+ if (operatorNumeric == null) {
+ phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, "");
+ } else {
+ String iso = "";
+ try{
+ iso = MccTable.countryCodeForMcc(Integer.parseInt(
+ operatorNumeric.substring(0,3)));
+ } catch ( NumberFormatException ex){
+ Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
+ } catch ( StringIndexOutOfBoundsException ex) {
+ Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
+ }
+
+ phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, iso);
+ mGotCountryCode = true;
+
+ if (mNeedFixZone) {
+ TimeZone zone = null;
+ // If the offset is (0, false) and the timezone property
+ // is set, use the timezone property rather than
+ // GMT.
+ String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
+ if ((mZoneOffset == 0) && (mZoneDst == false) &&
+ (zoneName != null) && (zoneName.length() > 0) &&
+ (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) {
+ zone = TimeZone.getDefault();
+ // For NITZ string without timezone,
+ // need adjust time to reflect default timezone setting
+ long tzOffset;
+ tzOffset = zone.getOffset(System.currentTimeMillis());
+ if (getAutoTime()) {
+ setAndBroadcastNetworkSetTime(System.currentTimeMillis() - tzOffset);
+ } else {
+ // Adjust the saved NITZ time to account for tzOffset.
+ mSavedTime = mSavedTime - tzOffset;
+ }
+ } else if (iso.equals("")){
+ // Country code not found. This is likely a test network.
+ // Get a TimeZone based only on the NITZ parameters (best guess).
+ zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
+ } else {
+ zone = TimeUtils.getTimeZone(mZoneOffset,
+ mZoneDst, mZoneTime, iso);
+ }
+
+ mNeedFixZone = false;
+
+ if (zone != null) {
+ if (getAutoTime()) {
+ setAndBroadcastNetworkSetTimeZone(zone.getID());
+ }
+ saveNitzTimeZone(zone.getID());
+ }
+ }
+ }
+
+ phone.setSystemProperty(PROPERTY_OPERATOR_ISROAMING,
+ ss.getRoaming() ? "true" : "false");
+
+ updateSpnDisplay();
+ phone.notifyServiceStateChanged(ss);
+ }
+
+ if (hasGprsAttached) {
+ gprsAttachedRegistrants.notifyRegistrants();
+ }
+
+ if (hasGprsDetached) {
+ gprsDetachedRegistrants.notifyRegistrants();
+ }
+
+ if (hasNetworkTypeChanged) {
+ phone.notifyDataConnection(null);
+ }
+
+ if (hasRoamingOn) {
+ roamingOnRegistrants.notifyRegistrants();
+ }
+
+ if (hasRoamingOff) {
+ roamingOffRegistrants.notifyRegistrants();
+ }
+
+ if (hasLocationChanged) {
+ phone.notifyLocationChanged();
+ }
+
+ if (! isGprsConsistant(gprsState, ss.getState())) {
+ if (!mStartedGprsRegCheck && !mReportedGprsNoReg) {
+ mStartedGprsRegCheck = true;
+
+ int check_period = Settings.Gservices.getInt(
+ phone.getContext().getContentResolver(),
+ Settings.Gservices.GPRS_REGISTER_CHECK_PERIOD_MS,
+ DEFAULT_GPRS_CHECK_PERIOD_MILLIS);
+ sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS),
+ check_period);
+ }
+ } else {
+ mReportedGprsNoReg = false;
+ }
+ }
+
+ /**
+ * Check if GPRS got registred while voice is registered
+ *
+ * @param gprsState for GPRS registration state, i.e. CGREG in GSM
+ * @param serviceState for voice registration state, i.e. CREG in GSM
+ * @return false if device only register to voice but not gprs
+ */
+ private boolean isGprsConsistant (int gprsState, int serviceState) {
+ return !((serviceState == ServiceState.STATE_IN_SERVICE) &&
+ (gprsState != ServiceState.STATE_IN_SERVICE));
+ }
+
+ /**
+ * Returns a TimeZone object based only on parameters from the NITZ string.
+ */
+ private TimeZone getNitzTimeZone(int offset, boolean dst, long when) {
+ TimeZone guess = findTimeZone(offset, dst, when);
+ if (guess == null) {
+ // Couldn't find a proper timezone. Perhaps the DST data is wrong.
+ guess = findTimeZone(offset, !dst, when);
+ }
+ if (DBG) {
+ Log.d(LOG_TAG, "getNitzTimeZone returning "
+ + (guess == null ? guess : guess.getID()));
+ }
+ return guess;
+ }
+
+ private TimeZone findTimeZone(int offset, boolean dst, long when) {
+ int rawOffset = offset;
+ if (dst) {
+ rawOffset -= 3600000;
+ }
+ String[] zones = TimeZone.getAvailableIDs(rawOffset);
+ TimeZone guess = null;
+ Date d = new Date(when);
+ for (String zone : zones) {
+ TimeZone tz = TimeZone.getTimeZone(zone);
+ if (tz.getOffset(when) == offset &&
+ tz.inDaylightTime(d) == dst) {
+ guess = tz;
+ break;
+ }
+ }
+
+ return guess;
+ }
+
+ private void
+ queueNextSignalStrengthPoll() {
+ if (dontPollSignalStrength || (cm.getRadioState().isCdma())) {
+ // The radio is telling us about signal strength changes
+ // we don't have to ask it
+ return;
+ }
+
+ Message msg;
+
+ msg = obtainMessage();
+ msg.what = EVENT_POLL_SIGNAL_STRENGTH;
+
+ long nextTime;
+
+ // TODO Done't poll signal strength if screen is off
+ sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
+ }
+
+ /**
+ * send signal-strength-changed notification if rssi changed
+ * Called both for solicited and unsolicited signal stength updates
+ */
+ private void
+ onSignalStrengthResult(AsyncResult ar) {
+ int oldRSSI = rssi;
+
+ if (ar.exception != null) {
+ // 99 = unknown
+ // most likely radio is resetting/disconnected
+ rssi = 99;
+ } else {
+ int[] ints = (int[])ar.result;
+
+ // bug 658816 seems to be a case where the result is 0-length
+ if (ints.length != 0) {
+ rssi = ints[0];
+ } else {
+ Log.e(LOG_TAG, "Bogus signal strength response");
+ rssi = 99;
+ }
+ }
+
+ if (rssi != oldRSSI) {
+ try { // This takes care of delayed EVENT_POLL_SIGNAL_STRENGTH (scheduled after
+ // POLL_PERIOD_MILLIS) during Radio Technology Change)
+ phone.notifySignalStrength();
+ } catch (NullPointerException ex) {
+ Log.d(LOG_TAG, "onSignalStrengthResult() Phone already destroyed: " + ex
+ + "Signal Stranth not notified");
+ }
+ }
+ }
+
+ /**
+ * Set restricted state based on the OnRestrictedStateChanged notification
+ * If any voice or packet restricted state changes, trigger a UI
+ * notification and notify registrants when sim is ready.
+ *
+ * @param ar an int value of RIL_RESTRICTED_STATE_*
+ */
+ private void onRestrictedStateChanged(AsyncResult ar)
+ {
+ Log.d(LOG_TAG, "[DSAC DEB] " + "onRestrictedStateChanged");
+ RestrictedState newRs = new RestrictedState();
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at enter "+ rs);
+
+ if (ar.exception == null) {
+ int[] ints = (int[])ar.result;
+ int state = ints[0];
+
+ newRs.setCsEmergencyRestricted(
+ ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) ||
+ ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
+ //ignore the normal call and data restricted state before SIM READY
+ if (phone.getIccCard().getState() == IccCard.State.READY) {
+ newRs.setCsNormalRestricted(
+ ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) ||
+ ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
+ newRs.setPsRestricted(
+ (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0);
+ }
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "new rs "+ newRs);
+
+ if (!rs.isPsRestricted() && newRs.isPsRestricted()) {
+ psRestrictEnabledRegistrants.notifyRegistrants();
+ setNotification(PS_ENABLED);
+ } else if (rs.isPsRestricted() && !newRs.isPsRestricted()) {
+ psRestrictDisabledRegistrants.notifyRegistrants();
+ setNotification(PS_DISABLED);
+ }
+
+ /**
+ * There are two kind of cs restriction, normal and emergency. So
+ * there are 4 x 4 combinations in current and new restricted states
+ * and we only need to notify when state is changed.
+ */
+ if (rs.isCsRestricted()) {
+ if (!newRs.isCsRestricted()) {
+ // remove all restriction
+ setNotification(CS_DISABLED);
+ } else if (!newRs.isCsNormalRestricted()) {
+ // remove normal restriction
+ setNotification(CS_EMERGENCY_ENABLED);
+ } else if (!newRs.isCsEmergencyRestricted()) {
+ // remove emergency restriction
+ setNotification(CS_NORMAL_ENABLED);
+ }
+ } else if (rs.isCsEmergencyRestricted() && !rs.isCsNormalRestricted()) {
+ if (!newRs.isCsRestricted()) {
+ // remove all restriction
+ setNotification(CS_DISABLED);
+ } else if (newRs.isCsRestricted()) {
+ // enable all restriction
+ setNotification(CS_ENABLED);
+ } else if (newRs.isCsNormalRestricted()) {
+ // remove emergency restriction and enable normal restriction
+ setNotification(CS_NORMAL_ENABLED);
+ }
+ } else if (!rs.isCsEmergencyRestricted() && rs.isCsNormalRestricted()) {
+ if (!newRs.isCsRestricted()) {
+ // remove all restriction
+ setNotification(CS_DISABLED);
+ } else if (newRs.isCsRestricted()) {
+ // enable all restriction
+ setNotification(CS_ENABLED);
+ } else if (newRs.isCsEmergencyRestricted()) {
+ // remove normal restriction and enable emergency restriction
+ setNotification(CS_EMERGENCY_ENABLED);
+ }
+ } else {
+ if (newRs.isCsRestricted()) {
+ // enable all restriction
+ setNotification(CS_ENABLED);
+ } else if (newRs.isCsEmergencyRestricted()) {
+ // enable emergency restriction
+ setNotification(CS_EMERGENCY_ENABLED);
+ } else if (newRs.isCsNormalRestricted()) {
+ // enable normal restriction
+ setNotification(CS_NORMAL_ENABLED);
+ }
+ }
+
+ rs = newRs;
+ }
+ Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at return "+ rs);
+ }
+
+ /** code is registration state 0-5 from TS 27.007 7.2 */
+ private int
+ regCodeToServiceState(int code) {
+ switch (code) {
+ case 0:
+ case 2: // 2 is "searching"
+ case 3: // 3 is "registration denied"
+ case 4: // 4 is "unknown" no vaild in current baseband
+ return ServiceState.STATE_OUT_OF_SERVICE;
+
+ case 1:
+ return ServiceState.STATE_IN_SERVICE;
+
+ case 5:
+ // in service, roam
+ return ServiceState.STATE_IN_SERVICE;
+
+ default:
+ Log.w(LOG_TAG, "unexpected service state " + code);
+ return ServiceState.STATE_OUT_OF_SERVICE;
+ }
+ }
+
+
+ /**
+ * code is registration state 0-5 from TS 27.007 7.2
+ * returns true if registered roam, false otherwise
+ */
+ private boolean
+ regCodeIsRoaming (int code) {
+ // 5 is "in service -- roam"
+ return 5 == code;
+ }
+
+ /**
+ * Set roaming state when gsmRoaming is true and, if operator mcc is the
+ * same as sim mcc, ons is different from spn
+ * @param gsmRoaming TS 27.007 7.2 CREG registered roaming
+ * @param s ServiceState hold current ons
+ * @return true for roaming state set
+ */
+ private
+ boolean isRoamingBetweenOperators(boolean gsmRoaming, ServiceState s) {
+ String spn = SystemProperties.get(PROPERTY_ICC_OPERATOR_ALPHA, "empty");
+
+ String onsl = s.getOperatorAlphaLong();
+ String onss = s.getOperatorAlphaShort();
+
+ boolean equalsOnsl = onsl != null && spn.equals(onsl);
+ boolean equalsOnss = onss != null && spn.equals(onss);
+
+ String simNumeric = SystemProperties.get(PROPERTY_ICC_OPERATOR_NUMERIC, "");
+ String operatorNumeric = s.getOperatorNumeric();
+
+ boolean equalsMcc = true;
+ try {
+ equalsMcc = simNumeric.substring(0, 3).
+ equals(operatorNumeric.substring(0, 3));
+ } catch (Exception e){
+ }
+
+ return gsmRoaming && !(equalsMcc && (equalsOnsl || equalsOnss));
+ }
+
+ private static
+ int twoDigitsAt(String s, int offset) {
+ int a, b;
+
+ a = Character.digit(s.charAt(offset), 10);
+ b = Character.digit(s.charAt(offset+1), 10);
+
+ if (a < 0 || b < 0) {
+
+ throw new RuntimeException("invalid format");
+ }
+
+ return a*10 + b;
+ }
+
+ /**
+ * @return The current GPRS state. IN_SERVICE is the same as "attached"
+ * and OUT_OF_SERVICE is the same as detached.
+ */
+ /*package*/ int getCurrentGprsState() {
+ return gprsState;
+ }
+
+ /**
+ * @return true if phone is camping on a technology (eg UMTS)
+ * that could support voice and data simultaniously.
+ */
+ boolean isConcurrentVoiceAndData() {
+ return (networkType == DATA_ACCESS_UMTS);
+ }
+
+ /**
+ * Provides the name of the algorithmic time zone for the specified
+ * offset. Taken from TimeZone.java.
+ */
+ private static String displayNameFor(int off) {
+ off = off / 1000 / 60;
+
+ char[] buf = new char[9];
+ buf[0] = 'G';
+ buf[1] = 'M';
+ buf[2] = 'T';
+
+ if (off < 0) {
+ buf[3] = '-';
+ off = -off;
+ } else {
+ buf[3] = '+';
+ }
+
+ int hours = off / 60;
+ int minutes = off % 60;
+
+ buf[4] = (char) ('0' + hours / 10);
+ buf[5] = (char) ('0' + hours % 10);
+
+ buf[6] = ':';
+
+ buf[7] = (char) ('0' + minutes / 10);
+ buf[8] = (char) ('0' + minutes % 10);
+
+ return new String(buf);
+ }
+
+ /**
+ * nitzReceiveTime is time_t that the NITZ time was posted
+ */
+
+ private
+ void setTimeFromNITZString (String nitz, long nitzReceiveTime)
+ {
+ // "yy/mm/dd,hh:mm:ss(+/-)tz"
+ // tz is in number of quarter-hours
+
+ long start = SystemClock.elapsedRealtime();
+ Log.i(LOG_TAG, "NITZ: " + nitz + "," + nitzReceiveTime +
+ " start=" + start + " delay=" + (start - nitzReceiveTime));
+
+ try {
+ /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
+ * offset as well (which we won't worry about until later) */
+ Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+
+ c.clear();
+ c.set(Calendar.DST_OFFSET, 0);
+
+ String[] nitzSubs = nitz.split("[/:,+-]");
+
+ int year = 2000 + Integer.parseInt(nitzSubs[0]);
+ c.set(Calendar.YEAR, year);
+
+ // month is 0 based!
+ int month = Integer.parseInt(nitzSubs[1]) - 1;
+ c.set(Calendar.MONTH, month);
+
+ int date = Integer.parseInt(nitzSubs[2]);
+ c.set(Calendar.DATE, date);
+
+ int hour = Integer.parseInt(nitzSubs[3]);
+ c.set(Calendar.HOUR, hour);
+
+ int minute = Integer.parseInt(nitzSubs[4]);
+ c.set(Calendar.MINUTE, minute);
+
+ int second = Integer.parseInt(nitzSubs[5]);
+ c.set(Calendar.SECOND, second);
+
+ boolean sign = (nitz.indexOf('-') == -1);
+
+ int tzOffset = Integer.parseInt(nitzSubs[6]);
+
+ int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
+ : 0;
+
+ // The zone offset received from NITZ is for current local time,
+ // so DST correction is already applied. Don't add it again.
+ //
+ // tzOffset += dst * 4;
+ //
+ // We could unapply it if we wanted the raw offset.
+
+ tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
+
+ TimeZone zone = null;
+
+ // As a special extension, the Android emulator appends the name of
+ // the host computer's timezone to the nitz string. this is zoneinfo
+ // timezone name of the form Area!Location or Area!Location!SubLocation
+ // so we need to convert the ! into /
+ if (nitzSubs.length >= 9) {
+ String tzname = nitzSubs[8].replace('!','/');
+ zone = TimeZone.getTimeZone( tzname );
+ }
+
+ String iso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY);
+
+ if (zone == null) {
+
+ if (mGotCountryCode) {
+ if (iso != null && iso.length() > 0) {
+ zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
+ c.getTimeInMillis(),
+ iso);
+ } else {
+ // We don't have a valid iso country code. This is
+ // most likely because we're on a test network that's
+ // using a bogus MCC (eg, "001"), so get a TimeZone
+ // based only on the NITZ parameters.
+ zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
+ }
+ }
+ }
+
+ if (zone == null) {
+ // We got the time before the country, so we don't know
+ // how to identify the DST rules yet. Save the information
+ // and hope to fix it up later.
+
+ mNeedFixZone = true;
+ mZoneOffset = tzOffset;
+ mZoneDst = dst != 0;
+ mZoneTime = c.getTimeInMillis();
+ }
+
+ if (zone != null) {
+ if (getAutoTime()) {
+ setAndBroadcastNetworkSetTimeZone(zone.getID());
+ }
+ saveNitzTimeZone(zone.getID());
+ }
+
+ String ignore = SystemProperties.get("gsm.ignore-nitz");
+ if (ignore != null && ignore.equals("yes")) {
+ Log.i(LOG_TAG, "NITZ: Not setting clock because gsm.ignore-nitz is set");
+ return;
+ }
+
+ try {
+ mWakeLock.acquire();
+
+ if (getAutoTime()) {
+ long millisSinceNitzReceived
+ = SystemClock.elapsedRealtime() - nitzReceiveTime;
+
+ if (millisSinceNitzReceived < 0) {
+ // Sanity check: something is wrong
+ Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
+ + "backwards since NITZ time was received, "
+ + nitz);
+ return;
+ }
+
+ if (millisSinceNitzReceived > Integer.MAX_VALUE) {
+ // If the time is this far off, something is wrong > 24 days!
+ Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
+ + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
+ + " days");
+ return;
+ }
+
+ // Note: with range checks above, cast to int is safe
+ c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
+
+ Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime()
+ + " NITZ receive delay(ms): " + millisSinceNitzReceived
+ + " gained(ms): "
+ + (c.getTimeInMillis() - System.currentTimeMillis())
+ + " from " + nitz);
+
+ setAndBroadcastNetworkSetTime(c.getTimeInMillis());
+ Log.i(LOG_TAG, "NITZ: after Setting time of day");
+ }
+ SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
+ saveNitzTime(c.getTimeInMillis());
+ if (Config.LOGV) {
+ long end = SystemClock.elapsedRealtime();
+ Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
+ }
+ } finally {
+ mWakeLock.release();
+ }
+ } catch (RuntimeException ex) {
+ Log.e(LOG_TAG, "NITZ: Parsing NITZ time " + nitz, ex);
+ }
+ }
+
+ private boolean getAutoTime() {
+ try {
+ return Settings.System.getInt(phone.getContext().getContentResolver(),
+ Settings.System.AUTO_TIME) > 0;
+ } catch (SettingNotFoundException snfe) {
+ return true;
+ }
+ }
+
+ private void saveNitzTimeZone(String zoneId) {
+ mSavedTimeZone = zoneId;
+ }
+
+ private void saveNitzTime(long time) {
+ mSavedTime = time;
+ mSavedAtTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
+ * Set the timezone and send out a sticky broadcast so the system can
+ * determine if the timezone was set by the carrier.
+ *
+ * @param zoneId timezone set by carrier
+ */
+ private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
+ AlarmManager alarm =
+ (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
+ alarm.setTimeZone(zoneId);
+ Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
+ intent.putExtra("time-zone", zoneId);
+ phone.getContext().sendStickyBroadcast(intent);
+ }
+
+ /**
+ * Set the time and Send out a sticky broadcast so the system can determine
+ * if the time was set by the carrier.
+ *
+ * @param time time set by network
+ */
+ private void setAndBroadcastNetworkSetTime(long time) {
+ SystemClock.setCurrentTimeMillis(time);
+ Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
+ intent.putExtra("time", time);
+ phone.getContext().sendStickyBroadcast(intent);
+ }
+
+ private void revertToNitz() {
+ if (Settings.System.getInt(phone.getContext().getContentResolver(),
+ Settings.System.AUTO_TIME, 0) == 0) {
+ return;
+ }
+ Log.d(LOG_TAG, "Reverting to NITZ: tz='" + mSavedTimeZone
+ + "' mSavedTime=" + mSavedTime
+ + " mSavedAtTime=" + mSavedAtTime);
+ if (mSavedTimeZone != null && mSavedTime != 0 && mSavedAtTime != 0) {
+ setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
+ setAndBroadcastNetworkSetTime(mSavedTime
+ + (SystemClock.elapsedRealtime() - mSavedAtTime));
+ }
+ }
+
+ /**
+ * Post a notification to NotificationManager for restricted state
+ *
+ * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE
+ */
+ private void setNotification(int notifyType) {
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "create notification " + notifyType);
+ Context context = phone.getContext();
+
+ mNotification = new Notification();
+ mNotification.when = System.currentTimeMillis();
+ mNotification.flags = Notification.FLAG_AUTO_CANCEL;
+ mNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
+ Intent intent = new Intent();
+ mNotification.contentIntent = PendingIntent
+ .getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ CharSequence details = "";
+ CharSequence title = context.getText(com.android.internal.R.string.RestrictedChangedTitle);
+ int notificationId = CS_NOTIFICATION;
+
+ switch (notifyType) {
+ case PS_ENABLED:
+ notificationId = PS_NOTIFICATION;
+ details = context.getText(com.android.internal.R.string.RestrictedOnData);;
+ break;
+ case PS_DISABLED:
+ notificationId = PS_NOTIFICATION;
+ break;
+ case CS_ENABLED:
+ details = context.getText(com.android.internal.R.string.RestrictedOnAll);;
+ break;
+ case CS_NORMAL_ENABLED:
+ details = context.getText(com.android.internal.R.string.RestrictedOnNormal);;
+ break;
+ case CS_EMERGENCY_ENABLED:
+ details = context.getText(com.android.internal.R.string.RestrictedOnEmergency);;
+ break;
+ case CS_DISABLED:
+ // do nothing and cancel the notification later
+ break;
+ }
+
+ Log.d(LOG_TAG, "[DSAC DEB] " + "put notification " + title + " / " +details);
+ mNotification.tickerText = title;
+ mNotification.setLatestEventInfo(context, title, details,
+ mNotification.contentIntent);
+
+ NotificationManager notificationManager = (NotificationManager)
+ context.getSystemService(Context.NOTIFICATION_SERVICE);
+
+ if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) {
+ // cancel previous post notification
+ notificationManager.cancel(notificationId);
+ } else {
+ // update restricted state notification
+ notificationManager.notify(notificationId, mNotification);
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java b/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java
deleted file mode 100644
index a4cded9..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSimCard.java
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.os.AsyncResult;
-import android.os.RemoteException;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Registrant;
-import android.os.RegistrantList;
-import android.util.Log;
-import com.android.internal.telephony.SimCard;
-import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.TelephonyIntents;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.app.ActivityManagerNative;
-
-import static android.Manifest.permission.READ_PHONE_STATE;
-
-/**
- * {@hide}
- */
-public final class GsmSimCard extends Handler implements SimCard {
- static final String LOG_TAG="GSM";
-
- //***** Instance Variables
- private static final boolean DBG = true;
-
- private GSMPhone phone;
- private CommandsInterface.SimStatus status = null;
- private boolean mSimPinLocked = true; // Default to locked
- private boolean mSimFdnEnabled = false; // Default to disabled.
- // Will be updated when SIM_READY.
- private boolean mDesiredPinLocked;
- private boolean mDesiredFdnEnabled;
-
- //***** Constants
-
- // FIXME I hope this doesn't conflict with the Dialer's notifications
- static final int NOTIFICATION_ID_SIM_STATUS = 33456;
-
- //***** Event Constants
-
- static final int EVENT_SIM_LOCKED_OR_ABSENT = 1;
- static final int EVENT_GET_SIM_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_SIM_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_SIM_PASSWORD_DONE = 9;
- static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
- static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
-
-
- //***** Constructor
-
- GsmSimCard(GSMPhone phone)
- {
- this.phone = phone;
-
- phone.mCM.registerForSIMLockedOrAbsent(
- this, EVENT_SIM_LOCKED_OR_ABSENT, null);
-
- phone.mCM.registerForOffOrNotAvailable(
- this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
-
- phone.mCM.registerForSIMReady(
- this, EVENT_SIM_READY, null);
-
- updateStateProperty();
- }
-
- //***** SimCard 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 SIM_NOT_READY:
- return State.UNKNOWN;
- case SIM_LOCKED_OR_ABSENT:
- //this should be transient-only
- return State.UNKNOWN;
- case SIM_READY:
- return State.READY;
- }
- } else {
- switch (status) {
- case SIM_ABSENT: return State.ABSENT;
- case SIM_NOT_READY: return State.UNKNOWN;
- case SIM_READY: return State.READY;
- case SIM_PIN: return State.PIN_REQUIRED;
- case SIM_PUK: return State.PUK_REQUIRED;
- case SIM_NETWORK_PERSONALIZATION: return State.NETWORK_LOCKED;
- }
- }
-
- Log.e(LOG_TAG, "GsmSimCard.getState(): case should never be reached");
- return State.UNKNOWN;
- }
-
- 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.supplySimPin(pin,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
-
- public void supplyPuk (String puk, String newPin, Message onComplete)
- {
- phone.mCM.supplySimPuk(puk, newPin,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
- public void supplyPin2 (String pin2, Message onComplete)
- {
- phone.mCM.supplySimPin2(pin2,
- obtainMessage(EVENT_PINPUK_DONE, onComplete));
- }
- public void supplyPuk2 (String puk2, String newPin2, Message onComplete)
- {
- phone.mCM.supplySimPuk2(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 getSimLockEnabled() {
- return mSimPinLocked;
- }
-
- public boolean getSimFdnEnabled() {
- return mSimFdnEnabled;
- }
-
- public void setSimLockEnabled (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 setSimFdnEnabled (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 changeSimLockPassword(String oldPassword, String newPassword,
- Message onComplete) {
- if(DBG) log("Change Pin1 old: " + oldPassword + " new: " + newPassword);
- phone.mCM.changeSimPin(oldPassword, newPassword,
- obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete));
-
- }
-
- public void changeSimFdnPassword(String oldPassword, String newPassword,
- Message onComplete) {
- if(DBG) log("Change Pin2 old: " + oldPassword + " new: " + newPassword);
- phone.mCM.changeSimPin2(oldPassword, newPassword,
- obtainMessage(EVENT_CHANGE_SIM_PASSWORD_DONE, onComplete));
-
- }
-
- public String getServiceProviderName () {
- return phone.mSIMRecords.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:
- status = null;
- updateStateProperty();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_NOT_READY, null);
- break;
- case EVENT_SIM_READY:
- //TODO: put facility read in SIM_READY now, maybe in REG_NW
- phone.mCM.getSimStatus(obtainMessage(EVENT_GET_SIM_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_SIM_LOCKED_OR_ABSENT:
- phone.mCM.getSimStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE));
- phone.mCM.queryFacilityLock (
- CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
- obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
- break;
- case EVENT_GET_SIM_STATUS_DONE:
- ar = (AsyncResult)msg.obj;
-
- getSimStatusDone(ar);
- break;
- case EVENT_PINPUK_DONE:
- // 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.getSimStatus(
- obtainMessage(EVENT_REPOLL_STATUS_DONE, ar.userObj));
- break;
- case EVENT_REPOLL_STATUS_DONE:
- // 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;
- getSimStatusDone(ar);
- ((Message)ar.userObj).sendToTarget();
- break;
- case EVENT_QUERY_FACILITY_LOCK_DONE:
- ar = (AsyncResult)msg.obj;
- onQueryFacilityLock(ar);
- break;
- case EVENT_QUERY_FACILITY_FDN_DONE:
- ar = (AsyncResult)msg.obj;
- onQueryFdnEnabled(ar);
- break;
- case EVENT_CHANGE_FACILITY_LOCK_DONE:
- ar = (AsyncResult)msg.obj;
- if (ar.exception == null) {
- mSimPinLocked = mDesiredPinLocked;
- if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
- "mSimPinLocked= " + mSimPinLocked);
- } 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:
- ar = (AsyncResult)msg.obj;
-
- if (ar.exception == null) {
- mSimFdnEnabled = mDesiredFdnEnabled;
- if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
- "mSimFdnEnabled=" + mSimFdnEnabled);
- } 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_SIM_PASSWORD_DONE:
- 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, "[GsmSimCard] Unknown Event " + msg.what);
- }
- }
-
-
- //***** Private methods
-
- /**
- * Interperate 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) {
- mSimPinLocked = (0!=ints[0]);
- if(DBG) log("Query facility lock : " + mSimPinLocked);
- } else {
- Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response");
- }
- }
-
- /**
- * Interperate 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) {
- mSimFdnEnabled = (0!=ints[0]);
- if(DBG) log("Query facility lock : " + mSimFdnEnabled);
- } else {
- Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response");
- }
- }
-
- private void
- getSimStatusDone(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.SimStatus newStatus
- = (CommandsInterface.SimStatus) ar.result;
-
- handleSimStatus(newStatus);
- }
-
- private void
- handleSimStatus(CommandsInterface.SimStatus newStatus) {
- boolean transitionedIntoPinLocked;
- boolean transitionedIntoAbsent;
- boolean transitionedIntoNetworkLocked;
-
- SimCard.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 SIM pin or puk locked.");
- pinLockedRegistrants.notifyRegistrants();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_LOCKED,
- (newState == State.PIN_REQUIRED) ?
- INTENT_VALUE_LOCKED_ON_PIN : INTENT_VALUE_LOCKED_ON_PUK);
- } else if (transitionedIntoAbsent) {
- if(DBG) log("Notify SIM missing.");
- absentRegistrants.notifyRegistrants();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_ABSENT, null);
- } else if (transitionedIntoNetworkLocked) {
- if(DBG) log("Notify SIM network locked.");
- networkLockedRegistrants.notifyRegistrants();
- broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_SIM_LOCKED,
- INTENT_VALUE_LOCKED_NETWORK);
- }
- }
-
- public void broadcastSimStateChangedIntent(String value, String reason) {
- Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName());
- intent.putExtra(SimCard.INTENT_KEY_SIM_STATE, value);
- intent.putExtra(SimCard.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, "[GsmSimCard] " + msg);
- }
-}
-
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java
new file mode 100644
index 0000000..c163803
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSmsAddress.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.telephony.PhoneNumberUtils;
+
+import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.SmsAddress;
+
+public class GsmSmsAddress extends SmsAddress {
+
+ static final int OFFSET_ADDRESS_LENGTH = 0;
+
+ static final int OFFSET_TOA = 1;
+
+ static final int OFFSET_ADDRESS_VALUE = 2;
+
+ /**
+ * New GsmSmsAddress from TS 23.040 9.1.2.5 Address Field
+ *
+ * @param offset the offset of the Address-Length byte
+ * @param length the length in bytes rounded up, e.g. "2 +
+ * (addressLength + 1) / 2"
+ */
+
+ public GsmSmsAddress(byte[] data, int offset, int length) {
+ origBytes = new byte[length];
+ System.arraycopy(data, offset, origBytes, 0, length);
+
+ // addressLength is the count of semi-octets, not bytes
+ int addressLength = origBytes[OFFSET_ADDRESS_LENGTH] & 0xff;
+
+ int toa = origBytes[OFFSET_TOA] & 0xff;
+ ton = 0x7 & (toa >> 4);
+
+ // TOA must have its high bit set
+ if ((toa & 0x80) != 0x80) {
+ throw new RuntimeException("Invalid TOA - high bit must be set");
+ }
+
+ if (isAlphanumeric()) {
+ // An alphanumeric address
+ int countSeptets = addressLength * 4 / 7;
+
+ address = GsmAlphabet.gsm7BitPackedToString(origBytes,
+ OFFSET_ADDRESS_VALUE, countSeptets);
+ } else {
+ // TS 23.040 9.1.2.5 says
+ // that "the MS shall interpret reserved values as 'Unknown'
+ // but shall store them exactly as received"
+
+ byte lastByte = origBytes[length - 1];
+
+ if ((addressLength & 1) == 1) {
+ // Make sure the final unused BCD digit is 0xf
+ origBytes[length - 1] |= 0xf0;
+ }
+ address = PhoneNumberUtils.calledPartyBCDToString(origBytes,
+ OFFSET_TOA, length - OFFSET_TOA);
+
+ // And restore origBytes
+ origBytes[length - 1] = lastByte;
+ }
+ }
+
+ public String getAddressString() {
+ return address;
+ }
+
+ /**
+ * Returns true if this is an alphanumeric address
+ */
+ public boolean isAlphanumeric() {
+ return ton == TON_ALPHANUMERIC;
+ }
+
+ public boolean isNetworkSpecific() {
+ return ton == TON_NETWORK;
+ }
+
+ /**
+ * Returns true of this is a valid CPHS voice message waiting indicator
+ * address
+ */
+ public boolean isCphsVoiceMessageIndicatorAddress() {
+ // CPHS-style MWI message
+ // See CPHS 4.7 B.4.2.1
+ //
+ // Basically:
+ //
+ // - Originating address should be 4 bytes long and alphanumeric
+ // - Decode will result with two chars:
+ // - Char 1
+ // 76543210
+ // ^ set/clear indicator (0 = clear)
+ // ^^^ type of indicator (000 = voice)
+ // ^^^^ must be equal to 0001
+ // - Char 2:
+ // 76543210
+ // ^ line number (0 = line 1)
+ // ^^^^^^^ set to 0
+ //
+ // Remember, since the alpha address is stored in 7-bit compact form,
+ // the "line number" is really the top bit of the first address value
+ // byte
+
+ return (origBytes[OFFSET_ADDRESS_LENGTH] & 0xff) == 4
+ && isAlphanumeric() && (origBytes[OFFSET_TOA] & 0x0f) == 0;
+ }
+
+ /**
+ * Returns true if this is a valid CPHS voice message waiting indicator
+ * address indicating a "set" of "indicator 1" of type "voice message
+ * waiting"
+ */
+ public boolean isCphsVoiceMessageSet() {
+ // 0x11 means "set" "voice message waiting" "indicator 1"
+ return isCphsVoiceMessageIndicatorAddress()
+ && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x11;
+
+ }
+
+ /**
+ * Returns true if this is a valid CPHS voice message waiting indicator
+ * address indicating a "clear" of "indicator 1" of type "voice message
+ * waiting"
+ */
+ public boolean isCphsVoiceMessageClear() {
+ // 0x10 means "clear" "voice message waiting" "indicator 1"
+ return isCphsVoiceMessageIndicatorAddress()
+ && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x10;
+
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/ISimPhoneBook.aidl b/telephony/java/com/android/internal/telephony/gsm/ISimPhoneBook.aidl
deleted file mode 100644
index 77033a7..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/ISimPhoneBook.aidl
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
-** 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.gsm;
-
-import com.android.internal.telephony.gsm.AdnRecord;
-
-import java.util.List;
-
-/** Interface for applications to access the SIM phone book.
- *
- * The following code snippet demonstrates a static method to
- * retrieve the ISimPhoneBook interface from Android:
- * private static ISimPhoneBook getSimPhoneBookInterface()
- throws DeadObjectException {
- IServiceManager sm = ServiceManagerNative.getDefault();
- ISimPhoneBook spb;
- spb = ISimPhoneBook.Stub.asInterface(sm.getService("simphonebook"));
- return spb;
-}
- *
- */
-
-interface ISimPhoneBook {
-
- /**
- * Loads the AdnRecords in efid and returns them as a
- * List of AdnRecords
- *
- * @param efid the EF id of a ADN-like SIM
- * @return List of AdnRecord
- */
- List getAdnRecordsInEf(int efid);
-
- /**
- * 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
- *
- * @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
- */
- boolean updateAdnRecordsInEfBySearch(int efid,
- String oldTag, String oldPhoneNumber,
- String newTag, String newPhoneNumber,
- String pin2);
-
- /**
- * 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
- *
- * @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
- */
- boolean updateAdnRecordsInEfByIndex(int efid, String newTag,
- String newPhoneNumber, int index,
- String pin2);
-
- /**
- * Get the max munber of records in efid
- *
- * @param efid the EF id of a ADN-like SIM
- * @return int[3] array
- * recordSizes[0] is the single record length
- * recordSizes[1] is the total length of the EF file
- * recordSizes[2] is the number of records in the EF file
- */
- int[] getAdnRecordsSize(int efid);
-
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/ISms.aidl b/telephony/java/com/android/internal/telephony/gsm/ISms.aidl
deleted file mode 100644
index 904a54e..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/ISms.aidl
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
-** 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.gsm;
-
-import android.app.PendingIntent;
-import com.android.internal.telephony.gsm.SmsRawData;
-
-/** Interface for applications to access the SIM phone book.
- *
- * The following code snippet demonstrates a static method to
- * retrieve the ISimSms interface from Android:
- * private static ISimSms getSimSmsInterface()
- throws DeadObjectException {
- IServiceManager sm = ServiceManagerNative.getDefault();
- ISimSms ss;
- ss = ISimSms.Stub.asInterface(sm.getService("isms"));
- return ss;
-}
- *
- */
-
-interface ISms {
- /**
- * Retrieves all messages currently stored on SIM.
- *
- * @return list of SmsRawData of all sms on SIM
- */
- List getAllMessagesFromSimEf();
-
- /**
- * Update the specified message on the SIM.
- *
- * @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 pdu the raw PDU to store
- * @return success or not
- *
- */
- boolean updateMessageOnSimEf(int messageIndex, int newStatus,
- in byte[] pdu);
-
- /**
- * Copy a raw SMS PDU to the SIM.
- *
- * @param pdu the raw PDU to store
- * @param status message status (STATUS_ON_SIM_READ, STATUS_ON_SIM_UNREAD,
- * STATUS_ON_SIM_SENT, STATUS_ON_SIM_UNSENT)
- * @return success or not
- *
- */
- boolean copyMessageToSimEf(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
- * @param pdu the raw PDU to send
- * @param sentIntent if not NULL this Intent
is
- * broadcast when the message is sucessfully sent, or failed.
- * The result code will be Activity.RESULT_OK for success,
- * or one of these errors:
- * RESULT_ERROR_GENERIC_FAILURE
- * RESULT_ERROR_RADIO_OFF
- * RESULT_ERROR_NULL_PDU
.
- * @param deliveryIntent if not NULL this Intent
is
- * broadcast when the message is delivered to the recipient. The
- * raw pdu of the status report is in the extended data ("pdu").
- */
- void sendRawPdu(in byte[] smsc, in byte[] pdu, in PendingIntent sentIntent,
- in PendingIntent 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 ArrayList
of strings that, in order,
- * comprise the original message
- * @param sentIntents if not null, an ArrayList
of
- * PendingIntent
s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be Activity.RESULT_OK for success,
- * or one of these errors:
- * RESULT_ERROR_GENERIC_FAILURE
- * RESULT_ERROR_RADIO_OFF
- * RESULT_ERROR_NULL_PDU
.
- * @param deliveryIntents if not null, an ArrayList
of
- * PendingIntent
s (one for each message part) that is
- * broadcast when the corresponding message part has been delivered
- * to the recipient. The raw pdu of the status report is in the
- * extended data ("pdu").
- */
- void sendMultipartText(in String destinationAddress, in String scAddress,
- in List parts, in List sentIntents,
- in List deliveryIntents);
-
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/MccTable.java b/telephony/java/com/android/internal/telephony/gsm/MccTable.java
index bb17cc4..8473a21 100644
--- a/telephony/java/com/android/internal/telephony/gsm/MccTable.java
+++ b/telephony/java/com/android/internal/telephony/gsm/MccTable.java
@@ -62,11 +62,11 @@ public final class MccTable
entryForMcc(int mcc)
{
int index;
-
+
MccEntry m;
m = new MccEntry(mcc, null, 0);
-
+
index = Collections.binarySearch(table, m);
if (index < 0) {
@@ -154,7 +154,7 @@ public final class MccTable
/*
* The table below is built from two resources:
- *
+ *
* 1) ITU "Mobile Network Code (MNC) for the international
* identification plan for mobile terminals and mobile users"
* which is available as an annex to the ITU operational bulletin
diff --git a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl
index c600530..d88d0b7 100644
--- a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.aidl
@@ -16,11 +16,11 @@
package com.android.internal.telephony.gsm;
-/**
+/**
* Used to indicate that the NetworkInfo object is parcelable to aidl.
* This is a simple effort to make NetworkInfo parcelable rather than
* trying to make the conventional containing object (AsyncResult),
- * implement parcelable. This functionality is needed for the
+ * implement parcelable. This functionality is needed for the
* NetworkQueryService to fix 1128695
*/
parcelable NetworkInfo;
diff --git a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java
index bebf9ba..04fd13e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java
+++ b/telephony/java/com/android/internal/telephony/gsm/NetworkInfo.java
@@ -22,8 +22,7 @@ import android.os.Parcelable;
/**
* {@hide}
*/
-public class NetworkInfo implements Parcelable
-{
+public class NetworkInfo implements Parcelable {
public enum State {
UNKNOWN,
AVAILABLE,
@@ -39,34 +38,29 @@ public class NetworkInfo implements Parcelable
public String
- getOperatorAlphaLong()
- {
+ getOperatorAlphaLong() {
return operatorAlphaLong;
}
public String
- getOperatorAlphaShort()
- {
+ getOperatorAlphaShort() {
return operatorAlphaShort;
}
public String
- getOperatorNumeric()
- {
+ getOperatorNumeric() {
return operatorNumeric;
}
public State
- getState()
- {
+ getState() {
return state;
}
- NetworkInfo(String operatorAlphaLong,
- String operatorAlphaShort,
- String operatorNumeric,
- State state)
- {
+ NetworkInfo(String operatorAlphaLong,
+ String operatorAlphaShort,
+ String operatorNumeric,
+ State state) {
this.operatorAlphaLong = operatorAlphaLong;
this.operatorAlphaShort = operatorAlphaShort;
@@ -76,20 +70,18 @@ public class NetworkInfo implements Parcelable
}
- NetworkInfo(String operatorAlphaLong,
- String operatorAlphaShort,
- String operatorNumeric,
- String stateString)
- {
- this (operatorAlphaLong, operatorAlphaShort,
+ public NetworkInfo(String operatorAlphaLong,
+ String operatorAlphaShort,
+ String operatorNumeric,
+ String stateString) {
+ this (operatorAlphaLong, operatorAlphaShort,
operatorNumeric, rilStateToState(stateString));
}
/**
* See state strings defined in ril.h RIL_REQUEST_QUERY_AVAILABLE_NETWORKS
*/
- private static State rilStateToState(String s)
- {
+ private static State rilStateToState(String s) {
if (s.equals("unknown")) {
return State.UNKNOWN;
} else if (s.equals("available")) {
@@ -105,29 +97,28 @@ public class NetworkInfo implements Parcelable
}
- public String toString()
- {
- return "NetworkInfo " + operatorAlphaLong
- + "/" + operatorAlphaShort
- + "/" + operatorNumeric
+ public String toString() {
+ return "NetworkInfo " + operatorAlphaLong
+ + "/" + operatorAlphaShort
+ + "/" + operatorNumeric
+ "/" + state;
}
-
- /**
+
+ /**
* Parcelable interface implemented below.
* This is a simple effort to make NetworkInfo parcelable rather than
* trying to make the conventional containing object (AsyncResult),
- * implement parcelable. This functionality is needed for the
+ * implement parcelable. This functionality is needed for the
* NetworkQueryService to fix 1128695.
*/
-
+
public int describeContents() {
return 0;
}
- /**
+ /**
* Implement the Parcelable interface.
- * Method to serialize a NetworkInfo object.
+ * Method to serialize a NetworkInfo object.
*/
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(operatorAlphaLong);
@@ -136,9 +127,9 @@ public class NetworkInfo implements Parcelable
dest.writeSerializable(state);
}
- /**
+ /**
* Implement the Parcelable interface
- * Method to deserialize a NetworkInfo object, or an array thereof.
+ * Method to deserialize a NetworkInfo object, or an array thereof.
*/
public static final Creator CREATOR =
new Creator() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java b/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java
index d5d481a..feb78f8 100644
--- a/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java
+++ b/telephony/java/com/android/internal/telephony/gsm/PDPContextState.java
@@ -19,8 +19,7 @@ package com.android.internal.telephony.gsm;
/**
* {@hide}
*/
-public class PDPContextState
-{
+public class PDPContextState {
public int cid;
public boolean active;
public String type;
diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
index 66f8b72..88acb1b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
@@ -17,88 +17,26 @@
package com.android.internal.telephony.gsm;
import android.os.*;
-import android.database.Cursor;
-import android.provider.Telephony;
import android.text.util.Regex;
import android.util.EventLog;
import android.util.Log;
-import java.util.ArrayList;
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.DataLink;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.TelephonyEventLog;
/**
* {@hide}
*/
-public class PdpConnection extends Handler {
+public class PdpConnection extends DataConnection {
private static final String LOG_TAG = "GSM";
private static final boolean DBG = true;
private static final boolean FAKE_FAIL = false;
- public enum PdpState {
- ACTIVE, /* has active pdp context */
- ACTIVATING, /* during connecting process */
- INACTIVE; /* has empty pdp context */
-
- public String toString() {
- switch (this) {
- case ACTIVE: return "active";
- case ACTIVATING: return "setting up";
- default: return "inactive";
- }
- }
-
- public boolean isActive() {
- return this == ACTIVE;
- }
-
- public boolean isInactive() {
- return this == INACTIVE;
- }
- }
-
- public enum PdpFailCause {
- NONE,
- BAD_APN,
- BAD_PAP_SECRET,
- BARRED,
- USER_AUTHENTICATION,
- SERVICE_OPTION_NOT_SUPPORTED,
- SERVICE_OPTION_NOT_SUBSCRIBED,
- SIM_LOCKED,
- RADIO_OFF,
- NO_SIGNAL,
- NO_DATA_PLAN,
- RADIO_NOT_AVIALABLE,
- SUSPENED_TEMPORARY,
- RADIO_ERROR_RETRY,
- UNKNOWN;
-
- public boolean isPermanentFail() {
- return (this == RADIO_OFF);
- }
-
- public String toString() {
- switch (this) {
- case NONE: return "no error";
- case BAD_APN: return "bad apn";
- case BAD_PAP_SECRET:return "bad pap secret";
- case BARRED: return "barred";
- case USER_AUTHENTICATION: return "error user autentication";
- case SERVICE_OPTION_NOT_SUPPORTED: return "data not supported";
- case SERVICE_OPTION_NOT_SUBSCRIBED: return "datt not subcribed";
- case SIM_LOCKED: return "sim locked";
- case RADIO_OFF: return "radio is off";
- case NO_SIGNAL: return "no signal";
- case NO_DATA_PLAN: return "no data plan";
- case RADIO_NOT_AVIALABLE: return "radio not available";
- case SUSPENED_TEMPORARY: return "suspend temporary";
- case RADIO_ERROR_RETRY: return "transient radio error";
- default: return "unknown data error";
- }
- }
- }
-
/** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */
private static final int PDP_FAIL_RIL_BARRED = 8;
private static final int PDP_FAIL_RIL_BAD_APN = 27;
@@ -107,54 +45,20 @@ public class PdpConnection extends Handler {
private static final int PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUBSCRIBED = 33;
private static final int PDP_FAIL_RIL_ERROR_UNSPECIFIED = 0xffff;
- //***** Event codes
- private static final int EVENT_SETUP_PDP_DONE = 1;
- private static final int EVENT_GET_LAST_FAIL_DONE = 2;
- private static final int EVENT_LINK_STATE_CHANGED = 3;
- private static final int EVENT_DEACTIVATE_DONE = 4;
- private static final int EVENT_FORCE_RETRY = 5;
-
//***** Instance Variables
- private GSMPhone phone;
private String pdp_name;
- private PdpState state;
- private Message onConnectCompleted;
- private Message onDisconnect;
- private int cid;
- private long createTime;
- private long lastFailTime;
- private PdpFailCause lastFailCause;
private ApnSetting apn;
- private String interfaceName;
- private String ipAddress;
- private String gatewayAddress;
- private String[] dnsServers;
-
- private static final String NULL_IP = "0.0.0.0";
// dataLink is only used to support pppd link
- DataLink dataLink;
- // receivedDisconnectReq is set when disconnect pdp link during activating
- private boolean receivedDisconnectReq;
+ private DataLink dataLink;
//***** Constructor
- PdpConnection(GSMPhone phone)
- {
- this.phone = phone;
- this.state = PdpState.INACTIVE;
- onConnectCompleted = null;
- onDisconnect = null;
- this.cid = -1;
- this.createTime = -1;
- this.lastFailTime = -1;
- this.lastFailCause = PdpFailCause.NONE;
- this.apn = null;
+ PdpConnection(GSMPhone phone) {
+ super(phone);
this.dataLink = null;
- receivedDisconnectReq = false;
- this.dnsServers = new String[2];
if (SystemProperties.get("ro.radio.use-ppp","no").equals("yes")) {
- dataLink = new PppLink(phone.mDataConnection);
+ dataLink = new PppLink((GsmDataConnectionTracker) phone.mDataConnection, phone);
dataLink.setOnLinkChange(this, EVENT_LINK_STATE_CHANGED, null);
}
}
@@ -171,37 +75,37 @@ public class PdpConnection extends Handler {
setHttpProxy (apn.proxy, apn.port);
- state = PdpState.ACTIVATING;
+ state = State.ACTIVATING;
this.apn = apn;
onConnectCompleted = onCompleted;
createTime = -1;
lastFailTime = -1;
- lastFailCause = PdpFailCause.NONE;
+ lastFailCause = FailCause.NONE;
receivedDisconnectReq = false;
if (FAKE_FAIL) {
// for debug before baseband implement error in setup PDP
if (apn.apn.equalsIgnoreCase("badapn")){
- notifyFail(PdpFailCause.BAD_APN, onConnectCompleted);
+ notifyFail(FailCause.BAD_APN, onConnectCompleted);
return;
}
}
- phone.mCM.setupDefaultPDP(apn.apn, apn.user, apn.password,
- obtainMessage(EVENT_SETUP_PDP_DONE));
+ phone.mCM.setupDataCall(Integer.toString(RILConstants.GSM_PHONE), null, apn.apn, apn.user,
+ apn.password, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
}
- void disconnect(Message msg) {
+ protected void disconnect(Message msg) {
onDisconnect = msg;
- if (state == PdpState.ACTIVE) {
+ if (state == State.ACTIVE) {
if (dataLink != null) {
dataLink.disconnect();
}
if (phone.mCM.getRadioState().isOn()) {
- phone.mCM.deactivateDefaultPDP(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg));
+ phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg));
}
- } else if (state == PdpState.ACTIVATING) {
+ } else if (state == State.ACTIVATING) {
receivedDisconnectReq = true;
} else {
// state == INACTIVE. Nothing to do, so notify immediately.
@@ -209,20 +113,9 @@ public class PdpConnection extends Handler {
}
}
- private void
- setHttpProxy(String httpProxy, String httpPort)
- {
- if (httpProxy == null || httpProxy.length() == 0) {
- phone.setSystemProperty("net.gprs.http-proxy", null);
- return;
- }
-
- if (httpPort == null || httpPort.length() == 0) {
- httpPort = "8080"; // Default to port 8080
- }
-
- phone.setSystemProperty("net.gprs.http-proxy",
- "http://" + httpProxy + ":" + httpPort + "/");
+ public void clearSettings() {
+ super.clearSettings();
+ apn = null;
}
public String toString() {
@@ -231,61 +124,30 @@ public class PdpConnection extends Handler {
" lastFailCause=" + lastFailCause;
}
- public long getConnectionTime() {
- return createTime;
- }
-
- public long getLastFailTime() {
- return lastFailTime;
- }
-
- public PdpFailCause getLastFailCause() {
- return lastFailCause;
- }
-
- public ApnSetting getApn() {
- return apn;
- }
-
- String getInterface() {
- return interfaceName;
- }
-
- String getIpAddress() {
- return ipAddress;
- }
-
- String getGatewayAddress() {
- return gatewayAddress;
- }
-
- String[] getDnsServers() {
- return dnsServers;
- }
-
- public PdpState getState() {
- return state;
- }
- private void notifyFail(PdpFailCause cause, Message onCompleted) {
+ protected void notifyFail(FailCause cause, Message onCompleted) {
if (onCompleted == null) return;
- state = PdpState.INACTIVE;
+ state = State.INACTIVE;
lastFailCause = cause;
lastFailTime = System.currentTimeMillis();
onConnectCompleted = null;
- if (DBG) log("Notify PDP fail at " + lastFailTime
- + " due to " + lastFailCause);
+ if (DBG) {
+ log("Notify PDP fail at " + lastFailTime +
+ " due to " + lastFailCause);
+ }
AsyncResult.forMessage(onCompleted, cause, new Exception());
onCompleted.sendToTarget();
}
- private void notifySuccess(Message onCompleted) {
- if (onCompleted == null) return;
+ protected void notifySuccess(Message onCompleted) {
+ if (onCompleted == null) {
+ return;
+ }
- state = PdpState.ACTIVE;
+ state = State.ACTIVE;
createTime = System.currentTimeMillis();
onConnectCompleted = null;
onCompleted.arg1 = cid;
@@ -296,7 +158,7 @@ public class PdpConnection extends Handler {
onCompleted.sendToTarget();
}
- private void notifyDisconnect(Message msg) {
+ protected void notifyDisconnect(Message msg) {
if (DBG) log("Notify PDP disconnect");
if (msg != null) {
@@ -306,22 +168,7 @@ public class PdpConnection extends Handler {
clearSettings();
}
- void clearSettings() {
- state = PdpState.INACTIVE;
- receivedDisconnectReq = false;
- createTime = -1;
- lastFailTime = -1;
- lastFailCause = PdpFailCause.NONE;
- apn = null;
- onConnectCompleted = null;
- interfaceName = null;
- ipAddress = null;
- gatewayAddress = null;
- dnsServers[0] = null;
- dnsServers[1] = null;
- }
-
- private void onLinkStateChanged(DataLink.LinkState linkState) {
+ protected void onLinkStateChanged(DataLink.LinkState linkState) {
switch (linkState) {
case LINK_UP:
notifySuccess(onConnectCompleted);
@@ -335,151 +182,110 @@ public class PdpConnection extends Handler {
}
}
- private PdpFailCause getFailCauseFromRequest(int rilCause) {
- PdpFailCause cause;
+ protected FailCause getFailCauseFromRequest(int rilCause) {
+ FailCause cause;
switch (rilCause) {
case PDP_FAIL_RIL_BARRED:
- cause = PdpFailCause.BARRED;
+ cause = FailCause.BARRED;
break;
case PDP_FAIL_RIL_BAD_APN:
- cause = PdpFailCause.BAD_APN;
+ cause = FailCause.BAD_APN;
break;
case PDP_FAIL_RIL_USER_AUTHENTICATION:
- cause = PdpFailCause.USER_AUTHENTICATION;
+ cause = FailCause.USER_AUTHENTICATION;
break;
case PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUPPORTED:
- cause = PdpFailCause.SERVICE_OPTION_NOT_SUPPORTED;
+ cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED;
break;
case PDP_FAIL_RIL_SERVICE_OPTION_NOT_SUBSCRIBED:
- cause = PdpFailCause.SERVICE_OPTION_NOT_SUBSCRIBED;
+ cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED;
break;
default:
- cause = PdpFailCause.UNKNOWN;
+ cause = FailCause.UNKNOWN;
}
return cause;
}
-
- private void log(String s) {
+ protected void log(String s) {
Log.d(LOG_TAG, "[PdpConnection] " + s);
}
@Override
- public void handleMessage(Message msg) {
- AsyncResult ar;
-
- switch (msg.what) {
- case EVENT_SETUP_PDP_DONE:
- ar = (AsyncResult) msg.obj;
-
- if (ar.exception != null) {
- Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception);
-
- if (receivedDisconnectReq) {
- // Don't bother reporting the error if there's already a
- // pending disconnect request, since DataConnectionTracker
- // has already updated its state.
- notifyDisconnect(onDisconnect);
- } else {
- if ( ar.exception instanceof CommandException &&
- ((CommandException) (ar.exception)).getCommandError()
- == CommandException.Error.RADIO_NOT_AVAILABLE) {
- notifyFail(PdpFailCause.RADIO_NOT_AVIALABLE,
- onConnectCompleted);
- } else {
- phone.mCM.getLastPdpFailCause(
- obtainMessage(EVENT_GET_LAST_FAIL_DONE));
- }
- }
+ protected void onDeactivated(AsyncResult ar) {
+ notifyDisconnect((Message) ar.userObj);
+ if (DBG) log("PDP Connection Deactivated");
+ }
+
+ @Override
+ protected void onSetupConnectionCompleted(AsyncResult ar) {
+ if (ar.exception != null) {
+ Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception);
+
+ if (receivedDisconnectReq) {
+ // Don't bother reporting the error if there's already a
+ // pending disconnect request, since DataConnectionTracker
+ // has already updated its state.
+ notifyDisconnect(onDisconnect);
+ } else {
+ if ( ar.exception instanceof CommandException &&
+ ((CommandException) (ar.exception)).getCommandError()
+ == CommandException.Error.RADIO_NOT_AVAILABLE) {
+ notifyFail(FailCause.RADIO_NOT_AVAILABLE,
+ onConnectCompleted);
} else {
- if (receivedDisconnectReq) {
- // Don't bother reporting success if there's already a
- // pending disconnect request, since DataConnectionTracker
- // has already updated its state.
- // Set ACTIVE so that disconnect does the right thing.
- state = PdpState.ACTIVE;
- 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])
- && !phone.isDnsCheckDisabled()) {
- // Work around a race condition where QMI does not fill in DNS:
- // Deactivate PDP and let DataConnectionTracker retry.
- // Do not apply the race condition workaround for MMS APN
- // if Proxy is an IP-address.
- // Otherwise, the default APN will not be restored anymore.
- if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
- || !isIpAddress(apn.mmsProxy)) {
- EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
- dnsServers[0]);
- phone.mCM.deactivateDefaultPDP(cid,
- obtainMessage(EVENT_FORCE_RETRY));
- break;
- }
- }
- }
+ phone.mCM.getLastPdpFailCause(
+ obtainMessage(EVENT_GET_LAST_FAIL_DONE));
+ }
+ }
+ } else {
+ if (receivedDisconnectReq) {
+ // Don't bother reporting success if there's already a
+ // pending disconnect request, since DataConnectionTracker
+ // has already updated its state.
+ disconnect(onDisconnect);
+ } else {
+ String[] response = ((String[]) ar.result);
+ cid = Integer.parseInt(response[0]);
+
+ if (response.length > 2) {
+ interfaceName = response[1];
+ ipAddress = response[2];
+ String prefix = "net." + interfaceName + ".";
+ gatewayAddress = SystemProperties.get(prefix + "gw");
+ dnsServers[0] = SystemProperties.get(prefix + "dns1");
+ dnsServers[1] = SystemProperties.get(prefix + "dns2");
+ if (DBG) {
+ log("interface=" + interfaceName + " ipAddress=" + ipAddress
+ + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
+ + " DNS2=" + dnsServers[1]);
+ }
- if (dataLink != null) {
- dataLink.connect();
- } else {
- onLinkStateChanged(DataLink.LinkState.LINK_UP);
+ if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
+ && !((GSMPhone) phone).isDnsCheckDisabled()) {
+ // Work around a race condition where QMI does not fill in DNS:
+ // Deactivate PDP and let DataConnectionTracker retry.
+ // Do not apply the race condition workaround for MMS APN
+ // if Proxy is an IP-address.
+ // Otherwise, the default APN will not be restored anymore.
+ if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
+ || !isIpAddress(apn.mmsProxy)) {
+ EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
+ dnsServers[0]);
+ phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY));
+ return;
}
-
- if (DBG) log("PDP setup on cid = " + cid);
}
}
- break;
- case EVENT_FORCE_RETRY:
- if (receivedDisconnectReq) {
- notifyDisconnect(onDisconnect);
- } else {
- ar = (AsyncResult) msg.obj;
- notifyFail(PdpFailCause.RADIO_ERROR_RETRY, onConnectCompleted);
- }
- break;
- case EVENT_GET_LAST_FAIL_DONE:
- if (receivedDisconnectReq) {
- // Don't bother reporting the error if there's already a
- // pending disconnect request, since DataConnectionTracker
- // has already updated its state.
- notifyDisconnect(onDisconnect);
- } else {
- ar = (AsyncResult) msg.obj;
- PdpFailCause cause = PdpFailCause.UNKNOWN;
- if (ar.exception == null) {
- int rilFailCause = ((int[]) (ar.result))[0];
- cause = getFailCauseFromRequest(rilFailCause);
- }
- notifyFail(cause, onConnectCompleted);
+ if (dataLink != null) {
+ dataLink.connect();
+ } else {
+ onLinkStateChanged(DataLink.LinkState.LINK_UP);
}
- break;
- case EVENT_LINK_STATE_CHANGED:
- ar = (AsyncResult) msg.obj;
- DataLink.LinkState ls = (DataLink.LinkState) ar.result;
- onLinkStateChanged(ls);
- break;
- case EVENT_DEACTIVATE_DONE:
- ar = (AsyncResult) msg.obj;
- notifyDisconnect((Message) ar.userObj);
- break;
+ if (DBG) log("PDP setup on cid = " + cid);
+ }
}
}
@@ -488,4 +294,8 @@ public class PdpConnection extends Handler {
return Regex.IP_ADDRESS_PATTERN.matcher(apn.mmsProxy).matches();
}
+
+ public ApnSetting getApn() {
+ return this.apn;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/PppLink.java b/telephony/java/com/android/internal/telephony/gsm/PppLink.java
index 43d4f1f..9627696 100644
--- a/telephony/java/com/android/internal/telephony/gsm/PppLink.java
+++ b/telephony/java/com/android/internal/telephony/gsm/PppLink.java
@@ -16,28 +16,31 @@
package com.android.internal.telephony.gsm;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-
import android.database.Cursor;
import android.os.Message;
import android.os.SystemProperties;
import android.os.SystemService;
-import com.android.internal.telephony.gsm.DataConnectionTracker.State;
-import com.android.internal.util.ArrayUtils;
import android.util.Log;
+import com.android.internal.telephony.DataLink;
+import com.android.internal.telephony.DataConnectionTracker.State;
+import com.android.internal.telephony.PhoneBase;
+import com.android.internal.util.ArrayUtils;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
/**
* Represents a PPP link.
- *
+ *
* Ideally this would be managed by the RIL implementation, but
* we currently have implementations where this is not the case.
*
* {@hide}
*/
-final class PppLink extends DataLink implements DataLinkInterface {
+final class PppLink extends DataLink {
private static final String LOG_TAG = "GSM";
static final String PATH_PPP_OPERSTATE = "/sys/class/net/ppp0/operstate";
@@ -69,11 +72,14 @@ final class PppLink extends DataLink implements DataLinkInterface {
};
private final byte[] mCheckPPPBuffer = new byte[32];
+ private PhoneBase phone;
+
int lastPppdExitCode = EXIT_OK;
- PppLink(DataConnectionTracker dc) {
+ PppLink(GsmDataConnectionTracker dc, GSMPhone p) {
super(dc);
+ this.phone = p;
}
public void connect() {
@@ -131,7 +137,7 @@ final class PppLink extends DataLink implements DataLinkInterface {
checkPPP();
// keep polling in case interface goes down
- if (dataConnection.state != State.IDLE) {
+ if (dataConnection.getState() != State.IDLE) {
Message poll = obtainMessage();
poll.what = EVENT_POLL_DATA_CONNECTION;
sendMessageDelayed(poll, POLL_SYSFS_MILLIS);
@@ -141,7 +147,7 @@ final class PppLink extends DataLink implements DataLinkInterface {
}
private void checkPPP() {
- boolean connecting = (dataConnection.state == State.CONNECTING);
+ boolean connecting = (dataConnection.getState() == State.CONNECTING);
try {
RandomAccessFile file = new RandomAccessFile(PATH_PPP_OPERSTATE, "r");
@@ -152,10 +158,10 @@ final class PppLink extends DataLink implements DataLinkInterface {
// "unknown" where one might otherwise expect "up"
if (ArrayUtils.equals(mCheckPPPBuffer, UP_ASCII_STRING, UP_ASCII_STRING.length)
|| ArrayUtils.equals(mCheckPPPBuffer, UNKNOWN_ASCII_STRING,
- UNKNOWN_ASCII_STRING.length)
- && dataConnection.state == State.CONNECTING) {
+ UNKNOWN_ASCII_STRING.length)
+ && dataConnection.getState() == State.CONNECTING) {
- Log.i(LOG_TAG,
+ Log.i(LOG_TAG,
"found ppp interface. Notifying GPRS connected");
if (mLinkChangeRegistrant != null) {
@@ -163,23 +169,23 @@ final class PppLink extends DataLink implements DataLinkInterface {
}
connecting = false;
- } else if (dataConnection.state == State.CONNECTED
+ } else if (dataConnection.getState() == State.CONNECTED
&& ArrayUtils.equals(mCheckPPPBuffer, DOWN_ASCII_STRING,
- DOWN_ASCII_STRING.length)) {
+ DOWN_ASCII_STRING.length)) {
- Log.i(LOG_TAG,
+ Log.i(LOG_TAG,
"ppp interface went down. Reconnecting...");
if (mLinkChangeRegistrant != null) {
mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN);
}
- }
+ }
} catch (IOException ex) {
if (! (ex instanceof FileNotFoundException)) {
Log.i(LOG_TAG, "Poll ppp0 ex " + ex.toString());
}
- if (dataConnection.state == State.CONNECTED &&
+ if (dataConnection.getState() == State.CONNECTED &&
mLinkChangeRegistrant != null) {
mLinkChangeRegistrant.notifyResult(LinkState.LINK_DOWN);
}
@@ -206,4 +212,8 @@ final class PppLink extends DataLink implements DataLinkInterface {
}
}
+
+ protected void log(String s) {
+ Log.d(LOG_TAG, "[PppLink] " + s);
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/RIL.java b/telephony/java/com/android/internal/telephony/gsm/RIL.java
deleted file mode 100644
index e2d0f72..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/RIL.java
+++ /dev/null
@@ -1,2586 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import static com.android.internal.telephony.gsm.RILConstants.*;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.gsm.SmsManager;
-import android.telephony.gsm.SmsMessage;
-import android.telephony.NeighboringCellInfo;
-import android.util.Config;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-
-/**
- * {@hide}
- */
-class RILRequest
-{
- static final String LOG_TAG = "RILJ";
-
- //***** Class Variables
- static int sNextSerial = 0;
- static Object sSerialMonitor = new Object();
- private static Object sPoolSync = new Object();
- private static RILRequest sPool = null;
- private static int sPoolSize = 0;
- private static final int MAX_POOL_SIZE = 4;
-
- //***** Instance Variables
- int mSerial;
- int mRequest;
- Message mResult;
- Parcel mp;
- RILRequest mNext;
-
- /**
- * Retrieves a new RILRequest instance from the pool.
- *
- * @param request RIL_REQUEST_*
- * @param result sent when operation completes
- * @return a RILRequest instance from the pool.
- */
- static RILRequest obtain(int request, Message result) {
- RILRequest rr = null;
-
- synchronized(sPoolSync) {
- if (sPool != null) {
- rr = sPool;
- sPool = rr.mNext;
- rr.mNext = null;
- sPoolSize--;
- }
- }
-
- if (rr == null) {
- rr = new RILRequest();
- }
-
- synchronized(sSerialMonitor) {
- rr.mSerial = sNextSerial++;
- }
- rr.mRequest = request;
- rr.mResult = result;
- rr.mp = Parcel.obtain();
-
- if (result != null && result.getTarget() == null) {
- throw new NullPointerException("Message target must not be null");
- }
-
- // first elements in any RIL Parcel
- rr.mp.writeInt(request);
- rr.mp.writeInt(rr.mSerial);
-
- return rr;
- }
-
- /**
- * Returns a RILRequest instance to the pool.
- *
- * Note: This should only be called once per use.
- */
- void release() {
- synchronized (sPoolSync) {
- if (sPoolSize < MAX_POOL_SIZE) {
- this.mNext = sPool;
- sPool = this;
- sPoolSize++;
- }
- }
- }
-
- private RILRequest()
- {
- }
-
- static void
- resetSerial()
- {
- synchronized(sSerialMonitor) {
- sNextSerial = 0;
- }
- }
-
- String
- serialString()
- {
- //Cheesy way to do %04d
- StringBuilder sb = new StringBuilder(8);
- String sn;
-
- sn = Integer.toString(mSerial);
-
- //sb.append("J[");
- sb.append('[');
- for (int i = 0, s = sn.length() ; i < 4 - s; i++) {
- sb.append('0');
- }
-
- sb.append(sn);
- sb.append(']');
- return sb.toString();
- }
-
- void
- onError(int error)
- {
- CommandException ex;
-
- ex = CommandException.fromRilErrno(error);
-
- if (RIL.RILJ_LOGD) Log.d(LOG_TAG, serialString() + "< "
- + RIL.requestToString(mRequest)
- + " error: " + ex);
-
- if (mResult != null) {
- AsyncResult.forMessage(mResult, null, ex);
- mResult.sendToTarget();
- }
-
- if (mp != null) {
- mp.recycle();
- mp = null;
- }
- }
-}
-
-
-/**
- * RIL implementation of the CommandsInterface.
- * FIXME public only for testing
- *
- * {@hide}
- */
-public final class RIL extends BaseCommands implements CommandsInterface
-{
- static final String LOG_TAG = "RILJ";
- private static final boolean DBG = false;
- static final boolean RILJ_LOGD = Config.LOGD;
- static final boolean RILJ_LOGV = DBG ? Config.LOGD : Config.LOGV;
- static int WAKE_LOCK_TIMEOUT = 5000;
-
- //***** Instance Variables
-
- LocalSocket mSocket;
- HandlerThread mSenderThread;
- RILSender mSender;
- Thread mReceiverThread;
- RILReceiver mReceiver;
- private Context mContext;
- WakeLock mWakeLock;
- int mRequestMessagesPending;
-
- // Is this the first radio state change?
- private boolean mInitialRadioStateChange = true;
-
- //I'd rather this be LinkedList or something
- ArrayList mRequestsList = new ArrayList();
-
- Object mLastNITZTimeInfo;
-
- //***** Events
-
- static final int EVENT_SEND = 1;
- static final int EVENT_WAKE_LOCK_TIMEOUT = 2;
-
- //***** Constants
-
- // match with constant in ril.cpp
- static final int RIL_MAX_COMMAND_BYTES = (8 * 1024);
- static final int RESPONSE_SOLICITED = 0;
- static final int RESPONSE_UNSOLICITED = 1;
-
- static final String SOCKET_NAME_RIL = "rild";
-
- static final int SOCKET_OPEN_RETRY_MILLIS = 4 * 1000;
-
-
- BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
- sendScreenState(true);
- } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
- sendScreenState(false);
- } else {
- Log.w(LOG_TAG, "RIL received unexpected Intent: " + intent.getAction());
- }
- }
- };
-
- class RILSender extends Handler implements Runnable
- {
- public RILSender(Looper looper) {
- super(looper);
- }
-
- // Only allocated once
- byte[] dataLength = new byte[4];
-
- //***** Runnable implementation
- public void
- run()
- {
- //setup if needed
- }
-
-
- //***** Handler implemementation
-
- public void
- handleMessage(Message msg)
- {
- RILRequest rr = (RILRequest)(msg.obj);
- RILRequest req = null;
-
- switch (msg.what) {
- case EVENT_SEND:
- /**
- * mRequestMessagePending++ already happened for every
- * EVENT_SEND, thus we must make sure
- * mRequestMessagePending-- happens once and only once
- */
- boolean alreadySubtracted = false;
- try {
- LocalSocket s;
-
- s = mSocket;
-
- if (s == null) {
- rr.onError(RADIO_NOT_AVAILABLE);
- rr.release();
- mRequestMessagesPending--;
- alreadySubtracted = true;
- return;
- }
-
- synchronized (mRequestsList) {
- mRequestsList.add(rr);
- }
-
- mRequestMessagesPending--;
- alreadySubtracted = true;
-
- byte[] data;
-
- data = rr.mp.marshall();
- rr.mp.recycle();
- rr.mp = null;
-
- if (data.length > RIL_MAX_COMMAND_BYTES) {
- throw new RuntimeException(
- "Parcel larger than max bytes allowed! "
- + data.length);
- }
-
- // parcel length in big endian
- dataLength[0] = dataLength[1] = 0;
- dataLength[2] = (byte)((data.length >> 8) & 0xff);
- dataLength[3] = (byte)((data.length) & 0xff);
-
- //Log.v(LOG_TAG, "writing packet: " + data.length + " bytes");
-
- s.getOutputStream().write(dataLength);
- s.getOutputStream().write(data);
- } catch (IOException ex) {
- Log.e(LOG_TAG, "IOException", ex);
- req = findAndRemoveRequestFromList(rr.mSerial);
- // make sure this request has not already been handled,
- // eg, if RILReceiver cleared the list.
- if (req != null || !alreadySubtracted) {
- rr.onError(RADIO_NOT_AVAILABLE);
- rr.release();
- }
- } catch (RuntimeException exc) {
- Log.e(LOG_TAG, "Uncaught exception ", exc);
- req = findAndRemoveRequestFromList(rr.mSerial);
- // make sure this request has not already been handled,
- // eg, if RILReceiver cleared the list.
- if (req != null || !alreadySubtracted) {
- rr.onError(GENERIC_FAILURE);
- rr.release();
- }
- }
-
- if (!alreadySubtracted) {
- mRequestMessagesPending--;
- }
-
- break;
-
- case EVENT_WAKE_LOCK_TIMEOUT:
- // Haven't heard back from the last request. Assume we're
- // not getting a response and release the wake lock.
- // TODO should we clean up mRequestList and mRequestPending
- synchronized (mWakeLock) {
- if (mWakeLock.isHeld()) {
- if (RILJ_LOGD) {
- synchronized (mRequestsList) {
- int count = mRequestsList.size();
- Log.d(LOG_TAG, "WAKE_LOCK_TIMEOUT " +
- " mReqPending=" + mRequestMessagesPending +
- " mRequestList=" + count);
-
- for (int i = 0; i < count; i++) {
- rr = mRequestsList.get(i);
- Log.d(LOG_TAG, i + ": [" + rr.mSerial + "] " +
- requestToString(rr.mRequest));
-
- }
- }
- }
- mWakeLock.release();
- }
- }
-
- break;
- }
- }
- }
-
- /**
- * Reads in a single RIL message off the wire. A RIL message consists
- * of a 4-byte little-endian length and a subsequent series of bytes.
- * The final message (length header omitted) is read into
- * buffer
and the length of the final message (less header)
- * is returned. A return value of -1 indicates end-of-stream.
- *
- * @param is non-null; Stream to read from
- * @param buffer Buffer to fill in. Must be as large as maximum
- * message size, or an ArrayOutOfBounds exception will be thrown.
- * @return Length of message less header, or -1 on end of stream.
- * @throws IOException
- */
- private static int readRilMessage(InputStream is, byte[] buffer)
- throws IOException
- {
- int countRead;
- int offset;
- int remaining;
- int messageLength;
-
- // First, read in the length of the message
- offset = 0;
- remaining = 4;
- do {
- countRead = is.read(buffer, offset, remaining);
-
- if (countRead < 0 ) {
- Log.e(LOG_TAG, "Hit EOS reading message length");
- return -1;
- }
-
- offset += countRead;
- remaining -= countRead;
- } while (remaining > 0);
-
- messageLength = ((buffer[0] & 0xff) << 24)
- | ((buffer[1] & 0xff) << 16)
- | ((buffer[2] & 0xff) << 8)
- | (buffer[3] & 0xff);
-
- // Then, re-use the buffer and read in the message itself
- offset = 0;
- remaining = messageLength;
- do {
- countRead = is.read(buffer, offset, remaining);
-
- if (countRead < 0 ) {
- Log.e(LOG_TAG, "Hit EOS reading message. messageLength=" + messageLength
- + " remaining=" + remaining);
- return -1;
- }
-
- offset += countRead;
- remaining -= countRead;
- } while (remaining > 0);
-
- return messageLength;
- }
-
- class RILReceiver implements Runnable
- {
- byte[] buffer;
-
- RILReceiver()
- {
- buffer = new byte[RIL_MAX_COMMAND_BYTES];
- }
-
- public void
- run()
- {
- int retryCount = 0;
-
- try {for (;;) {
- LocalSocket s = null;
- LocalSocketAddress l;
-
- try {
- s = new LocalSocket();
- l = new LocalSocketAddress(SOCKET_NAME_RIL,
- LocalSocketAddress.Namespace.RESERVED);
- s.connect(l);
- } catch (IOException ex){
- try {
- if (s != null) {
- s.close();
- }
- } catch (IOException ex2) {
- //ignore failure to close after failure to connect
- }
-
- // don't print an error message after the the first time
- // or after the 8th time
-
- if (retryCount == 8) {
- Log.e (LOG_TAG,
- "Couldn't find '" + SOCKET_NAME_RIL
- + "' socket after " + retryCount
- + " times, continuing to retry silently");
- } else if (retryCount > 0 && retryCount < 8) {
- Log.i (LOG_TAG,
- "Couldn't find '" + SOCKET_NAME_RIL
- + "' socket; retrying after timeout");
- }
-
- try {
- Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
- } catch (InterruptedException er) {
- }
-
- retryCount++;
- continue;
- }
-
- retryCount = 0;
-
- mSocket = s;
- Log.i(LOG_TAG, "Connected to '" + SOCKET_NAME_RIL + "' socket");
-
- int length = 0;
- try {
- InputStream is = mSocket.getInputStream();
-
- for (;;) {
- Parcel p;
-
- length = readRilMessage(is, buffer);
-
- if (length < 0) {
- // End-of-stream reached
- break;
- }
-
- p = Parcel.obtain();
- p.unmarshall(buffer, 0, length);
- p.setDataPosition(0);
-
- //Log.v(LOG_TAG, "Read packet: " + length + " bytes");
-
- processResponse(p);
- p.recycle();
- }
- } catch (java.io.IOException ex) {
- Log.i(LOG_TAG, "'" + SOCKET_NAME_RIL + "' socket closed",
- ex);
- } catch (Throwable tr) {
- Log.e(LOG_TAG, "Uncaught exception read length=" + length +
- "Exception:" + tr.toString());
- }
-
- Log.i(LOG_TAG, "Disconnected from '" + SOCKET_NAME_RIL
- + "' socket");
-
- setRadioState (RadioState.RADIO_UNAVAILABLE);
-
- try {
- mSocket.close();
- } catch (IOException ex) {
- }
-
- mSocket = null;
- RILRequest.resetSerial();
-
- // Clear request list on close
- synchronized (mRequestsList) {
- for (int i = 0, sz = mRequestsList.size() ; i < sz ; i++) {
- RILRequest rr = mRequestsList.get(i);
- rr.onError(RADIO_NOT_AVAILABLE);
- rr.release();
- }
-
- mRequestsList.clear();
- }
- }} catch (Throwable tr) {
- Log.e(LOG_TAG,"Uncaught exception", tr);
- }
- }
- }
-
-
-
- //***** Constructor
-
- public
- RIL(Context context)
- {
- super(context);
-
- PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
- mWakeLock.setReferenceCounted(false);
- mRequestMessagesPending = 0;
-
- mContext = context;
-
- mSenderThread = new HandlerThread("RILSender");
- mSenderThread.start();
-
- Looper looper = mSenderThread.getLooper();
- mSender = new RILSender(looper);
-
- mReceiver = new RILReceiver();
- mReceiverThread = new Thread(mReceiver, "RILReceiver");
- mReceiverThread.start();
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_SCREEN_ON);
- filter.addAction(Intent.ACTION_SCREEN_OFF);
- context.registerReceiver(mIntentReceiver, filter);
- }
-
- //***** CommandsInterface implementation
-
- @Override public void
- setOnNITZTime(Handler h, int what, Object obj)
- {
- super.setOnNITZTime(h, what, obj);
-
- // Send the last NITZ time if we have it
- if (mLastNITZTimeInfo != null) {
- mNITZTimeRegistrant
- .notifyRegistrant(
- new AsyncResult (null, mLastNITZTimeInfo, null));
- mLastNITZTimeInfo = null;
- }
- }
-
- public void
- getSimStatus(Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_SIM_STATUS, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- supplySimPin(String pin, Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeInt(1);
- rr.mp.writeString(pin);
-
- send(rr);
- }
-
- public void
- supplySimPuk(String puk, String newPin, Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeInt(2);
- rr.mp.writeString(puk);
- rr.mp.writeString(newPin);
-
- send(rr);
- }
-
- public void
- supplySimPin2(String pin, Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PIN2, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeInt(1);
- rr.mp.writeString(pin);
-
- send(rr);
- }
-
- public void
- supplySimPuk2(String puk, String newPin2, Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_SIM_PUK2, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeInt(2);
- rr.mp.writeString(puk);
- rr.mp.writeString(newPin2);
-
- send(rr);
- }
-
- public void
- changeSimPin(String oldPin, String newPin, Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeInt(2);
- rr.mp.writeString(oldPin);
- rr.mp.writeString(newPin);
-
- send(rr);
- }
-
- public void
- changeSimPin2(String oldPin2, String newPin2, Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_SIM_PIN2, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeInt(2);
- rr.mp.writeString(oldPin2);
- rr.mp.writeString(newPin2);
-
- send(rr);
- }
-
- public void
- changeBarringPassword(String facility, String oldPwd, String newPwd, Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_BARRING_PASSWORD, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeInt(3);
- rr.mp.writeString(facility);
- rr.mp.writeString(oldPwd);
- rr.mp.writeString(newPwd);
-
- send(rr);
- }
-
- public void
- supplyNetworkDepersonalization(String netpin, Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeInt(1);
- rr.mp.writeString(netpin);
-
- send(rr);
- }
-
- public void
- getCurrentCalls (Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_CURRENT_CALLS, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getPDPContextList(Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_PDP_CONTEXT_LIST, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- dial (String address, int clirMode, Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
-
- rr.mp.writeString(address);
- rr.mp.writeInt(clirMode);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getIMSI(Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> getIMSI:RIL_REQUEST_GET_IMSI " + RIL_REQUEST_GET_IMSI + " " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getIMEI(Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEI, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getIMEISV(Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEISV, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
-
- public void
- hangupConnection (int gsmIndex, Message result)
- {
- if (RILJ_LOGD) riljLog("hangupConnection: gsmIndex=" + gsmIndex);
-
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + gsmIndex);
-
- rr.mp.writeInt(1);
- rr.mp.writeInt(gsmIndex);
-
- send(rr);
- }
-
- public void
- hangupWaitingOrBackground (Message result)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
- result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- hangupForegroundResumeBackground (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(
- RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND,
- result);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- switchWaitingOrHoldingAndActive (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(
- RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE,
- result);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- conference (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_CONFERENCE, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
-
- public void
- separateConnection (int gsmIndex, Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SEPARATE_CONNECTION, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " " + gsmIndex);
-
- rr.mp.writeInt(1);
- rr.mp.writeInt(gsmIndex);
-
- send(rr);
- }
-
- public void
- acceptCall (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_ANSWER, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- rejectCall (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_UDUB, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- explicitCallTransfer (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_EXPLICIT_CALL_TRANSFER, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getLastCallFailCause (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getLastPdpFailCause (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_LAST_PDP_FAIL_CAUSE, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- setMute (boolean enableMute, Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SET_MUTE, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " " + enableMute);
-
- rr.mp.writeInt(1);
- rr.mp.writeInt(enableMute ? 1 : 0);
-
- send(rr);
- }
-
- public void
- getMute (Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_GET_MUTE, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getSignalStrength (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SIGNAL_STRENGTH, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getRegistrationState (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_REGISTRATION_STATE, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getGPRSRegistrationState (Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_GPRS_REGISTRATION_STATE, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getOperator(Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_OPERATOR, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- sendDtmf(char c, Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_DTMF, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeString(Character.toString(c));
-
- send(rr);
- }
-
- public void
- startDtmf(char c, Message result) {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_DTMF_START, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeString(Character.toString(c));
-
- send(rr);
- }
-
- public void
- stopDtmf(Message result) {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_DTMF_STOP, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
-
- public void
- sendSMS (String smscPDU, String pdu, Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SEND_SMS, result);
-
- rr.mp.writeInt(2);
- rr.mp.writeString(smscPDU);
- rr.mp.writeString(pdu);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void deleteSmsOnSim(int index, Message response) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_DELETE_SMS_ON_SIM,
- response);
-
- rr.mp.writeInt(1);
- rr.mp.writeInt(index);
-
- if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> "
- + requestToString(rr.mRequest)
- + " " + index);
- }
-
- send(rr);
- }
-
- public void writeSmsToSim(int status, String smsc, String pdu, Message response) {
- status = translateStatus(status);
-
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_WRITE_SMS_TO_SIM,
- response);
-
- rr.mp.writeInt(status);
- rr.mp.writeString(pdu);
- rr.mp.writeString(smsc);
-
- if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> "
- + requestToString(rr.mRequest)
- + " " + status);
- }
-
- send(rr);
- }
-
- /**
- * Translates EF_SMS status bits to a status value compatible with
- * SMS AT commands. See TS 27.005 3.1.
- */
- private int translateStatus(int status) {
- switch(status & 0x7) {
- case SmsManager.STATUS_ON_SIM_READ:
- return 1;
- case SmsManager.STATUS_ON_SIM_UNREAD:
- return 0;
- case SmsManager.STATUS_ON_SIM_SENT:
- return 3;
- case SmsManager.STATUS_ON_SIM_UNSENT:
- return 2;
- }
-
- // Default to READ.
- return 1;
- }
-
- public void
- setupDefaultPDP(String apn, String user, String password, Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SETUP_DEFAULT_PDP, result);
-
- rr.mp.writeInt(3);
- rr.mp.writeString(apn);
- rr.mp.writeString(user);
- rr.mp.writeString(password);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " "
- + apn);
-
- send(rr);
- }
-
- public void
- deactivateDefaultPDP(int cid, Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_DEACTIVATE_DEFAULT_PDP, result);
-
- rr.mp.writeInt(1);
- rr.mp.writeString(Integer.toString(cid));
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + cid);
-
- send(rr);
- }
-
- public void
- setRadioPower(boolean on, Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result);
-
- rr.mp.writeInt(1);
- rr.mp.writeInt(on ? 1 : 0);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- setSuppServiceNotifications(boolean enable, Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION, result);
-
- rr.mp.writeInt(1);
- rr.mp.writeInt(enable ? 1 : 0);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> "
- + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- acknowledgeLastIncomingSMS(boolean success, Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SMS_ACKNOWLEDGE, result);
-
- rr.mp.writeInt(1);
- rr.mp.writeInt(success ? 1 : 0);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- simIO (int command, int fileid, String path, int p1, int p2, int p3,
- String data, String pin2, Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SIM_IO, result);
-
- rr.mp.writeInt(command);
- rr.mp.writeInt(fileid);
- rr.mp.writeString(path);
- rr.mp.writeInt(p1);
- rr.mp.writeInt(p2);
- rr.mp.writeInt(p3);
- rr.mp.writeString(data);
- rr.mp.writeString(pin2);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> simIO: " + requestToString(rr.mRequest)
- + " 0x" + Integer.toHexString(command)
- + " 0x" + Integer.toHexString(fileid) + " "
- + p1 + "," + p2 + "," + p3);
-
- send(rr);
- }
-
- public void
- getCLIR(Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_GET_CLIR, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- setCLIR(int clirMode, Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SET_CLIR, result);
-
- // count ints
- rr.mp.writeInt(1);
-
- rr.mp.writeInt(clirMode);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " " + clirMode);
-
- send(rr);
- }
-
- public void
- queryCallWaiting(int serviceClass, Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_QUERY_CALL_WAITING, response);
-
- rr.mp.writeInt(1);
- rr.mp.writeInt(serviceClass);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " " + serviceClass);
-
- send(rr);
- }
-
- public void
- setCallWaiting(boolean enable, int serviceClass, Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SET_CALL_WAITING, response);
-
- rr.mp.writeInt(2);
- rr.mp.writeInt(enable ? 1 : 0);
- rr.mp.writeInt(serviceClass);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " " + enable + ", " + serviceClass);
-
- send(rr);
- }
-
- public void
- setNetworkSelectionModeAutomatic(Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC,
- response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- setNetworkSelectionModeManual(String operatorNumeric, Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL,
- response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " " + operatorNumeric);
-
- rr.mp.writeString(operatorNumeric);
-
- send(rr);
- }
-
- public void
- getNetworkSelectionMode(Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE,
- response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- getAvailableNetworks(Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_NETWORKS,
- response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- setCallForward(int action, int cfReason, int serviceClass,
- String number, int timeSeconds, Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SET_CALL_FORWARD, response);
-
- rr.mp.writeInt(action);
- rr.mp.writeInt(cfReason);
- rr.mp.writeInt(serviceClass);
- rr.mp.writeInt(PhoneNumberUtils.toaFromString(number));
- rr.mp.writeString(number);
- rr.mp.writeInt (timeSeconds);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " " + action + " " + cfReason + " " + serviceClass
- + timeSeconds);
-
- send(rr);
- }
-
- public void
- queryCallForwardStatus(int cfReason, int serviceClass,
- String number, Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_QUERY_CALL_FORWARD_STATUS, response);
-
- rr.mp.writeInt(2); // 2 is for query action, not in used anyway
- rr.mp.writeInt(cfReason);
- rr.mp.writeInt(serviceClass);
- rr.mp.writeInt(PhoneNumberUtils.toaFromString(number));
- rr.mp.writeString(number);
- rr.mp.writeInt (0);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " " + cfReason + " " + serviceClass);
-
- send(rr);
- }
-
- public void
- queryCLIP(Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_QUERY_CLIP, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
-
- public void
- getBasebandVersion (Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_BASEBAND_VERSION, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void
- queryFacilityLock (String facility, String password, int serviceClass,
- Message response)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_QUERY_FACILITY_LOCK, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- // count strings
- rr.mp.writeInt(3);
-
- rr.mp.writeString(facility);
- rr.mp.writeString(password);
-
- rr.mp.writeString(Integer.toString(serviceClass));
-
- send(rr);
- }
-
- public void
- setFacilityLock (String facility, boolean lockState, String password,
- int serviceClass, Message response)
- {
- String lockString;
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SET_FACILITY_LOCK, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- // count strings
- rr.mp.writeInt(4);
-
- rr.mp.writeString(facility);
- lockString = (lockState)?"1":"0";
- rr.mp.writeString(lockString);
- rr.mp.writeString(password);
- rr.mp.writeString(Integer.toString(serviceClass));
-
- send(rr);
-
- }
-
- public void
- sendUSSD (String ussdString, Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SEND_USSD, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " " + ussdString);
-
- rr.mp.writeString(ussdString);
-
- send(rr);
- }
-
- // inherited javadoc suffices
- public void cancelPendingUssd (Message response) {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_CANCEL_USSD, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString()
- + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
-
- public void resetRadio(Message result)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_RESET_RADIO, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- public void invokeOemRilRequestRaw(byte[] data, Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_RAW, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + "[" + SimUtils.bytesToHexString(data) + "]");
-
- rr.mp.writeByteArray(data);
-
- send(rr);
-
- }
-
- public void invokeOemRilRequestStrings(String[] strings, Message response)
- {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_OEM_HOOK_STRINGS, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeStringArray(strings);
-
- send(rr);
- }
-
- /**
- * Assign a specified band for RF configuration.
- *
- * @param bandMode one of BM_*_BAND
- * @param response is callback message
- */
- public void setBandMode (int bandMode, Message response) {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_SET_BAND_MODE, response);
-
- rr.mp.writeInt(1);
- rr.mp.writeInt(bandMode);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " " + bandMode);
-
- send(rr);
- }
-
- /**
- * 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
- */
- public void queryAvailableBandMode (Message response) {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE,
- response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- /**
- * {@inheritDoc}
- */
- public void sendTerminalResponse(String contents, Message response) {
- RILRequest rr = RILRequest.obtain(
- RILConstants.RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeString(contents);
- send(rr);
- }
-
- /**
- * {@inheritDoc}
- */
- public void sendEnvelope(String contents, Message response) {
- RILRequest rr = RILRequest.obtain(
- RILConstants.RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- rr.mp.writeString(contents);
- send(rr);
- }
-
- /**
- * {@inheritDoc}
- */
- public void handleCallSetupRequestFromSim(
- boolean accept, Message response) {
-
- RILRequest rr = RILRequest.obtain(
- RILConstants.RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM,
- response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- int[] param = new int[1];
- param[0] = accept ? 1 : 0;
- rr.mp.writeIntArray(param);
- send(rr);
- }
-
- /**
- * {@inheritDoc}
- */
- public void setPreferredNetworkType(int networkType , Message response) {
- RILRequest rr = RILRequest.obtain(
- RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, response);
-
- rr.mp.writeInt(1);
- rr.mp.writeInt(networkType);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " : " + networkType);
-
- send(rr);
- }
-
- /**
- * {@inheritDoc}
- */
- public void getPreferredNetworkType(Message response) {
- RILRequest rr = RILRequest.obtain(
- RILConstants.RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- /**
- * {@inheritDoc}
- */
- public void getNeighboringCids(Message response) {
- RILRequest rr = RILRequest.obtain(
- RILConstants.RIL_REQUEST_GET_NEIGHBORING_CELL_IDS, response);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
- /**
- * {@inheritDoc}
- */
- public void setLocationUpdates(boolean enable, Message response) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_LOCATION_UPDATES, response);
- rr.mp.writeInt(1);
- rr.mp.writeInt(enable ? 1 : 0);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> "
- + requestToString(rr.mRequest) + ": " + enable);
-
- send(rr);
- }
-
- //***** Private Methods
-
- private void sendScreenState(boolean on)
- {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_SCREEN_STATE, null);
- rr.mp.writeInt(1);
- rr.mp.writeInt(on ? 1 : 0);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + ": " + on);
-
- send(rr);
- }
-
- protected void
- onRadioAvailable()
- {
- // In case screen state was lost (due to process crash),
- // this ensures that the RIL knows the correct screen state.
-
- // TODO: Should query Power Manager and send the actual
- // screen state. Just send true for now.
- sendScreenState(true);
- }
-
- private void setRadioStateFromRILInt(int state) {
- RadioState newState;
-
- /* RIL_RadioState ril.h */
- switch(state) {
- case 0: newState = RadioState.RADIO_OFF; break;
- case 1: newState = RadioState.RADIO_UNAVAILABLE; break;
- case 2: newState = RadioState.SIM_NOT_READY; break;
- case 3: newState = RadioState.SIM_LOCKED_OR_ABSENT; break;
- case 4: newState = RadioState.SIM_READY; break;
- default:
- throw new RuntimeException(
- "Unrecognized RIL_RadioState: " +state);
- }
-
- if (mInitialRadioStateChange) {
- mInitialRadioStateChange = false;
- if (newState.isOn()) {
- /* If this is our first notification, make sure the radio
- * is powered off. This gets the radio into a known state,
- * since it's possible for the phone proc to have restarted
- * (eg, if it or the runtime crashed) without the RIL
- * and/or radio knowing.
- */
- if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF");
- setRadioPower(false, null);
- return;
- }
- }
-
- setRadioState(newState);
- }
-
- /**
- * Holds a PARTIAL_WAKE_LOCK whenever
- * a) There is outstanding RIL request sent to RIL deamon and no replied
- * b) There is a request waiting to be sent out.
- *
- * There is a WAKE_LOCK_TIMEOUT to release the lock, though it shouldn't
- * happen often.
- */
-
- private void
- acquireWakeLock()
- {
- synchronized (mWakeLock) {
- mWakeLock.acquire();
- mRequestMessagesPending++;
-
- mSender.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
- Message msg = mSender.obtainMessage(EVENT_WAKE_LOCK_TIMEOUT);
- mSender.sendMessageDelayed(msg, WAKE_LOCK_TIMEOUT);
- }
- }
-
- private void
- releaseWakeLockIfDone()
- {
- synchronized (mWakeLock) {
- if (mWakeLock.isHeld() &&
- (mRequestMessagesPending == 0) &&
- (mRequestsList.size() == 0)) {
- mSender.removeMessages(EVENT_WAKE_LOCK_TIMEOUT);
- mWakeLock.release();
- }
- }
- }
-
- private void
- send(RILRequest rr)
- {
- Message msg;
-
- msg = mSender.obtainMessage(EVENT_SEND, rr);
-
- acquireWakeLock();
-
- msg.sendToTarget();
- }
-
- private void
- processResponse (Parcel p)
- {
- int type;
-
- type = p.readInt();
-
- if (type == RESPONSE_UNSOLICITED) {
- processUnsolicited (p);
- } else if (type == RESPONSE_SOLICITED) {
- processSolicited (p);
- }
-
- releaseWakeLockIfDone();
- }
-
-
-
- private RILRequest findAndRemoveRequestFromList(int serial)
- {
- synchronized (mRequestsList) {
- for (int i = 0, s = mRequestsList.size() ; i < s ; i++) {
- RILRequest rr = mRequestsList.get(i);
-
- if (rr.mSerial == serial) {
- mRequestsList.remove(i);
- return rr;
- }
- }
- }
-
- return null;
- }
-
- private void
- processSolicited (Parcel p)
- {
- int serial, error;
- boolean found = false;
-
- serial = p.readInt();
- error = p.readInt();
-
- RILRequest rr;
-
- rr = findAndRemoveRequestFromList(serial);
-
- if (rr == null) {
- Log.w(LOG_TAG, "Unexpected solicited response! sn: "
- + serial + " error: " + error);
- return;
- }
-
- if (error != 0) {
- rr.onError(error);
- rr.release();
- return;
- }
-
- Object ret;
-
- try {switch (rr.mRequest) {
-/*
- cat libs/telephony/ril_commands.h \
- | egrep "^ *{RIL_" \
- | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/'
-*/
- case RIL_REQUEST_GET_SIM_STATUS: ret = responseSimStatus(p); break;
- case RIL_REQUEST_ENTER_SIM_PIN: ret = responseVoid(p); break;
- case RIL_REQUEST_ENTER_SIM_PUK: ret = responseVoid(p); break;
- case RIL_REQUEST_ENTER_SIM_PIN2: ret = responseVoid(p); break;
- case RIL_REQUEST_ENTER_SIM_PUK2: ret = responseVoid(p); break;
- case RIL_REQUEST_CHANGE_SIM_PIN: ret = responseVoid(p); break;
- case RIL_REQUEST_CHANGE_SIM_PIN2: ret = responseVoid(p); break;
- case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: ret = responseVoid(p); break;
- case RIL_REQUEST_GET_CURRENT_CALLS: ret = responseCallList(p); break;
- case RIL_REQUEST_DIAL: ret = responseVoid(p); break;
- case RIL_REQUEST_GET_IMSI: ret = responseString(p); break;
- case RIL_REQUEST_HANGUP: ret = responseVoid(p); break;
- case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: ret = responseVoid(p); break;
- case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: ret = responseVoid(p); break;
- case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: ret = responseVoid(p); break;
- case RIL_REQUEST_CONFERENCE: ret = responseVoid(p); break;
- case RIL_REQUEST_UDUB: ret = responseVoid(p); break;
- case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: ret = responseInts(p); break;
- case RIL_REQUEST_SIGNAL_STRENGTH: ret = responseInts(p); break;
- case RIL_REQUEST_REGISTRATION_STATE: ret = responseStrings(p); break;
- case RIL_REQUEST_GPRS_REGISTRATION_STATE: ret = responseStrings(p); break;
- case RIL_REQUEST_OPERATOR: ret = responseStrings(p); break;
- case RIL_REQUEST_RADIO_POWER: ret = responseVoid(p); break;
- case RIL_REQUEST_DTMF: ret = responseVoid(p); break;
- case RIL_REQUEST_SEND_SMS: ret = responseSMS(p); break;
- case RIL_REQUEST_SEND_SMS_EXPECT_MORE: ret = responseSMS(p); break;
- case RIL_REQUEST_SETUP_DEFAULT_PDP: ret = responseStrings(p); break;
- case RIL_REQUEST_SIM_IO: ret = responseSIM_IO(p); break;
- case RIL_REQUEST_SEND_USSD: ret = responseVoid(p); break;
- case RIL_REQUEST_CANCEL_USSD: ret = responseVoid(p); break;
- case RIL_REQUEST_GET_CLIR: ret = responseInts(p); break;
- case RIL_REQUEST_SET_CLIR: ret = responseVoid(p); break;
- case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: ret = responseCallForward(p); break;
- case RIL_REQUEST_SET_CALL_FORWARD: ret = responseVoid(p); break;
- case RIL_REQUEST_QUERY_CALL_WAITING: ret = responseInts(p); break;
- case RIL_REQUEST_SET_CALL_WAITING: ret = responseVoid(p); break;
- case RIL_REQUEST_SMS_ACKNOWLEDGE: ret = responseVoid(p); break;
- case RIL_REQUEST_GET_IMEI: ret = responseString(p); break;
- case RIL_REQUEST_GET_IMEISV: ret = responseString(p); break;
- case RIL_REQUEST_ANSWER: ret = responseVoid(p); break;
- case RIL_REQUEST_DEACTIVATE_DEFAULT_PDP: ret = responseVoid(p); break;
- case RIL_REQUEST_QUERY_FACILITY_LOCK: ret = responseInts(p); break;
- case RIL_REQUEST_SET_FACILITY_LOCK: ret = responseVoid(p); break;
- case RIL_REQUEST_CHANGE_BARRING_PASSWORD: ret = responseVoid(p); break;
- case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: ret = responseInts(p); break;
- case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: ret = responseVoid(p); break;
- case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: ret = responseVoid(p); break;
- case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS : ret = responseNetworkInfos(p); break;
- case RIL_REQUEST_DTMF_START: ret = responseVoid(p); break;
- case RIL_REQUEST_DTMF_STOP: ret = responseVoid(p); break;
- case RIL_REQUEST_BASEBAND_VERSION: ret = responseString(p); break;
- case RIL_REQUEST_SEPARATE_CONNECTION: ret = responseVoid(p); break;
- case RIL_REQUEST_SET_MUTE: ret =responseVoid(p); break;
- case RIL_REQUEST_GET_MUTE: ret = responseInts(p); break;
- case RIL_REQUEST_QUERY_CLIP: ret = responseInts(p); break;
- case RIL_REQUEST_LAST_PDP_FAIL_CAUSE: ret = responseInts(p); break;
- case RIL_REQUEST_PDP_CONTEXT_LIST: ret = responseContextList(p); break;
- case RIL_REQUEST_RESET_RADIO: ret = responseVoid(p); break;
- case RIL_REQUEST_OEM_HOOK_RAW: ret = responseRaw(p); break;
- case RIL_REQUEST_OEM_HOOK_STRINGS: ret = responseStrings(p); break;
- case RIL_REQUEST_SCREEN_STATE: ret = responseVoid(p); break;
- case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: ret = responseVoid(p); break;
- case RIL_REQUEST_WRITE_SMS_TO_SIM: ret = responseInts(p); break;
- case RIL_REQUEST_DELETE_SMS_ON_SIM: ret = responseVoid(p); break;
- case RIL_REQUEST_SET_BAND_MODE: ret = responseVoid(p); break;
- case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: ret = responseInts(p); break;
- case RIL_REQUEST_STK_GET_PROFILE: ret = responseString(p); break;
- case RIL_REQUEST_STK_SET_PROFILE: ret = responseVoid(p); break;
- case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: ret = responseString(p); break;
- case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: ret = responseVoid(p); break;
- case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: ret = responseInts(p); break;
- case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: ret = responseVoid(p); break;
- case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: ret = responseVoid(p); break;
- case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: ret = responseInts(p); break;
- case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: ret = responseCellList(p); break;
- case RIL_REQUEST_SET_LOCATION_UPDATES: ret = responseVoid(p); break;
-
- default:
- throw new RuntimeException("Unrecognized solicited response: " + rr.mRequest);
- //break;
- }} catch (Throwable tr) {
- // Exceptions here usually mean invalid RIL responses
-
- Log.w(LOG_TAG, rr.serialString() + "< "
- + requestToString(rr.mRequest) + " exception, possible invalid RIL response", tr);
-
- if (rr.mResult != null) {
- AsyncResult.forMessage(rr.mResult, null, tr);
- rr.mResult.sendToTarget();
- }
- rr.release();
- return;
- }
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest)
- + " " + retToString(rr.mRequest, ret));
-
- if (rr.mResult != null) {
- AsyncResult.forMessage(rr.mResult, ret, null);
- rr.mResult.sendToTarget();
- }
-
- rr.release();
- }
-
- private String
- retToString(int req, Object ret)
- {
- if (ret == null) return "";
- switch (req) {
- // Don't log these return values, for privacy's sake.
- case RIL_REQUEST_GET_IMSI:
- case RIL_REQUEST_GET_IMEI:
- case RIL_REQUEST_GET_IMEISV:
- return "";
- }
-
- StringBuilder sb;
- String s;
- int length;
- if (ret instanceof int[]){
- int[] intArray = (int[]) ret;
- length = intArray.length;
- sb = new StringBuilder("{");
- if (length > 0) {
- int i = 0;
- sb.append(intArray[i++]);
- while ( i < length) {
- sb.append(", ").append(intArray[i++]);
- }
- }
- sb.append("}");
- s = sb.toString();
- } else if (ret instanceof String[]) {
- String[] strings = (String[]) ret;
- length = strings.length;
- sb = new StringBuilder("{");
- if (length > 0) {
- int i = 0;
- sb.append(strings[i++]);
- while ( i < length) {
- sb.append(", ").append(strings[i++]);
- }
- }
- sb.append("}");
- s = sb.toString();
- }else if (req == RIL_REQUEST_GET_CURRENT_CALLS) {
- ArrayList calls = (ArrayList) ret;
- sb = new StringBuilder(" ");
- for (DriverCall dc : calls) {
- sb.append("[").append(dc).append("] ");
- }
- s = sb.toString();
- } else if (req == RIL_REQUEST_GET_NEIGHBORING_CELL_IDS) {
- ArrayList cells;
- cells = (ArrayList) ret;
- sb = new StringBuilder(" ");
- for (NeighboringCellInfo cell : cells) {
- sb.append(cell).append(" ");
- }
- s = sb.toString();
- } else {
- s = ret.toString();
- }
- return s;
- }
-
- private void
- processUnsolicited (Parcel p)
- {
- int response;
- Object ret;
-
- response = p.readInt();
-
- try {switch(response) {
-/*
- cat libs/telephony/ril_unsol_commands.h \
- | egrep "^ *{RIL_" \
- | sed -re 's/\{([^,]+),[^,]+,([^}]+).+/case \1: \2(rr, p); break;/'
-*/
-
- case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: ret = responseVoid(p); break;
- case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: ret = responseVoid(p); break;
- case RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED: ret = responseVoid(p); break;
- case RIL_UNSOL_RESPONSE_NEW_SMS: ret = responseString(p); break;
- case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: ret = responseString(p); break;
- case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: ret = responseInts(p); break;
- case RIL_UNSOL_ON_USSD: ret = responseStrings(p); break;
- case RIL_UNSOL_NITZ_TIME_RECEIVED: ret = responseString(p); break;
- case RIL_UNSOL_SIGNAL_STRENGTH: ret = responseInts(p); break;
- case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED: ret = responseContextList(p);break;
- case RIL_UNSOL_SUPP_SVC_NOTIFICATION: ret = responseSuppServiceNotification(p); break;
- case RIL_UNSOL_STK_SESSION_END: ret = responseVoid(p); break;
- case RIL_UNSOL_STK_PROACTIVE_COMMAND: ret = responseString(p); break;
- case RIL_UNSOL_STK_EVENT_NOTIFY: ret = responseString(p); break;
- case RIL_UNSOL_STK_CALL_SETUP: ret = responseInts(p); break;
- case RIL_UNSOL_SIM_SMS_STORAGE_FULL: ret = responseVoid(p); break;
- case RIL_UNSOL_SIM_REFRESH: ret = responseInts(p); break;
- case RIL_UNSOL_CALL_RING: ret = responseVoid(p); break;
- case RIL_UNSOL_RESTRICTED_STATE_CHANGED: ret = responseInts(p); break;
- default:
- throw new RuntimeException("Unrecognized unsol response: " + response);
- //break; (implied)
- }} catch (Throwable tr) {
- Log.e(LOG_TAG, "Exception processing unsol response: " + response +
- "Exception:" + tr.toString());
- return;
- }
-
- switch(response) {
- case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED:
- /* has bonus radio state int */
- setRadioStateFromRILInt(p.readInt());
-
- if (RILJ_LOGD) unsljLogMore(response, mState.toString());
- break;
- case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED:
- if (RILJ_LOGD) unsljLog(response);
-
- mCallStateRegistrants
- .notifyRegistrants(new AsyncResult(null, null, null));
- break;
- case RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED:
- if (RILJ_LOGD) unsljLog(response);
-
- mNetworkStateRegistrants
- .notifyRegistrants(new AsyncResult(null, null, null));
- break;
- case RIL_UNSOL_RESPONSE_NEW_SMS: {
- if (RILJ_LOGD) unsljLog(response);
-
- // FIXME this should move up a layer
- String a[] = new String[2];
-
- a[1] = (String)ret;
-
- SmsMessage sms;
-
- sms = SmsMessage.newFromCMT(a);
- if (mSMSRegistrant != null) {
- mSMSRegistrant
- .notifyRegistrant(new AsyncResult(null, sms, null));
- }
- break;
- }
- case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT:
- if (RILJ_LOGD) unsljLogRet(response, ret);
-
- if (mSmsStatusRegistrant != null) {
- mSmsStatusRegistrant.notifyRegistrant(
- new AsyncResult(null, ret, null));
- }
- break;
- case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM:
- if (RILJ_LOGD) unsljLogRet(response, ret);
-
- int[] smsIndex = (int[])ret;
-
- if(smsIndex.length == 1) {
- if (mSmsOnSimRegistrant != null) {
- mSmsOnSimRegistrant.
- notifyRegistrant(new AsyncResult(null, smsIndex, null));
- }
- } else {
- if (RILJ_LOGD) riljLog(" NEW_SMS_ON_SIM ERROR with wrong length "
- + smsIndex.length);
- }
- break;
- case RIL_UNSOL_ON_USSD:
- String[] resp = (String[])ret;
-
- if (resp.length < 2) {
- resp = new String[2];
- resp[0] = ((String[])ret)[0];
- resp[1] = null;
- }
- if (RILJ_LOGD) unsljLogMore(response, resp[0]);
- if (mUSSDRegistrant != null) {
- mUSSDRegistrant.notifyRegistrant(
- new AsyncResult (null, resp, null));
- }
- break;
- case RIL_UNSOL_NITZ_TIME_RECEIVED:
- if (RILJ_LOGD) unsljLogRet(response, ret);
-
- // has bonus long containing milliseconds since boot that the NITZ
- // time was received
- long nitzReceiveTime = p.readLong();
-
- Object[] result = new Object[2];
-
- result[0] = ret;
- result[1] = Long.valueOf(nitzReceiveTime);
-
- if (mNITZTimeRegistrant != null) {
-
- mNITZTimeRegistrant
- .notifyRegistrant(new AsyncResult (null, result, null));
- } else {
- // in case NITZ time registrant isnt registered yet
- mLastNITZTimeInfo = result;
- }
- break;
-
- case RIL_UNSOL_SIGNAL_STRENGTH:
- // Note this is set to "verbose" because it happens
- // frequently
- if (RILJ_LOGV) unsljLogvRet(response, ret);
-
- if (mSignalStrengthRegistrant != null) {
- mSignalStrengthRegistrant.notifyRegistrant(
- new AsyncResult (null, ret, null));
- }
- break;
- case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED:
- if (RILJ_LOGD) unsljLogRet(response, ret);
-
- mPDPRegistrants
- .notifyRegistrants(new AsyncResult(null, ret, null));
- break;
-
- case RIL_UNSOL_SUPP_SVC_NOTIFICATION:
- if (RILJ_LOGD) unsljLogRet(response, ret);
-
- if (mSsnRegistrant != null) {
- mSsnRegistrant.notifyRegistrant(
- new AsyncResult (null, ret, null));
- }
- break;
-
- case RIL_UNSOL_STK_SESSION_END:
- if (RILJ_LOGD) unsljLog(response);
-
- if (mStkSessionEndRegistrant != null) {
- mStkSessionEndRegistrant.notifyRegistrant(
- new AsyncResult (null, ret, null));
- }
- break;
-
- case RIL_UNSOL_STK_PROACTIVE_COMMAND:
- if (RILJ_LOGD) unsljLogRet(response, ret);
-
- if (mStkProCmdRegistrant != null) {
- mStkProCmdRegistrant.notifyRegistrant(
- new AsyncResult (null, ret, null));
- }
- break;
-
- case RIL_UNSOL_STK_EVENT_NOTIFY:
- if (RILJ_LOGD) unsljLogRet(response, ret);
-
- if (mStkEventRegistrant != null) {
- mStkEventRegistrant.notifyRegistrant(
- new AsyncResult (null, ret, null));
- }
- break;
-
- case RIL_UNSOL_STK_CALL_SETUP:
- if (RILJ_LOGD) unsljLogRet(response, ret);
-
- if (mStkCallSetUpRegistrant != null) {
- mStkCallSetUpRegistrant.notifyRegistrant(
- new AsyncResult (null, ret, null));
- }
- break;
-
- case RIL_UNSOL_SIM_SMS_STORAGE_FULL:
- if (RILJ_LOGD) unsljLog(response);
-
- if (mSimSmsFullRegistrant != null) {
- mSimSmsFullRegistrant.notifyRegistrant();
- }
- break;
-
- case RIL_UNSOL_SIM_REFRESH:
- if (RILJ_LOGD) unsljLogRet(response, ret);
-
- if (mSimRefreshRegistrant != null) {
- mSimRefreshRegistrant.notifyRegistrant(
- new AsyncResult (null, ret, null));
- }
- break;
-
- case RIL_UNSOL_CALL_RING:
- if (RILJ_LOGD) unsljLog(response);
-
- if (mRingRegistrant != null) {
- mRingRegistrant.notifyRegistrant();
- }
- break;
-
- case RIL_UNSOL_RESTRICTED_STATE_CHANGED:
- if (RILJ_LOGD) unsljLogvRet(response, ret);
- if (mRestrictedStateRegistrant != null) {
- mRestrictedStateRegistrant.notifyRegistrant(
- new AsyncResult (null, ret, null));
- }
- }
- }
-
- private Object
- responseInts(Parcel p)
- {
- int numInts;
- int response[];
-
- numInts = p.readInt();
-
- response = new int[numInts];
-
- for (int i = 0 ; i < numInts ; i++) {
- response[i] = p.readInt();
- }
-
- return response;
- }
-
-
- private Object
- responseVoid(Parcel p)
- {
- return null;
- }
-
- private Object
- responseCallForward(Parcel p)
- {
- int numInfos;
- CallForwardInfo infos[];
-
- numInfos = p.readInt();
-
- infos = new CallForwardInfo[numInfos];
-
- for (int i = 0 ; i < numInfos ; i++) {
- infos[i] = new CallForwardInfo();
-
- infos[i].status = p.readInt();
- infos[i].reason = p.readInt();
- infos[i].serviceClass = p.readInt();
- infos[i].toa = p.readInt();
- infos[i].number = p.readString();
- infos[i].timeSeconds = p.readInt();
- }
-
- return infos;
- }
-
- private Object
- responseSuppServiceNotification(Parcel p)
- {
- SuppServiceNotification notification = new SuppServiceNotification();
-
- notification.notificationType = p.readInt();
- notification.code = p.readInt();
- notification.index = p.readInt();
- notification.type = p.readInt();
- notification.number = p.readString();
-
- return notification;
- }
-
- private Object
- responseString(Parcel p)
- {
- String response;
-
- response = p.readString();
-
- return response;
- }
-
- private Object
- responseStrings(Parcel p)
- {
- int num;
- String response[];
-
- response = p.readStringArray();
-
- if (false) {
- num = p.readInt();
-
- response = new String[num];
- for (int i = 0; i < num; i++) {
- response[i] = p.readString();
- }
- }
-
- return response;
- }
-
- private Object
- responseRaw(Parcel p)
- {
- int num;
- byte response[];
-
- response = p.createByteArray();
-
- return response;
- }
-
- private Object
- responseSMS(Parcel p)
- {
- int messageRef;
- String ackPDU;
-
- messageRef = p.readInt();
- ackPDU = p.readString();
-
- SmsResponse response = new SmsResponse(messageRef, ackPDU);
-
- return response;
- }
-
-
- private Object
- responseSIM_IO(Parcel p)
- {
- int sw1, sw2;
- byte data[] = null;
- Message ret;
-
- sw1 = p.readInt();
- sw2 = p.readInt();
-
- String s = p.readString();
-
- return new SimIoResult(sw1, sw2, s);
- }
-
- private Object
- responseSimStatus(Parcel p)
- {
- int status;
-
- status = ((int[])responseInts(p))[0];
- switch (status){
- case RIL_SIM_ABSENT: return SimStatus.SIM_ABSENT;
- case RIL_SIM_NOT_READY: return SimStatus.SIM_NOT_READY;
- case RIL_SIM_READY: return SimStatus.SIM_READY;
- case RIL_SIM_PIN: return SimStatus.SIM_PIN;
- case RIL_SIM_PUK: return SimStatus.SIM_PUK;
- case RIL_SIM_NETWORK_PERSONALIZATION:
- return SimStatus.SIM_NETWORK_PERSONALIZATION;
- default:
- // Unrecognized SIM status. Treat it like a missing SIM.
- Log.e(LOG_TAG, "Unrecognized RIL_REQUEST_GET_SIM_STATUS result: " + status);
- return SimStatus.SIM_ABSENT;
- }
- }
-
-
- private Object
- responseCallList(Parcel p)
- {
- int num;
- ArrayList response;
- DriverCall dc;
-
- num = p.readInt();
- response = new ArrayList(num);
-
- for (int i = 0 ; i < num ; i++) {
- dc = new DriverCall();
-
- dc.state = DriverCall.stateFromCLCC(p.readInt());
- dc.index = p.readInt();
- dc.TOA = p.readInt();
- dc.isMpty = (0 != p.readInt());
- dc.isMT = (0 != p.readInt());
- dc.als = p.readInt();
- dc.isVoice = (0 == p.readInt()) ? false : true;
- dc.number = p.readString();
- dc.numberPresentation = DriverCall.presentationFromCLIP(p.readInt());
-
- // Make sure there's a leading + on addresses with a TOA
- // of 145
-
- dc.number = PhoneNumberUtils.stringFromStringAndTOA(
- dc.number, dc.TOA);
-
- response.add(dc);
- }
-
- Collections.sort(response);
-
- return response;
- }
-
- private Object
- responseContextList(Parcel p)
- {
- int num;
- ArrayList response;
-
- num = p.readInt();
- response = new ArrayList(num);
-
- for (int i = 0; i < num; i++) {
- PDPContextState pdp = new PDPContextState();
-
- pdp.cid = p.readInt();
- pdp.active = p.readInt() == 0 ? false : true;
- pdp.type = p.readString();
- pdp.apn = p.readString();
- pdp.address = p.readString();
-
- response.add(pdp);
- }
-
- return response;
- }
-
- private Object
- responseNetworkInfos(Parcel p)
- {
- String strings[] = (String [])responseStrings(p);
- ArrayList ret;
-
- if (strings.length % 4 != 0) {
- throw new RuntimeException(
- "RIL_REQUEST_QUERY_AVAILABLE_NETWORKS: invalid response. Got "
- + strings.length + " strings, expected multible of 4");
- }
-
- ret = new ArrayList(strings.length / 4);
-
- for (int i = 0 ; i < strings.length ; i += 4) {
- ret.add (
- new NetworkInfo(
- strings[i+0],
- strings[i+1],
- strings[i+2],
- strings[i+3]));
- }
-
- return ret;
- }
-
- private Object
- responseCellList(Parcel p)
- {
- int num;
- ArrayList response;
- NeighboringCellInfo cell;
-
- num = p.readInt();
- response = new ArrayList(num);
-
- for (int i = 0 ; i < num ; i++) {
- try {
- int rssi = p.readInt();
- int cid = Integer.valueOf(p.readString(), 16);
- cell = new NeighboringCellInfo(rssi, cid);
- response.add(cell);
- } catch ( Exception e) {
- }
- }
-
- return response;
- }
-
-
- static String
- requestToString(int request)
- {
-/*
- cat libs/telephony/ril_commands.h \
- | egrep "^ *{RIL_" \
- | sed -re 's/\{RIL_([^,]+),[^,]+,([^}]+).+/case RIL_\1: return "\1";/'
-*/
- switch(request) {
- case RIL_REQUEST_GET_SIM_STATUS: return "GET_SIM_STATUS";
- case RIL_REQUEST_ENTER_SIM_PIN: return "ENTER_SIM_PIN";
- case RIL_REQUEST_ENTER_SIM_PUK: return "ENTER_SIM_PUK";
- case RIL_REQUEST_ENTER_SIM_PIN2: return "ENTER_SIM_PIN2";
- case RIL_REQUEST_ENTER_SIM_PUK2: return "ENTER_SIM_PUK2";
- case RIL_REQUEST_CHANGE_SIM_PIN: return "CHANGE_SIM_PIN";
- case RIL_REQUEST_CHANGE_SIM_PIN2: return "CHANGE_SIM_PIN2";
- case RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION: return "ENTER_NETWORK_DEPERSONALIZATION";
- case RIL_REQUEST_GET_CURRENT_CALLS: return "GET_CURRENT_CALLS";
- case RIL_REQUEST_DIAL: return "DIAL";
- case RIL_REQUEST_GET_IMSI: return "GET_IMSI";
- case RIL_REQUEST_HANGUP: return "HANGUP";
- case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND: return "HANGUP_WAITING_OR_BACKGROUND";
- case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND: return "HANGUP_FOREGROUND_RESUME_BACKGROUND";
- case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE: return "REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE";
- case RIL_REQUEST_CONFERENCE: return "CONFERENCE";
- case RIL_REQUEST_UDUB: return "UDUB";
- case RIL_REQUEST_LAST_CALL_FAIL_CAUSE: return "LAST_CALL_FAIL_CAUSE";
- case RIL_REQUEST_SIGNAL_STRENGTH: return "SIGNAL_STRENGTH";
- case RIL_REQUEST_REGISTRATION_STATE: return "REGISTRATION_STATE";
- case RIL_REQUEST_GPRS_REGISTRATION_STATE: return "GPRS_REGISTRATION_STATE";
- case RIL_REQUEST_OPERATOR: return "OPERATOR";
- case RIL_REQUEST_RADIO_POWER: return "RADIO_POWER";
- case RIL_REQUEST_DTMF: return "DTMF";
- case RIL_REQUEST_SEND_SMS: return "SEND_SMS";
- case RIL_REQUEST_SEND_SMS_EXPECT_MORE: return "SEND_SMS_EXPECT_MORE";
- case RIL_REQUEST_SETUP_DEFAULT_PDP: return "SETUP_DEFAULT_PDP";
- case RIL_REQUEST_SIM_IO: return "SIM_IO";
- case RIL_REQUEST_SEND_USSD: return "SEND_USSD";
- case RIL_REQUEST_CANCEL_USSD: return "CANCEL_USSD";
- case RIL_REQUEST_GET_CLIR: return "GET_CLIR";
- case RIL_REQUEST_SET_CLIR: return "SET_CLIR";
- case RIL_REQUEST_QUERY_CALL_FORWARD_STATUS: return "QUERY_CALL_FORWARD_STATUS";
- case RIL_REQUEST_SET_CALL_FORWARD: return "SET_CALL_FORWARD";
- case RIL_REQUEST_QUERY_CALL_WAITING: return "QUERY_CALL_WAITING";
- case RIL_REQUEST_SET_CALL_WAITING: return "SET_CALL_WAITING";
- case RIL_REQUEST_SMS_ACKNOWLEDGE: return "SMS_ACKNOWLEDGE";
- case RIL_REQUEST_GET_IMEI: return "GET_IMEI";
- case RIL_REQUEST_GET_IMEISV: return "GET_IMEISV";
- case RIL_REQUEST_ANSWER: return "ANSWER";
- case RIL_REQUEST_DEACTIVATE_DEFAULT_PDP: return "DEACTIVATE_DEFAULT_PDP";
- case RIL_REQUEST_QUERY_FACILITY_LOCK: return "QUERY_FACILITY_LOCK";
- case RIL_REQUEST_SET_FACILITY_LOCK: return "SET_FACILITY_LOCK";
- case RIL_REQUEST_CHANGE_BARRING_PASSWORD: return "CHANGE_BARRING_PASSWORD";
- case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE: return "QUERY_NETWORK_SELECTION_MODE";
- case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC: return "SET_NETWORK_SELECTION_AUTOMATIC";
- case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL: return "SET_NETWORK_SELECTION_MANUAL";
- case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS : return "QUERY_AVAILABLE_NETWORKS ";
- case RIL_REQUEST_DTMF_START: return "DTMF_START";
- case RIL_REQUEST_DTMF_STOP: return "DTMF_STOP";
- case RIL_REQUEST_BASEBAND_VERSION: return "BASEBAND_VERSION";
- case RIL_REQUEST_SEPARATE_CONNECTION: return "SEPARATE_CONNECTION";
- case RIL_REQUEST_SET_MUTE: return "SET_MUTE";
- case RIL_REQUEST_GET_MUTE: return "GET_MUTE";
- case RIL_REQUEST_QUERY_CLIP: return "QUERY_CLIP";
- case RIL_REQUEST_LAST_PDP_FAIL_CAUSE: return "LAST_PDP_FAIL_CAUSE";
- case RIL_REQUEST_PDP_CONTEXT_LIST: return "PDP_CONTEXT_LIST";
- case RIL_REQUEST_RESET_RADIO: return "RESET_RADIO";
- case RIL_REQUEST_OEM_HOOK_RAW: return "OEM_HOOK_RAW";
- case RIL_REQUEST_OEM_HOOK_STRINGS: return "OEM_HOOK_STRINGS";
- case RIL_REQUEST_SCREEN_STATE: return "SCREEN_STATE";
- case RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION: return "SET_SUPP_SVC_NOTIFICATION";
- case RIL_REQUEST_WRITE_SMS_TO_SIM: return "WRITE_SMS_TO_SIM";
- case RIL_REQUEST_DELETE_SMS_ON_SIM: return "DELETE_SMS_ON_SIM";
- case RIL_REQUEST_SET_BAND_MODE: return "SET_BAND_MODE";
- case RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE: return "QUERY_AVAILABLE_BAND_MODE";
- case RIL_REQUEST_STK_GET_PROFILE: return "REQUEST_STK_GET_PROFILE";
- case RIL_REQUEST_STK_SET_PROFILE: return "REQUEST_STK_SET_PROFILE";
- case RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND: return "REQUEST_STK_SEND_ENVELOPE_COMMAND";
- case RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE: return "REQUEST_STK_SEND_TERMINAL_RESPONSE";
- case RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM: return "REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM";
- case RIL_REQUEST_EXPLICIT_CALL_TRANSFER: return "REQUEST_EXPLICIT_CALL_TRANSFER";
- case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE: return "REQUEST_SET_PREFERRED_NETWORK_TYPE";
- case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE: return "REQUEST_GET_PREFERRED_NETWORK_TYPE";
- case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS: return "REQUEST_GET_NEIGHBORING_CELL_IDS";
- case RIL_REQUEST_SET_LOCATION_UPDATES: return "REQUEST_SET_LOCATION_UPDATES";
- default: return "";
- }
- }
-
- static String
- responseToString(int request)
- {
-/*
- cat libs/telephony/ril_unsol_commands.h \
- | egrep "^ *{RIL_" \
- | sed -re 's/\{RIL_([^,]+),[^,]+,([^}]+).+/case RIL_\1: return "\1";/'
-*/
- switch(request) {
- case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: return "UNSOL_RESPONSE_RADIO_STATE_CHANGED";
- case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: return "UNSOL_RESPONSE_CALL_STATE_CHANGED";
- case RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED: return "UNSOL_RESPONSE_NETWORK_STATE_CHANGED";
- case RIL_UNSOL_RESPONSE_NEW_SMS: return "UNSOL_RESPONSE_NEW_SMS";
- case RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT: return "UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT";
- case RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM: return "UNSOL_RESPONSE_NEW_SMS_ON_SIM";
- case RIL_UNSOL_ON_USSD: return "UNSOL_ON_USSD";
- case RIL_UNSOL_ON_USSD_REQUEST: return "UNSOL_ON_USSD_REQUEST";
- case RIL_UNSOL_NITZ_TIME_RECEIVED: return "UNSOL_NITZ_TIME_RECEIVED";
- case RIL_UNSOL_SIGNAL_STRENGTH: return "UNSOL_SIGNAL_STRENGTH";
- case RIL_UNSOL_PDP_CONTEXT_LIST_CHANGED: return "UNSOL_PDP_CONTEXT_LIST_CHANGED";
- case RIL_UNSOL_SUPP_SVC_NOTIFICATION: return "UNSOL_SUPP_SVC_NOTIFICATION";
- case RIL_UNSOL_STK_SESSION_END: return "UNSOL_STK_SESSION_END";
- case RIL_UNSOL_STK_PROACTIVE_COMMAND: return "UNSOL_STK_PROACTIVE_COMMAND";
- case RIL_UNSOL_STK_EVENT_NOTIFY: return "UNSOL_STK_EVENT_NOTIFY";
- case RIL_UNSOL_STK_CALL_SETUP: return "UNSOL_STK_CALL_SETUP";
- case RIL_UNSOL_SIM_SMS_STORAGE_FULL: return "UNSOL_SIM_SMS_STORAGE_FULL";
- case RIL_UNSOL_SIM_REFRESH: return "UNSOL_SIM_REFRESH";
- case RIL_UNSOL_CALL_RING: return "UNSOL_CALL_RING";
- case RIL_UNSOL_RESTRICTED_STATE_CHANGED: return "RIL_UNSOL_RESTRICTED_STATE_CHANGED";
- default: return "";
- }
- }
-
- private void riljLog(String msg) {
- Log.d(LOG_TAG, msg);
- }
-
- private void riljLogv(String msg) {
- Log.v(LOG_TAG, msg);
- }
-
- private void unsljLog(int response) {
- riljLog("[UNSL]< " + responseToString(response));
- }
-
- private void unsljLogMore(int response, String more) {
- riljLog("[UNSL]< " + responseToString(response) + " " + more);
- }
-
- private void unsljLogRet(int response, Object ret) {
- riljLog("[UNSL]< " + responseToString(response) + " " + retToString(response, ret));
- }
-
- private void unsljLogvRet(int response, Object ret) {
- riljLogv("[UNSL]< " + responseToString(response) + " " + retToString(response, ret));
- }
-
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/RILConstants.java b/telephony/java/com/android/internal/telephony/gsm/RILConstants.java
deleted file mode 100644
index 4463b20..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/RILConstants.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-
-/**
- * {@hide}
- */
-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 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 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 */
-/*
-cat include/telephony/ril.h | \
- egrep '^#define' | \
- sed -re 's/^#define +([^ ]+)* +([^ ]+)/ int \1 = \2;/' \
- >>java/android/com.android.internal.telephony/gsm/RILConstants.java
-*/
-
-
- int RIL_SIM_ABSENT = 0;
- int RIL_SIM_NOT_READY = 1;
- int RIL_SIM_READY = 2;
- int RIL_SIM_PIN = 3;
- int RIL_SIM_PUK = 4;
- int RIL_SIM_NETWORK_PERSONALIZATION = 5;
-
- /**
- * No restriction at all including voice/SMS/USSD/SS/AV64
- * and packet data.
- */
- int RIL_RESTRICTED_STATE_NONE = 0x00;
- /**
- * Block emergency call due to restriction.
- * But allow all normal voice/SMS/USSD/SS/AV64.
- */
- int RIL_RESTRICTED_STATE_CS_EMERGENCY = 0x01;
- /**
- * Block all normal voice/SMS/USSD/SS/AV64 due to restriction.
- * Only Emergency call allowed.
- */
- int RIL_RESTRICTED_STATE_CS_NORMAL = 0x02;
- /**
- * Block all voice/SMS/USSD/SS/AV64
- * including emergency call due to restriction.
- */
- int RIL_RESTRICTED_STATE_CS_ALL = 0x04;
- /**
- * 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;
- int RIL_REQUEST_ENTER_SIM_PIN2 = 4;
- int RIL_REQUEST_ENTER_SIM_PUK2 = 5;
- int RIL_REQUEST_CHANGE_SIM_PIN = 6;
- int RIL_REQUEST_CHANGE_SIM_PIN2 = 7;
- int RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION = 8;
- int RIL_REQUEST_GET_CURRENT_CALLS = 9;
- int RIL_REQUEST_DIAL = 10;
- int RIL_REQUEST_GET_IMSI = 11;
- int RIL_REQUEST_HANGUP = 12;
- int RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND = 13;
- int RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND = 14;
- int RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE = 15;
- int RIL_REQUEST_CONFERENCE = 16;
- int RIL_REQUEST_UDUB = 17;
- int RIL_REQUEST_LAST_CALL_FAIL_CAUSE = 18;
- int RIL_REQUEST_SIGNAL_STRENGTH = 19;
- int RIL_REQUEST_REGISTRATION_STATE = 20;
- int RIL_REQUEST_GPRS_REGISTRATION_STATE = 21;
- int RIL_REQUEST_OPERATOR = 22;
- int RIL_REQUEST_RADIO_POWER = 23;
- 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_SIM_IO = 28;
- int RIL_REQUEST_SEND_USSD = 29;
- int RIL_REQUEST_CANCEL_USSD = 30;
- int RIL_REQUEST_GET_CLIR = 31;
- int RIL_REQUEST_SET_CLIR = 32;
- int RIL_REQUEST_QUERY_CALL_FORWARD_STATUS = 33;
- int RIL_REQUEST_SET_CALL_FORWARD = 34;
- int RIL_REQUEST_QUERY_CALL_WAITING = 35;
- int RIL_REQUEST_SET_CALL_WAITING = 36;
- int RIL_REQUEST_SMS_ACKNOWLEDGE = 37;
- 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_QUERY_FACILITY_LOCK = 42;
- int RIL_REQUEST_SET_FACILITY_LOCK = 43;
- int RIL_REQUEST_CHANGE_BARRING_PASSWORD = 44;
- int RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE = 45;
- int RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC = 46;
- int RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL = 47;
- int RIL_REQUEST_QUERY_AVAILABLE_NETWORKS = 48;
- int RIL_REQUEST_DTMF_START = 49;
- int RIL_REQUEST_DTMF_STOP = 50;
- int RIL_REQUEST_BASEBAND_VERSION = 51;
- int RIL_REQUEST_SEPARATE_CONNECTION = 52;
- 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_RESET_RADIO = 58;
- int RIL_REQUEST_OEM_HOOK_RAW = 59;
- int RIL_REQUEST_OEM_HOOK_STRINGS = 60;
- int RIL_REQUEST_SCREEN_STATE = 61;
- int RIL_REQUEST_SET_SUPP_SVC_NOTIFICATION = 62;
- int RIL_REQUEST_WRITE_SMS_TO_SIM = 63;
- int RIL_REQUEST_DELETE_SMS_ON_SIM = 64;
- int RIL_REQUEST_SET_BAND_MODE = 65;
- int RIL_REQUEST_QUERY_AVAILABLE_BAND_MODE = 66;
- int RIL_REQUEST_STK_GET_PROFILE = 67;
- int RIL_REQUEST_STK_SET_PROFILE = 68;
- int RIL_REQUEST_STK_SEND_ENVELOPE_COMMAND = 69;
- int RIL_REQUEST_STK_SEND_TERMINAL_RESPONSE = 70;
- int RIL_REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM = 71;
- int RIL_REQUEST_EXPLICIT_CALL_TRANSFER = 72;
- int RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE = 73;
- 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_UNSOL_RESPONSE_BASE = 1000;
- int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
- int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
- int RIL_UNSOL_RESPONSE_NETWORK_STATE_CHANGED = 1002;
- int RIL_UNSOL_RESPONSE_NEW_SMS = 1003;
- int RIL_UNSOL_RESPONSE_NEW_SMS_STATUS_REPORT = 1004;
- int RIL_UNSOL_RESPONSE_NEW_SMS_ON_SIM = 1005;
- int RIL_UNSOL_ON_USSD = 1006;
- 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_SUPP_SVC_NOTIFICATION = 1011;
- int RIL_UNSOL_STK_SESSION_END = 1012;
- int RIL_UNSOL_STK_PROACTIVE_COMMAND = 1013;
- int RIL_UNSOL_STK_EVENT_NOTIFY = 1014;
- int RIL_UNSOL_STK_CALL_SETUP = 1015;
- int RIL_UNSOL_SIM_SMS_STORAGE_FULL = 1016;
- int RIL_UNSOL_SIM_REFRESH = 1017;
- int RIL_UNSOL_CALL_RING = 1018;
- int RIL_UNSOL_RESTRICTED_STATE_CHANGED = 1023;
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
index 81fc657..ead1327 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMFileHandler.java
@@ -16,506 +16,54 @@
package com.android.internal.telephony.gsm;
-import com.android.internal.telephony.*;
-import com.android.internal.telephony.gsm.stk.ImageDescriptor;
import android.os.*;
import android.os.AsyncResult;
-import android.os.RegistrantList;
-import android.os.Registrant;
import android.util.Log;
+
+import com.android.internal.telephony.IccConstants;
+import com.android.internal.telephony.IccException;
+import com.android.internal.telephony.IccFileHandler;
+import com.android.internal.telephony.IccFileTypeMismatch;
+import com.android.internal.telephony.IccIoResult;
+import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.PhoneProxy;
+
import java.util.ArrayList;
/**
* {@hide}
*/
-public final class SIMFileHandler extends Handler
-{
+public final class SIMFileHandler extends IccFileHandler {
static final String LOG_TAG = "GSM";
- //from TS 11.11 9.1 or elsewhere
- static private final int COMMAND_READ_BINARY = 0xb0;
- static private final int COMMAND_UPDATE_BINARY = 0xd6;
- static private final int COMMAND_READ_RECORD = 0xb2;
- static private final int COMMAND_UPDATE_RECORD = 0xdc;
- static private final int COMMAND_SEEK = 0xa2;
- static private final int COMMAND_GET_RESPONSE = 0xc0;
-
- // from TS 11.11 9.2.5
- static private final int READ_RECORD_MODE_ABSOLUTE = 4;
-
- //***** types of files TS 11.11 9.3
- static private final int EF_TYPE_TRANSPARENT = 0;
- static private final int EF_TYPE_LINEAR_FIXED = 1;
- static private final int EF_TYPE_CYCLIC = 3;
-
- //***** types of files TS 11.11 9.3
- static private final int TYPE_RFU = 0;
- static private final int TYPE_MF = 1;
- static private final int TYPE_DF = 2;
- static private final int TYPE_EF = 4;
-
- // size of GET_RESPONSE for EF
- static private final int GET_RESPONSE_EF_SIZE_BYTES = 15;
-
- // Byte order received in response to COMMAND_GET_RESPONSE
- // Refer TS 51.011 Section 9.2.1
- static private final int RESPONSE_DATA_RFU_1 = 0;
- static private final int RESPONSE_DATA_RFU_2 = 1;
-
- static private final int RESPONSE_DATA_FILE_SIZE_1 = 2;
- static private final int RESPONSE_DATA_FILE_SIZE_2 = 3;
-
- static private final int RESPONSE_DATA_FILE_ID_1 = 4;
- static private final int RESPONSE_DATA_FILE_ID_2 = 5;
- static private final int RESPONSE_DATA_FILE_TYPE = 6;
- static private final int RESPONSE_DATA_RFU_3 = 7;
- static private final int RESPONSE_DATA_ACCESS_CONDITION_1 = 8;
- static private final int RESPONSE_DATA_ACCESS_CONDITION_2 = 9;
- static private final int RESPONSE_DATA_ACCESS_CONDITION_3 = 10;
- static private final int RESPONSE_DATA_FILE_STATUS = 11;
- static private final int RESPONSE_DATA_LENGTH = 12;
- static private final int RESPONSE_DATA_STRUCTURE = 13;
- static private final int RESPONSE_DATA_RECORD_LENGTH = 14;
-
-
//***** Instance Variables
- GSMPhone phone;
-
- //***** Events
-
- /** Finished retrieving size of transparent EF; start loading. */
- static private final int EVENT_GET_BINARY_SIZE_DONE = 4;
- /** Finished loading contents of transparent EF; post result. */
- static private final int EVENT_READ_BINARY_DONE = 5;
- /** Finished retrieving size of records for linear-fixed EF; now load. */
- static private final int EVENT_GET_RECORD_SIZE_DONE = 6;
- /** Finished loading single record from a linear-fixed EF; post result. */
- static private final int EVENT_READ_RECORD_DONE = 7;
- /** Finished retrieving record size; post result. */
- static private final int EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE = 8;
- /** Finished retrieving image instance record; post result. */
- static private final int EVENT_READ_IMG_DONE = 9;
- /** Finished retrieving icon data; post result. */
- static private final int EVENT_READ_ICON_DONE = 10;
-
- //***** Inner Classes
-
- static class LoadLinearFixedContext
- {
-
- int efid;
- int recordNum, recordSize, countRecords;
- boolean loadAll;
-
- Message onLoaded;
-
- ArrayList results;
-
- LoadLinearFixedContext(int efid, int recordNum, Message onLoaded)
- {
- this.efid = efid;
- this.recordNum = recordNum;
- this.onLoaded = onLoaded;
- this.loadAll = false;
- }
-
- LoadLinearFixedContext(int efid, Message onLoaded)
- {
- this.efid = efid;
- this.recordNum = 1;
- this.loadAll = true;
- this.onLoaded = onLoaded;
- }
-
- }
-
//***** Constructor
- SIMFileHandler(GSMPhone phone)
- {
- this.phone = phone;
+ SIMFileHandler(GSMPhone phone) {
+ super(phone);
}
- //***** Public Methods
-
- /**
- * Load a record from a SIM Linear Fixed EF
- *
- * @param fileid EF id
- * @param recordNum 1-based (not 0-based) record number
- * @param onLoaded
- *
- * ((AsyncResult)(onLoaded.obj)).result is the byte[]
- *
- */
- void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded)
- {
- Message response
- = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
- new LoadLinearFixedContext(fileid, recordNum, onLoaded));
-
- phone.mCM.simIO(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(SimConstants.EF_IMG, recordNum,
- onLoaded));
-
- phone.mCM.simIO(COMMAND_GET_RESPONSE, SimConstants.EF_IMG, "img",
- recordNum, READ_RECORD_MODE_ABSOLUTE,
- ImageDescriptor.ID_LENGTH, null, null, response);
- }
-
- /**
- * get record size for a linear fixed EF
- *
- * @param fileid EF id
- * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[]
- * int[0] is the record length int[1] is the total length of the EF
- * file int[3] is the number of records in the EF file So int[0] *
- * int[3] = int[1]
- */
- void getEFLinearRecordSize(int fileid, Message onLoaded)
- {
- Message response
- = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE,
- new LoadLinearFixedContext(fileid, onLoaded));
- phone.mCM.simIO(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
- *
- */
- void loadEFLinearFixedAll(int fileid, Message onLoaded)
- {
- Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
- new LoadLinearFixedContext(fileid,onLoaded));
-
- phone.mCM.simIO(COMMAND_GET_RESPONSE, fileid, null,
- 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
+ public void dispose() {
+ super.dispose();
}
- /**
- * Load a SIM Transparent EF
- *
- * @param fileid EF id
- * @param onLoaded
- *
- * ((AsyncResult)(onLoaded.obj)).result is the byte[]
- *
- */
-
- void loadEFTransparent(int fileid, Message onLoaded)
- {
- Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,
- fileid, 0, onLoaded);
-
- phone.mCM.simIO(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.simIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset,
- length, null, null, response);
+ protected void finalize() {
+ Log.d(LOG_TAG, "SIMFileHandler finalized");
}
- /**
- * 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 SimIoResult on success
- */
- void updateEFLinearFixed(int fileid, int recordNum, byte[] data,
- String pin2, Message onComplete)
- {
- phone.mCM.simIO(COMMAND_UPDATE_RECORD, fileid, null,
- recordNum, READ_RECORD_MODE_ABSOLUTE, data.length,
- SimUtils.bytesToHexString(data), pin2, onComplete);
- }
+ //***** Overridden from IccFileHandler
- /**
- * Update a transparent EF
- * @param fileid EF id
- * @param data must be exactly as long as the EF
- */
- void updateEFTransparent(int fileid, byte[] data, Message onComplete)
- {
- phone.mCM.simIO(COMMAND_UPDATE_BINARY, fileid, null,
- 0, 0, data.length,
- SimUtils.bytesToHexString(data), null, onComplete);
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
}
- //***** Overridden from Handler
-
- public void handleMessage(Message msg)
- {
- AsyncResult ar;
- SimIoResult result;
- Message response = null;
- String str;
- LoadLinearFixedContext lc;
-
- SimException simException;
- 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 = (SimIoResult) ar.result;
- response = lc.onLoaded;
-
- simException = result.getException();
- if (simException != null) {
- sendResult(response, result.payload, ar.exception);
- }
- break;
- case EVENT_READ_ICON_DONE:
- ar = (AsyncResult) msg.obj;
- response = (Message) ar.userObj;
- result = (SimIoResult) ar.result;
-
- simException = result.getException();
- if (simException != 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 = (SimIoResult) ar.result;
- response = lc.onLoaded;
-
- if (ar.exception != null) {
- sendResult(response, null, ar.exception);
- break;
- }
-
- simException = result.getException();
- if (simException != null) {
- sendResult(response, null, simException);
- break;
- }
-
- data = result.payload;
-
- if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] ||
- EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
- throw new SimFileTypeMismatch();
- }
-
- 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 = (SimIoResult) ar.result;
- response = lc.onLoaded;
-
- if (ar.exception != null) {
- sendResult(response, null, ar.exception);
- break;
- }
-
- simException = result.getException();
-
- if (simException != null) {
- sendResult(response, null, simException);
- break;
- }
-
- data = result.payload;
- fileid = lc.efid;
- recordNum = lc.recordNum;
-
- if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
- throw new SimFileTypeMismatch();
- }
-
- if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
- throw new SimFileTypeMismatch();
- }
-
- 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(lc.countRecords);
- }
-
- phone.mCM.simIO(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 = (SimIoResult) ar.result;
-
- if (ar.exception != null) {
- sendResult(response, null, ar.exception);
- break;
- }
-
- simException = result.getException();
-
- if (simException != null) {
- sendResult(response, null, simException);
- break;
- }
-
- data = result.payload;
-
- fileid = msg.arg1;
-
- if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
- throw new SimFileTypeMismatch();
- }
-
- if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
- throw new SimFileTypeMismatch();
- }
-
- size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
- + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
-
- phone.mCM.simIO(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 = (SimIoResult) ar.result;
- response = lc.onLoaded;
-
- if (ar.exception != null) {
- sendResult(response, null, ar.exception);
- break;
- }
-
- simException = result.getException();
-
- if (simException != null) {
- sendResult(response, null, simException);
- 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.simIO(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 = (SimIoResult) ar.result;
-
- if (ar.exception != null) {
- sendResult(response, null, ar.exception);
- break;
- }
-
- simException = result.getException();
-
- if (simException != null) {
- sendResult(response, null, simException);
- break;
- }
-
- sendResult(response, result.payload, null);
- break;
-
- }} catch (Exception exc) {
- if (response != null) {
- sendResult(response, null, exc);
- } else {
- Log.e(LOG_TAG, "uncaught exception", exc);
- }
- }
+ protected void logd(String msg) {
+ Log.d(LOG_TAG, "[SIMFileHandler] " + msg);
}
- //***** Private Methods
-
- private void sendResult(Message response, Object result, Throwable ex)
- {
- if (response == null) {
- return;
- }
-
- AsyncResult.forMessage(response, result, ex);
-
- response.sendToTarget();
+ protected void loge(String msg) {
+ Log.e(LOG_TAG, "[SIMFileHandler] " + msg);
}
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index 4467536..09a17f5 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -16,26 +16,45 @@
package com.android.internal.telephony.gsm;
+import android.app.ActivityManagerNative;
import android.app.AlarmManager;
+import android.app.IActivityManager;
import android.content.Context;
+import android.content.res.Configuration;
import android.os.AsyncResult;
-import android.os.RegistrantList;
-import android.os.Registrant;
import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
-import android.telephony.gsm.SmsMessage;
+import android.os.Registrant;
import android.util.Log;
import java.util.ArrayList;
+
import static com.android.internal.telephony.TelephonyProperties.*;
-import com.android.internal.telephony.SimCard;
+
+import com.android.internal.telephony.AdnRecord;
+import com.android.internal.telephony.AdnRecordCache;
+import com.android.internal.telephony.AdnRecordLoader;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.gsm.SimCard;
+import com.android.internal.telephony.gsm.SmsMessage;
+import com.android.internal.telephony.IccFileHandler;
+import com.android.internal.telephony.IccRecords;
+import com.android.internal.telephony.IccUtils;
+import com.android.internal.telephony.IccVmFixedException;
+import com.android.internal.telephony.IccVmNotSupportedException;
+import com.android.internal.telephony.PhoneProxy;
+
+
+
+
+
+
/**
* {@hide}
*/
-public final class SIMRecords extends Handler implements SimConstants
-{
+public final class SIMRecords extends IccRecords {
static final String LOG_TAG = "GSM";
private static final boolean CRASH_RIL = false;
@@ -44,37 +63,19 @@ public final class SIMRecords extends Handler implements SimConstants
//***** Instance Variables
- GSMPhone phone;
- RegistrantList recordsLoadedRegistrants = new RegistrantList();
-
- int recordsToLoad; // number of pending load requests
+ VoiceMailConstants mVmConfig;
- AdnRecordCache adnCache;
- VoiceMailConstants mVmConfig;
SpnOverride mSpnOverride;
//***** Cached SIM State; cleared on channel close
- boolean recordsRequested = false; // true if we've made requests for the sim records
-
String imsi;
- String iccid;
- String msisdn = null; // My mobile number
- String msisdnTag = null;
- String voiceMailNum = null;
- String voiceMailTag = null;
- String newVoiceMailNum = null;
- String newVoiceMailTag = null;
- boolean isVoiceMailFixed = false;
- int countVoiceMessages = 0;
boolean callForwardingEnabled;
- int mncLength = 0; // 0 is used to indicate that the value
- // is not initialized
- int mailboxIndex = 0; // 0 is no mailbox dailing number associated
+
/**
- * Sates only used by getSpnFsm FSM
+ * States only used by getSpnFsm FSM
*/
private Get_Spn_Fsm_State spnState;
@@ -157,9 +158,8 @@ public final class SIMRecords extends Handler implements SimConstants
//***** Constructor
- SIMRecords(GSMPhone phone)
- {
- this.phone = phone;
+ SIMRecords(GSMPhone p) {
+ super(p);
adnCache = new AdnRecordCache(phone);
@@ -172,30 +172,35 @@ public final class SIMRecords extends Handler implements SimConstants
recordsToLoad = 0;
- phone.mCM.registerForSIMReady(this, EVENT_SIM_READY, null);
- phone.mCM.registerForOffOrNotAvailable(
+ p.mCM.registerForSIMReady(this, EVENT_SIM_READY, null);
+ p.mCM.registerForOffOrNotAvailable(
this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
- phone.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
- phone.mCM.setOnSimRefresh(this, EVENT_SIM_REFRESH, null);
+ p.mCM.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
+ p.mCM.setOnIccRefresh(this, EVENT_SIM_REFRESH, null);
// Start off by setting empty state
- onRadioOffOrNotAvailable();
+ onRadioOffOrNotAvailable();
}
- AdnRecordCache getAdnCache() {
- return adnCache;
+ public void dispose() {
+ //Unregister for all events
+ phone.mCM.unregisterForSIMReady(this);
+ phone.mCM.unregisterForOffOrNotAvailable( this);
+ phone.mCM.unSetOnIccRefresh(this);
}
- private void onRadioOffOrNotAvailable()
- {
+ protected void finalize() {
+ if(DBG) Log.d(LOG_TAG, "SIMRecords finalized");
+ }
+
+ protected void onRadioOffOrNotAvailable() {
imsi = null;
msisdn = null;
voiceMailNum = null;
countVoiceMessages = 0;
mncLength = 0;
iccid = null;
- spn = null;
// -1 means no EF_SPN found; treat accordingly.
spnDisplayCondition = -1;
efMWIS = null;
@@ -205,9 +210,9 @@ public final class SIMRecords extends Handler implements SimConstants
adnCache.reset();
- phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, null);
- phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, null);
- phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY, null);
+ phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null);
+ phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, null);
+ phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null);
// recordsRequested is set to false indicating that the SIM
// read requests made so far are not valid. This is set to
@@ -217,24 +222,13 @@ public final class SIMRecords extends Handler implements SimConstants
//***** Public Methods
- public void registerForRecordsLoaded(Handler h, int what, Object obj)
- {
- Registrant r = new Registrant(h, what, obj);
- recordsLoadedRegistrants.add(r);
-
- if (recordsToLoad == 0 && recordsRequested == true) {
- r.notifyRegistrant(new AsyncResult(null, null, null));
- }
- }
/** Returns null if SIM is not yet ready */
- public String getIMSI()
- {
+ public String getIMSI() {
return imsi;
}
- public String getMsisdnNumber()
- {
+ public String getMsisdnNumber() {
return msisdn;
}
@@ -272,28 +266,18 @@ public final class SIMRecords extends Handler implements SimConstants
return msisdnTag;
}
- public String getVoiceMailNumber()
- {
+ public String getVoiceMailNumber() {
return voiceMailNum;
}
/**
- * Return Service Provider Name stored in SIM
- * @return null if SIM is not yet ready
- */
- 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
@@ -314,7 +298,7 @@ public final class SIMRecords extends Handler implements SimConstants
Message onComplete) {
if (isVoiceMailFixed) {
AsyncResult.forMessage((onComplete)).exception =
- new SimVmFixedException("Voicemail number is fixed by operator");
+ new IccVmFixedException("Voicemail number is fixed by operator");
onComplete.sendToTarget();
return;
}
@@ -336,9 +320,9 @@ public final class SIMRecords extends Handler implements SimConstants
EF_EXT1, 1, null,
obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE, onComplete));
- }else {
+ } else {
AsyncResult.forMessage((onComplete)).exception =
- new SimVmNotSupportedException("Update SIM voice mailbox error");
+ new IccVmNotSupportedException("Update SIM voice mailbox error");
onComplete.sendToTarget();
}
}
@@ -352,12 +336,11 @@ public final class SIMRecords extends Handler implements SimConstants
* Sets the SIM voice message waiting indicator records
* @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
* @param countWaiting The number of messages waiting, if known. Use
- * -1 to indicate that an unknown number of
+ * -1 to indicate that an unknown number of
* messages are waiting
*/
public void
- setVoiceMessageWaiting(int line, int countWaiting)
- {
+ setVoiceMessageWaiting(int line, int countWaiting) {
if (line != 1) {
// only profile 1 is supported
return;
@@ -374,14 +357,14 @@ public final class SIMRecords extends Handler implements SimConstants
countVoiceMessages = countWaiting;
- phone.notifyMessageWaitingIndicator();
+ ((GSMPhone) phone).notifyMessageWaitingIndicator();
try {
if (efMWIS != null) {
// TS 51.011 10.3.45
// lsb of byte 0 is 'voicemail' status
- efMWIS[0] = (byte)((efMWIS[0] & 0xfe)
+ efMWIS[0] = (byte)((efMWIS[0] & 0xfe)
| (countVoiceMessages == 0 ? 0 : 1));
// byte 1 is the number of voice messages waiting
@@ -393,17 +376,17 @@ public final class SIMRecords extends Handler implements SimConstants
efMWIS[1] = (byte) countWaiting;
}
- phone.mSIMFileHandler.updateEFLinearFixed(
+ phone.getIccFileHandler().updateEFLinearFixed(
EF_MWIS, 1, efMWIS, null,
obtainMessage (EVENT_UPDATE_DONE, EF_MWIS));
- }
+ }
if (efCPHS_MWI != null) {
// Refer CPHS4_2.WW6 B4.2.3
- efCPHS_MWI[0] = (byte)((efCPHS_MWI[0] & 0xf0)
+ efCPHS_MWI[0] = (byte)((efCPHS_MWI[0] & 0xf0)
| (countVoiceMessages == 0 ? 0x5 : 0xa));
- phone.mSIMFileHandler.updateEFTransparent(
+ phone.getIccFileHandler().updateEFTransparent(
EF_VOICE_MAIL_INDICATOR_CPHS, efCPHS_MWI,
obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS));
}
@@ -413,22 +396,6 @@ public final class SIMRecords extends Handler implements SimConstants
}
}
- /** @return true if there are messages waiting, false otherwise. */
- public boolean getVoiceMessageWaiting()
- {
- return countVoiceMessages != 0;
- }
-
- /**
- * Returns number of voice messages waiting, if available
- * If not available (eg, on an older CPHS SIM) -1 is returned if
- * getVoiceMessageWaiting() is true
- */
- public int getCountVoiceMessages()
- {
- return countVoiceMessages;
- }
-
public boolean getVoiceCallForwardingFlag() {
return callForwardingEnabled;
}
@@ -439,7 +406,7 @@ public final class SIMRecords extends Handler implements SimConstants
callForwardingEnabled = enable;
- phone.notifyCallForwardingIndicator();
+ ((GSMPhone) phone).notifyCallForwardingIndicator();
try {
if (mEfCfis != null) {
@@ -453,7 +420,7 @@ public final class SIMRecords extends Handler implements SimConstants
// TODO: Should really update other fields in EF_CFIS, eg,
// dialing number. We don't read or use it right now.
- phone.mSIMFileHandler.updateEFLinearFixed(
+ phone.getIccFileHandler().updateEFLinearFixed(
EF_CFIS, 1, mEfCfis, null,
obtainMessage (EVENT_UPDATE_DONE, EF_CFIS));
}
@@ -467,7 +434,7 @@ public final class SIMRecords extends Handler implements SimConstants
| CFF_UNCONDITIONAL_DEACTIVE);
}
- phone.mSIMFileHandler.updateEFTransparent(
+ phone.getIccFileHandler().updateEFTransparent(
EF_CFF_CPHS, mEfCff,
obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS));
}
@@ -496,8 +463,7 @@ public final class SIMRecords extends Handler implements SimConstants
/** Returns the 5 or 6 digit MCC/MNC of the operator that
* provided the SIM card. Returns null of SIM is not yet ready
*/
- String getSIMOperatorNumeric()
- {
+ String getSIMOperatorNumeric() {
if (imsi == null) {
return null;
}
@@ -517,17 +483,8 @@ public final class SIMRecords extends Handler implements SimConstants
return imsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
}
-
- boolean getRecordsLoaded()
- {
- if (recordsToLoad == 0 && recordsRequested == true) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
+
+ /**
* If the timezone is not already set, set it based on the MCC of the SIM.
* @param mcc Mobile Country Code of the SIM
*/
@@ -557,8 +514,7 @@ public final class SIMRecords extends Handler implements SimConstants
}
//***** Overridden from Handler
- public void handleMessage(Message msg)
- {
+ public void handleMessage(Message msg) {
AsyncResult ar;
AdnRecord adn;
@@ -573,19 +529,19 @@ public final class SIMRecords extends Handler implements SimConstants
case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
onRadioOffOrNotAvailable();
- break;
+ break;
/* IO events */
case EVENT_GET_IMSI_DONE:
isRecordLoadResponse = true;
-
+
ar = (AsyncResult)msg.obj;
if (ar.exception != null) {
Log.e(LOG_TAG, "Exception querying IMSI, Exception:" + ar.exception);
break;
- }
-
+ }
+
imsi = (String) ar.result;
// IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
@@ -594,11 +550,11 @@ public final class SIMRecords extends Handler implements SimConstants
Log.e(LOG_TAG, "invalid IMSI " + imsi);
imsi = null;
}
-
+
Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxxxx");
- phone.mSimCard.updateImsiConfiguration(imsi);
- phone.mSimCard.broadcastSimStateChangedIntent(
- SimCard.INTENT_VALUE_SIM_IMSI, null);
+ ((GSMPhone) phone).mSimCard.updateImsiConfiguration(imsi);
+ ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+ SimCard.INTENT_VALUE_ICC_IMSI, null);
int mcc = Integer.parseInt(imsi.substring(0, 3));
setTimezoneFromMccIfNeeded(mcc);
@@ -616,7 +572,7 @@ public final class SIMRecords extends Handler implements SimConstants
if (ar.exception == null) {
// Refer TS 51.011 Section 10.3.44 for content details
Log.d(LOG_TAG, "EF_MBI: " +
- SimUtils.bytesToHexString(data));
+ IccUtils.bytesToHexString(data));
// Voice mail record number stored first
mailboxIndex = (int)data[0] & 0xff;
@@ -651,20 +607,20 @@ public final class SIMRecords extends Handler implements SimConstants
ar = (AsyncResult)msg.obj;
if (ar.exception != null) {
-
- Log.d(LOG_TAG, "Invalid or missing EF"
+
+ Log.d(LOG_TAG, "Invalid or missing EF"
+ ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? "[MAILBOX]" : "[MBDN]"));
// Bug #645770 fall back to CPHS
// FIXME should use SST to decide
if (msg.what == EVENT_GET_MBDN_DONE) {
- //load CPHS on fail...
+ //load CPHS on fail...
// FIXME right now, only load line1's CPHS voice mail entry
recordsToLoad += 1;
new AdnRecordLoader(phone).loadFromEF(
- EF_MAILBOX_CPHS, EF_EXT1, 1,
+ EF_MAILBOX_CPHS, EF_EXT1, 1,
obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
}
break;
@@ -672,7 +628,8 @@ public final class SIMRecords extends Handler implements SimConstants
adn = (AdnRecord)ar.result;
- Log.d(LOG_TAG, "VM: " + adn + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]"));
+ Log.d(LOG_TAG, "VM: " + adn +
+ ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE) ? " EF[MAILBOX]" : " EF[MBDN]"));
if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) {
// Bug #645770 fall back to CPHS
@@ -680,7 +637,7 @@ public final class SIMRecords extends Handler implements SimConstants
// FIXME right now, only load line1's CPHS voice mail entry
recordsToLoad += 1;
new AdnRecordLoader(phone).loadFromEF(
- EF_MAILBOX_CPHS, EF_EXT1, 1,
+ EF_MAILBOX_CPHS, EF_EXT1, 1,
obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
break;
@@ -730,7 +687,7 @@ public final class SIMRecords extends Handler implements SimConstants
}
Log.d(LOG_TAG, "EF_MWIS: " +
- SimUtils.bytesToHexString(data));
+ IccUtils.bytesToHexString(data));
efMWIS = data;
@@ -744,11 +701,11 @@ public final class SIMRecords extends Handler implements SimConstants
countVoiceMessages = data[1] & 0xff;
if (voiceMailWaiting && countVoiceMessages == 0) {
- // Unknown count = -1
+ // Unknown count = -1
countVoiceMessages = -1;
}
- phone.notifyMessageWaitingIndicator();
+ ((GSMPhone) phone).notifyMessageWaitingIndicator();
break;
case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
@@ -777,7 +734,7 @@ public final class SIMRecords extends Handler implements SimConstants
countVoiceMessages = 0;
}
- phone.notifyMessageWaitingIndicator();
+ ((GSMPhone) phone).notifyMessageWaitingIndicator();
}
break;
@@ -786,13 +743,13 @@ public final class SIMRecords extends Handler implements SimConstants
ar = (AsyncResult)msg.obj;
data = (byte[])ar.result;
-
+
if (ar.exception != null) {
break;
- }
+ }
+
+ iccid = IccUtils.bcdToString(data, 0, data.length);
- iccid = SimUtils.bcdToString(data, 0, data.length);
-
Log.d(LOG_TAG, "iccid: " + iccid);
break;
@@ -809,7 +766,7 @@ public final class SIMRecords extends Handler implements SimConstants
}
Log.d(LOG_TAG, "EF_AD: " +
- SimUtils.bytesToHexString(data));
+ IccUtils.bytesToHexString(data));
if (data.length < 3) {
Log.d(LOG_TAG, "SIMRecords: Corrupt AD data on SIM");
@@ -851,14 +808,14 @@ public final class SIMRecords extends Handler implements SimConstants
}
Log.d(LOG_TAG, "EF_CFF_CPHS: " +
- SimUtils.bytesToHexString(data));
+ IccUtils.bytesToHexString(data));
mEfCff = data;
if (mEfCfis == null) {
callForwardingEnabled =
((data[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE);
- phone.notifyCallForwardingIndicator();
+ ((GSMPhone) phone).notifyCallForwardingIndicator();
}
break;
@@ -872,7 +829,7 @@ public final class SIMRecords extends Handler implements SimConstants
break;
}
- parseEfSpdi(data);
+ parseEfSpdi(data);
break;
case EVENT_UPDATE_DONE:
@@ -896,8 +853,8 @@ public final class SIMRecords extends Handler implements SimConstants
for ( ; tlv.isValidObject() ; tlv.nextObject()) {
if (tlv.getTag() == TAG_FULL_NETWORK_NAME) {
- pnnHomeName
- = SimUtils.networkNameToString(
+ pnnHomeName
+ = IccUtils.networkNameToString(
tlv.getData(), 0, tlv.getData().length);
break;
}
@@ -931,7 +888,8 @@ public final class SIMRecords extends Handler implements SimConstants
+ ar.exception + " length " + index.length);
} else {
Log.d(LOG_TAG, "READ EF_SMS RECORD index=" + index[0]);
- phone.mSIMFileHandler.loadEFLinearFixed(EF_SMS,index[0],obtainMessage(EVENT_GET_SMS_DONE));
+ phone.getIccFileHandler().loadEFLinearFixed(EF_SMS,index[0],
+ obtainMessage(EVENT_GET_SMS_DONE));
}
break;
@@ -955,7 +913,7 @@ public final class SIMRecords extends Handler implements SimConstants
break;
}
- //Log.d(LOG_TAG, "SST: " + SimUtils.bytesToHexString(data));
+ //Log.d(LOG_TAG, "SST: " + IccUtils.bytesToHexString(data));
break;
case EVENT_GET_INFO_CPHS_DONE:
@@ -969,7 +927,7 @@ public final class SIMRecords extends Handler implements SimConstants
mCphsInfo = (byte[])ar.result;
- if (DBG) log("iCPHS: " + SimUtils.bytesToHexString(mCphsInfo));
+ if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo));
break;
case EVENT_SET_MBDN_DONE:
@@ -1050,20 +1008,20 @@ public final class SIMRecords extends Handler implements SimConstants
}
Log.d(LOG_TAG, "EF_CFIS: " +
- SimUtils.bytesToHexString(data));
+ IccUtils.bytesToHexString(data));
mEfCfis = data;
// Refer TS 51.011 Section 10.3.46 for the content description
callForwardingEnabled = ((data[1] & 0x01) != 0);
- phone.notifyCallForwardingIndicator();
+ ((GSMPhone) phone).notifyCallForwardingIndicator();
break;
}}catch (RuntimeException exc) {
// I don't want these exceptions to be fatal
Log.w(LOG_TAG, "Exception parsing SIM record", exc);
- } finally {
+ } finally {
// Count up record load responses even if they are fails
if (isRecordLoadResponse) {
onRecordLoaded();
@@ -1076,12 +1034,12 @@ public final class SIMRecords extends Handler implements SimConstants
case EF_MBDN:
recordsToLoad++;
new AdnRecordLoader(phone).loadFromEF(EF_MBDN, EF_EXT6,
- mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
+ mailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
break;
case EF_MAILBOX_CPHS:
recordsToLoad++;
new AdnRecordLoader(phone).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1,
- 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
+ 1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
break;
default:
// For now, fetch all records if this is not a
@@ -1093,7 +1051,7 @@ public final class SIMRecords extends Handler implements SimConstants
}
}
- private void handleSimRefresh(int[] result) {
+ private void handleSimRefresh(int[] result) {
if (result == null || result.length == 0) {
if (DBG) log("handleSimRefresh without input");
return;
@@ -1102,7 +1060,7 @@ public final class SIMRecords extends Handler implements SimConstants
switch ((result[0])) {
case CommandsInterface.SIM_REFRESH_FILE_UPDATED:
if (DBG) log("handleSimRefresh with SIM_REFRESH_FILE_UPDATED");
- // result[1] contains the EFID of the updated file.
+ // result[1] contains the EFID of the updated file.
int efid = result[1];
handleFileUpdate(efid);
break;
@@ -1130,8 +1088,7 @@ public final class SIMRecords extends Handler implements SimConstants
}
}
- private void handleSms(byte[] ba)
- {
+ private void handleSms(byte[] ba) {
if (ba[0] != 0)
Log.d("ENF", "status : " + ba[0]);
@@ -1145,12 +1102,13 @@ public final class SIMRecords extends Handler implements SimConstants
byte[] nba = new byte[n - 1];
System.arraycopy(ba, 1, nba, 0, n - 1);
- String pdu = SimUtils.bytesToHexString(nba);
+ String pdu = IccUtils.bytesToHexString(nba);
// XXX first line is bogus
SmsMessage message = SmsMessage.newFromCMT(
new String[] { "", pdu });
- phone.mSMS.dispatchMessage(message);
+
+ ((GSMPhone) phone).mSMS.dispatchMessage(message);
}
}
@@ -1175,12 +1133,13 @@ public final class SIMRecords extends Handler implements SimConstants
byte[] nba = new byte[n - 1];
System.arraycopy(ba, 1, nba, 0, n - 1);
- String pdu = SimUtils.bytesToHexString(nba);
+ String pdu = IccUtils.bytesToHexString(nba);
// XXX first line is bogus
SmsMessage message = SmsMessage.newFromCMT(
new String[] { "", pdu });
- phone.mSMS.dispatchMessage(message);
+
+ ((GSMPhone) phone).mSMS.dispatchMessage(message);
// 3GPP TS 51.011 v5.0.0 (20011-12) 10.5.3
// 1 == "received by MS from network; message read"
@@ -1188,18 +1147,14 @@ public final class SIMRecords extends Handler implements SimConstants
ba[0] = 1;
if (false) { // XXX writing seems to crash RdoServD
- phone.mSIMFileHandler.updateEFLinearFixed(EF_SMS, i, ba, null,
- obtainMessage(EVENT_MARK_SMS_READ_DONE, i));
+ phone.getIccFileHandler().updateEFLinearFixed(EF_SMS,
+ i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i));
}
}
}
}
-
- //***** Private Methods
-
- private void onRecordLoaded()
- {
+ protected void onRecordLoaded() {
// One record loaded successfully or failed, In either case
// we need to update the recordsToLoad count
recordsToLoad -= 1;
@@ -1211,21 +1166,19 @@ public final class SIMRecords extends Handler implements SimConstants
recordsToLoad = 0;
}
}
-
- private void onAllRecordsLoaded()
- {
+
+ protected void onAllRecordsLoaded() {
Log.d(LOG_TAG, "SIMRecords: record load complete");
String operator = getSIMOperatorNumeric();
// Some fields require more than one SIM record to set
- phone.setSystemProperty(PROPERTY_SIM_OPERATOR_NUMERIC, operator);
+ phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
if (imsi != null) {
- phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ISO_COUNTRY,
- MccTable.countryCodeForMcc(
- Integer.parseInt(imsi.substring(0,3))));
+ phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
+ MccTable.countryCodeForMcc(Integer.parseInt(imsi.substring(0,3))));
}
else {
Log.e("SIM", "[SIMRecords] onAllRecordsLoaded: imsi is NULL!");
@@ -1236,16 +1189,19 @@ public final class SIMRecords extends Handler implements SimConstants
recordsLoadedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
- phone.mSimCard.broadcastSimStateChangedIntent(
- SimCard.INTENT_VALUE_SIM_LOADED, null);
+ ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+ SimCard.INTENT_VALUE_ICC_LOADED, null);
}
+ //***** Private methods
+
private void setSpnFromConfig(String carrier) {
if (mSpnOverride.containsCarrier(carrier)) {
spn = mSpnOverride.getSpn(carrier);
}
}
+
private void setVoiceMailByCountry (String spn) {
if (mVmConfig.containsCarrier(spn)) {
isVoiceMailFixed = true;
@@ -1258,22 +1214,22 @@ public final class SIMRecords extends Handler implements SimConstants
/* broadcast intent SIM_READY here so that we can make sure
READY is sent before IMSI ready
*/
- phone.mSimCard.broadcastSimStateChangedIntent(
- SimCard.INTENT_VALUE_SIM_READY, null);
+ ((GSMPhone) phone).mSimCard.broadcastSimStateChangedIntent(
+ SimCard.INTENT_VALUE_ICC_READY, null);
fetchSimRecords();
}
private void fetchSimRecords() {
recordsRequested = true;
+ IccFileHandler iccFh = phone.getIccFileHandler();
- Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad);
+ Log.v(LOG_TAG, "SIMRecords:fetchSimRecords " + recordsToLoad);
phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
recordsToLoad++;
- phone.mSIMFileHandler.loadEFTransparent(EF_ICCID,
- obtainMessage(EVENT_GET_ICCID_DONE));
+ iccFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
recordsToLoad++;
// FIXME should examine EF[MSISDN]'s capability configuration
@@ -1283,17 +1239,14 @@ public final class SIMRecords extends Handler implements SimConstants
recordsToLoad++;
// Record number is subscriber profile
- phone.mSIMFileHandler.loadEFLinearFixed(EF_MBI, 1,
- obtainMessage(EVENT_GET_MBI_DONE));
+ iccFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
recordsToLoad++;
- phone.mSIMFileHandler.loadEFTransparent(EF_AD,
- obtainMessage(EVENT_GET_AD_DONE));
+ iccFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
recordsToLoad++;
// Record number is subscriber profile
- phone.mSIMFileHandler.loadEFLinearFixed(EF_MWIS, 1,
- obtainMessage(EVENT_GET_MWIS_DONE));
+ iccFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
recordsToLoad++;
@@ -1301,50 +1254,49 @@ public final class SIMRecords extends Handler implements SimConstants
// the same info as EF[MWIS]. If both exist, both are updated
// but the EF[MWIS] data is preferred
// Please note this must be loaded after EF[MWIS]
- phone.mSIMFileHandler.loadEFTransparent(
- EF_VOICE_MAIL_INDICATOR_CPHS,
+ iccFh.loadEFTransparent(
+ EF_VOICE_MAIL_INDICATOR_CPHS,
obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
recordsToLoad++;
// Same goes for Call Forward Status indicator: fetch both
// EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
- phone.mSIMFileHandler.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
+ iccFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
recordsToLoad++;
- phone.mSIMFileHandler.loadEFTransparent(EF_CFF_CPHS,
- obtainMessage(EVENT_GET_CFF_DONE));
+ iccFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
recordsToLoad++;
getSpnFsm(true, null);
- phone.mSIMFileHandler.loadEFTransparent(EF_SPDI,
- obtainMessage(EVENT_GET_SPDI_DONE));
+ iccFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
recordsToLoad++;
- phone.mSIMFileHandler.loadEFLinearFixed(EF_PNN, 1,
- obtainMessage(EVENT_GET_PNN_DONE));
+ iccFh.loadEFLinearFixed(EF_PNN, 1, obtainMessage(EVENT_GET_PNN_DONE));
recordsToLoad++;
- phone.mSIMFileHandler.loadEFTransparent(EF_SST,
- obtainMessage(EVENT_GET_SST_DONE));
+ iccFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
recordsToLoad++;
- phone.mSIMFileHandler.loadEFTransparent(EF_INFO_CPHS,
- obtainMessage(EVENT_GET_INFO_CPHS_DONE));
+ iccFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
recordsToLoad++;
// XXX should seek instead of examining them all
if (false) { // XXX
- phone.mSIMFileHandler.loadEFLinearFixedAll(EF_SMS,
- obtainMessage(EVENT_GET_ALL_SMS_DONE));
+ iccFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
recordsToLoad++;
}
if (CRASH_RIL) {
- String sms = "0107912160130310f20404d0110041007030208054832b0120ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
- byte[] ba = SimUtils.hexStringToBytes(sms);
-
- phone.mSIMFileHandler.updateEFLinearFixed(EF_SMS, 1, ba, null,
+ String sms = "0107912160130310f20404d0110041007030208054832b0120"
+ + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ + "ffffffffffffffffffffffffffffff";
+ byte[] ba = IccUtils.hexStringToBytes(sms);
+
+ iccFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
}
}
@@ -1356,7 +1308,7 @@ public final class SIMRecords extends Handler implements SimConstants
*
* If the SPN is not found on the SIM, the rule is always PLMN_ONLY.
*/
- int getDisplayRule(String plmn) {
+ protected int getDisplayRule(String plmn) {
int rule;
if (spn == null || spnDisplayCondition == -1) {
// EF_SPN was not found on the SIM, or not yet loaded. Just show ONS.
@@ -1431,7 +1383,7 @@ public final class SIMRecords extends Handler implements SimConstants
case INIT:
spn = null;
- phone.mSIMFileHandler.loadEFTransparent( EF_SPN,
+ phone.getIccFileHandler().loadEFTransparent( EF_SPN,
obtainMessage(EVENT_GET_SPN_DONE));
recordsToLoad++;
@@ -1441,20 +1393,20 @@ public final class SIMRecords extends Handler implements SimConstants
if (ar != null && ar.exception == null) {
data = (byte[]) ar.result;
spnDisplayCondition = 0xff & data[0];
- spn = SimUtils.adnStringFieldToString(data, 1, data.length - 1);
+ spn = IccUtils.adnStringFieldToString(data, 1, data.length - 1);
if (DBG) log("Load EF_SPN: " + spn
+ " spnDisplayCondition: " + spnDisplayCondition);
- phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn);
+ phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
spnState = Get_Spn_Fsm_State.IDLE;
} else {
- phone.mSIMFileHandler.loadEFTransparent( EF_SPN_CPHS,
+ phone.getIccFileHandler().loadEFTransparent( EF_SPN_CPHS,
obtainMessage(EVENT_GET_SPN_DONE));
recordsToLoad++;
spnState = Get_Spn_Fsm_State.READ_SPN_CPHS;
-
+
// See TS 51.011 10.3.11. Basically, default to
// show PLMN always, and SPN also if roaming.
spnDisplayCondition = -1;
@@ -1463,16 +1415,16 @@ public final class SIMRecords extends Handler implements SimConstants
case READ_SPN_CPHS:
if (ar != null && ar.exception == null) {
data = (byte[]) ar.result;
- spn = SimUtils.adnStringFieldToString(
+ spn = IccUtils.adnStringFieldToString(
data, 0, data.length - 1 );
if (DBG) log("Load EF_SPN_CPHS: " + spn);
- phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn);
+ phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
spnState = Get_Spn_Fsm_State.IDLE;
} else {
- phone.mSIMFileHandler.loadEFTransparent( EF_SPN_SHORT_CPHS,
- obtainMessage(EVENT_GET_SPN_DONE));
+ phone.getIccFileHandler().loadEFTransparent(
+ EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
recordsToLoad++;
spnState = Get_Spn_Fsm_State.READ_SPN_SHORT_CPHS;
@@ -1481,11 +1433,11 @@ public final class SIMRecords extends Handler implements SimConstants
case READ_SPN_SHORT_CPHS:
if (ar != null && ar.exception == null) {
data = (byte[]) ar.result;
- spn = SimUtils.adnStringFieldToString(
+ spn = IccUtils.adnStringFieldToString(
data, 0, data.length - 1);
if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn);
- phone.setSystemProperty(PROPERTY_SIM_OPERATOR_ALPHA, spn);
+ phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ALPHA, spn);
}else {
if (DBG) log("No SPN loaded in either CHPS or 3GPP");
}
@@ -1503,8 +1455,7 @@ public final class SIMRecords extends Handler implements SimConstants
* are treated specially when determining SPN display
*/
private void
- parseEfSpdi(byte[] data)
- {
+ parseEfSpdi(byte[] data) {
SimTlv tlv = new SimTlv(data, 0, data.length);
byte[] plmnEntries = null;
@@ -1524,8 +1475,8 @@ public final class SIMRecords extends Handler implements SimConstants
spdiNetworks = new ArrayList(plmnEntries.length / 3);
for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) {
- String plmnCode;
- plmnCode = SimUtils.bcdToString(plmnEntries, i, 3);
+ String plmnCode;
+ plmnCode = IccUtils.bcdToString(plmnEntries, i, 3);
// Valid operator codes are 5 or 6 digits
if (plmnCode.length() >= 5) {
@@ -1543,7 +1494,11 @@ public final class SIMRecords extends Handler implements SimConstants
return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED );
}
- private void log(String s) {
+ protected void log(String s) {
Log.d(LOG_TAG, "[SIMRecords] " + s);
}
+
}
+
+
+
diff --git a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
deleted file mode 100644
index 5585524..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/SMSDispatcher.java
+++ /dev/null
@@ -1,979 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.app.AlertDialog;
-import android.app.PendingIntent.CanceledException;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.database.Cursor;
-import android.database.SQLException;
-import android.net.Uri;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.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.telephony.ServiceState;
-import android.util.Config;
-import com.android.internal.util.HexDump;
-import android.util.Log;
-import android.view.WindowManager;
-
-import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Random;
-
-import com.android.internal.R;
-
-final class SMSDispatcher extends Handler {
- private static final String TAG = "GSM";
-
- /** Default checking period for SMS sent without uesr permit */
- private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000;
-
- /** Default number of SMS sent in checking period without uesr permit */
- private static final int DEFAULT_SMS_MAX_COUNT = 100;
-
- /** Default timeout for SMS sent query */
- private static final int DEFAULT_SMS_TIMOUEOUT = 6000;
-
- private 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 int EVENT_SEND_SMS_COMPLETE = 2;
-
- /** Retry sending a previously failed SMS message */
- static final int EVENT_SEND_RETRY = 3;
-
- /** Status report received */
- static final int EVENT_NEW_SMS_STATUS_REPORT = 5;
-
- /** SIM storage is full */
- static final int EVENT_SIM_FULL = 6;
-
- /** SMS confirm required */
- static final int EVENT_POST_ALERT = 7;
-
- /** Send the user confirmed SMS */
- static final int EVENT_SEND_CONFIRMED_SMS = 8;
-
- /** Alert is timeout */
- static final int EVENT_ALERT_TIMEOUT = 9;
-
- private final GSMPhone mPhone;
-
- private 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");
-
- /** Maximum number of times to retry sending a failed SMS. */
- private static final int MAX_SEND_RETRIES = 3;
- /** Delay before next send attempt on a failed SMS, in milliseconds. */
- private static final int SEND_RETRY_DELAY = 2000;
- /** single part SMS */
- private static final int SINGLE_PART_SMS = 1;
-
- /**
- * Message reference for a CONCATENATED_8_BIT_REFERENCE or
- * CONCATENATED_16_BIT_REFERENCE message set. Should be
- * incremented for each set of concatenated messages.
- */
- private static int sConcatenatedRef;
-
- private SmsCounter mCounter;
-
- private SmsTracker mSTracker;
-
- /** 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;
-
- /**
- * Implement the per-application based SMS control, which only allows
- * a limit on the number of SMS/MMS messages an app can send in checking
- * period.
- */
- private class SmsCounter {
- private int mCheckPeriod;
- private int mMaxAllowed;
- private HashMap> mSmsStamp;
-
- /**
- * Create SmsCounter
- * @param mMax is the number of SMS allowed without user permit
- * @param mPeriod is the checking period
- */
- SmsCounter(int mMax, int mPeriod) {
- mMaxAllowed = mMax;
- mCheckPeriod = mPeriod;
- mSmsStamp = new HashMap> ();
- }
-
- /**
- * Check to see if an application allow to send new SMS messages
- *
- * @param appName is the application sending sms
- * @param smsWaiting is the number of new sms wants to be sent
- * @return true if application is allowed to send the requested number
- * of new sms messages
- */
- boolean check(String appName, int smsWaiting) {
- if (!mSmsStamp.containsKey(appName)) {
- mSmsStamp.put(appName, new ArrayList());
- }
-
- return isUnderLimit(mSmsStamp.get(appName), smsWaiting);
- }
-
- private boolean isUnderLimit(ArrayList sent, int smsWaiting) {
- Long ct = System.currentTimeMillis();
-
- Log.d(TAG, "SMS send size=" + sent.size() + "time=" + ct);
-
- while (sent.size() > 0 && (ct - sent.get(0)) > mCheckPeriod ) {
- sent.remove(0);
- }
-
- if ( (sent.size() + smsWaiting) <= mMaxAllowed) {
- for (int i = 0; i < smsWaiting; i++ ) {
- sent.add(ct);
- }
- return true;
- }
- return false;
- }
- }
-
- SMSDispatcher(GSMPhone phone) {
- mPhone = phone;
- mWapPush = new WapPushOverSms(phone);
- mContext = phone.getContext();
- mResolver = mContext.getContentResolver();
- mCm = phone.mCM;
- mSTracker = null;
-
- createWakelock();
-
- int check_period = Settings.Gservices.getInt(mResolver,
- Settings.Gservices.SMS_OUTGOING_CEHCK_INTERVAL_MS,
- DEFAULT_SMS_CHECK_PERIOD);
- int max_count = Settings.Gservices.getInt(mResolver,
- Settings.Gservices.SMS_OUTGOING_CEHCK_MAX_COUNT,
- DEFAULT_SMS_MAX_COUNT);
- mCounter = new SmsCounter(max_count, check_period);
-
- mCm.setOnNewSMS(this, EVENT_NEW_SMS, null);
- mCm.setOnSmsStatus(this, EVENT_NEW_SMS_STATUS_REPORT, null);
- mCm.setOnSimSmsFull(this, EVENT_SIM_FULL, null);
-
- // Don't always start message ref at 0.
- sConcatenatedRef = new Random().nextInt(256);
- }
-
- /* TODO: Need to figure out how to keep track of status report routing in a
- * persistent manner. If the phone process restarts (reboot or crash),
- * we will lose this list and any status reports that come in after
- * will be dropped.
- */
- /** Sent messages awaiting a delivery status report. */
- private final ArrayList deliveryPendingList = new ArrayList();
-
- /**
- * Handles events coming from the phone stack. Overridden from handler.
- *
- * @param msg the message to handle
- */
- @Override
- public void handleMessage(Message msg) {
- AsyncResult ar;
-
- switch (msg.what) {
- case EVENT_NEW_SMS:
- // A new SMS has been received by the device
- if (Config.LOGD) {
- Log.d(TAG, "New SMS Message Received");
- }
-
- SmsMessage sms;
-
- ar = (AsyncResult) msg.obj;
-
- // FIXME unit test leaves cm == null. this should change
- if (mCm != null) {
- // FIXME only acknowledge on store
- mCm.acknowledgeLastIncomingSMS(true, null);
- }
-
- if (ar.exception != null) {
- Log.e(TAG, "Exception processing incoming SMS. Exception:" + ar.exception);
- return;
- }
-
- sms = (SmsMessage) ar.result;
- dispatchMessage(sms);
-
- break;
-
- case EVENT_SEND_SMS_COMPLETE:
- // An outbound SMS has been sucessfully transferred, or failed.
- handleSendComplete((AsyncResult) msg.obj);
- break;
-
- case EVENT_SEND_RETRY:
- sendSms((SmsTracker) msg.obj);
- break;
-
- case EVENT_NEW_SMS_STATUS_REPORT:
- handleStatusReport((AsyncResult)msg.obj);
- break;
-
- case EVENT_SIM_FULL:
- handleSimFull();
- break;
-
- case EVENT_POST_ALERT:
- handleReachSentLimit((SmsTracker)(msg.obj));
- break;
-
- case EVENT_ALERT_TIMEOUT:
- ((AlertDialog)(msg.obj)).dismiss();
- msg.obj = null;
- mSTracker = null;
- break;
-
- case EVENT_SEND_CONFIRMED_SMS:
- if (mSTracker!=null) {
- if (isMultipartTracker(mSTracker)) {
- sendMultipartSms(mSTracker);
- } else {
- sendSms(mSTracker);
- }
- mSTracker = null;
- }
- break;
- }
- }
-
- 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() {
- // broadcast SIM_FULL intent
- Intent intent = new Intent(Intents.SIM_FULL_ACTION);
- sendBroadcast(intent, "android.permission.RECEIVE_SMS");
- }
-
- /**
- * Called when a status report is received. This should correspond to
- * a previously successful SEND.
- *
- * @param ar AsyncResult passed into the message handler. ar.result should
- * be a String representing the status report PDU, as ASCII hex.
- */
- private void handleStatusReport(AsyncResult ar) {
- 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);
- }
- }
-
- /**
- * Called when SMS send completes. Broadcasts a sentIntent on success.
- * On failure, either sets up retries or broadcasts a sentIntent with
- * the failure in the result code.
- *
- * @param ar AsyncResult passed into the message handler. ar.result should
- * an SmsResponse instance if send was successful. ar.userObj
- * should be an SmsTracker instance.
- */
- private void handleSendComplete(AsyncResult ar) {
- SmsTracker tracker = (SmsTracker) ar.userObj;
- PendingIntent sentIntent = tracker.mSentIntent;
-
- if (ar.exception == null) {
- if (Config.LOGD) {
- Log.d(TAG, "SMS send complete. Broadcasting "
- + "intent: " + sentIntent);
- }
-
- if (tracker.mDeliveryIntent != null) {
- // Expecting a status report. Add it to the list.
- int messageRef = ((SmsResponse)ar.result).messageRef;
- tracker.mMessageRef = messageRef;
- deliveryPendingList.add(tracker);
- }
-
- if (sentIntent != null) {
- try {
- sentIntent.send(Activity.RESULT_OK);
- } catch (CanceledException ex) {}
- }
- } else {
- if (Config.LOGD) {
- Log.d(TAG, "SMS send failed");
- }
-
- int ss = mPhone.getServiceState().getState();
-
- if (ss != ServiceState.STATE_IN_SERVICE) {
- handleNotInService(ss, tracker);
- } else if ((((CommandException)(ar.exception)).getCommandError()
- == CommandException.Error.SMS_FAIL_RETRY) &&
- tracker.mRetryCount < MAX_SEND_RETRIES) {
- // Retry after a delay if needed.
- // TODO: According to TS 23.040, 9.2.3.6, we should resend
- // with the same TP-MR as the failed message, and
- // TP-RD set to 1. However, we don't have a means of
- // knowing the MR for the failed message (EF_SMSstatus
- // may or may not have the MR corresponding to this
- // message, depending on the failure). Also, in some
- // implementations this retry is handled by the baseband.
- tracker.mRetryCount++;
- Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
- sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
- } else if (tracker.mSentIntent != null) {
- // Done retrying; return an error to the app.
- try {
- tracker.mSentIntent.send(SmsManager.RESULT_ERROR_GENERIC_FAILURE);
- } catch (CanceledException ex) {}
- }
- }
- }
-
- /**
- * Handles outbound message when the phone is not in service.
- *
- * @param ss Current service state. Valid values are:
- * OUT_OF_SERVICE
- * EMERGENCY_ONLY
- * POWER_OFF
- * @param tracker An SmsTracker for the current message.
- */
- private void handleNotInService(int ss, SmsTracker tracker) {
- if (tracker.mSentIntent != null) {
- try {
- if (ss == ServiceState.STATE_POWER_OFF) {
- tracker.mSentIntent.send(SmsManager.RESULT_ERROR_RADIO_OFF);
- } else {
- tracker.mSentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE);
- }
- } catch (CanceledException ex) {}
- }
- }
-
- /**
- * Dispatches an incoming SMS messages.
- *
- * @param sms the incoming message from the phone
- */
- /* package */ void dispatchMessage(SmsMessage sms) {
-
- // 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,
- int sequence, int count, int destinationPort) {
- // Lookup all other related parts
- StringBuilder where = new StringBuilder("reference_number =");
- where.append(referenceNumber);
- where.append(" AND address = ?");
- String[] whereArgs = new String[] {sms.getOriginatingAddress()};
-
- byte[][] pdus = null;
- Cursor cursor = null;
- try {
- cursor = mResolver.query(mRawUri, RAW_PROJECTION, where.toString(), whereArgs, null);
- int cursorCount = cursor.getCount();
- if (cursorCount != count - 1) {
- // We don't have all the parts yet, store this one away
- ContentValues values = new ContentValues();
- values.put("date", new Long(sms.getTimestampMillis()));
- values.put("pdu", HexDump.toHexString(sms.getPdu()));
- values.put("address", sms.getOriginatingAddress());
- values.put("reference_number", referenceNumber);
- values.put("count", count);
- values.put("sequence", sequence);
- if (destinationPort != -1) {
- values.put("destination_port", destinationPort);
- }
- mResolver.insert(mRawUri, values);
-
- return;
- }
-
- // All the parts are in place, deal with them
- int pduColumn = cursor.getColumnIndex("pdu");
- int sequenceColumn = cursor.getColumnIndex("sequence");
-
- pdus = new byte[count][];
- for (int i = 0; i < cursorCount; i++) {
- cursor.moveToNext();
- int cursorSequence = (int)cursor.getLong(sequenceColumn);
- pdus[cursorSequence - 1] = HexDump.hexStringToByteArray(
- cursor.getString(pduColumn));
- }
- // This one isn't in the DB, so add it
- pdus[sequence - 1] = sms.getPdu();
-
- // Remove the parts from the database
- mResolver.delete(mRawUri, where.toString(), whereArgs);
- } catch (SQLException e) {
- Log.e(TAG, "Can't access multipart SMS database", e);
- return; // TODO: NACK the message or something, don't just discard.
- } finally {
- if (cursor != null) cursor.close();
- }
-
- // Dispatch the PDUs to applications
- switch (destinationPort) {
- case SmsHeader.PORT_WAP_PUSH: {
- // Build up the data stream
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- for (int i = 0; i < count; i++) {
- SmsMessage msg = SmsMessage.createFromPdu(pdus[i]);
- byte[] data = msg.getUserData();
- output.write(data, 0, data.length);
- }
-
- // Handle the PUSH
- mWapPush.dispatchWapPdu(output.toByteArray());
- break;
- }
-
- case -1:
- // The messages were not sent to a port
- dispatchPdus(pdus);
- break;
-
- default:
- // The messages were sent to a port, so concoct a URI for it
- dispatchPortAddressedPdus(pdus, destinationPort);
- break;
- }
- }
-
- /**
- * Dispatches standard PDUs to interested applications
- *
- * @param pdus The raw PDUs making up the message
- */
- private void dispatchPdus(byte[][] pdus) {
- Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
- intent.putExtra("pdus", pdus);
- sendBroadcast(intent, "android.permission.RECEIVE_SMS");
- }
-
- /**
- * Dispatches port addressed PDUs to interested applications
- *
- * @param pdus The raw PDUs making up the message
- * @param port The destination port of the messages
- */
- private void dispatchPortAddressedPdus(byte[][] pdus, int port) {
- 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");
- }
-
-
- /**
- * 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 ArrayList
of strings that, in order,
- * comprise the original message
- * @param sentIntents if not null, an ArrayList
of
- * PendingIntent
s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be Activity.RESULT_OK for success,
- * or one of these errors:
- * RESULT_ERROR_GENERIC_FAILURE
- * RESULT_ERROR_RADIO_OFF
- * RESULT_ERROR_NULL_PDU
.
- * 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 ArrayList
of
- * PendingIntent
s (one for each message part) that is
- * broadcast when the corresponding message part has been delivered
- * to the recipient. The raw pdu of the status report is in the
- * extended data ("pdu").
- */
- void sendMultipartText(String destinationAddress, String scAddress, ArrayList parts,
- ArrayList sentIntents, ArrayList 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 map = new HashMap();
- 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 ArrayList
of strings that, in order,
- * comprise the original message
- * @param sentIntents if not null, an ArrayList
of
- * PendingIntent
s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be Activity.RESULT_OK for success,
- * or one of these errors:
- * RESULT_ERROR_GENERIC_FAILURE
- * RESULT_ERROR_RADIO_OFF
- * RESULT_ERROR_NULL_PDU
.
- * @param deliveryIntents if not null, an ArrayList
of
- * PendingIntent
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 parts,
- ArrayList sentIntents,
- ArrayList 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 map = new HashMap();
- map.put("smsc", pdus.encodedScAddress);
- map.put("pdu", pdus.encodedMessage);
-
- SmsTracker tracker = new SmsTracker(map, sentIntent,
- deliveryIntent);
- sendSms(tracker);
- }
- }
-
- /**
- * Send a SMS
- *
- * @param smsc the SMSC to send the message through, or NULL for the
- * defatult SMSC
- * @param pdu the raw PDU to send
- * @param sentIntent if not NULL this Intent
is
- * broadcast when the message is sucessfully sent, or failed.
- * The result code will be Activity.RESULT_OK for success,
- * or one of these errors:
- * RESULT_ERROR_GENERIC_FAILURE
- * RESULT_ERROR_RADIO_OFF
- * RESULT_ERROR_NULL_PDU
.
- * 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 Intent
is
- * broadcast when the message is delivered to the recipient. The
- * raw pdu of the status report is in the extended data ("pdu").
- */
- void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
- PendingIntent deliveryIntent) {
- if (pdu == null) {
- if (sentIntent != null) {
- try {
- sentIntent.send(SmsManager.RESULT_ERROR_NULL_PDU);
- } catch (CanceledException ex) {}
- }
- return;
- }
-
- HashMap map = new HashMap();
- map.put("smsc", smsc);
- map.put("pdu", pdu);
-
- SmsTracker tracker = new SmsTracker(map, sentIntent,
- deliveryIntent);
- int ss = mPhone.getServiceState().getState();
-
- if (ss != ServiceState.STATE_IN_SERVICE) {
- handleNotInService(ss, tracker);
- } else {
- String appName = getAppNameByIntent(sentIntent);
- if (mCounter.check(appName, SINGLE_PART_SMS)) {
- sendSms(tracker);
- } else {
- sendMessage(obtainMessage(EVENT_POST_ALERT, tracker));
- }
- }
- }
-
- /**
- * Post an alert while SMS needs user confirm.
- *
- * An SmsTracker for the current message.
- */
- private void handleReachSentLimit(SmsTracker tracker) {
-
- Resources r = Resources.getSystem();
-
- String appName = getAppNameByIntent(tracker.mSentIntent);
-
- AlertDialog d = new AlertDialog.Builder(mContext)
- .setTitle(r.getString(R.string.sms_control_title))
- .setMessage(appName + " " + r.getString(R.string.sms_control_message))
- .setPositiveButton(r.getString(R.string.sms_control_yes), mListener)
- .setNegativeButton(r.getString(R.string.sms_control_no), null)
- .create();
-
- d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
- d.show();
-
- mSTracker = tracker;
- sendMessageDelayed ( obtainMessage(EVENT_ALERT_TIMEOUT, d),
- DEFAULT_SMS_TIMOUEOUT);
- }
-
- private String getAppNameByIntent(PendingIntent intent) {
- Resources r = Resources.getSystem();
- return (intent != null) ? intent.getTargetPackage()
- : r.getString(R.string.sms_control_default_app_name);
- }
-
- /**
- * Send the message along to the radio.
- *
- * @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);
- }
-
- /**
- * 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 parts;
- ArrayList sentIntents;
- ArrayList deliveryIntents;
-
- HashMap map = tracker.mData;
-
- String destinationAddress = (String) map.get("destination");
- String scAddress = (String) map.get("scaddress");
-
- parts = (ArrayList) map.get("parts");
- sentIntents = (ArrayList) map.get("sentIntents");
- deliveryIntents = (ArrayList) map.get("deliveryIntents");
-
- sendMultipartTextWithPermit(destinationAddress,
- scAddress, parts, sentIntents, deliveryIntents);
-
- }
-
- /**
- * Check if a SmsTracker holds multi-part Sms
- *
- * @param tracker a SmsTracker could hold a multi-part Sms
- * @return true for tracker holds Multi-parts Sms
- */
- private boolean isMultipartTracker (SmsTracker tracker) {
- 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;
-
- PendingIntent mSentIntent;
- PendingIntent mDeliveryIntent;
-
- SmsTracker(HashMap data, PendingIntent sentIntent,
- PendingIntent deliveryIntent) {
- mData = data;
- mSentIntent = sentIntent;
- mDeliveryIntent = deliveryIntent;
- mRetryCount = 0;
- }
-
- }
-
- private DialogInterface.OnClickListener mListener =
- new DialogInterface.OnClickListener() {
-
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- Log.d(TAG, "click YES to send out sms");
- sendMessage(obtainMessage(EVENT_SEND_CONFIRMED_SMS));
- }
- }
- };
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
deleted file mode 100644
index e336d7d..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/ServiceStateTracker.java
+++ /dev/null
@@ -1,1696 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE;
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ALPHA;
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISROAMING;
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_NUMERIC;
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_ALPHA;
-import static com.android.internal.telephony.TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC;
-
-import com.android.internal.telephony.SimCard;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.gsm.DataConnectionTracker.State;
-
-import android.app.AlarmManager;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.Registrant;
-import android.os.RegistrantList;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.provider.Checkin;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.provider.Telephony.Intents;
-import android.telephony.gsm.GsmCellLocation;
-import android.telephony.ServiceState;
-import android.text.TextUtils;
-import android.util.Config;
-import android.util.Log;
-import android.util.TimeUtils;
-import android.util.EventLog;
-
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.TimeZone;
-
-/**
- * {@hide}
- */
-final class ServiceStateTracker extends Handler
-{
- /**
- * The access technology currently in use:
- * 0 = unknown
- * 1 = GPRS only
- * 2 = EDGE
- * 3 = UMTS
- */
- static final int DATA_ACCESS_UNKNOWN = 0;
- static final int DATA_ACCESS_GPRS = 1;
- static final int DATA_ACCESS_EDGE = 2;
- static final int DATA_ACCESS_UMTS = 3;
-
- static final int MAX_NUM_DATA_STATE_READS = 15;
- static final int DATA_STATE_POLL_SLEEP_MS = 100;
-
- //***** Instance Variables
-
- GSMPhone phone;
- CommandsInterface cm;
-
- ServiceState ss;
- ServiceState newSS;
- GsmCellLocation cellLoc;
- GsmCellLocation newCellLoc;
- int mPreferredNetworkType;
- RestrictedState rs;
-
- int rssi = 99; // signal strength 0-31, 99=unknown
- // That's "received signal strength indication" fyi
-
- int[] pollingContext; // 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
-
- boolean mDesiredPowerState;
-
- 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
-
- private int gprsState = ServiceState.STATE_OUT_OF_SERVICE;
- private int newGPRSState = ServiceState.STATE_OUT_OF_SERVICE;
-
- /**
- * The access technology currently in use: DATA_ACCESS_
- */
- private int networkType = 0;
- private int newNetworkType = 0;
- /* gsm roaming status solely based on TS 27.007 7.2 CREG */
- private boolean mGsmRoaming = false;
-
- private RegistrantList networkAttachedRegistrants = new RegistrantList();
- private RegistrantList gprsAttachedRegistrants = new RegistrantList();
- private RegistrantList gprsDetachedRegistrants = new RegistrantList();
- private RegistrantList roamingOnRegistrants = new RegistrantList();
- private RegistrantList roamingOffRegistrants = new RegistrantList();
- private RegistrantList psRestrictEnabledRegistrants = new RegistrantList();
- private RegistrantList psRestrictDisabledRegistrants = new RegistrantList();
-
-
- // Sometimes we get the NITZ time before we know what country we are in.
- // Keep the time zone information from the NITZ string so we can fix
- // the time zone once know the country.
- private boolean mNeedFixZone = false;
- private int mZoneOffset;
- private boolean mZoneDst;
- private long mZoneTime;
- private boolean mGotCountryCode = false;
-
- String mSavedTimeZone;
- long mSavedTime;
- long mSavedAtTime;
-
- // We can't register for SIM_RECORDS_LOADED immediately because the
- // SIMRecords object may not be instantiated yet.
- private boolean mNeedToRegForSimLoaded;
-
- // Started the recheck process after finding gprs should registerd but not
- private boolean mStartedGprsRegCheck = false;
- // Already sent the event-log for no gprs register
- private boolean mReportedGprsNoReg = false;
-
- /**
- * The Notification object given to the NotificationManager.
- */
- private Notification mNotification;
-
- // Wake lock used while setting time of day.
- private PowerManager.WakeLock mWakeLock;
- private static final String WAKELOCK_TAG = "ServiceStateTracker";
-
- // Keep track of SPN display rules, so we only broadcast intent if something changes.
- private String curSpn = null;
- private String curPlmn = null;
- private int curSpnRule = 0;
-
- //***** Constants
-
- static final boolean DBG = true;
- static final String LOG_TAG = "GSM";
-
- // signal strength poll rate
- static final int POLL_PERIOD_MILLIS = 20 * 1000;
-
- // waiting period before recheck gprs and voice registration
- static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
-
- // restricted state type
- static final int PS_ENABLED = 1001; // Access Control blocks data service
- static final int PS_DISABLED = 1002; // Access Control enables data service
- static final int CS_ENABLED = 1003; // Access Control blocks all voice/sms service
- static final int CS_DISABLED = 1004; // Access Control enables all voice/sms service
- static final int CS_NORMAL_ENABLED = 1005; // Access Control blocks normal voice/sms service
- static final int CS_EMERGENCY_ENABLED = 1006; // Access Control blocks emergency call service
-
- // notification id
- static final int PS_NOTIFICATION = 888; //id to update and cancel PS restricted
- static final int CS_NOTIFICATION = 999; //id to update and cancel CS restricted
-
- //***** Events
- static final int EVENT_RADIO_STATE_CHANGED = 1;
- static final int EVENT_NETWORK_STATE_CHANGED = 2;
- static final int EVENT_GET_SIGNAL_STRENGTH = 3;
- static final int EVENT_POLL_STATE_REGISTRATION = 4;
- static final int EVENT_POLL_STATE_GPRS = 5;
- static final int EVENT_POLL_STATE_OPERATOR = 6;
- static final int EVENT_POLL_SIGNAL_STRENGTH = 10;
- static final int EVENT_NITZ_TIME = 11;
- static final int EVENT_SIGNAL_STRENGTH_UPDATE = 12;
- static final int EVENT_RADIO_AVAILABLE = 13;
- static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14;
- static final int EVENT_GET_LOC_DONE = 15;
- static final int EVENT_SIM_RECORDS_LOADED = 16;
- static final int EVENT_SIM_READY = 17;
- static final int EVENT_LOCATION_UPDATES_ENABLED = 18;
- static final int EVENT_GET_PREFERRED_NETWORK_TYPE = 19;
- static final int EVENT_SET_PREFERRED_NETWORK_TYPE = 20;
- static final int EVENT_RESET_PREFERRED_NETWORK_TYPE = 21;
- static final int EVENT_CHECK_REPORT_GPRS = 22;
- static final int EVENT_RESTRICTED_STATE_CHANGED = 23;
-
- //***** Time Zones
-
- private 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.
- private 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
- };
-
- private ContentObserver mAutoTimeObserver = new ContentObserver(new Handler()) {
- @Override
- public void onChange(boolean selfChange) {
- Log.i("ServiceStateTracker", "Auto time state changed");
- revertToNitz();
- }
- };
-
- //***** Constructors
-
- ServiceStateTracker(GSMPhone phone)
- {
- this.phone = phone;
- cm = phone.mCM;
- ss = new ServiceState();
- newSS = new ServiceState();
- cellLoc = new GsmCellLocation();
- newCellLoc = new GsmCellLocation();
- rs = new RestrictedState();
-
- PowerManager powerManager =
- (PowerManager)phone.getContext().getSystemService(Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
-
- cm.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
- cm.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
-
- cm.registerForNetworkStateChanged(this, EVENT_NETWORK_STATE_CHANGED, null);
- cm.setOnNITZTime(this, EVENT_NITZ_TIME, null);
- cm.setOnSignalStrengthUpdate(this, EVENT_SIGNAL_STRENGTH_UPDATE, null);
- cm.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
- cm.registerForSIMReady(this, EVENT_SIM_READY, null);
-
- // system setting property AIRPLANE_MODE_ON is set in Settings.
- int airplaneMode = Settings.System.getInt(
- phone.getContext().getContentResolver(),
- Settings.System.AIRPLANE_MODE_ON, 0);
- mDesiredPowerState = ! (airplaneMode > 0);
-
- ContentResolver cr = phone.getContext().getContentResolver();
- cr.registerContentObserver(
- Settings.System.getUriFor(Settings.System.AUTO_TIME), true,
- mAutoTimeObserver);
- setRssiDefaultValues();
- mNeedToRegForSimLoaded = true;
- }
-
- /**
- * Registration point for transition into GPRS attached.
- * @param h handler to notify
- * @param what what code of message when delivered
- * @param obj placed in Message.obj
- */
- /*protected*/ void registerForGprsAttached(Handler h, int what, Object obj) {
- Registrant r = new Registrant(h, what, obj);
- gprsAttachedRegistrants.add(r);
-
- if (gprsState == ServiceState.STATE_IN_SERVICE) {
- r.notifyRegistrant();
- }
- }
-
- void registerForNetworkAttach(Handler h, int what, Object obj) {
- Registrant r = new Registrant(h, what, obj);
- networkAttachedRegistrants.add(r);
-
- if (ss.getState() == ServiceState.STATE_IN_SERVICE) {
- r.notifyRegistrant();
- }
- }
- /**
- * Registration point for transition into GPRS detached.
- * @param h handler to notify
- * @param what what code of message when delivered
- * @param obj placed in Message.obj
- */
- /*protected*/ void registerForGprsDetached(Handler h, int what, Object obj) {
- Registrant r = new Registrant(h, what, obj);
- gprsDetachedRegistrants.add(r);
-
- if (gprsState == ServiceState.STATE_OUT_OF_SERVICE) {
- r.notifyRegistrant();
- }
- }
-
- /**
- * 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
- */
- void registerForRoamingOn(Handler h, int what, Object obj) {
- Registrant r = new Registrant(h, what, obj);
- roamingOnRegistrants.add(r);
-
- if (ss.getRoaming()) {
- r.notifyRegistrant();
- }
- }
-
- /**
- * 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
- */
- void registerForRoamingOff(Handler h, int what, Object obj) {
- Registrant r = new Registrant(h, what, obj);
- roamingOffRegistrants.add(r);
-
- if (!ss.getRoaming()) {
- r.notifyRegistrant();
- }
- }
-
- /**
- * 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.
- */
- void reRegisterNetwork(Message onComplete) {
- cm.getPreferredNetworkType(
- obtainMessage(EVENT_GET_PREFERRED_NETWORK_TYPE, onComplete));
- }
-
- /**
- * Registration point for transition into packet service restricted zone.
- * @param h handler to notify
- * @param what what code of message when delivered
- * @param obj placed in Message.obj
- */
- void registerForPsRestrictedEnabled(Handler h, int what, Object obj) {
- Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedEnabled ");
- Registrant r = new Registrant(h, what, obj);
- psRestrictEnabledRegistrants.add(r);
-
- if (rs.isPsRestricted()) {
- r.notifyRegistrant();
- }
- }
-
- /**
- * Registration point for transition out of packet service restricted zone.
- * @param h handler to notify
- * @param what what code of message when delivered
- * @param obj placed in Message.obj
- */
- void registerForPsRestrictedDisabled(Handler h, int what, Object obj) {
- Log.d(LOG_TAG, "[DSAC DEB] " + "registerForPsRestrictedDisabled ");
- Registrant r = new Registrant(h, what, obj);
- psRestrictDisabledRegistrants.add(r);
-
- if (rs.isPsRestricted()) {
- r.notifyRegistrant();
- }
- }
-
- //***** Called from GSMPhone
-
- public void
- setRadioPower(boolean power)
- {
- mDesiredPowerState = power;
-
- setPowerStateToDesired();
- }
-
- public void
- getLacAndCid(Message onComplete) {
- cm.getRegistrationState(obtainMessage(
- EVENT_GET_LOC_DONE, onComplete));
- }
-
- /*package*/ void enableLocationUpdates() {
- cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
- }
-
- /*package*/ void disableLocationUpdates() {
- cm.setLocationUpdates(false, null);
- }
- //***** Overridden from Handler
-
- public void
- handleMessage (Message msg)
- {
- AsyncResult ar;
- int[] ints;
- String[] strings;
- Message message;
-
- switch (msg.what) {
- case EVENT_RADIO_AVAILABLE:
- //this is unnecessary
- //setPowerStateToDesired();
- break;
-
- case EVENT_SIM_READY:
- // The SIM is now ready i.e if it was locked
- // it has been unlocked. At this stage, the radio is already
- // powered on.
- if (mNeedToRegForSimLoaded) {
- phone.mSIMRecords.registerForRecordsLoaded(this,
- EVENT_SIM_RECORDS_LOADED, null);
- mNeedToRegForSimLoaded = false;
- }
- // restore the previous network selection.
- phone.restoreSavedNetworkSelection(null);
- pollState();
- // Signal strength polling stops when radio is off
- queueNextSignalStrengthPoll();
- break;
-
- case EVENT_RADIO_STATE_CHANGED:
- // This will do nothing in the radio not
- // available case
- setPowerStateToDesired();
- pollState();
- break;
-
- case EVENT_NETWORK_STATE_CHANGED:
- pollState();
- break;
-
- case EVENT_GET_SIGNAL_STRENGTH:
- // This callback is called when signal strength is polled
- // all by itself
-
- if (!(cm.getRadioState().isOn())) {
- // Polling will continue when radio turns back on
- return;
- }
- ar = (AsyncResult) msg.obj;
- onSignalStrengthResult(ar);
- queueNextSignalStrengthPoll();
-
- break;
-
- case EVENT_GET_LOC_DONE:
- ar = (AsyncResult) msg.obj;
-
- if (ar.exception == null) {
- String states[] = (String[])ar.result;
- int lac = -1;
- int cid = -1;
- if (states.length == 3) {
- try {
- if (states[1] != null && states[1].length() > 0) {
- lac = Integer.parseInt(states[1], 16);
- }
- if (states[2] != null && states[2].length() > 0) {
- cid = Integer.parseInt(states[2], 16);
- }
- } catch (NumberFormatException ex) {
- Log.w(LOG_TAG, "error parsing location: " + ex);
- }
- }
-
- // only update if lac or cid changed
- if (cellLoc.getCid() != cid || cellLoc.getLac() != lac) {
- cellLoc.setLacAndCid(lac, cid);
- phone.notifyLocationChanged();
- }
- }
-
- if (ar.userObj != null) {
- AsyncResult.forMessage(((Message) ar.userObj)).exception
- = ar.exception;
- ((Message) ar.userObj).sendToTarget();
- }
- break;
-
- case EVENT_POLL_STATE_REGISTRATION:
- case EVENT_POLL_STATE_GPRS:
- case EVENT_POLL_STATE_OPERATOR:
- case EVENT_POLL_STATE_NETWORK_SELECTION_MODE:
- ar = (AsyncResult) msg.obj;
-
- handlePollStateResult(msg.what, ar);
- break;
-
- case EVENT_POLL_SIGNAL_STRENGTH:
- // Just poll signal strength...not part of pollState()
-
- cm.getSignalStrength(obtainMessage(EVENT_GET_SIGNAL_STRENGTH));
- break;
-
- case EVENT_NITZ_TIME:
- ar = (AsyncResult) msg.obj;
-
- String nitzString = (String)((Object[])ar.result)[0];
- long nitzReceiveTime = ((Long)((Object[])ar.result)[1]).longValue();
-
- setTimeFromNITZString(nitzString, nitzReceiveTime);
- break;
-
- case EVENT_SIGNAL_STRENGTH_UPDATE:
- // This is a notification from
- // CommandsInterface.setOnSignalStrengthUpdate
-
- ar = (AsyncResult) msg.obj;
-
- // The radio is telling us about signal strength changes
- // we don't have to ask it
- dontPollSignalStrength = true;
-
- onSignalStrengthResult(ar);
- break;
-
- case EVENT_SIM_RECORDS_LOADED:
- updateSpnDisplay();
- break;
-
- case EVENT_LOCATION_UPDATES_ENABLED:
- ar = (AsyncResult) msg.obj;
-
- if (ar.exception == null) {
- getLacAndCid(null);
- }
- break;
-
- case EVENT_SET_PREFERRED_NETWORK_TYPE:
- ar = (AsyncResult) msg.obj;
- // Don't care the result, only use for dereg network (COPS=2)
- message = obtainMessage(EVENT_RESET_PREFERRED_NETWORK_TYPE, ar.userObj);
- cm.setPreferredNetworkType(mPreferredNetworkType, message);
- break;
-
- case EVENT_RESET_PREFERRED_NETWORK_TYPE:
- ar = (AsyncResult) msg.obj;
- if (ar.userObj != null) {
- AsyncResult.forMessage(((Message) ar.userObj)).exception
- = ar.exception;
- ((Message) ar.userObj).sendToTarget();
- }
- break;
-
- case EVENT_GET_PREFERRED_NETWORK_TYPE:
- ar = (AsyncResult) msg.obj;
-
- if (ar.exception == null) {
- mPreferredNetworkType = ((int[])ar.result)[0];
- } else {
- mPreferredNetworkType = Phone.NT_AUTO_TYPE;
- }
-
- message = obtainMessage(EVENT_SET_PREFERRED_NETWORK_TYPE, ar.userObj);
- int toggledNetworkType =
- (mPreferredNetworkType == Phone.NT_AUTO_TYPE) ?
- Phone.NT_GSM_TYPE : Phone.NT_AUTO_TYPE;
-
- cm.setPreferredNetworkType(toggledNetworkType, message);
- break;
-
- case EVENT_CHECK_REPORT_GPRS:
- if (ss != null && !isGprsConsistant(gprsState, ss.getState())) {
-
- // Can't register data sevice while voice service is ok
- // i.e. CREG is ok while CGREG is not
- // possible a network or baseband side error
- int cid = -1;
- GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
- if (loc != null) cid = loc.getCid();
-
- EventLog.List val = new EventLog.List(ss.getOperatorNumeric(), cid);
- EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_CGREG_FAIL, val);
- mReportedGprsNoReg = true;
- }
- mStartedGprsRegCheck = false;
- break;
-
- case EVENT_RESTRICTED_STATE_CHANGED:
- // This is a notification from
- // CommandsInterface.setOnRestrictedStateChanged
-
- Log.d(LOG_TAG, "[DSAC DEB] " + "EVENT_RESTRICTED_STATE_CHANGED");
-
- ar = (AsyncResult) msg.obj;
-
- onRestrictedStateChanged(ar);
- break;
-
- }
- }
-
- //***** Private Instance Methods
-
- private void updateSpnDisplay() {
- int rule = phone.mSIMRecords.getDisplayRule(ss.getOperatorNumeric());
- String spn = phone.mSIMRecords.getServiceProviderName();
- String plmn = ss.getOperatorAlphaLong();
-
- if (rule != curSpnRule
- || !TextUtils.equals(spn, curSpn)
- || !TextUtils.equals(plmn, curPlmn)) {
- boolean showSpn =
- (rule & SIMRecords.SPN_RULE_SHOW_SPN) == SIMRecords.SPN_RULE_SHOW_SPN;
- boolean showPlmn =
- (rule & SIMRecords.SPN_RULE_SHOW_PLMN) == SIMRecords.SPN_RULE_SHOW_PLMN;
- Intent intent = new Intent(Intents.SPN_STRINGS_UPDATED_ACTION);
- intent.putExtra(Intents.EXTRA_SHOW_SPN, showSpn);
- intent.putExtra(Intents.EXTRA_SPN, spn);
- intent.putExtra(Intents.EXTRA_SHOW_PLMN, showPlmn);
- intent.putExtra(Intents.EXTRA_PLMN, plmn);
- phone.getContext().sendStickyBroadcast(intent);
- }
- curSpnRule = rule;
- curSpn = spn;
- curPlmn = plmn;
- }
-
- private void
- setPowerStateToDesired()
- {
- // If we want it on and it's off, turn it on
- if (mDesiredPowerState
- && cm.getRadioState() == CommandsInterface.RadioState.RADIO_OFF
- ) {
- cm.setRadioPower(true, null);
- } else if (!mDesiredPowerState && cm.getRadioState().isOn()) {
- DataConnectionTracker dcTracker = phone.mDataConnection;
- if (! dcTracker.isDataConnectionAsDesired()) {
-
- EventLog.List val = new EventLog.List(
- dcTracker.getStateInString(),
- (dcTracker.getAnyDataEnabled() ? 1 : 0) );
- EventLog.writeEvent(TelephonyEventLog.EVENT_DATA_STATE_RADIO_OFF, val);
- }
- dcTracker.cleanConnectionBeforeRadioOff();
-
- // poll data state up to 15 times, with a 100ms delay
- // totaling 1.5 sec. Normal data disable action will finish in 100ms.
- for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) {
- if (dcTracker.state != State.CONNECTED
- && dcTracker.state != State.DISCONNECTING) {
- Log.d(LOG_TAG, "Data shutdown complete.");
- break;
- }
- SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS);
- }
- // If it's on and available and we want it off..
- cm.setRadioPower(false, null);
- } // Otherwise, we're in the desired state
- }
-
- /** Cancel a pending (if any) pollState() operation */
- private void
- cancelPollState()
- {
- // This will effectively cancel the rest of the poll requests
- pollingContext = new int[1];
- }
-
- /**
- * Handle the result of one of the pollState()-related requests
- */
-
- private void
- handlePollStateResult (int what, AsyncResult ar)
- {
- int ints[];
- String states[];
-
- // Ignore stale requests from last poll
- if (ar.userObj != pollingContext) return;
-
- if (ar.exception != null) {
- CommandException.Error err=null;
-
- if (ar.exception instanceof CommandException) {
- err = ((CommandException)(ar.exception)).getCommandError();
- }
-
- if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
- // Radio has crashed or turned off
- cancelPollState();
- return;
- }
-
- if (!cm.getRadioState().isOn()) {
- // Radio has crashed or turned off
- cancelPollState();
- return;
- }
-
- if (err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW &&
- err != CommandException.Error.OP_NOT_ALLOWED_BEFORE_REG_NW) {
- Log.e(LOG_TAG,
- "RIL implementation has returned an error where it must succeed" +
- ar.exception);
- }
- } else try {
- switch (what) {
- case EVENT_POLL_STATE_REGISTRATION:
- states = (String[])ar.result;
- int lac = -1;
- int cid = -1;
- int regState = -1;
- if (states.length > 0) {
- try {
- regState = Integer.parseInt(states[0]);
- if (states.length == 3) {
- if (states[1] != null && states[1].length() > 0) {
- lac = Integer.parseInt(states[1], 16);
- }
- if (states[2] != null && states[2].length() > 0) {
- cid = Integer.parseInt(states[2], 16);
- }
- }
- } catch (NumberFormatException ex) {
- Log.w(LOG_TAG, "error parsing RegistrationState: " + ex);
- }
- }
-
- mGsmRoaming = regCodeIsRoaming(regState);
- newSS.setState (regCodeToServiceState(regState));
-
- // LAC and CID are -1 if not avail
- newCellLoc.setLacAndCid(lac, cid);
- break;
-
- case EVENT_POLL_STATE_GPRS:
- states = (String[])ar.result;
-
- int type = 0;
- regState = -1;
- if (states.length > 0) {
- try {
- regState = Integer.parseInt(states[0]);
-
- // states[3] (if present) is the current radio technology
- if (states.length >= 4 && states[3] != null) {
- type = Integer.parseInt(states[3]);
- }
- } catch (NumberFormatException ex) {
- Log.w(LOG_TAG, "error parsing GprsRegistrationState: " + ex);
- }
- }
- newGPRSState = regCodeToServiceState(regState);
- newNetworkType = type;
- break;
-
- case EVENT_POLL_STATE_OPERATOR:
- String opNames[] = (String[])ar.result;
-
- if (opNames != null && opNames.length >= 3) {
- newSS.setOperatorName (
- opNames[0], opNames[1], opNames[2]);
- }
- break;
-
- case EVENT_POLL_STATE_NETWORK_SELECTION_MODE:
- ints = (int[])ar.result;
- newSS.setIsManualSelection(ints[0] == 1);
- break;
- }
-
- } catch (RuntimeException ex) {
- Log.e(LOG_TAG, "Exception while polling service state. "
- + "Probably malformed RIL response.", ex);
- }
-
- pollingContext[0]--;
-
- if (pollingContext[0] == 0) {
- newSS.setRoaming(isRoamingBetweenOperators(mGsmRoaming, newSS));
- pollStateDone();
- }
-
- }
-
- private void
- setRssiDefaultValues()
- {
- rssi = 99;
- }
-
- /**
- * A complete "service state" from our perspective is
- * composed of a handful of separate requests to the radio.
- *
- * We make all of these requests at once, but then abandon them
- * and start over again if the radio notifies us that some
- * event has changed
- */
-
- private void
- pollState()
- {
- pollingContext = new int[1];
- pollingContext[0] = 0;
-
- switch (cm.getRadioState()) {
- case RADIO_UNAVAILABLE:
- newSS.setStateOutOfService();
- newCellLoc.setStateInvalid();
- setRssiDefaultValues();
- mGotCountryCode = false;
-
- pollStateDone();
- break;
-
-
- case RADIO_OFF:
- newSS.setStateOff();
- newCellLoc.setStateInvalid();
- setRssiDefaultValues();
- mGotCountryCode = false;
-
- pollStateDone();
- break;
-
- default:
- // Issue all poll-related commands at once
- // then count down the responses, which
- // are allowed to arrive out-of-order
-
- pollingContext[0]++;
- cm.getOperator(
- obtainMessage(
- EVENT_POLL_STATE_OPERATOR, pollingContext));
-
- pollingContext[0]++;
- cm.getGPRSRegistrationState(
- obtainMessage(
- EVENT_POLL_STATE_GPRS, pollingContext));
-
- pollingContext[0]++;
- cm.getRegistrationState(
- obtainMessage(
- EVENT_POLL_STATE_REGISTRATION, pollingContext));
-
- pollingContext[0]++;
- cm.getNetworkSelectionMode(
- obtainMessage(
- EVENT_POLL_STATE_NETWORK_SELECTION_MODE, pollingContext));
- break;
- }
- }
-
- private static String networkTypeToString(int type) {
- String ret = "unknown";
-
- switch (type) {
- case DATA_ACCESS_GPRS:
- ret = "GPRS";
- break;
- case DATA_ACCESS_EDGE:
- ret = "EDGE";
- break;
- case DATA_ACCESS_UMTS:
- ret = "UMTS";
- break;
- }
-
- return ret;
- }
-
- private void
- pollStateDone()
- {
- if (DBG) {
- Log.d(LOG_TAG, "Poll ServiceState done: " +
- " oldSS=[" + ss + "] newSS=[" + newSS +
- "] oldGprs=" + gprsState + " newGprs=" + newGPRSState +
- " oldType=" + networkTypeToString(networkType) +
- " newType=" + networkTypeToString(newNetworkType));
- }
-
- boolean hasRegistered =
- ss.getState() != ServiceState.STATE_IN_SERVICE
- && newSS.getState() == ServiceState.STATE_IN_SERVICE;
-
- boolean hasDeregistered =
- ss.getState() == ServiceState.STATE_IN_SERVICE
- && newSS.getState() != ServiceState.STATE_IN_SERVICE;
-
- boolean hasGprsAttached =
- gprsState != ServiceState.STATE_IN_SERVICE
- && newGPRSState == ServiceState.STATE_IN_SERVICE;
-
- boolean hasGprsDetached =
- gprsState == ServiceState.STATE_IN_SERVICE
- && newGPRSState != ServiceState.STATE_IN_SERVICE;
-
- boolean hasNetworkTypeChanged = networkType != newNetworkType;
-
- boolean hasChanged = !newSS.equals(ss);
-
- boolean hasRoamingOn = !ss.getRoaming() && newSS.getRoaming();
-
- boolean hasRoamingOff = ss.getRoaming() && !newSS.getRoaming();
-
- boolean hasLocationChanged = !newCellLoc.equals(cellLoc);
-
- ServiceState tss;
- tss = ss;
- ss = newSS;
- newSS = tss;
- // clean slate for next time
- newSS.setStateOutOfService();
-
- GsmCellLocation tcl = cellLoc;
- cellLoc = newCellLoc;
- newCellLoc = tcl;
-
- gprsState = newGPRSState;
- networkType = newNetworkType;
-
- newSS.setStateOutOfService(); // clean slate for next time
-
- if (hasNetworkTypeChanged) {
- phone.setSystemProperty(PROPERTY_DATA_NETWORK_TYPE,
- networkTypeToString(networkType));
- }
-
- if (hasRegistered) {
- Checkin.updateStats(phone.getContext().getContentResolver(),
- Checkin.Stats.Tag.PHONE_GSM_REGISTERED, 1, 0.0);
- networkAttachedRegistrants.notifyRegistrants();
- }
-
- if (hasChanged) {
- String operatorNumeric;
-
- phone.setSystemProperty(PROPERTY_OPERATOR_ALPHA,
- ss.getOperatorAlphaLong());
-
- operatorNumeric = ss.getOperatorNumeric();
- phone.setSystemProperty(PROPERTY_OPERATOR_NUMERIC, operatorNumeric);
-
- if (operatorNumeric == null) {
- phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, "");
- } else {
- String iso = "";
- try{
- iso = MccTable.countryCodeForMcc(Integer.parseInt(
- operatorNumeric.substring(0,3)));
- } catch ( NumberFormatException ex){
- Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
- } catch ( StringIndexOutOfBoundsException ex) {
- Log.w(LOG_TAG, "countryCodeForMcc error" + ex);
- }
-
- phone.setSystemProperty(PROPERTY_OPERATOR_ISO_COUNTRY, iso);
- mGotCountryCode = true;
-
- if (mNeedFixZone) {
- TimeZone zone = null;
- // If the offset is (0, false) and the timezone property
- // is set, use the timezone property rather than
- // GMT.
- String zoneName = SystemProperties.get(TIMEZONE_PROPERTY);
- if ((mZoneOffset == 0) && (mZoneDst == false) &&
- (zoneName != null) && (zoneName.length() > 0) &&
- (Arrays.binarySearch(GMT_COUNTRY_CODES, iso) < 0)) {
- zone = TimeZone.getDefault();
- // For NITZ string without timezone,
- // need adjust time to reflect default timezone setting
- long tzOffset;
- tzOffset = zone.getOffset(System.currentTimeMillis());
- if (getAutoTime()) {
- setAndBroadcastNetworkSetTime(System.currentTimeMillis() - tzOffset);
- } else {
- // Adjust the saved NITZ time to account for tzOffset.
- mSavedTime = mSavedTime - tzOffset;
- }
- } else if (iso.equals("")){
- // Country code not found. This is likely a test network.
- // Get a TimeZone based only on the NITZ parameters (best guess).
- zone = getNitzTimeZone(mZoneOffset, mZoneDst, mZoneTime);
- } else {
- zone = TimeUtils.getTimeZone(mZoneOffset,
- mZoneDst, mZoneTime, iso);
- }
-
- mNeedFixZone = false;
-
- if (zone != null) {
- if (getAutoTime()) {
- setAndBroadcastNetworkSetTimeZone(zone.getID());
- }
- saveNitzTimeZone(zone.getID());
- }
- }
- }
-
- phone.setSystemProperty(PROPERTY_OPERATOR_ISROAMING,
- ss.getRoaming() ? "true" : "false");
-
- updateSpnDisplay();
- phone.notifyServiceStateChanged(ss);
- }
-
- if (hasGprsAttached) {
- gprsAttachedRegistrants.notifyRegistrants();
- }
-
- if (hasGprsDetached) {
- gprsDetachedRegistrants.notifyRegistrants();
- }
-
- if (hasNetworkTypeChanged) {
- phone.notifyDataConnection(null);
- }
-
- if (hasRoamingOn) {
- roamingOnRegistrants.notifyRegistrants();
- }
-
- if (hasRoamingOff) {
- roamingOffRegistrants.notifyRegistrants();
- }
-
- if (hasLocationChanged) {
- phone.notifyLocationChanged();
- }
-
- if (! isGprsConsistant(gprsState, ss.getState())) {
- if (!mStartedGprsRegCheck && !mReportedGprsNoReg) {
- mStartedGprsRegCheck = true;
-
- int check_period = Settings.Gservices.getInt(
- phone.getContext().getContentResolver(),
- Settings.Gservices.GPRS_REGISTER_CHECK_PERIOD_MS,
- DEFAULT_GPRS_CHECK_PERIOD_MILLIS);
- sendMessageDelayed(obtainMessage(EVENT_CHECK_REPORT_GPRS),
- check_period);
- }
- } else {
- mReportedGprsNoReg = false;
- }
- }
-
- /**
- * Check if GPRS got registred while voice is registered
- *
- * @param gprsState for GPRS registration state, i.e. CGREG in GSM
- * @param serviceState for voice registration state, i.e. CREG in GSM
- * @return false if device only register to voice but not gprs
- */
- private boolean isGprsConsistant (int gprsState, int serviceState) {
- return !((serviceState == ServiceState.STATE_IN_SERVICE) &&
- (gprsState != ServiceState.STATE_IN_SERVICE));
- }
-
- /**
- * Returns a TimeZone object based only on parameters from the NITZ string.
- */
- private TimeZone getNitzTimeZone(int offset, boolean dst, long when) {
- TimeZone guess = findTimeZone(offset, dst, when);
- if (guess == null) {
- // Couldn't find a proper timezone. Perhaps the DST data is wrong.
- guess = findTimeZone(offset, !dst, when);
- }
- if (DBG) {
- Log.d(LOG_TAG, "getNitzTimeZone returning "
- + (guess == null ? guess : guess.getID()));
- }
- return guess;
- }
-
- private TimeZone findTimeZone(int offset, boolean dst, long when) {
- int rawOffset = offset;
- if (dst) {
- rawOffset -= 3600000;
- }
- String[] zones = TimeZone.getAvailableIDs(rawOffset);
- TimeZone guess = null;
- Date d = new Date(when);
- for (String zone : zones) {
- TimeZone tz = TimeZone.getTimeZone(zone);
- if (tz.getOffset(when) == offset &&
- tz.inDaylightTime(d) == dst) {
- guess = tz;
- break;
- }
- }
-
- return guess;
- }
-
- private void
- queueNextSignalStrengthPoll()
- {
- if (dontPollSignalStrength) {
- // The radio is telling us about signal strength changes
- // we don't have to ask it
- return;
- }
-
- Message msg;
-
- msg = obtainMessage();
- msg.what = EVENT_POLL_SIGNAL_STRENGTH;
-
- long nextTime;
-
- // TODO Done't poll signal strength if screen is off
- sendMessageDelayed(msg, POLL_PERIOD_MILLIS);
- }
-
- /**
- * send signal-strength-changed notification if rssi changed
- * Called both for solicited and unsolicited signal stength updates
- */
- private void
- onSignalStrengthResult(AsyncResult ar)
- {
- int oldRSSI = rssi;
-
- if (ar.exception != null) {
- // 99 = unknown
- // most likely radio is resetting/disconnected
- rssi = 99;
- } else {
- int[] ints = (int[])ar.result;
-
- // bug 658816 seems to be a case where the result is 0-length
- if (ints.length != 0) {
- rssi = ints[0];
- } else {
- Log.e(LOG_TAG, "Bogus signal strength response");
- rssi = 99;
- }
- }
-
- if (rssi != oldRSSI) {
- phone.notifySignalStrength();
- }
- }
-
- /**
- * Set restricted state based on the OnRestrictedStateChanged notification
- * If any voice or packet restricted state changes, trigger a UI
- * notification and notify registrants when sim is ready.
- *
- * @param ar an int value of RIL_RESTRICTED_STATE_*
- */
- private void onRestrictedStateChanged(AsyncResult ar)
- {
- Log.d(LOG_TAG, "[DSAC DEB] " + "onRestrictedStateChanged");
- RestrictedState newRs = new RestrictedState();
-
- Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at enter "+ rs);
-
- if (ar.exception == null) {
- int[] ints = (int[])ar.result;
- int state = ints[0];
-
- newRs.setCsEmergencyRestricted(
- ((state & RILConstants.RIL_RESTRICTED_STATE_CS_EMERGENCY) != 0) ||
- ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
-
-
- //ignore the normal call and data restricted state before SIM READY
- if (phone.getSimCard().getState() == SimCard.State.READY){
- newRs.setCsNormalRestricted(
- ((state & RILConstants.RIL_RESTRICTED_STATE_CS_NORMAL) != 0) ||
- ((state & RILConstants.RIL_RESTRICTED_STATE_CS_ALL) != 0) );
- newRs.setPsRestricted(
- (state & RILConstants.RIL_RESTRICTED_STATE_PS_ALL)!= 0);
- }
-
- Log.d(LOG_TAG, "[DSAC DEB] " + "new rs "+ newRs);
-
- if (!rs.isPsRestricted() && newRs.isPsRestricted()) {
- psRestrictEnabledRegistrants.notifyRegistrants();
- setNotification(PS_ENABLED);
- } else if (rs.isPsRestricted() && !newRs.isPsRestricted()) {
- psRestrictDisabledRegistrants.notifyRegistrants();
- setNotification(PS_DISABLED);
- }
-
- /**
- * There are two kind of cs restriction, normal and emergency. So
- * there are 4 x 4 combinations in current and new restricted states
- * and we only need to notify when state is changed.
- */
- if (rs.isCsRestricted()) {
- if (!newRs.isCsRestricted()) {
- // remove all restriction
- setNotification(CS_DISABLED);
- } else if (!newRs.isCsNormalRestricted()) {
- // remove normal restriction
- setNotification(CS_EMERGENCY_ENABLED);
- } else if (!newRs.isCsEmergencyRestricted()) {
- // remove emergency restriction
- setNotification(CS_NORMAL_ENABLED);
- }
- } else if (rs.isCsEmergencyRestricted() && !rs.isCsNormalRestricted()) {
- if (!newRs.isCsRestricted()) {
- // remove all restriction
- setNotification(CS_DISABLED);
- } else if (newRs.isCsRestricted()) {
- // enable all restriction
- setNotification(CS_ENABLED);
- } else if (newRs.isCsNormalRestricted()) {
- // remove emergency restriction and enable normal restriction
- setNotification(CS_NORMAL_ENABLED);
- }
- } else if (!rs.isCsEmergencyRestricted() && rs.isCsNormalRestricted()) {
- if (!newRs.isCsRestricted()) {
- // remove all restriction
- setNotification(CS_DISABLED);
- } else if (newRs.isCsRestricted()) {
- // enable all restriction
- setNotification(CS_ENABLED);
- } else if (newRs.isCsEmergencyRestricted()) {
- // remove normal restriction and enable emergency restriction
- setNotification(CS_EMERGENCY_ENABLED);
- }
- } else {
- if (newRs.isCsRestricted()) {
- // enable all restriction
- setNotification(CS_ENABLED);
- } else if (newRs.isCsEmergencyRestricted()) {
- // enable emergency restriction
- setNotification(CS_EMERGENCY_ENABLED);
- } else if (newRs.isCsNormalRestricted()) {
- // enable normal restriction
- setNotification(CS_NORMAL_ENABLED);
- }
- }
-
- rs = newRs;
- }
- Log.d(LOG_TAG, "[DSAC DEB] " + "current rs at return "+ rs);
- }
-
- /** code is registration state 0-5 from TS 27.007 7.2 */
- private int
- regCodeToServiceState(int code)
- {
- switch (code) {
- case 0:
- case 2: // 2 is "searching"
- case 3: // 3 is "registration denied"
- case 4: // 4 is "unknown" no vaild in current baseband
- return ServiceState.STATE_OUT_OF_SERVICE;
-
- case 1:
- return ServiceState.STATE_IN_SERVICE;
-
- case 5:
- // in service, roam
- return ServiceState.STATE_IN_SERVICE;
-
- default:
- Log.w(LOG_TAG, "unexpected service state " + code);
- return ServiceState.STATE_OUT_OF_SERVICE;
- }
- }
-
-
- /**
- * code is registration state 0-5 from TS 27.007 7.2
- * returns true if registered roam, false otherwise
- */
- private boolean
- regCodeIsRoaming (int code)
- {
- // 5 is "in service -- roam"
- return 5 == code;
- }
-
- /**
- * Set roaming state when gsmRoaming is true and, if operator mcc is the
- * same as sim mcc, ons is different from spn
- * @param gsmRoaming TS 27.007 7.2 CREG registered roaming
- * @param s ServiceState hold current ons
- * @return true for roaming state set
- */
- private
- boolean isRoamingBetweenOperators(boolean gsmRoaming, ServiceState s) {
- String spn = SystemProperties.get(PROPERTY_SIM_OPERATOR_ALPHA, "empty");
-
- String onsl = s.getOperatorAlphaLong();
- String onss = s.getOperatorAlphaShort();
-
- boolean equalsOnsl = onsl != null && spn.equals(onsl);
- boolean equalsOnss = onss != null && spn.equals(onss);
-
- String simNumeric = SystemProperties.get(PROPERTY_SIM_OPERATOR_NUMERIC, "");
- String operatorNumeric = s.getOperatorNumeric();
-
- boolean equalsMcc = true;
- try {
- equalsMcc = simNumeric.substring(0, 3).
- equals(operatorNumeric.substring(0, 3));
- } catch (Exception e){
- }
-
- return gsmRoaming && !(equalsMcc && (equalsOnsl || equalsOnss));
- }
-
- private static
- int twoDigitsAt(String s, int offset)
- {
- int a, b;
-
- a = Character.digit(s.charAt(offset), 10);
- b = Character.digit(s.charAt(offset+1), 10);
-
- if (a < 0 || b < 0) {
-
- throw new RuntimeException("invalid format");
- }
-
- return a*10 + b;
- }
-
- /**
- * @return The current GPRS state. IN_SERVICE is the same as "attached"
- * and OUT_OF_SERVICE is the same as detached.
- */
- /*package*/ int getCurrentGprsState() {
- return gprsState;
- }
-
- /**
- * @return true if phone is camping on a technology (eg UMTS)
- * that could support voice and data simultaniously.
- */
- boolean isConcurrentVoiceAndData() {
- return (networkType == DATA_ACCESS_UMTS);
- }
-
- /**
- * Provides the name of the algorithmic time zone for the specified
- * offset. Taken from TimeZone.java.
- */
- private static String displayNameFor(int off) {
- off = off / 1000 / 60;
-
- char[] buf = new char[9];
- buf[0] = 'G';
- buf[1] = 'M';
- buf[2] = 'T';
-
- if (off < 0) {
- buf[3] = '-';
- off = -off;
- } else {
- buf[3] = '+';
- }
-
- int hours = off / 60;
- int minutes = off % 60;
-
- buf[4] = (char) ('0' + hours / 10);
- buf[5] = (char) ('0' + hours % 10);
-
- buf[6] = ':';
-
- buf[7] = (char) ('0' + minutes / 10);
- buf[8] = (char) ('0' + minutes % 10);
-
- return new String(buf);
- }
-
- /**
- * nitzReceiveTime is time_t that the NITZ time was posted
- */
-
- private
- void setTimeFromNITZString (String nitz, long nitzReceiveTime)
- {
- // "yy/mm/dd,hh:mm:ss(+/-)tz"
- // tz is in number of quarter-hours
-
- long start = SystemClock.elapsedRealtime();
- Log.i(LOG_TAG, "NITZ: " + nitz + "," + nitzReceiveTime +
- " start=" + start + " delay=" + (start - nitzReceiveTime));
-
- try {
- /* NITZ time (hour:min:sec) will be in UTC but it supplies the timezone
- * offset as well (which we won't worry about until later) */
- Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
-
- c.clear();
- c.set(Calendar.DST_OFFSET, 0);
-
- String[] nitzSubs = nitz.split("[/:,+-]");
-
- int year = 2000 + Integer.parseInt(nitzSubs[0]);
- c.set(Calendar.YEAR, year);
-
- // month is 0 based!
- int month = Integer.parseInt(nitzSubs[1]) - 1;
- c.set(Calendar.MONTH, month);
-
- int date = Integer.parseInt(nitzSubs[2]);
- c.set(Calendar.DATE, date);
-
- int hour = Integer.parseInt(nitzSubs[3]);
- c.set(Calendar.HOUR, hour);
-
- int minute = Integer.parseInt(nitzSubs[4]);
- c.set(Calendar.MINUTE, minute);
-
- int second = Integer.parseInt(nitzSubs[5]);
- c.set(Calendar.SECOND, second);
-
- boolean sign = (nitz.indexOf('-') == -1);
-
- int tzOffset = Integer.parseInt(nitzSubs[6]);
-
- int dst = (nitzSubs.length >= 8 ) ? Integer.parseInt(nitzSubs[7])
- : 0;
-
- // The zone offset received from NITZ is for current local time,
- // so DST correction is already applied. Don't add it again.
- //
- // tzOffset += dst * 4;
- //
- // We could unapply it if we wanted the raw offset.
-
- tzOffset = (sign ? 1 : -1) * tzOffset * 15 * 60 * 1000;
-
- TimeZone zone = null;
-
- // As a special extension, the Android emulator appends the name of
- // the host computer's timezone to the nitz string. this is zoneinfo
- // timezone name of the form Area!Location or Area!Location!SubLocation
- // so we need to convert the ! into /
- if (nitzSubs.length >= 9) {
- String tzname = nitzSubs[8].replace('!','/');
- zone = TimeZone.getTimeZone( tzname );
- }
-
- String iso = SystemProperties.get(PROPERTY_OPERATOR_ISO_COUNTRY);
-
- if (zone == null) {
-
- if (mGotCountryCode) {
- if (iso != null && iso.length() > 0) {
- zone = TimeUtils.getTimeZone(tzOffset, dst != 0,
- c.getTimeInMillis(),
- iso);
- } else {
- // We don't have a valid iso country code. This is
- // most likely because we're on a test network that's
- // using a bogus MCC (eg, "001"), so get a TimeZone
- // based only on the NITZ parameters.
- zone = getNitzTimeZone(tzOffset, (dst != 0), c.getTimeInMillis());
- }
- }
- }
-
- if (zone == null) {
- // We got the time before the country, so we don't know
- // how to identify the DST rules yet. Save the information
- // and hope to fix it up later.
-
- mNeedFixZone = true;
- mZoneOffset = tzOffset;
- mZoneDst = dst != 0;
- mZoneTime = c.getTimeInMillis();
- }
-
- if (zone != null) {
- if (getAutoTime()) {
- setAndBroadcastNetworkSetTimeZone(zone.getID());
- }
- saveNitzTimeZone(zone.getID());
- }
-
- String ignore = SystemProperties.get("gsm.ignore-nitz");
- if (ignore != null && ignore.equals("yes")) {
- Log.i(LOG_TAG, "NITZ: Not setting clock because gsm.ignore-nitz is set");
- return;
- }
-
- try {
- mWakeLock.acquire();
-
- if (getAutoTime()) {
- long millisSinceNitzReceived
- = SystemClock.elapsedRealtime() - nitzReceiveTime;
-
- if (millisSinceNitzReceived < 0) {
- // Sanity check: something is wrong
- Log.i(LOG_TAG, "NITZ: not setting time, clock has rolled "
- + "backwards since NITZ time was received, "
- + nitz);
- return;
- }
-
- if (millisSinceNitzReceived > Integer.MAX_VALUE) {
- // If the time is this far off, something is wrong > 24 days!
- Log.i(LOG_TAG, "NITZ: not setting time, processing has taken "
- + (millisSinceNitzReceived / (1000 * 60 * 60 * 24))
- + " days");
- return;
- }
-
- // Note: with range checks above, cast to int is safe
- c.add(Calendar.MILLISECOND, (int)millisSinceNitzReceived);
-
- Log.i(LOG_TAG, "NITZ: Setting time of day to " + c.getTime()
- + " NITZ receive delay(ms): " + millisSinceNitzReceived
- + " gained(ms): "
- + (c.getTimeInMillis() - System.currentTimeMillis())
- + " from " + nitz);
-
- setAndBroadcastNetworkSetTime(c.getTimeInMillis());
- Log.i(LOG_TAG, "NITZ: after Setting time of day");
- }
- SystemProperties.set("gsm.nitz.time", String.valueOf(c.getTimeInMillis()));
- saveNitzTime(c.getTimeInMillis());
- if (Config.LOGV) {
- long end = SystemClock.elapsedRealtime();
- Log.v(LOG_TAG, "NITZ: end=" + end + " dur=" + (end - start));
- }
- } finally {
- mWakeLock.release();
- }
- } catch (RuntimeException ex) {
- Log.e(LOG_TAG, "NITZ: Parsing NITZ time " + nitz, ex);
- }
- }
-
- private boolean getAutoTime() {
- try {
- return Settings.System.getInt(phone.getContext().getContentResolver(),
- Settings.System.AUTO_TIME) > 0;
- } catch (SettingNotFoundException snfe) {
- return true;
- }
- }
-
- private void saveNitzTimeZone(String zoneId) {
- mSavedTimeZone = zoneId;
- }
-
- private void saveNitzTime(long time) {
- mSavedTime = time;
- mSavedAtTime = SystemClock.elapsedRealtime();
- }
-
- /**
- * Set the timezone and send out a sticky broadcast so the system can
- * determine if the timezone was set by the carrier.
- *
- * @param zoneId timezone set by carrier
- */
- private void setAndBroadcastNetworkSetTimeZone(String zoneId) {
- AlarmManager alarm =
- (AlarmManager) phone.getContext().getSystemService(Context.ALARM_SERVICE);
- alarm.setTimeZone(zoneId);
- Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE);
- intent.putExtra("time-zone", zoneId);
- phone.getContext().sendStickyBroadcast(intent);
- }
-
- /**
- * Set the time and Send out a sticky broadcast so the system can determine
- * if the time was set by the carrier.
- *
- * @param time time set by network
- */
- private void setAndBroadcastNetworkSetTime(long time) {
- SystemClock.setCurrentTimeMillis(time);
- Intent intent = new Intent(TelephonyIntents.ACTION_NETWORK_SET_TIME);
- intent.putExtra("time", time);
- phone.getContext().sendStickyBroadcast(intent);
- }
-
- private void revertToNitz() {
- if (Settings.System.getInt(phone.getContext().getContentResolver(),
- Settings.System.AUTO_TIME, 0) == 0) {
- return;
- }
- Log.d(LOG_TAG, "Reverting to NITZ: tz='" + mSavedTimeZone
- + "' mSavedTime=" + mSavedTime
- + " mSavedAtTime=" + mSavedAtTime);
- if (mSavedTimeZone != null && mSavedTime != 0 && mSavedAtTime != 0) {
- setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
- setAndBroadcastNetworkSetTime(mSavedTime
- + (SystemClock.elapsedRealtime() - mSavedAtTime));
- }
- }
-
- /**
- * Post a notification to NotificationManager for restricted state
- *
- * @param notifyType is one state of PS/CS_*_ENABLE/DISABLE
- */
- private void setNotification(int notifyType) {
-
- Log.d(LOG_TAG, "[DSAC DEB] " + "create notification " + notifyType);
-
- Context context = phone.getContext();
-
- mNotification = new Notification();
- mNotification.when = System.currentTimeMillis();
- mNotification.flags = Notification.FLAG_AUTO_CANCEL;
- mNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
- Intent intent = new Intent();
- mNotification.contentIntent = PendingIntent
- .getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
-
- CharSequence details = "";
- CharSequence title = context.getText(com.android.internal.R.string.RestrictedChangedTitle);
- int notificationId = CS_NOTIFICATION;
-
- switch (notifyType) {
- case PS_ENABLED:
- notificationId = PS_NOTIFICATION;
- details = context.getText(com.android.internal.R.string.RestrictedOnData);;
- break;
- case PS_DISABLED:
- notificationId = PS_NOTIFICATION;
- break;
- case CS_ENABLED:
- details = context.getText(com.android.internal.R.string.RestrictedOnAll);;
- break;
- case CS_NORMAL_ENABLED:
- details = context.getText(com.android.internal.R.string.RestrictedOnNormal);;
- break;
- case CS_EMERGENCY_ENABLED:
- details = context.getText(com.android.internal.R.string.RestrictedOnEmergency);;
- break;
- case CS_DISABLED:
- // do nothing and cancel the notification later
- break;
- }
-
- Log.d(LOG_TAG, "[DSAC DEB] " + "put notification " + title + " / " +details);
- mNotification.tickerText = title;
- mNotification.setLatestEventInfo(context, title, details,
- mNotification.contentIntent);
-
- NotificationManager notificationManager = (NotificationManager)
- context.getSystemService(Context.NOTIFICATION_SERVICE);
-
- if (notifyType == PS_DISABLED || notifyType == CS_DISABLED) {
- // cancel previous post notification
- notificationManager.cancel(notificationId);
- } else {
- // update restricted state notification
- notificationManager.notify(notificationId, mNotification);
- }
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimCard.java b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
new file mode 100644
index 0000000..9af3aa6
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/SimCard.java
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.app.ActivityManagerNative;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.AsyncResult;
+import android.os.RemoteException;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.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 static android.Manifest.permission.READ_PHONE_STATE;
+
+/**
+ * Note: this class shares common code with RuimCard, consider a base class to minimize code
+ * duplication.
+ * {@hide}
+ */
+public final class SimCard extends Handler implements IccCard {
+ static final String LOG_TAG="GSM";
+
+ //***** Instance Variables
+ private static final boolean DBG = true;
+
+ private GSMPhone phone;
+ private CommandsInterface.IccStatus status = null;
+ private boolean mDesiredPinLocked;
+ private boolean mDesiredFdnEnabled;
+ private boolean mSimPinLocked = true; // Default to locked
+ private boolean mSimFdnEnabled = false; // Default to disabled.
+ // Will be updated when SIM_READY.
+
+ //***** Constants
+
+ // FIXME I hope this doesn't conflict with the Dialer's notifications
+ static final int NOTIFICATION_ID_SIM_STATUS = 33456;
+
+ //***** Event Constants
+
+ static final int EVENT_SIM_LOCKED_OR_ABSENT = 1;
+ static final int EVENT_GET_SIM_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_SIM_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_SIM_PASSWORD_DONE = 9;
+ static final int EVENT_QUERY_FACILITY_FDN_DONE = 10;
+ static final int EVENT_CHANGE_FACILITY_FDN_DONE = 11;
+
+
+ //***** Constructor
+
+ SimCard(GSMPhone phone) {
+ this.phone = phone;
+
+ phone.mCM.registerForSIMLockedOrAbsent(
+ this, EVENT_SIM_LOCKED_OR_ABSENT, null);
+
+ phone.mCM.registerForOffOrNotAvailable(
+ this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
+
+ phone.mCM.registerForSIMReady(
+ this, EVENT_SIM_READY, null);
+
+ updateStateProperty();
+ }
+
+ public void dispose() {
+ //Unregister for all events
+ phone.mCM.unregisterForSIMLockedOrAbsent(this);
+ phone.mCM.unregisterForOffOrNotAvailable(this);
+ phone.mCM.unregisterForSIMReady(this);
+ }
+
+ protected void finalize() {
+ if(DBG) Log.d(LOG_TAG, "SimCard finalized");
+ }
+
+ //***** SimCard implementation
+
+ public State
+ 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 SIM_NOT_READY:
+ return State.UNKNOWN;
+ case SIM_LOCKED_OR_ABSENT:
+ //this should be transient-only
+ return State.UNKNOWN;
+ case SIM_READY:
+ return State.READY;
+ }
+ } 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, "GsmSimCard.getState(): case should never be reached");
+ return State.UNKNOWN;
+ }
+
+ 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 mSimPinLocked;
+ }
+
+ public boolean getIccFdnEnabled() {
+ return mSimFdnEnabled;
+ }
+
+ 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_SIM_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_SIM_PASSWORD_DONE, onComplete));
+
+ }
+
+ public String getServiceProviderName () {
+ return phone.mSIMRecords.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:
+ status = null;
+ updateStateProperty();
+ broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_NOT_READY, null);
+ break;
+ case EVENT_SIM_READY:
+ //TODO: put facility read in SIM_READY now, maybe in REG_NW
+ phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_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_SIM_LOCKED_OR_ABSENT:
+ phone.mCM.getIccStatus(obtainMessage(EVENT_GET_SIM_STATUS_DONE));
+ phone.mCM.queryFacilityLock (
+ CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
+ obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
+ break;
+ case EVENT_GET_SIM_STATUS_DONE:
+ ar = (AsyncResult)msg.obj;
+
+ getSimStatusDone(ar);
+ break;
+ case EVENT_PINPUK_DONE:
+ // 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:
+ // 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;
+ getSimStatusDone(ar);
+ ((Message)ar.userObj).sendToTarget();
+ break;
+ case EVENT_QUERY_FACILITY_LOCK_DONE:
+ ar = (AsyncResult)msg.obj;
+ onQueryFacilityLock(ar);
+ break;
+ case EVENT_QUERY_FACILITY_FDN_DONE:
+ ar = (AsyncResult)msg.obj;
+ onQueryFdnEnabled(ar);
+ break;
+ case EVENT_CHANGE_FACILITY_LOCK_DONE:
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception == null) {
+ mSimPinLocked = mDesiredPinLocked;
+ if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: " +
+ "mSimPinLocked= " + mSimPinLocked);
+ } 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:
+ ar = (AsyncResult)msg.obj;
+
+ if (ar.exception == null) {
+ mSimFdnEnabled = mDesiredFdnEnabled;
+ if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
+ "mSimFdnEnabled=" + mSimFdnEnabled);
+ } 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_SIM_PASSWORD_DONE:
+ 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, "[GsmSimCard] Unknown Event " + msg.what);
+ }
+ }
+
+
+ //***** Private methods
+
+ /**
+ * Interperate 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) {
+ mSimPinLocked = (0!=ints[0]);
+ if(DBG) log("Query facility lock : " + mSimPinLocked);
+ } else {
+ Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response");
+ }
+ }
+
+ /**
+ * Interperate 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) {
+ mSimFdnEnabled = (0!=ints[0]);
+ if(DBG) log("Query facility lock : " + mSimFdnEnabled);
+ } else {
+ Log.e(LOG_TAG, "[GsmSimCard] Bogus facility lock response");
+ }
+ }
+
+ private void
+ getSimStatusDone(AsyncResult ar) {
+ if (ar.exception != null) {
+ Log.e(LOG_TAG,"Error getting ICC status. "
+ + "RIL_REQUEST_GET_ICC_STATUS should "
+ + "never return an error", ar.exception);
+ return;
+ }
+
+ CommandsInterface.IccStatus newStatus
+ = (CommandsInterface.IccStatus) ar.result;
+
+ handleSimStatus(newStatus);
+ }
+
+ private void
+ handleSimStatus(CommandsInterface.IccStatus newStatus) {
+ boolean transitionedIntoPinLocked;
+ boolean transitionedIntoAbsent;
+ boolean transitionedIntoNetworkLocked;
+
+ SimCard.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 SIM pin or puk locked.");
+ pinLockedRegistrants.notifyRegistrants();
+ broadcastSimStateChangedIntent(SimCard.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 SIM missing.");
+ absentRegistrants.notifyRegistrants();
+ broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_ABSENT, null);
+ } else if (transitionedIntoNetworkLocked) {
+ if(DBG) log("Notify SIM network locked.");
+ networkLockedRegistrants.notifyRegistrants();
+ broadcastSimStateChangedIntent(SimCard.INTENT_VALUE_ICC_LOCKED,
+ INTENT_VALUE_LOCKED_NETWORK);
+ }
+ }
+
+ public void broadcastSimStateChangedIntent(String value, String reason) {
+ Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(Phone.PHONE_NAME_KEY, phone.getPhoneName());
+ intent.putExtra(SimCard.INTENT_KEY_ICC_STATE, value);
+ intent.putExtra(SimCard.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, "[GsmSimCard] " + msg);
+ }
+}
+
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimConstants.java b/telephony/java/com/android/internal/telephony/gsm/SimConstants.java
deleted file mode 100644
index a7e3bbc..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/SimConstants.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-/**
- * {@hide}
- */
-public interface SimConstants {
- // 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;
- public static final int EF_EXT1 = 0x6F4A;
- public static final int EF_EXT2 = 0x6F4B;
- public static final int EF_EXT3 = 0x6F4C;
- public static final int EF_EXT6 = 0x6fc8; // Ext record for EF[MBDN]
- public static final int EF_MWIS = 0x6FCA;
- public static final int EF_MBDN = 0x6fc7;
- public static final int EF_PNN = 0x6fc5;
- public static final int EF_SPN = 0x6F46;
- public static final int EF_SMS = 0x6F3C;
- public static final int EF_ICCID = 0x2fe2;
- public static final int EF_AD = 0x6FAD;
- public static final int EF_MBI = 0x6fc9;
- public static final int EF_MSISDN = 0x6f40;
- public static final int EF_SPDI = 0x6fcd;
- public static final int EF_SST = 0x6f38;
- 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
- 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;
- public static final int EF_SPN_CPHS = 0x6f14;
- public static final int EF_SPN_SHORT_CPHS = 0x6f18;
- public static final int EF_INFO_CPHS = 0x6f16;
-
- // SMS record length from TS 51.011 10.5.3
- static public final int SMS_RECORD_LENGTH = 176;
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimException.java b/telephony/java/com/android/internal/telephony/gsm/SimException.java
deleted file mode 100644
index 1c0daba..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/SimException.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-/**
- * {@hide}
- */
-public class SimException extends Exception
-{
- SimException()
- {
-
- }
-
- SimException(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);
- }
-}
-
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimFileNotFound.java b/telephony/java/com/android/internal/telephony/gsm/SimFileNotFound.java
deleted file mode 100644
index 982e2fd..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/SimFileNotFound.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-/**
- * {@hide}
- */
-public class SimFileNotFound extends SimException
-{
- SimFileNotFound()
- {
-
- }
-
- SimFileNotFound(String s)
- {
- super(s);
- }
-
- SimFileNotFound(int ef)
- {
- super("SIM EF Not Found 0x" + Integer.toHexString(ef));
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimFileTypeMismatch.java b/telephony/java/com/android/internal/telephony/gsm/SimFileTypeMismatch.java
deleted file mode 100644
index 72790d0..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/SimFileTypeMismatch.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-/**
- * {@hide}
- */
-public class SimFileTypeMismatch extends SimException
-{
- SimFileTypeMismatch()
- {
-
- }
-
- SimFileTypeMismatch(String s)
- {
- super(s);
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimIoResult.java b/telephony/java/com/android/internal/telephony/gsm/SimIoResult.java
deleted file mode 100644
index 2c4da83..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/SimIoResult.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-/**
- * {@hide}
- */
-public class
-SimIoResult
-{
- int sw1;
- int sw2;
- byte[] payload;
-
- public SimIoResult(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 String toString()
- {
- return "SimIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x"
- + Integer.toHexString(sw2);
- }
-
- /**
- * true if this operation was successful
- * See GSM 11.11 Section 9.4
- * (the fun stuff is absent in 51.011)
- */
- public boolean success()
- {
- return sw1 == 0x90 || sw1 == 0x91 || sw1 == 0x9e || sw1 == 0x9f;
- }
-
- /**
- * Returns exception on error or null if success
- */
- public SimException getException()
- {
- if (success()) return null;
-
- switch (sw1) {
- case 0x94:
- if (sw2 == 0x08) {
- return new SimFileTypeMismatch();
- } else {
- return new SimFileNotFound();
- }
- default:
- return new SimException("sw1:" + sw1 + " sw2:" + sw2);
- }
- }
-}
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
index 7cc9a80..076da6b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SimPhoneBookInterfaceManager.java
@@ -25,6 +25,11 @@ 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;
@@ -32,247 +37,65 @@ import java.util.List;
* SimPhoneBookInterfaceManager to provide an inter-process communication to
* access ADN-like SIM records.
*/
-public class SimPhoneBookInterfaceManager extends ISimPhoneBook.Stub {
- static final String LOG_TAG = "GSM";
- static final boolean DBG = false;
- private GSMPhone phone;
- private AdnRecordCache adnCache;
- private final Object mLock = new Object();
- private int recordSize[];
- private boolean success;
- private List records;
- private static final boolean ALLOW_SIM_OP_IN_UI_THREAD = false;
+public class SimPhoneBookInterfaceManager extends IccPhoneBookInterfaceManager {
+ static final String LOG_TAG = "GSM";
- private static final int EVENT_GET_SIZE_DONE = 1;
- private static final int EVENT_LOAD_DONE = 2;
- private static final int EVENT_UPDATE_DONE = 3;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
- switch (msg.what) {
- case EVENT_GET_SIZE_DONE:
- ar = (AsyncResult) msg.obj;
- synchronized (mLock) {
- if (ar.exception == null) {
- recordSize = (int[])ar.result;
- // recordSize[0] is the record length
- // recordSize[1] is the total length of the EF file
- // recordSize[2] is the number of records in the EF file
- log("GET_RECORD_SIZE Size " + recordSize[0] +
- " total " + recordSize[1] +
- " #record " + recordSize[2]);
- mLock.notifyAll();
- }
- }
- break;
- case EVENT_UPDATE_DONE:
- ar = (AsyncResult) msg.obj;
- synchronized (mLock) {
- success = (ar.exception == null);
- mLock.notifyAll();
- }
- break;
- case EVENT_LOAD_DONE:
- ar = (AsyncResult)msg.obj;
- synchronized (mLock) {
- if (ar.exception == null) {
- records = (List)
- ((ArrayList) ar.result);
- } else {
- if(DBG) log("Cannot load ADN records");
- if (records != null) {
- records.clear();
- }
- }
- mLock.notifyAll();
- }
+ switch(msg.what) {
+ default:
+ mBaseHandler.handleMessage(msg);
break;
}
}
};
public SimPhoneBookInterfaceManager(GSMPhone phone) {
- this.phone = phone;
+ super(phone);
adnCache = phone.mSIMRecords.getAdnCache();
- publish();
+ //NOTE service "simphonebook" added by IccSmsInterfaceManagerProxy
}
- private void publish() {
- ServiceManager.addService("simphonebook", this);
+ public void dispose() {
+ super.dispose();
}
- /**
- * Replace oldAdn with newAdn in ADN-like record in EF
- *
- * getAdnRecordsInEf must be called at least once before this function,
- * otherwise an error will be returned
- * throws SecurityException if no WRITE_CONTACTS permission
- *
- * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
- * @param oldTag adn tag to be replaced
- * @param oldPhoneNumber adn number to be replaced
- * Set both oldTag and oldPhoneNubmer to "" means to replace an
- * empty record, aka, insert new record
- * @param newTag adn tag to be stored
- * @param newPhoneNumber adn number ot be stored
- * Set both newTag and newPhoneNubmer to "" means to replace the old
- * record with empty one, aka, delete old record
- * @param pin2 required to update EF_FDN, otherwise must be null
- * @return true for success
- */
- public boolean
- updateAdnRecordsInEfBySearch (int efid,
- String oldTag, String oldPhoneNumber,
- String newTag, String newPhoneNumber, String pin2) {
-
-
- if (phone.getContext().checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_CONTACTS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "Requires android.permission.WRITE_CONTACTS permission");
- }
-
-
- if (DBG) log("updateAdnRecordsInEfBySearch: efid=" + efid +
- " ("+ oldTag + "," + oldPhoneNumber + ")"+ "==>" +
- " ("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2);
- synchronized(mLock) {
- checkThread();
- success = false;
- Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
- AdnRecord oldAdn = new AdnRecord(oldTag, oldPhoneNumber);
- AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber);
- adnCache.updateAdnBySearch(efid, oldAdn, newAdn, pin2, response);
- try {
- mLock.wait();
- } catch (InterruptedException e) {
- log("interrupted while trying to update by search");
- }
- }
- return success;
- }
-
- /**
- * Update an ADN-like EF record by record index
- *
- * This is useful for iteration the whole ADN file, such as write the whole
- * phone book or erase/format the whole phonebook
- * throws SecurityException if no WRITE_CONTACTS permission
- *
- * @param efid must be one among EF_ADN, EF_FDN, and EF_SDN
- * @param newTag adn tag to be stored
- * @param newPhoneNumber adn number to be stored
- * Set both newTag and newPhoneNubmer to "" means to replace the old
- * record with empty one, aka, delete old record
- * @param index is 1-based adn record index to be updated
- * @param pin2 required to update EF_FDN, otherwise must be null
- * @return true for success
- */
- public boolean
- updateAdnRecordsInEfByIndex(int efid, String newTag,
- String newPhoneNumber, int index, String pin2) {
-
- if (phone.getContext().checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_CONTACTS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "Requires android.permission.WRITE_CONTACTS permission");
- }
-
- if (DBG) log("updateAdnRecordsInEfByIndex: efid=" + efid +
- " Index=" + index + " ==> " +
- "("+ newTag + "," + newPhoneNumber + ")"+ " pin2=" + pin2);
- synchronized(mLock) {
- checkThread();
- success = false;
- Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE);
- AdnRecord newAdn = new AdnRecord(newTag, newPhoneNumber);
- adnCache.updateAdnByIndex(efid, newAdn, index, pin2, response);
- try {
- mLock.wait();
- } catch (InterruptedException e) {
- log("interrupted while trying to update by index");
- }
- }
- return success;
+ protected void finalize() {
+ if(DBG) Log.d(LOG_TAG, "SimPhoneBookInterfaceManager finalized");
}
- /**
- * Get the capacity of records in efid
- *
- * @param efid the EF id of a ADN-like SIM
- * @return int[3] array
- * recordSizes[0] is the single record length
- * recordSizes[1] is the total length of the EF file
- * recordSizes[2] is the number of records in the EF file
- */
public int[] getAdnRecordsSize(int efid) {
- if (DBG) log("getAdnRecordsSize: efid=" + efid);
+ if (DBG) logd("getAdnRecordsSize: efid=" + efid);
synchronized(mLock) {
checkThread();
recordSize = new int[3];
- Message response = mHandler.obtainMessage(EVENT_GET_SIZE_DONE);
- phone.mSIMFileHandler.getEFLinearRecordSize(efid, response);
- try {
- mLock.wait();
- } catch (InterruptedException e) {
- log("interrupted while trying to load from the SIM");
- }
- }
- return recordSize;
- }
+ //Using mBaseHandler, no difference in EVENT_GET_SIZE_DONE handling
+ Message response = mBaseHandler.obtainMessage(EVENT_GET_SIZE_DONE);
- /**
- * Loads the AdnRecords in efid and returns them as a
- * List of AdnRecords
- *
- * throws SecurityException if no READ_CONTACTS permission
- *
- * @param efid the EF id of a ADN-like SIM
- * @return List of AdnRecord
- */
- public List getAdnRecordsInEf(int efid) {
-
- if (phone.getContext().checkCallingOrSelfPermission(
- android.Manifest.permission.READ_CONTACTS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(
- "Requires android.permission.READ_CONTACTS permission");
- }
-
- if (DBG) log("getAdnRecordsInEF: efid=" + efid);
-
- synchronized(mLock) {
- checkThread();
- Message response = mHandler.obtainMessage(EVENT_LOAD_DONE);
- adnCache.requestLoadAllAdnLike(efid, response);
+ phone.getIccFileHandler().getEFLinearRecordSize(efid, response);
try {
mLock.wait();
} catch (InterruptedException e) {
- log("interrupted while trying to load from the SIM");
+ logd("interrupted while trying to load from the SIM");
}
}
- return records;
+
+ return recordSize;
}
- private void checkThread() {
- if (!ALLOW_SIM_OP_IN_UI_THREAD) {
- // Make sure this isn't the UI thread, since it will block
- if (mHandler.getLooper().equals(Looper.myLooper())) {
- Log.e(LOG_TAG, "query() called on the main UI thread!");
- throw new IllegalStateException("You cannot call query on this provder from the main UI thread.");
- }
- }
+ protected void logd(String msg) {
+ Log.d(LOG_TAG, "[SimPbInterfaceManager] " + msg);
}
- private void log(String msg) {
- Log.d(LOG_TAG, "[SpbInterfaceManager] " + msg);
+ protected void loge(String msg) {
+ Log.e(LOG_TAG, "[SimPbInterfaceManager] " + msg);
}
}
+
diff --git a/telephony/java/com/android/internal/telephony/gsm/SimProvider.java b/telephony/java/com/android/internal/telephony/gsm/SimProvider.java
deleted file mode 100644
index cece4ba..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/SimProvider.java
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.content.ContentProvider;
-import android.content.UriMatcher;
-import android.content.ContentValues;
-import com.android.internal.database.ArrayListCursor;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.SystemProperties;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * {@hide}
- */
-public class SimProvider extends ContentProvider {
- private static final String TAG = "SimProvider";
- private static final boolean DBG = false;
-
-
- private static final String[] ADDRESS_BOOK_COLUMN_NAMES = new String[] {
- "name",
- "number"
- };
-
- private static final int ADN = 1;
- private static final int FDN = 2;
- private static final int SDN = 3;
-
- private static final String STR_TAG = "tag";
- private static final String STR_NUMBER = "number";
- private static final String STR_PIN2 = "pin2";
-
- private static final UriMatcher URL_MATCHER =
- new UriMatcher(UriMatcher.NO_MATCH);
-
- static {
- URL_MATCHER.addURI("sim", "adn", ADN);
- URL_MATCHER.addURI("sim", "fdn", FDN);
- URL_MATCHER.addURI("sim", "sdn", SDN);
- }
-
-
- private boolean mSimulator;
-
- @Override
- public boolean onCreate() {
- String device = SystemProperties.get("ro.product.device");
- if (!TextUtils.isEmpty(device)) {
- mSimulator = false;
- } else {
- // simulator
- mSimulator = true;
- }
-
- return true;
- }
-
- @Override
- public Cursor query(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sort) {
- ArrayList results;
-
- if (!mSimulator) {
- switch (URL_MATCHER.match(url)) {
- case ADN:
- results = loadFromEf(SimConstants.EF_ADN);
- break;
-
- case FDN:
- results = loadFromEf(SimConstants.EF_FDN);
- break;
-
- case SDN:
- results = loadFromEf(SimConstants.EF_SDN);
- break;
-
- default:
- throw new IllegalArgumentException("Unknown URL " + url);
- }
- } else {
- // Fake up some data for the simulator
- results = new ArrayList(4);
- ArrayList contact;
-
- contact = new ArrayList();
- contact.add("Ron Stevens/H");
- contact.add("512-555-5038");
- results.add(contact);
-
- contact = new ArrayList();
- contact.add("Ron Stevens/M");
- contact.add("512-555-8305");
- results.add(contact);
-
- contact = new ArrayList();
- contact.add("Melissa Owens");
- contact.add("512-555-8305");
- results.add(contact);
-
- contact = new ArrayList();
- contact.add("Directory Assistence");
- contact.add("411");
- results.add(contact);
- }
-
- return new ArrayListCursor(ADDRESS_BOOK_COLUMN_NAMES, results);
- }
-
- @Override
- public String getType(Uri url) {
- switch (URL_MATCHER.match(url)) {
- case ADN:
- case FDN:
- case SDN:
- return "vnd.android.cursor.dir/sim-contact";
-
- default:
- throw new IllegalArgumentException("Unknown URL " + url);
- }
- }
-
- @Override
- public Uri insert(Uri url, ContentValues initialValues) {
- Uri resultUri;
- int efType;
- String pin2 = null;
-
- if (DBG) log("insert");
-
- int match = URL_MATCHER.match(url);
- switch (match) {
- case ADN:
- efType = SimConstants.EF_ADN;
- break;
-
- case FDN:
- efType = SimConstants.EF_FDN;
- pin2 = initialValues.getAsString("pin2");
- break;
-
- default:
- throw new UnsupportedOperationException(
- "Cannot insert into URL: " + url);
- }
-
- String tag = initialValues.getAsString("tag");
- String number = initialValues.getAsString("number");
- boolean success = addSimRecordToEf(efType, tag, number, pin2);
-
- if (!success) {
- return null;
- }
-
- StringBuilder buf = new StringBuilder("content://im/");
- switch (match) {
- case ADN:
- buf.append("adn/");
- break;
-
- case FDN:
- buf.append("fdn/");
- break;
- }
-
- // TODO: we need to find out the rowId for the newly added record
- buf.append(0);
-
- resultUri = Uri.parse(buf.toString());
-
- /*
- // notify interested parties that an insertion happened
- getContext().getContentResolver().notifyInsert(
- resultUri, rowID, null);
- */
-
- return resultUri;
- }
-
- private String normalizeValue(String inVal) {
- int len = inVal.length();
- String retVal = inVal;
-
- if (inVal.charAt(0) == '\'' && inVal.charAt(len-1) == '\'') {
- retVal = inVal.substring(1, len-1);
- }
-
- return retVal;
- }
-
- @Override
- public int delete(Uri url, String where, String[] whereArgs) {
- int efType;
-
- if (DBG) log("delete");
-
- int match = URL_MATCHER.match(url);
- switch (match) {
- case ADN:
- efType = SimConstants.EF_ADN;
- break;
-
- case FDN:
- efType = SimConstants.EF_FDN;
- break;
-
- default:
- throw new UnsupportedOperationException(
- "Cannot insert into URL: " + url);
- }
-
- // parse where clause
- String tag = null;
- String number = null;
- String pin2 = null;
-
- String[] tokens = where.split("AND");
- int n = tokens.length;
-
- while (--n >= 0) {
- String param = tokens[n];
- if (DBG) log("parsing '" + param + "'");
-
- String[] pair = param.split("=");
-
- if (pair.length != 2) {
- Log.e(TAG, "resolve: bad whereClause parameter: " + param);
- continue;
- }
-
- String key = pair[0].trim();
- String val = pair[1].trim();
-
- if (STR_TAG.equals(key)) {
- tag = normalizeValue(val);
- } else if (STR_NUMBER.equals(key)) {
- number = normalizeValue(val);
- } else if (STR_PIN2.equals(key)) {
- pin2 = normalizeValue(val);
- }
- }
-
- if (TextUtils.isEmpty(tag)) {
- return 0;
- }
-
- if (efType == FDN && TextUtils.isEmpty(pin2)) {
- return 0;
- }
-
- boolean success = deleteSimRecordFromEf(efType, tag, number, pin2);
- if (!success) {
- return 0;
- }
-
- return 1;
- }
-
- @Override
- public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
- int efType;
- String pin2 = null;
-
- if (DBG) log("update");
-
- int match = URL_MATCHER.match(url);
- switch (match) {
- case ADN:
- efType = SimConstants.EF_ADN;
- break;
-
- case FDN:
- efType = SimConstants.EF_FDN;
- pin2 = values.getAsString("pin2");
- break;
-
- default:
- throw new UnsupportedOperationException(
- "Cannot insert into URL: " + url);
- }
-
- String tag = values.getAsString("tag");
- String number = values.getAsString("number");
- String newTag = values.getAsString("newTag");
- String newNumber = values.getAsString("newNumber");
-
- boolean success = updateSimRecordInEf(efType, tag, number,
- newTag, newNumber, pin2);
-
- if (!success) {
- return 0;
- }
-
- return 1;
- }
-
- private ArrayList loadFromEf(int efType) {
- ArrayList results = new ArrayList