[automerger] Fixed Invalid Pdu Issue am: 4b938358de am: fc2a2d071a am: ca00d5d151 am: 23de93c197 am: 909c1606d3 am: bfb0076f03 skipped: c8ec5c3e94 am: 63d433cd2b
Change-Id: Ic7cd6aafc8aaecc58ec2cb3d657aff53c6d5fbe1
diff --git a/Android.mk b/Android.mk
index add14fa..70acfcd 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,10 +26,12 @@
$(call all-proto-files-under, proto)
LOCAL_JAVA_LIBRARIES := voip-common ims-common
+LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.radio-V1.0-java-static \
+ android.hardware.radio.deprecated-V1.0-java-static
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := telephony-common
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors,store_unknown_fields=true,enum_style=java
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := store_unknown_fields=true,enum_style=java
LOCAL_JARJAR_RULES := $(LOCAL_PATH)/jarjar-rules.txt
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk $(LOCAL_PATH)/jarjar-rules.txt
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..f3db20e
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,2 @@
+[Hook Scripts]
+checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/jarjar-rules.txt b/jarjar-rules.txt
index 50220b4..958e2bb 100644
--- a/jarjar-rules.txt
+++ b/jarjar-rules.txt
@@ -1,2 +1,2 @@
-rule com.google.protobuf.nano.** com.android.framework.protobuf.nano.@1
+rule com.google.protobuf.nano.** com.android.internal.telephony.protobuf.nano.@1
diff --git a/proto/telephony.proto b/proto/telephony.proto
index 70d210b..1f1a2bb 100644
--- a/proto/telephony.proto
+++ b/proto/telephony.proto
@@ -95,13 +95,13 @@
// Telephony related user settings
message TelephonySettings {
- // NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE
+ // NETWORK_MODE_* See ril.h PREF_NET_TYPE_XXXX
enum RilNetworkMode {
// Mode is unknown.
NETWORK_MODE_UNKNOWN = 0;
- // GSM/WCDMA (WCDMA preferred)
+ // GSM/WCDMA (WCDMA preferred). Note the following values are all off by 1.
NETWORK_MODE_WCDMA_PREF = 1;
// GSM only
@@ -236,6 +236,9 @@
// Roaming type
enum RoamingType {
+ // Unknown. The default value. Different from ROAMING_TYPE_UNKNOWN.
+ UNKNOWN = -1;
+
// In home network
ROAMING_TYPE_NOT_ROAMING = 0;
@@ -257,21 +260,26 @@
optional TelephonyOperator data_operator = 2;
// Current voice network roaming type
- optional RoamingType voice_roaming_type = 3;
+ optional RoamingType voice_roaming_type = 3 [default = UNKNOWN];
// Current data network roaming type
- optional RoamingType data_roaming_type = 4;
+ optional RoamingType data_roaming_type = 4 [default = UNKNOWN];
// Current voice radio technology
- optional RadioAccessTechnology voice_rat = 5;
+ optional RadioAccessTechnology voice_rat = 5 [default = UNKNOWN];
// Current data radio technology
- optional RadioAccessTechnology data_rat = 6;
+ optional RadioAccessTechnology data_rat = 6 [default = UNKNOWN];
}
// Radio access families
enum RadioAccessTechnology {
+ // This is the default value. Different from RAT_UNKNOWN.
+ UNKNOWN = -1;
+
+ // Airplane mode, out of service, or when the modem cannot determine
+ // the RAT.
RAT_UNKNOWN = 0;
RAT_GPRS = 1;
@@ -377,6 +385,7 @@
// type is unknown.
RIL_E_UNKNOWN = 0;
+ // Note the following values are all off by 1.
RIL_E_SUCCESS = 1;
// If radio did not start or is resetting
@@ -458,8 +467,12 @@
// SS request modified to different SS request
RIL_E_SS_MODIFIED_TO_SS = 28;
- // LCE service not supported(36 in RILConstants.java)
- RIL_E_LCE_NOT_SUPPORTED = 36;
+ // LCE service not supported(36 in RILConstants.java. This is a mistake.
+ // The value should be off by 1 ideally.)
+ RIL_E_LCE_NOT_SUPPORTED = 36 [deprecated=true];
+
+ // LCE service not supported
+ RIL_E_LCE_NOT_SUPPORTED_NEW = 37;
}
// PDP_type values in TS 27.007 section 10.1.1.
@@ -561,7 +574,7 @@
}
// Radio technology to use
- optional RadioAccessTechnology rat = 1;
+ optional RadioAccessTechnology rat = 1 [default = UNKNOWN];
// optional RIL_DataProfile
optional RilDataProfile data_profile = 2;
@@ -576,8 +589,7 @@
// RIL response to RilSetupDataCall
message RilSetupDataCallResponse {
- // Copy of enum RIL_DataCallFailCause defined at
- // https://cs.corp.google.com/android/hardware/ril/include/telephony/ril.h
+ // Copy of enum RIL_DataCallFailCause defined at ril.h
enum RilDataCallFailCause {
// Failure reason is unknown.
@@ -1097,10 +1109,10 @@
optional ImsReasonInfo reason_info = 18;
// Original access technology
- optional RadioAccessTechnology src_access_tech = 19;
+ optional RadioAccessTechnology src_access_tech = 19 [default = UNKNOWN];
// New access technology
- optional RadioAccessTechnology target_access_tech = 20;
+ optional RadioAccessTechnology target_access_tech = 20 [default = UNKNOWN];
// NITZ time in milliseconds
optional int64 nitz_timestamp_millis = 21;
diff --git a/src/java/android/provider/Telephony.java b/src/java/android/provider/Telephony.java
deleted file mode 100644
index 943a6ca..0000000
--- a/src/java/android/provider/Telephony.java
+++ /dev/null
@@ -1,2975 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.provider;
-
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.TestApi;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.database.sqlite.SqliteWrapper;
-import android.net.Uri;
-import android.telephony.SmsMessage;
-import android.telephony.SubscriptionManager;
-import android.text.TextUtils;
-import android.telephony.Rlog;
-import android.util.Patterns;
-
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.SmsApplication;
-
-
-import java.util.HashSet;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * The Telephony provider contains data related to phone operation, specifically SMS and MMS
- * messages and access to the APN list, including the MMSC to use.
- *
- * <p class="note"><strong>Note:</strong> These APIs are not available on all Android-powered
- * devices. If your app depends on telephony features such as for managing SMS messages, include
- * a <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code <uses-feature>}
- * </a> element in your manifest that declares the {@code "android.hardware.telephony"} hardware
- * feature. Alternatively, you can check for telephony availability at runtime using either
- * {@link android.content.pm.PackageManager#hasSystemFeature
- * hasSystemFeature(PackageManager.FEATURE_TELEPHONY)} or {@link
- * android.telephony.TelephonyManager#getPhoneType}.</p>
- *
- * <h3>Creating an SMS app</h3>
- *
- * <p>Only the default SMS app (selected by the user in system settings) is able to write to the
- * SMS Provider (the tables defined within the {@code Telephony} class) and only the default SMS
- * app receives the {@link android.provider.Telephony.Sms.Intents#SMS_DELIVER_ACTION} broadcast
- * when the user receives an SMS or the {@link
- * android.provider.Telephony.Sms.Intents#WAP_PUSH_DELIVER_ACTION} broadcast when the user
- * receives an MMS.</p>
- *
- * <p>Any app that wants to behave as the user's default SMS app must handle the following intents:
- * <ul>
- * <li>In a broadcast receiver, include an intent filter for {@link Sms.Intents#SMS_DELIVER_ACTION}
- * (<code>"android.provider.Telephony.SMS_DELIVER"</code>). The broadcast receiver must also
- * require the {@link android.Manifest.permission#BROADCAST_SMS} permission.
- * <p>This allows your app to directly receive incoming SMS messages.</p></li>
- * <li>In a broadcast receiver, include an intent filter for {@link
- * Sms.Intents#WAP_PUSH_DELIVER_ACTION}} ({@code "android.provider.Telephony.WAP_PUSH_DELIVER"})
- * with the MIME type <code>"application/vnd.wap.mms-message"</code>.
- * The broadcast receiver must also require the {@link
- * android.Manifest.permission#BROADCAST_WAP_PUSH} permission.
- * <p>This allows your app to directly receive incoming MMS messages.</p></li>
- * <li>In your activity that delivers new messages, include an intent filter for
- * {@link android.content.Intent#ACTION_SENDTO} (<code>"android.intent.action.SENDTO"
- * </code>) with schemas, <code>sms:</code>, <code>smsto:</code>, <code>mms:</code>, and
- * <code>mmsto:</code>.
- * <p>This allows your app to receive intents from other apps that want to deliver a
- * message.</p></li>
- * <li>In a service, include an intent filter for {@link
- * android.telephony.TelephonyManager#ACTION_RESPOND_VIA_MESSAGE}
- * (<code>"android.intent.action.RESPOND_VIA_MESSAGE"</code>) with schemas,
- * <code>sms:</code>, <code>smsto:</code>, <code>mms:</code>, and <code>mmsto:</code>.
- * This service must also require the {@link
- * android.Manifest.permission#SEND_RESPOND_VIA_MESSAGE} permission.
- * <p>This allows users to respond to incoming phone calls with an immediate text message
- * using your app.</p></li>
- * </ul>
- *
- * <p>Other apps that are not selected as the default SMS app can only <em>read</em> the SMS
- * Provider, but may also be notified when a new SMS arrives by listening for the {@link
- * Sms.Intents#SMS_RECEIVED_ACTION}
- * broadcast, which is a non-abortable broadcast that may be delivered to multiple apps. This
- * broadcast is intended for apps that—while not selected as the default SMS app—need to
- * read special incoming messages such as to perform phone number verification.</p>
- *
- * <p>For more information about building SMS apps, read the blog post, <a
- * href="http://android-developers.blogspot.com/2013/10/getting-your-sms-apps-ready-for-kitkat.html"
- * >Getting Your SMS Apps Ready for KitKat</a>.</p>
- *
- */
-public final class Telephony {
- private static final String TAG = "Telephony";
-
- /**
- * Not instantiable.
- * @hide
- */
- private Telephony() {
- }
-
- /**
- * Base columns for tables that contain text-based SMSs.
- */
- public interface TextBasedSmsColumns {
-
- /** Message type: all messages. */
- public static final int MESSAGE_TYPE_ALL = 0;
-
- /** Message type: inbox. */
- public static final int MESSAGE_TYPE_INBOX = 1;
-
- /** Message type: sent messages. */
- public static final int MESSAGE_TYPE_SENT = 2;
-
- /** Message type: drafts. */
- public static final int MESSAGE_TYPE_DRAFT = 3;
-
- /** Message type: outbox. */
- public static final int MESSAGE_TYPE_OUTBOX = 4;
-
- /** Message type: failed outgoing message. */
- public static final int MESSAGE_TYPE_FAILED = 5;
-
- /** Message type: queued to send later. */
- public static final int MESSAGE_TYPE_QUEUED = 6;
-
- /**
- * The type of message.
- * <P>Type: INTEGER</P>
- */
- public static final String TYPE = "type";
-
- /**
- * The thread ID of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String THREAD_ID = "thread_id";
-
- /**
- * The address of the other party.
- * <P>Type: TEXT</P>
- */
- public static final String ADDRESS = "address";
-
- /**
- * The date the message was received.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String DATE = "date";
-
- /**
- * The date the message was sent.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String DATE_SENT = "date_sent";
-
- /**
- * Has the message been read?
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String READ = "read";
-
- /**
- * Has the message been seen by the user? The "seen" flag determines
- * whether we need to show a notification.
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String SEEN = "seen";
-
- /**
- * {@code TP-Status} value for the message, or -1 if no status has been received.
- * <P>Type: INTEGER</P>
- */
- public static final String STATUS = "status";
-
- /** TP-Status: no status received. */
- public static final int STATUS_NONE = -1;
- /** TP-Status: complete. */
- public static final int STATUS_COMPLETE = 0;
- /** TP-Status: pending. */
- public static final int STATUS_PENDING = 32;
- /** TP-Status: failed. */
- public static final int STATUS_FAILED = 64;
-
- /**
- * The subject of the message, if present.
- * <P>Type: TEXT</P>
- */
- public static final String SUBJECT = "subject";
-
- /**
- * The body of the message.
- * <P>Type: TEXT</P>
- */
- public static final String BODY = "body";
-
- /**
- * The ID of the sender of the conversation, if present.
- * <P>Type: INTEGER (reference to item in {@code content://contacts/people})</P>
- */
- public static final String PERSON = "person";
-
- /**
- * The protocol identifier code.
- * <P>Type: INTEGER</P>
- */
- public static final String PROTOCOL = "protocol";
-
- /**
- * Is the {@code TP-Reply-Path} flag set?
- * <P>Type: BOOLEAN</P>
- */
- public static final String REPLY_PATH_PRESENT = "reply_path_present";
-
- /**
- * The service center (SC) through which to send the message, if present.
- * <P>Type: TEXT</P>
- */
- public static final String SERVICE_CENTER = "service_center";
-
- /**
- * Is the message locked?
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String LOCKED = "locked";
-
- /**
- * The subscription to which the message belongs to. Its value will be
- * < 0 if the sub id cannot be determined.
- * <p>Type: INTEGER (long) </p>
- */
- public static final String SUBSCRIPTION_ID = "sub_id";
-
- /**
- * The MTU size of the mobile interface to which the APN connected
- * @hide
- */
- public static final String MTU = "mtu";
-
- /**
- * Error code associated with sending or receiving this message
- * <P>Type: INTEGER</P>
- */
- public static final String ERROR_CODE = "error_code";
-
- /**
- * The identity of the sender of a sent message. It is
- * usually the package name of the app which sends the message.
- * <p class="note"><strong>Note:</strong>
- * This column is read-only. It is set by the provider and can not be changed by apps.
- * <p>Type: TEXT</p>
- */
- public static final String CREATOR = "creator";
- }
-
- /**
- * Contains all text-based SMS messages.
- */
- public static final class Sms implements BaseColumns, TextBasedSmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Sms() {
- }
-
- /**
- * Used to determine the currently configured default SMS package.
- * @param context context of the requesting application
- * @return package name for the default SMS package or null
- */
- public static String getDefaultSmsPackage(Context context) {
- ComponentName component = SmsApplication.getDefaultSmsApplication(context, false);
- if (component != null) {
- return component.getPackageName();
- }
- return null;
- }
-
- /**
- * Return cursor for table query.
- * @hide
- */
- public static Cursor query(ContentResolver cr, String[] projection) {
- return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
- }
-
- /**
- * Return cursor for table query.
- * @hide
- */
- public static Cursor query(ContentResolver cr, String[] projection,
- String where, String orderBy) {
- return cr.query(CONTENT_URI, projection, where,
- null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri CONTENT_URI = Uri.parse("content://sms");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
-
- /**
- * Add an SMS to the given URI.
- *
- * @param resolver the content resolver to use
- * @param uri the URI to add the message to
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the pseudo-subject of the message
- * @param date the timestamp for the message
- * @param read true if the message has been read, false if not
- * @param deliveryReport true if a delivery report was requested, false if not
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessageToUri(ContentResolver resolver,
- Uri uri, String address, String body, String subject,
- Long date, boolean read, boolean deliveryReport) {
- return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
- resolver, uri, address, body, subject, date, read, deliveryReport, -1L);
- }
-
- /**
- * Add an SMS to the given URI.
- *
- * @param resolver the content resolver to use
- * @param uri the URI to add the message to
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the psuedo-subject of the message
- * @param date the timestamp for the message
- * @param read true if the message has been read, false if not
- * @param deliveryReport true if a delivery report was requested, false if not
- * @param subId the subscription which the message belongs to
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessageToUri(int subId, ContentResolver resolver,
- Uri uri, String address, String body, String subject,
- Long date, boolean read, boolean deliveryReport) {
- return addMessageToUri(subId, resolver, uri, address, body, subject,
- date, read, deliveryReport, -1L);
- }
-
- /**
- * Add an SMS to the given URI with the specified thread ID.
- *
- * @param resolver the content resolver to use
- * @param uri the URI to add the message to
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the pseudo-subject of the message
- * @param date the timestamp for the message
- * @param read true if the message has been read, false if not
- * @param deliveryReport true if a delivery report was requested, false if not
- * @param threadId the thread_id of the message
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessageToUri(ContentResolver resolver,
- Uri uri, String address, String body, String subject,
- Long date, boolean read, boolean deliveryReport, long threadId) {
- return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
- resolver, uri, address, body, subject,
- date, read, deliveryReport, threadId);
- }
-
- /**
- * Add an SMS to the given URI with thread_id specified.
- *
- * @param resolver the content resolver to use
- * @param uri the URI to add the message to
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the psuedo-subject of the message
- * @param date the timestamp for the message
- * @param read true if the message has been read, false if not
- * @param deliveryReport true if a delivery report was requested, false if not
- * @param threadId the thread_id of the message
- * @param subId the subscription which the message belongs to
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessageToUri(int subId, ContentResolver resolver,
- Uri uri, String address, String body, String subject,
- Long date, boolean read, boolean deliveryReport, long threadId) {
- ContentValues values = new ContentValues(8);
- Rlog.v(TAG,"Telephony addMessageToUri sub id: " + subId);
-
- values.put(SUBSCRIPTION_ID, subId);
- values.put(ADDRESS, address);
- if (date != null) {
- values.put(DATE, date);
- }
- values.put(READ, read ? Integer.valueOf(1) : Integer.valueOf(0));
- values.put(SUBJECT, subject);
- values.put(BODY, body);
- if (deliveryReport) {
- values.put(STATUS, STATUS_PENDING);
- }
- if (threadId != -1L) {
- values.put(THREAD_ID, threadId);
- }
- return resolver.insert(uri, values);
- }
-
- /**
- * Move a message to the given folder.
- *
- * @param context the context to use
- * @param uri the message to move
- * @param folder the folder to move to
- * @return true if the operation succeeded
- * @hide
- */
- public static boolean moveMessageToFolder(Context context,
- Uri uri, int folder, int error) {
- if (uri == null) {
- return false;
- }
-
- boolean markAsUnread = false;
- boolean markAsRead = false;
- switch(folder) {
- case MESSAGE_TYPE_INBOX:
- case MESSAGE_TYPE_DRAFT:
- break;
- case MESSAGE_TYPE_OUTBOX:
- case MESSAGE_TYPE_SENT:
- markAsRead = true;
- break;
- case MESSAGE_TYPE_FAILED:
- case MESSAGE_TYPE_QUEUED:
- markAsUnread = true;
- break;
- default:
- return false;
- }
-
- ContentValues values = new ContentValues(3);
-
- values.put(TYPE, folder);
- if (markAsUnread) {
- values.put(READ, 0);
- } else if (markAsRead) {
- values.put(READ, 1);
- }
- values.put(ERROR_CODE, error);
-
- return 1 == SqliteWrapper.update(context, context.getContentResolver(),
- uri, values, null, null);
- }
-
- /**
- * Returns true iff the folder (message type) identifies an
- * outgoing message.
- * @hide
- */
- public static boolean isOutgoingFolder(int messageType) {
- return (messageType == MESSAGE_TYPE_FAILED)
- || (messageType == MESSAGE_TYPE_OUTBOX)
- || (messageType == MESSAGE_TYPE_SENT)
- || (messageType == MESSAGE_TYPE_QUEUED);
- }
-
- /**
- * Contains all text-based SMS messages in the SMS app inbox.
- */
- public static final class Inbox implements BaseColumns, TextBasedSmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Inbox() {
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri CONTENT_URI = Uri.parse("content://sms/inbox");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
-
- /**
- * Add an SMS to the Draft box.
- *
- * @param resolver the content resolver to use
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the pseudo-subject of the message
- * @param date the timestamp for the message
- * @param read true if the message has been read, false if not
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessage(ContentResolver resolver,
- String address, String body, String subject, Long date,
- boolean read) {
- return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
- resolver, CONTENT_URI, address, body, subject, date, read, false);
- }
-
- /**
- * Add an SMS to the Draft box.
- *
- * @param resolver the content resolver to use
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the psuedo-subject of the message
- * @param date the timestamp for the message
- * @param read true if the message has been read, false if not
- * @param subId the subscription which the message belongs to
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessage(int subId, ContentResolver resolver,
- String address, String body, String subject, Long date, boolean read) {
- return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
- subject, date, read, false);
- }
- }
-
- /**
- * Contains all sent text-based SMS messages in the SMS app.
- */
- public static final class Sent implements BaseColumns, TextBasedSmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Sent() {
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri CONTENT_URI = Uri.parse("content://sms/sent");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
-
- /**
- * Add an SMS to the Draft box.
- *
- * @param resolver the content resolver to use
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the pseudo-subject of the message
- * @param date the timestamp for the message
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessage(ContentResolver resolver,
- String address, String body, String subject, Long date) {
- return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
- resolver, CONTENT_URI, address, body, subject, date, true, false);
- }
-
- /**
- * Add an SMS to the Draft box.
- *
- * @param resolver the content resolver to use
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the psuedo-subject of the message
- * @param date the timestamp for the message
- * @param subId the subscription which the message belongs to
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessage(int subId, ContentResolver resolver,
- String address, String body, String subject, Long date) {
- return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
- subject, date, true, false);
- }
- }
-
- /**
- * Contains all sent text-based SMS messages in the SMS app.
- */
- public static final class Draft implements BaseColumns, TextBasedSmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Draft() {
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri CONTENT_URI = Uri.parse("content://sms/draft");
-
- /**
- * @hide
- */
- public static Uri addMessage(ContentResolver resolver,
- String address, String body, String subject, Long date) {
- return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
- resolver, CONTENT_URI, address, body, subject, date, true, false);
- }
-
- /**
- * Add an SMS to the Draft box.
- *
- * @param resolver the content resolver to use
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the psuedo-subject of the message
- * @param date the timestamp for the message
- * @param subId the subscription which the message belongs to
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessage(int subId, ContentResolver resolver,
- String address, String body, String subject, Long date) {
- return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
- subject, date, true, false);
- }
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
- }
-
- /**
- * Contains all pending outgoing text-based SMS messages.
- */
- public static final class Outbox implements BaseColumns, TextBasedSmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Outbox() {
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri CONTENT_URI = Uri.parse("content://sms/outbox");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
-
- /**
- * Add an SMS to the outbox.
- *
- * @param resolver the content resolver to use
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the pseudo-subject of the message
- * @param date the timestamp for the message
- * @param deliveryReport whether a delivery report was requested for the message
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessage(ContentResolver resolver,
- String address, String body, String subject, Long date,
- boolean deliveryReport, long threadId) {
- return addMessageToUri(SubscriptionManager.getDefaultSmsSubscriptionId(),
- resolver, CONTENT_URI, address, body, subject, date,
- true, deliveryReport, threadId);
- }
-
- /**
- * Add an SMS to the Out box.
- *
- * @param resolver the content resolver to use
- * @param address the address of the sender
- * @param body the body of the message
- * @param subject the psuedo-subject of the message
- * @param date the timestamp for the message
- * @param deliveryReport whether a delivery report was requested for the message
- * @param subId the subscription which the message belongs to
- * @return the URI for the new message
- * @hide
- */
- public static Uri addMessage(int subId, ContentResolver resolver,
- String address, String body, String subject, Long date,
- boolean deliveryReport, long threadId) {
- return addMessageToUri(subId, resolver, CONTENT_URI, address, body,
- subject, date, true, deliveryReport, threadId);
- }
- }
-
- /**
- * Contains all sent text-based SMS messages in the SMS app.
- */
- public static final class Conversations
- implements BaseColumns, TextBasedSmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Conversations() {
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri CONTENT_URI = Uri.parse("content://sms/conversations");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
-
- /**
- * The first 45 characters of the body of the message.
- * <P>Type: TEXT</P>
- */
- public static final String SNIPPET = "snippet";
-
- /**
- * The number of messages in the conversation.
- * <P>Type: INTEGER</P>
- */
- public static final String MESSAGE_COUNT = "msg_count";
- }
-
- /**
- * Contains constants for SMS related Intents that are broadcast.
- */
- public static final class Intents {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Intents() {
- }
-
- /**
- * Set by BroadcastReceiver to indicate that the message was handled
- * successfully.
- */
- public static final int RESULT_SMS_HANDLED = 1;
-
- /**
- * Set by BroadcastReceiver to indicate a generic error while
- * processing the message.
- */
- public static final int RESULT_SMS_GENERIC_ERROR = 2;
-
- /**
- * Set by BroadcastReceiver to indicate insufficient memory to store
- * the message.
- */
- public static final int RESULT_SMS_OUT_OF_MEMORY = 3;
-
- /**
- * Set by BroadcastReceiver to indicate that the message, while
- * possibly valid, is of a format or encoding that is not
- * supported.
- */
- public static final int RESULT_SMS_UNSUPPORTED = 4;
-
- /**
- * Set by BroadcastReceiver to indicate a duplicate incoming message.
- */
- public static final int RESULT_SMS_DUPLICATED = 5;
-
- /**
- * Activity action: Ask the user to change the default
- * SMS application. This will show a dialog that asks the
- * user whether they want to replace the current default
- * SMS application with the one specified in
- * {@link #EXTRA_PACKAGE_NAME}.
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_CHANGE_DEFAULT =
- "android.provider.Telephony.ACTION_CHANGE_DEFAULT";
-
- /**
- * The PackageName string passed in as an
- * extra for {@link #ACTION_CHANGE_DEFAULT}
- *
- * @see #ACTION_CHANGE_DEFAULT
- */
- public static final String EXTRA_PACKAGE_NAME = "package";
-
- /**
- * Broadcast Action: A new text-based SMS message has been received
- * by the device. This intent will only be delivered to the default
- * sms app. That app is responsible for writing the message and notifying
- * the user. The intent will have the following extra values:</p>
- *
- * <ul>
- * <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
- * that make up the message.</li>
- * <li><em>"format"</em> - A String describing the format of the PDUs. It can
- * be either "3gpp" or "3gpp2".</li>
- * <li><em>"subscription"</em> - An optional long value of the subscription id which
- * received the message.</li>
- * <li><em>"slot"</em> - An optional int value of the SIM slot containing the
- * subscription.</li>
- * <li><em>"phone"</em> - An optional int value of the phone id associated with the
- * subscription.</li>
- * <li><em>"errorCode"</em> - An optional int error code associated with receiving
- * the message.</li>
- * </ul>
- *
- * <p>The extra values can be extracted using
- * {@link #getMessagesFromIntent(Intent)}.</p>
- *
- * <p>If a BroadcastReceiver encounters an error while processing
- * this intent it should set the result code appropriately.</p>
- *
- * <p class="note"><strong>Note:</strong>
- * The broadcast receiver that filters for this intent must declare
- * {@link android.Manifest.permission#BROADCAST_SMS} as a required permission in
- * the <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
- * <receiver>}</a> tag.
- *
- * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String SMS_DELIVER_ACTION =
- "android.provider.Telephony.SMS_DELIVER";
-
- /**
- * Broadcast Action: A new text-based SMS message has been received
- * by the device. This intent will be delivered to all registered
- * receivers as a notification. These apps are not expected to write the
- * message or notify the user. The intent will have the following extra
- * values:</p>
- *
- * <ul>
- * <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
- * that make up the message.</li>
- * </ul>
- *
- * <p>The extra values can be extracted using
- * {@link #getMessagesFromIntent(Intent)}.</p>
- *
- * <p>If a BroadcastReceiver encounters an error while processing
- * this intent it should set the result code appropriately.</p>
- *
- * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String SMS_RECEIVED_ACTION =
- "android.provider.Telephony.SMS_RECEIVED";
-
- /**
- * Broadcast Action: A new data based SMS message has been received
- * by the device. This intent will be delivered to all registered
- * receivers as a notification. The intent will have the following extra
- * values:</p>
- *
- * <ul>
- * <li><em>"pdus"</em> - An Object[] of byte[]s containing the PDUs
- * that make up the message.</li>
- * </ul>
- *
- * <p>The extra values can be extracted using
- * {@link #getMessagesFromIntent(Intent)}.</p>
- *
- * <p>If a BroadcastReceiver encounters an error while processing
- * this intent it should set the result code appropriately.</p>
- *
- * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String DATA_SMS_RECEIVED_ACTION =
- "android.intent.action.DATA_SMS_RECEIVED";
-
- /**
- * Broadcast Action: A new WAP PUSH message has been received by the
- * device. This intent will only be delivered to the default
- * sms app. That app is responsible for writing the message and notifying
- * the user. The intent will have the following extra values:</p>
- *
- * <ul>
- * <li><em>"transactionId"</em> - (Integer) The WAP transaction ID</li>
- * <li><em>"pduType"</em> - (Integer) The WAP PDU type</li>
- * <li><em>"header"</em> - (byte[]) The header of the message</li>
- * <li><em>"data"</em> - (byte[]) The data payload of the message</li>
- * <li><em>"contentTypeParameters" </em>
- * -(HashMap<String,String>) Any parameters associated with the content type
- * (decoded from the WSP Content-Type header)</li>
- * <li><em>"subscription"</em> - An optional long value of the subscription id which
- * received the message.</li>
- * <li><em>"slot"</em> - An optional int value of the SIM slot containing the
- * subscription.</li>
- * <li><em>"phone"</em> - An optional int value of the phone id associated with the
- * subscription.</li>
- * </ul>
- *
- * <p>If a BroadcastReceiver encounters an error while processing
- * this intent it should set the result code appropriately.</p>
- *
- * <p>The contentTypeParameters extra value is map of content parameters keyed by
- * their names.</p>
- *
- * <p>If any unassigned well-known parameters are encountered, the key of the map will
- * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter. If
- * a parameter has No-Value the value in the map will be null.</p>
- *
- * <p>Requires {@link android.Manifest.permission#RECEIVE_MMS} or
- * {@link android.Manifest.permission#RECEIVE_WAP_PUSH} (depending on WAP PUSH type) to
- * receive.</p>
- *
- * <p class="note"><strong>Note:</strong>
- * The broadcast receiver that filters for this intent must declare
- * {@link android.Manifest.permission#BROADCAST_WAP_PUSH} as a required permission in
- * the <a href="{@docRoot}guide/topics/manifest/receiver-element.html">{@code
- * <receiver>}</a> tag.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String WAP_PUSH_DELIVER_ACTION =
- "android.provider.Telephony.WAP_PUSH_DELIVER";
-
- /**
- * Broadcast Action: A new WAP PUSH message has been received by the
- * device. This intent will be delivered to all registered
- * receivers as a notification. These apps are not expected to write the
- * message or notify the user. The intent will have the following extra
- * values:</p>
- *
- * <ul>
- * <li><em>"transactionId"</em> - (Integer) The WAP transaction ID</li>
- * <li><em>"pduType"</em> - (Integer) The WAP PDU type</li>
- * <li><em>"header"</em> - (byte[]) The header of the message</li>
- * <li><em>"data"</em> - (byte[]) The data payload of the message</li>
- * <li><em>"contentTypeParameters"</em>
- * - (HashMap<String,String>) Any parameters associated with the content type
- * (decoded from the WSP Content-Type header)</li>
- * </ul>
- *
- * <p>If a BroadcastReceiver encounters an error while processing
- * this intent it should set the result code appropriately.</p>
- *
- * <p>The contentTypeParameters extra value is map of content parameters keyed by
- * their names.</p>
- *
- * <p>If any unassigned well-known parameters are encountered, the key of the map will
- * be 'unassigned/0x...', where '...' is the hex value of the unassigned parameter. If
- * a parameter has No-Value the value in the map will be null.</p>
- *
- * <p>Requires {@link android.Manifest.permission#RECEIVE_MMS} or
- * {@link android.Manifest.permission#RECEIVE_WAP_PUSH} (depending on WAP PUSH type) to
- * receive.</p>
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String WAP_PUSH_RECEIVED_ACTION =
- "android.provider.Telephony.WAP_PUSH_RECEIVED";
-
- /**
- * Broadcast Action: A new Cell Broadcast message has been received
- * by the device. The intent will have the following extra
- * values:</p>
- *
- * <ul>
- * <li><em>"message"</em> - An SmsCbMessage object containing the broadcast message
- * data. This is not an emergency alert, so ETWS and CMAS data will be null.</li>
- * </ul>
- *
- * <p>The extra values can be extracted using
- * {@link #getMessagesFromIntent(Intent)}.</p>
- *
- * <p>If a BroadcastReceiver encounters an error while processing
- * this intent it should set the result code appropriately.</p>
- *
- * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String SMS_CB_RECEIVED_ACTION =
- "android.provider.Telephony.SMS_CB_RECEIVED";
-
- /**
- * Action: A SMS based carrier provision intent. Used to identify default
- * carrier provisioning app on the device.
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @TestApi
- public static final String SMS_CARRIER_PROVISION_ACTION =
- "android.provider.Telephony.SMS_CARRIER_PROVISION";
-
- /**
- * Broadcast Action: A new Emergency Broadcast message has been received
- * by the device. The intent will have the following extra
- * values:</p>
- *
- * <ul>
- * <li><em>"message"</em> - An SmsCbMessage object containing the broadcast message
- * data, including ETWS or CMAS warning notification info if present.</li>
- * </ul>
- *
- * <p>The extra values can be extracted using
- * {@link #getMessagesFromIntent(Intent)}.</p>
- *
- * <p>If a BroadcastReceiver encounters an error while processing
- * this intent it should set the result code appropriately.</p>
- *
- * <p>Requires {@link android.Manifest.permission#RECEIVE_EMERGENCY_BROADCAST} to
- * receive.</p>
- * @removed
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String SMS_EMERGENCY_CB_RECEIVED_ACTION =
- "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED";
-
- /**
- * Broadcast Action: A new CDMA SMS has been received containing Service Category
- * Program Data (updates the list of enabled broadcast channels). The intent will
- * have the following extra values:</p>
- *
- * <ul>
- * <li><em>"operations"</em> - An array of CdmaSmsCbProgramData objects containing
- * the service category operations (add/delete/clear) to perform.</li>
- * </ul>
- *
- * <p>The extra values can be extracted using
- * {@link #getMessagesFromIntent(Intent)}.</p>
- *
- * <p>If a BroadcastReceiver encounters an error while processing
- * this intent it should set the result code appropriately.</p>
- *
- * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION =
- "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED";
-
- /**
- * Broadcast Action: The SIM storage for SMS messages is full. If
- * space is not freed, messages targeted for the SIM (class 2) may
- * not be saved.
- *
- * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String SIM_FULL_ACTION =
- "android.provider.Telephony.SIM_FULL";
-
- /**
- * Broadcast Action: An incoming SMS has been rejected by the
- * telephony framework. This intent is sent in lieu of any
- * of the RECEIVED_ACTION intents. The intent will have the
- * following extra value:</p>
- *
- * <ul>
- * <li><em>"result"</em> - An int result code, e.g. {@link #RESULT_SMS_OUT_OF_MEMORY}
- * indicating the error returned to the network.</li>
- * </ul>
- *
- * <p>Requires {@link android.Manifest.permission#RECEIVE_SMS} to receive.</p>
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String SMS_REJECTED_ACTION =
- "android.provider.Telephony.SMS_REJECTED";
-
- /**
- * Broadcast Action: An incoming MMS has been downloaded. The intent is sent to all
- * users, except for secondary users where SMS has been disabled and to managed
- * profiles.
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String MMS_DOWNLOADED_ACTION =
- "android.provider.Telephony.MMS_DOWNLOADED";
-
- /**
- * Broadcast action: When the default SMS package changes,
- * the previous default SMS package and the new default SMS
- * package are sent this broadcast to notify them of the change.
- * A boolean is specified in {@link #EXTRA_IS_DEFAULT_SMS_APP} to
- * indicate whether the package is the new default SMS package.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_DEFAULT_SMS_PACKAGE_CHANGED =
- "android.provider.action.DEFAULT_SMS_PACKAGE_CHANGED";
-
- /**
- * The IsDefaultSmsApp boolean passed as an
- * extra for {@link #ACTION_DEFAULT_SMS_PACKAGE_CHANGED} to indicate whether the
- * SMS app is becoming the default SMS app or is no longer the default.
- *
- * @see #ACTION_DEFAULT_SMS_PACKAGE_CHANGED
- */
- public static final String EXTRA_IS_DEFAULT_SMS_APP =
- "android.provider.extra.IS_DEFAULT_SMS_APP";
-
- /**
- * Broadcast action: When a change is made to the SmsProvider or
- * MmsProvider by a process other than the default SMS application,
- * this intent is broadcast to the default SMS application so it can
- * re-sync or update the change. The uri that was used to call the provider
- * can be retrieved from the intent with getData(). The actual affected uris
- * (which would depend on the selection specified) are not included.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_EXTERNAL_PROVIDER_CHANGE =
- "android.provider.action.EXTERNAL_PROVIDER_CHANGE";
-
- /**
- * Read the PDUs out of an {@link #SMS_RECEIVED_ACTION} or a
- * {@link #DATA_SMS_RECEIVED_ACTION} intent.
- *
- * @param intent the intent to read from
- * @return an array of SmsMessages for the PDUs
- */
- public static SmsMessage[] getMessagesFromIntent(Intent intent) {
- Object[] messages;
- try {
- messages = (Object[]) intent.getSerializableExtra("pdus");
- }
- catch (ClassCastException e) {
- Rlog.e(TAG, "getMessagesFromIntent: " + e);
- return null;
- }
-
- if (messages == null) {
- Rlog.e(TAG, "pdus does not exist in the intent");
- return null;
- }
-
- String format = intent.getStringExtra("format");
- int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
- SubscriptionManager.getDefaultSmsSubscriptionId());
-
- Rlog.v(TAG, " getMessagesFromIntent sub_id : " + subId);
-
- int pduCount = messages.length;
- SmsMessage[] msgs = new SmsMessage[pduCount];
-
- for (int i = 0; i < pduCount; i++) {
- byte[] pdu = (byte[]) messages[i];
- msgs[i] = SmsMessage.createFromPdu(pdu, format);
- if (msgs[i] != null) msgs[i].setSubId(subId);
- }
- return msgs;
- }
- }
- }
-
- /**
- * Base columns for tables that contain MMSs.
- */
- public interface BaseMmsColumns extends BaseColumns {
-
- /** Message box: all messages. */
- public static final int MESSAGE_BOX_ALL = 0;
- /** Message box: inbox. */
- public static final int MESSAGE_BOX_INBOX = 1;
- /** Message box: sent messages. */
- public static final int MESSAGE_BOX_SENT = 2;
- /** Message box: drafts. */
- public static final int MESSAGE_BOX_DRAFTS = 3;
- /** Message box: outbox. */
- public static final int MESSAGE_BOX_OUTBOX = 4;
- /** Message box: failed. */
- public static final int MESSAGE_BOX_FAILED = 5;
-
- /**
- * The thread ID of the message.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String THREAD_ID = "thread_id";
-
- /**
- * The date the message was received.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String DATE = "date";
-
- /**
- * The date the message was sent.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String DATE_SENT = "date_sent";
-
- /**
- * The box which the message belongs to, e.g. {@link #MESSAGE_BOX_INBOX}.
- * <P>Type: INTEGER</P>
- */
- public static final String MESSAGE_BOX = "msg_box";
-
- /**
- * Has the message been read?
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String READ = "read";
-
- /**
- * Has the message been seen by the user? The "seen" flag determines
- * whether we need to show a new message notification.
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String SEEN = "seen";
-
- /**
- * Does the message have only a text part (can also have a subject) with
- * no picture, slideshow, sound, etc. parts?
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String TEXT_ONLY = "text_only";
-
- /**
- * The {@code Message-ID} of the message.
- * <P>Type: TEXT</P>
- */
- public static final String MESSAGE_ID = "m_id";
-
- /**
- * The subject of the message, if present.
- * <P>Type: TEXT</P>
- */
- public static final String SUBJECT = "sub";
-
- /**
- * The character set of the subject, if present.
- * <P>Type: INTEGER</P>
- */
- public static final String SUBJECT_CHARSET = "sub_cs";
-
- /**
- * The {@code Content-Type} of the message.
- * <P>Type: TEXT</P>
- */
- public static final String CONTENT_TYPE = "ct_t";
-
- /**
- * The {@code Content-Location} of the message.
- * <P>Type: TEXT</P>
- */
- public static final String CONTENT_LOCATION = "ct_l";
-
- /**
- * The expiry time of the message.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String EXPIRY = "exp";
-
- /**
- * The class of the message.
- * <P>Type: TEXT</P>
- */
- public static final String MESSAGE_CLASS = "m_cls";
-
- /**
- * The type of the message defined by MMS spec.
- * <P>Type: INTEGER</P>
- */
- public static final String MESSAGE_TYPE = "m_type";
-
- /**
- * The version of the specification that this message conforms to.
- * <P>Type: INTEGER</P>
- */
- public static final String MMS_VERSION = "v";
-
- /**
- * The size of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String MESSAGE_SIZE = "m_size";
-
- /**
- * The priority of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String PRIORITY = "pri";
-
- /**
- * The {@code read-report} of the message.
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String READ_REPORT = "rr";
-
- /**
- * Is read report allowed?
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String REPORT_ALLOWED = "rpt_a";
-
- /**
- * The {@code response-status} of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String RESPONSE_STATUS = "resp_st";
-
- /**
- * The {@code status} of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String STATUS = "st";
-
- /**
- * The {@code transaction-id} of the message.
- * <P>Type: TEXT</P>
- */
- public static final String TRANSACTION_ID = "tr_id";
-
- /**
- * The {@code retrieve-status} of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String RETRIEVE_STATUS = "retr_st";
-
- /**
- * The {@code retrieve-text} of the message.
- * <P>Type: TEXT</P>
- */
- public static final String RETRIEVE_TEXT = "retr_txt";
-
- /**
- * The character set of the retrieve-text.
- * <P>Type: INTEGER</P>
- */
- public static final String RETRIEVE_TEXT_CHARSET = "retr_txt_cs";
-
- /**
- * The {@code read-status} of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String READ_STATUS = "read_status";
-
- /**
- * The {@code content-class} of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String CONTENT_CLASS = "ct_cls";
-
- /**
- * The {@code delivery-report} of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String DELIVERY_REPORT = "d_rpt";
-
- /**
- * The {@code delivery-time-token} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String DELIVERY_TIME_TOKEN = "d_tm_tok";
-
- /**
- * The {@code delivery-time} of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String DELIVERY_TIME = "d_tm";
-
- /**
- * The {@code response-text} of the message.
- * <P>Type: TEXT</P>
- */
- public static final String RESPONSE_TEXT = "resp_txt";
-
- /**
- * The {@code sender-visibility} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String SENDER_VISIBILITY = "s_vis";
-
- /**
- * The {@code reply-charging} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String REPLY_CHARGING = "r_chg";
-
- /**
- * The {@code reply-charging-deadline-token} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String REPLY_CHARGING_DEADLINE_TOKEN = "r_chg_dl_tok";
-
- /**
- * The {@code reply-charging-deadline} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String REPLY_CHARGING_DEADLINE = "r_chg_dl";
-
- /**
- * The {@code reply-charging-id} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String REPLY_CHARGING_ID = "r_chg_id";
-
- /**
- * The {@code reply-charging-size} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String REPLY_CHARGING_SIZE = "r_chg_sz";
-
- /**
- * The {@code previously-sent-by} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String PREVIOUSLY_SENT_BY = "p_s_by";
-
- /**
- * The {@code previously-sent-date} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String PREVIOUSLY_SENT_DATE = "p_s_d";
-
- /**
- * The {@code store} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String STORE = "store";
-
- /**
- * The {@code mm-state} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String MM_STATE = "mm_st";
-
- /**
- * The {@code mm-flags-token} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String MM_FLAGS_TOKEN = "mm_flg_tok";
-
- /**
- * The {@code mm-flags} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String MM_FLAGS = "mm_flg";
-
- /**
- * The {@code store-status} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String STORE_STATUS = "store_st";
-
- /**
- * The {@code store-status-text} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String STORE_STATUS_TEXT = "store_st_txt";
-
- /**
- * The {@code stored} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String STORED = "stored";
-
- /**
- * The {@code totals} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String TOTALS = "totals";
-
- /**
- * The {@code mbox-totals} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String MBOX_TOTALS = "mb_t";
-
- /**
- * The {@code mbox-totals-token} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String MBOX_TOTALS_TOKEN = "mb_t_tok";
-
- /**
- * The {@code quotas} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String QUOTAS = "qt";
-
- /**
- * The {@code mbox-quotas} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String MBOX_QUOTAS = "mb_qt";
-
- /**
- * The {@code mbox-quotas-token} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String MBOX_QUOTAS_TOKEN = "mb_qt_tok";
-
- /**
- * The {@code message-count} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String MESSAGE_COUNT = "m_cnt";
-
- /**
- * The {@code start} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String START = "start";
-
- /**
- * The {@code distribution-indicator} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String DISTRIBUTION_INDICATOR = "d_ind";
-
- /**
- * The {@code element-descriptor} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String ELEMENT_DESCRIPTOR = "e_des";
-
- /**
- * The {@code limit} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String LIMIT = "limit";
-
- /**
- * The {@code recommended-retrieval-mode} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String RECOMMENDED_RETRIEVAL_MODE = "r_r_mod";
-
- /**
- * The {@code recommended-retrieval-mode-text} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String RECOMMENDED_RETRIEVAL_MODE_TEXT = "r_r_mod_txt";
-
- /**
- * The {@code status-text} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String STATUS_TEXT = "st_txt";
-
- /**
- * The {@code applic-id} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String APPLIC_ID = "apl_id";
-
- /**
- * The {@code reply-applic-id} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String REPLY_APPLIC_ID = "r_apl_id";
-
- /**
- * The {@code aux-applic-id} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String AUX_APPLIC_ID = "aux_apl_id";
-
- /**
- * The {@code drm-content} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String DRM_CONTENT = "drm_c";
-
- /**
- * The {@code adaptation-allowed} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String ADAPTATION_ALLOWED = "adp_a";
-
- /**
- * The {@code replace-id} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String REPLACE_ID = "repl_id";
-
- /**
- * The {@code cancel-id} of the message.
- * <P>Type: TEXT</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String CANCEL_ID = "cl_id";
-
- /**
- * The {@code cancel-status} of the message.
- * <P>Type: INTEGER</P>
- * @deprecated this column is no longer supported.
- * @hide
- */
- @Deprecated
- public static final String CANCEL_STATUS = "cl_st";
-
- /**
- * Is the message locked?
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String LOCKED = "locked";
-
- /**
- * The subscription to which the message belongs to. Its value will be
- * < 0 if the sub id cannot be determined.
- * <p>Type: INTEGER (long)</p>
- */
- public static final String SUBSCRIPTION_ID = "sub_id";
-
- /**
- * The identity of the sender of a sent message. It is
- * usually the package name of the app which sends the message.
- * <p class="note"><strong>Note:</strong>
- * This column is read-only. It is set by the provider and can not be changed by apps.
- * <p>Type: TEXT</p>
- */
- public static final String CREATOR = "creator";
- }
-
- /**
- * Columns for the "canonical_addresses" table used by MMS and SMS.
- */
- public interface CanonicalAddressesColumns extends BaseColumns {
- /**
- * An address used in MMS or SMS. Email addresses are
- * converted to lower case and are compared by string
- * equality. Other addresses are compared using
- * PHONE_NUMBERS_EQUAL.
- * <P>Type: TEXT</P>
- */
- public static final String ADDRESS = "address";
- }
-
- /**
- * Columns for the "threads" table used by MMS and SMS.
- */
- public interface ThreadsColumns extends BaseColumns {
-
- /**
- * The date at which the thread was created.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String DATE = "date";
-
- /**
- * A string encoding of the recipient IDs of the recipients of
- * the message, in numerical order and separated by spaces.
- * <P>Type: TEXT</P>
- */
- public static final String RECIPIENT_IDS = "recipient_ids";
-
- /**
- * The message count of the thread.
- * <P>Type: INTEGER</P>
- */
- public static final String MESSAGE_COUNT = "message_count";
-
- /**
- * Indicates whether all messages of the thread have been read.
- * <P>Type: INTEGER</P>
- */
- public static final String READ = "read";
-
- /**
- * The snippet of the latest message in the thread.
- * <P>Type: TEXT</P>
- */
- public static final String SNIPPET = "snippet";
-
- /**
- * The charset of the snippet.
- * <P>Type: INTEGER</P>
- */
- public static final String SNIPPET_CHARSET = "snippet_cs";
-
- /**
- * Type of the thread, either {@link Threads#COMMON_THREAD} or
- * {@link Threads#BROADCAST_THREAD}.
- * <P>Type: INTEGER</P>
- */
- public static final String TYPE = "type";
-
- /**
- * Indicates whether there is a transmission error in the thread.
- * <P>Type: INTEGER</P>
- */
- public static final String ERROR = "error";
-
- /**
- * Indicates whether this thread contains any attachments.
- * <P>Type: INTEGER</P>
- */
- public static final String HAS_ATTACHMENT = "has_attachment";
-
- /**
- * If the thread is archived
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String ARCHIVED = "archived";
- }
-
- /**
- * Helper functions for the "threads" table used by MMS and SMS.
- */
- public static final class Threads implements ThreadsColumns {
-
- private static final String[] ID_PROJECTION = { BaseColumns._ID };
-
- /**
- * Private {@code content://} style URL for this table. Used by
- * {@link #getOrCreateThreadId(android.content.Context, java.util.Set)}.
- */
- private static final Uri THREAD_ID_CONTENT_URI = Uri.parse(
- "content://mms-sms/threadID");
-
- /**
- * The {@code content://} style URL for this table, by conversation.
- */
- public static final Uri CONTENT_URI = Uri.withAppendedPath(
- MmsSms.CONTENT_URI, "conversations");
-
- /**
- * The {@code content://} style URL for this table, for obsolete threads.
- */
- public static final Uri OBSOLETE_THREADS_URI = Uri.withAppendedPath(
- CONTENT_URI, "obsolete");
-
- /** Thread type: common thread. */
- public static final int COMMON_THREAD = 0;
-
- /** Thread type: broadcast thread. */
- public static final int BROADCAST_THREAD = 1;
-
- /**
- * Not instantiable.
- * @hide
- */
- private Threads() {
- }
-
- /**
- * This is a single-recipient version of {@code getOrCreateThreadId}.
- * It's convenient for use with SMS messages.
- * @param context the context object to use.
- * @param recipient the recipient to send to.
- */
- public static long getOrCreateThreadId(Context context, String recipient) {
- Set<String> recipients = new HashSet<String>();
-
- recipients.add(recipient);
- return getOrCreateThreadId(context, recipients);
- }
-
- /**
- * Given the recipients list and subject of an unsaved message,
- * return its thread ID. If the message starts a new thread,
- * allocate a new thread ID. Otherwise, use the appropriate
- * existing thread ID.
- *
- * <p>Find the thread ID of the same set of recipients (in any order,
- * without any additions). If one is found, return it. Otherwise,
- * return a unique thread ID.</p>
- */
- public static long getOrCreateThreadId(
- Context context, Set<String> recipients) {
- Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon();
-
- for (String recipient : recipients) {
- if (Mms.isEmailAddress(recipient)) {
- recipient = Mms.extractAddrSpec(recipient);
- }
-
- uriBuilder.appendQueryParameter("recipient", recipient);
- }
-
- Uri uri = uriBuilder.build();
- //if (DEBUG) Rlog.v(TAG, "getOrCreateThreadId uri: " + uri);
-
- Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
- uri, ID_PROJECTION, null, null, null);
- if (cursor != null) {
- try {
- if (cursor.moveToFirst()) {
- return cursor.getLong(0);
- } else {
- Rlog.e(TAG, "getOrCreateThreadId returned no rows!");
- }
- } finally {
- cursor.close();
- }
- }
-
- Rlog.e(TAG, "getOrCreateThreadId failed with " + recipients.size() + " recipients");
- throw new IllegalArgumentException("Unable to find or allocate a thread ID.");
- }
- }
-
- /**
- * Contains all MMS messages.
- */
- public static final class Mms implements BaseMmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Mms() {
- }
-
- /**
- * The {@code content://} URI for this table.
- */
- public static final Uri CONTENT_URI = Uri.parse("content://mms");
-
- /**
- * Content URI for getting MMS report requests.
- */
- public static final Uri REPORT_REQUEST_URI = Uri.withAppendedPath(
- CONTENT_URI, "report-request");
-
- /**
- * Content URI for getting MMS report status.
- */
- public static final Uri REPORT_STATUS_URI = Uri.withAppendedPath(
- CONTENT_URI, "report-status");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
-
- /**
- * Regex pattern for names and email addresses.
- * <ul>
- * <li><em>mailbox</em> = {@code name-addr}</li>
- * <li><em>name-addr</em> = {@code [display-name] angle-addr}</li>
- * <li><em>angle-addr</em> = {@code [CFWS] "<" addr-spec ">" [CFWS]}</li>
- * </ul>
- * @hide
- */
- public static final Pattern NAME_ADDR_EMAIL_PATTERN =
- Pattern.compile("\\s*(\"[^\"]*\"|[^<>\"]+)\\s*<([^<>]+)>\\s*");
-
- /**
- * Helper method to query this table.
- * @hide
- */
- public static Cursor query(
- ContentResolver cr, String[] projection) {
- return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
- }
-
- /**
- * Helper method to query this table.
- * @hide
- */
- public static Cursor query(
- ContentResolver cr, String[] projection,
- String where, String orderBy) {
- return cr.query(CONTENT_URI, projection,
- where, null, orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
- }
-
- /**
- * Helper method to extract email address from address string.
- * @hide
- */
- public static String extractAddrSpec(String address) {
- Matcher match = NAME_ADDR_EMAIL_PATTERN.matcher(address);
-
- if (match.matches()) {
- return match.group(2);
- }
- return address;
- }
-
- /**
- * Is the specified address an email address?
- *
- * @param address the input address to test
- * @return true if address is an email address; false otherwise.
- * @hide
- */
- public static boolean isEmailAddress(String address) {
- if (TextUtils.isEmpty(address)) {
- return false;
- }
-
- String s = extractAddrSpec(address);
- Matcher match = Patterns.EMAIL_ADDRESS.matcher(s);
- return match.matches();
- }
-
- /**
- * Is the specified number a phone number?
- *
- * @param number the input number to test
- * @return true if number is a phone number; false otherwise.
- * @hide
- */
- public static boolean isPhoneNumber(String number) {
- if (TextUtils.isEmpty(number)) {
- return false;
- }
-
- Matcher match = Patterns.PHONE.matcher(number);
- return match.matches();
- }
-
- /**
- * Contains all MMS messages in the MMS app inbox.
- */
- public static final class Inbox implements BaseMmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Inbox() {
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri
- CONTENT_URI = Uri.parse("content://mms/inbox");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
- }
-
- /**
- * Contains all MMS messages in the MMS app sent folder.
- */
- public static final class Sent implements BaseMmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Sent() {
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri
- CONTENT_URI = Uri.parse("content://mms/sent");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
- }
-
- /**
- * Contains all MMS messages in the MMS app drafts folder.
- */
- public static final class Draft implements BaseMmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Draft() {
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri
- CONTENT_URI = Uri.parse("content://mms/drafts");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
- }
-
- /**
- * Contains all MMS messages in the MMS app outbox.
- */
- public static final class Outbox implements BaseMmsColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Outbox() {
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri
- CONTENT_URI = Uri.parse("content://mms/outbox");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "date DESC";
- }
-
- /**
- * Contains address information for an MMS message.
- */
- public static final class Addr implements BaseColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Addr() {
- }
-
- /**
- * The ID of MM which this address entry belongs to.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String MSG_ID = "msg_id";
-
- /**
- * The ID of contact entry in Phone Book.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String CONTACT_ID = "contact_id";
-
- /**
- * The address text.
- * <P>Type: TEXT</P>
- */
- public static final String ADDRESS = "address";
-
- /**
- * Type of address: must be one of {@code PduHeaders.BCC},
- * {@code PduHeaders.CC}, {@code PduHeaders.FROM}, {@code PduHeaders.TO}.
- * <P>Type: INTEGER</P>
- */
- public static final String TYPE = "type";
-
- /**
- * Character set of this entry (MMS charset value).
- * <P>Type: INTEGER</P>
- */
- public static final String CHARSET = "charset";
- }
-
- /**
- * Contains message parts.
- */
- public static final class Part implements BaseColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Part() {
- }
-
- /**
- * The identifier of the message which this part belongs to.
- * <P>Type: INTEGER</P>
- */
- public static final String MSG_ID = "mid";
-
- /**
- * The order of the part.
- * <P>Type: INTEGER</P>
- */
- public static final String SEQ = "seq";
-
- /**
- * The content type of the part.
- * <P>Type: TEXT</P>
- */
- public static final String CONTENT_TYPE = "ct";
-
- /**
- * The name of the part.
- * <P>Type: TEXT</P>
- */
- public static final String NAME = "name";
-
- /**
- * The charset of the part.
- * <P>Type: TEXT</P>
- */
- public static final String CHARSET = "chset";
-
- /**
- * The file name of the part.
- * <P>Type: TEXT</P>
- */
- public static final String FILENAME = "fn";
-
- /**
- * The content disposition of the part.
- * <P>Type: TEXT</P>
- */
- public static final String CONTENT_DISPOSITION = "cd";
-
- /**
- * The content ID of the part.
- * <P>Type: INTEGER</P>
- */
- public static final String CONTENT_ID = "cid";
-
- /**
- * The content location of the part.
- * <P>Type: INTEGER</P>
- */
- public static final String CONTENT_LOCATION = "cl";
-
- /**
- * The start of content-type of the message.
- * <P>Type: INTEGER</P>
- */
- public static final String CT_START = "ctt_s";
-
- /**
- * The type of content-type of the message.
- * <P>Type: TEXT</P>
- */
- public static final String CT_TYPE = "ctt_t";
-
- /**
- * The location (on filesystem) of the binary data of the part.
- * <P>Type: INTEGER</P>
- */
- public static final String _DATA = "_data";
-
- /**
- * The message text.
- * <P>Type: TEXT</P>
- */
- public static final String TEXT = "text";
- }
-
- /**
- * Message send rate table.
- */
- public static final class Rate {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Rate() {
- }
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri CONTENT_URI = Uri.withAppendedPath(
- Mms.CONTENT_URI, "rate");
-
- /**
- * When a message was successfully sent.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String SENT_TIME = "sent_time";
- }
-
- /**
- * Intents class.
- */
- public static final class Intents {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Intents() {
- }
-
- /**
- * Indicates that the contents of specified URIs were changed.
- * The application which is showing or caching these contents
- * should be updated.
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String CONTENT_CHANGED_ACTION
- = "android.intent.action.CONTENT_CHANGED";
-
- /**
- * An extra field which stores the URI of deleted contents.
- */
- public static final String DELETED_CONTENTS = "deleted_contents";
- }
- }
-
- /**
- * Contains all MMS and SMS messages.
- */
- public static final class MmsSms implements BaseColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private MmsSms() {
- }
-
- /**
- * The column to distinguish SMS and MMS messages in query results.
- */
- public static final String TYPE_DISCRIMINATOR_COLUMN =
- "transport_type";
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri CONTENT_URI = Uri.parse("content://mms-sms/");
-
- /**
- * The {@code content://} style URL for this table, by conversation.
- */
- public static final Uri CONTENT_CONVERSATIONS_URI = Uri.parse(
- "content://mms-sms/conversations");
-
- /**
- * The {@code content://} style URL for this table, by phone number.
- */
- public static final Uri CONTENT_FILTER_BYPHONE_URI = Uri.parse(
- "content://mms-sms/messages/byphone");
-
- /**
- * The {@code content://} style URL for undelivered messages in this table.
- */
- public static final Uri CONTENT_UNDELIVERED_URI = Uri.parse(
- "content://mms-sms/undelivered");
-
- /**
- * The {@code content://} style URL for draft messages in this table.
- */
- public static final Uri CONTENT_DRAFT_URI = Uri.parse(
- "content://mms-sms/draft");
-
- /**
- * The {@code content://} style URL for locked messages in this table.
- */
- public static final Uri CONTENT_LOCKED_URI = Uri.parse(
- "content://mms-sms/locked");
-
- /**
- * Pass in a query parameter called "pattern" which is the text to search for.
- * The sort order is fixed to be: {@code thread_id ASC, date DESC}.
- */
- public static final Uri SEARCH_URI = Uri.parse(
- "content://mms-sms/search");
-
- // Constants for message protocol types.
-
- /** SMS protocol type. */
- public static final int SMS_PROTO = 0;
-
- /** MMS protocol type. */
- public static final int MMS_PROTO = 1;
-
- // Constants for error types of pending messages.
-
- /** Error type: no error. */
- public static final int NO_ERROR = 0;
-
- /** Error type: generic transient error. */
- public static final int ERR_TYPE_GENERIC = 1;
-
- /** Error type: SMS protocol transient error. */
- public static final int ERR_TYPE_SMS_PROTO_TRANSIENT = 2;
-
- /** Error type: MMS protocol transient error. */
- public static final int ERR_TYPE_MMS_PROTO_TRANSIENT = 3;
-
- /** Error type: transport failure. */
- public static final int ERR_TYPE_TRANSPORT_FAILURE = 4;
-
- /** Error type: permanent error (along with all higher error values). */
- public static final int ERR_TYPE_GENERIC_PERMANENT = 10;
-
- /** Error type: SMS protocol permanent error. */
- public static final int ERR_TYPE_SMS_PROTO_PERMANENT = 11;
-
- /** Error type: MMS protocol permanent error. */
- public static final int ERR_TYPE_MMS_PROTO_PERMANENT = 12;
-
- /**
- * Contains pending messages info.
- */
- public static final class PendingMessages implements BaseColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private PendingMessages() {
- }
-
- public static final Uri CONTENT_URI = Uri.withAppendedPath(
- MmsSms.CONTENT_URI, "pending");
-
- /**
- * The type of transport protocol (MMS or SMS).
- * <P>Type: INTEGER</P>
- */
- public static final String PROTO_TYPE = "proto_type";
-
- /**
- * The ID of the message to be sent or downloaded.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String MSG_ID = "msg_id";
-
- /**
- * The type of the message to be sent or downloaded.
- * This field is only valid for MM. For SM, its value is always set to 0.
- * <P>Type: INTEGER</P>
- */
- public static final String MSG_TYPE = "msg_type";
-
- /**
- * The type of the error code.
- * <P>Type: INTEGER</P>
- */
- public static final String ERROR_TYPE = "err_type";
-
- /**
- * The error code of sending/retrieving process.
- * <P>Type: INTEGER</P>
- */
- public static final String ERROR_CODE = "err_code";
-
- /**
- * How many times we tried to send or download the message.
- * <P>Type: INTEGER</P>
- */
- public static final String RETRY_INDEX = "retry_index";
-
- /**
- * The time to do next retry.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String DUE_TIME = "due_time";
-
- /**
- * The time we last tried to send or download the message.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String LAST_TRY = "last_try";
-
- /**
- * The subscription to which the message belongs to. Its value will be
- * < 0 if the sub id cannot be determined.
- * <p>Type: INTEGER (long) </p>
- */
- public static final String SUBSCRIPTION_ID = "pending_sub_id";
- }
-
- /**
- * Words table used by provider for full-text searches.
- * @hide
- */
- public static final class WordsTable {
-
- /**
- * Not instantiable.
- * @hide
- */
- private WordsTable() {}
-
- /**
- * Primary key.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String ID = "_id";
-
- /**
- * Source row ID.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String SOURCE_ROW_ID = "source_id";
-
- /**
- * Table ID (either 1 or 2).
- * <P>Type: INTEGER</P>
- */
- public static final String TABLE_ID = "table_to_use";
-
- /**
- * The words to index.
- * <P>Type: TEXT</P>
- */
- public static final String INDEXED_TEXT = "index_text";
- }
- }
-
- /**
- * Carriers class contains information about APNs, including MMSC information.
- */
- public static final class Carriers implements BaseColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private Carriers() {}
-
- /**
- * The {@code content://} style URL for this table.
- */
- public static final Uri CONTENT_URI = Uri.parse("content://telephony/carriers");
-
- /**
- * The default sort order for this table.
- */
- public static final String DEFAULT_SORT_ORDER = "name ASC";
-
- /**
- * Entry name.
- * <P>Type: TEXT</P>
- */
- public static final String NAME = "name";
-
- /**
- * APN name.
- * <P>Type: TEXT</P>
- */
- public static final String APN = "apn";
-
- /**
- * Proxy address.
- * <P>Type: TEXT</P>
- */
- public static final String PROXY = "proxy";
-
- /**
- * Proxy port.
- * <P>Type: TEXT</P>
- */
- public static final String PORT = "port";
-
- /**
- * MMS proxy address.
- * <P>Type: TEXT</P>
- */
- public static final String MMSPROXY = "mmsproxy";
-
- /**
- * MMS proxy port.
- * <P>Type: TEXT</P>
- */
- public static final String MMSPORT = "mmsport";
-
- /**
- * Server address.
- * <P>Type: TEXT</P>
- */
- public static final String SERVER = "server";
-
- /**
- * APN username.
- * <P>Type: TEXT</P>
- */
- public static final String USER = "user";
-
- /**
- * APN password.
- * <P>Type: TEXT</P>
- */
- public static final String PASSWORD = "password";
-
- /**
- * MMSC URL.
- * <P>Type: TEXT</P>
- */
- public static final String MMSC = "mmsc";
-
- /**
- * Mobile Country Code (MCC).
- * <P>Type: TEXT</P>
- */
- public static final String MCC = "mcc";
-
- /**
- * Mobile Network Code (MNC).
- * <P>Type: TEXT</P>
- */
- public static final String MNC = "mnc";
-
- /**
- * Numeric operator ID (as String). Usually {@code MCC + MNC}.
- * <P>Type: TEXT</P>
- */
- public static final String NUMERIC = "numeric";
-
- /**
- * Authentication type.
- * <P>Type: INTEGER</P>
- */
- public static final String AUTH_TYPE = "authtype";
-
- /**
- * Comma-delimited list of APN types.
- * <P>Type: TEXT</P>
- */
- public static final String TYPE = "type";
-
- /**
- * The protocol to use to connect to this APN.
- *
- * One of the {@code PDP_type} values in TS 27.007 section 10.1.1.
- * For example: {@code IP}, {@code IPV6}, {@code IPV4V6}, or {@code PPP}.
- * <P>Type: TEXT</P>
- */
- public static final String PROTOCOL = "protocol";
-
- /**
- * The protocol to use to connect to this APN when roaming.
- * The syntax is the same as protocol.
- * <P>Type: TEXT</P>
- */
- public static final String ROAMING_PROTOCOL = "roaming_protocol";
-
- /**
- * Is this the current APN?
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String CURRENT = "current";
-
- /**
- * Is this APN enabled?
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String CARRIER_ENABLED = "carrier_enabled";
-
- /**
- * Radio Access Technology info.
- * To check what values are allowed, refer to {@link android.telephony.ServiceState}.
- * This should be spread to other technologies,
- * but is currently only used for LTE (14) and eHRPD (13).
- * <P>Type: INTEGER</P>
- */
- public static final String BEARER = "bearer";
-
- /**
- * Radio Access Technology bitmask.
- * To check what values can be contained, refer to {@link android.telephony.ServiceState}.
- * 0 indicates all techs otherwise first bit refers to RAT/bearer 1, second bit refers to
- * RAT/bearer 2 and so on.
- * Bitmask for a radio tech R is (1 << (R - 1))
- * <P>Type: INTEGER</P>
- * @hide
- */
- public static final String BEARER_BITMASK = "bearer_bitmask";
-
- /**
- * MVNO type:
- * {@code SPN (Service Provider Name), IMSI, GID (Group Identifier Level 1)}.
- * <P>Type: TEXT</P>
- */
- public static final String MVNO_TYPE = "mvno_type";
-
- /**
- * MVNO data.
- * Use the following examples.
- * <ul>
- * <li>SPN: A MOBILE, BEN NL, ...</li>
- * <li>IMSI: 302720x94, 2060188, ...</li>
- * <li>GID: 4E, 33, ...</li>
- * </ul>
- * <P>Type: TEXT</P>
- */
- public static final String MVNO_MATCH_DATA = "mvno_match_data";
-
- /**
- * The subscription to which the APN belongs to
- * <p>Type: INTEGER (long) </p>
- */
- public static final String SUBSCRIPTION_ID = "sub_id";
-
- /**
- * The profile_id to which the APN saved in modem
- * <p>Type: INTEGER</p>
- *@hide
- */
- public static final String PROFILE_ID = "profile_id";
-
- /**
- * Is the apn setting to be set in modem
- * <P>Type: INTEGER (boolean)</P>
- *@hide
- */
- public static final String MODEM_COGNITIVE = "modem_cognitive";
-
- /**
- * The max connections of this apn
- * <p>Type: INTEGER</p>
- *@hide
- */
- public static final String MAX_CONNS = "max_conns";
-
- /**
- * The wait time for retry of the apn
- * <p>Type: INTEGER</p>
- *@hide
- */
- public static final String WAIT_TIME = "wait_time";
-
- /**
- * The time to limit max connection for the apn
- * <p>Type: INTEGER</p>
- *@hide
- */
- public static final String MAX_CONNS_TIME = "max_conns_time";
-
- /**
- * The MTU size of the mobile interface to which the APN connected
- * <p>Type: INTEGER </p>
- * @hide
- */
- public static final String MTU = "mtu";
-
- /**
- * Is this APN added/edited/deleted by a user or carrier?
- * <p>Type: INTEGER </p>
- * @hide
- */
- public static final String EDITED = "edited";
-
- /**
- * Is this APN visible to the user?
- * <p>Type: INTEGER (boolean) </p>
- * @hide
- */
- public static final String USER_VISIBLE = "user_visible";
-
- /**
- * Following are possible values for the EDITED field
- * @hide
- */
- public static final int UNEDITED = 0;
- /**
- * @hide
- */
- public static final int USER_EDITED = 1;
- /**
- * @hide
- */
- public static final int USER_DELETED = 2;
- /**
- * DELETED_BUT_PRESENT is an intermediate value used to indicate that an entry deleted
- * by the user is still present in the new APN database and therefore must remain tagged
- * as user deleted rather than completely removed from the database
- * @hide
- */
- public static final int USER_DELETED_BUT_PRESENT_IN_XML = 3;
- /**
- * @hide
- */
- public static final int CARRIER_EDITED = 4;
- /**
- * CARRIER_DELETED values are currently not used as there is no usecase. If they are used,
- * delete() will have to change accordingly. Currently it is hardcoded to USER_DELETED.
- * @hide
- */
- public static final int CARRIER_DELETED = 5;
- /**
- * @hide
- */
- public static final int CARRIER_DELETED_BUT_PRESENT_IN_XML = 6;
- }
-
- /**
- * Contains received SMS cell broadcast messages.
- * @hide
- */
- public static final class CellBroadcasts implements BaseColumns {
-
- /**
- * Not instantiable.
- * @hide
- */
- private CellBroadcasts() {}
-
- /**
- * The {@code content://} URI for this table.
- */
- public static final Uri CONTENT_URI = Uri.parse("content://cellbroadcasts");
-
- /**
- * Message geographical scope.
- * <P>Type: INTEGER</P>
- */
- public static final String GEOGRAPHICAL_SCOPE = "geo_scope";
-
- /**
- * Message serial number.
- * <P>Type: INTEGER</P>
- */
- public static final String SERIAL_NUMBER = "serial_number";
-
- /**
- * PLMN of broadcast sender. {@code SERIAL_NUMBER + PLMN + LAC + CID} uniquely identifies
- * a broadcast for duplicate detection purposes.
- * <P>Type: TEXT</P>
- */
- public static final String PLMN = "plmn";
-
- /**
- * Location Area (GSM) or Service Area (UMTS) of broadcast sender. Unused for CDMA.
- * Only included if Geographical Scope of message is not PLMN wide (01).
- * <P>Type: INTEGER</P>
- */
- public static final String LAC = "lac";
-
- /**
- * Cell ID of message sender (GSM/UMTS). Unused for CDMA. Only included when the
- * Geographical Scope of message is cell wide (00 or 11).
- * <P>Type: INTEGER</P>
- */
- public static final String CID = "cid";
-
- /**
- * Message code. <em>OBSOLETE: merged into SERIAL_NUMBER.</em>
- * <P>Type: INTEGER</P>
- */
- public static final String V1_MESSAGE_CODE = "message_code";
-
- /**
- * Message identifier. <em>OBSOLETE: renamed to SERVICE_CATEGORY.</em>
- * <P>Type: INTEGER</P>
- */
- public static final String V1_MESSAGE_IDENTIFIER = "message_id";
-
- /**
- * Service category (GSM/UMTS: message identifier; CDMA: service category).
- * <P>Type: INTEGER</P>
- */
- public static final String SERVICE_CATEGORY = "service_category";
-
- /**
- * Message language code.
- * <P>Type: TEXT</P>
- */
- public static final String LANGUAGE_CODE = "language";
-
- /**
- * Message body.
- * <P>Type: TEXT</P>
- */
- public static final String MESSAGE_BODY = "body";
-
- /**
- * Message delivery time.
- * <P>Type: INTEGER (long)</P>
- */
- public static final String DELIVERY_TIME = "date";
-
- /**
- * Has the message been viewed?
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String MESSAGE_READ = "read";
-
- /**
- * Message format (3GPP or 3GPP2).
- * <P>Type: INTEGER</P>
- */
- public static final String MESSAGE_FORMAT = "format";
-
- /**
- * Message priority (including emergency).
- * <P>Type: INTEGER</P>
- */
- public static final String MESSAGE_PRIORITY = "priority";
-
- /**
- * ETWS warning type (ETWS alerts only).
- * <P>Type: INTEGER</P>
- */
- public static final String ETWS_WARNING_TYPE = "etws_warning_type";
-
- /**
- * CMAS message class (CMAS alerts only).
- * <P>Type: INTEGER</P>
- */
- public static final String CMAS_MESSAGE_CLASS = "cmas_message_class";
-
- /**
- * CMAS category (CMAS alerts only).
- * <P>Type: INTEGER</P>
- */
- public static final String CMAS_CATEGORY = "cmas_category";
-
- /**
- * CMAS response type (CMAS alerts only).
- * <P>Type: INTEGER</P>
- */
- public static final String CMAS_RESPONSE_TYPE = "cmas_response_type";
-
- /**
- * CMAS severity (CMAS alerts only).
- * <P>Type: INTEGER</P>
- */
- public static final String CMAS_SEVERITY = "cmas_severity";
-
- /**
- * CMAS urgency (CMAS alerts only).
- * <P>Type: INTEGER</P>
- */
- public static final String CMAS_URGENCY = "cmas_urgency";
-
- /**
- * CMAS certainty (CMAS alerts only).
- * <P>Type: INTEGER</P>
- */
- public static final String CMAS_CERTAINTY = "cmas_certainty";
-
- /** The default sort order for this table. */
- public static final String DEFAULT_SORT_ORDER = DELIVERY_TIME + " DESC";
-
- /**
- * Query columns for instantiating {@link android.telephony.CellBroadcastMessage} objects.
- */
- public static final String[] QUERY_COLUMNS = {
- _ID,
- GEOGRAPHICAL_SCOPE,
- PLMN,
- LAC,
- CID,
- SERIAL_NUMBER,
- SERVICE_CATEGORY,
- LANGUAGE_CODE,
- MESSAGE_BODY,
- DELIVERY_TIME,
- MESSAGE_READ,
- MESSAGE_FORMAT,
- MESSAGE_PRIORITY,
- ETWS_WARNING_TYPE,
- CMAS_MESSAGE_CLASS,
- CMAS_CATEGORY,
- CMAS_RESPONSE_TYPE,
- CMAS_SEVERITY,
- CMAS_URGENCY,
- CMAS_CERTAINTY
- };
- }
-}
diff --git a/src/java/android/telephony/SmsCbCmasInfo.java b/src/java/android/telephony/SmsCbCmasInfo.java
deleted file mode 100644
index c912924..0000000
--- a/src/java/android/telephony/SmsCbCmasInfo.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Contains CMAS warning notification Type 1 elements for a {@link SmsCbMessage}.
- * Supported values for each element are defined in TIA-1149-0-1 (CMAS over CDMA) and
- * 3GPP TS 23.041 (for GSM/UMTS).
- *
- * {@hide}
- */
-public class SmsCbCmasInfo implements Parcelable {
-
- // CMAS message class (in GSM/UMTS message identifier or CDMA service category).
-
- /** Presidential-level alert (Korean Public Alert System Class 0 message). */
- public static final int CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT = 0x00;
-
- /** Extreme threat to life and property (Korean Public Alert System Class 1 message). */
- public static final int CMAS_CLASS_EXTREME_THREAT = 0x01;
-
- /** Severe threat to life and property (Korean Public Alert System Class 1 message). */
- public static final int CMAS_CLASS_SEVERE_THREAT = 0x02;
-
- /** Child abduction emergency (AMBER Alert). */
- public static final int CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY = 0x03;
-
- /** CMAS test message. */
- public static final int CMAS_CLASS_REQUIRED_MONTHLY_TEST = 0x04;
-
- /** CMAS exercise. */
- public static final int CMAS_CLASS_CMAS_EXERCISE = 0x05;
-
- /** CMAS category for operator defined use. */
- public static final int CMAS_CLASS_OPERATOR_DEFINED_USE = 0x06;
-
- /** CMAS category for warning types that are reserved for future extension. */
- public static final int CMAS_CLASS_UNKNOWN = -1;
-
- // CMAS alert category (in CDMA type 1 elements record).
-
- /** CMAS alert category: Geophysical including landslide. */
- public static final int CMAS_CATEGORY_GEO = 0x00;
-
- /** CMAS alert category: Meteorological including flood. */
- public static final int CMAS_CATEGORY_MET = 0x01;
-
- /** CMAS alert category: General emergency and public safety. */
- public static final int CMAS_CATEGORY_SAFETY = 0x02;
-
- /** CMAS alert category: Law enforcement, military, homeland/local/private security. */
- public static final int CMAS_CATEGORY_SECURITY = 0x03;
-
- /** CMAS alert category: Rescue and recovery. */
- public static final int CMAS_CATEGORY_RESCUE = 0x04;
-
- /** CMAS alert category: Fire suppression and rescue. */
- public static final int CMAS_CATEGORY_FIRE = 0x05;
-
- /** CMAS alert category: Medical and public health. */
- public static final int CMAS_CATEGORY_HEALTH = 0x06;
-
- /** CMAS alert category: Pollution and other environmental. */
- public static final int CMAS_CATEGORY_ENV = 0x07;
-
- /** CMAS alert category: Public and private transportation. */
- public static final int CMAS_CATEGORY_TRANSPORT = 0x08;
-
- /** CMAS alert category: Utility, telecom, other non-transport infrastructure. */
- public static final int CMAS_CATEGORY_INFRA = 0x09;
-
- /** CMAS alert category: Chem, bio, radiological, nuclear, high explosive threat or attack. */
- public static final int CMAS_CATEGORY_CBRNE = 0x0a;
-
- /** CMAS alert category: Other events. */
- public static final int CMAS_CATEGORY_OTHER = 0x0b;
-
- /**
- * CMAS alert category is unknown. The category is only available for CDMA broadcasts
- * containing a type 1 elements record, so GSM and UMTS broadcasts always return unknown.
- */
- public static final int CMAS_CATEGORY_UNKNOWN = -1;
-
- // CMAS response type (in CDMA type 1 elements record).
-
- /** CMAS response type: Take shelter in place. */
- public static final int CMAS_RESPONSE_TYPE_SHELTER = 0x00;
-
- /** CMAS response type: Evacuate (Relocate). */
- public static final int CMAS_RESPONSE_TYPE_EVACUATE = 0x01;
-
- /** CMAS response type: Make preparations. */
- public static final int CMAS_RESPONSE_TYPE_PREPARE = 0x02;
-
- /** CMAS response type: Execute a pre-planned activity. */
- public static final int CMAS_RESPONSE_TYPE_EXECUTE = 0x03;
-
- /** CMAS response type: Attend to information sources. */
- public static final int CMAS_RESPONSE_TYPE_MONITOR = 0x04;
-
- /** CMAS response type: Avoid hazard. */
- public static final int CMAS_RESPONSE_TYPE_AVOID = 0x05;
-
- /** CMAS response type: Evaluate the information in this message (not for public warnings). */
- public static final int CMAS_RESPONSE_TYPE_ASSESS = 0x06;
-
- /** CMAS response type: No action recommended. */
- public static final int CMAS_RESPONSE_TYPE_NONE = 0x07;
-
- /**
- * CMAS response type is unknown. The response type is only available for CDMA broadcasts
- * containing a type 1 elements record, so GSM and UMTS broadcasts always return unknown.
- */
- public static final int CMAS_RESPONSE_TYPE_UNKNOWN = -1;
-
- // 4-bit CMAS severity (in GSM/UMTS message identifier or CDMA type 1 elements record).
-
- /** CMAS severity type: Extraordinary threat to life or property. */
- public static final int CMAS_SEVERITY_EXTREME = 0x0;
-
- /** CMAS severity type: Significant threat to life or property. */
- public static final int CMAS_SEVERITY_SEVERE = 0x1;
-
- /**
- * CMAS alert severity is unknown. The severity is available for CDMA warning alerts
- * containing a type 1 elements record and for all GSM and UMTS alerts except for the
- * Presidential-level alert class (Korean Public Alert System Class 0).
- */
- public static final int CMAS_SEVERITY_UNKNOWN = -1;
-
- // CMAS urgency (in GSM/UMTS message identifier or CDMA type 1 elements record).
-
- /** CMAS urgency type: Responsive action should be taken immediately. */
- public static final int CMAS_URGENCY_IMMEDIATE = 0x0;
-
- /** CMAS urgency type: Responsive action should be taken within the next hour. */
- public static final int CMAS_URGENCY_EXPECTED = 0x1;
-
- /**
- * CMAS alert urgency is unknown. The urgency is available for CDMA warning alerts
- * containing a type 1 elements record and for all GSM and UMTS alerts except for the
- * Presidential-level alert class (Korean Public Alert System Class 0).
- */
- public static final int CMAS_URGENCY_UNKNOWN = -1;
-
- // CMAS certainty (in GSM/UMTS message identifier or CDMA type 1 elements record).
-
- /** CMAS certainty type: Determined to have occurred or to be ongoing. */
- public static final int CMAS_CERTAINTY_OBSERVED = 0x0;
-
- /** CMAS certainty type: Likely (probability > ~50%). */
- public static final int CMAS_CERTAINTY_LIKELY = 0x1;
-
- /**
- * CMAS alert certainty is unknown. The certainty is available for CDMA warning alerts
- * containing a type 1 elements record and for all GSM and UMTS alerts except for the
- * Presidential-level alert class (Korean Public Alert System Class 0).
- */
- public static final int CMAS_CERTAINTY_UNKNOWN = -1;
-
- /** CMAS message class. */
- private final int mMessageClass;
-
- /** CMAS category. */
- private final int mCategory;
-
- /** CMAS response type. */
- private final int mResponseType;
-
- /** CMAS severity. */
- private final int mSeverity;
-
- /** CMAS urgency. */
- private final int mUrgency;
-
- /** CMAS certainty. */
- private final int mCertainty;
-
- /** Create a new SmsCbCmasInfo object with the specified values. */
- public SmsCbCmasInfo(int messageClass, int category, int responseType, int severity,
- int urgency, int certainty) {
- mMessageClass = messageClass;
- mCategory = category;
- mResponseType = responseType;
- mSeverity = severity;
- mUrgency = urgency;
- mCertainty = certainty;
- }
-
- /** Create a new SmsCbCmasInfo object from a Parcel. */
- SmsCbCmasInfo(Parcel in) {
- mMessageClass = in.readInt();
- mCategory = in.readInt();
- mResponseType = in.readInt();
- mSeverity = in.readInt();
- mUrgency = in.readInt();
- mCertainty = in.readInt();
- }
-
- /**
- * Flatten this object into a Parcel.
- *
- * @param dest The Parcel in which the object should be written.
- * @param flags Additional flags about how the object should be written (ignored).
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mMessageClass);
- dest.writeInt(mCategory);
- dest.writeInt(mResponseType);
- dest.writeInt(mSeverity);
- dest.writeInt(mUrgency);
- dest.writeInt(mCertainty);
- }
-
- /**
- * Returns the CMAS message class, e.g. {@link #CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT}.
- * @return one of the {@code CMAS_CLASS} values
- */
- public int getMessageClass() {
- return mMessageClass;
- }
-
- /**
- * Returns the CMAS category, e.g. {@link #CMAS_CATEGORY_GEO}.
- * @return one of the {@code CMAS_CATEGORY} values
- */
- public int getCategory() {
- return mCategory;
- }
-
- /**
- * Returns the CMAS response type, e.g. {@link #CMAS_RESPONSE_TYPE_SHELTER}.
- * @return one of the {@code CMAS_RESPONSE_TYPE} values
- */
- public int getResponseType() {
- return mResponseType;
- }
-
- /**
- * Returns the CMAS severity, e.g. {@link #CMAS_SEVERITY_EXTREME}.
- * @return one of the {@code CMAS_SEVERITY} values
- */
- public int getSeverity() {
- return mSeverity;
- }
-
- /**
- * Returns the CMAS urgency, e.g. {@link #CMAS_URGENCY_IMMEDIATE}.
- * @return one of the {@code CMAS_URGENCY} values
- */
- public int getUrgency() {
- return mUrgency;
- }
-
- /**
- * Returns the CMAS certainty, e.g. {@link #CMAS_CERTAINTY_OBSERVED}.
- * @return one of the {@code CMAS_CERTAINTY} values
- */
- public int getCertainty() {
- return mCertainty;
- }
-
- @Override
- public String toString() {
- return "SmsCbCmasInfo{messageClass=" + mMessageClass + ", category=" + mCategory
- + ", responseType=" + mResponseType + ", severity=" + mSeverity
- + ", urgency=" + mUrgency + ", certainty=" + mCertainty + '}';
- }
-
- /**
- * Describe the kinds of special objects contained in the marshalled representation.
- * @return a bitmask indicating this Parcelable contains no special objects
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** Creator for unparcelling objects. */
- public static final Parcelable.Creator<SmsCbCmasInfo>
- CREATOR = new Parcelable.Creator<SmsCbCmasInfo>() {
- @Override
- public SmsCbCmasInfo createFromParcel(Parcel in) {
- return new SmsCbCmasInfo(in);
- }
-
- @Override
- public SmsCbCmasInfo[] newArray(int size) {
- return new SmsCbCmasInfo[size];
- }
- };
-}
diff --git a/src/java/android/telephony/SmsCbEtwsInfo.java b/src/java/android/telephony/SmsCbEtwsInfo.java
deleted file mode 100644
index 14e02de..0000000
--- a/src/java/android/telephony/SmsCbEtwsInfo.java
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.format.Time;
-
-import com.android.internal.telephony.uicc.IccUtils;
-
-import java.util.Arrays;
-
-/**
- * Contains information elements for a GSM or UMTS ETWS warning notification.
- * Supported values for each element are defined in 3GPP TS 23.041.
- *
- * {@hide}
- */
-public class SmsCbEtwsInfo implements Parcelable {
-
- /** ETWS warning type for earthquake. */
- public static final int ETWS_WARNING_TYPE_EARTHQUAKE = 0x00;
-
- /** ETWS warning type for tsunami. */
- public static final int ETWS_WARNING_TYPE_TSUNAMI = 0x01;
-
- /** ETWS warning type for earthquake and tsunami. */
- public static final int ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI = 0x02;
-
- /** ETWS warning type for test messages. */
- public static final int ETWS_WARNING_TYPE_TEST_MESSAGE = 0x03;
-
- /** ETWS warning type for other emergency types. */
- public static final int ETWS_WARNING_TYPE_OTHER_EMERGENCY = 0x04;
-
- /** Unknown ETWS warning type. */
- public static final int ETWS_WARNING_TYPE_UNKNOWN = -1;
-
- /** One of the ETWS warning type constants defined in this class. */
- private final int mWarningType;
-
- /** Whether or not to activate the emergency user alert tone and vibration. */
- private final boolean mEmergencyUserAlert;
-
- /** Whether or not to activate a popup alert. */
- private final boolean mActivatePopup;
-
- /** Whether ETWS primary message or not/ */
- private final boolean mPrimary;
-
- /**
- * 50-byte security information (ETWS primary notification for GSM only). As of Release 10,
- * 3GPP TS 23.041 states that the UE shall ignore the ETWS primary notification timestamp
- * and digital signature if received. Therefore it is treated as a raw byte array and
- * parceled with the broadcast intent if present, but the timestamp is only computed if an
- * application asks for the individual components.
- */
- private final byte[] mWarningSecurityInformation;
-
- /** Create a new SmsCbEtwsInfo object with the specified values. */
- public SmsCbEtwsInfo(int warningType, boolean emergencyUserAlert, boolean activatePopup,
- boolean primary, byte[] warningSecurityInformation) {
- mWarningType = warningType;
- mEmergencyUserAlert = emergencyUserAlert;
- mActivatePopup = activatePopup;
- mPrimary = primary;
- mWarningSecurityInformation = warningSecurityInformation;
- }
-
- /** Create a new SmsCbEtwsInfo object from a Parcel. */
- SmsCbEtwsInfo(Parcel in) {
- mWarningType = in.readInt();
- mEmergencyUserAlert = (in.readInt() != 0);
- mActivatePopup = (in.readInt() != 0);
- mPrimary = (in.readInt() != 0);
- mWarningSecurityInformation = in.createByteArray();
- }
-
- /**
- * Flatten this object into a Parcel.
- *
- * @param dest The Parcel in which the object should be written.
- * @param flags Additional flags about how the object should be written (ignored).
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mWarningType);
- dest.writeInt(mEmergencyUserAlert ? 1 : 0);
- dest.writeInt(mActivatePopup ? 1 : 0);
- dest.writeInt(mPrimary ? 1 : 0);
- dest.writeByteArray(mWarningSecurityInformation);
- }
-
- /**
- * Returns the ETWS warning type.
- * @return a warning type such as {@link #ETWS_WARNING_TYPE_EARTHQUAKE}
- */
- public int getWarningType() {
- return mWarningType;
- }
-
- /**
- * Returns the ETWS emergency user alert flag.
- * @return true to notify terminal to activate emergency user alert; false otherwise
- */
- public boolean isEmergencyUserAlert() {
- return mEmergencyUserAlert;
- }
-
- /**
- * Returns the ETWS activate popup flag.
- * @return true to notify terminal to activate display popup; false otherwise
- */
- public boolean isPopupAlert() {
- return mActivatePopup;
- }
-
- /**
- * Returns the ETWS format flag.
- * @return true if the message is primary message, otherwise secondary message
- */
- public boolean isPrimary() {
- return mPrimary;
- }
-
- /**
- * Returns the Warning-Security-Information timestamp (GSM primary notifications only).
- * As of Release 10, 3GPP TS 23.041 states that the UE shall ignore this value if received.
- * @return a UTC timestamp in System.currentTimeMillis() format, or 0 if not present
- */
- public long getPrimaryNotificationTimestamp() {
- if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 7) {
- return 0;
- }
-
- int year = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[0]);
- int month = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[1]);
- int day = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[2]);
- int hour = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[3]);
- int minute = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[4]);
- int second = IccUtils.gsmBcdByteToInt(mWarningSecurityInformation[5]);
-
- // For the timezone, the most significant bit of the
- // least significant nibble is the sign byte
- // (meaning the max range of this field is 79 quarter-hours,
- // which is more than enough)
-
- byte tzByte = mWarningSecurityInformation[6];
-
- // Mask out sign bit.
- int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08)));
-
- timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset;
-
- Time time = new Time(Time.TIMEZONE_UTC);
-
- // We only need to support years above 2000.
- time.year = year + 2000;
- time.month = month - 1;
- time.monthDay = day;
- time.hour = hour;
- time.minute = minute;
- time.second = second;
-
- // Timezone offset is in quarter hours.
- return time.toMillis(true) - timezoneOffset * 15 * 60 * 1000;
- }
-
- /**
- * Returns the digital signature (GSM primary notifications only). As of Release 10,
- * 3GPP TS 23.041 states that the UE shall ignore this value if received.
- * @return a byte array containing a copy of the primary notification digital signature
- */
- public byte[] getPrimaryNotificationSignature() {
- if (mWarningSecurityInformation == null || mWarningSecurityInformation.length < 50) {
- return null;
- }
- return Arrays.copyOfRange(mWarningSecurityInformation, 7, 50);
- }
-
- @Override
- public String toString() {
- return "SmsCbEtwsInfo{warningType=" + mWarningType + ", emergencyUserAlert="
- + mEmergencyUserAlert + ", activatePopup=" + mActivatePopup + '}';
- }
-
- /**
- * Describe the kinds of special objects contained in the marshalled representation.
- * @return a bitmask indicating this Parcelable contains no special objects
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** Creator for unparcelling objects. */
- public static final Creator<SmsCbEtwsInfo> CREATOR = new Creator<SmsCbEtwsInfo>() {
- @Override
- public SmsCbEtwsInfo createFromParcel(Parcel in) {
- return new SmsCbEtwsInfo(in);
- }
-
- @Override
- public SmsCbEtwsInfo[] newArray(int size) {
- return new SmsCbEtwsInfo[size];
- }
- };
-}
diff --git a/src/java/android/telephony/SmsCbLocation.java b/src/java/android/telephony/SmsCbLocation.java
deleted file mode 100644
index 6eb72a8..0000000
--- a/src/java/android/telephony/SmsCbLocation.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Represents the location and geographical scope of a cell broadcast message.
- * For GSM/UMTS, the Location Area and Cell ID are set when the broadcast
- * geographical scope is cell wide or Location Area wide. For CDMA, the
- * broadcast geographical scope is always PLMN wide.
- *
- * @hide
- */
-public class SmsCbLocation implements Parcelable {
-
- /** The PLMN. Note that this field may be an empty string, but isn't allowed to be null. */
- private final String mPlmn;
-
- private final int mLac;
- private final int mCid;
-
- /**
- * Construct an empty location object. This is used for some test cases, and for
- * cell broadcasts saved in older versions of the database without location info.
- */
- public SmsCbLocation() {
- mPlmn = "";
- mLac = -1;
- mCid = -1;
- }
-
- /**
- * Construct a location object for the PLMN. This class is immutable, so
- * the same object can be reused for multiple broadcasts.
- */
- public SmsCbLocation(String plmn) {
- mPlmn = plmn;
- mLac = -1;
- mCid = -1;
- }
-
- /**
- * Construct a location object for the PLMN, LAC, and Cell ID. This class is immutable, so
- * the same object can be reused for multiple broadcasts.
- */
- public SmsCbLocation(String plmn, int lac, int cid) {
- mPlmn = plmn;
- mLac = lac;
- mCid = cid;
- }
-
- /**
- * Initialize the object from a Parcel.
- */
- public SmsCbLocation(Parcel in) {
- mPlmn = in.readString();
- mLac = in.readInt();
- mCid = in.readInt();
- }
-
- /**
- * Returns the MCC/MNC of the network as a String.
- * @return the PLMN identifier (MCC+MNC) as a String
- */
- public String getPlmn() {
- return mPlmn;
- }
-
- /**
- * Returns the GSM location area code, or UMTS service area code.
- * @return location area code, -1 if unknown, 0xffff max legal value
- */
- public int getLac() {
- return mLac;
- }
-
- /**
- * Returns the GSM or UMTS cell ID.
- * @return gsm cell id, -1 if unknown, 0xffff max legal value
- */
- public int getCid() {
- return mCid;
- }
-
- @Override
- public int hashCode() {
- int hash = mPlmn.hashCode();
- hash = hash * 31 + mLac;
- hash = hash * 31 + mCid;
- return hash;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (o == null || !(o instanceof SmsCbLocation)) {
- return false;
- }
- SmsCbLocation other = (SmsCbLocation) o;
- return mPlmn.equals(other.mPlmn) && mLac == other.mLac && mCid == other.mCid;
- }
-
- @Override
- public String toString() {
- return '[' + mPlmn + ',' + mLac + ',' + mCid + ']';
- }
-
- /**
- * Test whether this location is within the location area of the specified object.
- *
- * @param area the location area to compare with this location
- * @return true if this location is contained within the specified location area
- */
- public boolean isInLocationArea(SmsCbLocation area) {
- if (mCid != -1 && mCid != area.mCid) {
- return false;
- }
- if (mLac != -1 && mLac != area.mLac) {
- return false;
- }
- return mPlmn.equals(area.mPlmn);
- }
-
- /**
- * Test whether this location is within the location area of the CellLocation.
- *
- * @param plmn the PLMN to use for comparison
- * @param lac the Location Area (GSM) or Service Area (UMTS) to compare with
- * @param cid the Cell ID to compare with
- * @return true if this location is contained within the specified PLMN, LAC, and Cell ID
- */
- public boolean isInLocationArea(String plmn, int lac, int cid) {
- if (!mPlmn.equals(plmn)) {
- return false;
- }
-
- if (mLac != -1 && mLac != lac) {
- return false;
- }
-
- if (mCid != -1 && mCid != cid) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Flatten this object into a Parcel.
- *
- * @param dest The Parcel in which the object should be written.
- * @param flags Additional flags about how the object should be written (ignored).
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mPlmn);
- dest.writeInt(mLac);
- dest.writeInt(mCid);
- }
-
- public static final Parcelable.Creator<SmsCbLocation> CREATOR
- = new Parcelable.Creator<SmsCbLocation>() {
- @Override
- public SmsCbLocation createFromParcel(Parcel in) {
- return new SmsCbLocation(in);
- }
-
- @Override
- public SmsCbLocation[] newArray(int size) {
- return new SmsCbLocation[size];
- }
- };
-
- /**
- * Describe the kinds of special objects contained in the marshalled representation.
- * @return a bitmask indicating this Parcelable contains no special objects
- */
- @Override
- public int describeContents() {
- return 0;
- }
-}
diff --git a/src/java/android/telephony/SmsCbMessage.java b/src/java/android/telephony/SmsCbMessage.java
deleted file mode 100644
index 046bf8c..0000000
--- a/src/java/android/telephony/SmsCbMessage.java
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Parcelable object containing a received cell broadcast message. There are four different types
- * of Cell Broadcast messages:
- *
- * <ul>
- * <li>opt-in informational broadcasts, e.g. news, weather, stock quotes, sports scores</li>
- * <li>cell information messages, broadcast on channel 50, indicating the current cell name for
- * roaming purposes (required to display on the idle screen in Brazil)</li>
- * <li>emergency broadcasts for the Japanese Earthquake and Tsunami Warning System (ETWS)</li>
- * <li>emergency broadcasts for the American Commercial Mobile Alert Service (CMAS)</li>
- * </ul>
- *
- * <p>There are also four different CB message formats: GSM, ETWS Primary Notification (GSM only),
- * UMTS, and CDMA. Some fields are only applicable for some message formats. Other fields were
- * unified under a common name, avoiding some names, such as "Message Identifier", that refer to
- * two completely different concepts in 3GPP and CDMA.
- *
- * <p>The GSM/UMTS Message Identifier field is available via {@link #getServiceCategory}, the name
- * of the equivalent field in CDMA. In both cases the service category is a 16-bit value, but 3GPP
- * and 3GPP2 have completely different meanings for the respective values. For ETWS and CMAS, the
- * application should
- *
- * <p>The CDMA Message Identifier field is available via {@link #getSerialNumber}, which is used
- * to detect the receipt of a duplicate message to be discarded. In CDMA, the message ID is
- * unique to the current PLMN. In GSM/UMTS, there is a 16-bit serial number containing a 2-bit
- * Geographical Scope field which indicates whether the 10-bit message code and 4-bit update number
- * are considered unique to the PLMN, to the current cell, or to the current Location Area (or
- * Service Area in UMTS). The relevant values are concatenated into a single String which will be
- * unique if the messages are not duplicates.
- *
- * <p>The SMS dispatcher does not detect duplicate messages. However, it does concatenate the
- * pages of a GSM multi-page cell broadcast into a single SmsCbMessage object.
- *
- * <p>Interested applications with {@code RECEIVE_SMS_PERMISSION} can register to receive
- * {@code SMS_CB_RECEIVED_ACTION} broadcast intents for incoming non-emergency broadcasts.
- * Only system applications such as the CellBroadcastReceiver may receive notifications for
- * emergency broadcasts (ETWS and CMAS). This is intended to prevent any potential for delays or
- * interference with the immediate display of the alert message and playing of the alert sound and
- * vibration pattern, which could be caused by poorly written or malicious non-system code.
- *
- * @hide
- */
-public class SmsCbMessage implements Parcelable {
-
- protected static final String LOG_TAG = "SMSCB";
-
- /** Cell wide geographical scope with immediate display (GSM/UMTS only). */
- public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0;
-
- /** PLMN wide geographical scope (GSM/UMTS and all CDMA broadcasts). */
- public static final int GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1;
-
- /** Location / service area wide geographical scope (GSM/UMTS only). */
- public static final int GEOGRAPHICAL_SCOPE_LA_WIDE = 2;
-
- /** Cell wide geographical scope (GSM/UMTS only). */
- public static final int GEOGRAPHICAL_SCOPE_CELL_WIDE = 3;
-
- /** GSM or UMTS format cell broadcast. */
- public static final int MESSAGE_FORMAT_3GPP = 1;
-
- /** CDMA format cell broadcast. */
- public static final int MESSAGE_FORMAT_3GPP2 = 2;
-
- /** Normal message priority. */
- public static final int MESSAGE_PRIORITY_NORMAL = 0;
-
- /** Interactive message priority. */
- public static final int MESSAGE_PRIORITY_INTERACTIVE = 1;
-
- /** Urgent message priority. */
- public static final int MESSAGE_PRIORITY_URGENT = 2;
-
- /** Emergency message priority. */
- public static final int MESSAGE_PRIORITY_EMERGENCY = 3;
-
- /** Format of this message (for interpretation of service category values). */
- private final int mMessageFormat;
-
- /** Geographical scope of broadcast. */
- private final int mGeographicalScope;
-
- /**
- * Serial number of broadcast (message identifier for CDMA, geographical scope + message code +
- * update number for GSM/UMTS). The serial number plus the location code uniquely identify
- * a cell broadcast for duplicate detection.
- */
- private final int mSerialNumber;
-
- /**
- * Location identifier for this message. It consists of the current operator MCC/MNC as a
- * 5 or 6-digit decimal string. In addition, for GSM/UMTS, if the Geographical Scope of the
- * message is not binary 01, the Location Area is included for comparison. If the GS is
- * 00 or 11, the Cell ID is also included. LAC and Cell ID are -1 if not specified.
- */
- private final SmsCbLocation mLocation;
-
- /**
- * 16-bit CDMA service category or GSM/UMTS message identifier. For ETWS and CMAS warnings,
- * the information provided by the category is also available via {@link #getEtwsWarningInfo()}
- * or {@link #getCmasWarningInfo()}.
- */
- private final int mServiceCategory;
-
- /** Message language, as a two-character string, e.g. "en". */
- private final String mLanguage;
-
- /** Message body, as a String. */
- private final String mBody;
-
- /** Message priority (including emergency priority). */
- private final int mPriority;
-
- /** ETWS warning notification information (ETWS warnings only). */
- private final SmsCbEtwsInfo mEtwsWarningInfo;
-
- /** CMAS warning notification information (CMAS warnings only). */
- private final SmsCbCmasInfo mCmasWarningInfo;
-
- /**
- * Create a new SmsCbMessage with the specified data.
- */
- public SmsCbMessage(int messageFormat, int geographicalScope, int serialNumber,
- SmsCbLocation location, int serviceCategory, String language, String body,
- int priority, SmsCbEtwsInfo etwsWarningInfo, SmsCbCmasInfo cmasWarningInfo) {
- mMessageFormat = messageFormat;
- mGeographicalScope = geographicalScope;
- mSerialNumber = serialNumber;
- mLocation = location;
- mServiceCategory = serviceCategory;
- mLanguage = language;
- mBody = body;
- mPriority = priority;
- mEtwsWarningInfo = etwsWarningInfo;
- mCmasWarningInfo = cmasWarningInfo;
- }
-
- /** Create a new SmsCbMessage object from a Parcel. */
- public SmsCbMessage(Parcel in) {
- mMessageFormat = in.readInt();
- mGeographicalScope = in.readInt();
- mSerialNumber = in.readInt();
- mLocation = new SmsCbLocation(in);
- mServiceCategory = in.readInt();
- mLanguage = in.readString();
- mBody = in.readString();
- mPriority = in.readInt();
- int type = in.readInt();
- switch (type) {
- case 'E':
- // unparcel ETWS warning information
- mEtwsWarningInfo = new SmsCbEtwsInfo(in);
- mCmasWarningInfo = null;
- break;
-
- case 'C':
- // unparcel CMAS warning information
- mEtwsWarningInfo = null;
- mCmasWarningInfo = new SmsCbCmasInfo(in);
- break;
-
- default:
- mEtwsWarningInfo = null;
- mCmasWarningInfo = null;
- }
- }
-
- /**
- * Flatten this object into a Parcel.
- *
- * @param dest The Parcel in which the object should be written.
- * @param flags Additional flags about how the object should be written (ignored).
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mMessageFormat);
- dest.writeInt(mGeographicalScope);
- dest.writeInt(mSerialNumber);
- mLocation.writeToParcel(dest, flags);
- dest.writeInt(mServiceCategory);
- dest.writeString(mLanguage);
- dest.writeString(mBody);
- dest.writeInt(mPriority);
- if (mEtwsWarningInfo != null) {
- // parcel ETWS warning information
- dest.writeInt('E');
- mEtwsWarningInfo.writeToParcel(dest, flags);
- } else if (mCmasWarningInfo != null) {
- // parcel CMAS warning information
- dest.writeInt('C');
- mCmasWarningInfo.writeToParcel(dest, flags);
- } else {
- // no ETWS or CMAS warning information
- dest.writeInt('0');
- }
- }
-
- public static final Parcelable.Creator<SmsCbMessage> CREATOR
- = new Parcelable.Creator<SmsCbMessage>() {
- @Override
- public SmsCbMessage createFromParcel(Parcel in) {
- return new SmsCbMessage(in);
- }
-
- @Override
- public SmsCbMessage[] newArray(int size) {
- return new SmsCbMessage[size];
- }
- };
-
- /**
- * Return the geographical scope of this message (GSM/UMTS only).
- *
- * @return Geographical scope
- */
- public int getGeographicalScope() {
- return mGeographicalScope;
- }
-
- /**
- * Return the broadcast serial number of broadcast (message identifier for CDMA, or
- * geographical scope + message code + update number for GSM/UMTS). The serial number plus
- * the location code uniquely identify a cell broadcast for duplicate detection.
- *
- * @return the 16-bit CDMA message identifier or GSM/UMTS serial number
- */
- public int getSerialNumber() {
- return mSerialNumber;
- }
-
- /**
- * Return the location identifier for this message, consisting of the MCC/MNC as a
- * 5 or 6-digit decimal string. In addition, for GSM/UMTS, if the Geographical Scope of the
- * message is not binary 01, the Location Area is included. If the GS is 00 or 11, the
- * cell ID is also included. The {@link SmsCbLocation} object includes a method to test
- * if the location is included within another location area or within a PLMN and CellLocation.
- *
- * @return the geographical location code for duplicate message detection
- */
- public SmsCbLocation getLocation() {
- return mLocation;
- }
-
- /**
- * Return the 16-bit CDMA service category or GSM/UMTS message identifier. The interpretation
- * of the category is radio technology specific. For ETWS and CMAS warnings, the information
- * provided by the category is available via {@link #getEtwsWarningInfo()} or
- * {@link #getCmasWarningInfo()} in a radio technology independent format.
- *
- * @return the radio technology specific service category
- */
- public int getServiceCategory() {
- return mServiceCategory;
- }
-
- /**
- * Get the ISO-639-1 language code for this message, or null if unspecified
- *
- * @return Language code
- */
- public String getLanguageCode() {
- return mLanguage;
- }
-
- /**
- * Get the body of this message, or null if no body available
- *
- * @return Body, or null
- */
- public String getMessageBody() {
- return mBody;
- }
-
- /**
- * Get the message format ({@link #MESSAGE_FORMAT_3GPP} or {@link #MESSAGE_FORMAT_3GPP2}).
- * @return an integer representing 3GPP or 3GPP2 message format
- */
- public int getMessageFormat() {
- return mMessageFormat;
- }
-
- /**
- * Get the message priority. Normal broadcasts return {@link #MESSAGE_PRIORITY_NORMAL}
- * and emergency broadcasts return {@link #MESSAGE_PRIORITY_EMERGENCY}. CDMA also may return
- * {@link #MESSAGE_PRIORITY_INTERACTIVE} or {@link #MESSAGE_PRIORITY_URGENT}.
- * @return an integer representing the message priority
- */
- public int getMessagePriority() {
- return mPriority;
- }
-
- /**
- * If this is an ETWS warning notification then this method will return an object containing
- * the ETWS warning type, the emergency user alert flag, and the popup flag. If this is an
- * ETWS primary notification (GSM only), there will also be a 7-byte timestamp and 43-byte
- * digital signature. As of Release 10, 3GPP TS 23.041 states that the UE shall ignore the
- * ETWS primary notification timestamp and digital signature if received.
- *
- * @return an SmsCbEtwsInfo object, or null if this is not an ETWS warning notification
- */
- public SmsCbEtwsInfo getEtwsWarningInfo() {
- return mEtwsWarningInfo;
- }
-
- /**
- * If this is a CMAS warning notification then this method will return an object containing
- * the CMAS message class, category, response type, severity, urgency and certainty.
- * The message class is always present. Severity, urgency and certainty are present for CDMA
- * warning notifications containing a type 1 elements record and for GSM and UMTS warnings
- * except for the Presidential-level alert category. Category and response type are only
- * available for CDMA notifications containing a type 1 elements record.
- *
- * @return an SmsCbCmasInfo object, or null if this is not a CMAS warning notification
- */
- public SmsCbCmasInfo getCmasWarningInfo() {
- return mCmasWarningInfo;
- }
-
- /**
- * Return whether this message is an emergency (PWS) message type.
- * @return true if the message is a public warning notification; false otherwise
- */
- public boolean isEmergencyMessage() {
- return mPriority == MESSAGE_PRIORITY_EMERGENCY;
- }
-
- /**
- * Return whether this message is an ETWS warning alert.
- * @return true if the message is an ETWS warning notification; false otherwise
- */
- public boolean isEtwsMessage() {
- return mEtwsWarningInfo != null;
- }
-
- /**
- * Return whether this message is a CMAS warning alert.
- * @return true if the message is a CMAS warning notification; false otherwise
- */
- public boolean isCmasMessage() {
- return mCmasWarningInfo != null;
- }
-
- @Override
- public String toString() {
- return "SmsCbMessage{geographicalScope=" + mGeographicalScope + ", serialNumber="
- + mSerialNumber + ", location=" + mLocation + ", serviceCategory="
- + mServiceCategory + ", language=" + mLanguage + ", body=" + mBody
- + ", priority=" + mPriority
- + (mEtwsWarningInfo != null ? (", " + mEtwsWarningInfo.toString()) : "")
- + (mCmasWarningInfo != null ? (", " + mCmasWarningInfo.toString()) : "") + '}';
- }
-
- /**
- * Describe the kinds of special objects contained in the marshalled representation.
- * @return a bitmask indicating this Parcelable contains no special objects
- */
- @Override
- public int describeContents() {
- return 0;
- }
-}
diff --git a/src/java/android/telephony/SmsManager.java b/src/java/android/telephony/SmsManager.java
deleted file mode 100644
index 8063364..0000000
--- a/src/java/android/telephony/SmsManager.java
+++ /dev/null
@@ -1,1662 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony;
-
-import android.app.ActivityThread;
-import android.app.PendingIntent;
-import android.content.ActivityNotFoundException;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.BaseBundle;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.internal.telephony.IMms;
-import com.android.internal.telephony.ISms;
-import com.android.internal.telephony.SmsRawData;
-import com.android.internal.telephony.uicc.IccConstants;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-/*
- * TODO(code review): Curious question... Why are a lot of these
- * methods not declared as static, since they do not seem to require
- * any local object state? Presumably this cannot be changed without
- * interfering with the API...
- */
-
-/**
- * Manages SMS operations such as sending data, text, and pdu SMS messages.
- * Get this object by calling the static method {@link #getDefault()}.
- *
- * <p>For information about how to behave as the default SMS app on Android 4.4 (API level 19)
- * and higher, see {@link android.provider.Telephony}.
- */
-public final class SmsManager {
- private static final String TAG = "SmsManager";
- /**
- * A psuedo-subId that represents the default subId at any given time. The actual subId it
- * represents changes as the default subId is changed.
- */
- private static final int DEFAULT_SUBSCRIPTION_ID = -1002;
-
- /** Singleton object constructed during class initialization. */
- private static final SmsManager sInstance = new SmsManager(DEFAULT_SUBSCRIPTION_ID);
- private static final Object sLockObject = new Object();
-
- /** @hide */
- public static final int CELL_BROADCAST_RAN_TYPE_GSM = 0;
- /** @hide */
- public static final int CELL_BROADCAST_RAN_TYPE_CDMA = 1;
-
- private static final Map<Integer, SmsManager> sSubInstances =
- new ArrayMap<Integer, SmsManager>();
-
- /** A concrete subscription id, or the pseudo DEFAULT_SUBSCRIPTION_ID */
- private int mSubId;
-
- /*
- * Key for the various carrier-dependent configuration values.
- * Some of the values are used by the system in processing SMS or MMS messages. Others
- * are provided for the convenience of SMS applications.
- */
-
- /**
- * Whether to append transaction id to MMS WAP Push M-Notification.ind's content location URI
- * when constructing the download URL of a new MMS (boolean type)
- */
- public static final String MMS_CONFIG_APPEND_TRANSACTION_ID =
- CarrierConfigManager.KEY_MMS_APPEND_TRANSACTION_ID_BOOL;
- /**
- * Whether MMS is enabled for the current carrier (boolean type)
- */
- public static final String
- MMS_CONFIG_MMS_ENABLED = CarrierConfigManager.KEY_MMS_MMS_ENABLED_BOOL;
- /**
- * Whether group MMS is enabled for the current carrier (boolean type)
- */
- public static final String
- MMS_CONFIG_GROUP_MMS_ENABLED = CarrierConfigManager.KEY_MMS_GROUP_MMS_ENABLED_BOOL;
- /**
- * If this is enabled, M-NotifyResp.ind should be sent to the WAP Push content location instead
- * of the default MMSC (boolean type)
- */
- public static final String MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED =
- CarrierConfigManager.KEY_MMS_NOTIFY_WAP_MMSC_ENABLED_BOOL;
- /**
- * Whether alias is enabled (boolean type)
- */
- public static final String
- MMS_CONFIG_ALIAS_ENABLED = CarrierConfigManager.KEY_MMS_ALIAS_ENABLED_BOOL;
- /**
- * Whether audio is allowed to be attached for MMS messages (boolean type)
- */
- public static final String
- MMS_CONFIG_ALLOW_ATTACH_AUDIO = CarrierConfigManager.KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL;
- /**
- * Whether multipart SMS is enabled (boolean type)
- */
- public static final String MMS_CONFIG_MULTIPART_SMS_ENABLED =
- CarrierConfigManager.KEY_MMS_MULTIPART_SMS_ENABLED_BOOL;
- /**
- * Whether SMS delivery report is enabled (boolean type)
- */
- public static final String MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED =
- CarrierConfigManager.KEY_MMS_SMS_DELIVERY_REPORT_ENABLED_BOOL;
- /**
- * Whether content-disposition field should be expected in an MMS PDU (boolean type)
- */
- public static final String MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION =
- CarrierConfigManager.KEY_MMS_SUPPORT_MMS_CONTENT_DISPOSITION_BOOL;
- /**
- * Whether multipart SMS should be sent as separate messages
- */
- public static final String MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES =
- CarrierConfigManager.KEY_MMS_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES_BOOL;
- /**
- * Whether MMS read report is enabled (boolean type)
- */
- public static final String MMS_CONFIG_MMS_READ_REPORT_ENABLED =
- CarrierConfigManager.KEY_MMS_MMS_READ_REPORT_ENABLED_BOOL;
- /**
- * Whether MMS delivery report is enabled (boolean type)
- */
- public static final String MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED =
- CarrierConfigManager.KEY_MMS_MMS_DELIVERY_REPORT_ENABLED_BOOL;
- /**
- * Max MMS message size in bytes (int type)
- */
- public static final String
- MMS_CONFIG_MAX_MESSAGE_SIZE = CarrierConfigManager.KEY_MMS_MAX_MESSAGE_SIZE_INT;
- /**
- * Max MMS image width (int type)
- */
- public static final String
- MMS_CONFIG_MAX_IMAGE_WIDTH = CarrierConfigManager.KEY_MMS_MAX_IMAGE_WIDTH_INT;
- /**
- * Max MMS image height (int type)
- */
- public static final String
- MMS_CONFIG_MAX_IMAGE_HEIGHT = CarrierConfigManager.KEY_MMS_MAX_IMAGE_HEIGHT_INT;
- /**
- * Limit of recipients of MMS messages (int type)
- */
- public static final String
- MMS_CONFIG_RECIPIENT_LIMIT = CarrierConfigManager.KEY_MMS_RECIPIENT_LIMIT_INT;
- /**
- * Min alias character count (int type)
- */
- public static final String
- MMS_CONFIG_ALIAS_MIN_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MIN_CHARS_INT;
- /**
- * Max alias character count (int type)
- */
- public static final String
- MMS_CONFIG_ALIAS_MAX_CHARS = CarrierConfigManager.KEY_MMS_ALIAS_MAX_CHARS_INT;
- /**
- * When the number of parts of a multipart SMS reaches this threshold, it should be converted
- * into an MMS (int type)
- */
- public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD =
- CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT;
- /**
- * Some carriers require SMS to be converted into MMS when text length reaches this threshold
- * (int type)
- */
- public static final String MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD =
- CarrierConfigManager.KEY_MMS_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD_INT;
- /**
- * Max message text size (int type)
- */
- public static final String MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE =
- CarrierConfigManager.KEY_MMS_MESSAGE_TEXT_MAX_SIZE_INT;
- /**
- * Max message subject length (int type)
- */
- public static final String
- MMS_CONFIG_SUBJECT_MAX_LENGTH = CarrierConfigManager.KEY_MMS_SUBJECT_MAX_LENGTH_INT;
- /**
- * MMS HTTP socket timeout in milliseconds (int type)
- */
- public static final String
- MMS_CONFIG_HTTP_SOCKET_TIMEOUT = CarrierConfigManager.KEY_MMS_HTTP_SOCKET_TIMEOUT_INT;
- /**
- * The name of the UA Prof URL HTTP header for MMS HTTP request (String type)
- */
- public static final String
- MMS_CONFIG_UA_PROF_TAG_NAME = CarrierConfigManager.KEY_MMS_UA_PROF_TAG_NAME_STRING;
- /**
- * The User-Agent header value for MMS HTTP request (String type)
- */
- public static final String
- MMS_CONFIG_USER_AGENT = CarrierConfigManager.KEY_MMS_USER_AGENT_STRING;
- /**
- * The UA Profile URL header value for MMS HTTP request (String type)
- */
- public static final String
- MMS_CONFIG_UA_PROF_URL = CarrierConfigManager.KEY_MMS_UA_PROF_URL_STRING;
- /**
- * A list of HTTP headers to add to MMS HTTP request, separated by "|" (String type)
- */
- public static final String
- MMS_CONFIG_HTTP_PARAMS = CarrierConfigManager.KEY_MMS_HTTP_PARAMS_STRING;
- /**
- * Email gateway number (String type)
- */
- public static final String MMS_CONFIG_EMAIL_GATEWAY_NUMBER =
- CarrierConfigManager.KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING;
- /**
- * The suffix to append to the NAI header value for MMS HTTP request (String type)
- */
- public static final String
- MMS_CONFIG_NAI_SUFFIX = CarrierConfigManager.KEY_MMS_NAI_SUFFIX_STRING;
- /**
- * If true, show the cell broadcast (amber alert) in the SMS settings. Some carriers don't want
- * this shown. (Boolean type)
- */
- public static final String MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS =
- CarrierConfigManager.KEY_MMS_SHOW_CELL_BROADCAST_APP_LINKS_BOOL;
- /**
- * Whether the carrier MMSC supports charset field in Content-Type header. If this is false,
- * then we don't add "charset" to "Content-Type"
- */
- public static final String MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER =
- CarrierConfigManager.KEY_MMS_SUPPORT_HTTP_CHARSET_HEADER_BOOL;
- /**
- * If true, add "Connection: close" header to MMS HTTP requests so the connection
- * is immediately closed (disabling keep-alive). (Boolean type)
- * @hide
- */
- public static final String MMS_CONFIG_CLOSE_CONNECTION =
- CarrierConfigManager.KEY_MMS_CLOSE_CONNECTION_BOOL;
-
- /*
- * Forwarded constants from SimDialogActivity.
- */
- private static String DIALOG_TYPE_KEY = "dialog_type";
- private static final int SMS_PICK = 2;
-
- /**
- * Send a text based SMS.
- *
- * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
- * {@link android.Manifest.permission#SEND_SMS} permission.</p>
- *
- * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
- * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
- * writes messages sent using this method to the SMS Provider (the default SMS app is always
- * responsible for writing its sent messages to the SMS Provider). For information about
- * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
- *
- *
- * @param destinationAddress the address to send the message to
- * @param scAddress is the service center address or null to use
- * the current default SMSC
- * @param text the body of the message to send
- * @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is successfully sent, or failed.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
- * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
- * <code>RESULT_ERROR_RADIO_OFF</code><br>
- * <code>RESULT_ERROR_NULL_PDU</code><br>
- * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
- * the extra "errorCode" containing a radio technology specific value,
- * generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
- * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is delivered to the recipient. The
- * raw pdu of the status report is in the extended data ("pdu").
- *
- * @throws IllegalArgumentException if destinationAddress or text are empty
- */
- public void sendTextMessage(
- String destinationAddress, String scAddress, String text,
- PendingIntent sentIntent, PendingIntent deliveryIntent) {
- sendTextMessageInternal(destinationAddress, scAddress, text,
- sentIntent, deliveryIntent, true /* persistMessageForCarrierApp*/);
- }
-
- private void sendTextMessageInternal(String destinationAddress, String scAddress,
- String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
- boolean persistMessageForCarrierApp) {
- if (TextUtils.isEmpty(destinationAddress)) {
- throw new IllegalArgumentException("Invalid destinationAddress");
- }
-
- if (TextUtils.isEmpty(text)) {
- throw new IllegalArgumentException("Invalid message body");
- }
-
- try {
- ISms iccISms = getISmsServiceOrThrow();
- iccISms.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
- destinationAddress,
- scAddress, text, sentIntent, deliveryIntent,
- persistMessageForCarrierApp);
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
- * Send a text based SMS without writing it into the SMS Provider.
- *
- * <p>Only the carrier app can call this method.</p>
- *
- * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent)
- * @hide
- */
- public void sendTextMessageWithoutPersisting(
- String destinationAddress, String scAddress, String text,
- PendingIntent sentIntent, PendingIntent deliveryIntent) {
- sendTextMessageInternal(destinationAddress, scAddress, text,
- sentIntent, deliveryIntent, false /* persistMessageForCarrierApp*/);
- }
-
- /**
- * A variant of {@link SmsManager#sendTextMessage} that allows self to be the caller. This is
- * for internal use only.
- *
- * @param persistMessage whether to persist the sent message in the SMS app. the caller must be
- * the Phone process if set to false.
- *
- * @hide
- */
- public void sendTextMessageWithSelfPermissions(
- String destinationAddress, String scAddress, String text,
- PendingIntent sentIntent, PendingIntent deliveryIntent, boolean persistMessage) {
- if (TextUtils.isEmpty(destinationAddress)) {
- throw new IllegalArgumentException("Invalid destinationAddress");
- }
-
- if (TextUtils.isEmpty(text)) {
- throw new IllegalArgumentException("Invalid message body");
- }
-
- try {
- ISms iccISms = getISmsServiceOrThrow();
- iccISms.sendTextForSubscriberWithSelfPermissions(getSubscriptionId(),
- ActivityThread.currentPackageName(),
- destinationAddress,
- scAddress, text, sentIntent, deliveryIntent, persistMessage);
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
- * Inject an SMS PDU into the android application framework.
- *
- * The caller should have carrier privileges.
- * @see android.telephony.TelephonyManager#hasCarrierPrivileges
- *
- * @param pdu is the byte array of pdu to be injected into android application framework
- * @param format is the format of SMS pdu (3gpp or 3gpp2)
- * @param receivedIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is successfully received by the
- * android application framework, or failed. This intent is broadcasted at
- * the same time an SMS received from radio is acknowledged back.
- * The result code will be <code>RESULT_SMS_HANDLED</code> for success, or
- * <code>RESULT_SMS_GENERIC_ERROR</code> for error.
- *
- * @throws IllegalArgumentException if format is not one of 3gpp and 3gpp2.
- */
- public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
- if (!format.equals(SmsMessage.FORMAT_3GPP) && !format.equals(SmsMessage.FORMAT_3GPP2)) {
- // Format must be either 3gpp or 3gpp2.
- throw new IllegalArgumentException(
- "Invalid pdu format. format must be either 3gpp or 3gpp2");
- }
- try {
- ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
- if (iccISms != null) {
- iccISms.injectSmsPduForSubscriber(
- getSubscriptionId(), pdu, format, receivedIntent);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
- * Divide a message text into several fragments, none bigger than
- * the maximum SMS message size.
- *
- * @param text the original message. Must not be null.
- * @return an <code>ArrayList</code> of strings that, in order,
- * comprise the original message
- *
- * @throws IllegalArgumentException if text is null
- */
- public ArrayList<String> divideMessage(String text) {
- if (null == text) {
- throw new IllegalArgumentException("text is null");
- }
- return SmsMessage.fragmentText(text);
- }
-
- /**
- * Send a multi-part text based SMS. The callee should have already
- * divided the message into correctly sized parts by calling
- * <code>divideMessage</code>.
- *
- * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
- * {@link android.Manifest.permission#SEND_SMS} permission.</p>
- *
- * <p class="note"><strong>Note:</strong> Beginning with Android 4.4 (API level 19), if
- * <em>and only if</em> an app is not selected as the default SMS app, the system automatically
- * writes messages sent using this method to the SMS Provider (the default SMS app is always
- * responsible for writing its sent messages to the SMS Provider). For information about
- * how to behave as the default SMS app, see {@link android.provider.Telephony}.</p>
- *
- * @param destinationAddress the address to send the message to
- * @param scAddress is the service center address or null to use
- * the current default SMSC
- * @param parts an <code>ArrayList</code> of strings that, in order,
- * comprise the original message
- * @param sentIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
- * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
- * <code>RESULT_ERROR_RADIO_OFF</code><br>
- * <code>RESULT_ERROR_NULL_PDU</code><br>
- * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
- * the extra "errorCode" containing a radio technology specific value,
- * generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
- * @param deliveryIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been delivered
- * to the recipient. The raw pdu of the status report is in the
- * extended data ("pdu").
- *
- * @throws IllegalArgumentException if destinationAddress or data are empty
- */
- public void sendMultipartTextMessage(
- String destinationAddress, String scAddress, ArrayList<String> parts,
- ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
- sendMultipartTextMessageInternal(destinationAddress, scAddress, parts,
- sentIntents, deliveryIntents, true /* persistMessageForCarrierApp*/);
- }
-
- private void sendMultipartTextMessageInternal(
- String destinationAddress, String scAddress, ArrayList<String> parts,
- ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents,
- boolean persistMessageForCarrierApp) {
- if (TextUtils.isEmpty(destinationAddress)) {
- throw new IllegalArgumentException("Invalid destinationAddress");
- }
- if (parts == null || parts.size() < 1) {
- throw new IllegalArgumentException("Invalid message body");
- }
-
- if (parts.size() > 1) {
- try {
- ISms iccISms = getISmsServiceOrThrow();
- iccISms.sendMultipartTextForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
- destinationAddress, scAddress, parts,
- sentIntents, deliveryIntents, persistMessageForCarrierApp);
- } catch (RemoteException ex) {
- // ignore it
- }
- } else {
- PendingIntent sentIntent = null;
- PendingIntent deliveryIntent = null;
- if (sentIntents != null && sentIntents.size() > 0) {
- sentIntent = sentIntents.get(0);
- }
- if (deliveryIntents != null && deliveryIntents.size() > 0) {
- deliveryIntent = deliveryIntents.get(0);
- }
- sendTextMessage(destinationAddress, scAddress, parts.get(0),
- sentIntent, deliveryIntent);
- }
- }
-
- /**
- * Send a multi-part text based SMS without writing it into the SMS Provider.
- *
- * <p>Only the carrier app can call this method.</p>
- *
- * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList)
- * @hide
- **/
- public void sendMultipartTextMessageWithoutPersisting(
- String destinationAddress, String scAddress, ArrayList<String> parts,
- ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
- sendMultipartTextMessageInternal(destinationAddress, scAddress, parts,
- sentIntents, deliveryIntents, false /* persistMessageForCarrierApp*/);
- }
-
- /**
- * Send a data based SMS to a specific application port.
- *
- * <p class="note"><strong>Note:</strong> Using this method requires that your app has the
- * {@link android.Manifest.permission#SEND_SMS} permission.</p>
- *
- * @param destinationAddress the address to send the message to
- * @param scAddress is the service center address or null to use
- * the current default SMSC
- * @param destinationPort the port to deliver the message to
- * @param data the body of the message to send
- * @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is successfully sent, or failed.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
- * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
- * <code>RESULT_ERROR_RADIO_OFF</code><br>
- * <code>RESULT_ERROR_NULL_PDU</code><br>
- * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
- * the extra "errorCode" containing a radio technology specific value,
- * generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
- * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is delivered to the recipient. The
- * raw pdu of the status report is in the extended data ("pdu").
- *
- * @throws IllegalArgumentException if destinationAddress or data are empty
- */
- public void sendDataMessage(
- String destinationAddress, String scAddress, short destinationPort,
- byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
- if (TextUtils.isEmpty(destinationAddress)) {
- throw new IllegalArgumentException("Invalid destinationAddress");
- }
-
- if (data == null || data.length == 0) {
- throw new IllegalArgumentException("Invalid message data");
- }
-
- try {
- ISms iccISms = getISmsServiceOrThrow();
- iccISms.sendDataForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
- destinationAddress, scAddress, destinationPort & 0xFFFF,
- data, sentIntent, deliveryIntent);
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
- * A variant of {@link SmsManager#sendDataMessage} that allows self to be the caller. This is
- * for internal use only.
- *
- * @hide
- */
- public void sendDataMessageWithSelfPermissions(
- String destinationAddress, String scAddress, short destinationPort,
- byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) {
- if (TextUtils.isEmpty(destinationAddress)) {
- throw new IllegalArgumentException("Invalid destinationAddress");
- }
-
- if (data == null || data.length == 0) {
- throw new IllegalArgumentException("Invalid message data");
- }
-
- try {
- ISms iccISms = getISmsServiceOrThrow();
- iccISms.sendDataForSubscriberWithSelfPermissions(getSubscriptionId(),
- ActivityThread.currentPackageName(), destinationAddress, scAddress,
- destinationPort & 0xFFFF, data, sentIntent, deliveryIntent);
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
-
-
- /**
- * Get the SmsManager associated with the default subscription id. The instance will always be
- * associated with the default subscription id, even if the default subscription id is changed.
- *
- * @return the SmsManager associated with the default subscription id
- */
- public static SmsManager getDefault() {
- return sInstance;
- }
-
- /**
- * Get the the instance of the SmsManager associated with a particular subscription id
- *
- * @param subId an SMS subscription id, typically accessed using
- * {@link android.telephony.SubscriptionManager}
- * @return the instance of the SmsManager associated with subId
- */
- public static SmsManager getSmsManagerForSubscriptionId(int subId) {
- // TODO(shri): Add javadoc link once SubscriptionManager is made public api
- synchronized(sLockObject) {
- SmsManager smsManager = sSubInstances.get(subId);
- if (smsManager == null) {
- smsManager = new SmsManager(subId);
- sSubInstances.put(subId, smsManager);
- }
- return smsManager;
- }
- }
-
- private SmsManager(int subId) {
- mSubId = subId;
- }
-
- /**
- * Get the associated subscription id. If the instance was returned by {@link #getDefault()},
- * then this method may return different values at different points in time (if the user
- * changes the default subscription id). It will return < 0 if the default subscription id
- * cannot be determined.
- *
- * Additionally, to support legacy applications that are not multi-SIM aware,
- * if the following are true:
- * - We are using a multi-SIM device
- * - A default SMS SIM has not been selected
- * - At least one SIM subscription is available
- * then ask the user to set the default SMS SIM.
- *
- * @return associated subscription id
- */
- public int getSubscriptionId() {
- final int subId = (mSubId == DEFAULT_SUBSCRIPTION_ID)
- ? getDefaultSmsSubscriptionId() : mSubId;
- boolean isSmsSimPickActivityNeeded = false;
- final Context context = ActivityThread.currentApplication().getApplicationContext();
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- isSmsSimPickActivityNeeded = iccISms.isSmsSimPickActivityNeeded(subId);
- }
- } catch (RemoteException ex) {
- Log.e(TAG, "Exception in getSubscriptionId");
- }
-
- if (isSmsSimPickActivityNeeded) {
- Log.d(TAG, "getSubscriptionId isSmsSimPickActivityNeeded is true");
- // ask the user for a default SMS SIM.
- Intent intent = new Intent();
- intent.setClassName("com.android.settings",
- "com.android.settings.sim.SimDialogActivity");
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(DIALOG_TYPE_KEY, SMS_PICK);
- try {
- context.startActivity(intent);
- } catch (ActivityNotFoundException anfe) {
- // If Settings is not installed, only log the error as we do not want to break
- // legacy applications.
- Log.e(TAG, "Unable to launch Settings application.");
- }
- }
-
- return subId;
- }
-
- /**
- * Returns the ISms service, or throws an UnsupportedOperationException if
- * the service does not exist.
- */
- private static ISms getISmsServiceOrThrow() {
- ISms iccISms = getISmsService();
- if (iccISms == null) {
- throw new UnsupportedOperationException("Sms is not supported");
- }
- return iccISms;
- }
-
- private static ISms getISmsService() {
- return ISms.Stub.asInterface(ServiceManager.getService("isms"));
- }
-
- /**
- * Copy a raw SMS PDU to the ICC.
- * ICC (Integrated Circuit Card) is the card of the device.
- * For example, this can be the SIM or USIM for GSM.
- *
- * @param smsc the SMSC for this message, or NULL for the default SMSC
- * @param pdu the raw PDU to store
- * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD,
- * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT)
- * @return true for success
- *
- * @throws IllegalArgumentException if pdu is NULL
- * {@hide}
- */
- public boolean copyMessageToIcc(byte[] smsc, byte[] pdu,int status) {
- boolean success = false;
-
- if (null == pdu) {
- throw new IllegalArgumentException("pdu is NULL");
- }
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- success = iccISms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
- status, pdu, smsc);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- return success;
- }
-
- /**
- * Delete the specified message from the ICC.
- * ICC (Integrated Circuit Card) is the card of the device.
- * For example, this can be the SIM or USIM for GSM.
- *
- * @param messageIndex is the record index of the message on ICC
- * @return true for success
- *
- * {@hide}
- */
- public boolean
- deleteMessageFromIcc(int messageIndex) {
- boolean success = false;
- byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1];
- Arrays.fill(pdu, (byte)0xff);
-
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
- messageIndex, STATUS_ON_ICC_FREE, pdu);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- return success;
- }
-
- /**
- * Update the specified message on the ICC.
- * ICC (Integrated Circuit Card) is the card of the device.
- * For example, this can be the SIM or USIM for GSM.
- *
- * @param messageIndex record index of message to update
- * @param newStatus new message status (STATUS_ON_ICC_READ,
- * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT,
- * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE)
- * @param pdu the raw PDU to store
- * @return true for success
- *
- * {@hide}
- */
- public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) {
- boolean success = false;
-
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
- ActivityThread.currentPackageName(),
- messageIndex, newStatus, pdu);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- return success;
- }
-
- /**
- * Retrieves all messages currently stored on ICC.
- * ICC (Integrated Circuit Card) is the card of the device.
- * For example, this can be the SIM or USIM for GSM.
- *
- * @return <code>ArrayList</code> of <code>SmsMessage</code> objects
- *
- * {@hide}
- */
- public ArrayList<SmsMessage> getAllMessagesFromIcc() {
- List<SmsRawData> records = null;
-
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- records = iccISms.getAllMessagesFromIccEfForSubscriber(
- getSubscriptionId(),
- ActivityThread.currentPackageName());
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- return createMessageListFromRawRecords(records);
- }
-
- /**
- * Enable reception of cell broadcast (SMS-CB) messages with the given
- * message identifier and RAN type. The RAN type specify this message ID
- * belong to 3GPP (GSM) or 3GPP2(CDMA).Note that if two different clients
- * enable the same message identifier, they must both disable it for the device to stop
- * receiving those messages. All received messages will be broadcast in an
- * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
- * Note: This call is blocking, callers may want to avoid calling it from
- * the main thread of an application.
- *
- * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
- * or C.R1001-G (3GPP2)
- * @param ranType as defined in class SmsManager, the value can be one of these:
- * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
- * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
- * @return true if successful, false otherwise
- * @see #disableCellBroadcast(int, int)
- *
- * {@hide}
- */
- public boolean enableCellBroadcast(int messageIdentifier, int ranType) {
- boolean success = false;
-
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- success = iccISms.enableCellBroadcastForSubscriber(
- getSubscriptionId(), messageIdentifier, ranType);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- return success;
- }
-
- /**
- * Disable reception of cell broadcast (SMS-CB) messages with the given
- * message identifier and RAN type. The RAN type specify this message ID
- * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients
- * enable the same message identifier, they must both disable it for the
- * device to stop receiving those messages.
- * Note: This call is blocking, callers may want to avoid calling it from
- * the main thread of an application.
- *
- * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP)
- * or C.R1001-G (3GPP2)
- * @param ranType as defined in class SmsManager, the value can be one of these:
- * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
- * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
- * @return true if successful, false otherwise
- *
- * @see #enableCellBroadcast(int, int)
- *
- * {@hide}
- */
- public boolean disableCellBroadcast(int messageIdentifier, int ranType) {
- boolean success = false;
-
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- success = iccISms.disableCellBroadcastForSubscriber(
- getSubscriptionId(), messageIdentifier, ranType);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- return success;
- }
-
- /**
- * Enable reception of cell broadcast (SMS-CB) messages with the given
- * message identifier range and RAN type. The RAN type specify this message ID
- * belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different clients enable
- * the same message identifier, they must both disable it for the device to stop
- * receiving those messages. All received messages will be broadcast in an
- * intent with the action "android.provider.Telephony.SMS_CB_RECEIVED".
- * Note: This call is blocking, callers may want to avoid calling it from
- * the main thread of an application.
- *
- * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
- * or C.R1001-G (3GPP2)
- * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
- * or C.R1001-G (3GPP2)
- * @param ranType as defined in class SmsManager, the value can be one of these:
- * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
- * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
- * @return true if successful, false otherwise
- * @see #disableCellBroadcastRange(int, int, int)
- *
- * @throws IllegalArgumentException if endMessageId < startMessageId
- * {@hide}
- */
- public boolean enableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
- boolean success = false;
-
- if (endMessageId < startMessageId) {
- throw new IllegalArgumentException("endMessageId < startMessageId");
- }
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- success = iccISms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
- startMessageId, endMessageId, ranType);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- return success;
- }
-
- /**
- * Disable reception of cell broadcast (SMS-CB) messages with the given
- * message identifier range and RAN type. The RAN type specify this message
- * ID range belong to 3GPP (GSM) or 3GPP2(CDMA). Note that if two different
- * clients enable the same message identifier, they must both disable it for
- * the device to stop receiving those messages.
- * Note: This call is blocking, callers may want to avoid calling it from
- * the main thread of an application.
- *
- * @param startMessageId first message identifier as specified in TS 23.041 (3GPP)
- * or C.R1001-G (3GPP2)
- * @param endMessageId last message identifier as specified in TS 23.041 (3GPP)
- * or C.R1001-G (3GPP2)
- * @param ranType as defined in class SmsManager, the value can be one of these:
- * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_GSM
- * android.telephony.SmsMessage.CELL_BROADCAST_RAN_TYPE_CDMA
- * @return true if successful, false otherwise
- *
- * @see #enableCellBroadcastRange(int, int, int)
- *
- * @throws IllegalArgumentException if endMessageId < startMessageId
- * {@hide}
- */
- public boolean disableCellBroadcastRange(int startMessageId, int endMessageId, int ranType) {
- boolean success = false;
-
- if (endMessageId < startMessageId) {
- throw new IllegalArgumentException("endMessageId < startMessageId");
- }
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- success = iccISms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
- startMessageId, endMessageId, ranType);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
-
- return success;
- }
-
- /**
- * Create a list of <code>SmsMessage</code>s from a list of RawSmsData
- * records returned by <code>getAllMessagesFromIcc()</code>
- *
- * @param records SMS EF records, returned by
- * <code>getAllMessagesFromIcc</code>
- * @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
- */
- private static ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
- ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
- if (records != null) {
- int count = records.size();
- for (int i = 0; i < count; i++) {
- SmsRawData data = records.get(i);
- // List contains all records, including "free" records (null)
- if (data != null) {
- SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
- if (sms != null) {
- messages.add(sms);
- }
- }
- }
- }
- return messages;
- }
-
- /**
- * SMS over IMS is supported if IMS is registered and SMS is supported
- * on IMS.
- *
- * @return true if SMS over IMS is supported, false otherwise
- *
- * @see #getImsSmsFormat()
- *
- * @hide
- */
- public boolean isImsSmsSupported() {
- boolean boSupported = false;
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- boSupported = iccISms.isImsSmsSupportedForSubscriber(getSubscriptionId());
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return boSupported;
- }
-
- /**
- * Gets SMS format supported on IMS. SMS over IMS format is
- * either 3GPP or 3GPP2.
- *
- * @return SmsMessage.FORMAT_3GPP,
- * SmsMessage.FORMAT_3GPP2
- * or SmsMessage.FORMAT_UNKNOWN
- *
- * @see #isImsSmsSupported()
- *
- * @hide
- */
- public String getImsSmsFormat() {
- String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN;
- try {
- ISms iccISms = getISmsService();
- if (iccISms != null) {
- format = iccISms.getImsSmsFormatForSubscriber(getSubscriptionId());
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return format;
- }
-
- /**
- * Get default sms subscription id
- *
- * @return the default SMS subscription id
- */
- public static int getDefaultSmsSubscriptionId() {
- ISms iccISms = null;
- try {
- iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
- return iccISms.getPreferredSmsSubscription();
- } catch (RemoteException ex) {
- return -1;
- } catch (NullPointerException ex) {
- return -1;
- }
- }
-
- /**
- * Get SMS prompt property, enabled or not
- *
- * @return true if enabled, false otherwise
- * @hide
- */
- public boolean isSMSPromptEnabled() {
- ISms iccISms = null;
- try {
- iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
- return iccISms.isSMSPromptEnabled();
- } catch (RemoteException ex) {
- return false;
- } catch (NullPointerException ex) {
- return false;
- }
- }
-
- // see SmsMessage.getStatusOnIcc
-
- /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
- static public final int STATUS_ON_ICC_FREE = 0;
-
- /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
- static public final int STATUS_ON_ICC_READ = 1;
-
- /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
- static public final int STATUS_ON_ICC_UNREAD = 3;
-
- /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
- static public final int STATUS_ON_ICC_SENT = 5;
-
- /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */
- static public final int STATUS_ON_ICC_UNSENT = 7;
-
- // SMS send failure result codes
-
- /** Generic failure cause */
- static public final int RESULT_ERROR_GENERIC_FAILURE = 1;
- /** Failed because radio was explicitly turned off */
- static public final int RESULT_ERROR_RADIO_OFF = 2;
- /** Failed because no pdu provided */
- static public final int RESULT_ERROR_NULL_PDU = 3;
- /** Failed because service is currently unavailable */
- static public final int RESULT_ERROR_NO_SERVICE = 4;
- /** Failed because we reached the sending queue limit. {@hide} */
- static public final int RESULT_ERROR_LIMIT_EXCEEDED = 5;
- /** Failed because FDN is enabled. {@hide} */
- static public final int RESULT_ERROR_FDN_CHECK_FAILURE = 6;
-
- static private final String PHONE_PACKAGE_NAME = "com.android.phone";
-
- /**
- * Send an MMS message
- *
- * @param context application context
- * @param contentUri the content Uri from which the message pdu will be read
- * @param locationUrl the optional location url where message should be sent to
- * @param configOverrides the carrier-specific messaging configuration values to override for
- * sending the message.
- * @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is successfully sent, or failed
- * @throws IllegalArgumentException if contentUri is empty
- */
- public void sendMultimediaMessage(Context context, Uri contentUri, String locationUrl,
- Bundle configOverrides, PendingIntent sentIntent) {
- if (contentUri == null) {
- throw new IllegalArgumentException("Uri contentUri null");
- }
- try {
- final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms == null) {
- return;
- }
-
- iMms.sendMessage(getSubscriptionId(), ActivityThread.currentPackageName(), contentUri,
- locationUrl, configOverrides, sentIntent);
- } catch (RemoteException e) {
- // Ignore it
- }
- }
-
- /**
- * Download an MMS message from carrier by a given location URL
- *
- * @param context application context
- * @param locationUrl the location URL of the MMS message to be downloaded, usually obtained
- * from the MMS WAP push notification
- * @param contentUri the content uri to which the downloaded pdu will be written
- * @param configOverrides the carrier-specific messaging configuration values to override for
- * downloading the message.
- * @param downloadedIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is downloaded, or the download is failed
- * @throws IllegalArgumentException if locationUrl or contentUri is empty
- */
- public void downloadMultimediaMessage(Context context, String locationUrl, Uri contentUri,
- Bundle configOverrides, PendingIntent downloadedIntent) {
- if (TextUtils.isEmpty(locationUrl)) {
- throw new IllegalArgumentException("Empty MMS location URL");
- }
- if (contentUri == null) {
- throw new IllegalArgumentException("Uri contentUri null");
- }
- try {
- final IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms == null) {
- return;
- }
- iMms.downloadMessage(
- getSubscriptionId(), ActivityThread.currentPackageName(), locationUrl,
- contentUri, configOverrides, downloadedIntent);
- } catch (RemoteException e) {
- // Ignore it
- }
- }
-
- // MMS send/download failure result codes
- public static final int MMS_ERROR_UNSPECIFIED = 1;
- public static final int MMS_ERROR_INVALID_APN = 2;
- public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3;
- public static final int MMS_ERROR_HTTP_FAILURE = 4;
- public static final int MMS_ERROR_IO_ERROR = 5;
- public static final int MMS_ERROR_RETRY = 6;
- public static final int MMS_ERROR_CONFIGURATION_ERROR = 7;
- public static final int MMS_ERROR_NO_DATA_NETWORK = 8;
-
- /** Intent extra name for MMS sending result data in byte array type */
- public static final String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
- /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */
- public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
-
- /**
- * Import a text message into system's SMS store
- *
- * Only default SMS apps can import SMS
- *
- * @param address the destination(source) address of the sent(received) message
- * @param type the type of the message
- * @param text the message text
- * @param timestampMillis the message timestamp in milliseconds
- * @param seen if the message is seen
- * @param read if the message is read
- * @return the message URI, null if failed
- * @hide
- */
- public Uri importTextMessage(String address, int type, String text, long timestampMillis,
- boolean seen, boolean read) {
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.importTextMessage(ActivityThread.currentPackageName(),
- address, type, text, timestampMillis, seen, read);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return null;
- }
-
- /** Represents the received SMS message for importing {@hide} */
- public static final int SMS_TYPE_INCOMING = 0;
- /** Represents the sent SMS message for importing {@hide} */
- public static final int SMS_TYPE_OUTGOING = 1;
-
- /**
- * Import a multimedia message into system's MMS store. Only the following PDU type is
- * supported: Retrieve.conf, Send.req, Notification.ind, Delivery.ind, Read-Orig.ind
- *
- * Only default SMS apps can import MMS
- *
- * @param contentUri the content uri from which to read the PDU of the message to import
- * @param messageId the optional message id. Use null if not specifying
- * @param timestampSecs the optional message timestamp. Use -1 if not specifying
- * @param seen if the message is seen
- * @param read if the message is read
- * @return the message URI, null if failed
- * @throws IllegalArgumentException if pdu is empty
- * {@hide}
- */
- public Uri importMultimediaMessage(Uri contentUri, String messageId, long timestampSecs,
- boolean seen, boolean read) {
- if (contentUri == null) {
- throw new IllegalArgumentException("Uri contentUri null");
- }
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.importMultimediaMessage(ActivityThread.currentPackageName(),
- contentUri, messageId, timestampSecs, seen, read);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return null;
- }
-
- /**
- * Delete a system stored SMS or MMS message
- *
- * Only default SMS apps can delete system stored SMS and MMS messages
- *
- * @param messageUri the URI of the stored message
- * @return true if deletion is successful, false otherwise
- * @throws IllegalArgumentException if messageUri is empty
- * {@hide}
- */
- public boolean deleteStoredMessage(Uri messageUri) {
- if (messageUri == null) {
- throw new IllegalArgumentException("Empty message URI");
- }
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.deleteStoredMessage(ActivityThread.currentPackageName(), messageUri);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return false;
- }
-
- /**
- * Delete a system stored SMS or MMS thread
- *
- * Only default SMS apps can delete system stored SMS and MMS conversations
- *
- * @param conversationId the ID of the message conversation
- * @return true if deletion is successful, false otherwise
- * {@hide}
- */
- public boolean deleteStoredConversation(long conversationId) {
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.deleteStoredConversation(
- ActivityThread.currentPackageName(), conversationId);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return false;
- }
-
- /**
- * Update the status properties of a system stored SMS or MMS message, e.g.
- * the read status of a message, etc.
- *
- * @param messageUri the URI of the stored message
- * @param statusValues a list of status properties in key-value pairs to update
- * @return true if update is successful, false otherwise
- * @throws IllegalArgumentException if messageUri is empty
- * {@hide}
- */
- public boolean updateStoredMessageStatus(Uri messageUri, ContentValues statusValues) {
- if (messageUri == null) {
- throw new IllegalArgumentException("Empty message URI");
- }
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.updateStoredMessageStatus(ActivityThread.currentPackageName(),
- messageUri, statusValues);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return false;
- }
-
- /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */
- public static final String MESSAGE_STATUS_SEEN = "seen";
- /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */
- public static final String MESSAGE_STATUS_READ = "read";
-
- /**
- * Archive or unarchive a stored conversation
- *
- * @param conversationId the ID of the message conversation
- * @param archived true to archive the conversation, false to unarchive
- * @return true if update is successful, false otherwise
- * {@hide}
- */
- public boolean archiveStoredConversation(long conversationId, boolean archived) {
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.archiveStoredConversation(ActivityThread.currentPackageName(),
- conversationId, archived);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return false;
- }
-
- /**
- * Add a text message draft to system SMS store
- *
- * Only default SMS apps can add SMS draft
- *
- * @param address the destination address of message
- * @param text the body of the message to send
- * @return the URI of the stored draft message
- * {@hide}
- */
- public Uri addTextMessageDraft(String address, String text) {
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.addTextMessageDraft(ActivityThread.currentPackageName(), address, text);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return null;
- }
-
- /**
- * Add a multimedia message draft to system MMS store
- *
- * Only default SMS apps can add MMS draft
- *
- * @param contentUri the content uri from which to read the PDU data of the draft MMS
- * @return the URI of the stored draft message
- * @throws IllegalArgumentException if pdu is empty
- * {@hide}
- */
- public Uri addMultimediaMessageDraft(Uri contentUri) {
- if (contentUri == null) {
- throw new IllegalArgumentException("Uri contentUri null");
- }
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.addMultimediaMessageDraft(ActivityThread.currentPackageName(),
- contentUri);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return null;
- }
-
- /**
- * Send a system stored text message.
- *
- * You can only send a failed text message or a draft text message.
- *
- * @param messageUri the URI of the stored message
- * @param scAddress is the service center address or null to use the current default SMSC
- * @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is successfully sent, or failed.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
- * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
- * <code>RESULT_ERROR_RADIO_OFF</code><br>
- * <code>RESULT_ERROR_NULL_PDU</code><br>
- * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
- * the extra "errorCode" containing a radio technology specific value,
- * generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
- * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is delivered to the recipient. The
- * raw pdu of the status report is in the extended data ("pdu").
- *
- * @throws IllegalArgumentException if messageUri is empty
- * {@hide}
- */
- public void sendStoredTextMessage(Uri messageUri, String scAddress, PendingIntent sentIntent,
- PendingIntent deliveryIntent) {
- if (messageUri == null) {
- throw new IllegalArgumentException("Empty message URI");
- }
- try {
- ISms iccISms = getISmsServiceOrThrow();
- iccISms.sendStoredText(
- getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
- scAddress, sentIntent, deliveryIntent);
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
- * Send a system stored multi-part text message.
- *
- * You can only send a failed text message or a draft text message.
- * The provided <code>PendingIntent</code> lists should match the part number of the
- * divided text of the stored message by using <code>divideMessage</code>
- *
- * @param messageUri the URI of the stored message
- * @param scAddress is the service center address or null to use
- * the current default SMSC
- * @param sentIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been sent.
- * The result code will be <code>Activity.RESULT_OK</code> for success,
- * or one of these errors:<br>
- * <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
- * <code>RESULT_ERROR_RADIO_OFF</code><br>
- * <code>RESULT_ERROR_NULL_PDU</code><br>
- * For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
- * the extra "errorCode" containing a radio technology specific value,
- * generally only useful for troubleshooting.<br>
- * The per-application based SMS control checks sentIntent. If sentIntent
- * is NULL the caller will be checked against all unknown applications,
- * which cause smaller number of SMS to be sent in checking period.
- * @param deliveryIntents if not null, an <code>ArrayList</code> of
- * <code>PendingIntent</code>s (one for each message part) that is
- * broadcast when the corresponding message part has been delivered
- * to the recipient. The raw pdu of the status report is in the
- * extended data ("pdu").
- *
- * @throws IllegalArgumentException if messageUri is empty
- * {@hide}
- */
- public void sendStoredMultipartTextMessage(Uri messageUri, String scAddress,
- ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
- if (messageUri == null) {
- throw new IllegalArgumentException("Empty message URI");
- }
- try {
- ISms iccISms = getISmsServiceOrThrow();
- iccISms.sendStoredMultipartText(
- getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
- scAddress, sentIntents, deliveryIntents);
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
- * Send a system stored MMS message
- *
- * This is used for sending a previously sent, but failed-to-send, message or
- * for sending a text message that has been stored as a draft.
- *
- * @param messageUri the URI of the stored message
- * @param configOverrides the carrier-specific messaging configuration values to override for
- * sending the message.
- * @param sentIntent if not NULL this <code>PendingIntent</code> is
- * broadcast when the message is successfully sent, or failed
- * @throws IllegalArgumentException if messageUri is empty
- * {@hide}
- */
- public void sendStoredMultimediaMessage(Uri messageUri, Bundle configOverrides,
- PendingIntent sentIntent) {
- if (messageUri == null) {
- throw new IllegalArgumentException("Empty message URI");
- }
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- iMms.sendStoredMessage(
- getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
- configOverrides, sentIntent);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
- * Turns on/off the flag to automatically write sent/received SMS/MMS messages into system
- *
- * When this flag is on, all SMS/MMS sent/received are stored by system automatically
- * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
- * automatically
- *
- * This flag can only be changed by default SMS apps
- *
- * @param enabled Whether to enable message auto persisting
- * {@hide}
- */
- public void setAutoPersisting(boolean enabled) {
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- iMms.setAutoPersisting(ActivityThread.currentPackageName(), enabled);
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
- * Get the value of the flag to automatically write sent/received SMS/MMS messages into system
- *
- * When this flag is on, all SMS/MMS sent/received are stored by system automatically
- * When this flag is off, only SMS/MMS sent by non-default SMS apps are stored by system
- * automatically
- *
- * @return the current value of the auto persist flag
- * {@hide}
- */
- public boolean getAutoPersisting() {
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.getAutoPersisting();
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return false;
- }
-
- /**
- * Get carrier-dependent configuration values.
- *
- * @return bundle key/values pairs of configuration values
- */
- public Bundle getCarrierConfigValues() {
- try {
- IMms iMms = IMms.Stub.asInterface(ServiceManager.getService("imms"));
- if (iMms != null) {
- return iMms.getCarrierConfigValues(getSubscriptionId());
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- return null;
- }
-
- /**
- * Filters a bundle to only contain MMS config variables.
- *
- * This is for use with bundles returned by {@link CarrierConfigManager} which contain MMS
- * config and unrelated config. It is assumed that all MMS_CONFIG_* keys are present in the
- * supplied bundle.
- *
- * @param config a Bundle that contains MMS config variables and possibly more.
- * @return a new Bundle that only contains the MMS_CONFIG_* keys defined above.
- * @hide
- */
- public static Bundle getMmsConfig(BaseBundle config) {
- Bundle filtered = new Bundle();
- filtered.putBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID,
- config.getBoolean(MMS_CONFIG_APPEND_TRANSACTION_ID));
- filtered.putBoolean(MMS_CONFIG_MMS_ENABLED, config.getBoolean(MMS_CONFIG_MMS_ENABLED));
- filtered.putBoolean(MMS_CONFIG_GROUP_MMS_ENABLED,
- config.getBoolean(MMS_CONFIG_GROUP_MMS_ENABLED));
- filtered.putBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED,
- config.getBoolean(MMS_CONFIG_NOTIFY_WAP_MMSC_ENABLED));
- filtered.putBoolean(MMS_CONFIG_ALIAS_ENABLED, config.getBoolean(MMS_CONFIG_ALIAS_ENABLED));
- filtered.putBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO,
- config.getBoolean(MMS_CONFIG_ALLOW_ATTACH_AUDIO));
- filtered.putBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED,
- config.getBoolean(MMS_CONFIG_MULTIPART_SMS_ENABLED));
- filtered.putBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED,
- config.getBoolean(MMS_CONFIG_SMS_DELIVERY_REPORT_ENABLED));
- filtered.putBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION,
- config.getBoolean(MMS_CONFIG_SUPPORT_MMS_CONTENT_DISPOSITION));
- filtered.putBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES,
- config.getBoolean(MMS_CONFIG_SEND_MULTIPART_SMS_AS_SEPARATE_MESSAGES));
- filtered.putBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED,
- config.getBoolean(MMS_CONFIG_MMS_READ_REPORT_ENABLED));
- filtered.putBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED,
- config.getBoolean(MMS_CONFIG_MMS_DELIVERY_REPORT_ENABLED));
- filtered.putBoolean(MMS_CONFIG_CLOSE_CONNECTION,
- config.getBoolean(MMS_CONFIG_CLOSE_CONNECTION));
- filtered.putInt(MMS_CONFIG_MAX_MESSAGE_SIZE, config.getInt(MMS_CONFIG_MAX_MESSAGE_SIZE));
- filtered.putInt(MMS_CONFIG_MAX_IMAGE_WIDTH, config.getInt(MMS_CONFIG_MAX_IMAGE_WIDTH));
- filtered.putInt(MMS_CONFIG_MAX_IMAGE_HEIGHT, config.getInt(MMS_CONFIG_MAX_IMAGE_HEIGHT));
- filtered.putInt(MMS_CONFIG_RECIPIENT_LIMIT, config.getInt(MMS_CONFIG_RECIPIENT_LIMIT));
- filtered.putInt(MMS_CONFIG_ALIAS_MIN_CHARS, config.getInt(MMS_CONFIG_ALIAS_MIN_CHARS));
- filtered.putInt(MMS_CONFIG_ALIAS_MAX_CHARS, config.getInt(MMS_CONFIG_ALIAS_MAX_CHARS));
- filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD,
- config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_THRESHOLD));
- filtered.putInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD,
- config.getInt(MMS_CONFIG_SMS_TO_MMS_TEXT_LENGTH_THRESHOLD));
- filtered.putInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE,
- config.getInt(MMS_CONFIG_MESSAGE_TEXT_MAX_SIZE));
- filtered.putInt(MMS_CONFIG_SUBJECT_MAX_LENGTH,
- config.getInt(MMS_CONFIG_SUBJECT_MAX_LENGTH));
- filtered.putInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT,
- config.getInt(MMS_CONFIG_HTTP_SOCKET_TIMEOUT));
- filtered.putString(MMS_CONFIG_UA_PROF_TAG_NAME,
- config.getString(MMS_CONFIG_UA_PROF_TAG_NAME));
- filtered.putString(MMS_CONFIG_USER_AGENT, config.getString(MMS_CONFIG_USER_AGENT));
- filtered.putString(MMS_CONFIG_UA_PROF_URL, config.getString(MMS_CONFIG_UA_PROF_URL));
- filtered.putString(MMS_CONFIG_HTTP_PARAMS, config.getString(MMS_CONFIG_HTTP_PARAMS));
- filtered.putString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER,
- config.getString(MMS_CONFIG_EMAIL_GATEWAY_NUMBER));
- filtered.putString(MMS_CONFIG_NAI_SUFFIX, config.getString(MMS_CONFIG_NAI_SUFFIX));
- filtered.putBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS,
- config.getBoolean(MMS_CONFIG_SHOW_CELL_BROADCAST_APP_LINKS));
- filtered.putBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER,
- config.getBoolean(MMS_CONFIG_SUPPORT_HTTP_CHARSET_HEADER));
- return filtered;
- }
-
-}
diff --git a/src/java/android/telephony/SmsMessage.java b/src/java/android/telephony/SmsMessage.java
deleted file mode 100644
index 73e1f1a..0000000
--- a/src/java/android/telephony/SmsMessage.java
+++ /dev/null
@@ -1,890 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony;
-
-import android.os.Binder;
-import android.os.Parcel;
-import android.content.res.Resources;
-import android.text.TextUtils;
-
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.SmsMessageBase.SubmitPduBase;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
-
-import java.lang.Math;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
-
-
-/**
- * A Short Message Service message.
- * @see android.provider.Telephony.Sms.Intents#getMessagesFromIntent
- */
-public class SmsMessage {
- private static final String LOG_TAG = "SmsMessage";
-
- /**
- * SMS Class enumeration.
- * See TS 23.038.
- *
- */
- public enum MessageClass{
- UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3;
- }
-
- /** User data text encoding code unit size */
- public static final int ENCODING_UNKNOWN = 0;
- public static final int ENCODING_7BIT = 1;
- public static final int ENCODING_8BIT = 2;
- public static final int ENCODING_16BIT = 3;
- /**
- * @hide This value is not defined in global standard. Only in Korea, this is used.
- */
- public static final int ENCODING_KSC5601 = 4;
-
- /** The maximum number of payload bytes per message */
- public static final int MAX_USER_DATA_BYTES = 140;
-
- /**
- * The maximum number of payload bytes per message if a user data header
- * is present. This assumes the header only contains the
- * CONCATENATED_8_BIT_REFERENCE element.
- */
- public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134;
-
- /** The maximum number of payload septets per message */
- public static final int MAX_USER_DATA_SEPTETS = 160;
-
- /**
- * The maximum number of payload septets per message if a user data header
- * is present. This assumes the header only contains the
- * CONCATENATED_8_BIT_REFERENCE element.
- */
- public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153;
-
- /**
- * Indicates a 3GPP format SMS message.
- * @hide pending API council approval
- */
- public static final String FORMAT_3GPP = "3gpp";
-
- /**
- * Indicates a 3GPP2 format SMS message.
- * @hide pending API council approval
- */
- public static final String FORMAT_3GPP2 = "3gpp2";
-
- /** Contains actual SmsMessage. Only public for debugging and for framework layer.
- *
- * @hide
- */
- public SmsMessageBase mWrappedSmsMessage;
-
- /** Indicates the subId
- *
- * @hide
- */
- private int mSubId = 0;
-
- /** set Subscription information
- *
- * @hide
- */
- public void setSubId(int subId) {
- mSubId = subId;
- }
-
- /** get Subscription information
- *
- * @hide
- */
- public int getSubId() {
- return mSubId;
- }
-
- public static class SubmitPdu {
-
- public byte[] encodedScAddress; // Null if not applicable.
- public byte[] encodedMessage;
-
- @Override
- public String toString() {
- return "SubmitPdu: encodedScAddress = "
- + Arrays.toString(encodedScAddress)
- + ", encodedMessage = "
- + Arrays.toString(encodedMessage);
- }
-
- /**
- * @hide
- */
- protected SubmitPdu(SubmitPduBase spb) {
- this.encodedMessage = spb.encodedMessage;
- this.encodedScAddress = spb.encodedScAddress;
- }
-
- }
-
- private SmsMessage(SmsMessageBase smb) {
- mWrappedSmsMessage = smb;
- }
-
- /**
- * Create an SmsMessage from a raw PDU. Guess format based on Voice
- * technology first, if it fails use other format.
- * All applications which handle
- * incoming SMS messages by processing the {@code SMS_RECEIVED_ACTION} broadcast
- * intent <b>must</b> now pass the new {@code format} String extra from the intent
- * into the new method {@code createFromPdu(byte[], String)} which takes an
- * extra format parameter. This is required in order to correctly decode the PDU on
- * devices that require support for both 3GPP and 3GPP2 formats at the same time,
- * such as dual-mode GSM/CDMA and CDMA/LTE phones.
- * @deprecated Use {@link #createFromPdu(byte[], String)} instead.
- */
- @Deprecated
- public static SmsMessage createFromPdu(byte[] pdu) {
- SmsMessage message = null;
-
- // cdma(3gpp2) vs gsm(3gpp) format info was not given,
- // guess from active voice phone type
- int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
- String format = (PHONE_TYPE_CDMA == activePhone) ?
- SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP;
- message = createFromPdu(pdu, format);
-
- if (null == message || null == message.mWrappedSmsMessage) {
- // decoding pdu failed based on activePhone type, must be other format
- format = (PHONE_TYPE_CDMA == activePhone) ?
- SmsConstants.FORMAT_3GPP : SmsConstants.FORMAT_3GPP2;
- message = createFromPdu(pdu, format);
- }
- return message;
- }
-
- /**
- * Create an SmsMessage from a raw PDU with the specified message format. The
- * message format is passed in the
- * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} as the {@code format}
- * String extra, and will be either "3gpp" for GSM/UMTS/LTE messages in 3GPP format
- * or "3gpp2" for CDMA/LTE messages in 3GPP2 format.
- *
- * @param pdu the message PDU from the
- * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} intent
- * @param format the format extra from the
- * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} intent
- */
- public static SmsMessage createFromPdu(byte[] pdu, String format) {
- SmsMessageBase wrappedMessage;
-
- if (SmsConstants.FORMAT_3GPP2.equals(format)) {
- wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
- } else if (SmsConstants.FORMAT_3GPP.equals(format)) {
- wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromPdu(pdu);
- } else {
- Rlog.e(LOG_TAG, "createFromPdu(): unsupported message format " + format);
- return null;
- }
-
- if (wrappedMessage != null) {
- return new SmsMessage(wrappedMessage);
- } else {
- Rlog.e(LOG_TAG, "createFromPdu(): wrappedMessage is null");
- return null;
- }
- }
-
- /**
- * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
- * +CMT unsolicited response (PDU mode, of course)
- * +CMT: [<alpha>],<length><CR><LF><pdu>
- *
- * Only public for debugging and for RIL
- *
- * {@hide}
- */
- public static SmsMessage newFromCMT(String[] lines) {
- // received SMS in 3GPP format
- SmsMessageBase wrappedMessage =
- com.android.internal.telephony.gsm.SmsMessage.newFromCMT(lines);
-
- if (wrappedMessage != null) {
- return new SmsMessage(wrappedMessage);
- } else {
- Rlog.e(LOG_TAG, "newFromCMT(): wrappedMessage is null");
- return null;
- }
- }
-
- /** @hide */
- public static SmsMessage newFromParcel(Parcel p) {
- // received SMS in 3GPP2 format
- SmsMessageBase wrappedMessage =
- com.android.internal.telephony.cdma.SmsMessage.newFromParcel(p);
-
- return new SmsMessage(wrappedMessage);
- }
-
- /**
- * Create an SmsMessage from an SMS EF record.
- *
- * @param index Index of SMS record. This should be index in ArrayList
- * returned by SmsManager.getAllMessagesFromSim + 1.
- * @param data Record data.
- * @return An SmsMessage representing the record.
- *
- * @hide
- */
- public static SmsMessage createFromEfRecord(int index, byte[] data) {
- SmsMessageBase wrappedMessage;
-
- if (isCdmaVoice()) {
- wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord(
- index, data);
- } else {
- wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord(
- index, data);
- }
-
- if (wrappedMessage != null) {
- return new SmsMessage(wrappedMessage);
- } else {
- Rlog.e(LOG_TAG, "createFromEfRecord(): wrappedMessage is null");
- return null;
- }
- }
-
- /**
- * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
- * length in bytes (not hex chars) less the SMSC header
- *
- * FIXME: This method is only used by a CTS test case that isn't run on CDMA devices.
- * We should probably deprecate it and remove the obsolete test case.
- */
- public static int getTPLayerLengthForPDU(String pdu) {
- if (isCdmaVoice()) {
- return com.android.internal.telephony.cdma.SmsMessage.getTPLayerLengthForPDU(pdu);
- } else {
- return com.android.internal.telephony.gsm.SmsMessage.getTPLayerLengthForPDU(pdu);
- }
- }
-
- /*
- * TODO(cleanup): It would make some sense if the result of
- * preprocessing a message to determine the proper encoding (i.e.
- * the resulting data structure from calculateLength) could be
- * passed as an argument to the actual final encoding function.
- * This would better ensure that the logic behind size calculation
- * actually matched the encoding.
- */
-
- /**
- * Calculates the number of SMS's required to encode the message body and
- * the number of characters remaining until the next message.
- *
- * @param msgBody the message to encode
- * @param use7bitOnly if true, characters that are not part of the
- * radio-specific 7-bit encoding are counted as single
- * space chars. If false, and if the messageBody contains
- * non-7-bit encodable characters, length is calculated
- * using a 16-bit encoding.
- * @return an int[4] with int[0] being the number of SMS's
- * required, int[1] the number of code units used, and
- * int[2] is the number of code units remaining until the
- * next message. int[3] is an indicator of the encoding
- * code unit size (see the ENCODING_* definitions in SmsConstants)
- */
- public static int[] calculateLength(CharSequence msgBody, boolean use7bitOnly) {
- // this function is for MO SMS
- TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?
- com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly,
- true) :
- com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly);
- int ret[] = new int[4];
- ret[0] = ted.msgCount;
- ret[1] = ted.codeUnitCount;
- ret[2] = ted.codeUnitsRemaining;
- ret[3] = ted.codeUnitSize;
- return ret;
- }
-
- /**
- * Divide a message text into several fragments, none bigger than
- * the maximum SMS message text size.
- *
- * @param text text, must not be null.
- * @return an <code>ArrayList</code> of strings that, in order,
- * comprise the original msg text
- *
- * @hide
- */
- public static ArrayList<String> fragmentText(String text) {
- // This function is for MO SMS
- TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?
- com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false, true) :
- com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false);
-
- // TODO(cleanup): The code here could be rolled into the logic
- // below cleanly if these MAX_* constants were defined more
- // flexibly...
-
- int limit;
- if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {
- int udhLength;
- if (ted.languageTable != 0 && ted.languageShiftTable != 0) {
- udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES;
- } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) {
- udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE;
- } else {
- udhLength = 0;
- }
-
- if (ted.msgCount > 1) {
- udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE;
- }
-
- if (udhLength != 0) {
- udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH;
- }
-
- limit = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength;
- } else {
- if (ted.msgCount > 1) {
- limit = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
- // If EMS is not supported, break down EMS into single segment SMS
- // and add page info " x/y".
- // In the case of UCS2 encoding, we need 8 bytes for this,
- // but we only have 6 bytes from UDH, so truncate the limit for
- // each segment by 2 bytes (1 char).
- // Make sure total number of segments is less than 10.
- if (!hasEmsSupport() && ted.msgCount < 10) {
- limit -= 2;
- }
- } else {
- limit = SmsConstants.MAX_USER_DATA_BYTES;
- }
- }
-
- String newMsgBody = null;
- Resources r = Resources.getSystem();
- if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
- newMsgBody = Sms7BitEncodingTranslator.translate(text);
- }
- if (TextUtils.isEmpty(newMsgBody)) {
- newMsgBody = text;
- }
- int pos = 0; // Index in code units.
- int textLen = newMsgBody.length();
- ArrayList<String> result = new ArrayList<String>(ted.msgCount);
- while (pos < textLen) {
- int nextPos = 0; // Counts code units.
- if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {
- if (useCdmaFormatForMoSms() && ted.msgCount == 1) {
- // For a singleton CDMA message, the encoding must be ASCII...
- nextPos = pos + Math.min(limit, textLen - pos);
- } else {
- // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode).
- nextPos = GsmAlphabet.findGsmSeptetLimitIndex(newMsgBody, pos, limit,
- ted.languageTable, ted.languageShiftTable);
- }
- } else { // Assume unicode.
- nextPos = SmsMessageBase.findNextUnicodePosition(pos, limit, newMsgBody);
- }
- if ((nextPos <= pos) || (nextPos > textLen)) {
- Rlog.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +
- nextPos + " >= " + textLen + ")");
- break;
- }
- result.add(newMsgBody.substring(pos, nextPos));
- pos = nextPos;
- }
- return result;
- }
-
- /**
- * Calculates the number of SMS's required to encode the message body and
- * the number of characters remaining until the next message, given the
- * current encoding.
- *
- * @param messageBody the message to encode
- * @param use7bitOnly if true, characters that are not part of the radio
- * specific (GSM / CDMA) alphabet encoding are converted to as a
- * single space characters. If false, a messageBody containing
- * non-GSM or non-CDMA alphabet characters are encoded using
- * 16-bit encoding.
- * @return an int[4] with int[0] being the number of SMS's required, int[1]
- * the number of code units used, and int[2] is the number of code
- * units remaining until the next message. int[3] is the encoding
- * type that should be used for the message.
- */
- public static int[] calculateLength(String messageBody, boolean use7bitOnly) {
- return calculateLength((CharSequence)messageBody, use7bitOnly);
- }
-
- /*
- * TODO(cleanup): It looks like there is now no useful reason why
- * apps should generate pdus themselves using these routines,
- * instead of handing the raw data to SMSDispatcher (and thereby
- * have the phone process do the encoding). Moreover, CDMA now
- * has shared state (in the form of the msgId system property)
- * which can only be modified by the phone process, and hence
- * makes the output of these routines incorrect. Since they now
- * serve no purpose, they should probably just return null
- * directly, and be deprecated. Going further in that direction,
- * the above parsers of serialized pdu data should probably also
- * be gotten rid of, hiding all but the necessarily visible
- * structured data from client apps. A possible concern with
- * doing this is that apps may be using these routines to generate
- * pdus that are then sent elsewhere, some network server, for
- * example, and that always returning null would thereby break
- * otherwise useful apps.
- */
-
- /**
- * Get an SMS-SUBMIT PDU for a destination address and a message.
- * This method will not attempt to use any GSM national language 7 bit encodings.
- *
- * @param scAddress Service Centre address. Null means use default.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- */
- public static SubmitPdu getSubmitPdu(String scAddress,
- String destinationAddress, String message, boolean statusReportRequested) {
- SubmitPduBase spb;
-
- if (useCdmaFormatForMoSms()) {
- spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
- destinationAddress, message, statusReportRequested, null);
- } else {
- spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
- destinationAddress, message, statusReportRequested);
- }
-
- return new SubmitPdu(spb);
- }
-
- /**
- * Get an SMS-SUBMIT PDU for a data message to a destination address & port.
- * This method will not attempt to use any GSM national language 7 bit encodings.
- *
- * @param scAddress Service Centre address. null == use default
- * @param destinationAddress the address of the destination for the message
- * @param destinationPort the port to deliver the message to at the
- * destination
- * @param data the data for the message
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- */
- public static SubmitPdu getSubmitPdu(String scAddress,
- String destinationAddress, short destinationPort, byte[] data,
- boolean statusReportRequested) {
- SubmitPduBase spb;
-
- if (useCdmaFormatForMoSms()) {
- spb = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu(scAddress,
- destinationAddress, destinationPort, data, statusReportRequested);
- } else {
- spb = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(scAddress,
- destinationAddress, destinationPort, data, statusReportRequested);
- }
-
- return new SubmitPdu(spb);
- }
-
- /**
- * Returns the address of the SMS service center that relayed this message
- * or null if there is none.
- */
- public String getServiceCenterAddress() {
- return mWrappedSmsMessage.getServiceCenterAddress();
- }
-
- /**
- * Returns the originating address (sender) of this SMS message in String
- * form or null if unavailable
- */
- public String getOriginatingAddress() {
- return mWrappedSmsMessage.getOriginatingAddress();
- }
-
- /**
- * Returns the originating address, or email from address if this message
- * was from an email gateway. Returns null if originating address
- * unavailable.
- */
- public String getDisplayOriginatingAddress() {
- return mWrappedSmsMessage.getDisplayOriginatingAddress();
- }
-
- /**
- * Returns the message body as a String, if it exists and is text based.
- * @return message body is there is one, otherwise null
- */
- public String getMessageBody() {
- return mWrappedSmsMessage.getMessageBody();
- }
-
- /**
- * Returns the class of this message.
- */
- public MessageClass getMessageClass() {
- switch(mWrappedSmsMessage.getMessageClass()) {
- case CLASS_0: return MessageClass.CLASS_0;
- case CLASS_1: return MessageClass.CLASS_1;
- case CLASS_2: return MessageClass.CLASS_2;
- case CLASS_3: return MessageClass.CLASS_3;
- default: return MessageClass.UNKNOWN;
-
- }
- }
-
- /**
- * Returns the message body, or email message body if this message was from
- * an email gateway. Returns null if message body unavailable.
- */
- public String getDisplayMessageBody() {
- return mWrappedSmsMessage.getDisplayMessageBody();
- }
-
- /**
- * Unofficial convention of a subject line enclosed in parens empty string
- * if not present
- */
- public String getPseudoSubject() {
- return mWrappedSmsMessage.getPseudoSubject();
- }
-
- /**
- * Returns the service centre timestamp in currentTimeMillis() format
- */
- public long getTimestampMillis() {
- return mWrappedSmsMessage.getTimestampMillis();
- }
-
- /**
- * Returns true if message is an email.
- *
- * @return true if this message came through an email gateway and email
- * sender / subject / parsed body are available
- */
- public boolean isEmail() {
- return mWrappedSmsMessage.isEmail();
- }
-
- /**
- * @return if isEmail() is true, body of the email sent through the gateway.
- * null otherwise
- */
- public String getEmailBody() {
- return mWrappedSmsMessage.getEmailBody();
- }
-
- /**
- * @return if isEmail() is true, email from address of email sent through
- * the gateway. null otherwise
- */
- public String getEmailFrom() {
- return mWrappedSmsMessage.getEmailFrom();
- }
-
- /**
- * Get protocol identifier.
- */
- public int getProtocolIdentifier() {
- return mWrappedSmsMessage.getProtocolIdentifier();
- }
-
- /**
- * See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
- * SMS
- */
- public boolean isReplace() {
- return mWrappedSmsMessage.isReplace();
- }
-
- /**
- * Returns true for CPHS MWI toggle message.
- *
- * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section
- * B.4.2
- */
- public boolean isCphsMwiMessage() {
- return mWrappedSmsMessage.isCphsMwiMessage();
- }
-
- /**
- * returns true if this message is a CPHS voicemail / message waiting
- * indicator (MWI) clear message
- */
- public boolean isMWIClearMessage() {
- return mWrappedSmsMessage.isMWIClearMessage();
- }
-
- /**
- * returns true if this message is a CPHS voicemail / message waiting
- * indicator (MWI) set message
- */
- public boolean isMWISetMessage() {
- return mWrappedSmsMessage.isMWISetMessage();
- }
-
- /**
- * returns true if this message is a "Message Waiting Indication Group:
- * Discard Message" notification and should not be stored.
- */
- public boolean isMwiDontStore() {
- return mWrappedSmsMessage.isMwiDontStore();
- }
-
- /**
- * returns the user data section minus the user data header if one was
- * present.
- */
- public byte[] getUserData() {
- return mWrappedSmsMessage.getUserData();
- }
-
- /**
- * Returns the raw PDU for the message.
- *
- * @return the raw PDU for the message.
- */
- public byte[] getPdu() {
- return mWrappedSmsMessage.getPdu();
- }
-
- /**
- * Returns the status of the message on the SIM (read, unread, sent, unsent).
- *
- * @return the status of the message on the SIM. These are:
- * SmsManager.STATUS_ON_SIM_FREE
- * SmsManager.STATUS_ON_SIM_READ
- * SmsManager.STATUS_ON_SIM_UNREAD
- * SmsManager.STATUS_ON_SIM_SEND
- * SmsManager.STATUS_ON_SIM_UNSENT
- * @deprecated Use getStatusOnIcc instead.
- */
- @Deprecated public int getStatusOnSim() {
- return mWrappedSmsMessage.getStatusOnIcc();
- }
-
- /**
- * Returns the status of the message on the ICC (read, unread, sent, unsent).
- *
- * @return the status of the message on the ICC. These are:
- * SmsManager.STATUS_ON_ICC_FREE
- * SmsManager.STATUS_ON_ICC_READ
- * SmsManager.STATUS_ON_ICC_UNREAD
- * SmsManager.STATUS_ON_ICC_SEND
- * SmsManager.STATUS_ON_ICC_UNSENT
- */
- public int getStatusOnIcc() {
- return mWrappedSmsMessage.getStatusOnIcc();
- }
-
- /**
- * Returns the record index of the message on the SIM (1-based index).
- * @return the record index of the message on the SIM, or -1 if this
- * SmsMessage was not created from a SIM SMS EF record.
- * @deprecated Use getIndexOnIcc instead.
- */
- @Deprecated public int getIndexOnSim() {
- return mWrappedSmsMessage.getIndexOnIcc();
- }
-
- /**
- * Returns the record index of the message on the ICC (1-based index).
- * @return the record index of the message on the ICC, or -1 if this
- * SmsMessage was not created from a ICC SMS EF record.
- */
- public int getIndexOnIcc() {
- return mWrappedSmsMessage.getIndexOnIcc();
- }
-
- /**
- * GSM:
- * For an SMS-STATUS-REPORT message, this returns the status field from
- * the status report. This field indicates the status of a previously
- * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a
- * description of values.
- * CDMA:
- * For not interfering with status codes from GSM, the value is
- * shifted to the bits 31-16.
- * The value is composed of an error class (bits 25-24) and a status code (bits 23-16).
- * Possible codes are described in C.S0015-B, v2.0, 4.5.21.
- *
- * @return 0 indicates the previously sent message was received.
- * See TS 23.040, 9.9.2.3.15 and C.S0015-B, v2.0, 4.5.21
- * for a description of other possible values.
- */
- public int getStatus() {
- return mWrappedSmsMessage.getStatus();
- }
-
- /**
- * Return true iff the message is a SMS-STATUS-REPORT message.
- */
- public boolean isStatusReportMessage() {
- return mWrappedSmsMessage.isStatusReportMessage();
- }
-
- /**
- * Returns true iff the <code>TP-Reply-Path</code> bit is set in
- * this message.
- */
- public boolean isReplyPathPresent() {
- return mWrappedSmsMessage.isReplyPathPresent();
- }
-
- /**
- * Determines whether or not to use CDMA format for MO SMS.
- * If SMS over IMS is supported, then format is based on IMS SMS format,
- * otherwise format is based on current phone type.
- *
- * @return true if Cdma format should be used for MO SMS, false otherwise.
- */
- private static boolean useCdmaFormatForMoSms() {
- if (!SmsManager.getDefault().isImsSmsSupported()) {
- // use Voice technology to determine SMS format.
- return isCdmaVoice();
- }
- // IMS is registered with SMS support, check the SMS format supported
- return (SmsConstants.FORMAT_3GPP2.equals(SmsManager.getDefault().getImsSmsFormat()));
- }
-
- /**
- * Determines whether or not to current phone type is cdma.
- *
- * @return true if current phone type is cdma, false otherwise.
- */
- private static boolean isCdmaVoice() {
- int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
- return (PHONE_TYPE_CDMA == activePhone);
- }
-
- /**
- * Decide if the carrier supports long SMS.
- * {@hide}
- */
- public static boolean hasEmsSupport() {
- if (!isNoEmsSupportConfigListExisted()) {
- return true;
- }
-
- String simOperator;
- String gid;
- final long identity = Binder.clearCallingIdentity();
- try {
- simOperator = TelephonyManager.getDefault().getSimOperatorNumeric();
- gid = TelephonyManager.getDefault().getGroupIdLevel1();
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- if (!TextUtils.isEmpty(simOperator)) {
- for (NoEmsSupportConfig currentConfig : mNoEmsSupportConfigList) {
- if (simOperator.startsWith(currentConfig.mOperatorNumber) &&
- (TextUtils.isEmpty(currentConfig.mGid1) ||
- (!TextUtils.isEmpty(currentConfig.mGid1) &&
- currentConfig.mGid1.equalsIgnoreCase(gid)))) {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Check where to add " x/y" in each SMS segment, begin or end.
- * {@hide}
- */
- public static boolean shouldAppendPageNumberAsPrefix() {
- if (!isNoEmsSupportConfigListExisted()) {
- return false;
- }
-
- String simOperator;
- String gid;
- final long identity = Binder.clearCallingIdentity();
- try {
- simOperator = TelephonyManager.getDefault().getSimOperatorNumeric();
- gid = TelephonyManager.getDefault().getGroupIdLevel1();
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
-
- for (NoEmsSupportConfig currentConfig : mNoEmsSupportConfigList) {
- if (simOperator.startsWith(currentConfig.mOperatorNumber) &&
- (TextUtils.isEmpty(currentConfig.mGid1) ||
- (!TextUtils.isEmpty(currentConfig.mGid1)
- && currentConfig.mGid1.equalsIgnoreCase(gid)))) {
- return currentConfig.mIsPrefix;
- }
- }
- return false;
- }
-
- private static class NoEmsSupportConfig {
- String mOperatorNumber;
- String mGid1;
- boolean mIsPrefix;
-
- public NoEmsSupportConfig(String[] config) {
- mOperatorNumber = config[0];
- mIsPrefix = "prefix".equals(config[1]);
- mGid1 = config.length > 2 ? config[2] : null;
- }
-
- @Override
- public String toString() {
- return "NoEmsSupportConfig { mOperatorNumber = " + mOperatorNumber
- + ", mIsPrefix = " + mIsPrefix + ", mGid1 = " + mGid1 + " }";
- }
- }
-
- private static NoEmsSupportConfig[] mNoEmsSupportConfigList = null;
- private static boolean mIsNoEmsSupportConfigListLoaded = false;
-
- private static boolean isNoEmsSupportConfigListExisted() {
- if (!mIsNoEmsSupportConfigListLoaded) {
- Resources r = Resources.getSystem();
- if (r != null) {
- String[] listArray = r.getStringArray(
- com.android.internal.R.array.no_ems_support_sim_operators);
- if ((listArray != null) && (listArray.length > 0)) {
- mNoEmsSupportConfigList = new NoEmsSupportConfig[listArray.length];
- for (int i=0; i<listArray.length; i++) {
- mNoEmsSupportConfigList[i] = new NoEmsSupportConfig(listArray[i].split(";"));
- }
- }
- mIsNoEmsSupportConfigListLoaded = true;
- }
- }
-
- if (mNoEmsSupportConfigList != null && mNoEmsSupportConfigList.length != 0) {
- return true;
- }
-
- return false;
- }
-}
diff --git a/src/java/com/android/internal/telephony/AppSmsManager.java b/src/java/com/android/internal/telephony/AppSmsManager.java
new file mode 100644
index 0000000..11e7f10
--- /dev/null
+++ b/src/java/com/android/internal/telephony/AppSmsManager.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 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.AppOpsManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Binder;
+import android.provider.Telephony.Sms.Intents;
+import android.telephony.SmsMessage;
+import android.util.ArrayMap;
+import android.util.Base64;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.security.SecureRandom;
+import java.util.Map;
+
+
+/**
+ * Manager for app specific incoming SMS requests. This can be used to implement SMS based
+ * communication channels (e.g. for SMS based phone number verification) without needing the
+ * {@link Manifest.permission#RECEIVE_SMS} permission.
+ *
+ * {@link #createAppSpecificSmsRequest} allows an application to provide a {@link PendingIntent}
+ * that is triggered when an incoming SMS is received that contains the provided token.
+ */
+public class AppSmsManager {
+ private static final String LOG_TAG = "AppSmsManager";
+
+ private final SecureRandom mRandom;
+ private final Context mContext;
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private final Map<String, AppRequestInfo> mTokenMap;
+ @GuardedBy("mLock")
+ private final Map<String, AppRequestInfo> mPackageMap;
+
+ public AppSmsManager(Context context) {
+ mRandom = new SecureRandom();
+ mTokenMap = new ArrayMap<>();
+ mPackageMap = new ArrayMap<>();
+ mContext = context;
+ }
+
+ /**
+ * Create an app specific incoming SMS request for the the calling package.
+ *
+ * This method returns a token that if included in a subsequent incoming SMS message the
+ * {@link Intents.SMS_RECEIVED_ACTION} intent will be delivered only to the calling package and
+ * will not require the application have the {@link Manifest.permission#RECEIVE_SMS} permission.
+ *
+ * An app can only have one request at a time, if the app already has a request it will be
+ * dropped and the new one will be added.
+ *
+ * @return Token to include in an SMS to have it delivered directly to the app.
+ */
+ public String createAppSpecificSmsToken(String callingPkg, PendingIntent intent) {
+ // Check calling uid matches callingpkg.
+ AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+ appOps.checkPackage(Binder.getCallingUid(), callingPkg);
+
+ // Generate a nonce to store the request under.
+ String token = generateNonce();
+ synchronized (mLock) {
+ // Only allow one request in flight from a package.
+ if (mPackageMap.containsKey(callingPkg)) {
+ removeRequestLocked(mPackageMap.get(callingPkg));
+ }
+ // Store state.
+ AppRequestInfo info = new AppRequestInfo(callingPkg, intent, token);
+ addRequestLocked(info);
+ }
+ return token;
+ }
+
+ /**
+ * Handle an incoming SMS_DELIVER_ACTION intent if it is an app-only SMS.
+ */
+ public boolean handleSmsReceivedIntent(Intent intent) {
+ // Sanity check the action.
+ if (intent.getAction() != Intents.SMS_DELIVER_ACTION) {
+ Log.wtf(LOG_TAG, "Got intent with incorrect action: " + intent.getAction());
+ return false;
+ }
+
+ synchronized (mLock) {
+ AppRequestInfo info = findAppRequestInfoSmsIntentLocked(intent);
+ if (info == null) {
+ // The message didn't contain a token -- nothing to do.
+ return false;
+ }
+ try {
+ Intent fillIn = new Intent();
+ fillIn.putExtras(intent.getExtras());
+ info.pendingIntent.send(mContext, 0, fillIn);
+ } catch (PendingIntent.CanceledException e) {
+ // The pending intent is canceled, send this SMS as normal.
+ removeRequestLocked(info);
+ return false;
+ }
+
+ removeRequestLocked(info);
+ return true;
+ }
+ }
+
+ private AppRequestInfo findAppRequestInfoSmsIntentLocked(Intent intent) {
+ SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
+ if (messages == null) {
+ return null;
+ }
+ StringBuilder fullMessageBuilder = new StringBuilder();
+ for (SmsMessage message : messages) {
+ if (message == null || message.getMessageBody() == null) {
+ continue;
+ }
+ fullMessageBuilder.append(message.getMessageBody());
+ }
+
+ String fullMessage = fullMessageBuilder.toString();
+
+ // Look for any tokens in the full message.
+ for (String token : mTokenMap.keySet()) {
+ if (fullMessage.contains(token)) {
+ return mTokenMap.get(token);
+ }
+ }
+ return null;
+ }
+
+ private String generateNonce() {
+ byte[] bytes = new byte[8];
+ mRandom.nextBytes(bytes);
+ return Base64.encodeToString(bytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
+ }
+
+ private void removeRequestLocked(AppRequestInfo info) {
+ mTokenMap.remove(info.token);
+ mPackageMap.remove(info.packageName);
+ }
+
+ private void addRequestLocked(AppRequestInfo info) {
+ mTokenMap.put(info.token, info);
+ mPackageMap.put(info.packageName, info);
+ }
+
+ private final class AppRequestInfo {
+ public final String packageName;
+ public final PendingIntent pendingIntent;
+ public final String token;
+
+ AppRequestInfo(String packageName, PendingIntent pendingIntent, String token) {
+ this.packageName = packageName;
+ this.pendingIntent = pendingIntent;
+ this.token = token;
+ }
+ }
+
+}
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index df91ceb..8865901 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -18,16 +18,13 @@
package com.android.internal.telephony;
import android.content.Context;
-import android.os.Message;
-import android.os.RegistrantList;
-import android.os.Registrant;
-import android.os.Handler;
import android.os.AsyncResult;
-import android.telephony.RadioAccessFamily;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
import android.telephony.TelephonyManager;
-import com.android.internal.telephony.RadioCapability;
-
/**
* {@hide}
*/
@@ -43,8 +40,8 @@
protected RegistrantList mOffOrNotAvailRegistrants = new RegistrantList();
protected RegistrantList mNotAvailRegistrants = new RegistrantList();
protected RegistrantList mCallStateRegistrants = new RegistrantList();
- protected RegistrantList mVoiceNetworkStateRegistrants = new RegistrantList();
- protected RegistrantList mDataNetworkStateRegistrants = new RegistrantList();
+ protected RegistrantList mNetworkStateRegistrants = new RegistrantList();
+ protected RegistrantList mDataCallListChangedRegistrants = new RegistrantList();
protected RegistrantList mVoiceRadioTechChangedRegistrants = new RegistrantList();
protected RegistrantList mImsNetworkStateChangedRegistrants = new RegistrantList();
protected RegistrantList mIccStatusChangedRegistrants = new RegistrantList();
@@ -237,27 +234,27 @@
}
@Override
- public void registerForVoiceNetworkStateChanged(Handler h, int what, Object obj) {
+ public void registerForNetworkStateChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
- mVoiceNetworkStateRegistrants.add(r);
+ mNetworkStateRegistrants.add(r);
}
@Override
- public void unregisterForVoiceNetworkStateChanged(Handler h) {
- mVoiceNetworkStateRegistrants.remove(h);
+ public void unregisterForNetworkStateChanged(Handler h) {
+ mNetworkStateRegistrants.remove(h);
}
@Override
- public void registerForDataNetworkStateChanged(Handler h, int what, Object obj) {
+ public void registerForDataCallListChanged(Handler h, int what, Object obj) {
Registrant r = new Registrant (h, what, obj);
- mDataNetworkStateRegistrants.add(r);
+ mDataCallListChangedRegistrants.add(r);
}
@Override
- public void unregisterForDataNetworkStateChanged(Handler h) {
- mDataNetworkStateRegistrants.remove(h);
+ public void unregisterForDataCallListChanged(Handler h) {
+ mDataCallListChangedRegistrants.remove(h);
}
@Override
@@ -785,7 +782,6 @@
if (mState.isAvailable() && !oldState.isAvailable()) {
mAvailRegistrants.notifyRegistrants();
- onRadioAvailable();
}
if (!mState.isAvailable() && oldState.isAvailable()) {
@@ -804,9 +800,6 @@
}
}
- protected void onRadioAvailable() {
- }
-
/**
* {@inheritDoc}
*/
diff --git a/src/java/com/android/internal/telephony/CallFailCause.java b/src/java/com/android/internal/telephony/CallFailCause.java
index d532175..8d2093e 100644
--- a/src/java/com/android/internal/telephony/CallFailCause.java
+++ b/src/java/com/android/internal/telephony/CallFailCause.java
@@ -53,6 +53,7 @@
int ACM_LIMIT_EXCEEDED = 68;
int CALL_BARRED = 240;
int FDN_BLOCKED = 241;
+ int IMEI_NOT_ACCEPTED = 243;
// Stk Call Control
int DIAL_MODIFIED_TO_USSD = 244;
diff --git a/src/java/com/android/internal/telephony/CallManager.java b/src/java/com/android/internal/telephony/CallManager.java
index 4016217..2775fe6 100644
--- a/src/java/com/android/internal/telephony/CallManager.java
+++ b/src/java/com/android/internal/telephony/CallManager.java
@@ -1493,6 +1493,7 @@
* <code>obj.result</code> will be an "MmiCode" object
*/
public void registerForMmiComplete(Handler h, int what, Object obj){
+ Rlog.d(LOG_TAG, "registerForMmiComplete");
mMmiCompleteRegistrants.addUnique(h, what, obj);
}
@@ -2317,7 +2318,7 @@
mMmiInitiateRegistrants.notifyRegistrants((AsyncResult) msg.obj);
break;
case EVENT_MMI_COMPLETE:
- if (VDBG) Rlog.d(LOG_TAG, " handleMessage (EVENT_MMI_COMPLETE)");
+ Rlog.d(LOG_TAG, "CallManager: handleMessage (EVENT_MMI_COMPLETE)");
mMmiCompleteRegistrants.notifyRegistrants((AsyncResult) msg.obj);
break;
case EVENT_ECM_TIMER_RESET:
diff --git a/src/java/com/android/internal/telephony/CallTracker.java b/src/java/com/android/internal/telephony/CallTracker.java
index ad64a4a..31c5e42 100644
--- a/src/java/com/android/internal/telephony/CallTracker.java
+++ b/src/java/com/android/internal/telephony/CallTracker.java
@@ -16,10 +16,13 @@
package com.android.internal.telephony;
+import android.content.Context;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.SystemProperties;
+import android.telephony.CarrierConfigManager;
import android.text.TextUtils;
import java.io.FileDescriptor;
@@ -203,8 +206,20 @@
if (dialNumber == null) {
return dialNumber;
}
- String[] convertMaps = phone.getContext().getResources().getStringArray(
- com.android.internal.R.array.dial_string_replace);
+ String[] convertMaps = null;
+ CarrierConfigManager configManager = (CarrierConfigManager)
+ phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ PersistableBundle bundle = configManager.getConfig();
+ if (bundle != null) {
+ convertMaps =
+ bundle.getStringArray(CarrierConfigManager.KEY_DIAL_STRING_REPLACE_STRING_ARRAY);
+ }
+ if (convertMaps == null) {
+ // By default no replacement is necessary
+ log("convertNumberIfNecessary convertMaps is null");
+ return dialNumber;
+ }
+
log("convertNumberIfNecessary Roaming"
+ " convertMaps.length " + convertMaps.length
+ " dialNumber.length() " + dialNumber.length());
@@ -214,39 +229,30 @@
}
String[] entry;
- String[] tmpArray;
String outNumber = "";
- boolean needConvert = false;
for(String convertMap : convertMaps) {
log("convertNumberIfNecessary: " + convertMap);
+ // entry format is "dialStringToReplace:dialStringReplacement"
entry = convertMap.split(":");
- if (entry.length > 1) {
- tmpArray = entry[1].split(",");
- if (!TextUtils.isEmpty(entry[0]) && dialNumber.equals(entry[0])) {
- if (tmpArray.length >= 2 && !TextUtils.isEmpty(tmpArray[1])) {
- if (compareGid1(phone, tmpArray[1])) {
- needConvert = true;
- }
- } else if (outNumber.isEmpty()) {
- needConvert = true;
- }
-
- if (needConvert) {
- if(!TextUtils.isEmpty(tmpArray[0]) && tmpArray[0].endsWith("MDN")) {
- String mdn = phone.getLine1Number();
- if (!TextUtils.isEmpty(mdn) ) {
- if (mdn.startsWith("+")) {
- outNumber = mdn;
- } else {
- outNumber = tmpArray[0].substring(0, tmpArray[0].length() -3)
- + mdn;
- }
+ if (entry != null && entry.length > 1) {
+ String dsToReplace = entry[0];
+ String dsReplacement = entry[1];
+ if (!TextUtils.isEmpty(dsToReplace) && dialNumber.equals(dsToReplace)) {
+ // Needs to be converted
+ if (!TextUtils.isEmpty(dsReplacement) && dsReplacement.endsWith("MDN")) {
+ String mdn = phone.getLine1Number();
+ if (!TextUtils.isEmpty(mdn)) {
+ if (mdn.startsWith("+")) {
+ outNumber = mdn;
+ } else {
+ outNumber = dsReplacement.substring(0, dsReplacement.length() -3)
+ + mdn;
}
- } else {
- outNumber = tmpArray[0];
}
- needConvert = false;
+ } else {
+ outNumber = dsReplacement;
}
+ break;
}
}
}
diff --git a/src/java/com/android/internal/telephony/CarrierActionAgent.java b/src/java/com/android/internal/telephony/CarrierActionAgent.java
new file mode 100644
index 0000000..2b91720
--- /dev/null
+++ b/src/java/com/android/internal/telephony/CarrierActionAgent.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2016 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.database.ContentObserver;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Registrant;
+import android.os.RegistrantList;
+import android.provider.Settings;
+import android.telephony.Rlog;
+import android.util.LocalLog;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Carrier Action Agent(CAA) paired with
+ * {@link com.android.internal.telephony.CarrierSignalAgent CarrierSignalAgent},
+ * serves as an agent to dispatch carrier actions from carrier apps to different telephony modules,
+ * {@link android.telephony.TelephonyManager#carrierActionSetRadioEnabled(int, boolean)
+ * carrierActionSetRadioEnabled} for example.
+ *
+ * CAA supports dynamic registration where different telephony modules could listen for a specific
+ * carrier action event and implement their own handler. CCA will dispatch the event to all
+ * interested parties and maintain the received action states internally for future inspection.
+ * Each CarrierActionAgent is associated with a phone object.
+ */
+public class CarrierActionAgent extends Handler {
+ private static final String LOG_TAG = "CarrierActionAgent";
+ private static final boolean DBG = true;
+ private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE);
+
+ /** A list of carrier actions */
+ public static final int CARRIER_ACTION_SET_METERED_APNS_ENABLED = 0;
+ public static final int CARRIER_ACTION_SET_RADIO_ENABLED = 1;
+ public static final int CARRIER_ACTION_RESET = 2;
+
+ /** Member variables */
+ private final Phone mPhone;
+ /** registrant list per carrier action */
+ private RegistrantList mMeteredApnEnableRegistrants = new RegistrantList();
+ private RegistrantList mRadioEnableRegistrants = new RegistrantList();
+ /** local log for carrier actions */
+ private LocalLog mMeteredApnEnabledLog = new LocalLog(10);
+ private LocalLog mRadioEnabledLog = new LocalLog(10);
+ /** carrier actions, true by default */
+ private Boolean mCarrierActionOnMeteredApnEnabled = true;
+ private Boolean mCarrierActionOnRadioEnabled = true;
+ /** content observer for APM change */
+ private final SettingsObserver mSettingsObserver;
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+ if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){
+ if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
+ // ignore rebroadcast since carrier apps are direct boot aware.
+ return;
+ }
+ if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState) ||
+ IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) {
+ sendEmptyMessage(CARRIER_ACTION_RESET);
+ }
+ }
+ }
+ };
+
+ private class SettingsObserver extends ContentObserver {
+ SettingsObserver() {
+ super(null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ if (Settings.Global.getInt(mPhone.getContext().getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0) {
+ sendEmptyMessage(CARRIER_ACTION_RESET);
+ }
+ }
+ }
+
+ /** Constructor */
+ public CarrierActionAgent(Phone phone) {
+ mPhone = phone;
+ mPhone.getContext().registerReceiver(mReceiver,
+ new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
+ mSettingsObserver = new SettingsObserver();
+ mPhone.getContext().getContentResolver().registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
+ false, mSettingsObserver);
+ if (DBG) log("Creating CarrierActionAgent");
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
+ mCarrierActionOnMeteredApnEnabled = (boolean) msg.obj;
+ log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled);
+ mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: "
+ + mCarrierActionOnMeteredApnEnabled);
+ mMeteredApnEnableRegistrants.notifyRegistrants(
+ new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null));
+ break;
+ case CARRIER_ACTION_SET_RADIO_ENABLED:
+ mCarrierActionOnRadioEnabled = (boolean) msg.obj;
+ log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
+ mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
+ mRadioEnableRegistrants.notifyRegistrants(
+ new AsyncResult(null, mCarrierActionOnRadioEnabled, null));
+ break;
+ case CARRIER_ACTION_RESET:
+ log("CARRIER_ACTION_RESET");
+ carrierActionSetMeteredApnsEnabled(true);
+ carrierActionSetRadioEnabled(true);
+ // notify configured carrier apps for reset
+ mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(
+ new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET));
+ break;
+ default:
+ loge("Unknown carrier action: " + msg.what);
+ }
+ }
+
+ /**
+ * Return current carrier action values
+ */
+ public Object getCarrierActionValue(int action) {
+ Object val = getCarrierAction(action);
+ if (val == null) {
+ throw new IllegalArgumentException("invalid carrier action: " + action);
+ }
+ return val;
+ }
+
+ /**
+ * Action set from carrier app to enable/disable radio
+ */
+ public void carrierActionSetRadioEnabled(boolean enabled) {
+ sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled));
+ }
+
+ /**
+ * Action set from carrier app to enable/disable metered APNs
+ */
+ public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
+ sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled));
+ }
+
+ private RegistrantList getRegistrantsFromAction(int action) {
+ switch (action) {
+ case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
+ return mMeteredApnEnableRegistrants;
+ case CARRIER_ACTION_SET_RADIO_ENABLED:
+ return mRadioEnableRegistrants;
+ default:
+ loge("Unsupported action: " + action);
+ return null;
+ }
+ }
+
+ private Object getCarrierAction(int action) {
+ switch (action) {
+ case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
+ return mCarrierActionOnMeteredApnEnabled;
+ case CARRIER_ACTION_SET_RADIO_ENABLED:
+ return mCarrierActionOnRadioEnabled;
+ default:
+ loge("Unsupported action: " + action);
+ return null;
+ }
+ }
+
+ /**
+ * Register with CAA for a specific event.
+ * @param action which carrier action registrant is interested in
+ * @param notifyNow if carrier action has once set, notify registrant right after
+ * registering, so that registrants will get the latest carrier action.
+ */
+ public void registerForCarrierAction(int action, Handler h, int what, Object obj,
+ boolean notifyNow) {
+ Object carrierAction = getCarrierAction(action);
+ if (carrierAction == null) {
+ throw new IllegalArgumentException("invalid carrier action: " + action);
+ }
+ RegistrantList list = getRegistrantsFromAction(action);
+ Registrant r = new Registrant(h, what, obj);
+ list.add(r);
+ if (notifyNow) {
+ r.notifyRegistrant(new AsyncResult(null, carrierAction, null));
+ }
+ }
+
+ /**
+ * Unregister with CAA for a specific event. Callers will no longer be notified upon such event.
+ * @param action which carrier action caller is no longer interested in
+ */
+ public void unregisterForCarrierAction(Handler h, int action) {
+ RegistrantList list = getRegistrantsFromAction(action);
+ if (list == null) {
+ throw new IllegalArgumentException("invalid carrier action: " + action);
+ }
+ list.remove(h);
+ }
+
+ @VisibleForTesting
+ public ContentObserver getContentObserver() {
+ return mSettingsObserver;
+ }
+
+ private void log(String s) {
+ Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
+ }
+
+ private void loge(String s) {
+ Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
+ }
+
+ private void logv(String s) {
+ Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ pw.println(" mCarrierActionOnMeteredApnsEnabled Log:");
+ ipw.increaseIndent();
+ mMeteredApnEnabledLog.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+
+ pw.println(" mCarrierActionOnRadioEnabled Log:");
+ ipw.increaseIndent();
+ mRadioEnabledLog.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ }
+}
diff --git a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
index 3123ccb..ab010cc 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceBindHelper.java
@@ -28,6 +28,8 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.os.Process;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.service.carrier.CarrierService;
import android.telephony.SubscriptionManager;
@@ -48,6 +50,12 @@
public class CarrierServiceBindHelper {
private static final String LOG_TAG = "CarrierSvcBindHelper";
+ /**
+ * How long to linger a binding after an app loses carrier privileges, as long as no new
+ * binding comes in to take its place.
+ */
+ private static final int UNBIND_DELAY_MILLIS = 30 * 1000; // 30 seconds
+
private Context mContext;
private AppBinding[] mBindings;
private String[] mLastSimState;
@@ -70,6 +78,7 @@
};
private static final int EVENT_REBIND = 0;
+ private static final int EVENT_PERFORM_IMMEDIATE_UNBIND = 1;
private Handler mHandler = new Handler() {
@Override
@@ -83,6 +92,10 @@
log("Rebinding if necessary for phoneId: " + binding.getPhoneId());
binding.rebind();
break;
+ case EVENT_PERFORM_IMMEDIATE_UNBIND:
+ binding = (AppBinding) msg.obj;
+ binding.performImmediateUnbind();
+ break;
}
}
};
@@ -129,6 +142,7 @@
private long lastUnbindMillis;
private String carrierPackage;
private String carrierServiceClass;
+ private long mUnbindScheduledUptimeMillis = -1;
public AppBinding(int phoneId) {
this.phoneId = phoneId;
@@ -158,15 +172,16 @@
if (carrierPackageNames == null || carrierPackageNames.size() <= 0) {
log("No carrier app for: " + phoneId);
- unbind();
+ // Unbind after a delay in case this is a temporary blip in carrier privileges.
+ unbind(false /* immediate */);
return;
}
log("Found carrier app: " + carrierPackageNames);
String candidateCarrierPackage = carrierPackageNames.get(0);
- // If we are binding to a different package, unbind from the current one.
+ // If we are binding to a different package, unbind immediately from the current one.
if (!TextUtils.equals(carrierPackage, candidateCarrierPackage)) {
- unbind();
+ unbind(true /* immediate */);
}
// Look up the carrier service
@@ -187,15 +202,17 @@
if (metadata == null ||
!metadata.getBoolean("android.service.carrier.LONG_LIVED_BINDING", false)) {
log("Carrier app does not want a long lived binding");
- unbind();
+ unbind(true /* immediate */);
return;
}
if (!TextUtils.equals(carrierServiceClass, candidateServiceClass)) {
- // Unbind if the carrier service component has changed.
- unbind();
+ // Unbind immediately if the carrier service component has changed.
+ unbind(true /* immediate */);
} else if (connection != null) {
- // Component is unchanged and connection is up - do nothing.
+ // Component is unchanged and connection is up - do nothing, but cancel any
+ // scheduled unbinds.
+ cancelScheduledUnbind();
return;
}
@@ -212,8 +229,9 @@
String error;
try {
- if (mContext.bindService(carrierService, connection, Context.BIND_AUTO_CREATE |
- Context.BIND_FOREGROUND_SERVICE)) {
+ if (mContext.bindServiceAsUser(carrierService, connection,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ mHandler, Process.myUserHandle())) {
return;
}
@@ -224,19 +242,46 @@
log("Unable to bind to " + carrierPackage + " for phone " + phoneId +
". Error: " + error);
- unbind();
+ unbind(true /* immediate */);
}
- void unbind() {
+ /**
+ * Release the binding.
+ *
+ * @param immediate whether the binding should be released immediately or after a short
+ * delay. This should be true unless the reason for the unbind is that no
+ * app has carrier privileges, in which case it is useful to delay
+ * unbinding in case this is a temporary SIM blip.
+ */
+ void unbind(boolean immediate) {
if (connection == null) {
+ // Already fully unbound.
return;
}
+ // Only let the binding linger if a delayed unbind is requested *and* the connection is
+ // currently active. If the connection is down, unbind immediately as the app is likely
+ // not running anyway and it may be a permanent disconnection (e.g. the app was
+ // disabled).
+ if (immediate || !connection.connected) {
+ cancelScheduledUnbind();
+ performImmediateUnbind();
+ } else if (mUnbindScheduledUptimeMillis == -1) {
+ long currentUptimeMillis = SystemClock.uptimeMillis();
+ mUnbindScheduledUptimeMillis = currentUptimeMillis + UNBIND_DELAY_MILLIS;
+ log("Scheduling unbind in " + UNBIND_DELAY_MILLIS + " millis");
+ mHandler.sendMessageAtTime(
+ mHandler.obtainMessage(EVENT_PERFORM_IMMEDIATE_UNBIND, this),
+ mUnbindScheduledUptimeMillis);
+ }
+ }
+
+ private void performImmediateUnbind() {
// Log debug information
unbindCount++;
lastUnbindMillis = System.currentTimeMillis();
- // Clear package state now that no binding is present.
+ // Clear package state now that no binding is desired.
carrierPackage = null;
carrierServiceClass = null;
@@ -244,6 +289,12 @@
log("Unbinding from carrier app");
mContext.unbindService(connection);
connection = null;
+ mUnbindScheduledUptimeMillis = -1;
+ }
+
+ private void cancelScheduledUnbind() {
+ mHandler.removeMessages(EVENT_PERFORM_IMMEDIATE_UNBIND);
+ mUnbindScheduledUptimeMillis = -1;
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -253,6 +304,7 @@
pw.println(" lastBindStartMillis: " + lastBindStartMillis);
pw.println(" unbindCount: " + unbindCount);
pw.println(" lastUnbindMillis: " + lastUnbindMillis);
+ pw.println(" mUnbindScheduledUptimeMillis: " + mUnbindScheduledUptimeMillis);
pw.println();
}
}
@@ -322,7 +374,7 @@
}
if (appBindingPackage == null || isBindingForPackage) {
if (forceUnbind) {
- appBinding.unbind();
+ appBinding.unbind(true /* immediate */);
}
appBinding.rebind();
}
diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
index 735bfe2..9865d1b 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
@@ -30,6 +30,8 @@
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
+import com.android.internal.telephony.util.NotificationChannelController;
+
/**
* This contains Carrier specific logic based on the states/events
* managed in ServiceStateTracker.
@@ -174,6 +176,7 @@
.setStyle(new Notification.BigTextStyle().bigText(details))
.setContentText(details)
.setContentIntent(settingsIntent)
+ .setChannel(NotificationChannelController.CHANNEL_ID_ALERT)
.build();
notificationManager.notify(NOTIFICATION_ID, mNotification);
diff --git a/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java b/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java
new file mode 100644
index 0000000..f3bc1fd
--- /dev/null
+++ b/src/java/com/android/internal/telephony/CarrierServicesSmsFilter.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (C) 2017 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.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.service.carrier.CarrierMessagingService;
+import android.service.carrier.ICarrierMessagingCallback;
+import android.service.carrier.ICarrierMessagingService;
+import android.service.carrier.MessagePdu;
+import android.telephony.CarrierMessagingServiceManager;
+import android.telephony.Rlog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.uicc.UiccCard;
+import com.android.internal.telephony.uicc.UiccController;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * Filters incoming SMS with carrier services.
+ * <p> A new instance must be created for filtering each message.
+ */
+public class CarrierServicesSmsFilter {
+ protected static final boolean DBG = true;
+
+ private final Context mContext;
+ private final Phone mPhone;
+ private final byte[][] mPdus;
+ private final int mDestPort;
+ private final String mPduFormat;
+ private final CarrierServicesSmsFilterCallbackInterface mCarrierServicesSmsFilterCallback;
+ private final String mLogTag;
+
+ @VisibleForTesting
+ public CarrierServicesSmsFilter(
+ Context context,
+ Phone phone,
+ byte[][] pdus,
+ int destPort,
+ String pduFormat,
+ CarrierServicesSmsFilterCallbackInterface carrierServicesSmsFilterCallback,
+ String logTag) {
+ mContext = context;
+ mPhone = phone;
+ mPdus = pdus;
+ mDestPort = destPort;
+ mPduFormat = pduFormat;
+ mCarrierServicesSmsFilterCallback = carrierServicesSmsFilterCallback;
+ mLogTag = logTag;
+ }
+
+ /**
+ * @return {@code true} if the SMS was handled by carrier services.
+ */
+ @VisibleForTesting
+ public boolean filter() {
+ Optional<String> carrierAppForFiltering = getCarrierAppPackageForFiltering();
+ List<String> smsFilterPackages = new ArrayList<>();
+ if (carrierAppForFiltering.isPresent()) {
+ smsFilterPackages.add(carrierAppForFiltering.get());
+ }
+ String carrierImsPackage = CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
+ new Intent(CarrierMessagingService.SERVICE_INTERFACE));
+ if (carrierImsPackage != null) {
+ smsFilterPackages.add(carrierImsPackage);
+ }
+ FilterAggregator filterAggregator = new FilterAggregator(smsFilterPackages.size());
+ for (String smsFilterPackage : smsFilterPackages) {
+ filterWithPackage(smsFilterPackage, filterAggregator);
+ }
+ boolean handled = smsFilterPackages.size() > 0;
+ return handled;
+ }
+
+ private Optional<String> getCarrierAppPackageForFiltering() {
+ List<String> carrierPackages = null;
+ UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
+ if (card != null) {
+ carrierPackages = card.getCarrierPackageNamesForIntent(
+ mContext.getPackageManager(),
+ new Intent(CarrierMessagingService.SERVICE_INTERFACE));
+ } else {
+ Rlog.e(mLogTag, "UiccCard not initialized.");
+ }
+ if (carrierPackages != null && carrierPackages.size() == 1) {
+ log("Found carrier package.");
+ return Optional.of(carrierPackages.get(0));
+ }
+
+ // It is possible that carrier app is not present as a CarrierPackage, but instead as a
+ // system app
+ List<String> systemPackages =
+ getSystemAppForIntent(new Intent(CarrierMessagingService.SERVICE_INTERFACE));
+
+ if (systemPackages != null && systemPackages.size() == 1) {
+ log("Found system package.");
+ return Optional.of(systemPackages.get(0));
+ }
+ logv("Unable to find carrier package: " + carrierPackages
+ + ", nor systemPackages: " + systemPackages);
+ return Optional.empty();
+ }
+
+ private void filterWithPackage(String packageName, FilterAggregator filterAggregator) {
+ CarrierSmsFilter smsFilter = new CarrierSmsFilter(mPdus, mDestPort, mPduFormat);
+ CarrierSmsFilterCallback smsFilterCallback =
+ new CarrierSmsFilterCallback(filterAggregator, smsFilter);
+ smsFilter.filterSms(packageName, smsFilterCallback);
+ }
+
+ private List<String> getSystemAppForIntent(Intent intent) {
+ List<String> packages = new ArrayList<String>();
+ PackageManager packageManager = mContext.getPackageManager();
+ List<ResolveInfo> receivers = packageManager.queryIntentServices(intent, 0);
+ String carrierFilterSmsPerm = "android.permission.CARRIER_FILTER_SMS";
+
+ for (ResolveInfo info : receivers) {
+ if (info.serviceInfo == null) {
+ loge("Can't get service information from " + info);
+ continue;
+ }
+ String packageName = info.serviceInfo.packageName;
+ if (packageManager.checkPermission(carrierFilterSmsPerm, packageName)
+ == packageManager.PERMISSION_GRANTED) {
+ packages.add(packageName);
+ if (DBG) log("getSystemAppForIntent: added package " + packageName);
+ }
+ }
+ return packages;
+ }
+
+ private void log(String message) {
+ Rlog.d(mLogTag, message);
+ }
+
+ private void loge(String message) {
+ Rlog.e(mLogTag, message);
+ }
+
+ private void logv(String message) {
+ Rlog.e(mLogTag, message);
+ }
+
+ /**
+ * Result of filtering SMS is returned in this callback.
+ */
+ @VisibleForTesting
+ public interface CarrierServicesSmsFilterCallbackInterface {
+ void onFilterComplete(int result);
+ }
+
+ /**
+ * Asynchronously binds to the carrier messaging service, and filters out the message if
+ * instructed to do so by the carrier messaging service. A new instance must be used for every
+ * message.
+ */
+ private final class CarrierSmsFilter extends CarrierMessagingServiceManager {
+ private final byte[][] mPdus;
+ private final int mDestPort;
+ private final String mSmsFormat;
+ // Instantiated in filterSms.
+ private volatile CarrierSmsFilterCallback mSmsFilterCallback;
+
+ CarrierSmsFilter(byte[][] pdus, int destPort, String smsFormat) {
+ mPdus = pdus;
+ mDestPort = destPort;
+ mSmsFormat = smsFormat;
+ }
+
+ /**
+ * Attempts to bind to a {@link ICarrierMessagingService}. Filtering is initiated
+ * asynchronously once the service is ready using {@link #onServiceReady}.
+ */
+ void filterSms(String carrierPackageName, CarrierSmsFilterCallback smsFilterCallback) {
+ mSmsFilterCallback = smsFilterCallback;
+ if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
+ loge("bindService() for carrier messaging service failed");
+ smsFilterCallback.onFilterComplete(CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
+ } else {
+ logv("bindService() for carrier messaging service succeeded");
+ }
+ }
+
+ /**
+ * Invokes the {@code carrierMessagingService} to filter messages. The filtering result is
+ * delivered to {@code smsFilterCallback}.
+ */
+ @Override
+ protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
+ try {
+ carrierMessagingService.filterSms(
+ new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort,
+ mPhone.getSubId(), mSmsFilterCallback);
+ } catch (RemoteException e) {
+ loge("Exception filtering the SMS: " + e);
+ mSmsFilterCallback.onFilterComplete(
+ CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
+ }
+ }
+ }
+
+ /**
+ * A callback used to notify the platform of the carrier messaging app filtering result. Once
+ * the result is ready, the carrier messaging service connection is disposed.
+ */
+ private final class CarrierSmsFilterCallback extends ICarrierMessagingCallback.Stub {
+ private final FilterAggregator mFilterAggregator;
+ private final CarrierMessagingServiceManager mCarrierMessagingServiceManager;
+
+ CarrierSmsFilterCallback(FilterAggregator filterAggregator,
+ CarrierMessagingServiceManager carrierMessagingServiceManager) {
+ mFilterAggregator = filterAggregator;
+ mCarrierMessagingServiceManager = carrierMessagingServiceManager;
+ }
+
+ /**
+ * This method should be called only once.
+ */
+ @Override
+ public void onFilterComplete(int result) {
+ mCarrierMessagingServiceManager.disposeConnection(mContext);
+ mFilterAggregator.onFilterComplete(result);
+ }
+
+ @Override
+ public void onSendSmsComplete(int result, int messageRef) {
+ loge("Unexpected onSendSmsComplete call with result: " + result);
+ }
+
+ @Override
+ public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
+ loge("Unexpected onSendMultipartSmsComplete call with result: " + result);
+ }
+
+ @Override
+ public void onSendMmsComplete(int result, byte[] sendConfPdu) {
+ loge("Unexpected onSendMmsComplete call with result: " + result);
+ }
+
+ @Override
+ public void onDownloadMmsComplete(int result) {
+ loge("Unexpected onDownloadMmsComplete call with result: " + result);
+ }
+ }
+
+ private final class FilterAggregator {
+ private final Object mFilterLock = new Object();
+ private int mNumPendingFilters;
+ private int mFilterResult;
+
+ FilterAggregator(int numFilters) {
+ mNumPendingFilters = numFilters;
+ mFilterResult = CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT;
+ }
+
+ void onFilterComplete(int result) {
+ synchronized (mFilterLock) {
+ mNumPendingFilters--;
+ combine(result);
+ if (mNumPendingFilters == 0) {
+ // Calling identity was the CarrierMessagingService in this callback, change it
+ // back to ours.
+ long token = Binder.clearCallingIdentity();
+ try {
+ mCarrierServicesSmsFilterCallback.onFilterComplete(mFilterResult);
+ } finally {
+ // return back to the CarrierMessagingService, restore the calling identity.
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
+ }
+
+ private void combine(int result) {
+ mFilterResult = mFilterResult | result;
+ }
+ }
+}
diff --git a/src/java/com/android/internal/telephony/CarrierSignalAgent.java b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
index 19a508c..4d6d464 100644
--- a/src/java/com/android/internal/telephony/CarrierSignalAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
@@ -16,144 +16,262 @@
package com.android.internal.telephony;
import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
+import android.text.TextUtils;
+import android.util.LocalLog;
+import android.util.Log;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
+import java.util.Set;
+
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY;
/**
* This class act as an CarrierSignalling Agent.
- * it load registered carrier signalling receivers from Carrier Config and cache the result to avoid
+ * it load registered carrier signalling receivers from carrier config, cache the result to avoid
* repeated polling and send the intent to the interested receivers.
- * each CarrierSignalAgent is associated with a phone object.
+ * Each CarrierSignalAgent is associated with a phone object.
*/
public class CarrierSignalAgent {
- private static final String LOG_TAG = "CarrierSignalAgent";
+ private static final String LOG_TAG = CarrierSignalAgent.class.getSimpleName();
private static final boolean DBG = true;
+ private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE);
+ private static final boolean WAKE = true;
+ private static final boolean NO_WAKE = false;
+
+ /** delimiters for parsing config of the form: pakName./receiverName : signal1, signal2,..*/
+ private static final String COMPONENT_NAME_DELIMITER = "\\s*:\\s*";
+ private static final String CARRIER_SIGNAL_DELIMITER = "\\s*,\\s*";
/** Member variables */
private final Phone mPhone;
+
/**
- * This is a map of intent action -> string array of carrier signal receiver names which are
- * interested in this intent action
+ * This is a map of intent action -> array list of component name of statically registered
+ * carrier signal receivers(wakeup receivers).
+ * Those intents are declared in the Manifest files, aiming to wakeup broadcast receivers.
+ * Carrier apps should be careful when configuring the wake signal list to avoid unnecessary
+ * wakeup.
+ * @see CarrierConfigManager#KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY
*/
- private final HashMap<String, String[]> mCachedCarrierSignalReceiverNames =
- new HashMap<>();
+ private final Map<String, List<ComponentName>> mCachedWakeSignalConfigs = new HashMap<>();
+
/**
- * This is a map of intent action -> carrier config key of signal receiver names which are
- * interested in this intent action
+ * This is a map of intent action -> array list of component name of dynamically registered
+ * carrier signal receivers(non-wakeup receivers). Those intents will not wake up the apps.
+ * Note Carrier apps should avoid configuring no wake signals in there Manifest files.
+ * @see CarrierConfigManager#KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY
*/
- private final Map<String, String> mIntentToCarrierConfigKeyMap =
- new HashMap<String, String>() {{
- put(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED,
- CarrierConfigManager.KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY);
- put(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE,
- CarrierConfigManager.KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY);
- put(TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
- CarrierConfigManager.KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY);
- }};
+ private final Map<String, List<ComponentName>> mCachedNoWakeSignalConfigs = new HashMap<>();
+
+ /**
+ * This is a list of supported signals from CarrierSignalAgent
+ */
+ private final Set<String> mCarrierSignalList = new HashSet<>(Arrays.asList(
+ TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE,
+ TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED,
+ TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
+ TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET));
+
+ private final LocalLog mErrorLocalLog = new LocalLog(20);
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (DBG) log("CarrierSignalAgent receiver action: " + action);
+ if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
+ // notify carrier apps before cache get purged
+ if (mPhone.getIccCard() != null
+ && IccCardConstants.State.ABSENT == mPhone.getIccCard().getState()) {
+ notifyCarrierSignalReceivers(
+ new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET));
+ }
+ loadCarrierConfig();
+ }
+ }
+ };
/** Constructor */
public CarrierSignalAgent(Phone phone) {
mPhone = phone;
+ loadCarrierConfig();
+ // reload configurations on CARRIER_CONFIG_CHANGED
+ mPhone.getContext().registerReceiver(mReceiver,
+ new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
}
/**
- * Read carrier signalling receiver name from CarrierConfig based on the intent type
- * @return array of receiver Name: the package (a String) name / the class (a String) name
+ * load carrier config and cached the results into a hashMap action -> array list of components.
*/
- private String[] getCarrierSignalReceiverName(String intentAction) {
- String receiverType = mIntentToCarrierConfigKeyMap.get(intentAction);
- if(receiverType == null) {
- return null;
+ private void loadCarrierConfig() {
+ CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
+ .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ PersistableBundle b = null;
+ if (configManager != null) {
+ b = configManager.getConfig();
}
- String[] receiverNames = mCachedCarrierSignalReceiverNames.get(intentAction);
- // In case of cache miss, we need to look up/load from carrier config.
- if (!mCachedCarrierSignalReceiverNames.containsKey(intentAction)) {
- CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
- .getSystemService(Context.CARRIER_CONFIG_SERVICE);
- PersistableBundle b = null;
- if (configManager != null) {
- b = configManager.getConfig();
+ if (b != null) {
+ synchronized (mCachedWakeSignalConfigs) {
+ mCachedWakeSignalConfigs.clear();
+ log("Loading carrier config: " + KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY);
+ parseAndCache(b.getStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY),
+ mCachedWakeSignalConfigs);
}
- if (b != null) {
- receiverNames = b.getStringArray(receiverType);
- if(receiverNames!=null) {
- for(String name: receiverNames) {
- Rlog.d("loadCarrierSignalReceiverNames: ", name);
+
+ synchronized (mCachedNoWakeSignalConfigs) {
+ mCachedNoWakeSignalConfigs.clear();
+ log("Loading carrier config: "
+ + KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY);
+ parseAndCache(b.getStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY),
+ mCachedNoWakeSignalConfigs);
+ }
+ }
+ }
+
+ /**
+ * Parse each config with the form {pakName./receiverName : signal1, signal2,.} and cached the
+ * result internally to avoid repeated polling
+ * @see #CARRIER_SIGNAL_DELIMITER
+ * @see #COMPONENT_NAME_DELIMITER
+ * @param configs raw information from carrier config
+ */
+ private void parseAndCache(String[] configs,
+ Map<String, List<ComponentName>> cachedConfigs) {
+ if (!ArrayUtils.isEmpty(configs)) {
+ for (String config : configs) {
+ if (!TextUtils.isEmpty(config)) {
+ String[] splitStr = config.trim().split(COMPONENT_NAME_DELIMITER, 2);
+ if (splitStr.length == 2) {
+ ComponentName componentName = ComponentName
+ .unflattenFromString(splitStr[0]);
+ if (componentName == null) {
+ loge("Invalid component name: " + splitStr[0]);
+ continue;
+ }
+ String[] signals = splitStr[1].split(CARRIER_SIGNAL_DELIMITER);
+ for (String s : signals) {
+ if (!mCarrierSignalList.contains(s)) {
+ loge("Invalid signal name: " + s);
+ continue;
+ }
+ List<ComponentName> componentList = cachedConfigs.get(s);
+ if (componentList == null) {
+ componentList = new ArrayList<>();
+ cachedConfigs.put(s, componentList);
+ }
+ componentList.add(componentName);
+ if (VDBG) {
+ logv("Add config " + "{signal: " + s
+ + " componentName: " + componentName + "}");
+ }
+ }
+ } else {
+ loge("invalid config format: " + config);
}
}
}
- mCachedCarrierSignalReceiverNames.put(intentAction, receiverNames);
}
- return receiverNames;
}
/**
- * Check if there are registered carrier broadcast receivers to handle any registered intents.
+ * Check if there are registered carrier broadcast receivers to handle the passing intent
*/
- public boolean hasRegisteredCarrierSignalReceivers() {
- for(String intent : mIntentToCarrierConfigKeyMap.keySet()) {
- if(!ArrayUtils.isEmpty(getCarrierSignalReceiverName(intent))) {
- return true;
- }
- }
- return false;
+ public boolean hasRegisteredReceivers(String action) {
+ return mCachedWakeSignalConfigs.containsKey(action)
+ || mCachedNoWakeSignalConfigs.containsKey(action);
}
- public boolean notifyCarrierSignalReceivers(Intent intent) {
- // Read a list of broadcast receivers from carrier config manager
- // which are interested on certain intent type
- String[] receiverName = getCarrierSignalReceiverName(intent.getAction());
- if (receiverName == null) {
- loge("Carrier receiver name is null");
- return false;
- }
+ /**
+ * Broadcast the intents explicitly.
+ * Some sanity check will be applied before broadcasting.
+ * - for non-wakeup(runtime) receivers, make sure the intent is not declared in their manifests
+ * and apply FLAG_EXCLUDE_STOPPED_PACKAGES to avoid wake-up
+ * - for wakeup(manifest) receivers, make sure there are matched receivers with registered
+ * intents.
+ *
+ * @param intent intent which signals carrier apps
+ * @param receivers a list of component name for broadcast receivers.
+ * Those receivers could either be statically declared in Manifest or
+ * registered during run-time.
+ * @param wakeup true indicate wakeup receivers otherwise non-wakeup receivers
+ */
+ private void broadcast(Intent intent, List<ComponentName> receivers, boolean wakeup) {
final PackageManager packageManager = mPhone.getContext().getPackageManager();
- boolean ret = false;
+ for (ComponentName name : receivers) {
+ Intent signal = new Intent(intent);
+ signal.setComponent(name);
- for(String name : receiverName) {
- ComponentName componentName = ComponentName.unflattenFromString(name);
- if (componentName == null) {
- loge("Carrier receiver name could not be parsed");
- return false;
- }
- intent.setComponent(componentName);
- // Check if broadcast receiver is available
- if (packageManager.queryBroadcastReceivers(intent,
+ if (wakeup && packageManager.queryBroadcastReceivers(signal,
PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
- loge("Carrier signal receiver is configured, but not available: " + name);
- break;
+ loge("Carrier signal receivers are configured but unavailable: "
+ + signal.getComponent());
+ return;
+ }
+ if (!wakeup && !packageManager.queryBroadcastReceivers(signal,
+ PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
+ loge("Runtime signals shouldn't be configured in Manifest: "
+ + signal.getComponent());
+ return;
}
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mPhone.getSubId());
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ signal.putExtra(PhoneConstants.SUBSCRIPTION_KEY, mPhone.getSubId());
+ signal.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ if (!wakeup) signal.setFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
try {
- mPhone.getContext().sendBroadcast(intent);
- if (DBG) log("send Intent to carrier signal receiver with action: " +
- intent.getAction());
- ret = true;
+ mPhone.getContext().sendBroadcast(signal);
+ if (DBG) {
+ log("Sending signal " + signal.getAction() + ((signal.getComponent() != null)
+ ? " to the carrier signal receiver: " + signal.getComponent() : ""));
+ }
} catch (ActivityNotFoundException e) {
- loge("sendBroadcast failed: " + e);
+ loge("Send broadcast failed: " + e);
+ }
+ }
+ }
+
+ /**
+ * Match the intent against cached tables to find a list of registered carrier signal
+ * receivers and broadcast the intent.
+ * @param intent broadcasting intent, it could belong to wakeup, non-wakeup signal list or both
+ *
+ */
+ public void notifyCarrierSignalReceivers(Intent intent) {
+ List<ComponentName> receiverList;
+
+ synchronized (mCachedWakeSignalConfigs) {
+ receiverList = mCachedWakeSignalConfigs.get(intent.getAction());
+ if (!ArrayUtils.isEmpty(receiverList)) {
+ broadcast(intent, receiverList, WAKE);
}
}
- return ret;
- }
-
- /* Clear cached receiver names */
- public void reset() {
- mCachedCarrierSignalReceiverNames.clear();
+ synchronized (mCachedNoWakeSignalConfigs) {
+ receiverList = mCachedNoWakeSignalConfigs.get(intent.getAction());
+ if (!ArrayUtils.isEmpty(receiverList)) {
+ broadcast(intent, receiverList, NO_WAKE);
+ }
+ }
}
private void log(String s) {
@@ -161,6 +279,33 @@
}
private void loge(String s) {
+ mErrorLocalLog.log(s);
Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
}
+
+ private void logv(String s) {
+ Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ pw.println("mCachedWakeSignalConfigs:");
+ ipw.increaseIndent();
+ for (Map.Entry<String, List<ComponentName>> entry : mCachedWakeSignalConfigs.entrySet()) {
+ pw.println("signal: " + entry.getKey() + " componentName list: " + entry.getValue());
+ }
+ ipw.decreaseIndent();
+
+ pw.println("mCachedNoWakeSignalConfigs:");
+ ipw.increaseIndent();
+ for (Map.Entry<String, List<ComponentName>> entry : mCachedNoWakeSignalConfigs.entrySet()) {
+ pw.println("signal: " + entry.getKey() + " componentName list: " + entry.getValue());
+ }
+ ipw.decreaseIndent();
+
+ pw.println("error log:");
+ ipw.increaseIndent();
+ mErrorLocalLog.dump(fd, pw, args);
+ ipw.decreaseIndent();
+ }
}
diff --git a/src/java/com/android/internal/telephony/CarrierSmsUtils.java b/src/java/com/android/internal/telephony/CarrierSmsUtils.java
new file mode 100644
index 0000000..a64aea7
--- /dev/null
+++ b/src/java/com/android/internal/telephony/CarrierSmsUtils.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2017 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.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Binder;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.Rlog;
+
+import java.util.List;
+
+/**
+ * This is a basic utility class for common Carrier SMS Functions
+ */
+public class CarrierSmsUtils {
+ protected static final boolean VDBG = false;
+ protected static final String TAG = CarrierSmsUtils.class.getSimpleName();
+
+ private static final String CARRIER_IMS_PACKAGE_KEY =
+ CarrierConfigManager.KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING;
+
+ /** Return a Carrier-overridden IMS package, if it exists and is a CarrierSmsFilter
+ *
+ * @param context calling context
+ * @param phone object from telephony
+ * @param intent that should match a CarrierSmsFilter
+ * @return the name of the IMS CarrierService package
+ */
+ @Nullable
+ public static String getCarrierImsPackageForIntent(
+ Context context, Phone phone, Intent intent) {
+
+ String carrierImsPackage = getCarrierImsPackage(context, phone);
+ if (carrierImsPackage == null) {
+ if (VDBG) Rlog.v(TAG, "No CarrierImsPackage override found");
+ return null;
+ }
+
+ PackageManager packageManager = context.getPackageManager();
+ List<ResolveInfo> receivers = packageManager.queryIntentServices(intent, 0);
+ for (ResolveInfo info : receivers) {
+ if (info.serviceInfo == null) {
+ Rlog.e(TAG, "Can't get service information from " + info);
+ continue;
+ }
+
+ if (carrierImsPackage.equals(info.serviceInfo.packageName)) {
+ return carrierImsPackage;
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private static String getCarrierImsPackage(Context context, Phone phone) {
+ CarrierConfigManager cm = (CarrierConfigManager) context.getSystemService(
+ Context.CARRIER_CONFIG_SERVICE);
+ if (cm == null) {
+ Rlog.e(TAG, "Failed to retrieve CarrierConfigManager");
+ return null;
+ }
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ PersistableBundle config = cm.getConfigForSubId(phone.getSubId());
+ if (config == null) {
+ if (VDBG) Rlog.v(TAG, "No CarrierConfig for subId:" + phone.getSubId());
+ return null;
+ }
+ return config.getString(CARRIER_IMS_PACKAGE_KEY, null);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private CarrierSmsUtils() {}
+}
diff --git a/src/java/com/android/internal/telephony/CellBroadcastHandler.java b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
index 5cb329a..4227148 100644
--- a/src/java/com/android/internal/telephony/CellBroadcastHandler.java
+++ b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
@@ -16,16 +16,20 @@
package com.android.internal.telephony;
+import static android.provider.Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG;
+
import android.Manifest;
import android.app.Activity;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.os.Message;
import android.os.UserHandle;
+import android.provider.Settings;
import android.provider.Telephony;
-import android.telephony.SubscriptionManager;
import android.telephony.SmsCbMessage;
+import android.telephony.SubscriptionManager;
/**
* Dispatch new Cell Broadcasts to receivers. Acquires a private wakelock until the broadcast
@@ -82,16 +86,38 @@
if (message.isEmergencyMessage()) {
log("Dispatching emergency SMS CB, SmsCbMessage is: " + message);
intent = new Intent(Telephony.Sms.Intents.SMS_EMERGENCY_CB_RECEIVED_ACTION);
+ // Explicitly send the intent to the default cell broadcast receiver.
+ intent.setPackage(mContext.getResources().getString(
+ com.android.internal.R.string.config_defaultCellBroadcastReceiverPkg));
receiverPermission = Manifest.permission.RECEIVE_EMERGENCY_BROADCAST;
appOp = AppOpsManager.OP_RECEIVE_EMERGECY_SMS;
} else {
log("Dispatching SMS CB, SmsCbMessage is: " + message);
intent = new Intent(Telephony.Sms.Intents.SMS_CB_RECEIVED_ACTION);
+ // Send implicit intent since there are various 3rd party carrier apps listen to
+ // this intent.
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
receiverPermission = Manifest.permission.RECEIVE_SMS;
appOp = AppOpsManager.OP_RECEIVE_SMS;
}
+
intent.putExtra("message", message);
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
+
+ if (Build.IS_DEBUGGABLE) {
+ // Send additional broadcast intent to the specified package. This is only for sl4a
+ // automation tests.
+ final String additionalPackage = Settings.Secure.getString(
+ mContext.getContentResolver(), CMAS_ADDITIONAL_BROADCAST_PKG);
+ if (additionalPackage != null) {
+ Intent additionalIntent = new Intent(intent);
+ additionalIntent.setPackage(additionalPackage);
+ mContext.sendOrderedBroadcastAsUser(additionalIntent, UserHandle.ALL,
+ receiverPermission, appOp, null, getHandler(), Activity.RESULT_OK, null,
+ null);
+ }
+ }
+
mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, receiverPermission, appOp,
mReceiver, getHandler(), Activity.RESULT_OK, null, null);
}
diff --git a/src/java/com/android/internal/telephony/ClientWakelockAccountant.java b/src/java/com/android/internal/telephony/ClientWakelockAccountant.java
new file mode 100644
index 0000000..c47faab
--- /dev/null
+++ b/src/java/com/android/internal/telephony/ClientWakelockAccountant.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 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.telephony.ClientRequestStats;
+import android.telephony.Rlog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import java.util.ArrayList;
+
+public class ClientWakelockAccountant {
+ public static final String LOG_TAG = "ClientWakelockAccountant: ";
+
+ @VisibleForTesting
+ public ClientRequestStats mRequestStats = new ClientRequestStats();
+ @VisibleForTesting
+ public ArrayList<RilWakelockInfo> mPendingRilWakelocks = new ArrayList<>();
+
+ @VisibleForTesting
+ public ClientWakelockAccountant(String callingPackage) {
+ mRequestStats.setCallingPackage(callingPackage);
+ }
+
+ @VisibleForTesting
+ public void startAttributingWakelock(int request,
+ int token, int concurrentRequests, long time) {
+
+ RilWakelockInfo wlInfo = new RilWakelockInfo(request, token, concurrentRequests, time);
+ synchronized (mPendingRilWakelocks) {
+ mPendingRilWakelocks.add(wlInfo);
+ }
+ }
+
+ @VisibleForTesting
+ public void stopAttributingWakelock(int request, int token, long time) {
+ RilWakelockInfo wlInfo = removePendingWakelock(request, token);
+ if (wlInfo != null) {
+ completeRequest(wlInfo, time);
+ }
+ }
+
+ @VisibleForTesting
+ public void stopAllPendingRequests(long time) {
+ synchronized (mPendingRilWakelocks) {
+ for (RilWakelockInfo wlInfo : mPendingRilWakelocks) {
+ completeRequest(wlInfo, time);
+ }
+ mPendingRilWakelocks.clear();
+ }
+ }
+
+ @VisibleForTesting
+ public void changeConcurrentRequests(int concurrentRequests, long time) {
+ synchronized (mPendingRilWakelocks) {
+ for (RilWakelockInfo wlInfo : mPendingRilWakelocks) {
+ wlInfo.updateConcurrentRequests(concurrentRequests, time);
+ }
+ }
+ }
+
+ private void completeRequest(RilWakelockInfo wlInfo, long time) {
+ wlInfo.setResponseTime(time);
+ synchronized (mRequestStats) {
+ mRequestStats.addCompletedWakelockTime(wlInfo.getWakelockTimeAttributedToClient());
+ mRequestStats.incrementCompletedRequestsCount();
+ mRequestStats.updateRequestHistograms(wlInfo.getRilRequestSent(),
+ (int) wlInfo.getWakelockTimeAttributedToClient());
+ }
+ }
+
+ @VisibleForTesting
+ public int getPendingRequestCount() {
+ return mPendingRilWakelocks.size();
+ }
+
+ @VisibleForTesting
+ public synchronized long updatePendingRequestWakelockTime(long uptime) {
+ long totalPendingWakelockTime = 0;
+ synchronized (mPendingRilWakelocks) {
+ for (RilWakelockInfo wlInfo : mPendingRilWakelocks) {
+ wlInfo.updateTime(uptime);
+ totalPendingWakelockTime += wlInfo.getWakelockTimeAttributedToClient();
+ }
+ }
+ synchronized (mRequestStats) {
+ mRequestStats.setPendingRequestsCount(getPendingRequestCount());
+ mRequestStats.setPendingRequestsWakelockTime(totalPendingWakelockTime);
+ }
+ return totalPendingWakelockTime;
+ }
+
+ private RilWakelockInfo removePendingWakelock(int request, int token) {
+ RilWakelockInfo result = null;
+ synchronized (mPendingRilWakelocks) {
+ for (RilWakelockInfo wlInfo : mPendingRilWakelocks) {
+ if ((wlInfo.getTokenNumber() == token) &&
+ (wlInfo.getRilRequestSent() == request)) {
+ result = wlInfo;
+ }
+ }
+ if( result != null ) {
+ mPendingRilWakelocks.remove(result);
+ }
+ }
+ if(result == null) {
+ Rlog.w(LOG_TAG, "Looking for Request<" + request + "," + token + "> in "
+ + mPendingRilWakelocks);
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "ClientWakelockAccountant{" +
+ "mRequestStats=" + mRequestStats +
+ ", mPendingRilWakelocks=" + mPendingRilWakelocks +
+ '}';
+ }
+}
diff --git a/src/java/com/android/internal/telephony/ClientWakelockTracker.java b/src/java/com/android/internal/telephony/ClientWakelockTracker.java
new file mode 100644
index 0000000..5bec60b
--- /dev/null
+++ b/src/java/com/android/internal/telephony/ClientWakelockTracker.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2016 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.SystemClock;
+import android.telephony.ClientRequestStats;
+import android.telephony.Rlog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class ClientWakelockTracker {
+ public static final String LOG_TAG = "ClientWakelockTracker";
+ @VisibleForTesting
+ public HashMap<String, ClientWakelockAccountant> mClients =
+ new HashMap<String, ClientWakelockAccountant>();
+ @VisibleForTesting
+ public ArrayList<ClientWakelockAccountant> mActiveClients = new ArrayList<>();
+
+ @VisibleForTesting
+ public void startTracking(String clientId, int requestId, int token, int numRequestsInQueue) {
+ ClientWakelockAccountant client = getClientWakelockAccountant(clientId);
+ long uptime = SystemClock.uptimeMillis();
+ client.startAttributingWakelock(requestId, token, numRequestsInQueue, uptime);
+ updateConcurrentRequests(numRequestsInQueue, uptime);
+ synchronized (mActiveClients) {
+ if (!mActiveClients.contains(client)) {
+ mActiveClients.add(client);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ public void stopTracking(String clientId, int requestId, int token, int numRequestsInQueue) {
+ ClientWakelockAccountant client = getClientWakelockAccountant(clientId);
+ long uptime = SystemClock.uptimeMillis();
+ client.stopAttributingWakelock(requestId, token, uptime);
+ if(client.getPendingRequestCount() == 0) {
+ synchronized (mActiveClients) {
+ mActiveClients.remove(client);
+ }
+ }
+ updateConcurrentRequests(numRequestsInQueue, uptime);
+ }
+
+ @VisibleForTesting
+ public void stopTrackingAll() {
+ long uptime = SystemClock.uptimeMillis();
+ synchronized (mActiveClients) {
+ for (ClientWakelockAccountant client : mActiveClients) {
+ client.stopAllPendingRequests(uptime);
+ }
+ mActiveClients.clear();
+ }
+ }
+
+ List<ClientRequestStats> getClientRequestStats() {
+ List<ClientRequestStats> list;
+ long uptime = SystemClock.uptimeMillis();
+ synchronized (mClients) {
+ list = new ArrayList<>(mClients.size());
+ for (String key : mClients.keySet()) {
+ ClientWakelockAccountant client = mClients.get(key);
+ client.updatePendingRequestWakelockTime(uptime);
+ list.add(new ClientRequestStats(client.mRequestStats));
+ }
+ }
+ return list;
+ }
+
+ private ClientWakelockAccountant getClientWakelockAccountant(String clientId) {
+ ClientWakelockAccountant client;
+ synchronized (mClients) {
+ if (mClients.containsKey(clientId)) {
+ client = mClients.get(clientId);
+ } else {
+ client = new ClientWakelockAccountant(clientId);
+ mClients.put(clientId, client);
+ }
+ }
+ return client;
+ }
+
+ private void updateConcurrentRequests(int numRequestsInQueue, long time) {
+ if(numRequestsInQueue != 0) {
+ synchronized (mActiveClients) {
+ for (ClientWakelockAccountant cI : mActiveClients) {
+ cI.changeConcurrentRequests(numRequestsInQueue, time);
+ }
+ }
+ }
+ }
+
+ public boolean isClientActive(String clientId) {
+ ClientWakelockAccountant client = getClientWakelockAccountant(clientId);
+ synchronized (mActiveClients) {
+ if (mActiveClients.contains(client)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void dumpClientRequestTracker() {
+ Rlog.d(RIL.RILJ_LOG_TAG, "-------mClients---------------");
+ synchronized (mClients) {
+ for (String key : mClients.keySet()) {
+ Rlog.d(RIL.RILJ_LOG_TAG, "Client : " + key);
+ Rlog.d(RIL.RILJ_LOG_TAG, mClients.get(key).toString());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index f23905a..106ec54 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -16,19 +16,19 @@
package com.android.internal.telephony;
+import android.os.Handler;
+import android.os.Message;
+import android.os.WorkSource;
+import android.service.carrier.CarrierIdentifier;
+import android.telephony.ClientRequestStats;
+
import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
import com.android.internal.telephony.dataconnection.DataProfile;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
-import com.android.internal.telephony.RadioCapability;
import com.android.internal.telephony.uicc.IccCardStatus;
-import android.os.Message;
-import android.os.Handler;
-import android.service.carrier.CarrierIdentifier;
-
import java.util.List;
-
/**
* {@hide}
*/
@@ -190,10 +190,14 @@
void registerForCallStateChanged(Handler h, int what, Object obj);
void unregisterForCallStateChanged(Handler h);
- void registerForVoiceNetworkStateChanged(Handler h, int what, Object obj);
- void unregisterForVoiceNetworkStateChanged(Handler h);
- void registerForDataNetworkStateChanged(Handler h, int what, Object obj);
- void unregisterForDataNetworkStateChanged(Handler h);
+ /** Register for network state changed event */
+ void registerForNetworkStateChanged(Handler h, int what, Object obj);
+ /** Unregister from network state changed event */
+ void unregisterForNetworkStateChanged(Handler h);
+ /** Register for data call list changed event */
+ void registerForDataCallListChanged(Handler h, int what, Object obj);
+ /** Unregister from data call list changed event */
+ void unregisterForDataCallListChanged(Handler h);
/** InCall voice privacy notifications */
void registerForInCallVoicePrivacyOn(Handler h, int what, Object obj);
@@ -1384,8 +1388,9 @@
* Query neighboring cell ids
*
* @param response s callback message to cell ids
+ * @param workSource calling WorkSource
*/
- void getNeighboringCids(Message response);
+ default void getNeighboringCids(Message response, WorkSource workSource){}
/**
* Request to enable/disable network state change notifications when
@@ -1599,26 +1604,17 @@
*
* @param radioTechnology
* Radio technology to use. Values is one of RIL_RADIO_TECHNOLOGY_*
- * @param profile
- * Profile Number. Values is one of DATA_PROFILE_*
- * @param apn
- * the APN to connect to if radio technology is GSM/UMTS.
- * Otherwise null for CDMA.
- * @param user
- * the username for APN, or NULL
- * @param password
- * the password for APN, or NULL
- * @param authType
- * the PAP / CHAP auth type. Values is one of SETUP_DATA_AUTH_*
- * @param protocol
- * one of the PDP_type values in TS 27.007 section 10.1.1.
- * For example, "IP", "IPV6", "IPV4V6", or "PPP".
+ * @param dataProfile
+ * Data profile for data call setup
+ * @param isRoaming
+ * Device is roaming or not
+ * @param allowRoaming
+ * Flag indicating data roaming is enabled or not
* @param result
* Callback message
*/
- public void setupDataCall(int radioTechnology, int profile,
- String apn, String user, String password, int authType,
- String protocol, Message result);
+ void setupDataCall(int radioTechnology, DataProfile dataProfile, boolean isRoaming,
+ boolean allowRoaming, Message result);
/**
* Deactivate packet data connection
@@ -1727,8 +1723,9 @@
* AsyncResult.result is a of Collection<CellInfo>
*
* @param result is sent back to handler and result.obj is a AsyncResult
+ * @param workSource calling WorkSource
*/
- void getCellInfoList(Message result);
+ default void getCellInfoList(Message result, WorkSource workSource) {}
/**
* Sets the minimum time in milli-seconds between when RIL_UNSOL_CELL_INFO_LIST
@@ -1744,8 +1741,9 @@
* @param response.obj is AsyncResult ar when sent to associated handler
* ar.exception carries exception on failure or null on success
* otherwise the error.
+ * @param workSource calling WorkSource
*/
- void setCellInfoListRate(int rateInMillis, Message response);
+ default void setCellInfoListRate(int rateInMillis, Message response, WorkSource workSource){}
/**
* Fires when RIL_UNSOL_CELL_INFO_LIST is received from the RIL.
@@ -1756,33 +1754,26 @@
/**
* Set Initial Attach Apn
*
- * @param apn
- * the APN to connect to if radio technology is GSM/UMTS.
- * @param protocol
- * one of the PDP_type values in TS 27.007 section 10.1.1.
- * For example, "IP", "IPV6", "IPV4V6", or "PPP".
- * @param authType
- * authentication protocol used for this PDP context
- * (None: 0, PAP: 1, CHAP: 2, PAP&CHAP: 3)
- * @param username
- * the username for APN, or NULL
- * @param password
- * the password for APN, or NULL
+ * @param dataProfile
+ * data profile for initial APN attach
+ * @param isRoaming
+ * indicating the device is roaming or not
* @param result
* callback message contains the information of SUCCESS/FAILURE
*/
- public void setInitialAttachApn(String apn, String protocol, int authType, String username,
- String password, Message result);
+ void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, Message result);
/**
* Set data profiles in modem
*
* @param dps
* Array of the data profiles set to modem
+ * @param isRoaming
+ * Indicating if the device is roaming or not
* @param result
* callback message contains the information of SUCCESS/FAILURE
*/
- public void setDataProfile(DataProfile[] dps, Message result);
+ void setDataProfile(DataProfile[] dps, boolean isRoaming, Message result);
/**
* Notifiy that we are testing an emergency call
@@ -1795,10 +1786,11 @@
* Input parameters equivalent to TS 27.007 AT+CCHO command.
*
* @param AID Application id. See ETSI 102.221 and 101.220.
+ * @param p2 P2 parameter (described in ISO 7816-4).
* @param response Callback message. response.obj will be an int [1] with
* element [0] set to the id of the logical channel.
*/
- public void iccOpenLogicalChannel(String AID, Message response);
+ public void iccOpenLogicalChannel(String AID, int p2, Message response);
/**
* Close a previously opened logical channel to the SIM.
@@ -2052,4 +2044,33 @@
* @param h handler to be removed
*/
public void unregisterForPcoData(Handler h);
+
+ /**
+ * Send the updated device state
+ *
+ * @param stateType Device state type
+ * @param state True if enabled, otherwise disabled
+ * @param result callback message contains the information of SUCCESS/FAILURE
+ */
+ void sendDeviceState(int stateType, boolean state, Message result);
+
+ /**
+ * Send the device state to the modem
+ *
+ * @param filter unsolicited response filter. See DeviceStateMonitor.UnsolicitedResponseFilter
+ * @param result callback message contains the information of SUCCESS/FAILURE
+ */
+ void setUnsolResponseFilter(int filter, Message result);
+
+ /**
+ * Set SIM card power up or down
+ *
+ * @param powerUp True if powering up the sim card
+ * @param result callback message contains the information of SUCCESS/FAILURE
+ */
+ void setSimCardPower(boolean powerUp, Message result);
+
+ default public List<ClientRequestStats> getClientRequestStats() {
+ return null;
+ }
}
diff --git a/src/java/com/android/internal/telephony/Connection.java b/src/java/com/android/internal/telephony/Connection.java
index 39523b4..8a77465 100644
--- a/src/java/com/android/internal/telephony/Connection.java
+++ b/src/java/com/android/internal/telephony/Connection.java
@@ -188,6 +188,7 @@
private int mVideoState;
private int mConnectionCapabilities;
private boolean mIsWifi;
+ private boolean mAudioModeIsVoip;
private int mAudioQuality;
private int mCallSubstate;
private android.telecom.Connection.VideoProvider mVideoProvider;
@@ -501,7 +502,9 @@
}
protected final void clearPostDialListeners() {
- mPostDialListeners.clear();
+ if (mPostDialListeners != null) {
+ mPostDialListeners.clear();
+ }
}
protected final void notifyPostDialListeners() {
@@ -700,6 +703,15 @@
}
/**
+ * Returns whether the connection uses voip audio mode
+ *
+ * @return {@code True} if the connection uses voip audio mode
+ */
+ public boolean getAudioModeIsVoip() {
+ return mAudioModeIsVoip;
+ }
+
+ /**
* Returns the {@link android.telecom.Connection.VideoProvider} for the connection.
*
* @return The {@link android.telecom.Connection.VideoProvider}.
@@ -770,6 +782,15 @@
}
/**
+ * Set the voip audio mode for the connection
+ *
+ * @param isVoip {@code True} if voip audio mode is being used.
+ */
+ public void setAudioModeIsVoip(boolean isVoip) {
+ mAudioModeIsVoip = isVoip;
+ }
+
+ /**
* Set the audio quality for the connection.
*
* @param audioQuality The audio quality.
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 0c23cf8..b83a6d1 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -28,12 +28,8 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.PreciseCallState;
-import android.telephony.DisconnectCause;
-import com.android.internal.telephony.Call;
-import com.android.internal.telephony.CallManager;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.ITelephonyRegistry;
+import com.android.internal.telephony.PhoneConstantConversions;
import com.android.internal.telephony.PhoneConstants;
import java.util.List;
@@ -64,7 +60,8 @@
try {
if (mRegistry != null) {
mRegistry.notifyCallStateForPhoneId(phoneId, subId,
- convertCallState(sender.getState()), incomingNumber);
+ PhoneConstantConversions.convertCallState(
+ sender.getState()), incomingNumber);
}
} catch (RemoteException ex) {
// system process is dead
@@ -182,7 +179,7 @@
try {
if (mRegistry != null) {
mRegistry.notifyDataConnectionForSubscriber(subId,
- convertDataState(state),
+ PhoneConstantConversions.convertDataState(state),
sender.isDataConnectivityPossible(apnType), reason,
sender.getActiveApnHost(apnType),
apnType,
@@ -294,75 +291,31 @@
}
@Override
- public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) {
+ public void notifyDataActivationStateChanged(Phone sender, int activationState) {
try {
- mRegistry.notifyOemHookRawEventForSubscriber(subId, rawData);
+ mRegistry.notifySimActivationStateChangedForPhoneId(sender.getPhoneId(),
+ sender.getSubId(), PhoneConstants.SIM_ACTIVATION_TYPE_DATA, activationState);
} catch (RemoteException ex) {
// system process is dead
}
}
- /**
- * Convert the {@link PhoneConstants.State} enum into the TelephonyManager.CALL_STATE_*
- * constants for the public API.
- */
- public static int convertCallState(PhoneConstants.State state) {
- switch (state) {
- case RINGING:
- return TelephonyManager.CALL_STATE_RINGING;
- case OFFHOOK:
- return TelephonyManager.CALL_STATE_OFFHOOK;
- default:
- return TelephonyManager.CALL_STATE_IDLE;
+ @Override
+ public void notifyVoiceActivationStateChanged(Phone sender, int activationState) {
+ try {
+ mRegistry.notifySimActivationStateChangedForPhoneId(sender.getPhoneId(),
+ sender.getSubId(), PhoneConstants.SIM_ACTIVATION_TYPE_VOICE, activationState);
+ } catch (RemoteException ex) {
+ // system process is dead
}
}
- /**
- * Convert the TelephonyManager.CALL_STATE_* constants into the
- * {@link PhoneConstants.State} enum for the public API.
- */
- public static PhoneConstants.State convertCallState(int state) {
- switch (state) {
- case TelephonyManager.CALL_STATE_RINGING:
- return PhoneConstants.State.RINGING;
- case TelephonyManager.CALL_STATE_OFFHOOK:
- return PhoneConstants.State.OFFHOOK;
- default:
- return PhoneConstants.State.IDLE;
- }
- }
-
- /**
- * Convert the {@link PhoneConstants.DataState} enum into the TelephonyManager.DATA_* constants
- * for the public API.
- */
- public static int convertDataState(PhoneConstants.DataState state) {
- switch (state) {
- case CONNECTING:
- return TelephonyManager.DATA_CONNECTING;
- case CONNECTED:
- return TelephonyManager.DATA_CONNECTED;
- case SUSPENDED:
- return TelephonyManager.DATA_SUSPENDED;
- default:
- return TelephonyManager.DATA_DISCONNECTED;
- }
- }
-
- /**
- * Convert the TelephonyManager.DATA_* constants into {@link PhoneConstants.DataState} enum
- * for the public API.
- */
- public static PhoneConstants.DataState convertDataState(int state) {
- switch (state) {
- case TelephonyManager.DATA_CONNECTING:
- return PhoneConstants.DataState.CONNECTING;
- case TelephonyManager.DATA_CONNECTED:
- return PhoneConstants.DataState.CONNECTED;
- case TelephonyManager.DATA_SUSPENDED:
- return PhoneConstants.DataState.SUSPENDED;
- default:
- return PhoneConstants.DataState.DISCONNECTED;
+ @Override
+ public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) {
+ try {
+ mRegistry.notifyOemHookRawEventForSubscriber(subId, rawData);
+ } catch (RemoteException ex) {
+ // system process is dead
}
}
diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
new file mode 100644
index 0000000..73ab075
--- /dev/null
+++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2017 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 static android.hardware.radio.V1_0.DeviceStateType.CHARGING_STATE;
+import static android.hardware.radio.V1_0.DeviceStateType.LOW_DATA_EXPECTED;
+import static android.hardware.radio.V1_0.DeviceStateType.POWER_SAVE_MODE;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.display.DisplayManager;
+import android.hardware.radio.V1_0.IndicationFilter;
+import android.net.ConnectivityManager;
+import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.telephony.Rlog;
+import android.util.LocalLog;
+import android.view.Display;
+
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * The device state monitor monitors the device state such as charging state, power saving sate,
+ * and then passes down the information to the radio modem for the modem to perform its own
+ * proprietary power saving strategy. Device state monitor also turns off the unsolicited
+ * response from the modem when the device does not need to receive it, for example, device's
+ * screen is off and does not have activities like tethering, remote display, etc...This effectively
+ * prevents the CPU from waking up by those unnecessary unsolicited responses such as signal
+ * strength update.
+ */
+public class DeviceStateMonitor extends Handler {
+ protected static final boolean DBG = false; /* STOPSHIP if true */
+ protected static final String TAG = DeviceStateMonitor.class.getSimpleName();
+
+ private static final int EVENT_RIL_CONNECTED = 0;
+ private static final int EVENT_SCREEN_STATE_CHANGED = 1;
+ private static final int EVENT_POWER_SAVE_MODE_CHANGED = 2;
+ private static final int EVENT_CHARGING_STATE_CHANGED = 3;
+ private static final int EVENT_TETHERING_STATE_CHANGED = 4;
+
+ private final Phone mPhone;
+
+ private final LocalLog mLocalLog = new LocalLog(100);
+
+ /**
+ * Flag for wifi/usb/bluetooth tethering turned on or not
+ */
+ private boolean mIsTetheringOn;
+
+ /**
+ * Screen state provided by Display Manager. True indicates one of the screen is on, otherwise
+ * all off.
+ */
+ private boolean mIsScreenOn;
+
+ /**
+ * Indicating the device is plugged in and is supplying sufficient power that the battery level
+ * is going up (or the battery is fully charged). See BatteryManager.isCharging() for the
+ * details
+ */
+ private boolean mIsCharging;
+
+ /**
+ * Flag for device power save mode. See PowerManager.isPowerSaveMode() for the details.
+ * Note that it is not possible both mIsCharging and mIsPowerSaveOn are true at the same time.
+ * The system will automatically end power save mode when the device starts charging.
+ */
+ private boolean mIsPowerSaveOn;
+
+ /**
+ * Low data expected mode. True indicates low data traffic is expected, for example, when the
+ * device is idle (e.g. screen is off and not doing tethering in the background). Note this
+ * doesn't mean no data is expected.
+ */
+ private boolean mIsLowDataExpected;
+
+ /**
+ * The unsolicited response filter. See IndicationFilter defined in types.hal for the definition
+ * of each bit.
+ */
+ private int mUnsolicitedResponseFilter = IndicationFilter.ALL;
+
+ private final DisplayManager.DisplayListener mDisplayListener =
+ new DisplayManager.DisplayListener() {
+ @Override
+ public void onDisplayAdded(int displayId) { }
+
+ @Override
+ public void onDisplayRemoved(int displayId) { }
+
+ @Override
+ public void onDisplayChanged(int displayId) {
+ boolean screenOn = isScreenOn();
+ Message msg = obtainMessage(EVENT_SCREEN_STATE_CHANGED);
+ msg.arg1 = screenOn ? 1 : 0;
+ sendMessage(msg);
+ }
+ };
+
+ /**
+ * Device state broadcast receiver
+ */
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ log("received: " + intent, true);
+
+ Message msg;
+ switch (intent.getAction()) {
+ case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
+ msg = obtainMessage(EVENT_POWER_SAVE_MODE_CHANGED);
+ msg.arg1 = isPowerSaveModeOn() ? 1 : 0;
+ log("Power Save mode " + ((msg.arg1 == 1) ? "on" : "off"), true);
+ break;
+ case BatteryManager.ACTION_CHARGING:
+ msg = obtainMessage(EVENT_CHARGING_STATE_CHANGED);
+ msg.arg1 = 1; // charging
+ break;
+ case BatteryManager.ACTION_DISCHARGING:
+ msg = obtainMessage(EVENT_CHARGING_STATE_CHANGED);
+ msg.arg1 = 0; // not charging
+ break;
+ case ConnectivityManager.ACTION_TETHER_STATE_CHANGED:
+ ArrayList<String> activeTetherIfaces = intent.getStringArrayListExtra(
+ ConnectivityManager.EXTRA_ACTIVE_TETHER);
+
+ boolean isTetheringOn = activeTetherIfaces != null
+ && activeTetherIfaces.size() > 0;
+ log("Tethering " + (isTetheringOn ? "on" : "off"), true);
+ msg = obtainMessage(EVENT_TETHERING_STATE_CHANGED);
+ msg.arg1 = isTetheringOn ? 1 : 0;
+ break;
+ default:
+ log("Unexpected broadcast intent: " + intent, false);
+ return;
+ }
+ sendMessage(msg);
+ }
+ };
+
+ /**
+ * Device state monitor constructor. Note that each phone object should have its own device
+ * state monitor, meaning there will be two device monitors on the multi-sim device.
+ *
+ * @param phone Phone object
+ */
+ public DeviceStateMonitor(Phone phone) {
+ mPhone = phone;
+ DisplayManager dm = (DisplayManager) phone.getContext().getSystemService(
+ Context.DISPLAY_SERVICE);
+ dm.registerDisplayListener(mDisplayListener, null);
+
+ mIsPowerSaveOn = isPowerSaveModeOn();
+ mIsCharging = isDeviceCharging();
+ mIsScreenOn = isScreenOn();
+ // Assuming tethering is always off after boot up.
+ mIsTetheringOn = false;
+ mIsLowDataExpected = false;
+
+ log("DeviceStateMonitor mIsPowerSaveOn=" + mIsPowerSaveOn + ",mIsScreenOn="
+ + mIsScreenOn + ",mIsCharging=" + mIsCharging, false);
+
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
+ filter.addAction(BatteryManager.ACTION_CHARGING);
+ filter.addAction(BatteryManager.ACTION_DISCHARGING);
+ filter.addAction(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+ mPhone.getContext().registerReceiver(mBroadcastReceiver, filter, null, mPhone);
+
+ mPhone.mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
+ }
+
+ /**
+ * @return True if low data is expected
+ */
+ private boolean isLowDataExpected() {
+ return mIsPowerSaveOn || (!mIsCharging && !mIsTetheringOn && !mIsScreenOn);
+ }
+
+ /**
+ * @return True if signal strength update should be turned off.
+ */
+ private boolean shouldTurnOffSignalStrength() {
+ return mIsPowerSaveOn || (!mIsCharging && !mIsScreenOn);
+ }
+
+ /**
+ * @return True if full network update should be turned off. Only significant changes will
+ * trigger the network update unsolicited response.
+ */
+ private boolean shouldTurnOffFullNetworkUpdate() {
+ return mIsPowerSaveOn || (!mIsCharging && !mIsScreenOn && !mIsTetheringOn);
+ }
+
+ /**
+ * @return True if data dormancy status update should be turned off.
+ */
+ private boolean shouldTurnOffDormancyUpdate() {
+ return mIsPowerSaveOn || (!mIsCharging && !mIsTetheringOn && !mIsScreenOn);
+ }
+
+ /**
+ * Message handler
+ *
+ * @param msg The message
+ */
+ @Override
+ public void handleMessage(Message msg) {
+ log("handleMessage msg=" + msg, false);
+ switch (msg.what) {
+ case EVENT_RIL_CONNECTED:
+ onRilConnected();
+ break;
+ default:
+ updateDeviceState(msg.what, msg.arg1 != 0);
+ }
+ }
+
+ /**
+ * Update the device and send the information to the modem.
+ *
+ * @param eventType Device state event type
+ * @param state True if enabled/on, otherwise disabled/off.
+ */
+ private void updateDeviceState(int eventType, boolean state) {
+ switch (eventType) {
+ case EVENT_SCREEN_STATE_CHANGED:
+ if (mIsScreenOn == state) return;
+ mIsScreenOn = state;
+ break;
+ case EVENT_CHARGING_STATE_CHANGED:
+ if (mIsCharging == state) return;
+ mIsCharging = state;
+ sendDeviceState(CHARGING_STATE, mIsCharging);
+ break;
+ case EVENT_TETHERING_STATE_CHANGED:
+ if (mIsTetheringOn == state) return;
+ mIsTetheringOn = state;
+ break;
+ case EVENT_POWER_SAVE_MODE_CHANGED:
+ if (mIsPowerSaveOn == state) return;
+ mIsPowerSaveOn = state;
+ sendDeviceState(POWER_SAVE_MODE, mIsPowerSaveOn);
+ break;
+ default:
+ return;
+ }
+
+ if (mIsLowDataExpected != isLowDataExpected()) {
+ mIsLowDataExpected = !mIsLowDataExpected;
+ sendDeviceState(LOW_DATA_EXPECTED, mIsLowDataExpected);
+ }
+
+ int newFilter = 0;
+ if (!shouldTurnOffSignalStrength()) {
+ newFilter |= IndicationFilter.SIGNAL_STRENGTH;
+ }
+
+ if (!shouldTurnOffFullNetworkUpdate()) {
+ newFilter |= IndicationFilter.FULL_NETWORK_STATE;
+ }
+
+ if (!shouldTurnOffDormancyUpdate()) {
+ newFilter |= IndicationFilter.DATA_CALL_DORMANCY_CHANGED;
+ }
+
+ setUnsolResponseFilter(newFilter, false);
+ }
+
+ /**
+ * Called when RIL is connected during boot up or reconnected after modem restart.
+ *
+ * When modem crashes, if the user turns the screen off before RIL reconnects, device
+ * state and filter cannot be sent to modem. Resend the state here so that modem
+ * has the correct state (to stop signal strength reporting, etc).
+ */
+ private void onRilConnected() {
+ log("RIL connected.", true);
+ sendDeviceState(CHARGING_STATE, mIsCharging);
+ sendDeviceState(LOW_DATA_EXPECTED, mIsLowDataExpected);
+ sendDeviceState(POWER_SAVE_MODE, mIsPowerSaveOn);
+ setUnsolResponseFilter(mUnsolicitedResponseFilter, true);
+ }
+
+ /**
+ * Convert the device state type into string
+ *
+ * @param type Device state type
+ * @return The converted string
+ */
+ private String deviceTypeToString(int type) {
+ switch (type) {
+ case CHARGING_STATE: return "CHARGING_STATE";
+ case LOW_DATA_EXPECTED: return "LOW_DATA_EXPECTED";
+ case POWER_SAVE_MODE: return "POWER_SAVE_MODE";
+ default: return "UNKNOWN";
+ }
+ }
+
+ /**
+ * Send the device state to the modem.
+ *
+ * @param type Device state type. See DeviceStateType defined in types.hal.
+ * @param state True if enabled/on, otherwise disabled/off
+ */
+ private void sendDeviceState(int type, boolean state) {
+ log("send type: " + deviceTypeToString(type) + ", state=" + state, true);
+ mPhone.mCi.sendDeviceState(type, state, null);
+ }
+
+ /**
+ * Turn on/off the unsolicited response from the modem.
+ *
+ * @param newFilter See UnsolicitedResponseFilter in types.hal for the definition of each bit.
+ * @param force Always set the filter when true.
+ */
+ private void setUnsolResponseFilter(int newFilter, boolean force) {
+ if (force || newFilter != mUnsolicitedResponseFilter) {
+ log("old filter: " + mUnsolicitedResponseFilter + ", new filter: " + newFilter, true);
+ mPhone.mCi.setUnsolResponseFilter(newFilter, null);
+ mUnsolicitedResponseFilter = newFilter;
+ }
+ }
+
+ /**
+ * @return True if the device is currently in power save mode.
+ * See {@link android.os.BatteryManager#isPowerSaveMode BatteryManager.isPowerSaveMode()}.
+ */
+ private boolean isPowerSaveModeOn() {
+ final PowerManager pm = (PowerManager) mPhone.getContext().getSystemService(
+ Context.POWER_SERVICE);
+ return pm.isPowerSaveMode();
+ }
+
+ /**
+ * @return Return true if the battery is currently considered to be charging. This means that
+ * the device is plugged in and is supplying sufficient power that the battery level is
+ * going up (or the battery is fully charged).
+ * See {@link android.os.BatteryManager#isCharging BatteryManager.isCharging()}.
+ */
+ private boolean isDeviceCharging() {
+ final BatteryManager bm = (BatteryManager) mPhone.getContext().getSystemService(
+ Context.BATTERY_SERVICE);
+ return bm.isCharging();
+ }
+
+ /**
+ * @return True if one the device's screen (e.g. main screen, wifi display, HDMI display, or
+ * Android auto, etc...) is on.
+ */
+ private boolean isScreenOn() {
+ // Note that we don't listen to Intent.SCREEN_ON and Intent.SCREEN_OFF because they are no
+ // longer adequate for monitoring the screen state since they are not sent in cases where
+ // the screen is turned off transiently such as due to the proximity sensor.
+ final DisplayManager dm = (DisplayManager) mPhone.getContext().getSystemService(
+ Context.DISPLAY_SERVICE);
+ Display[] displays = dm.getDisplays();
+
+ if (displays != null) {
+ for (Display display : displays) {
+ // Anything other than STATE_ON is treated as screen off, such as STATE_DOZE,
+ // STATE_DOZE_SUSPEND, etc...
+ if (display.getState() == Display.STATE_ON) {
+ log("Screen " + Display.typeToString(display.getType()) + " on", true);
+ return true;
+ }
+ }
+ log("Screens all off", true);
+ return false;
+ }
+
+ log("No displays found", true);
+ return false;
+ }
+
+ /**
+ * @param msg Debug message
+ * @param logIntoLocalLog True if log into the local log
+ */
+ private void log(String msg, boolean logIntoLocalLog) {
+ if (DBG) Rlog.d(TAG, msg);
+ if (logIntoLocalLog) {
+ mLocalLog.log(msg);
+ }
+ }
+
+ /**
+ * Print the DeviceStateMonitor into the given stream.
+ *
+ * @param fd The raw file descriptor that the dump is being sent to.
+ * @param pw A PrintWriter to which the dump is to be set.
+ * @param args Additional arguments to the dump request.
+ */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.increaseIndent();
+ ipw.println("mIsTetheringOn=" + mIsTetheringOn);
+ ipw.println("mIsScreenOn=" + mIsScreenOn);
+ ipw.println("mIsCharging=" + mIsCharging);
+ ipw.println("mIsPowerSaveOn=" + mIsPowerSaveOn);
+ ipw.println("mIsLowDataExpected=" + mIsLowDataExpected);
+ ipw.println("mUnsolicitedResponseFilter=" + mUnsolicitedResponseFilter);
+ ipw.println("Local logs:");
+ ipw.increaseIndent();
+ mLocalLog.dump(fd, ipw, args);
+ ipw.decreaseIndent();
+ ipw.decreaseIndent();
+ ipw.flush();
+ }
+}
diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
index f340e80..7c9e997 100755
--- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
@@ -24,19 +24,20 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
+import android.os.PersistableBundle;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.SystemProperties;
+import android.telephony.CarrierConfigManager;
import android.telephony.CellLocation;
import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import android.text.TextUtils;
-import java.util.Iterator;
-import android.telephony.Rlog;
import android.util.EventLog;
import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
@@ -44,8 +45,9 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.List;
import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
/**
* {@hide}
@@ -398,8 +400,7 @@
dialString = convertNumberIfNecessary(mPhone, dialString);
}
- String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
- boolean isPhoneInEcmMode = inEcm.equals("true");
+ boolean isPhoneInEcmMode = mPhone.isInEcm();
boolean isEmergencyCall =
PhoneNumberUtils.isLocalEmergencyNumber(mPhone.getContext(), dialString);
@@ -466,9 +467,17 @@
mPendingMO = new GsmCdmaConnection(mPhone,
checkForTestEmergencyNumber(dialString), this, mForegroundCall,
mIsInEmergencyCall);
- // Some network need a empty flash before sending the normal one
- m3WayCallFlashDelay = mPhone.getContext().getResources()
- .getInteger(com.android.internal.R.integer.config_cdma_3waycall_flash_delay);
+ // Some networks need an empty flash before sending the normal one
+ CarrierConfigManager configManager = (CarrierConfigManager)
+ mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ PersistableBundle bundle = configManager.getConfig();
+ if (bundle != null) {
+ m3WayCallFlashDelay =
+ bundle.getInt(CarrierConfigManager.KEY_CDMA_3WAYCALL_FLASH_DELAY_INT);
+ } else {
+ // The default 3-way call flash delay is 0s
+ m3WayCallFlashDelay = 0;
+ }
if (m3WayCallFlashDelay > 0) {
mCi.sendCDMAFeatureCode("", obtainMessage(EVENT_THREE_WAY_DIAL_BLANK_FLASH));
} else {
@@ -1090,10 +1099,10 @@
//dumpState();
}
- private void updateMetrics(GsmCdmaConnection []connections) {
+ private void updateMetrics(GsmCdmaConnection[] connections) {
ArrayList<GsmCdmaConnection> activeConnections = new ArrayList<>();
- for(GsmCdmaConnection conn : connections) {
- if(conn != null) activeConnections.add(conn);
+ for (GsmCdmaConnection conn : connections) {
+ if (conn != null) activeConnections.add(conn);
}
mMetrics.writeRilCallList(mPhone.getPhoneId(), activeConnections);
}
@@ -1283,7 +1292,7 @@
int count = call.mConnections.size();
for (int i = 0; i < count; i++) {
GsmCdmaConnection cn = (GsmCdmaConnection)call.mConnections.get(i);
- if (cn.getGsmCdmaIndex() == index) {
+ if (!cn.mDisconnected && cn.getGsmCdmaIndex() == index) {
mMetrics.writeRilHangup(mPhone.getPhoneId(), cn, cn.getGsmCdmaIndex());
mCi.hangupConnection(index, obtainCompleteMessage());
return;
@@ -1298,8 +1307,10 @@
int count = call.mConnections.size();
for (int i = 0; i < count; i++) {
GsmCdmaConnection cn = (GsmCdmaConnection)call.mConnections.get(i);
- mMetrics.writeRilHangup(mPhone.getPhoneId(), cn, cn.getGsmCdmaIndex());
- mCi.hangupConnection(cn.getGsmCdmaIndex(), obtainCompleteMessage());
+ if (!cn.mDisconnected) {
+ mMetrics.writeRilHangup(mPhone.getPhoneId(), cn, cn.getGsmCdmaIndex());
+ mCi.hangupConnection(cn.getGsmCdmaIndex(), obtainCompleteMessage());
+ }
}
} catch (CallStateException ex) {
Rlog.e(LOG_TAG, "hangupConnectionByIndex caught " + ex);
@@ -1311,7 +1322,7 @@
int count = call.mConnections.size();
for (int i = 0; i < count; i++) {
GsmCdmaConnection cn = (GsmCdmaConnection)call.mConnections.get(i);
- if (cn.getGsmCdmaIndex() == index) {
+ if (!cn.mDisconnected && cn.getGsmCdmaIndex() == index) {
return cn;
}
}
@@ -1548,11 +1559,11 @@
private void checkAndEnableDataCallAfterEmergencyCallDropped() {
if (mIsInEmergencyCall) {
mIsInEmergencyCall = false;
- String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+ boolean inEcm = mPhone.isInEcm();
if (Phone.DEBUG_PHONE) {
log("checkAndEnableDataCallAfterEmergencyCallDropped,inEcm=" + inEcm);
}
- if (inEcm.compareTo("false") == 0) {
+ if (!inEcm) {
// Re-initiate data connection
mPhone.mDcTracker.setInternalDataEnabled(true);
mPhone.notifyEmergencyCallRegistrants(false);
diff --git a/src/java/com/android/internal/telephony/GsmCdmaConnection.java b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
index 868955c..cfda75e 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaConnection.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
@@ -26,16 +26,15 @@
import android.os.SystemClock;
import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
-import android.telephony.Rlog;
import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.text.TextUtils;
import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
-import com.android.internal.telephony.uicc.UiccCardApplication;
-import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
+import com.android.internal.telephony.uicc.UiccCardApplication;
/**
* {@hide}
@@ -226,8 +225,7 @@
releaseAllWakeLocks();
}
- static boolean
- equalsHandlesNulls (Object a, Object b) {
+ static boolean equalsHandlesNulls(Object a, Object b) {
return (a == null) ? (b == null) : a.equals (b);
}
@@ -448,6 +446,9 @@
case CallFailCause.FDN_BLOCKED:
return DisconnectCause.FDN_BLOCKED;
+ case CallFailCause.IMEI_NOT_ACCEPTED:
+ return DisconnectCause.IMEI_NOT_ACCEPTED;
+
case CallFailCause.UNOBTAINABLE_NUMBER:
return DisconnectCause.UNOBTAINABLE_NUMBER;
@@ -805,13 +806,13 @@
protected void finalize()
{
/**
- * It is understood that This finializer is not guaranteed
+ * It is understood that This finalizer is not guaranteed
* to be called and the release lock call is here just in
* case there is some path that doesn't call onDisconnect
* and or onConnectedInOrOut.
*/
- if (mPartialWakeLock.isHeld()) {
- Rlog.e(LOG_TAG, "[GsmCdmaConn] UNEXPECTED; mPartialWakeLock is held when finalizing.");
+ if (mPartialWakeLock != null && mPartialWakeLock.isHeld()) {
+ Rlog.e(LOG_TAG, "UNEXPECTED; mPartialWakeLock is held when finalizing.");
}
clearPostDialListeners();
releaseWakeLock();
@@ -936,33 +937,37 @@
notifyPostDialListeners();
}
- private void
- createWakeLock(Context context) {
+ private void createWakeLock(Context context) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
}
- private void
- acquireWakeLock() {
- log("acquireWakeLock");
- mPartialWakeLock.acquire();
- }
-
- private void
- releaseWakeLock() {
- synchronized(mPartialWakeLock) {
- if (mPartialWakeLock.isHeld()) {
- log("releaseWakeLock");
- mPartialWakeLock.release();
+ private void acquireWakeLock() {
+ if (mPartialWakeLock != null) {
+ synchronized (mPartialWakeLock) {
+ log("acquireWakeLock");
+ mPartialWakeLock.acquire();
}
}
}
- private void
- releaseAllWakeLocks() {
- synchronized(mPartialWakeLock) {
- while (mPartialWakeLock.isHeld()) {
- mPartialWakeLock.release();
+ private void releaseWakeLock() {
+ if (mPartialWakeLock != null) {
+ synchronized (mPartialWakeLock) {
+ if (mPartialWakeLock.isHeld()) {
+ log("releaseWakeLock");
+ mPartialWakeLock.release();
+ }
+ }
+ }
+ }
+
+ private void releaseAllWakeLocks() {
+ if (mPartialWakeLock != null) {
+ synchronized (mPartialWakeLock) {
+ while (mPartialWakeLock.isHeld()) {
+ mPartialWakeLock.release();
+ }
}
}
}
@@ -983,8 +988,7 @@
// This function is to find the next PAUSE character index if
// multiple pauses in a row. Otherwise it finds the next non PAUSE or
// non WAIT character index.
- private static int
- findNextPCharOrNonPOrNonWCharIndex(String phoneNumber, int currIndex) {
+ private static int findNextPCharOrNonPOrNonWCharIndex(String phoneNumber, int currIndex) {
boolean wMatched = isWait(phoneNumber.charAt(currIndex));
int index = currIndex + 1;
int length = phoneNumber.length();
@@ -1011,12 +1015,12 @@
return index;
}
- //CDMA
+ // CDMA
// This function returns either PAUSE or WAIT character to append.
// It is based on the next non PAUSE/WAIT character in the phoneNumber and the
// index for the current PAUSE/WAIT character
- private static char
- findPOrWCharToAppend(String phoneNumber, int currPwIndex, int nextNonPwCharIndex) {
+ private static char findPOrWCharToAppend(String phoneNumber, int currPwIndex,
+ int nextNonPwCharIndex) {
char c = phoneNumber.charAt(currPwIndex);
char ret;
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 07afe0c..237a726 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -16,7 +16,19 @@
package com.android.internal.telephony;
-import android.app.ActivityManagerNative;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
+import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
+
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
@@ -33,8 +45,10 @@
import android.os.PowerManager;
import android.os.Registrant;
import android.os.RegistrantList;
+import android.os.ResultReceiver;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.WorkSource;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.provider.Telephony;
@@ -42,56 +56,46 @@
import android.telephony.CarrierConfigManager;
import android.telephony.CellLocation;
import android.telephony.PhoneNumberUtils;
+import android.telephony.Rlog;
import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-
+import android.telephony.UssdResponse;
import android.telephony.cdma.CdmaCellLocation;
import android.text.TextUtils;
-import android.telephony.Rlog;
import android.util.Log;
import com.android.ims.ImsManager;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
-import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.cdma.CdmaMmiCode;
import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.cdma.EriManager;
-import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.gsm.GsmMmiCode;
import com.android.internal.telephony.gsm.SuppServiceNotification;
+import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.test.SimulatedRadioControl;
import com.android.internal.telephony.uicc.IccCardProxy;
import com.android.internal.telephony.uicc.IccException;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.IccVmNotSupportedException;
+import com.android.internal.telephony.uicc.IsimRecords;
+import com.android.internal.telephony.uicc.IsimUiccRecords;
import com.android.internal.telephony.uicc.RuimRecords;
import com.android.internal.telephony.uicc.SIMRecords;
import com.android.internal.telephony.uicc.UiccCard;
import com.android.internal.telephony.uicc.UiccCardApplication;
import com.android.internal.telephony.uicc.UiccController;
-import com.android.internal.telephony.uicc.IsimRecords;
-import com.android.internal.telephony.uicc.IsimUiccRecords;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Deque;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
/**
* {@hide}
*/
@@ -124,14 +128,12 @@
// mEriFileLoadedRegistrants are informed after the ERI text has been loaded
private final RegistrantList mEriFileLoadedRegistrants = new RegistrantList();
// mEcmExitRespRegistrant is informed after the phone has been exited
- //the emergency callback mode
- //keep track of if phone is in emergency callback mode
- private boolean mIsPhoneInEcmState;
private Registrant mEcmExitRespRegistrant;
private String mEsn;
private String mMeid;
// string to define how the carrier specifies its own ota sp number
private String mCarrierOtaSpNumSchema;
+
// A runnable which is used to automatically exit from Ecm after a period of time.
private Runnable mExitEcmRunnable = new Runnable() {
@Override
@@ -155,6 +157,7 @@
public ServiceStateTracker mSST;
private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
+ private DeviceStateMonitor mDeviceStateMonitor;
private int mPrecisePhoneType;
@@ -207,6 +210,7 @@
// DcTracker uses SST so needs to be created after it is instantiated
mDcTracker = mTelephonyComponentFactory.makeDcTracker(this);
mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
+ mDeviceStateMonitor = mTelephonyComponentFactory.makeDeviceStateMonitor(this);
logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
}
@@ -279,8 +283,7 @@
} else {
mCdmaSubscriptionSource = CdmaSubscriptionSourceManager.SUBSCRIPTION_SOURCE_UNKNOWN;
// This is needed to handle phone process crashes
- String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
- mIsPhoneInEcmState = inEcm.equals("true");
+ mIsPhoneInEcmState = getInEcmMode();
if (mIsPhoneInEcmState) {
// Send a message which will invoke handleExitEmergencyCallbackMode
mCi.exitEmergencyCallbackMode(
@@ -384,7 +387,7 @@
@Override
protected void finalize() {
if(DBG) logd("GsmCdmaPhone finalized");
- if (mWakeLock.isHeld()) {
+ if (mWakeLock != null && mWakeLock.isHeld()) {
Rlog.e(LOG_TAG, "UNEXPECTED; mWakeLock is held when finalizing.");
mWakeLock.release();
}
@@ -409,9 +412,9 @@
}
@Override
- public CellLocation getCellLocation() {
+ public CellLocation getCellLocation(WorkSource workSource) {
if (isPhoneTypeGsm()) {
- return mSST.getCellLocation();
+ return mSST.getCellLocation(workSource);
} else {
CdmaCellLocation loc = (CdmaCellLocation)mSST.mCellLoc;
@@ -470,9 +473,8 @@
// get voice mail count from SIM
countVoiceMessages = r.getVoiceMessageCount();
}
- int countVoiceMessagesStored = getStoredVoiceMessageCount();
- if (countVoiceMessages == -1 && countVoiceMessagesStored != 0) {
- countVoiceMessages = countVoiceMessagesStored;
+ if (countVoiceMessages == IccRecords.DEFAULT_VOICE_MESSAGE_COUNT) {
+ countVoiceMessages = getStoredVoiceMessageCount();
}
logd("updateVoiceMail countVoiceMessages = " + countVoiceMessages
+ " subId " + getSubId());
@@ -630,7 +632,7 @@
Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
if (DBG) logd("sendEmergencyCallbackModeChange");
}
@@ -640,7 +642,7 @@
Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
intent.putExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, callActive);
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallStateChange: callActive " + callActive);
}
}
@@ -1057,7 +1059,7 @@
throw new CallStateException("Sending UUS information NOT supported in CDMA!");
}
- boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(dialString);
+ boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(getSubId(), dialString);
Phone imsPhone = mImsPhone;
CarrierConfigManager configManager =
@@ -1138,10 +1140,52 @@
}
}
+ /**
+ * @return {@code true} if the user should be informed of an attempt to dial an international
+ * number while on WFC only, {@code false} otherwise.
+ */
+ public boolean isNotificationOfWfcCallRequired(String dialString) {
+ CarrierConfigManager configManager =
+ (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ PersistableBundle config = configManager.getConfigForSubId(getSubId());
+
+ // Determine if carrier config indicates that international calls over WFC should trigger a
+ // notification to the user. This is controlled by carrier configuration and is off by
+ // default.
+ boolean shouldNotifyInternationalCallOnWfc = config != null
+ && config.getBoolean(
+ CarrierConfigManager.KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL);
+
+ if (!shouldNotifyInternationalCallOnWfc) {
+ return false;
+ }
+
+ Phone imsPhone = mImsPhone;
+ boolean isEmergency = PhoneNumberUtils.isEmergencyNumber(getSubId(), dialString);
+ boolean shouldConfirmCall =
+ // Using IMS
+ isImsUseEnabled()
+ && imsPhone != null
+ // VoLTE not available
+ && !imsPhone.isVolteEnabled()
+ // WFC is available
+ && imsPhone.isWifiCallingEnabled()
+ && !isEmergency
+ // Dialing international number
+ && PhoneNumberUtils.isInternationalNumber(dialString, getCountryIso());
+ return shouldConfirmCall;
+ }
+
@Override
protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
Bundle intentExtras)
throws CallStateException {
+ return dialInternal(dialString, uusInfo, videoState, intentExtras, null);
+ }
+
+ protected Connection dialInternal(String dialString, UUSInfo uusInfo, int videoState,
+ Bundle intentExtras, ResultReceiver wrappedCallback)
+ throws CallStateException {
// Need to make sure dialString gets parsed properly
String newDialString = PhoneNumberUtils.stripSeparators(dialString);
@@ -1154,9 +1198,9 @@
// Only look at the Network portion for mmi
String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
- GsmMmiCode mmi =
- GsmMmiCode.newFromDialString(networkPortion, this, mUiccApplication.get());
- if (DBG) logd("dialing w/ mmi '" + mmi + "'...");
+ GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this,
+ mUiccApplication.get(), wrappedCallback);
+ if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'...");
if (mmi == null) {
return mCT.dial(newDialString, uusInfo, intentExtras);
@@ -1165,13 +1209,7 @@
} else {
mPendingMMIs.add(mmi);
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
- try {
- mmi.processCode();
- } catch (CallStateException e) {
- //do nothing
- }
-
- // FIXME should this return null or something else?
+ mmi.processCode();
return null;
}
} else {
@@ -1179,7 +1217,7 @@
}
}
- @Override
+ @Override
public boolean handlePinMmi(String dialString) {
MmiCode mmi;
if (isPhoneTypeGsm()) {
@@ -1203,6 +1241,52 @@
return false;
}
+ private void sendUssdResponse(String ussdRequest, CharSequence message, int returnCode,
+ ResultReceiver wrappedCallback) {
+ UssdResponse response = new UssdResponse(ussdRequest, message);
+ Bundle returnData = new Bundle();
+ returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response);
+ wrappedCallback.send(returnCode, returnData);
+ }
+
+ @Override
+ public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback) {
+ if (!isPhoneTypeGsm() || mPendingMMIs.size() > 0) {
+ //todo: replace the generic failure with specific error code.
+ sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
+ wrappedCallback );
+ return true;
+ }
+
+ // Try over IMS if possible.
+ Phone imsPhone = mImsPhone;
+ if ((imsPhone != null)
+ && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
+ || imsPhone.isUtEnabled())) {
+ try {
+ logd("handleUssdRequest: attempting over IMS");
+ return imsPhone.handleUssdRequest(ussdRequest, wrappedCallback);
+ } catch (CallStateException cse) {
+ if (!CS_FALLBACK.equals(cse.getMessage())) {
+ return false;
+ }
+ // At this point we've tried over IMS but have been informed we need to handover
+ // back to GSM.
+ logd("handleUssdRequest: fallback to CS required");
+ }
+ }
+
+ // Try USSD over GSM.
+ try {
+ dialInternal(ussdRequest, null, VideoProfile.STATE_AUDIO_ONLY, null,
+ wrappedCallback);
+ } catch (Exception e) {
+ logd("handleUssdRequest: exception" + e);
+ return false;
+ }
+ return true;
+ }
+
@Override
public void sendUssdResponse(String ussdMessge) {
if (isPhoneTypeGsm()) {
@@ -1295,23 +1379,14 @@
}
if (TextUtils.isEmpty(number)) {
- String[] listArray = getContext().getResources()
- .getStringArray(com.android.internal.R.array.config_default_vm_number);
- if (listArray != null && listArray.length > 0) {
- for (int i=0; i<listArray.length; i++) {
- if (!TextUtils.isEmpty(listArray[i])) {
- String[] defaultVMNumberArray = listArray[i].split(";");
- if (defaultVMNumberArray != null && defaultVMNumberArray.length > 0) {
- if (defaultVMNumberArray.length == 1) {
- number = defaultVMNumberArray[0];
- } else if (defaultVMNumberArray.length == 2 &&
- !TextUtils.isEmpty(defaultVMNumberArray[1]) &&
- isMatchGid(defaultVMNumberArray[1])) {
- number = defaultVMNumberArray[0];
- break;
- }
- }
- }
+ CarrierConfigManager configManager = (CarrierConfigManager)
+ getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ PersistableBundle b = configManager.getConfig();
+ if (b != null) {
+ String defaultVmNumber =
+ b.getString(CarrierConfigManager.KEY_DEFAULT_VM_NUMBER_STRING);
+ if (!TextUtils.isEmpty(defaultVmNumber)) {
+ number = defaultVmNumber;
}
}
}
@@ -1411,12 +1486,7 @@
@Override
public String getMeid() {
- if (isPhoneTypeGsm()) {
- loge("[GsmCdmaPhone] getMeid() is a CDMA method");
- return "0";
- } else {
- return mMeid;
- }
+ return mMeid;
}
@Override
@@ -1729,9 +1799,9 @@
}
@Override
- public void getNeighboringCids(Message response) {
+ public void getNeighboringCids(Message response, WorkSource workSource) {
if (isPhoneTypeGsm()) {
- mCi.getNeighboringCids(response);
+ mCi.getNeighboringCids(response, workSource);
} else {
/*
* This is currently not implemented. At least as of June
@@ -1789,12 +1859,12 @@
@Override
public boolean getDataRoamingEnabled() {
- return mDcTracker.getDataOnRoamingEnabled();
+ return mDcTracker.getDataRoamingEnabled();
}
@Override
public void setDataRoamingEnabled(boolean enable) {
- mDcTracker.setDataOnRoamingEnabled(enable);
+ mDcTracker.setDataRoamingEnabled(enable);
}
@Override
@@ -1861,7 +1931,20 @@
*/
if (mPendingMMIs.remove(mmi) || (isPhoneTypeGsm() && (mmi.isUssdRequest() ||
((GsmMmiCode)mmi).isSsInfo()))) {
- mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
+
+ ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver();
+ if (receiverCallback != null) {
+ Rlog.i(LOG_TAG, "onMMIDone: invoking callback: " + mmi);
+ int returnCode = (mmi.getState() == MmiCode.State.COMPLETE) ?
+ TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE;
+ sendUssdResponse(mmi.getDialString(), mmi.getMessage(), returnCode,
+ receiverCallback );
+ } else {
+ Rlog.i(LOG_TAG, "onMMIDone: notifying registrants: " + mmi);
+ mMmiCompleteRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
+ }
+ } else {
+ Rlog.i(LOG_TAG, "onMMIDone: invalid response or already handled; ignoring: " + mmi);
}
}
@@ -1879,6 +1962,7 @@
}
private void onNetworkInitiatedUssd(MmiCode mmi) {
+ Rlog.v(LOG_TAG, "onNetworkInitiatedUssd: mmi=" + mmi);
mMmiCompleteRegistrants.notifyRegistrants(
new AsyncResult(null, mmi, null));
}
@@ -1923,19 +2007,18 @@
} else {
found.onUssdFinished(ussdMessage, isUssdRequest);
}
- } else { // pending USSD not found
+ } else if (!isUssdError && ussdMessage != null) {
+ // pending USSD not found
// The network may initiate its own USSD request
// ignore everything that isnt a Notify or a Request
// also, discard if there is no message to present
- if (!isUssdError && ussdMessage != null) {
- GsmMmiCode mmi;
- mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
+ GsmMmiCode mmi;
+ mmi = GsmMmiCode.newNetworkInitiatedUssd(ussdMessage,
isUssdRequest,
GsmCdmaPhone.this,
mUiccApplication.get());
- onNetworkInitiatedUssd(mmi);
- }
+ onNetworkInitiatedUssd(mmi);
}
}
@@ -1945,6 +2028,7 @@
private void syncClirSetting() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
int clirSetting = sp.getInt(CLIR_KEY + getPhoneId(), -1);
+ Rlog.i(LOG_TAG, "syncClirSetting: " + CLIR_KEY + getPhoneId() + "=" + clirSetting);
if (clirSetting >= 0) {
mCi.setCLIR(clirSetting, null);
}
@@ -1953,12 +2037,7 @@
private void handleRadioAvailable() {
mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
- if (isPhoneTypeGsm()) {
- mCi.getIMEI(obtainMessage(EVENT_GET_IMEI_DONE));
- mCi.getIMEISV(obtainMessage(EVENT_GET_IMEISV_DONE));
- } else {
- mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
- }
+ mCi.getDeviceIdentity(obtainMessage(EVENT_GET_DEVICE_IDENTITY_DONE));
mCi.getRadioCapability(obtainMessage(EVENT_GET_RADIO_CAPABILITY));
startLceAfterRadioIsAvailable();
}
@@ -2591,7 +2670,7 @@
if (isPhoneTypeGsm()) {
return false;
} else {
- return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
+ return mSST.getOtasp() != TelephonyManager.OTASP_NOT_NEEDED;
}
}
@@ -2665,6 +2744,10 @@
r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
} else {
r.registerForRecordsLoaded(this, EVENT_RUIM_RECORDS_LOADED, null);
+ if (isPhoneTypeCdmaLte()) {
+ // notify simRecordsLoaded registrants for cdmaLte phone
+ r.registerForRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
+ }
}
}
@@ -2700,9 +2783,9 @@
+ mIsPhoneInEcmState);
}
// if phone is not in Ecm mode, and it's changed to Ecm mode
- if (mIsPhoneInEcmState == false) {
- setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "true");
- mIsPhoneInEcmState = true;
+ if (!mIsPhoneInEcmState) {
+ setIsInEcm(true);
+
// notify change
sendEmergencyCallbackModeChange();
@@ -2732,8 +2815,7 @@
// if exiting ecm success
if (ar.exception == null) {
if (mIsPhoneInEcmState) {
- setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, "false");
- mIsPhoneInEcmState = false;
+ setIsInEcm(false);
}
// release wakeLock
@@ -3102,10 +3184,9 @@
// Send an Intent to the PhoneApp that we had a radio technology change
Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(PhoneConstants.PHONE_NAME_KEY, getPhoneName());
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
}
private void switchVoiceRadioTech(int newVoiceRadioTech) {
@@ -3189,6 +3270,9 @@
}
pw.flush();
pw.println("++++++++++++++++++++++++++++++++");
+ pw.println("DeviceStateMonitor:");
+ mDeviceStateMonitor.dump(fd, pw, args);
+ pw.println("++++++++++++++++++++++++++++++++");
}
@Override
@@ -3258,6 +3342,19 @@
return operatorNumeric;
}
+ /**
+ * @return The country ISO for the subscription associated with this phone.
+ */
+ public String getCountryIso() {
+ int subId = getSubId();
+ SubscriptionInfo subInfo = SubscriptionManager.from(getContext())
+ .getActiveSubscriptionInfo(subId);
+ if (subInfo == null) {
+ return null;
+ }
+ return subInfo.getCountryIso().toUpperCase();
+ }
+
public void notifyEcbmTimerReset(Boolean flag) {
mEcmTimerResetRegistrants.notifyResult(flag);
}
diff --git a/src/java/com/android/internal/telephony/HardwareConfig.java b/src/java/com/android/internal/telephony/HardwareConfig.java
index 0f855de..8623354 100644
--- a/src/java/com/android/internal/telephony/HardwareConfig.java
+++ b/src/java/com/android/internal/telephony/HardwareConfig.java
@@ -112,7 +112,7 @@
* default constructor.
*/
public HardwareConfig(int type) {
- type = type;
+ this.type = type;
}
/**
@@ -152,7 +152,7 @@
if (type == DEV_HARDWARE_TYPE_MODEM) {
char[] bits = Integer.toBinaryString(ratBits).toCharArray();
uuid = id;
- state = state;
+ this.state = state;
rilModel = model;
rat = new BitSet(bits.length);
for (int i = 0 ; i < bits.length ; i++) {
@@ -168,7 +168,7 @@
if (type == DEV_HARDWARE_TYPE_SIM) {
uuid = id;
modemUuid = link;
- state = state;
+ this.state = state;
}
}
diff --git a/src/java/com/android/internal/telephony/HbpcdUtils.java b/src/java/com/android/internal/telephony/HbpcdUtils.java
old mode 100755
new mode 100644
index acd31a6..2f31942
--- a/src/java/com/android/internal/telephony/HbpcdUtils.java
+++ b/src/java/com/android/internal/telephony/HbpcdUtils.java
@@ -16,17 +16,16 @@
package com.android.internal.telephony;
-import android.util.Log;
-import android.content.Context;
import android.content.ContentResolver;
+import android.content.Context;
import android.database.Cursor;
+import android.telephony.Rlog;
-import com.android.internal.telephony.HbpcdLookup;
+import com.android.internal.telephony.HbpcdLookup.ArbitraryMccSidMatch;
import com.android.internal.telephony.HbpcdLookup.MccIdd;
import com.android.internal.telephony.HbpcdLookup.MccLookup;
import com.android.internal.telephony.HbpcdLookup.MccSidConflicts;
import com.android.internal.telephony.HbpcdLookup.MccSidRange;
-import com.android.internal.telephony.HbpcdLookup.ArbitraryMccSidMatch;
public final class HbpcdUtils {
private static final String LOG_TAG = "HbpcdUtils";
@@ -55,16 +54,16 @@
if (c2 != null) {
int c2Counter = c2.getCount();
if (DBG) {
- Log.d(LOG_TAG, "Query unresolved arbitrary table, entries are " + c2Counter);
+ Rlog.d(LOG_TAG, "Query unresolved arbitrary table, entries are " + c2Counter);
}
if (c2Counter == 1) {
if (DBG) {
- Log.d(LOG_TAG, "Query Unresolved arbitrary returned the cursor " + c2 );
+ Rlog.d(LOG_TAG, "Query Unresolved arbitrary returned the cursor " + c2);
}
c2.moveToFirst();
tmpMcc = c2.getInt(0);
if (DBG) {
- Log.d(LOG_TAG, "MCC found in arbitrary_mcc_sid_match: " + tmpMcc);
+ Rlog.d(LOG_TAG, "MCC found in arbitrary_mcc_sid_match: " + tmpMcc);
}
c2.close();
return tmpMcc;
@@ -86,22 +85,25 @@
int c3Counter = c3.getCount();
if (c3Counter > 0) {
if (c3Counter > 1) {
- Log.w(LOG_TAG, "something wrong, get more results for 1 conflict SID: " + c3);
+ Rlog.w(LOG_TAG, "something wrong, get more results for 1 conflict SID: " + c3);
}
- if (DBG) Log.d(LOG_TAG, "Query conflict sid returned the cursor " + c3 );
+ if (DBG) Rlog.d(LOG_TAG, "Query conflict sid returned the cursor " + c3);
c3.moveToFirst();
tmpMcc = c3.getInt(0);
- if (DBG) Log.d(LOG_TAG,
- "MCC found in mcc_lookup_table. Return tmpMcc = " + tmpMcc);
- c3.close();
- if (isNitzTimeZone) {
- return tmpMcc;
- } else {
- // time zone is not accurate, it may get wrong mcc, ignore it.
- if (DBG) Log.d(LOG_TAG, "time zone is not accurate, mcc may be "
- + tmpMcc);
- return 0;
+ if (DBG) {
+ Rlog.d(LOG_TAG, "MCC found in mcc_lookup_table. Return tmpMcc = " + tmpMcc);
}
+ if (!isNitzTimeZone) {
+ // time zone is not accurate, it may get wrong mcc, ignore it.
+ if (DBG) {
+ Rlog.d(LOG_TAG, "time zone is not accurate, mcc may be " + tmpMcc);
+ }
+ tmpMcc = 0;
+ }
+ c3.close();
+ return tmpMcc;
+ } else {
+ c3.close();
}
}
@@ -113,18 +115,18 @@
null, null);
if (c5 != null) {
if (c5.getCount() > 0) {
- if (DBG) Log.d(LOG_TAG, "Query Range returned the cursor " + c5 );
+ if (DBG) Rlog.d(LOG_TAG, "Query Range returned the cursor " + c5);
c5.moveToFirst();
tmpMcc = c5.getInt(0);
- if (DBG) Log.d(LOG_TAG, "SID found in mcc_sid_range. Return tmpMcc = " + tmpMcc);
+ if (DBG) Rlog.d(LOG_TAG, "SID found in mcc_sid_range. Return tmpMcc = " + tmpMcc);
c5.close();
return tmpMcc;
}
c5.close();
}
- if (DBG) Log.d(LOG_TAG, "SID NOT found in mcc_sid_range.");
+ if (DBG) Rlog.d(LOG_TAG, "SID NOT found in mcc_sid_range.");
- if (DBG) Log.d(LOG_TAG, "Exit getMccByOtherFactors. Return tmpMcc = " + tmpMcc );
+ if (DBG) Rlog.d(LOG_TAG, "Exit getMccByOtherFactors. Return tmpMcc = " + tmpMcc);
// If unknown MCC still could not be resolved,
return tmpMcc;
}
@@ -133,7 +135,7 @@
* Gets country information with given MCC.
*/
public String getIddByMcc(int mcc) {
- if (DBG) Log.d(LOG_TAG, "Enter getHbpcdInfoByMCC.");
+ if (DBG) Rlog.d(LOG_TAG, "Enter getHbpcdInfoByMCC.");
String idd = "";
Cursor c = null;
@@ -143,19 +145,19 @@
MccIdd.MCC + "=" + mcc, null, null);
if (cur != null) {
if (cur.getCount() > 0) {
- if (DBG) Log.d(LOG_TAG, "Query Idd returned the cursor " + cur );
+ if (DBG) Rlog.d(LOG_TAG, "Query Idd returned the cursor " + cur);
// TODO: for those country having more than 1 IDDs, need more information
// to decide which IDD would be used. currently just use the first 1.
cur.moveToFirst();
idd = cur.getString(0);
- if (DBG) Log.d(LOG_TAG, "IDD = " + idd);
+ if (DBG) Rlog.d(LOG_TAG, "IDD = " + idd);
}
cur.close();
}
if (c != null) c.close();
- if (DBG) Log.d(LOG_TAG, "Exit getHbpcdInfoByMCC.");
+ if (DBG) Rlog.d(LOG_TAG, "Exit getHbpcdInfoByMCC.");
return idd;
}
}
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 6b32498..0fc08c6 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -25,6 +25,8 @@
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
@@ -32,9 +34,9 @@
import android.os.Binder;
import android.os.Handler;
import android.os.Message;
-import android.os.Process;
import android.os.UserManager;
import android.provider.Telephony;
+import android.service.carrier.CarrierMessagingService;
import android.telephony.Rlog;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
@@ -446,8 +448,7 @@
return;
}
if (!persistMessageForNonDefaultSmsApp) {
- // Only allow carrier app or phone process to skip auto message persistence.
- enforceCarrierOrPhonePrivilege();
+ enforcePrivilegedAppPermissions();
}
destAddr = filterDestAddress(destAddr);
mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
@@ -465,7 +466,7 @@
* the same time an SMS received from radio is acknowledged back.
*/
public void injectSmsPdu(byte[] pdu, String format, PendingIntent receivedIntent) {
- enforceCarrierPrivilege();
+ enforcePrivilegedAppPermissions();
if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
log("pdu: " + pdu +
"\n format=" + format +
@@ -507,8 +508,8 @@
Manifest.permission.SEND_SMS,
"Sending SMS message");
if (!persistMessageForNonDefaultSmsApp) {
- // Only allow carrier app to skip auto message persistence.
- enforceCarrierPrivilege();
+ // Only allow carrier app or carrier ims to skip auto message persistence.
+ enforcePrivilegedAppPermissions();
}
if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
int i = 0;
@@ -603,9 +604,9 @@
protected byte[] makeSmsRecordData(int status, byte[] pdu) {
byte[] data;
if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) {
- data = new byte[IccConstants.SMS_RECORD_LENGTH];
+ data = new byte[SmsManager.SMS_RECORD_LENGTH];
} else {
- data = new byte[IccConstants.CDMA_SMS_RECORD_LENGTH];
+ data = new byte[SmsManager.CDMA_SMS_RECORD_LENGTH];
}
// Status bits for this record. See TS 51.011 10.5.3
@@ -1115,11 +1116,36 @@
}
}
- private void enforceCarrierOrPhonePrivilege() {
- int callingUid = Binder.getCallingUid();
- if (callingUid != Process.PHONE_UID) {
- enforceCarrierPrivilege();
+ /**
+ * Enforces that the caller has {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ * permission or is one of the following apps:
+ * <ul>
+ * <li> IMS App
+ * <li> Carrier App
+ * </ul>
+ */
+ private void enforcePrivilegedAppPermissions() {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ == PackageManager.PERMISSION_GRANTED) {
+ return;
}
+
+ int callingUid = Binder.getCallingUid();
+ String carrierImsPackage = CarrierSmsUtils.getCarrierImsPackageForIntent(mContext, mPhone,
+ new Intent(CarrierMessagingService.SERVICE_INTERFACE));
+ try {
+ if (carrierImsPackage != null
+ && callingUid == mContext.getPackageManager().getPackageUid(
+ carrierImsPackage, 0)) {
+ return;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ if (Rlog.isLoggable("SMS", Log.DEBUG)) {
+ log("Cannot find configured carrier ims package");
+ }
+ }
+
+ enforceCarrierPrivilege();
}
private String filterDestAddress(String destAddr) {
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index b7eb32a..a9bada9 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -20,7 +20,7 @@
import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
import android.app.Activity;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
import android.app.Notification;
@@ -36,13 +36,10 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.database.Cursor;
import android.database.SQLException;
import android.net.Uri;
-import android.os.storage.StorageManager;
import android.os.AsyncResult;
import android.os.Binder;
import android.os.Build;
@@ -54,13 +51,10 @@
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.storage.StorageManager;
import android.provider.Telephony;
import android.provider.Telephony.Sms.Intents;
import android.service.carrier.CarrierMessagingService;
-import android.service.carrier.ICarrierMessagingCallback;
-import android.service.carrier.ICarrierMessagingService;
-import android.service.carrier.MessagePdu;
-import android.telephony.CarrierMessagingServiceManager;
import android.telephony.Rlog;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
@@ -70,14 +64,12 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.uicc.UiccCard;
-import com.android.internal.telephony.uicc.UiccController;
+import com.android.internal.telephony.util.NotificationChannelController;
import com.android.internal.util.HexDump;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import java.io.ByteArrayOutputStream;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@@ -142,8 +134,6 @@
public static final int DISPLAY_ADDRESS_COLUMN = 9;
public static final String SELECT_BY_ID = "_id=?";
- public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND " +
- "count=? AND deleted=0";
/** New SMS received as an AsyncResult. */
public static final int EVENT_NEW_SMS = 1;
@@ -653,6 +643,9 @@
// broadcast SMS_REJECTED_ACTION intent
Intent intent = new Intent(Intents.SMS_REJECTED_ACTION);
intent.putExtra("result", result);
+ // Allow registered broadcast receivers to get this intent even
+ // when they are in the background.
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mContext.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS);
}
acknowledgeLastIncomingSms(success, result, response);
@@ -774,7 +767,7 @@
// query for all segments and broadcast message if we have all the parts
String[] whereArgs = {address, refNumber, count};
cursor = mResolver.query(sRawUri, PDU_SEQUENCE_PORT_PROJECTION,
- SELECT_BY_REFERENCE, whereArgs, null);
+ tracker.getQueryForSegments(), whereArgs, null);
int cursorCount = cursor.getCount();
if (cursorCount < messageCount) {
@@ -954,7 +947,8 @@
.setDefaults(Notification.DEFAULT_ALL)
.setContentTitle(mContext.getString(R.string.new_sms_notification_title))
.setContentText(mContext.getString(R.string.new_sms_notification_content))
- .setContentIntent(intent);
+ .setContentIntent(intent)
+ .setChannelId(NotificationChannelController.CHANNEL_ID_SMS);
NotificationManager mNotificationManager =
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(
@@ -988,43 +982,15 @@
*/
private boolean filterSms(byte[][] pdus, int destPort,
InboundSmsTracker tracker, SmsBroadcastReceiver resultReceiver, boolean userUnlocked) {
- List<String> carrierPackages = null;
- UiccCard card = UiccController.getInstance().getUiccCard(mPhone.getPhoneId());
- if (card != null) {
- carrierPackages = card.getCarrierPackageNamesForIntent(
- mContext.getPackageManager(),
- new Intent(CarrierMessagingService.SERVICE_INTERFACE));
- } else {
- loge("UiccCard not initialized.");
- }
-
- if (carrierPackages != null && carrierPackages.size() == 1) {
- log("Found carrier package.");
- CarrierSmsFilter smsFilter = new CarrierSmsFilter(pdus, destPort,
- tracker.getFormat(), resultReceiver);
- CarrierSmsFilterCallback smsFilterCallback = new CarrierSmsFilterCallback(smsFilter,
- userUnlocked);
- smsFilter.filterSms(carrierPackages.get(0), smsFilterCallback);
+ CarrierServicesSmsFilterCallback filterCallback =
+ new CarrierServicesSmsFilterCallback(
+ pdus, destPort, tracker.getFormat(), resultReceiver, userUnlocked);
+ CarrierServicesSmsFilter carrierServicesFilter = new CarrierServicesSmsFilter(
+ mContext, mPhone, pdus, destPort, tracker.getFormat(), filterCallback, getName());
+ if (carrierServicesFilter.filter()) {
return true;
}
- // It is possible that carrier app is not present as a CarrierPackage, but instead as a
- // system app
- List<String> systemPackages =
- getSystemAppForIntent(new Intent(CarrierMessagingService.SERVICE_INTERFACE));
-
- if (systemPackages != null && systemPackages.size() == 1) {
- log("Found system package.");
- CarrierSmsFilter smsFilter = new CarrierSmsFilter(pdus, destPort,
- tracker.getFormat(), resultReceiver);
- CarrierSmsFilterCallback smsFilterCallback = new CarrierSmsFilterCallback(smsFilter,
- userUnlocked);
- smsFilter.filterSms(systemPackages.get(0), smsFilterCallback);
- return true;
- }
- logv("Unable to find carrier package: " + carrierPackages
- + ", nor systemPackages: " + systemPackages);
-
if (VisualVoicemailSmsFilter.filter(
mContext, pdus, tracker.getFormat(), destPort, mPhone.getSubId())) {
log("Visual voicemail SMS dropped");
@@ -1035,27 +1001,6 @@
return false;
}
- private List<String> getSystemAppForIntent(Intent intent) {
- List<String> packages = new ArrayList<String>();
- PackageManager packageManager = mContext.getPackageManager();
- List<ResolveInfo> receivers = packageManager.queryIntentServices(intent, 0);
- String carrierFilterSmsPerm = "android.permission.CARRIER_FILTER_SMS";
-
- for (ResolveInfo info : receivers) {
- if (info.serviceInfo == null) {
- loge("Can't get service information from " + info);
- continue;
- }
- String packageName = info.serviceInfo.packageName;
- if (packageManager.checkPermission(carrierFilterSmsPerm, packageName) ==
- packageManager.PERMISSION_GRANTED) {
- packages.add(packageName);
- if (DBG) log("getSystemAppForIntent: added package "+ packageName);
- }
- }
- return packages;
- }
-
/**
* Dispatch the intent with the specified permission, appOp, and result receiver, using
* this state machine's handler thread to run the result receiver.
@@ -1086,7 +1031,7 @@
// Get a list of currently started users.
int[] users = null;
try {
- users = ActivityManagerNative.getDefault().getRunningUserIds();
+ users = ActivityManager.getService().getRunningUserIds();
} catch (RemoteException re) {
}
if (users == null) {
@@ -1155,7 +1100,8 @@
}
/**
- * Creates and dispatches the intent to the default SMS app or the appropriate port.
+ * Creates and dispatches the intent to the default SMS app, appropriate port or via the {@link
+ * AppSmsManager}.
*
* @param pdus message pdus
* @param format the message format, typically "3gpp" or "3gpp2"
@@ -1163,7 +1109,7 @@
* @param resultReceiver the receiver handling the delivery result
*/
private void dispatchSmsDeliveryIntent(byte[][] pdus, String format, int destPort,
- BroadcastReceiver resultReceiver) {
+ SmsBroadcastReceiver resultReceiver) {
Intent intent = new Intent();
intent.putExtra("pdus", pdus);
intent.putExtra("format", format);
@@ -1191,11 +1137,22 @@
intent.putExtra("uri", uri.toString());
}
}
+
+ // Handle app specific sms messages.
+ AppSmsManager appManager = mPhone.getAppSmsManager();
+ if (appManager.handleSmsReceivedIntent(intent)) {
+ // The AppSmsManager handled this intent, we're done.
+ dropSms(resultReceiver);
+ return;
+ }
} else {
intent.setAction(Intents.DATA_SMS_RECEIVED_ACTION);
Uri uri = Uri.parse("sms://localhost:" + destPort);
intent.setData(uri);
intent.setComponent(null);
+ // Allow registered broadcast receivers to get this intent even
+ // when they are in the background.
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
}
Bundle options = handleSmsWhitelisting(intent.getComponent());
@@ -1226,9 +1183,8 @@
} else {
// for multi-part messages, deduping should also be done against undeleted
// segments that can cause ambiguity when contacenating the segments, that is,
- // segments with same address, reference_number, count and sequence
- where = "address=? AND reference_number=? AND count=? AND sequence=? AND " +
- "((date=? AND message_body=?) OR deleted=0)";
+ // segments with same address, reference_number, count, sequence and message type.
+ where = tracker.getQueryForMultiPartDuplicates();
}
Cursor cursor = null;
@@ -1305,7 +1261,7 @@
} else {
// set the delete selection args for multi-part message
String[] deleteWhereArgs = {address, refNumber, count};
- tracker.setDeleteWhere(SELECT_BY_REFERENCE, deleteWhereArgs);
+ tracker.setDeleteWhere(tracker.getQueryForSegments(), deleteWhereArgs);
}
return Intents.RESULT_SMS_HANDLED;
} catch (Exception e) {
@@ -1344,15 +1300,23 @@
if (action.equals(Intents.SMS_DELIVER_ACTION)) {
// Now dispatch the notification only intent
intent.setAction(Intents.SMS_RECEIVED_ACTION);
+ // Allow registered broadcast receivers to get this intent even
+ // when they are in the background.
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
intent.setComponent(null);
// All running users will be notified of the received sms.
Bundle options = handleSmsWhitelisting(null);
+
dispatchIntent(intent, android.Manifest.permission.RECEIVE_SMS,
- AppOpsManager.OP_RECEIVE_SMS, options, this, UserHandle.ALL);
+ AppOpsManager.OP_RECEIVE_SMS,
+ options, this, UserHandle.ALL);
} else if (action.equals(Intents.WAP_PUSH_DELIVER_ACTION)) {
// Now dispatch the notification only intent
intent.setAction(Intents.WAP_PUSH_RECEIVED_ACTION);
intent.setComponent(null);
+ // Allow registered broadcast receivers to get this intent even
+ // when they are in the background.
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
// Only the primary user will receive notification of incoming mms.
// That app will do the actual downloading of the mms.
Bundle options = null;
@@ -1400,131 +1364,53 @@
}
/**
- * Asynchronously binds to the carrier messaging service, and filters out the message if
- * instructed to do so by the carrier messaging service. A new instance must be used for every
- * message.
+ * Callback that handles filtering results by carrier services.
*/
- private final class CarrierSmsFilter extends CarrierMessagingServiceManager {
+ private final class CarrierServicesSmsFilterCallback implements
+ CarrierServicesSmsFilter.CarrierServicesSmsFilterCallbackInterface {
private final byte[][] mPdus;
private final int mDestPort;
private final String mSmsFormat;
private final SmsBroadcastReceiver mSmsBroadcastReceiver;
- // Instantiated in filterSms.
- private volatile CarrierSmsFilterCallback mSmsFilterCallback;
+ private final boolean mUserUnlocked;
- CarrierSmsFilter(byte[][] pdus, int destPort, String smsFormat,
- SmsBroadcastReceiver smsBroadcastReceiver) {
+ CarrierServicesSmsFilterCallback(byte[][] pdus, int destPort, String smsFormat,
+ SmsBroadcastReceiver smsBroadcastReceiver, boolean userUnlocked) {
mPdus = pdus;
mDestPort = destPort;
mSmsFormat = smsFormat;
mSmsBroadcastReceiver = smsBroadcastReceiver;
- }
-
- /**
- * Attempts to bind to a {@link ICarrierMessagingService}. Filtering is initiated
- * asynchronously once the service is ready using {@link #onServiceReady}.
- */
- void filterSms(String carrierPackageName, CarrierSmsFilterCallback smsFilterCallback) {
- mSmsFilterCallback = smsFilterCallback;
- if (!bindToCarrierMessagingService(mContext, carrierPackageName)) {
- loge("bindService() for carrier messaging service failed");
- smsFilterCallback.onFilterComplete(CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
- } else {
- logv("bindService() for carrier messaging service succeeded");
- }
- }
-
- /**
- * Invokes the {@code carrierMessagingService} to filter messages. The filtering result is
- * delivered to {@code smsFilterCallback}.
- */
- @Override
- protected void onServiceReady(ICarrierMessagingService carrierMessagingService) {
- try {
- carrierMessagingService.filterSms(
- new MessagePdu(Arrays.asList(mPdus)), mSmsFormat, mDestPort,
- mPhone.getSubId(), mSmsFilterCallback);
- } catch (RemoteException e) {
- loge("Exception filtering the SMS: " + e);
- mSmsFilterCallback.onFilterComplete(
- CarrierMessagingService.RECEIVE_OPTIONS_DEFAULT);
- }
- }
- }
-
- /**
- * A callback used to notify the platform of the carrier messaging app filtering result. Once
- * the result is ready, the carrier messaging service connection is disposed.
- */
- private final class CarrierSmsFilterCallback extends ICarrierMessagingCallback.Stub {
- private final CarrierSmsFilter mSmsFilter;
- private final boolean mUserUnlocked;
-
- CarrierSmsFilterCallback(CarrierSmsFilter smsFilter, boolean userUnlocked) {
- mSmsFilter = smsFilter;
mUserUnlocked = userUnlocked;
}
- /**
- * This method should be called only once.
- */
@Override
public void onFilterComplete(int result) {
- mSmsFilter.disposeConnection(mContext);
- // Calling identity was the CarrierMessagingService in this callback, change it back to
- // ours. This is required for dropSms() and VisualVoicemailSmsFilter.filter().
- long token = Binder.clearCallingIdentity();
- try {
- logv("onFilterComplete: result is " + result);
- if ((result & CarrierMessagingService.RECEIVE_OPTIONS_DROP) == 0) {
- if (VisualVoicemailSmsFilter.filter(mContext, mSmsFilter.mPdus,
- mSmsFilter.mSmsFormat, mSmsFilter.mDestPort, mPhone.getSubId())) {
- log("Visual voicemail SMS dropped");
- dropSms(mSmsFilter.mSmsBroadcastReceiver);
- return;
- }
-
- if (mUserUnlocked) {
- dispatchSmsDeliveryIntent(mSmsFilter.mPdus, mSmsFilter.mSmsFormat,
- mSmsFilter.mDestPort, mSmsFilter.mSmsBroadcastReceiver);
- } else {
- // Don't do anything further, leave the message in the raw table if the
- // credential-encrypted storage is still locked and show the new message
- // notification if the message is visible to the user.
- if (!isSkipNotifyFlagSet(result)) {
- showNewMessageNotification();
- }
- sendMessage(EVENT_BROADCAST_COMPLETE);
- }
- } else {
- // Drop this SMS.
- dropSms(mSmsFilter.mSmsBroadcastReceiver);
+ logv("onFilterComplete: result is " + result);
+ if ((result & CarrierMessagingService.RECEIVE_OPTIONS_DROP) == 0) {
+ if (VisualVoicemailSmsFilter.filter(mContext, mPdus,
+ mSmsFormat, mDestPort, mPhone.getSubId())) {
+ log("Visual voicemail SMS dropped");
+ dropSms(mSmsBroadcastReceiver);
+ return;
}
- } finally {
- // return back to the CarrierMessagingService, restore the calling identity.
- Binder.restoreCallingIdentity(token);
+
+ if (mUserUnlocked) {
+ dispatchSmsDeliveryIntent(
+ mPdus, mSmsFormat, mDestPort, mSmsBroadcastReceiver);
+ } else {
+ // Don't do anything further, leave the message in the raw table if the
+ // credential-encrypted storage is still locked and show the new message
+ // notification if the message is visible to the user.
+ if (!isSkipNotifyFlagSet(result)) {
+ showNewMessageNotification();
+ }
+ sendMessage(EVENT_BROADCAST_COMPLETE);
+ }
+ } else {
+ // Drop this SMS.
+ dropSms(mSmsBroadcastReceiver);
}
}
-
- @Override
- public void onSendSmsComplete(int result, int messageRef) {
- loge("Unexpected onSendSmsComplete call with result: " + result);
- }
-
- @Override
- public void onSendMultipartSmsComplete(int result, int[] messageRefs) {
- loge("Unexpected onSendMultipartSmsComplete call with result: " + result);
- }
-
- @Override
- public void onSendMmsComplete(int result, byte[] sendConfPdu) {
- loge("Unexpected onSendMmsComplete call with result: " + result);
- }
-
- @Override
- public void onDownloadMmsComplete(int result) {
- loge("Unexpected onDownloadMmsComplete call with result: " + result);
- }
}
private void dropSms(SmsBroadcastReceiver receiver) {
diff --git a/src/java/com/android/internal/telephony/InboundSmsTracker.java b/src/java/com/android/internal/telephony/InboundSmsTracker.java
index 9db83ab..c63ccc8 100644
--- a/src/java/com/android/internal/telephony/InboundSmsTracker.java
+++ b/src/java/com/android/internal/telephony/InboundSmsTracker.java
@@ -19,6 +19,7 @@
import android.content.ContentValues;
import android.database.Cursor;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import java.util.Arrays;
@@ -59,21 +60,47 @@
*/
private final String mDisplayAddress;
+ @VisibleForTesting
/** Destination port flag bit for no destination port. */
- private static final int DEST_PORT_FLAG_NO_PORT = (1 << 16);
+ public static final int DEST_PORT_FLAG_NO_PORT = (1 << 16);
/** Destination port flag bit to indicate 3GPP format message. */
private static final int DEST_PORT_FLAG_3GPP = (1 << 17);
+ @VisibleForTesting
/** Destination port flag bit to indicate 3GPP2 format message. */
- private static final int DEST_PORT_FLAG_3GPP2 = (1 << 18);
+ public static final int DEST_PORT_FLAG_3GPP2 = (1 << 18);
+ @VisibleForTesting
/** Destination port flag bit to indicate 3GPP2 format WAP message. */
- private static final int DEST_PORT_FLAG_3GPP2_WAP_PDU = (1 << 19);
+ public static final int DEST_PORT_FLAG_3GPP2_WAP_PDU = (1 << 19);
/** Destination port mask (16-bit unsigned value on GSM and CDMA). */
private static final int DEST_PORT_MASK = 0xffff;
+ @VisibleForTesting
+ public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND "
+ + "count=? AND (destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU
+ + "=0) AND deleted=0";
+
+ @VisibleForTesting
+ public static final String SELECT_BY_REFERENCE_3GPP2WAP = "address=? AND reference_number=? "
+ + "AND count=? AND (destination_port & "
+ + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=" + DEST_PORT_FLAG_3GPP2_WAP_PDU + ") AND deleted=0";
+
+ @VisibleForTesting
+ public static final String SELECT_BY_DUPLICATE_REFERENCE = "address=? AND "
+ + "reference_number=? AND count=? AND sequence=? AND "
+ + "((date=? AND message_body=?) OR deleted=0) AND (destination_port & "
+ + DEST_PORT_FLAG_3GPP2_WAP_PDU + "=0)";
+
+ @VisibleForTesting
+ public static final String SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP = "address=? AND "
+ + "reference_number=? " + "AND count=? AND sequence=? AND "
+ + "((date=? AND message_body=?) OR deleted=0) AND "
+ + "(destination_port & " + DEST_PORT_FLAG_3GPP2_WAP_PDU + "="
+ + DEST_PORT_FLAG_3GPP2_WAP_PDU + ")";
+
/**
* Create a tracker for a single-part SMS.
*
@@ -190,7 +217,7 @@
+ " of " + mMessageCount);
}
- mDeleteWhere = InboundSmsHandler.SELECT_BY_REFERENCE;
+ mDeleteWhere = getQueryForSegments();
mDeleteWhereArgs = new String[]{mAddress,
Integer.toString(mReferenceNumber), Integer.toString(mMessageCount)};
}
@@ -293,6 +320,15 @@
return mIs3gpp2 ? SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP;
}
+ public String getQueryForSegments() {
+ return mIs3gpp2WapPdu ? SELECT_BY_REFERENCE_3GPP2WAP : SELECT_BY_REFERENCE;
+ }
+
+ public String getQueryForMultiPartDuplicates() {
+ return mIs3gpp2WapPdu ? SELECT_BY_DUPLICATE_REFERENCE_3GPP2WAP :
+ SELECT_BY_DUPLICATE_REFERENCE;
+ }
+
/**
* Sequence numbers for concatenated messages start at 1. The exception is CDMA WAP PDU
* messages, which use a 0-based index.
diff --git a/src/java/com/android/internal/telephony/MccTable.java b/src/java/com/android/internal/telephony/MccTable.java
index 0ee153c..51ae81e 100644
--- a/src/java/com/android/internal/telephony/MccTable.java
+++ b/src/java/com/android/internal/telephony/MccTable.java
@@ -16,7 +16,7 @@
package com.android.internal.telephony;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -28,6 +28,12 @@
import android.text.TextUtils;
import android.util.Slog;
+import com.android.internal.app.LocaleStore;
+import com.android.internal.app.LocaleStore.LocaleInfo;
+
+import libcore.icu.ICU;
+import libcore.icu.TimeZoneNames;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -36,9 +42,6 @@
import java.util.Locale;
import java.util.Map;
-import libcore.icu.ICU;
-import libcore.icu.TimeZoneNames;
-
/**
* Mobile Country Code
*
@@ -94,7 +97,21 @@
Locale locale = new Locale("", entry.mIso);
String[] tz = TimeZoneNames.forLocale(locale);
if (tz.length == 0) return null;
- return tz[0];
+
+ String zoneName = tz[0];
+
+ /* Use Australia/Sydney instead of Australia/Lord_Howe for Australia.
+ * http://b/33228250
+ * Todo: remove the code, see b/62418027
+ */
+ if (mcc == 505 /* Australia / Norfolk Island */) {
+ for (String zone : tz) {
+ if (zone.contains("Sydney")) {
+ zoneName = zone;
+ }
+ }
+ }
+ return zoneName;
}
/**
@@ -211,7 +228,7 @@
if (updateConfig) {
Slog.d(LOG_TAG, "updateMccMncConfiguration updateConfig config=" + config);
- ActivityManagerNative.getDefault().updateConfiguration(config);
+ ActivityManager.getService().updateConfiguration(config);
} else {
Slog.d(LOG_TAG, "updateMccMncConfiguration nothing to update");
}
@@ -235,21 +252,21 @@
static {
// If we have English (without a country) explicitly prioritize en_US. http://b/28998094
FALLBACKS.put(Locale.ENGLISH, Locale.US);
- FALLBACKS.put(Locale.CANADA, Locale.US);
}
/**
- * Find the best match we actually have a localization for. This function assumes we
- * couldn't find an exact match.
+ * Finds a suitable locale among {@code candidates} to use as the fallback locale for
+ * {@code target}. This looks through the list of {@link #FALLBACKS}, and follows the chain
+ * until a locale in {@code candidates} is found.
+ * This function assumes that {@code target} is not in {@code candidates}.
*
* TODO: This should really follow the CLDR chain of parent locales! That might be a bit
* of a problem because we don't really have an en-001 locale on android.
+ *
+ * @return The fallback locale or {@code null} if there is no suitable fallback defined in the
+ * lookup.
*/
- private static Locale chooseBestFallback(Locale target, List<Locale> candidates) {
- if (candidates.isEmpty()) {
- return null;
- }
-
+ private static Locale lookupFallback(Locale target, List<Locale> candidates) {
Locale fallback = target;
while ((fallback = FALLBACKS.get(fallback)) != null) {
if (candidates.contains(fallback)) {
@@ -257,11 +274,7 @@
}
}
- // Somewhat arbitrarily take the first locale for the language,
- // unless we get a perfect match later. Note that these come back in no
- // particular order, so there's no reason to think the first match is
- // a particularly good match.
- return candidates.get(0);
+ return null;
}
/**
@@ -314,14 +327,40 @@
}
}
- Locale bestMatch = chooseBestFallback(target, languageMatches);
+ if (languageMatches.isEmpty()) {
+ Slog.d(LOG_TAG, "getLocaleForLanguageCountry: no locales for language " + language);
+ return null;
+ }
+
+ Locale bestMatch = lookupFallback(target, languageMatches);
if (bestMatch != null) {
- Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got a language-only match: " +
- bestMatch.toLanguageTag());
+ Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got a fallback match: "
+ + bestMatch.toLanguageTag());
return bestMatch;
} else {
- Slog.d(LOG_TAG, "getLocaleForLanguageCountry: no locales for language " +
- language);
+ // Ask {@link LocaleStore} whether this locale is considered "translated".
+ // LocaleStore has a broader definition of translated than just the asset locales
+ // above: a locale is "translated" if it has translation assets, or another locale
+ // with the same language and script has translation assets.
+ // If a locale is "translated", it is selectable in setup wizard, and can therefore
+ // be considerd a valid result for this method.
+ if (!TextUtils.isEmpty(target.getCountry())) {
+ LocaleStore.fillCache(context);
+ LocaleInfo targetInfo = LocaleStore.getLocaleInfo(target);
+ if (targetInfo.isTranslated()) {
+ Slog.d(LOG_TAG, "getLocaleForLanguageCountry: "
+ + "target locale is translated: " + target);
+ return target;
+ }
+ }
+
+ // Somewhat arbitrarily take the first locale for the language,
+ // unless we get a perfect match later. Note that these come back in no
+ // particular order, so there's no reason to think the first match is
+ // a particularly good match.
+ Slog.d(LOG_TAG, "getLocaleForLanguageCountry: got language-only match: "
+ + language);
+ return languageMatches.get(0);
}
} catch (Exception e) {
Slog.d(LOG_TAG, "getLocaleForLanguageCountry: exception", e);
@@ -344,7 +383,7 @@
AlarmManager alarm =
(AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.setTimeZone(zoneId);
- Slog.d(LOG_TAG, "timezone set to "+zoneId);
+ Slog.d(LOG_TAG, "timezone set to " + zoneId);
}
}
}
@@ -359,7 +398,8 @@
* @return locale for the mcc or null if none
*/
public static Locale getLocaleFromMcc(Context context, int mcc, String simLanguage) {
- String language = (simLanguage == null) ? MccTable.defaultLanguageForMcc(mcc) : simLanguage;
+ boolean hasSimLanguage = !TextUtils.isEmpty(simLanguage);
+ String language = hasSimLanguage ? simLanguage : MccTable.defaultLanguageForMcc(mcc);
String country = MccTable.countryCodeForMcc(mcc);
Slog.d(LOG_TAG, "getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
@@ -367,10 +407,10 @@
// If we couldn't find a locale that matches the SIM language, give it a go again
// with the "likely" language for the given country.
- if (locale == null && simLanguage != null) {
+ if (locale == null && hasSimLanguage) {
language = MccTable.defaultLanguageForMcc(mcc);
Slog.d(LOG_TAG, "[retry ] getLocaleFromMcc(" + language + ", " + country + ", " + mcc);
- return getLocaleForLanguageCountry(context, null, country);
+ return getLocaleForLanguageCountry(context, language, country);
}
return locale;
@@ -423,7 +463,7 @@
sTable.add(new MccEntry(225,"va",2)); //Vatican City State
sTable.add(new MccEntry(226,"ro",2)); //Romania
sTable.add(new MccEntry(228,"ch",2)); //Switzerland (Confederation of)
- sTable.add(new MccEntry(230,"cz",2)); //Czech Republic
+ sTable.add(new MccEntry(230,"cz",2)); //Czechia
sTable.add(new MccEntry(231,"sk",2)); //Slovak Republic
sTable.add(new MccEntry(232,"at",2)); //Austria
sTable.add(new MccEntry(234,"gb",2)); //United Kingdom of Great Britain and Northern Ireland
diff --git a/src/java/com/android/internal/telephony/MmiCode.java b/src/java/com/android/internal/telephony/MmiCode.java
index ae55e15..0adf83f 100644
--- a/src/java/com/android/internal/telephony/MmiCode.java
+++ b/src/java/com/android/internal/telephony/MmiCode.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony;
+import android.os.ResultReceiver;
+
/**
* {@hide}
*/
@@ -75,4 +77,13 @@
*/
void processCode() throws CallStateException;
+ /**
+ * @return the Receiver for the Ussd Callback.
+ */
+ public ResultReceiver getUssdCallbackReceiver();
+
+ /**
+ * @return the dialString.
+ */
+ public String getDialString();
}
diff --git a/src/java/com/android/internal/telephony/OemHookIndication.java b/src/java/com/android/internal/telephony/OemHookIndication.java
new file mode 100644
index 0000000..122a70e
--- /dev/null
+++ b/src/java/com/android/internal/telephony/OemHookIndication.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2017 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.hardware.radio.deprecated.V1_0.IOemHookIndication;
+import android.os.AsyncResult;
+
+import java.util.ArrayList;
+
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_OEM_HOOK_RAW;
+
+/**
+ * Class containing oem hook indication callbacks
+ */
+public class OemHookIndication extends IOemHookIndication.Stub {
+ RIL mRil;
+
+ public OemHookIndication(RIL ril) {
+ mRil = ril;
+ }
+
+ /**
+ * @param indicationType RadioIndicationType
+ * @param data Data sent by oem
+ */
+ public void oemHookRaw(int indicationType, ArrayList<Byte> data) {
+ mRil.processIndication(indicationType);
+
+ byte[] response = RIL.arrayListToPrimitiveArray(data);
+ if (RIL.RILJ_LOGD) {
+ mRil.unsljLogvRet(RIL_UNSOL_OEM_HOOK_RAW,
+ com.android.internal.telephony.uicc.IccUtils.bytesToHexString(response));
+ }
+
+ if (mRil.mUnsolOemHookRawRegistrant != null) {
+ mRil.mUnsolOemHookRawRegistrant.notifyRegistrant(new AsyncResult(null, response, null));
+ }
+ }
+}
diff --git a/src/java/com/android/internal/telephony/OemHookResponse.java b/src/java/com/android/internal/telephony/OemHookResponse.java
new file mode 100644
index 0000000..0afeac8
--- /dev/null
+++ b/src/java/com/android/internal/telephony/OemHookResponse.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (C) 2017 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.hardware.radio.deprecated.V1_0.IOemHookResponse;
+import android.hardware.radio.V1_0.RadioError;
+import android.hardware.radio.V1_0.RadioResponseInfo;
+
+import java.util.ArrayList;
+
+/**
+ * Class containing oem hook response callbacks
+ */
+public class OemHookResponse extends IOemHookResponse.Stub {
+ RIL mRil;
+
+ public OemHookResponse(RIL ril) {
+ mRil = ril;
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ * @param data Data returned by oem
+ */
+ public void sendRequestRawResponse(RadioResponseInfo responseInfo, ArrayList<Byte> data) {
+ RILRequest rr = mRil.processResponse(responseInfo);
+
+ if (rr != null) {
+ byte[] ret = null;
+ if (responseInfo.error == RadioError.NONE) {
+ ret = RIL.arrayListToPrimitiveArray(data);
+ RadioResponse.sendMessageResponse(rr.mResult, ret);
+ }
+ mRil.processResponseDone(rr, responseInfo, ret);
+ }
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ * @param data Data returned by oem
+ */
+ public void sendRequestStringsResponse(RadioResponseInfo responseInfo, ArrayList<String> data) {
+ RadioResponse.responseStringArrayList(mRil, responseInfo, data);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index e7cfe88..f9da65b 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -34,6 +34,7 @@
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.SystemProperties;
+import android.os.WorkSource;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.service.carrier.CarrierIdentifier;
@@ -41,6 +42,8 @@
import android.telephony.CellIdentityCdma;
import android.telephony.CellInfo;
import android.telephony.CellInfoCdma;
+import android.telephony.CellLocation;
+import android.telephony.ClientRequestStats;
import android.telephony.PhoneStateListener;
import android.telephony.RadioAccessFamily;
import android.telephony.Rlog;
@@ -55,6 +58,7 @@
import com.android.ims.ImsManager;
import com.android.internal.R;
import com.android.internal.telephony.dataconnection.DcTracker;
+import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
import com.android.internal.telephony.test.SimulatedRadioControl;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
@@ -92,6 +96,8 @@
protected final static Object lockForRadioTechnologyChange = new Object();
+ protected final int USSD_MAX_QUEUE = 10;
+
private BroadcastReceiver mImsIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -230,12 +236,19 @@
protected int mVmCount = 0;
private boolean mDnsCheckDisabled;
public DcTracker mDcTracker;
+ /* Used for dispatching signals to configured carrier apps */
+ private CarrierSignalAgent mCarrierSignalAgent;
+ /* Used for dispatching carrier action from carrier apps */
+ private CarrierActionAgent mCarrierActionAgent;
private boolean mDoesRilSendMultipleCallRing;
private int mCallRingContinueToken;
private int mCallRingDelay;
private boolean mIsVoiceCapable = true;
- /* Used for communicate between configured CarrierSignalling receivers */
- private CarrierSignalAgent mCarrierSignalAgent;
+ private final AppSmsManager mAppSmsManager;
+ private SimActivationTracker mSimActivationTracker;
+ // Keep track of whether or not the phone is in Emergency Callback Mode for Phone and
+ // subclasses
+ protected boolean mIsPhoneInEcmState = false;
// Variable to cache the video capability. When RAT changes, we lose this info and are unable
// to recover from the state. We cache it and notify listeners when they register.
@@ -266,6 +279,11 @@
protected TelephonyComponentFactory mTelephonyComponentFactory;
//IMS
+ /**
+ * {@link CallStateException} message text used to indicate that an IMS call has failed because
+ * it needs to be retried using GSM or CDMA (e.g. CS fallback).
+ * TODO: Replace this with a proper exception; {@link CallStateException} doesn't make sense.
+ */
public static final String CS_FALLBACK = "cs_fallback";
public static final String EXTRA_KEY_ALERT_TITLE = "alertTitle";
public static final String EXTRA_KEY_ALERT_MESSAGE = "alertMessage";
@@ -435,9 +453,9 @@
mContext = context;
mLooper = Looper.myLooper();
mCi = ci;
- mCarrierSignalAgent = new CarrierSignalAgent(this);
mActionDetached = this.getClass().getPackage().getName() + ".action_detached";
mActionAttached = this.getClass().getPackage().getName() + ".action_attached";
+ mAppSmsManager = telephonyComponentFactory.makeAppSmsManager(context);
if (Build.IS_DEBUGGABLE) {
mTelephonyTester = new TelephonyTester(this);
@@ -503,6 +521,9 @@
mSmsUsageMonitor = mTelephonyComponentFactory.makeSmsUsageMonitor(context);
mUiccController = UiccController.getInstance();
mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
+ mCarrierSignalAgent = mTelephonyComponentFactory.makeCarrierSignalAgent(this);
+ mCarrierActionAgent = mTelephonyComponentFactory.makeCarrierActionAgent(this);
+ mSimActivationTracker = mTelephonyComponentFactory.makeSimActivationTracker(this);
if (getPhoneType() != PhoneConstants.PHONE_TYPE_SIP) {
mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null);
}
@@ -512,7 +533,8 @@
}
/**
- * Start listening for IMS service UP/DOWN events.
+ * Start listening for IMS service UP/DOWN events. If using the new ImsResolver APIs, we should
+ * always be setting up ImsPhones.
*/
public void startMonitoringImsService() {
if (getPhoneType() == PhoneConstants.PHONE_TYPE_SIP) {
@@ -521,18 +543,26 @@
synchronized(Phone.lockForRadioTechnologyChange) {
IntentFilter filter = new IntentFilter();
- filter.addAction(ImsManager.ACTION_IMS_SERVICE_UP);
- filter.addAction(ImsManager.ACTION_IMS_SERVICE_DOWN);
+ ImsManager imsManager = ImsManager.getInstance(mContext, getPhoneId());
+ // Don't listen to deprecated intents using the new dynamic binding.
+ if (imsManager != null && !imsManager.isDynamicBinding()) {
+ filter.addAction(ImsManager.ACTION_IMS_SERVICE_UP);
+ filter.addAction(ImsManager.ACTION_IMS_SERVICE_DOWN);
+ }
filter.addAction(ImsConfig.ACTION_IMS_CONFIG_CHANGED);
mContext.registerReceiver(mImsIntentReceiver, filter);
// Monitor IMS service - but first poll to see if already up (could miss
- // intent)
- ImsManager imsManager = ImsManager.getInstance(mContext, getPhoneId());
- if (imsManager != null && imsManager.isServiceAvailable()) {
- mImsServiceReady = true;
- updateImsPhone();
- ImsManager.updateImsServiceConfig(mContext, mPhoneId, false);
+ // intent). Also, when using new ImsResolver APIs, the service will be available soon,
+ // so start trying to bind.
+ if (imsManager != null) {
+ // If it is dynamic binding, kick off ImsPhone creation now instead of waiting for
+ // the service to be available.
+ if (imsManager.isDynamicBinding() || imsManager.isServiceAvailable()) {
+ mImsServiceReady = true;
+ updateImsPhone();
+ ImsManager.updateImsServiceConfig(mContext, mPhoneId, false);
+ }
}
}
}
@@ -1158,6 +1188,10 @@
mCi.getNetworkSelectionMode(message);
}
+ public List<ClientRequestStats> getClientRequestStats() {
+ return mCi.getClientRequestStats();
+ }
+
/**
* Manually selects a network. <code>response</code> is
* dispatched when this is complete. <code>response.obj</code> will be
@@ -1294,6 +1328,8 @@
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putInt(CLIR_KEY + getPhoneId(), commandInterfaceCLIRMode);
+ Rlog.i(LOG_TAG, "saveClirSetting: " + CLIR_KEY + getPhoneId() + "=" +
+ commandInterfaceCLIRMode);
// Commit and log the result.
if (!editor.commit()) {
@@ -1525,6 +1561,32 @@
}
/**
+ * Update voice activation state
+ */
+ public void setVoiceActivationState(int state) {
+ mSimActivationTracker.setVoiceActivationState(state);
+ }
+ /**
+ * Update data activation state
+ */
+ public void setDataActivationState(int state) {
+ mSimActivationTracker.setDataActivationState(state);
+ }
+
+ /**
+ * Returns voice activation state
+ */
+ public int getVoiceActivationState() {
+ return mSimActivationTracker.getVoiceActivationState();
+ }
+ /**
+ * Returns data activation state
+ */
+ public int getDataActivationState() {
+ return mSimActivationTracker.getDataActivationState();
+ }
+
+ /**
* Update voice mail count related fields and notify listeners
*/
public void updateVoiceMail() {
@@ -1579,13 +1641,18 @@
}
/**
+ * @param workSource calling WorkSource
* @return all available cell information or null if none.
*/
- public List<CellInfo> getAllCellInfo() {
- List<CellInfo> cellInfoList = getServiceStateTracker().getAllCellInfo();
+ public List<CellInfo> getAllCellInfo(WorkSource workSource) {
+ List<CellInfo> cellInfoList = getServiceStateTracker().getAllCellInfo(workSource);
return privatizeCellInfoList(cellInfoList);
}
+ public CellLocation getCellLocation() {
+ return getCellLocation(null);
+ }
+
/**
* Clear CDMA base station lat/long values if location setting is disabled.
* @param cellInfoList the original cell info list from the RIL
@@ -1628,9 +1695,10 @@
* A onCellInfoChanged.
*
* @param rateInMillis the rate
+ * @param workSource calling WorkSource
*/
- public void setCellInfoListRate(int rateInMillis) {
- mCi.setCellInfoListRate(rateInMillis, null);
+ public void setCellInfoListRate(int rateInMillis, WorkSource workSource) {
+ mCi.setCellInfoListRate(rateInMillis, null, workSource);
}
/**
@@ -1735,6 +1803,10 @@
return mCarrierSignalAgent;
}
+ public CarrierActionAgent getCarrierActionAgent() {
+ return mCarrierActionAgent;
+ }
+
/**
* Query the CDMA roaming preference setting
*
@@ -1764,6 +1836,15 @@
}
/**
+ * @return true, if the device is in a state where both voice and data
+ * are supported simultaneously. This can change based on location or network condition.
+ */
+ public boolean isConcurrentVoiceAndDataAllowed() {
+ ServiceStateTracker sst = getServiceStateTracker();
+ return sst == null ? false : sst.isConcurrentVoiceAndDataAllowed();
+ }
+
+ /**
* Requests to set the CDMA roaming preference
* @param cdmaRoamingType one of CDMA_RM_*
* @param response is callback message
@@ -1935,7 +2016,9 @@
* com.android.internal.telephony.gsm.CommandException
*
* @see #invokeOemRilRequestRaw(byte[], android.os.Message)
+ * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
*/
+ @Deprecated
public void invokeOemRilRequestRaw(byte[] data, Message response) {
mCi.invokeOemRilRequestRaw(data, response);
}
@@ -1953,7 +2036,9 @@
* com.android.internal.telephony.gsm.CommandException
*
* @see #invokeOemRilRequestStrings(java.lang.String[], android.os.Message)
+ * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
*/
+ @Deprecated
public void invokeOemRilRequestStrings(String[] strings, Message response) {
mCi.invokeOemRilRequestStrings(strings, response);
}
@@ -2037,6 +2122,14 @@
mNotifier.notifyOtaspChanged(this, otaspMode);
}
+ public void notifyVoiceActivationStateChanged(int state) {
+ mNotifier.notifyVoiceActivationStateChanged(this, state);
+ }
+
+ public void notifyDataActivationStateChanged(int state) {
+ mNotifier.notifyDataActivationStateChanged(this, state);
+ }
+
public void notifySignalStrength() {
mNotifier.notifySignalStrength(this);
}
@@ -2056,13 +2149,26 @@
return false;
}
+ // This property is used to handle phone process crashes, and is the same for CDMA and IMS
+ // phones
+ protected static boolean getInEcmMode() {
+ return SystemProperties.getBoolean(TelephonyProperties.PROPERTY_INECM_MODE, false);
+ }
+
/**
* @return {@code true} if we are in emergency call back mode. This is a period where the phone
* should be using as little power as possible and be ready to receive an incoming call from the
* emergency operator.
+ *
+ * This method is overridden for GSM phones to return false always
*/
public boolean isInEcm() {
- return false;
+ return mIsPhoneInEcmState;
+ }
+
+ public void setIsInEcm(boolean isInEcm) {
+ setSystemProperty(TelephonyProperties.PROPERTY_INECM_MODE, String.valueOf(isInEcm));
+ mIsPhoneInEcmState = isInEcm;
}
private static int getVideoState(Call call) {
@@ -2188,6 +2294,21 @@
}
/**
+ * send secret dialer codes to launch arbitrary activities.
+ * an Intent is started with the android_secret_code://<code> URI.
+ *
+ * @param code stripped version of secret code without *#*# prefix and #*#* suffix
+ */
+ public void sendDialerSpecialCode(String code) {
+ if (!TextUtils.isEmpty(code)) {
+ Intent intent = new Intent(TelephonyIntents.SECRET_CODE_ACTION,
+ Uri.parse("android_secret_code://" + code));
+ intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ mContext.sendBroadcast(intent);
+ }
+ }
+
+ /**
* Returns the CDMA ERI icon index to display
*/
public int getCdmaEriIconIndex() {
@@ -2655,18 +2776,14 @@
* Action set from carrier signalling broadcast receivers to enable/disable metered apns.
*/
public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
- if(mDcTracker != null) {
- mDcTracker.setApnsEnabledByCarrier(enabled);
- }
+ mCarrierActionAgent.carrierActionSetMeteredApnsEnabled(enabled);
}
/**
* Action set from carrier signalling broadcast receivers to enable/disable radio
*/
public void carrierActionSetRadioEnabled(boolean enabled) {
- if(mDcTracker != null) {
- mDcTracker.carrierActionSetRadioEnabled(enabled);
- }
+ mCarrierActionAgent.carrierActionSetRadioEnabled(enabled);
}
/**
@@ -3353,6 +3470,18 @@
return null;
}
+ public AppSmsManager getAppSmsManager() {
+ return mAppSmsManager;
+ }
+
+ /**
+ * Set SIM card power state. Request is equivalent to inserting or removing the card.
+ * @param powerUp True if powering up the SIM, otherwise powering down
+ **/
+ public void setSimPowerState(boolean powerUp) {
+ mCi.setSimCardPower(powerUp, null);
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("Phone: subId=" + getSubId());
pw.println(" mPhoneId=" + mPhoneId);
@@ -3425,6 +3554,28 @@
pw.println("++++++++++++++++++++++++++++++++");
}
+ if (mCarrierActionAgent != null) {
+ try {
+ mCarrierActionAgent.dump(fd, pw, args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ pw.flush();
+ pw.println("++++++++++++++++++++++++++++++++");
+ }
+
+ if (mCarrierSignalAgent != null) {
+ try {
+ mCarrierSignalAgent.dump(fd, pw, args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ pw.flush();
+ pw.println("++++++++++++++++++++++++++++++++");
+ }
+
if (getCallTracker() != null) {
try {
getCallTracker().dump(fd, pw, args);
@@ -3436,6 +3587,17 @@
pw.println("++++++++++++++++++++++++++++++++");
}
+ if (mSimActivationTracker != null) {
+ try {
+ mSimActivationTracker.dump(fd, pw, args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ pw.flush();
+ pw.println("++++++++++++++++++++++++++++++++");
+ }
+
if (mCi != null && mCi instanceof RIL) {
try {
((RIL)mCi).dump(fd, pw, args);
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index aec3d8e..8ae7010 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -36,12 +36,14 @@
import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.dataconnection.TelephonyNetworkFactory;
+import com.android.internal.telephony.ims.ImsResolver;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneFactory;
import com.android.internal.telephony.sip.SipPhone;
import com.android.internal.telephony.sip.SipPhoneFactory;
import com.android.internal.telephony.uicc.IccCardProxy;
import com.android.internal.telephony.uicc.UiccController;
+import com.android.internal.telephony.util.NotificationChannelController;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
@@ -78,6 +80,8 @@
static private PhoneSwitcher sPhoneSwitcher;
static private SubscriptionMonitor sSubscriptionMonitor;
static private TelephonyNetworkFactory[] sTelephonyNetworkFactories;
+ static private ImsResolver sImsResolver;
+ static private NotificationChannelController sNotificationChannelController;
static private final HashMap<String, LocalLog>sLocalLogs = new HashMap<String, LocalLog>();
@@ -136,6 +140,13 @@
where as in single SIM mode only instance. isMultiSimEnabled() function checks
whether it is single SIM or multi SIM mode */
int numPhones = TelephonyManager.getDefault().getPhoneCount();
+ // Start ImsResolver and bind to ImsServices.
+ String defaultImsPackage = sContext.getResources().getString(
+ com.android.internal.R.string.config_ims_package);
+ Rlog.i(LOG_TAG, "ImsResolver: defaultImsPackage: " + defaultImsPackage);
+ sImsResolver = new ImsResolver(sContext, defaultImsPackage, numPhones);
+ sImsResolver.populateCacheAndStartBind();
+
int[] networkModes = new int[numPhones];
sPhones = new Phone[numPhones];
sCommandsInterfaces = new RIL[numPhones];
@@ -203,8 +214,9 @@
SubscriptionController.getInstance().updatePhonesAvailability(sPhones);
// Start monitoring after defaults have been made.
- // Default phone must be ready before ImsPhone is created
- // because ImsService might need it when it is being opened.
+ // Default phone must be ready before ImsPhone is created because ImsService might
+ // need it when it is being opened. This should initialize multiple ImsPhones for
+ // ImsResolver implementations of ImsService.
for (int i = 0; i < numPhones; i++) {
sPhones[i].startMonitoringImsService();
}
@@ -222,6 +234,8 @@
sProxyController = ProxyController.getInstance(context, sPhones,
sUiccController, sCommandsInterfaces, sPhoneSwitcher);
+ sNotificationChannelController = new NotificationChannelController(context);
+
sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
for (int i = 0; i < numPhones; i++) {
sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(
@@ -275,6 +289,10 @@
}
}
+ public static ImsResolver getImsResolver() {
+ return sImsResolver;
+ }
+
/**
* Makes a {@link SipPhone} object.
* @param sipUri the local SIP URI the phone runs on
diff --git a/src/java/com/android/internal/telephony/PhoneInternalInterface.java b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
index 652dac8..57fc43b 100644
--- a/src/java/com/android/internal/telephony/PhoneInternalInterface.java
+++ b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
@@ -16,30 +16,18 @@
package com.android.internal.telephony;
-import android.content.Context;
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
-import android.telephony.CellInfo;
+import android.os.WorkSource;
+import android.os.ResultReceiver;
import android.telephony.CellLocation;
import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-
-import com.android.internal.telephony.imsphone.ImsPhone;
-import com.android.internal.telephony.RadioCapability;
-import com.android.internal.telephony.test.SimulatedRadioControl;
-import com.android.internal.telephony.uicc.IsimRecords;
-import com.android.internal.telephony.uicc.UiccCard;
-import com.android.internal.telephony.uicc.UsimServiceTable;
import com.android.internal.telephony.PhoneConstants.*; // ????
import java.util.List;
-import java.util.Locale;
/**
* Internal interface used to control the phone; SDK developers cannot
@@ -219,8 +207,9 @@
/**
* Get the current CellLocation.
+ * @param workSource calling WorkSource
*/
- CellLocation getCellLocation();
+ CellLocation getCellLocation(WorkSource workSource);
/**
* Get the current DataState. No change notification exists at this
@@ -448,6 +437,15 @@
boolean handlePinMmi(String dialString);
/**
+ * Handles USSD commands
+ *
+ * @param ussdRequest the USSD command to be executed.
+ * @param wrappedCallback receives the callback result.
+ */
+ boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback)
+ throws CallStateException;
+
+ /**
* Handles in-call MMI commands. While in a call, or while receiving a
* call, use this to execute MMI commands.
* see 3GPP 20.030, section 6.5.5.1 for specs on the allowed MMI commands.
@@ -655,8 +653,9 @@
*
* @param response callback message that is dispatched when the query
* completes.
+ * @param workSource calling WorkSource
*/
- void getNeighboringCids(Message response);
+ default void getNeighboringCids(Message response, WorkSource workSource){}
/**
* Mutes or unmutes the microphone for the active call. The microphone
diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java
index 02f15d9..2caf5e2 100644
--- a/src/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/PhoneNotifier.java
@@ -59,5 +59,9 @@
public void notifyVoLteServiceStateChanged(Phone sender, VoLteServiceState lteState);
+ public void notifyVoiceActivationStateChanged(Phone sender, int activationState);
+
+ public void notifyDataActivationStateChanged(Phone sender, int activationState);
+
public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData);
}
diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
index a867d12..361b51a 100644
--- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java
+++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
@@ -33,6 +33,7 @@
import com.android.internal.telephony.uicc.UiccCardApplication;
import static android.Manifest.permission.CALL_PRIVILEGED;
+import static android.Manifest.permission.READ_PHONE_NUMBERS;
import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
import static android.Manifest.permission.READ_SMS;
@@ -434,7 +435,8 @@
}
/**
- * Besides READ_PHONE_STATE, WRITE_SMS and READ_SMS also allow apps to get phone numbers.
+ * Besides READ_PHONE_STATE, READ_PHONE_NUMBERS, WRITE_SMS and READ_SMS also allow apps to get
+ * phone numbers.
*/
private boolean checkReadPhoneNumber(String callingPackage, String message) {
// Default SMS app can always read it.
@@ -445,18 +447,36 @@
try {
return checkReadPhoneState(callingPackage, message);
} catch (SecurityException readPhoneStateSecurityException) {
- try {
- // Can be read with READ_SMS too.
- mContext.enforceCallingOrSelfPermission(READ_SMS, message);
- return mAppOps.noteOp(AppOpsManager.OP_READ_SMS,
- Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
- } catch (SecurityException readSmsSecurityException) {
- // Throw exception with message including both READ_PHONE_STATE and READ_SMS
- // permissions
- throw new SecurityException(message + ": Neither user " + Binder.getCallingUid() +
- " nor current process has " + READ_PHONE_STATE + " or " + READ_SMS + ".");
- }
}
+ try {
+ // Can be read with READ_SMS too.
+ mContext.enforceCallingOrSelfPermission(READ_SMS, message);
+ int opCode = mAppOps.permissionToOpCode(READ_SMS);
+ if (opCode != AppOpsManager.OP_NONE) {
+ return mAppOps.noteOp(opCode, Binder.getCallingUid(), callingPackage)
+ == AppOpsManager.MODE_ALLOWED;
+ } else {
+ return true;
+ }
+ } catch (SecurityException readSmsSecurityException) {
+ }
+ try {
+ // Can be read with READ_PHONE_NUMBERS too.
+ mContext.enforceCallingOrSelfPermission(READ_PHONE_NUMBERS, message);
+ int opCode = mAppOps.permissionToOpCode(READ_PHONE_NUMBERS);
+ if (opCode != AppOpsManager.OP_NONE) {
+ return mAppOps.noteOp(opCode, Binder.getCallingUid(), callingPackage)
+ == AppOpsManager.MODE_ALLOWED;
+ } else {
+ return true;
+ }
+ } catch (SecurityException readPhoneNumberSecurityException) {
+ }
+ // Throw exception with message including READ_PHONE_STATE, READ_SMS, and READ_PHONE_NUMBERS
+ // permissions
+ throw new SecurityException(message + ": Neither user " + Binder.getCallingUid() +
+ " nor current process has " + READ_PHONE_STATE + ", " +
+ READ_SMS + ", or " + READ_PHONE_STATE + ".");
}
private void log(String s) {
diff --git a/src/java/com/android/internal/telephony/PhoneSwitcher.java b/src/java/com/android/internal/telephony/PhoneSwitcher.java
index 41cccd4..15dc842 100644
--- a/src/java/com/android/internal/telephony/PhoneSwitcher.java
+++ b/src/java/com/android/internal/telephony/PhoneSwitcher.java
@@ -23,9 +23,12 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.net.MatchAllNetworkSpecifier;
import android.net.NetworkCapabilities;
import android.net.NetworkFactory;
import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
+import android.net.StringNetworkSpecifier;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -33,22 +36,16 @@
import android.os.RegistrantList;
import android.os.RemoteException;
import android.telephony.Rlog;
-import android.text.TextUtils;
import android.util.LocalLog;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.IOnSubscriptionsChangedListener;
-import com.android.internal.telephony.ITelephonyRegistry;
import com.android.internal.telephony.dataconnection.DcRequest;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.IllegalArgumentException;
import java.util.ArrayList;
import java.util.Calendar;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -148,7 +145,7 @@
netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS);
netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- netCap.setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
+ netCap.setNetworkSpecifier(new MatchAllNetworkSpecifier());
NetworkFactory networkFactory = new PhoneSwitcherNetworkRequestListener(looper, context,
netCap, this);
@@ -368,14 +365,23 @@
}
private int phoneIdForRequest(NetworkRequest netRequest) {
- String specifier = netRequest.networkCapabilities.getNetworkSpecifier();
+ NetworkSpecifier specifier = netRequest.networkCapabilities.getNetworkSpecifier();
int subId;
- if (TextUtils.isEmpty(specifier)) {
+ if (specifier == null) {
subId = mDefaultDataSubscription;
+ } else if (specifier instanceof StringNetworkSpecifier) {
+ try {
+ subId = Integer.parseInt(((StringNetworkSpecifier) specifier).specifier);
+ } catch (NumberFormatException e) {
+ Rlog.e(LOG_TAG, "NumberFormatException on "
+ + ((StringNetworkSpecifier) specifier).specifier);
+ subId = INVALID_SUBSCRIPTION_ID;
+ }
} else {
- subId = Integer.parseInt(specifier);
+ subId = INVALID_SUBSCRIPTION_ID;
}
+
int phoneId = INVALID_PHONE_INDEX;
if (subId == INVALID_SUBSCRIPTION_ID) return phoneId;
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 2e50b2f..7d211fb 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -16,77 +16,90 @@
package com.android.internal.telephony;
-import android.content.BroadcastReceiver;
+import static com.android.internal.telephony.RILConstants.*;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.hardware.display.DisplayManager;
+import android.hardware.radio.V1_0.Carrier;
+import android.hardware.radio.V1_0.CarrierRestrictions;
+import android.hardware.radio.V1_0.CdmaBroadcastSmsConfigInfo;
+import android.hardware.radio.V1_0.CdmaSmsAck;
+import android.hardware.radio.V1_0.CdmaSmsMessage;
+import android.hardware.radio.V1_0.CdmaSmsWriteArgs;
+import android.hardware.radio.V1_0.CellInfoCdma;
+import android.hardware.radio.V1_0.CellInfoGsm;
+import android.hardware.radio.V1_0.CellInfoLte;
+import android.hardware.radio.V1_0.CellInfoType;
+import android.hardware.radio.V1_0.CellInfoWcdma;
+import android.hardware.radio.V1_0.DataProfileInfo;
+import android.hardware.radio.V1_0.Dial;
+import android.hardware.radio.V1_0.GsmBroadcastSmsConfigInfo;
+import android.hardware.radio.V1_0.GsmSmsMessage;
+import android.hardware.radio.V1_0.HardwareConfigModem;
+import android.hardware.radio.V1_0.IRadio;
+import android.hardware.radio.V1_0.IccIo;
+import android.hardware.radio.V1_0.ImsSmsMessage;
+import android.hardware.radio.V1_0.LceDataInfo;
+import android.hardware.radio.V1_0.MvnoType;
+import android.hardware.radio.V1_0.NvWriteItem;
+import android.hardware.radio.V1_0.RadioError;
+import android.hardware.radio.V1_0.RadioIndicationType;
+import android.hardware.radio.V1_0.RadioResponseInfo;
+import android.hardware.radio.V1_0.RadioResponseType;
+import android.hardware.radio.V1_0.ResetNvType;
+import android.hardware.radio.V1_0.SelectUiccSub;
+import android.hardware.radio.V1_0.SetupDataCallResult;
+import android.hardware.radio.V1_0.SimApdu;
+import android.hardware.radio.V1_0.SmsWriteArgs;
+import android.hardware.radio.V1_0.UusInfo;
+import android.hardware.radio.deprecated.V1_0.IOemHook;
import android.net.ConnectivityManager;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
import android.os.AsyncResult;
-import android.os.BatteryManager;
import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
+import android.os.HwBinder;
import android.os.Message;
import android.os.Parcel;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.WorkSource;
import android.service.carrier.CarrierIdentifier;
import android.telephony.CellInfo;
+import android.telephony.ClientRequestStats;
import android.telephony.ModemActivityInfo;
import android.telephony.NeighboringCellInfo;
-import android.telephony.PcoData;
import android.telephony.PhoneNumberUtils;
import android.telephony.RadioAccessFamily;
import android.telephony.Rlog;
import android.telephony.SignalStrength;
import android.telephony.SmsManager;
-import android.telephony.SmsMessage;
-import android.telephony.SubscriptionManager;
import android.telephony.TelephonyHistogram;
-import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.SparseArray;
-import android.view.Display;
-import com.android.internal.telephony.TelephonyProto.SmsSession;
-import com.android.internal.telephony.TelephonyProto.TelephonySettings;
-import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
import com.android.internal.telephony.cdma.CdmaInformationRecords;
import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
import com.android.internal.telephony.dataconnection.DataCallResponse;
import com.android.internal.telephony.dataconnection.DataProfile;
-import com.android.internal.telephony.dataconnection.DcFailCause;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
-import com.android.internal.telephony.gsm.SsData;
-import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.metrics.TelephonyMetrics;
-import com.android.internal.telephony.uicc.IccCardApplicationStatus;
-import com.android.internal.telephony.uicc.IccCardStatus;
-import com.android.internal.telephony.uicc.IccIoResult;
-import com.android.internal.telephony.uicc.IccRefreshResponse;
+import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
import com.android.internal.telephony.uicc.IccUtils;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.FileDescriptor;
import java.io.IOException;
-import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-
-import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
-import static com.android.internal.telephony.RILConstants.*;
+import java.util.concurrent.atomic.AtomicLong;
/**
* {@hide}
@@ -102,15 +115,15 @@
private static RILRequest sPool = null;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 4;
- private Context mContext;
//***** Instance Variables
int mSerial;
int mRequest;
Message mResult;
- Parcel mParcel;
RILRequest mNext;
int mWakeLockType;
+ WorkSource mWorkSource;
+ String mClientId;
// time in ms when RIL request was made
long mStartTimeMs;
@@ -121,7 +134,7 @@
* @param result sent when operation completes
* @return a RILRequest instance from the pool.
*/
- static RILRequest obtain(int request, Message result) {
+ private static RILRequest obtain(int request, Message result) {
RILRequest rr = null;
synchronized(sPoolSync) {
@@ -141,17 +154,36 @@
rr.mRequest = request;
rr.mResult = result;
- rr.mParcel = Parcel.obtain();
rr.mWakeLockType = RIL.INVALID_WAKELOCK;
+ rr.mWorkSource = null;
rr.mStartTimeMs = SystemClock.elapsedRealtime();
if (result != null && result.getTarget() == null) {
throw new NullPointerException("Message target must not be null");
}
- // first elements in any RIL Parcel
- rr.mParcel.writeInt(request);
- rr.mParcel.writeInt(rr.mSerial);
+ return rr;
+ }
+
+
+ /**
+ * Retrieves a new RILRequest instance from the pool and sets the clientId
+ *
+ * @param request RIL_REQUEST_*
+ * @param result sent when operation completes
+ * @param workSource WorkSource to track the client
+ * @return a RILRequest instance from the pool.
+ */
+ static RILRequest obtain(int request, Message result, WorkSource workSource) {
+ RILRequest rr = null;
+
+ rr = obtain(request, result);
+ if(workSource != null) {
+ rr.mWorkSource = workSource;
+ rr.mClientId = String.valueOf(workSource.get(0)) + ":" + workSource.getName(0);
+ } else {
+ Rlog.e(LOG_TAG, "null workSource " + request);
+ }
return rr;
}
@@ -224,11 +256,6 @@
AsyncResult.forMessage(mResult, ret, ex);
mResult.sendToTarget();
}
-
- if (mParcel != null) {
- mParcel.recycle();
- mParcel = null;
- }
}
}
@@ -244,9 +271,6 @@
static final String RILJ_ACK_WAKELOCK_NAME = "RILJ_ACK_WL";
static final boolean RILJ_LOGD = true;
static final boolean RILJ_LOGV = false; // STOPSHIP if true
- static final int RADIO_SCREEN_UNSET = -1;
- static final int RADIO_SCREEN_OFF = 0;
- static final int RADIO_SCREEN_ON = 1;
static final int RIL_HISTOGRAM_BUCKET_COUNT = 5;
/**
@@ -264,18 +288,10 @@
public static final int INVALID_WAKELOCK = -1;
public static final int FOR_WAKELOCK = 0;
public static final int FOR_ACK_WAKELOCK = 1;
+ private final ClientWakelockTracker mClientWakelockTracker = new ClientWakelockTracker();
//***** Instance Variables
- LocalSocket mSocket;
- HandlerThread mSenderThread;
- RILSender mSender;
- Thread mReceiverThread;
- RILReceiver mReceiver;
- Display mDefaultDisplay;
- int mDefaultDisplayState = Display.STATE_UNKNOWN;
- int mRadioScreenState = RADIO_SCREEN_UNSET;
- boolean mIsDevicePlugged = false;
final WakeLock mWakeLock; // Wake lock associated with request/response
final WakeLock mAckWakeLock; // Wake lock associated with ack sent
final int mWakeLockTimeout; // Timeout associated with request/response
@@ -297,69 +313,39 @@
// When we are testing emergency calls
AtomicBoolean mTestingEmergencyCall = new AtomicBoolean(false);
- private Integer mInstanceId;
+ final Integer mPhoneId;
+ /* default work source which will blame phone process */
+ private WorkSource mRILDefaultWorkSource;
+
+ /* Worksource containing all applications causing wakelock to be held */
+ private WorkSource mActiveWakelockWorkSource;
+
+ /** Telephony metrics instance for logging metrics event */
private TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
- //***** Events
+ boolean mIsMobileNetworkSupported;
+ RadioResponse mRadioResponse;
+ RadioIndication mRadioIndication;
+ volatile IRadio mRadioProxy = null;
+ OemHookResponse mOemHookResponse;
+ OemHookIndication mOemHookIndication;
+ volatile IOemHook mOemHookProxy = null;
+ final AtomicLong mRadioProxyCookie = new AtomicLong(0);
+ final RadioProxyDeathRecipient mRadioProxyDeathRecipient;
+ final RilHandler mRilHandler;
- static final int EVENT_SEND = 1;
+ //***** Events
static final int EVENT_WAKE_LOCK_TIMEOUT = 2;
- static final int EVENT_SEND_ACK = 3;
static final int EVENT_ACK_WAKE_LOCK_TIMEOUT = 4;
static final int EVENT_BLOCKING_RESPONSE_TIMEOUT = 5;
+ static final int EVENT_RADIO_PROXY_DEAD = 6;
//***** 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 int RESPONSE_SOLICITED_ACK = 2;
- static final int RESPONSE_SOLICITED_ACK_EXP = 3;
- static final int RESPONSE_UNSOLICITED_ACK_EXP = 4;
+ static final String[] HIDL_SERVICE_NAME = {"slot1", "slot2", "slot3"};
- static final String[] SOCKET_NAME_RIL = {"rild", "rild2", "rild3"};
-
- static final int SOCKET_OPEN_RETRY_MILLIS = 4 * 1000;
-
- // The number of the required config values for broadcast SMS stored in the C struct
- // RIL_CDMA_BroadcastServiceInfo
- private static final int CDMA_BSI_NO_OF_INTS_STRUCT = 3;
-
- private static final int CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES = 31;
-
- private final DisplayManager.DisplayListener mDisplayListener =
- new DisplayManager.DisplayListener() {
- @Override
- public void onDisplayAdded(int displayId) { }
-
- @Override
- public void onDisplayRemoved(int displayId) { }
-
- @Override
- public void onDisplayChanged(int displayId) {
- if (displayId == Display.DEFAULT_DISPLAY) {
- final int oldState = mDefaultDisplayState;
- mDefaultDisplayState = mDefaultDisplay.getState();
- if (mDefaultDisplayState != oldState) {
- updateScreenState();
- }
- }
- }
- };
-
- private final BroadcastReceiver mBatteryStateListener = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- boolean oldState = mIsDevicePlugged;
- // 0 means it's on battery
- mIsDevicePlugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
- if (mIsDevicePlugged != oldState) {
- updateScreenState();
- }
- }
- };
+ static final int IRADIO_GET_SERVICE_DELAY_MILLIS = 4 * 1000;
public static List<TelephonyHistogram> getTelephonyRILTimingHistograms() {
List<TelephonyHistogram> list;
@@ -373,102 +359,13 @@
return list;
}
- class RILSender extends Handler implements Runnable {
- public RILSender(Looper looper) {
- super(looper);
- }
-
- // Only allocated once
- byte[] dataLength = new byte[4];
-
- //***** Runnable implementation
- @Override
- public void
- run() {
- //setup if needed
- }
-
-
+ class RilHandler extends Handler {
//***** Handler implementation
@Override public void
handleMessage(Message msg) {
- RILRequest rr = (RILRequest)(msg.obj);
- RILRequest req = null;
+ RILRequest rr;
switch (msg.what) {
- case EVENT_SEND:
- case EVENT_SEND_ACK:
- try {
- LocalSocket s;
-
- s = mSocket;
-
- if (s == null) {
- rr.onError(RADIO_NOT_AVAILABLE, null);
- decrementWakeLock(rr);
- rr.release();
- return;
- }
-
- // Acks should not be stored in list before sending
- if (msg.what != EVENT_SEND_ACK) {
- synchronized (mRequestList) {
- rr.mStartTimeMs = SystemClock.elapsedRealtime();
- mRequestList.append(rr.mSerial, rr);
- }
- }
-
- byte[] data;
-
- data = rr.mParcel.marshall();
- rr.mParcel.recycle();
- rr.mParcel = 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);
-
- //Rlog.v(RILJ_LOG_TAG, "writing packet: " + data.length + " bytes");
-
- s.getOutputStream().write(dataLength);
- s.getOutputStream().write(data);
- if (msg.what == EVENT_SEND_ACK) {
- rr.release();
- return;
- }
- } catch (IOException ex) {
- Rlog.e(RILJ_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) {
- rr.onError(RADIO_NOT_AVAILABLE, null);
- decrementWakeLock(rr);
- rr.release();
- return;
- }
- } catch (RuntimeException exc) {
- Rlog.e(RILJ_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) {
- rr.onError(GENERIC_FAILURE, null);
- decrementWakeLock(rr);
- rr.release();
- return;
- }
- }
-
- 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.
@@ -518,12 +415,25 @@
Object timeoutResponse = getResponseForTimedOutRILRequest(rr);
AsyncResult.forMessage( rr.mResult, timeoutResponse, null);
rr.mResult.sendToTarget();
- mMetrics.writeOnRilTimeoutResponse(mInstanceId, rr.mSerial, rr.mRequest);
+ mMetrics.writeOnRilTimeoutResponse(mPhoneId, rr.mSerial, rr.mRequest);
}
decrementWakeLock(rr);
rr.release();
break;
+
+ case EVENT_RADIO_PROXY_DEAD:
+ riljLog("handleMessage: EVENT_RADIO_PROXY_DEAD cookie = " + msg.obj +
+ " mRadioProxyCookie = " + mRadioProxyCookie.get());
+ if ((long) msg.obj == mRadioProxyCookie.get()) {
+ resetProxyAndRequestList();
+
+ // todo: rild should be back up since message was sent with a delay. this is
+ // a hack.
+ getRadioProxy(null);
+ getOemHookProxy(null);
+ }
+ break;
}
}
}
@@ -551,187 +461,129 @@
return timeoutResponse;
}
- /**
- * 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
- * <code>buffer</code> 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 ) {
- Rlog.e(RILJ_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 ) {
- Rlog.e(RILJ_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];
- }
-
+ final class RadioProxyDeathRecipient implements HwBinder.DeathRecipient {
@Override
- public void
- run() {
- int retryCount = 0;
- String rilSocket = "rild";
-
- try {for (;;) {
- LocalSocket s = null;
- LocalSocketAddress l;
-
- if (mInstanceId == null || mInstanceId == 0 ) {
- rilSocket = SOCKET_NAME_RIL[0];
- } else {
- rilSocket = SOCKET_NAME_RIL[mInstanceId];
- }
-
- try {
- s = new LocalSocket();
- l = new LocalSocketAddress(rilSocket,
- 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) {
- Rlog.e (RILJ_LOG_TAG,
- "Couldn't find '" + rilSocket
- + "' socket after " + retryCount
- + " times, continuing to retry silently");
- } else if (retryCount >= 0 && retryCount < 8) {
- Rlog.i (RILJ_LOG_TAG,
- "Couldn't find '" + rilSocket
- + "' socket; retrying after timeout");
- }
-
- try {
- Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
- } catch (InterruptedException er) {
- }
-
- retryCount++;
- continue;
- }
-
- retryCount = 0;
-
- mSocket = s;
- Rlog.i(RILJ_LOG_TAG, "(" + mInstanceId + ") Connected to '"
- + rilSocket + "' 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);
-
- //Rlog.v(RILJ_LOG_TAG, "Read packet: " + length + " bytes");
-
- processResponse(p);
- p.recycle();
- }
- } catch (java.io.IOException ex) {
- Rlog.i(RILJ_LOG_TAG, "'" + rilSocket + "' socket closed",
- ex);
- } catch (Throwable tr) {
- Rlog.e(RILJ_LOG_TAG, "Uncaught exception read length=" + length +
- "Exception:" + tr.toString());
- }
-
- Rlog.i(RILJ_LOG_TAG, "(" + mInstanceId + ") Disconnected from '" + rilSocket
- + "' socket");
-
- setRadioState (RadioState.RADIO_UNAVAILABLE);
-
- try {
- mSocket.close();
- } catch (IOException ex) {
- }
-
- mSocket = null;
- RILRequest.resetSerial();
-
- // Clear request list on close
- clearRequestList(RADIO_NOT_AVAILABLE, false);
- }} catch (Throwable tr) {
- Rlog.e(RILJ_LOG_TAG,"Uncaught exception", tr);
- }
-
- /* We're disconnected so we don't know the ril version */
- notifyRegistrantsRilConnectionChanged(-1);
+ public void serviceDied(long cookie) {
+ // Deal with service going away
+ riljLog("serviceDied");
+ // todo: temp hack to send delayed message so that rild is back up by then
+ //mRilHandler.sendMessage(mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD, cookie));
+ mRilHandler.sendMessageDelayed(
+ mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD, cookie),
+ IRADIO_GET_SERVICE_DELAY_MILLIS);
}
}
+ private void resetProxyAndRequestList() {
+ mRadioProxy = null;
+ mOemHookProxy = null;
+ // increment the cookie so that death notification can be ignored
+ mRadioProxyCookie.incrementAndGet();
+
+ setRadioState(RadioState.RADIO_UNAVAILABLE);
+
+ RILRequest.resetSerial();
+ // Clear request list on close
+ clearRequestList(RADIO_NOT_AVAILABLE, false);
+
+ // todo: need to get service right away so setResponseFunctions() can be called for
+ // unsolicited indications. getService() is not a blocking call, so it doesn't help to call
+ // it here. Current hack is to call getService() on death notification after a delay.
+ }
+
+ private IRadio getRadioProxy(Message result) {
+ if (!mIsMobileNetworkSupported) {
+ if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only");
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
+ result.sendToTarget();
+ }
+ return null;
+ }
+
+ if (mRadioProxy != null) {
+ return mRadioProxy;
+ }
+
+ try {
+ mRadioProxy = IRadio.getService(HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId]);
+ if (mRadioProxy != null) {
+ mRadioProxy.linkToDeath(mRadioProxyDeathRecipient,
+ mRadioProxyCookie.incrementAndGet());
+ mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication);
+ } else {
+ riljLoge("getRadioProxy: mRadioProxy == null");
+ }
+ } catch (RemoteException | RuntimeException e) {
+ mRadioProxy = null;
+ riljLoge("RadioProxy getService/setResponseFunctions: " + e);
+ }
+
+ if (mRadioProxy == null) {
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
+ result.sendToTarget();
+ }
+
+ // if service is not up, treat it like death notification to try to get service again
+ mRilHandler.sendMessageDelayed(
+ mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD,
+ mRadioProxyCookie.incrementAndGet()),
+ IRADIO_GET_SERVICE_DELAY_MILLIS);
+ }
+
+ return mRadioProxy;
+ }
+
+ private IOemHook getOemHookProxy(Message result) {
+ if (!mIsMobileNetworkSupported) {
+ if (RILJ_LOGV) riljLog("getOemHookProxy: Not calling getService(): wifi-only");
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
+ result.sendToTarget();
+ }
+ return null;
+ }
+
+ if (mOemHookProxy != null) {
+ return mOemHookProxy;
+ }
+
+ try {
+ mOemHookProxy = IOemHook.getService(
+ HIDL_SERVICE_NAME[mPhoneId == null ? 0 : mPhoneId]);
+ if (mOemHookProxy != null) {
+ // not calling linkToDeath() as ril service runs in the same process and death
+ // notification for that should be sufficient
+ mOemHookProxy.setResponseFunctions(mOemHookResponse, mOemHookIndication);
+ } else {
+ riljLoge("getOemHookProxy: mOemHookProxy == null");
+ }
+ } catch (RemoteException | RuntimeException e) {
+ mOemHookProxy = null;
+ riljLoge("OemHookProxy getService/setResponseFunctions: " + e);
+ }
+
+ if (mOemHookProxy == null) {
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(RADIO_NOT_AVAILABLE));
+ result.sendToTarget();
+ }
+
+ // if service is not up, treat it like death notification to try to get service again
+ mRilHandler.sendMessageDelayed(
+ mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD,
+ mRadioProxyCookie.incrementAndGet()),
+ IRADIO_GET_SERVICE_DELAY_MILLIS);
+ }
+
+ return mOemHookProxy;
+ }
//***** Constructors
@@ -743,15 +595,26 @@
int cdmaSubscription, Integer instanceId) {
super(context);
if (RILJ_LOGD) {
- riljLog("RIL(context, preferredNetworkType=" + preferredNetworkType +
- " cdmaSubscription=" + cdmaSubscription + ")");
+ riljLog("RIL: init preferredNetworkType=" + preferredNetworkType
+ + " cdmaSubscription=" + cdmaSubscription + ")");
}
mContext = context;
mCdmaSubscription = cdmaSubscription;
mPreferredNetworkType = preferredNetworkType;
mPhoneType = RILConstants.NO_PHONE;
- mInstanceId = instanceId;
+ mPhoneId = instanceId;
+
+ ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ mIsMobileNetworkSupported = cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+
+ mRadioResponse = new RadioResponse(this);
+ mRadioIndication = new RadioIndication(this);
+ mOemHookResponse = new OemHookResponse(this);
+ mOemHookIndication = new OemHookIndication(this);
+ mRilHandler = new RilHandler();
+ mRadioProxyDeathRecipient = new RadioProxyDeathRecipient();
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_LOG_TAG);
@@ -763,60 +626,16 @@
mAckWakeLockTimeout = SystemProperties.getInt(
TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT, DEFAULT_ACK_WAKE_LOCK_TIMEOUT_MS);
mWakeLockCount = 0;
-
- mSenderThread = new HandlerThread("RILSender" + mInstanceId);
- mSenderThread.start();
-
- Looper looper = mSenderThread.getLooper();
- mSender = new RILSender(looper);
-
- ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
- riljLog("Not starting RILReceiver: wifi-only");
- } else {
- riljLog("Starting RILReceiver" + mInstanceId);
- mReceiver = new RILReceiver();
- mReceiverThread = new Thread(mReceiver, "RILReceiver" + mInstanceId);
- mReceiverThread.start();
-
- DisplayManager dm = (DisplayManager)context.getSystemService(
- Context.DISPLAY_SERVICE);
- mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
- dm.registerDisplayListener(mDisplayListener, null);
- mDefaultDisplayState = mDefaultDisplay.getState();
-
- IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- Intent batteryStatus = context.registerReceiver(mBatteryStateListener, filter);
- if (batteryStatus != null) {
- // 0 means it's on battery
- mIsDevicePlugged = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
- }
- }
+ mRILDefaultWorkSource = new WorkSource(context.getApplicationInfo().uid,
+ context.getPackageName());
TelephonyDevController tdc = TelephonyDevController.getInstance();
tdc.registerRIL(this);
- }
- //***** CommandsInterface implementation
-
- @Override
- public void getVoiceRadioTechnology(Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_VOICE_RADIO_TECH, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
- }
-
-
- public void getImsRegistrationState(Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_IMS_REGISTRATION_STATE, result);
-
- if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
- }
- send(rr);
+ // set radio callback; needed to set RadioIndication callback (should be done after
+ // wakelock stuff is initialized above as callbacks are received on separate binder threads)
+ getRadioProxy(null);
+ getOemHookProxy(null);
}
@Override public void
@@ -831,46 +650,52 @@
}
}
+ private void addRequest(RILRequest rr) {
+ acquireWakeLock(rr, FOR_WAKELOCK);
+ synchronized (mRequestList) {
+ rr.mStartTimeMs = SystemClock.elapsedRealtime();
+ mRequestList.append(rr.mSerial, rr);
+ }
+ }
+
+ private RILRequest obtainRequest(int request, Message result, WorkSource workSource) {
+ RILRequest rr = RILRequest.obtain(request, result, workSource);
+ addRequest(rr);
+ return rr;
+ }
+
+ private void handleRadioProxyExceptionForRR(RILRequest rr, String caller, Exception e) {
+ riljLoge(caller + ": " + e);
+ resetProxyAndRequestList();
+
+ // service most likely died, handle exception like death notification to try to get service
+ // again
+ mRilHandler.sendMessageDelayed(
+ mRilHandler.obtainMessage(EVENT_RADIO_PROXY_DEAD,
+ mRadioProxyCookie.incrementAndGet()),
+ IRADIO_GET_SERVICE_DELAY_MILLIS);
+ }
+
+ private String convertNullToEmptyString(String string) {
+ return string != null ? string : "";
+ }
+
@Override
public void
getIccCardStatus(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);
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_GET_SIM_STATUS, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
- send(rr);
- }
-
- public void setUiccSubscription(int slotId, int appIndex, int subId,
- int subStatus, Message result) {
- //Note: This RIL request is also valid for SIM and RUIM (ICC card)
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_SET_UICC_SUBSCRIPTION, result);
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " slot: " + slotId + " appIndex: " + appIndex
- + " subId: " + subId + " subStatus: " + subStatus);
-
- rr.mParcel.writeInt(slotId);
- rr.mParcel.writeInt(appIndex);
- rr.mParcel.writeInt(subId);
- rr.mParcel.writeInt(subStatus);
-
- send(rr);
- }
-
- // FIXME This API should take an AID and slot ID
- public void setDataAllowed(boolean allowed, Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_ALLOW_DATA, result);
- if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) +
- " allowed: " + allowed);
+ try {
+ radioProxy.getIccCardStatus(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "getIccCardStatus", e);
+ }
}
-
- rr.mParcel.writeInt(1);
- rr.mParcel.writeInt(allowed ? 1 : 0);
- send(rr);
}
@Override public void
@@ -880,38 +705,52 @@
@Override public void
supplyIccPinForApp(String pin, String aid, 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);
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PIN, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " aid = " + aid);
+ }
- rr.mParcel.writeInt(2);
- rr.mParcel.writeString(pin);
- rr.mParcel.writeString(aid);
-
- send(rr);
+ try {
+ radioProxy.supplyIccPinForApp(rr.mSerial,
+ convertNullToEmptyString(pin),
+ convertNullToEmptyString(aid));
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "supplyIccPinForApp", e);
+ }
+ }
}
- @Override public void
- supplyIccPuk(String puk, String newPin, Message result) {
+ @Override
+ public void supplyIccPuk(String puk, String newPin, Message result) {
supplyIccPukForApp(puk, newPin, null, result);
}
- @Override public void
- supplyIccPukForApp(String puk, String newPin, String aid, 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);
+ @Override
+ public void supplyIccPukForApp(String puk, String newPin, String aid, Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PUK, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " aid = " + aid);
+ }
- rr.mParcel.writeInt(3);
- rr.mParcel.writeString(puk);
- rr.mParcel.writeString(newPin);
- rr.mParcel.writeString(aid);
-
- send(rr);
+ try {
+ radioProxy.supplyIccPukForApp(rr.mSerial,
+ convertNullToEmptyString(puk),
+ convertNullToEmptyString(newPin),
+ convertNullToEmptyString(aid));
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "supplyIccPukForApp", e);
+ }
+ }
}
@Override public void
@@ -921,17 +760,24 @@
@Override public void
supplyIccPin2ForApp(String pin, String aid, 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);
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PIN2, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " aid = " + aid);
+ }
- rr.mParcel.writeInt(2);
- rr.mParcel.writeString(pin);
- rr.mParcel.writeString(aid);
-
- send(rr);
+ try {
+ radioProxy.supplyIccPin2ForApp(rr.mSerial,
+ convertNullToEmptyString(pin),
+ convertNullToEmptyString(aid));
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "supplyIccPin2ForApp", e);
+ }
+ }
}
@Override public void
@@ -941,18 +787,25 @@
@Override public void
supplyIccPuk2ForApp(String puk, String newPin2, String aid, 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);
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_SIM_PUK2, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " aid = " + aid);
+ }
- rr.mParcel.writeInt(3);
- rr.mParcel.writeString(puk);
- rr.mParcel.writeString(newPin2);
- rr.mParcel.writeString(aid);
-
- send(rr);
+ try {
+ radioProxy.supplyIccPuk2ForApp(rr.mSerial,
+ convertNullToEmptyString(puk),
+ convertNullToEmptyString(newPin2),
+ convertNullToEmptyString(aid));
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "supplyIccPuk2ForApp", e);
+ }
+ }
}
@Override public void
@@ -962,18 +815,25 @@
@Override public void
changeIccPinForApp(String oldPin, String newPin, String aid, 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);
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_CHANGE_SIM_PIN, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " oldPin = "
+ + oldPin + " newPin = " + newPin + " aid = " + aid);
+ }
- rr.mParcel.writeInt(3);
- rr.mParcel.writeString(oldPin);
- rr.mParcel.writeString(newPin);
- rr.mParcel.writeString(aid);
-
- send(rr);
+ try {
+ radioProxy.changeIccPinForApp(rr.mSerial,
+ convertNullToEmptyString(oldPin),
+ convertNullToEmptyString(newPin),
+ convertNullToEmptyString(aid));
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "changeIccPinForApp", e);
+ }
+ }
}
@Override public void
@@ -983,284 +843,2826 @@
@Override public void
changeIccPin2ForApp(String oldPin2, String newPin2, String aid, 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);
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_CHANGE_SIM_PIN2, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " oldPin = "
+ + oldPin2 + " newPin = " + newPin2 + " aid = " + aid);
+ }
- rr.mParcel.writeInt(3);
- rr.mParcel.writeString(oldPin2);
- rr.mParcel.writeString(newPin2);
- rr.mParcel.writeString(aid);
-
- send(rr);
+ try {
+ radioProxy.changeIccPin2ForApp(rr.mSerial,
+ convertNullToEmptyString(oldPin2),
+ convertNullToEmptyString(newPin2),
+ convertNullToEmptyString(aid));
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "changeIccPin2ForApp", e);
+ }
+ }
}
@Override
- public void
- changeBarringPassword(String facility, String oldPwd, String newPwd, Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_CHANGE_BARRING_PASSWORD, result);
+ public void supplyNetworkDepersonalization(String netpin, Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " netpin = "
+ + netpin);
+ }
- rr.mParcel.writeInt(3);
- rr.mParcel.writeString(facility);
- rr.mParcel.writeString(oldPwd);
- rr.mParcel.writeString(newPwd);
-
- send(rr);
+ try {
+ radioProxy.supplyNetworkDepersonalization(rr.mSerial,
+ convertNullToEmptyString(netpin));
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "supplyNetworkDepersonalization", e);
+ }
+ }
}
@Override
- public void
- supplyNetworkDepersonalization(String netpin, Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_ENTER_NETWORK_DEPERSONALIZATION, result);
+ public void getCurrentCalls(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_GET_CURRENT_CALLS, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ }
- rr.mParcel.writeInt(1);
- rr.mParcel.writeString(netpin);
-
- send(rr);
+ try {
+ radioProxy.getCurrentCalls(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "getCurrentCalls", e);
+ }
+ }
}
@Override
- 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);
- }
-
- @Override
- @Deprecated public void
- getPDPContextList(Message result) {
- getDataCallList(result);
- }
-
- @Override
- 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);
- }
-
- @Override
- public void
- dial (String address, int clirMode, Message result) {
+ public void dial(String address, int clirMode, Message result) {
dial(address, clirMode, null, result);
}
@Override
- public void
- dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_DIAL, result);
+ public void dial(String address, int clirMode, UUSInfo uusInfo, Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_DIAL, result,
+ mRILDefaultWorkSource);
- rr.mParcel.writeString(address);
- rr.mParcel.writeInt(clirMode);
+ Dial dialInfo = new Dial();
+ dialInfo.address = convertNullToEmptyString(address);
+ dialInfo.clir = clirMode;
+ if (uusInfo != null) {
+ UusInfo info = new UusInfo();
+ info.uusType = uusInfo.getType();
+ info.uusDcs = uusInfo.getDcs();
+ info.uusData = new String(uusInfo.getUserData());
+ dialInfo.uusInfo.add(info);
+ }
- if (uusInfo == null) {
- rr.mParcel.writeInt(0); // UUS information is absent
- } else {
- rr.mParcel.writeInt(1); // UUS information is present
- rr.mParcel.writeInt(uusInfo.getType());
- rr.mParcel.writeInt(uusInfo.getDcs());
- rr.mParcel.writeByteArray(uusInfo.getUserData());
+ if (RILJ_LOGD) {
+ // Do not log function arg for privacy
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ }
+
+ try {
+ radioProxy.dial(rr.mSerial, dialInfo);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "dial", e);
+ }
}
-
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
-
- send(rr);
}
@Override
- public void
- getIMSI(Message result) {
+ public void getIMSI(Message result) {
getIMSIForApp(null, result);
}
@Override
- public void
- getIMSIForApp(String aid, Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result);
+ public void getIMSIForApp(String aid, Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_GET_IMSI, result,
+ mRILDefaultWorkSource);
- rr.mParcel.writeInt(1);
- rr.mParcel.writeString(aid);
-
- if (RILJ_LOGD) riljLog(rr.serialString() +
- "> getIMSI: " + requestToString(rr.mRequest)
- + " aid: " + aid);
-
- send(rr);
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString()
+ + "> " + requestToString(rr.mRequest) + " aid = " + aid);
+ }
+ try {
+ radioProxy.getImsiForApp(rr.mSerial, convertNullToEmptyString(aid));
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "getIMSIForApp", e);
+ }
+ }
}
@Override
- public void
- getIMEI(Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEI, result);
+ public void hangupConnection(int gsmIndex, Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " gsmIndex = "
+ + gsmIndex);
+ }
- send(rr);
+ try {
+ radioProxy.hangup(rr.mSerial, gsmIndex);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "hangupConnection", e);
+ }
+ }
}
@Override
- public void
- getIMEISV(Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMEISV, result);
+ public void hangupWaitingOrBackground(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
- send(rr);
- }
-
-
- @Override
- 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.mParcel.writeInt(1);
- rr.mParcel.writeInt(gsmIndex);
-
- send(rr);
+ try {
+ radioProxy.hangupWaitingOrBackground(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "hangupWaitingOrBackground", e);
+ }
+ }
}
@Override
- public void
- hangupWaitingOrBackground (Message result) {
- RILRequest rr = RILRequest.obtain(RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND,
- result);
+ public void hangupForegroundResumeBackground(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
- send(rr);
+ try {
+ radioProxy.hangupForegroundResumeBackground(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "hangupForegroundResumeBackground", e);
+ }
+ }
}
@Override
- 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));
+ public void switchWaitingOrHoldingAndActive(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, result,
+ mRILDefaultWorkSource);
- send(rr);
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ try {
+ radioProxy.switchWaitingOrHoldingAndActive(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "switchWaitingOrHoldingAndActive", e);
+ }
+ }
}
@Override
- 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));
+ public void conference(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_CONFERENCE, result,
+ mRILDefaultWorkSource);
- send(rr);
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ try {
+ radioProxy.conference(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "conference", e);
+ }
+ }
}
@Override
- public void
- conference (Message result) {
- RILRequest rr
- = RILRequest.obtain(RIL_REQUEST_CONFERENCE, result);
+ public void rejectCall(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_UDUB, result,
+ mRILDefaultWorkSource);
- if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
- send(rr);
+ try {
+ radioProxy.rejectCall(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "rejectCall", e);
+ }
+ }
}
+ @Override
+ public void getLastCallFailCause(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ try {
+ radioProxy.getLastCallFailCause(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "getLastCallFailCause", e);
+ }
+ }
+ }
+
+ @Override
+ public void getSignalStrength(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_SIGNAL_STRENGTH, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ try {
+ radioProxy.getSignalStrength(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "getSignalStrength", e);
+ }
+ }
+ }
+
+ @Override
+ public void getVoiceRegistrationState(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_VOICE_REGISTRATION_STATE, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ try {
+ radioProxy.getVoiceRegistrationState(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "getVoiceRegistrationState", e);
+ }
+ }
+ }
+
+ @Override
+ public void getDataRegistrationState(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_DATA_REGISTRATION_STATE, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ try {
+ radioProxy.getDataRegistrationState(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "getDataRegistrationState", e);
+ }
+ }
+ }
+
+ @Override
+ public void getOperator(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_OPERATOR, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+
+ try {
+ radioProxy.getOperator(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "getOperator", e);
+ }
+ }
+ }
+
+ @Override
+ public void setRadioPower(boolean on, Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ RILRequest rr = obtainRequest(RIL_REQUEST_RADIO_POWER, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " on = " + on);
+ }
+
+ try {
+ radioProxy.setRadioPower(rr.mSerial, on);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "setRadioPower", e);
+ }
+ }
+ }
+
+ @Override
+ public void sendDtmf(char c, Message result) {
+ IRadio radioProxy = getRadioProxy(result);