Merge "Get default from CdmaSubscriptionSourceManager"
diff --git a/Android.mk b/Android.mk
index 186b3f0..915ad01 100644
--- a/Android.mk
+++ b/Android.mk
@@ -25,14 +25,17 @@
$(call all-logtags-files-under, src/java) \
$(call all-proto-files-under, proto)
-LOCAL_JAVA_LIBRARIES := voip-common ims-common
-LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.radio-V1.1-java-static \
- android.hardware.radio.deprecated-V1.0-java-static
+LOCAL_JAVA_LIBRARIES := voip-common ims-common services
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android.hardware.radio-V1.0-java \
+ android.hardware.radio-V1.1-java \
+ android.hardware.radio.deprecated-V1.0-java \
+ android.hidl.base-V1.0-java
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/OWNERS b/OWNERS
new file mode 100644
index 0000000..0786c0e
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,7 @@
+amitmahajan@google.com
+breadley@google.com
+fionaxu@google.com
+jackyu@google.com
+hallliu@google.com
+rgreenwalt@google.com
+tgunn@google.com
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 a91e05e..0000000
--- a/src/java/android/provider/Telephony.java
+++ /dev/null
@@ -1,3246 +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.app.job.JobService;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.sqlite.SqliteWrapper;
-import android.net.Uri;
-import android.telephony.Rlog;
-import android.telephony.ServiceState;
-import android.telephony.SmsMessage;
-import android.telephony.SubscriptionManager;
-import android.text.TextUtils;
-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, access to the APN list, including the MMSC to use, and the service state.
- *
- * <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
- };
- }
-
- /**
- * Constants for interfacing with the ServiceStateProvider and the different fields of the
- * {@link ServiceState} class accessible through the provider.
- */
- public static final class ServiceStateTable {
-
- /**
- * Not instantiable.
- * @hide
- */
- private ServiceStateTable() {}
-
- /**
- * The authority string for the ServiceStateProvider
- */
- public static final String AUTHORITY = "service-state";
-
- /**
- * The {@code content://} style URL for the ServiceStateProvider
- */
- public static final Uri CONTENT_URI = Uri.parse("content://service-state/");
-
- /**
- * Generates a content {@link Uri} used to receive updates on a specific field in the
- * ServiceState provider.
- * <p>
- * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
- * {@link ServiceState} while your app is running. You can also use a {@link JobService} to
- * ensure your app is notified of changes to the {@link Uri} even when it is not running.
- * Note, however, that using a {@link JobService} does not guarantee timely delivery of
- * updates to the {@link Uri}.
- *
- * @param subscriptionId the subscriptionId to receive updates on
- * @param field the ServiceState field to receive updates on
- * @return the Uri used to observe {@link ServiceState} changes
- */
- public static Uri getUriForSubscriptionIdAndField(int subscriptionId, String field) {
- return CONTENT_URI.buildUpon().appendEncodedPath(String.valueOf(subscriptionId))
- .appendEncodedPath(field).build();
- }
-
- /**
- * Generates a content {@link Uri} used to receive updates on every field in the
- * ServiceState provider.
- * <p>
- * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
- * {@link ServiceState} while your app is running. You can also use a {@link JobService} to
- * ensure your app is notified of changes to the {@link Uri} even when it is not running.
- * Note, however, that using a {@link JobService} does not guarantee timely delivery of
- * updates to the {@link Uri}.
- *
- * @param subscriptionId the subscriptionId to receive updates on
- * @return the Uri used to observe {@link ServiceState} changes
- */
- public static Uri getUriForSubscriptionId(int subscriptionId) {
- return CONTENT_URI.buildUpon()
- .appendEncodedPath(String.valueOf(subscriptionId)).build();
- }
-
- /**
- * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance.
- *
- * @param state the ServiceState to convert into ContentValues
- * @return the convertedContentValues instance
- * @hide
- */
- public static ContentValues getContentValuesForServiceState(ServiceState state) {
- ContentValues values = new ContentValues();
- values.put(VOICE_REG_STATE, state.getVoiceRegState());
- values.put(DATA_REG_STATE, state.getDataRegState());
- values.put(VOICE_ROAMING_TYPE, state.getVoiceRoamingType());
- values.put(DATA_ROAMING_TYPE, state.getDataRoamingType());
- values.put(VOICE_OPERATOR_ALPHA_LONG, state.getVoiceOperatorAlphaLong());
- values.put(VOICE_OPERATOR_ALPHA_SHORT, state.getVoiceOperatorAlphaShort());
- values.put(VOICE_OPERATOR_NUMERIC, state.getVoiceOperatorNumeric());
- values.put(DATA_OPERATOR_ALPHA_LONG, state.getDataOperatorAlphaLong());
- values.put(DATA_OPERATOR_ALPHA_SHORT, state.getDataOperatorAlphaShort());
- values.put(DATA_OPERATOR_NUMERIC, state.getDataOperatorNumeric());
- values.put(IS_MANUAL_NETWORK_SELECTION, state.getIsManualSelection());
- values.put(RIL_VOICE_RADIO_TECHNOLOGY, state.getRilVoiceRadioTechnology());
- values.put(RIL_DATA_RADIO_TECHNOLOGY, state.getRilDataRadioTechnology());
- values.put(CSS_INDICATOR, state.getCssIndicator());
- values.put(NETWORK_ID, state.getNetworkId());
- values.put(SYSTEM_ID, state.getSystemId());
- values.put(CDMA_ROAMING_INDICATOR, state.getCdmaRoamingIndicator());
- values.put(CDMA_DEFAULT_ROAMING_INDICATOR, state.getCdmaDefaultRoamingIndicator());
- values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex());
- values.put(CDMA_ERI_ICON_MODE, state.getCdmaEriIconMode());
- values.put(IS_EMERGENCY_ONLY, state.isEmergencyOnly());
- values.put(IS_DATA_ROAMING_FROM_REGISTRATION, state.getDataRoamingFromRegistration());
- values.put(IS_USING_CARRIER_AGGREGATION, state.isUsingCarrierAggregation());
- return values;
- }
-
- /**
- * An integer value indicating the current voice service state.
- * <p>
- * Valid values: {@link ServiceState#STATE_IN_SERVICE},
- * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
- * {@link ServiceState#STATE_POWER_OFF}.
- * <p>
- * This is the same as {@link ServiceState#getState()}.
- */
- public static final String VOICE_REG_STATE = "voice_reg_state";
-
- /**
- * An integer value indicating the current data service state.
- * <p>
- * Valid values: {@link ServiceState#STATE_IN_SERVICE},
- * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
- * {@link ServiceState#STATE_POWER_OFF}.
- * <p>
- * This is the same as {@link ServiceState#getDataRegState()}.
- * @hide
- */
- public static final String DATA_REG_STATE = "data_reg_state";
-
- /**
- * An integer value indicating the current voice roaming type.
- * <p>
- * This is the same as {@link ServiceState#getVoiceRoamingType()}.
- * @hide
- */
- public static final String VOICE_ROAMING_TYPE = "voice_roaming_type";
-
- /**
- * An integer value indicating the current data roaming type.
- * <p>
- * This is the same as {@link ServiceState#getDataRoamingType()}.
- * @hide
- */
- public static final String DATA_ROAMING_TYPE = "data_roaming_type";
-
- /**
- * The current registered voice network operator name in long alphanumeric format.
- * <p>
- * This is the same as {@link ServiceState#getVoiceOperatorAlphaLong()}.
- * @hide
- */
- public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long";
-
- /**
- * The current registered operator name in short alphanumeric format.
- * <p>
- * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice
- * network operator name in long alphanumeric format.
- * <p>
- * This is the same as {@link ServiceState#getVoiceOperatorAlphaShort()}.
- * @hide
- */
- public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short";
-
-
- /**
- * The current registered operator numeric id.
- * <p>
- * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
- * network code.
- * <p>
- * This is the same as {@link ServiceState#getOperatorNumeric()}.
- */
- public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
-
- /**
- * The current registered data network operator name in long alphanumeric format.
- * <p>
- * This is the same as {@link ServiceState#getDataOperatorAlphaLong()}.
- * @hide
- */
- public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long";
-
- /**
- * The current registered data network operator name in short alphanumeric format.
- * <p>
- * This is the same as {@link ServiceState#getDataOperatorAlphaShort()}.
- * @hide
- */
- public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short";
-
- /**
- * The current registered data network operator numeric id.
- * <p>
- * This is the same as {@link ServiceState#getDataOperatorNumeric()}.
- * @hide
- */
- public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric";
-
- /**
- * The current network selection mode.
- * <p>
- * This is the same as {@link ServiceState#getIsManualSelection()}.
- */
- public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
-
- /**
- * This is the same as {@link ServiceState#getRilVoiceRadioTechnology()}.
- * @hide
- */
- public static final String RIL_VOICE_RADIO_TECHNOLOGY = "ril_voice_radio_technology";
-
- /**
- * This is the same as {@link ServiceState#getRilDataRadioTechnology()}.
- * @hide
- */
- public static final String RIL_DATA_RADIO_TECHNOLOGY = "ril_data_radio_technology";
-
- /**
- * This is the same as {@link ServiceState#getCssIndicator()}.
- * @hide
- */
- public static final String CSS_INDICATOR = "css_indicator";
-
- /**
- * This is the same as {@link ServiceState#getNetworkId()}.
- * @hide
- */
- public static final String NETWORK_ID = "network_id";
-
- /**
- * This is the same as {@link ServiceState#getSystemId()}.
- * @hide
- */
- public static final String SYSTEM_ID = "system_id";
-
- /**
- * This is the same as {@link ServiceState#getCdmaRoamingIndicator()}.
- * @hide
- */
- public static final String CDMA_ROAMING_INDICATOR = "cdma_roaming_indicator";
-
- /**
- * This is the same as {@link ServiceState#getCdmaDefaultRoamingIndicator()}.
- * @hide
- */
- public static final String CDMA_DEFAULT_ROAMING_INDICATOR =
- "cdma_default_roaming_indicator";
-
- /**
- * This is the same as {@link ServiceState#getCdmaEriIconIndex()}.
- * @hide
- */
- public static final String CDMA_ERI_ICON_INDEX = "cdma_eri_icon_index";
-
- /**
- * This is the same as {@link ServiceState#getCdmaEriIconMode()}.
- * @hide
- */
- public static final String CDMA_ERI_ICON_MODE = "cdma_eri_icon_mode";
-
- /**
- * This is the same as {@link ServiceState#isEmergencyOnly()}.
- * @hide
- */
- public static final String IS_EMERGENCY_ONLY = "is_emergency_only";
-
- /**
- * This is the same as {@link ServiceState#getDataRoamingFromRegistration()}.
- * @hide
- */
- public static final String IS_DATA_ROAMING_FROM_REGISTRATION =
- "is_data_roaming_from_registration";
-
- /**
- * This is the same as {@link ServiceState#isUsingCarrierAggregation()}.
- * @hide
- */
- public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
- }
-}
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 e31755a..0000000
--- a/src/java/android/telephony/SmsManager.java
+++ /dev/null
@@ -1,1671 +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.annotation.SystemApi;
-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 /* persistMessage*/);
- }
-
- private void sendTextMessageInternal(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.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
- destinationAddress,
- scAddress, text, sentIntent, deliveryIntent,
- persistMessage);
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
- * Send a text based SMS without writing it into the SMS Provider.
- *
- * <p>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
- * privileges.
- * </p>
- *
- * @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent)
- * @hide
- */
- @SystemApi
- public void sendTextMessageWithoutPersisting(
- String destinationAddress, String scAddress, String text,
- PendingIntent sentIntent, PendingIntent deliveryIntent) {
- sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent,
- false /* persistMessage */);
- }
-
- /**
- * 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 /* persistMessage*/);
- }
-
- private void sendMultipartTextMessageInternal(
- String destinationAddress, String scAddress, List<String> parts,
- List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents,
- boolean persistMessage) {
- 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, persistMessage);
- } 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>Requires Permission:
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
- * privileges.
- * </p>
- *
- * @see #sendMultipartTextMessage(String, String, ArrayList, ArrayList, ArrayList)
- * @hide
- **/
- @SystemApi
- public void sendMultipartTextMessageWithoutPersisting(
- String destinationAddress, String scAddress, List<String> parts,
- List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) {
- sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents,
- deliveryIntents, false /* persistMessage*/);
- }
-
- /**
- * 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 ba4deae..0000000
--- a/src/java/android/telephony/SmsMessage.java
+++ /dev/null
@@ -1,891 +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.hardware.radio.V1_0.CdmaSmsMessage;
-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(byte[] pdu) {
- // received SMS in 3GPP format
- SmsMessageBase wrappedMessage =
- com.android.internal.telephony.gsm.SmsMessage.newFromCMT(pdu);
-
- if (wrappedMessage != null) {
- return new SmsMessage(wrappedMessage);
- } else {
- Rlog.e(LOG_TAG, "newFromCMT(): wrappedMessage is null");
- return null;
- }
- }
-
- /** @hide */
- public static SmsMessage newCdmaSmsFromRil(CdmaSmsMessage msg) {
- // received SMS in 3GPP2 format
- SmsMessageBase wrappedMessage =
- com.android.internal.telephony.cdma.SmsMessage.newFromRil(msg);
-
- 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..f2a783f
--- /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.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 5400ae2..5e09c35 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -72,6 +72,7 @@
new RegistrantList();
protected RegistrantList mPcoDataRegistrants = new RegistrantList();
protected RegistrantList mCarrierInfoForImsiEncryptionRegistrants = new RegistrantList();
+ protected RegistrantList mRilNetworkScanResultRegistrants = new RegistrantList();
protected Registrant mGsmSmsRegistrant;
@@ -730,6 +731,17 @@
mHardwareConfigChangeRegistrants.remove(h);
}
+ @Override
+ public void registerForNetworkScanResult(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ mRilNetworkScanResultRegistrants.add(r);
+ }
+
+ @Override
+ public void unregisterForNetworkScanResult(Handler h) {
+ mRilNetworkScanResultRegistrants.remove(h);
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/src/java/com/android/internal/telephony/CallFailCause.java b/src/java/com/android/internal/telephony/CallFailCause.java
index 8d2093e..ed39b4d 100644
--- a/src/java/com/android/internal/telephony/CallFailCause.java
+++ b/src/java/com/android/internal/telephony/CallFailCause.java
@@ -60,6 +60,10 @@
int DIAL_MODIFIED_TO_SS = 245;
int DIAL_MODIFIED_TO_DIAL = 246;
+ //Emergency Redial
+ int EMERGENCY_TEMP_FAILURE = 325;
+ int EMERGENCY_PERM_FAILURE = 326;
+
int CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000;
int CDMA_DROP = 1001;
int CDMA_INTERCEPT = 1002;
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/CallStateException.java b/src/java/com/android/internal/telephony/CallStateException.java
index cac701a..8429146 100644
--- a/src/java/com/android/internal/telephony/CallStateException.java
+++ b/src/java/com/android/internal/telephony/CallStateException.java
@@ -26,7 +26,7 @@
/** The error code is not valid (Not received a disconnect cause) */
public static final int ERROR_INVALID = -1;
- public static final int ERROR_DISCONNECTED = 1;
+ public static final int ERROR_OUT_OF_SERVICE = 1;
public static final int ERROR_POWER_OFF = 2;
public
diff --git a/src/java/com/android/internal/telephony/CallTracker.java b/src/java/com/android/internal/telephony/CallTracker.java
index ad64a4a..23874e2 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;
}
}
}
@@ -290,6 +296,14 @@
public abstract PhoneConstants.State getState();
protected abstract void log(String msg);
+ /**
+ * Called when the call tracker should attempt to reconcile its calls against its underlying
+ * phone implementation and cleanup any stale calls.
+ */
+ public void cleanupCalls() {
+ // no base implementation
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("CallTracker:");
pw.println(" mPendingOperations=" + mPendingOperations);
diff --git a/src/java/com/android/internal/telephony/CarrierActionAgent.java b/src/java/com/android/internal/telephony/CarrierActionAgent.java
index 46430d6..d67636b 100644
--- a/src/java/com/android/internal/telephony/CarrierActionAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierActionAgent.java
@@ -19,15 +19,19 @@
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.telephony.TelephonyManager;
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;
@@ -53,6 +57,10 @@
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;
+ public static final int EVENT_APM_SETTINGS_CHANGED = 3;
+ public static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED = 4;
+ public static final int EVENT_DATA_ROAMING_OFF = 5;
+ public static final int EVENT_SIM_STATE_CHANGED = 6;
/** Member variables */
private final Phone mPhone;
@@ -65,6 +73,8 @@
/** 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
@@ -72,9 +82,20 @@
final String action = intent.getAction();
final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){
- if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState) ||
- IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) {
+ if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState)) {
sendEmptyMessage(CARRIER_ACTION_RESET);
+ String mobileData = Settings.Global.MOBILE_DATA;
+ if (TelephonyManager.getDefault().getSimCount() != 1) {
+ mobileData = mobileData + mPhone.getSubId();
+ }
+ mSettingsObserver.observe(Settings.Global.getUriFor(mobileData),
+ EVENT_MOBILE_DATA_SETTINGS_CHANGED);
+ mSettingsObserver.observe(
+ Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
+ EVENT_APM_SETTINGS_CHANGED);
+ } else if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) {
+ sendEmptyMessage(CARRIER_ACTION_RESET);
+ mSettingsObserver.unobserve();
}
}
}
@@ -85,6 +106,7 @@
mPhone = phone;
mPhone.getContext().registerReceiver(mReceiver,
new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
+ mSettingsObserver = new SettingsObserver(mPhone.getContext(), this);
if (DBG) log("Creating CarrierActionAgent");
}
@@ -108,11 +130,50 @@
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));
+ carrierActionReset();
+ break;
+ case EVENT_APM_SETTINGS_CHANGED:
+ log("EVENT_APM_SETTINGS_CHANGED");
+ if ((Settings.Global.getInt(mPhone.getContext().getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0)) {
+ carrierActionReset();
+ }
+ break;
+ case EVENT_MOBILE_DATA_SETTINGS_CHANGED:
+ log("EVENT_MOBILE_DATA_SETTINGS_CHANGED");
+ if (!mPhone.getDataEnabled()) carrierActionReset();
+ break;
+ case EVENT_DATA_ROAMING_OFF:
+ log("EVENT_DATA_ROAMING_OFF");
+ // reset carrier actions when exit roaming state.
+ carrierActionReset();
+ break;
+ case EVENT_SIM_STATE_CHANGED:
+ String iccState = (String) msg.obj;
+ if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState)) {
+ log("EVENT_SIM_STATE_CHANGED status: " + iccState);
+ carrierActionReset();
+ String mobileData = Settings.Global.MOBILE_DATA;
+ if (TelephonyManager.getDefault().getSimCount() != 1) {
+ mobileData = mobileData + mPhone.getSubId();
+ }
+ mSettingsObserver.observe(Settings.Global.getUriFor(mobileData),
+ EVENT_MOBILE_DATA_SETTINGS_CHANGED);
+ mSettingsObserver.observe(
+ Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
+ EVENT_APM_SETTINGS_CHANGED);
+ if (mPhone.getServiceStateTracker() != null) {
+ mPhone.getServiceStateTracker().registerForDataRoamingOff(
+ this, EVENT_DATA_ROAMING_OFF, null, false);
+ }
+ } else if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) {
+ log("EVENT_SIM_STATE_CHANGED status: " + iccState);
+ carrierActionReset();
+ mSettingsObserver.unobserve();
+ if (mPhone.getServiceStateTracker() != null) {
+ mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this);
+ }
+ }
break;
default:
loge("Unknown carrier action: " + msg.what);
@@ -144,6 +205,14 @@
sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled));
}
+ private void carrierActionReset() {
+ carrierActionSetMeteredApnsEnabled(true);
+ carrierActionSetRadioEnabled(true);
+ // notify configured carrier apps for reset
+ mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(
+ new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET));
+ }
+
private RegistrantList getRegistrantsFromAction(int action) {
switch (action) {
case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
@@ -200,6 +269,11 @@
list.remove(h);
}
+ @VisibleForTesting
+ public ContentObserver getContentObserver() {
+ return mSettingsObserver;
+ }
+
private void log(String s) {
Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
}
diff --git a/src/java/com/android/internal/telephony/CarrierInfoManager.java b/src/java/com/android/internal/telephony/CarrierInfoManager.java
new file mode 100644
index 0000000..96dd8c4
--- /dev/null
+++ b/src/java/com/android/internal/telephony/CarrierInfoManager.java
@@ -0,0 +1,52 @@
+/*
+ * 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.telephony.ImsiEncryptionInfo;
+
+ /**
+ * This class provides methods to retreive information from the CarrierKeyProvider.
+ */
+public class CarrierInfoManager {
+ private static final String TAG = "CarrierInfoManager";
+
+ /**
+ * Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
+ * @param keyType whether the key is being used for WLAN or ePDG.
+ * @return ImsiEncryptionInfo which contains the information including the public key to be
+ * used for encryption.
+ */
+ public static ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
+ //TODO implementation will be done in subsequent CL.
+ return null;
+ }
+
+ /**
+ * Sets the Carrier specific information that will be used to encrypt the IMSI and IMPI.
+ * This includes the public key and the key identifier. This information will be stored in the
+ * device keystore.
+ * @param imsiEncryptionInfo which includes the Key Type, the Public Key
+ * {@link java.security.PublicKey} and the Key Identifier.
+ * The keyIdentifier Attribute value pair that helps a server locate
+ * the private key to decrypt the permanent identity.
+ */
+ public static void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo) {
+ //TODO implementation will be done in subsequent CL.
+ return;
+ }
+}
+
diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
index 735bfe2..ab52c4a 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.
@@ -129,7 +131,7 @@
public void onReceive(Context context, Intent intent) {
CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- PersistableBundle b = carrierConfigManager.getConfig();
+ PersistableBundle b = carrierConfigManager.getConfigForSubId(mPhone.getSubId());
mDelay = b.getInt(CarrierConfigManager.KEY_PREF_NETWORK_NOTIFICATION_DELAY_INT);
Rlog.i(LOG_TAG, "reading time to delay notification: " + mDelay);
handleConfigChanges();
@@ -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);
@@ -189,4 +192,4 @@
context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFICATION_ID);
}
-}
\ No newline at end of file
+}
diff --git a/src/java/com/android/internal/telephony/CarrierSignalAgent.java b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
index 4d6d464..c6958cf 100644
--- a/src/java/com/android/internal/telephony/CarrierSignalAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierSignalAgent.java
@@ -34,11 +34,9 @@
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;
@@ -67,22 +65,24 @@
private final Phone mPhone;
/**
- * This is a map of intent action -> array list of component name of statically registered
+ * This is a map of intent action -> set 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.
+ * wakeup. Note we use Set as the entry value to compare config directly regardless of element
+ * order.
* @see CarrierConfigManager#KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY
*/
- private final Map<String, List<ComponentName>> mCachedWakeSignalConfigs = new HashMap<>();
+ private Map<String, Set<ComponentName>> mCachedWakeSignalConfigs = new HashMap<>();
/**
- * This is a map of intent action -> array list of component name of dynamically registered
+ * This is a map of intent action -> set 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.
+ * Note we use Set as the entry value to compare config directly regardless of element order.
* @see CarrierConfigManager#KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY
*/
- private final Map<String, List<ComponentName>> mCachedNoWakeSignalConfigs = new HashMap<>();
+ private Map<String, Set<ComponentName>> mCachedNoWakeSignalConfigs = new HashMap<>();
/**
* This is a list of supported signals from CarrierSignalAgent
@@ -100,12 +100,6 @@
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();
}
}
@@ -132,18 +126,36 @@
}
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);
+ Map<String, Set<ComponentName>> config = parseAndCache(
+ b.getStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY));
+ // In some rare cases, up-to-date config could be fetched with delay and all signals
+ // have already been delivered the receivers from the default carrier config.
+ // To handle this raciness, we should notify those receivers (from old configs)
+ // and reset carrier actions. This should be done before cached Config got purged
+ // and written with the up-to-date value, Otherwise those receivers from the
+ // old config might lingers without properly clean-up.
+ if (!mCachedWakeSignalConfigs.isEmpty()
+ && !config.equals(mCachedWakeSignalConfigs)) {
+ if (VDBG) log("carrier config changed, reset receivers from old config");
+ mPhone.getCarrierActionAgent().sendEmptyMessage(
+ CarrierActionAgent.CARRIER_ACTION_RESET);
+ }
+ mCachedWakeSignalConfigs = config;
}
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);
+ Map<String, Set<ComponentName>> config = parseAndCache(
+ b.getStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY));
+ if (!mCachedNoWakeSignalConfigs.isEmpty()
+ && !config.equals(mCachedNoWakeSignalConfigs)) {
+ if (VDBG) log("carrier config changed, reset receivers from old config");
+ mPhone.getCarrierActionAgent().sendEmptyMessage(
+ CarrierActionAgent.CARRIER_ACTION_RESET);
+ }
+ mCachedNoWakeSignalConfigs = config;
}
}
}
@@ -155,8 +167,8 @@
* @see #COMPONENT_NAME_DELIMITER
* @param configs raw information from carrier config
*/
- private void parseAndCache(String[] configs,
- Map<String, List<ComponentName>> cachedConfigs) {
+ private Map<String, Set<ComponentName>> parseAndCache(String[] configs) {
+ Map<String, Set<ComponentName>> newCachedWakeSignalConfigs = new HashMap<>();
if (!ArrayUtils.isEmpty(configs)) {
for (String config : configs) {
if (!TextUtils.isEmpty(config)) {
@@ -174,10 +186,10 @@
loge("Invalid signal name: " + s);
continue;
}
- List<ComponentName> componentList = cachedConfigs.get(s);
+ Set<ComponentName> componentList = newCachedWakeSignalConfigs.get(s);
if (componentList == null) {
- componentList = new ArrayList<>();
- cachedConfigs.put(s, componentList);
+ componentList = new HashSet<>();
+ newCachedWakeSignalConfigs.put(s, componentList);
}
componentList.add(componentName);
if (VDBG) {
@@ -191,6 +203,7 @@
}
}
}
+ return newCachedWakeSignalConfigs;
}
/**
@@ -215,7 +228,7 @@
* registered during run-time.
* @param wakeup true indicate wakeup receivers otherwise non-wakeup receivers
*/
- private void broadcast(Intent intent, List<ComponentName> receivers, boolean wakeup) {
+ private void broadcast(Intent intent, Set<ComponentName> receivers, boolean wakeup) {
final PackageManager packageManager = mPhone.getContext().getPackageManager();
for (ComponentName name : receivers) {
Intent signal = new Intent(intent);
@@ -257,19 +270,19 @@
*
*/
public void notifyCarrierSignalReceivers(Intent intent) {
- List<ComponentName> receiverList;
+ Set<ComponentName> receiverSet;
synchronized (mCachedWakeSignalConfigs) {
- receiverList = mCachedWakeSignalConfigs.get(intent.getAction());
- if (!ArrayUtils.isEmpty(receiverList)) {
- broadcast(intent, receiverList, WAKE);
+ receiverSet = mCachedWakeSignalConfigs.get(intent.getAction());
+ if (!ArrayUtils.isEmpty(receiverSet)) {
+ broadcast(intent, receiverSet, WAKE);
}
}
synchronized (mCachedNoWakeSignalConfigs) {
- receiverList = mCachedNoWakeSignalConfigs.get(intent.getAction());
- if (!ArrayUtils.isEmpty(receiverList)) {
- broadcast(intent, receiverList, NO_WAKE);
+ receiverSet = mCachedNoWakeSignalConfigs.get(intent.getAction());
+ if (!ArrayUtils.isEmpty(receiverSet)) {
+ broadcast(intent, receiverSet, NO_WAKE);
}
}
}
@@ -291,14 +304,14 @@
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
pw.println("mCachedWakeSignalConfigs:");
ipw.increaseIndent();
- for (Map.Entry<String, List<ComponentName>> entry : mCachedWakeSignalConfigs.entrySet()) {
+ for (Map.Entry<String, Set<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()) {
+ for (Map.Entry<String, Set<ComponentName>> entry : mCachedNoWakeSignalConfigs.entrySet()) {
pw.println("signal: " + entry.getKey() + " componentName list: " + entry.getValue());
}
ipw.decreaseIndent();
diff --git a/src/java/com/android/internal/telephony/CarrierSmsUtils.java b/src/java/com/android/internal/telephony/CarrierSmsUtils.java
index 845860c..a64aea7 100644
--- a/src/java/com/android/internal/telephony/CarrierSmsUtils.java
+++ b/src/java/com/android/internal/telephony/CarrierSmsUtils.java
@@ -21,6 +21,7 @@
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;
@@ -78,13 +79,17 @@
return null;
}
- PersistableBundle config = cm.getConfigForSubId(phone.getSubId());
- if (config == null) {
- if (VDBG) Rlog.v(TAG, "No CarrierConfig for subId:" + phone.getSubId());
- 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);
}
-
- return config.getString(CARRIER_IMS_PACKAGE_KEY, null);
}
private CarrierSmsUtils() {}
diff --git a/src/java/com/android/internal/telephony/CellBroadcastHandler.java b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
index 44479c5..4227148 100644
--- a/src/java/com/android/internal/telephony/CellBroadcastHandler.java
+++ b/src/java/com/android/internal/telephony/CellBroadcastHandler.java
@@ -86,11 +86,17 @@
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;
}
@@ -112,8 +118,6 @@
}
}
- intent.setPackage(mContext.getResources().getString(
- com.android.internal.R.string.config_defaultCellBroadcastReceiverPkg));
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
index ba4d86f..c47faab 100644
--- a/src/java/com/android/internal/telephony/ClientWakelockAccountant.java
+++ b/src/java/com/android/internal/telephony/ClientWakelockAccountant.java
@@ -20,7 +20,6 @@
import android.telephony.Rlog;
import com.android.internal.annotations.VisibleForTesting;
-
import java.util.ArrayList;
public class ClientWakelockAccountant {
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 3dfbcf3..524b813 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -21,13 +21,14 @@
import android.os.WorkSource;
import android.service.carrier.CarrierIdentifier;
import android.telephony.ClientRequestStats;
+import android.telephony.ImsiEncryptionInfo;
+import android.telephony.NetworkScanRequest;
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.uicc.IccCardStatus;
-import java.security.PublicKey;
import java.util.List;
/**
@@ -1284,12 +1285,29 @@
/**
* Queries the currently available networks
*
- * ((AsyncResult)response.obj).result is a List of NetworkInfo objects
+ * ((AsyncResult)response.obj).result is a List of NetworkInfo objects
*/
void getAvailableNetworks(Message response);
- void getBasebandVersion (Message response);
+ /**
+ * Starts a radio network scan
+ *
+ * ((AsyncResult)response.obj).result is a NetworkScanResult object
+ */
+ void startNetworkScan(NetworkScanRequest nsr, Message response);
+ /**
+ * Stops the ongoing network scan
+ *
+ * ((AsyncResult)response.obj).result is a NetworkScanResult object
+ *
+ */
+ void stopNetworkScan(Message response);
+
+ /**
+ * Gets the baseband version
+ */
+ void getBasebandVersion(Message response);
/**
* (AsyncResult)response.obj).result will be an Integer representing
@@ -1443,7 +1461,7 @@
* specific.
* @param response callback message
*/
- void setCarrierInfoForImsiEncryption(PublicKey publicKey, String keyIdentifier,
+ void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo,
Message response);
void invokeOemRilRequestStrings(String[] strings, Message response);
@@ -2078,10 +2096,13 @@
/**
* Set SIM card power up or down
*
- * @param powerUp True if powering up the sim card
+ * @param state State of SIM (power down, power up, pass through)
+ * - {@link android.telephony.TelephonyManager#CARD_POWER_DOWN}
+ * - {@link android.telephony.TelephonyManager#CARD_POWER_UP}
+ * - {@link android.telephony.TelephonyManager#CARD_POWER_UP_PASS_THROUGH}
* @param result callback message contains the information of SUCCESS/FAILURE
*/
- void setSimCardPower(boolean powerUp, Message result);
+ void setSimCardPower(int state, Message result);
/**
* Register for unsolicited Carrier Public Key.
@@ -2099,6 +2120,22 @@
*/
void unregisterForCarrierInfoForImsiEncryption(Handler h);
+ /**
+ * Register for unsolicited Network Scan result.
+ *
+ * @param h Handler for notificaiton message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+ void registerForNetworkScanResult(Handler h, int what, Object obj);
+
+ /**
+ * DeRegister for unsolicited Network Scan result.
+ *
+ * @param h Handler for notificaiton message.
+ */
+ void unregisterForNetworkScanResult(Handler h);
+
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 26d7ef7..74ee5c5 100644
--- a/src/java/com/android/internal/telephony/Connection.java
+++ b/src/java/com/android/internal/telephony/Connection.java
@@ -34,6 +34,7 @@
* {@hide}
*/
public abstract class Connection {
+ private static final String TAG = "Connection";
public interface PostDialListener {
void onPostDialWait();
@@ -311,6 +312,15 @@
}
/**
+ * Sets the Connection connect time in {@link SystemClock#elapsedRealtime()} format.
+ *
+ * @param connectTimeReal the new connect time.
+ */
+ public void setConnectTimeReal(long connectTimeReal) {
+ mConnectTimeReal = connectTimeReal;
+ }
+
+ /**
* Connection connect time in elapsedRealtime() format.
* For outgoing calls: Begins at (DIALING|ALERTING) -> ACTIVE transition.
* For incoming calls: Begins at (INCOMING|WAITING) -> ACTIVE transition.
@@ -633,6 +643,7 @@
mOrigConnection = c.getOrigConnection();
mPostDialString = c.mPostDialString;
mNextPostDialChar = c.mNextPostDialChar;
+ mPostDialState = c.mPostDialState;
}
/**
@@ -817,6 +828,16 @@
public void setConnectionExtras(Bundle extras) {
if (extras != null) {
mExtras = new Bundle(extras);
+
+ int previousCount = mExtras.size();
+ // Prevent vendors from passing in extras other than primitive types and android API
+ // parcelables.
+ mExtras = mExtras.filterValues();
+ int filteredCount = mExtras.size();
+ if (filteredCount != previousCount) {
+ Rlog.i(TAG, "setConnectionExtras: filtering " + (previousCount - filteredCount)
+ + " invalid extras.");
+ }
} else {
mExtras = null;
}
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index d11a5c6..504bf1d 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -22,12 +22,14 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.CellInfo;
+import android.telephony.PreciseCallState;
import android.telephony.Rlog;
-import android.telephony.VoLteServiceState;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.telephony.PreciseCallState;
+import android.telephony.VoLteServiceState;
+
+import com.android.internal.telephony.PhoneConstantConversions;
import java.util.List;
@@ -57,7 +59,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
@@ -175,15 +178,14 @@
try {
if (mRegistry != null) {
mRegistry.notifyDataConnectionForSubscriber(subId,
- convertDataState(state),
- sender.isDataConnectivityPossible(apnType), reason,
- sender.getActiveApnHost(apnType),
- apnType,
- linkProperties,
- networkCapabilities,
- ((telephony!=null) ? telephony.getDataNetworkType(subId) :
- TelephonyManager.NETWORK_TYPE_UNKNOWN),
- roaming);
+ PhoneConstantConversions.convertDataState(state),
+ sender.isDataAllowed(), reason,
+ sender.getActiveApnHost(apnType),
+ apnType,
+ linkProperties,
+ networkCapabilities,
+ ((telephony != null) ? telephony.getDataNetworkType(subId) :
+ TelephonyManager.NETWORK_TYPE_UNKNOWN), roaming);
}
} catch (RemoteException ex) {
// system process is dead
@@ -316,70 +318,6 @@
}
/**
- * 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;
- }
- }
-
- /**
- * 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;
- }
- }
-
- /**
* Convert the {@link Phone.DataActivityState} enum into the TelephonyManager.DATA_* constants
* for the public API.
*/
diff --git a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
index de3be01..5960051 100755
--- a/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaCallTracker.java
@@ -24,9 +24,11 @@
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;
@@ -38,6 +40,7 @@
import android.text.TextUtils;
import android.util.EventLog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
import com.android.internal.telephony.metrics.TelephonyMetrics;
@@ -66,7 +69,8 @@
private static final int MAX_CONNECTIONS_PER_CALL_CDMA = 1; //only 1 connection allowed per call
//***** Instance Variables
- private GsmCdmaConnection mConnections[];
+ @VisibleForTesting
+ public GsmCdmaConnection[] mConnections;
private RegistrantList mVoiceCallEndedRegistrants = new RegistrantList();
private RegistrantList mVoiceCallStartedRegistrants = new RegistrantList();
@@ -166,6 +170,11 @@
if (mPhone.isPhoneTypeGsm()) {
mConnections = new GsmCdmaConnection[MAX_CONNECTIONS_GSM];
mCi.unregisterForCallWaitingInfo(this);
+ // Prior to phone switch to GSM, if CDMA has any emergency call
+ // data will be in disabled state, after switching to GSM enable data.
+ if (mIsInEmergencyCall) {
+ mPhone.mDcTracker.setInternalDataEnabled(true);
+ }
} else {
mConnections = new GsmCdmaConnection[MAX_CONNECTIONS_CDMA];
mPendingCallInEcm = false;
@@ -180,10 +189,9 @@
private void reset() {
Rlog.d(LOG_TAG, "reset");
- clearDisconnected();
-
for (GsmCdmaConnection gsmCdmaConnection : mConnections) {
if (gsmCdmaConnection != null) {
+ gsmCdmaConnection.onDisconnect(DisconnectCause.ERROR_UNSPECIFIED);
gsmCdmaConnection.dispose();
}
}
@@ -194,7 +202,7 @@
mConnections = null;
mPendingMO = null;
- mState = PhoneConstants.State.IDLE;
+ clearDisconnected();
}
@Override
@@ -465,9 +473,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 {
@@ -1089,10 +1105,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);
}
@@ -1376,11 +1392,14 @@
case EVENT_CONFERENCE_RESULT:
if (isPhoneTypeGsm()) {
- // The conference merge failed, so notify listeners. Ultimately this bubbles up
- // to Telecom, which will inform the InCall UI of the failure.
- Connection connection = mForegroundCall.getLatestConnection();
- if (connection != null) {
- connection.onConferenceMergeFailed();
+ ar = (AsyncResult) msg.obj;
+ if (ar.exception != null) {
+ // The conference merge failed, so notify listeners. Ultimately this
+ // bubbles up to Telecom, which will inform the InCall UI of the failure.
+ Connection connection = mForegroundCall.getLatestConnection();
+ if (connection != null) {
+ connection.onConferenceMergeFailed();
+ }
}
}
// fall through
@@ -1662,4 +1681,13 @@
MAX_CONNECTIONS_PER_CALL_GSM :
MAX_CONNECTIONS_PER_CALL_CDMA;
}
+
+ /**
+ * Called to force the call tracker to cleanup any stale calls. Does this by triggering
+ * {@code GET_CURRENT_CALLS} on the RIL.
+ */
+ @Override
+ public void cleanupCalls() {
+ pollCallsWhenSafe();
+ }
}
diff --git a/src/java/com/android/internal/telephony/GsmCdmaConnection.java b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
index 1b453e6..f126600 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaConnection.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
@@ -441,6 +441,11 @@
case CallFailCause.BEARER_NOT_AVAIL:
return DisconnectCause.CONGESTION;
+ case CallFailCause.EMERGENCY_TEMP_FAILURE:
+ return DisconnectCause.EMERGENCY_TEMP_FAILURE;
+ case CallFailCause.EMERGENCY_PERM_FAILURE:
+ return DisconnectCause.EMERGENCY_PERM_FAILURE;
+
case CallFailCause.ACM_LIMIT_EXCEEDED:
return DisconnectCause.LIMIT_EXCEEDED;
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index cd73e76..3344da6 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -28,7 +28,7 @@
import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
@@ -55,6 +55,8 @@
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.CellLocation;
+import android.telephony.ImsiEncryptionInfo;
+import android.telephony.NetworkScanRequest;
import android.telephony.PhoneNumberUtils;
import android.telephony.Rlog;
import android.telephony.ServiceState;
@@ -62,7 +64,6 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.UssdResponse;
-
import android.telephony.cdma.CdmaCellLocation;
import android.text.TextUtils;
import android.util.Log;
@@ -74,6 +75,7 @@
import com.android.internal.telephony.cdma.EriManager;
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;
@@ -89,7 +91,9 @@
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;
@@ -615,22 +619,13 @@
}
}
- @Override
- public boolean isInEcm() {
- if (isPhoneTypeGsm()) {
- return false;
- } else {
- return mIsPhoneInEcmState;
- }
- }
-
//CDMA
private void sendEmergencyCallbackModeChange(){
//Send an Intent
Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
- intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, mIsPhoneInEcmState);
+ intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, isInEcm());
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
if (DBG) logd("sendEmergencyCallbackModeChange");
}
@@ -640,7 +635,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 +1052,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 =
@@ -1075,7 +1070,7 @@
&& isEmergency
&& alwaysTryImsForEmergencyCarrierConfig
&& ImsManager.isNonTtyOrTtyOnVolteEnabled(mContext)
- && (imsPhone.getServiceState().getState() != ServiceState.STATE_POWER_OFF);
+ && imsPhone.isImsAvailable();
String dialPart = PhoneNumberUtils.extractNetworkPortionAlt(PhoneNumberUtils.
stripSeparators(dialString));
@@ -1109,7 +1104,12 @@
} catch (CallStateException e) {
if (DBG) logd("IMS PS call exception " + e +
"imsUseEnabled =" + imsUseEnabled + ", imsPhone =" + imsPhone);
- if (!Phone.CS_FALLBACK.equals(e.getMessage())) {
+ // Do not throw a CallStateException and instead fall back to Circuit switch
+ // for emergency calls and MMI codes.
+ if (Phone.CS_FALLBACK.equals(e.getMessage()) || isEmergency) {
+ logi("IMS call failed with Exception: " + e.getMessage() + ". Falling back "
+ + "to CS.");
+ } else {
CallStateException ce = new CallStateException(e.getMessage());
ce.setStackTrace(e.getStackTrace());
throw ce;
@@ -1129,6 +1129,18 @@
CallStateException.ERROR_POWER_OFF,
"cannot dial voice call in airplane mode");
}
+ // Check for service before placing non emergency CS voice call.
+ // Allow dial only if either CS is camped on any RAT (or) PS is in LTE service.
+ if (mSST != null
+ && mSST.mSS.getState() == ServiceState.STATE_OUT_OF_SERVICE /* CS out of service */
+ && !(mSST.mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE
+ && ServiceState.isLte(mSST.mSS.getRilDataRadioTechnology())) /* PS not in LTE */
+ && !VideoProfile.isVideo(videoState) /* voice call */
+ && !isEmergency /* non-emergency call */) {
+ throw new CallStateException(
+ CallStateException.ERROR_OUT_OF_SERVICE,
+ "cannot dial voice call in out of service");
+ }
if (DBG) logd("Trying (non-IMS) CS call");
if (isPhoneTypeGsm()) {
@@ -1197,8 +1209,8 @@
// Only look at the Network portion for mmi
String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
GsmMmiCode mmi = GsmMmiCode.newFromDialString(networkPortion, this,
- mUiccApplication.get(), wrappedCallback);
- if (DBG) logd("dialing w/ mmi '" + mmi + "'...");
+ mUiccApplication.get(), wrappedCallback);
+ if (DBG) logd("dialInternal: dialing w/ mmi '" + mmi + "'...");
if (mmi == null) {
return mCT.dial(newDialString, uusInfo, intentExtras);
@@ -1207,13 +1219,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 {
@@ -1221,7 +1227,7 @@
}
}
- @Override
+ @Override
public boolean handlePinMmi(String dialString) {
MmiCode mmi;
if (isPhoneTypeGsm()) {
@@ -1245,15 +1251,50 @@
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) {
- try {
- dialInternal(ussdRequest, null, VideoProfile.STATE_AUDIO_ONLY, null, 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;
- } catch (Exception e) {
- logd("exception" + e);
- return false;
- }
+ }
+
+ // 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
@@ -1480,6 +1521,16 @@
}
@Override
+ public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
+ return CarrierInfoManager.getCarrierInfoForImsiEncryption(keyType);
+ }
+
+ @Override
+ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo) {
+ CarrierInfoManager.setCarrierInfoForImsiEncryption(imsiEncryptionInfo);
+ }
+
+ @Override
public String getGroupIdLevel1() {
if (isPhoneTypeGsm()) {
IccRecords r = mIccRecords.get();
@@ -1768,6 +1819,16 @@
}
@Override
+ public void startNetworkScan(NetworkScanRequest nsr, Message response) {
+ mCi.startNetworkScan(nsr, response);
+ }
+
+ @Override
+ public void stopNetworkScan(Message response) {
+ mCi.stopNetworkScan(response);
+ }
+
+ @Override
public void getNeighboringCids(Message response, WorkSource workSource) {
if (isPhoneTypeGsm()) {
mCi.getNeighboringCids(response, workSource);
@@ -1790,6 +1851,15 @@
}
@Override
+ public void setTTYMode(int ttyMode, Message onComplete) {
+ // Send out the TTY Mode change over RIL as well
+ super.setTTYMode(ttyMode, onComplete);
+ if (mImsPhone != null) {
+ mImsPhone.setTTYMode(ttyMode, onComplete);
+ }
+ }
+
+ @Override
public void setUiTTYMode(int uiTtyMode, Message onComplete) {
if (mImsPhone != null) {
mImsPhone.setUiTTYMode(uiTtyMode, onComplete);
@@ -1833,7 +1903,7 @@
@Override
public void setDataRoamingEnabled(boolean enable) {
- mDcTracker.setDataRoamingEnabled(enable);
+ mDcTracker.setDataRoamingEnabledByUser(enable);
}
@Override
@@ -1898,21 +1968,22 @@
* The exception is cancellation of an incoming USSD-REQUEST, which is
* not on the list.
*/
- logd("USSD Response:" + mmi);
if (mPendingMMIs.remove(mmi) || (isPhoneTypeGsm() && (mmi.isUssdRequest() ||
((GsmMmiCode)mmi).isSsInfo()))) {
ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver();
if (receiverCallback != null) {
- UssdResponse response = new UssdResponse(mmi.getDialString(), mmi.getMessage());
- Bundle returnData = new Bundle();
- returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response);
+ Rlog.i(LOG_TAG, "onMMIDone: invoking callback: " + mmi);
int returnCode = (mmi.getState() == MmiCode.State.COMPLETE) ?
TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE;
- receiverCallback.send(returnCode, returnData);
+ 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);
}
}
@@ -1930,6 +2001,7 @@
}
private void onNetworkInitiatedUssd(MmiCode mmi) {
+ Rlog.v(LOG_TAG, "onNetworkInitiatedUssd: mmi=" + mmi);
mMmiCompleteRegistrants.notifyRegistrants(
new AsyncResult(null, mmi, null));
}
@@ -1974,19 +2046,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);
}
}
@@ -1996,6 +2067,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);
}
@@ -2035,10 +2107,6 @@
}
}
}
- Phone imsPhone = mImsPhone;
- if (imsPhone != null) {
- imsPhone.getServiceState().setStateOff();
- }
mRadioOffOrNotAvailableRegistrants.notifyRegistrants();
}
@@ -2207,17 +2275,16 @@
break;
case EVENT_SIM_RECORDS_LOADED:
- if (isPhoneTypeGsm()) {
- updateCurrentCarrierInProvider();
+ updateCurrentCarrierInProvider();
- // Check if this is a different SIM than the previous one. If so unset the
- // voice mail number.
- String imsi = getVmSimImsi();
- String imsiFromSIM = getSubscriberId();
- if (imsi != null && imsiFromSIM != null && !imsiFromSIM.equals(imsi)) {
- storeVoiceMailNumber(null);
- setVmSimImsi(null);
- }
+ // Check if this is a different SIM than the previous one. If so unset the
+ // voice mail number.
+ String imsi = getVmSimImsi();
+ String imsiFromSIM = getSubscriberId();
+ if ((!isPhoneTypeGsm() || imsi != null) && imsiFromSIM != null
+ && !imsiFromSIM.equals(imsi)) {
+ storeVoiceMailNumber(null);
+ setVmSimImsi(null);
}
mSimRecordsLoadedRegistrants.notifyRegistrants();
@@ -2637,7 +2704,7 @@
if (isPhoneTypeGsm()) {
return false;
} else {
- return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
+ return mSST.getOtasp() != TelephonyManager.OTASP_NOT_NEEDED;
}
}
@@ -2647,26 +2714,35 @@
return (r != null) ? r.isCspPlmnEnabled() : false;
}
- public boolean isManualNetSelAllowed() {
+ /**
+ * Whether manual select is now allowed and we should set
+ * to auto network select mode.
+ */
+ public boolean shouldForceAutoNetworkSelect() {
int nwMode = Phone.PREFERRED_NT_MODE;
int subId = getSubId();
+ // If it's invalid subId, we shouldn't force to auto network select mode.
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ return false;
+ }
+
nwMode = android.provider.Settings.Global.getInt(mContext.getContentResolver(),
android.provider.Settings.Global.PREFERRED_NETWORK_MODE + subId, nwMode);
- logd("isManualNetSelAllowed in mode = " + nwMode);
+ logd("shouldForceAutoNetworkSelect in mode = " + nwMode);
/*
* For multimode targets in global mode manual network
- * selection is disallowed
+ * selection is disallowed. So we should force auto select mode.
*/
if (isManualSelProhibitedInGlobalMode()
&& ((nwMode == Phone.NT_MODE_LTE_CDMA_EVDO_GSM_WCDMA)
|| (nwMode == Phone.NT_MODE_GLOBAL)) ){
- logd("Manual selection not supported in mode = " + nwMode);
- return false;
+ logd("Should force auto network select mode = " + nwMode);
+ return true;
} else {
- logd("Manual selection is supported in mode = " + nwMode);
+ logd("Should not force auto network select mode = " + nwMode);
}
/*
@@ -2676,7 +2752,7 @@
* Note: the actual enabling/disabling manual selection for these
* cases will be controlled by csp
*/
- return true;
+ return false;
}
private boolean isManualSelProhibitedInGlobalMode() {
@@ -2730,6 +2806,10 @@
@Override
public void exitEmergencyCallbackMode() {
+ if (DBG) {
+ Rlog.d(LOG_TAG, "exitEmergencyCallbackMode: mImsPhone=" + mImsPhone
+ + " isPhoneTypeGsm=" + isPhoneTypeGsm());
+ }
if (isPhoneTypeGsm()) {
if (mImsPhone != null) {
mImsPhone.exitEmergencyCallbackMode();
@@ -2746,11 +2826,11 @@
//CDMA
private void handleEnterEmergencyCallbackMode(Message msg) {
if (DBG) {
- Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode,mIsPhoneInEcmState= "
- + mIsPhoneInEcmState);
+ Rlog.d(LOG_TAG, "handleEnterEmergencyCallbackMode, isInEcm()="
+ + isInEcm());
}
// if phone is not in Ecm mode, and it's changed to Ecm mode
- if (!mIsPhoneInEcmState) {
+ if (!isInEcm()) {
setIsInEcm(true);
// notify change
@@ -2770,8 +2850,8 @@
private void handleExitEmergencyCallbackMode(Message msg) {
AsyncResult ar = (AsyncResult)msg.obj;
if (DBG) {
- Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , mIsPhoneInEcmState "
- + ar.exception + mIsPhoneInEcmState);
+ Rlog.d(LOG_TAG, "handleExitEmergencyCallbackMode,ar.exception , isInEcm="
+ + ar.exception + isInEcm());
}
// Remove pending exit Ecm runnable, if any
removeCallbacks(mExitEcmRunnable);
@@ -2781,7 +2861,7 @@
}
// if exiting ecm success
if (ar.exception == null) {
- if (mIsPhoneInEcmState) {
+ if (isInEcm()) {
setIsInEcm(false);
}
@@ -3153,7 +3233,7 @@
Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED);
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) {
@@ -3216,7 +3296,7 @@
pw.println(" mCdmaSubscriptionSource=" + mCdmaSubscriptionSource);
pw.println(" mEriManager=" + mEriManager);
pw.println(" mWakeLock=" + mWakeLock);
- pw.println(" mIsPhoneInEcmState=" + mIsPhoneInEcmState);
+ pw.println(" isInEcm()=" + isInEcm());
if (VDBG) pw.println(" mEsn=" + mEsn);
if (VDBG) pw.println(" mMeid=" + mMeid);
pw.println(" mCarrierOtaSpNumSchema=" + mCarrierOtaSpNumSchema);
@@ -3368,6 +3448,10 @@
Rlog.d(LOG_TAG, "[GsmCdmaPhone] " + s);
}
+ private void logi(String s) {
+ Rlog.i(LOG_TAG, "[GsmCdmaPhone] " + s);
+ }
+
private void loge(String s) {
Rlog.e(LOG_TAG, "[GsmCdmaPhone] " + s);
}
diff --git a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
index 11225fc..0fc08c6 100644
--- a/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
+++ b/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java
@@ -604,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
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index 04bb568..59195f8 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;
@@ -64,6 +64,7 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
+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;
@@ -145,7 +146,7 @@
/** Sent on exit from {@link WaitingState} to return to idle after sending all broadcasts. */
private static final int EVENT_RETURN_TO_IDLE = 4;
- /** Release wakelock after a short timeout when returning to idle state. */
+ /** Release wakelock after {@link mWakeLockTimeout} when returning to idle state. */
private static final int EVENT_RELEASE_WAKELOCK = 5;
/** Sent by {@link SmsBroadcastUndelivered} after cleaning the raw table. */
@@ -215,6 +216,9 @@
private static String ACTION_OPEN_SMS_APP =
"com.android.internal.telephony.OPEN_DEFAULT_SMS_APP";
+ /** Timeout for releasing wakelock */
+ private int mWakeLockTimeout;
+
/**
* Create a new SMS broadcast helper.
* @param name the class name for logging
@@ -324,6 +328,14 @@
*/
private class StartupState extends State {
@Override
+ public void enter() {
+ if (DBG) log("entering Startup state");
+ // Set wakelock timeout to 0 during startup, this will ensure that the wakelock is not
+ // held if there are no pending messages to be handled.
+ setWakeLockTimeout(0);
+ }
+
+ @Override
public boolean processMessage(Message msg) {
log("StartupState.processMessage:" + msg.what);
switch (msg.what) {
@@ -355,7 +367,7 @@
@Override
public void enter() {
if (DBG) log("entering Idle state");
- sendMessageDelayed(EVENT_RELEASE_WAKELOCK, WAKELOCK_TIMEOUT);
+ sendMessageDelayed(EVENT_RELEASE_WAKELOCK, getWakeLockTimeout());
}
@Override
@@ -482,6 +494,14 @@
*/
private class WaitingState extends State {
@Override
+ public void exit() {
+ if (DBG) log("exiting Waiting state");
+ // Before moving to idle state, set wakelock timeout to WAKE_LOCK_TIMEOUT milliseconds
+ // to give any receivers time to take their own wake locks
+ setWakeLockTimeout(WAKELOCK_TIMEOUT);
+ }
+
+ @Override
public boolean processMessage(Message msg) {
log("WaitingState.processMessage:" + msg.what);
switch (msg.what) {
@@ -641,6 +661,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);
@@ -914,7 +937,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(
@@ -997,7 +1021,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) {
@@ -1066,7 +1090,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"
@@ -1074,7 +1099,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);
@@ -1102,11 +1127,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());
@@ -1260,8 +1296,10 @@
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);
@@ -1500,7 +1538,14 @@
@VisibleForTesting
public int getWakeLockTimeout() {
- return WAKELOCK_TIMEOUT;
+ return mWakeLockTimeout;
+ }
+
+ /**
+ * Sets the wakelock timeout to {@link timeOut} milliseconds
+ */
+ private void setWakeLockTimeout(int timeOut) {
+ mWakeLockTimeout = timeOut;
}
/**
diff --git a/src/java/com/android/internal/telephony/IntentBroadcaster.java b/src/java/com/android/internal/telephony/IntentBroadcaster.java
new file mode 100644
index 0000000..7528819
--- /dev/null
+++ b/src/java/com/android/internal/telephony/IntentBroadcaster.java
@@ -0,0 +1,102 @@
+/*
+ * 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.app.ActivityManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.UserHandle;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This class is used to broadcast intents that need to be rebroadcast after the device is unlocked.
+ * NOTE: Currently this is used only for SIM_STATE_CHANGED so logic is hardcoded for that;
+ * for example broadcasts are always sticky, only the last intent for the slotId is rebroadcast,
+ * etc.
+ */
+public class IntentBroadcaster {
+ private static final String TAG = "IntentBroadcaster";
+
+ private Map<Integer, Intent> mRebroadcastIntents = new HashMap<>();
+ private static IntentBroadcaster sIntentBroadcaster;
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
+ synchronized (mRebroadcastIntents) {
+ // rebroadcast intents
+ Iterator iterator = mRebroadcastIntents.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Map.Entry pair = (Map.Entry) iterator.next();
+ Intent i = (Intent) pair.getValue();
+ i.putExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK, true);
+ iterator.remove();
+ logd("Rebroadcasting intent " + i.getAction() + " "
+ + i.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)
+ + " for slotId " + pair.getKey());
+ ActivityManager.broadcastStickyIntent(i, UserHandle.USER_ALL);
+ }
+ }
+ }
+ }
+ };
+
+ private IntentBroadcaster(Context context) {
+ context.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
+ }
+
+ /**
+ * Method to get an instance of IntentBroadcaster after creating one if needed.
+ * @return IntentBroadcaster instance
+ */
+ public static IntentBroadcaster getInstance(Context context) {
+ if (sIntentBroadcaster == null) {
+ sIntentBroadcaster = new IntentBroadcaster(context);
+ }
+ return sIntentBroadcaster;
+ }
+
+ public static IntentBroadcaster getInstance() {
+ return sIntentBroadcaster;
+ }
+
+ /**
+ * Wrapper for ActivityManager.broadcastStickyIntent() that also stores intent to be rebroadcast
+ * on USER_UNLOCKED
+ */
+ public void broadcastStickyIntent(Intent intent, int slotId) {
+ logd("Broadcasting and adding intent for rebroadcast: " + intent.getAction() + " "
+ + intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE)
+ + " for slotId " + slotId);
+ synchronized (mRebroadcastIntents) {
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
+ mRebroadcastIntents.put(slotId, intent);
+ }
+ }
+
+ private void logd(String s) {
+ Log.d(TAG, s);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/MccTable.java b/src/java/com/android/internal/telephony/MccTable.java
index 07d7af9..5714b29 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;
@@ -97,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;
}
/**
@@ -214,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");
}
@@ -362,7 +376,14 @@
*/
private static void setTimezoneFromMccIfNeeded(Context context, int mcc) {
String timezone = SystemProperties.get(ServiceStateTracker.TIMEZONE_PROPERTY);
- if (timezone == null || timezone.length() == 0) {
+ // timezone.equals("GMT") will be true and only true if the timezone was
+ // set to a default value by the system server (when starting, system server.
+ // sets the persist.sys.timezone to "GMT" if it's not set)."GMT" is not used by
+ // any code that sets it explicitly (in case where something sets GMT explicitly,
+ // "Etc/GMT" Olsen ID would be used).
+ // TODO(b/64056758): Remove "timezone.equals("GMT")" hack when there's a
+ // better way of telling if the value has been defaulted.
+ if (timezone == null || timezone.length() == 0 || timezone.equals("GMT")) {
String zoneId = defaultTimeZoneForMcc(mcc);
if (zoneId != null && zoneId.length() > 0) {
// Set time zone based on MCC
diff --git a/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
new file mode 100644
index 0000000..14c6810
--- /dev/null
+++ b/src/java/com/android/internal/telephony/NetworkScanRequestTracker.java
@@ -0,0 +1,538 @@
+/*
+ * 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.telephony.RadioNetworkConstants.RadioAccessNetworks.EUTRAN;
+import static android.telephony.RadioNetworkConstants.RadioAccessNetworks.GERAN;
+import static android.telephony.RadioNetworkConstants.RadioAccessNetworks.UTRAN;
+
+import android.hardware.radio.V1_0.RadioError;
+import android.os.AsyncResult;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Process;
+import android.os.RemoteException;
+import android.telephony.CellInfo;
+import android.telephony.NetworkScan;
+import android.telephony.NetworkScanRequest;
+import android.telephony.RadioAccessSpecifier;
+import android.telephony.TelephonyScanManager;
+import android.util.Log;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Manages radio access network scan requests.
+ *
+ * Provides methods to start and stop network scan requests, and keeps track of all the live scans.
+ *
+ * {@hide}
+ */
+public final class NetworkScanRequestTracker {
+
+ private static final String TAG = "ScanRequestTracker";
+
+ private static final int CMD_START_NETWORK_SCAN = 1;
+ private static final int EVENT_START_NETWORK_SCAN_DONE = 2;
+ private static final int EVENT_RECEIVE_NETWORK_SCAN_RESULT = 3;
+ private static final int CMD_STOP_NETWORK_SCAN = 4;
+ private static final int EVENT_STOP_NETWORK_SCAN_DONE = 5;
+ private static final int CMD_INTERRUPT_NETWORK_SCAN = 6;
+ private static final int EVENT_INTERRUPT_NETWORK_SCAN_DONE = 7;
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case CMD_START_NETWORK_SCAN:
+ mScheduler.doStartScan((NetworkScanRequestInfo) msg.obj);
+ break;
+
+ case EVENT_START_NETWORK_SCAN_DONE:
+ mScheduler.startScanDone((AsyncResult) msg.obj);
+ break;
+
+ case EVENT_RECEIVE_NETWORK_SCAN_RESULT:
+ mScheduler.receiveResult((AsyncResult) msg.obj);
+ break;
+
+ case CMD_STOP_NETWORK_SCAN:
+ mScheduler.doStopScan(msg.arg1);
+ break;
+
+ case EVENT_STOP_NETWORK_SCAN_DONE:
+ mScheduler.stopScanDone((AsyncResult) msg.obj);
+ break;
+
+ case CMD_INTERRUPT_NETWORK_SCAN:
+ mScheduler.doInterruptScan(msg.arg1);
+ break;
+
+ case EVENT_INTERRUPT_NETWORK_SCAN_DONE:
+ mScheduler.interruptScanDone((AsyncResult) msg.obj);
+ break;
+ }
+ }
+ };
+
+ // The sequence number of NetworkScanRequests
+ private final AtomicInteger mNextNetworkScanRequestId = new AtomicInteger(1);
+ private final NetworkScanRequestScheduler mScheduler = new NetworkScanRequestScheduler();
+
+ private void logEmptyResultOrException(AsyncResult ar) {
+ if (ar.result == null) {
+ Log.e(TAG, "NetworkScanResult: Empty result");
+ } else {
+ Log.e(TAG, "NetworkScanResult: Exception: " + ar.exception);
+ }
+ }
+
+ private boolean isValidScan(NetworkScanRequestInfo nsri) {
+ if (nsri.mRequest.specifiers == null) {
+ return false;
+ }
+ if (nsri.mRequest.specifiers.length > NetworkScanRequest.MAX_RADIO_ACCESS_NETWORKS) {
+ return false;
+ }
+ for (RadioAccessSpecifier ras : nsri.mRequest.specifiers) {
+ if (ras.radioAccessNetwork != GERAN && ras.radioAccessNetwork != UTRAN
+ && ras.radioAccessNetwork != EUTRAN) {
+ return false;
+ }
+ if (ras.bands != null && ras.bands.length > NetworkScanRequest.MAX_BANDS) {
+ return false;
+ }
+ if (ras.channels != null && ras.channels.length > NetworkScanRequest.MAX_CHANNELS) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /** Sends a message back to the application via its callback. */
+ private void notifyMessenger(NetworkScanRequestInfo nsri, int what, int err,
+ List<CellInfo> result) {
+ Messenger messenger = nsri.mMessenger;
+ Message message = Message.obtain();
+ message.what = what;
+ message.arg1 = err;
+ message.arg2 = nsri.mScanId;
+ if (result != null) {
+ CellInfo[] ci = result.toArray(new CellInfo[result.size()]);
+ Bundle b = new Bundle();
+ b.putParcelableArray(TelephonyScanManager.SCAN_RESULT_KEY, ci);
+ message.setData(b);
+ } else {
+ message.obj = null;
+ }
+ try {
+ messenger.send(message);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Exception in notifyMessenger: " + e);
+ }
+ }
+
+ /**
+ * Tracks info about the radio network scan.
+ *
+ * Also used to notice when the calling process dies so we can self-expire.
+ */
+ class NetworkScanRequestInfo implements IBinder.DeathRecipient {
+ private final NetworkScanRequest mRequest;
+ private final Messenger mMessenger;
+ private final IBinder mBinder;
+ private final Phone mPhone;
+ private final int mScanId;
+ private final int mUid;
+ private final int mPid;
+ private boolean mIsBinderDead;
+
+ NetworkScanRequestInfo(NetworkScanRequest r, Messenger m, IBinder b, int id, Phone phone) {
+ super();
+ mRequest = r;
+ mMessenger = m;
+ mBinder = b;
+ mScanId = id;
+ mPhone = phone;
+ mUid = Binder.getCallingUid();
+ mPid = Binder.getCallingPid();
+ mIsBinderDead = false;
+
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ binderDied();
+ }
+ }
+
+ synchronized void setIsBinderDead(boolean val) {
+ mIsBinderDead = val;
+ }
+
+ synchronized boolean getIsBinderDead() {
+ return mIsBinderDead;
+ }
+
+ NetworkScanRequest getRequest() {
+ return mRequest;
+ }
+
+ void unlinkDeathRecipient() {
+ if (mBinder != null) {
+ mBinder.unlinkToDeath(this, 0);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ Log.e(TAG, "PhoneInterfaceManager NetworkScanRequestInfo binderDied("
+ + mRequest + ", " + mBinder + ")");
+ setIsBinderDead(true);
+ interruptNetworkScan(mScanId);
+ }
+ }
+
+ /**
+ * Handles multiplexing and scheduling for multiple requests.
+ */
+ private class NetworkScanRequestScheduler {
+
+ private NetworkScanRequestInfo mLiveRequestInfo;
+ private NetworkScanRequestInfo mPendingRequestInfo;
+
+ private int rilErrorToScanError(int rilError) {
+ switch (rilError) {
+ case RadioError.NONE:
+ return NetworkScan.SUCCESS;
+ case RadioError.RADIO_NOT_AVAILABLE:
+ Log.e(TAG, "rilErrorToScanError: RADIO_NOT_AVAILABLE");
+ return NetworkScan.ERROR_MODEM_ERROR;
+ case RadioError.REQUEST_NOT_SUPPORTED:
+ Log.e(TAG, "rilErrorToScanError: REQUEST_NOT_SUPPORTED");
+ return NetworkScan.ERROR_UNSUPPORTED;
+ case RadioError.NO_MEMORY:
+ Log.e(TAG, "rilErrorToScanError: NO_MEMORY");
+ return NetworkScan.ERROR_MODEM_ERROR;
+ case RadioError.INTERNAL_ERR:
+ Log.e(TAG, "rilErrorToScanError: INTERNAL_ERR");
+ return NetworkScan.ERROR_MODEM_ERROR;
+ case RadioError.MODEM_ERR:
+ Log.e(TAG, "rilErrorToScanError: MODEM_ERR");
+ return NetworkScan.ERROR_MODEM_ERROR;
+ case RadioError.OPERATION_NOT_ALLOWED:
+ Log.e(TAG, "rilErrorToScanError: OPERATION_NOT_ALLOWED");
+ return NetworkScan.ERROR_MODEM_ERROR;
+ case RadioError.INVALID_ARGUMENTS:
+ Log.e(TAG, "rilErrorToScanError: INVALID_ARGUMENTS");
+ return NetworkScan.ERROR_INVALID_SCAN;
+ case RadioError.DEVICE_IN_USE:
+ Log.e(TAG, "rilErrorToScanError: DEVICE_IN_USE");
+ return NetworkScan.ERROR_MODEM_BUSY;
+ default:
+ Log.e(TAG, "rilErrorToScanError: Unexpected RadioError " + rilError);
+ return NetworkScan.ERROR_RIL_ERROR;
+ }
+ }
+
+ private int commandExceptionErrorToScanError(CommandException.Error error) {
+ switch (error) {
+ case RADIO_NOT_AVAILABLE:
+ Log.e(TAG, "commandExceptionErrorToScanError: RADIO_NOT_AVAILABLE");
+ return NetworkScan.ERROR_MODEM_ERROR;
+ case REQUEST_NOT_SUPPORTED:
+ Log.e(TAG, "commandExceptionErrorToScanError: REQUEST_NOT_SUPPORTED");
+ return NetworkScan.ERROR_UNSUPPORTED;
+ case NO_MEMORY:
+ Log.e(TAG, "commandExceptionErrorToScanError: NO_MEMORY");
+ return NetworkScan.ERROR_MODEM_ERROR;
+ case INTERNAL_ERR:
+ Log.e(TAG, "commandExceptionErrorToScanError: INTERNAL_ERR");
+ return NetworkScan.ERROR_MODEM_ERROR;
+ case MODEM_ERR:
+ Log.e(TAG, "commandExceptionErrorToScanError: MODEM_ERR");
+ return NetworkScan.ERROR_MODEM_ERROR;
+ case OPERATION_NOT_ALLOWED:
+ Log.e(TAG, "commandExceptionErrorToScanError: OPERATION_NOT_ALLOWED");
+ return NetworkScan.ERROR_MODEM_ERROR;
+ case INVALID_ARGUMENTS:
+ Log.e(TAG, "commandExceptionErrorToScanError: INVALID_ARGUMENTS");
+ return NetworkScan.ERROR_INVALID_SCAN;
+ case DEVICE_IN_USE:
+ Log.e(TAG, "commandExceptionErrorToScanError: DEVICE_IN_USE");
+ return NetworkScan.ERROR_MODEM_BUSY;
+ default:
+ Log.e(TAG, "commandExceptionErrorToScanError: Unexpected CommandExceptionError "
+ + error);
+ return NetworkScan.ERROR_RIL_ERROR;
+ }
+ }
+
+ private void doStartScan(NetworkScanRequestInfo nsri) {
+ if (nsri == null) {
+ Log.e(TAG, "CMD_START_NETWORK_SCAN: nsri is null");
+ return;
+ }
+ if (!isValidScan(nsri)) {
+ notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_ERROR,
+ NetworkScan.ERROR_INVALID_SCAN, null);
+ return;
+ }
+ if (nsri.getIsBinderDead()) {
+ Log.e(TAG, "CMD_START_NETWORK_SCAN: Binder has died");
+ return;
+ }
+ if (!startNewScan(nsri)) {
+ if (!interruptLiveScan(nsri)) {
+ if (!cacheScan(nsri)) {
+ notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_ERROR,
+ NetworkScan.ERROR_MODEM_BUSY, null);
+ }
+ }
+ }
+ }
+
+ private synchronized void startScanDone(AsyncResult ar) {
+ NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj;
+ if (nsri == null) {
+ Log.e(TAG, "EVENT_START_NETWORK_SCAN_DONE: nsri is null");
+ return;
+ }
+ if (mLiveRequestInfo == null || nsri.mScanId != mLiveRequestInfo.mScanId) {
+ Log.e(TAG, "EVENT_START_NETWORK_SCAN_DONE: nsri does not match mLiveRequestInfo");
+ return;
+ }
+ if (ar.exception == null && ar.result != null) {
+ // Register for the scan results if the scan started successfully.
+ nsri.mPhone.mCi.registerForNetworkScanResult(mHandler,
+ EVENT_RECEIVE_NETWORK_SCAN_RESULT, nsri);
+ } else {
+ logEmptyResultOrException(ar);
+ if (ar.exception != null) {
+ CommandException.Error error =
+ ((CommandException) (ar.exception)).getCommandError();
+ deleteScanAndMayNotify(nsri, commandExceptionErrorToScanError(error), true);
+ } else {
+ Log.wtf(TAG, "EVENT_START_NETWORK_SCAN_DONE: ar.exception can not be null!");
+ }
+ }
+ }
+
+ private void receiveResult(AsyncResult ar) {
+ NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj;
+ if (nsri == null) {
+ Log.e(TAG, "EVENT_RECEIVE_NETWORK_SCAN_RESULT: nsri is null");
+ return;
+ }
+ if (ar.exception == null && ar.result != null) {
+ NetworkScanResult nsr = (NetworkScanResult) ar.result;
+ if (nsr.scanError == NetworkScan.SUCCESS) {
+ notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_RESULTS,
+ rilErrorToScanError(nsr.scanError), nsr.networkInfos);
+ if (nsr.scanStatus == NetworkScanResult.SCAN_STATUS_COMPLETE) {
+ deleteScanAndMayNotify(nsri, NetworkScan.SUCCESS, true);
+ nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler);
+ }
+ } else {
+ if (nsr.networkInfos != null) {
+ notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_RESULTS,
+ NetworkScan.SUCCESS, nsr.networkInfos);
+ }
+ deleteScanAndMayNotify(nsri, rilErrorToScanError(nsr.scanError), true);
+ nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler);
+ }
+ } else {
+ logEmptyResultOrException(ar);
+ deleteScanAndMayNotify(nsri, NetworkScan.ERROR_RIL_ERROR, true);
+ nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler);
+ }
+ }
+
+
+ // Stops the scan if the scanId and uid match the mScanId and mUid.
+ // If the scan to be stopped is the live scan, we only send the request to RIL, while the
+ // mLiveRequestInfo will not be cleared and the user will not be notified either.
+ // If the scan to be stopped is the pending scan, we will clear mPendingRequestInfo and
+ // notify the user.
+ private synchronized void doStopScan(int scanId) {
+ if (mLiveRequestInfo != null && scanId == mLiveRequestInfo.mScanId) {
+ mLiveRequestInfo.mPhone.stopNetworkScan(
+ mHandler.obtainMessage(EVENT_STOP_NETWORK_SCAN_DONE, mLiveRequestInfo));
+ } else if (mPendingRequestInfo != null && scanId == mPendingRequestInfo.mScanId) {
+ notifyMessenger(mPendingRequestInfo,
+ TelephonyScanManager.CALLBACK_SCAN_COMPLETE, NetworkScan.SUCCESS, null);
+ mPendingRequestInfo = null;
+ } else {
+ Log.e(TAG, "stopScan: scan " + scanId + " does not exist!");
+ }
+ }
+
+ private void stopScanDone(AsyncResult ar) {
+ NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj;
+ if (nsri == null) {
+ Log.e(TAG, "EVENT_STOP_NETWORK_SCAN_DONE: nsri is null");
+ return;
+ }
+ if (ar.exception == null && ar.result != null) {
+ deleteScanAndMayNotify(nsri, NetworkScan.SUCCESS, true);
+ } else {
+ logEmptyResultOrException(ar);
+ if (ar.exception != null) {
+ CommandException.Error error =
+ ((CommandException) (ar.exception)).getCommandError();
+ deleteScanAndMayNotify(nsri, commandExceptionErrorToScanError(error), true);
+ } else {
+ Log.wtf(TAG, "EVENT_STOP_NETWORK_SCAN_DONE: ar.exception can not be null!");
+ }
+ }
+ nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler);
+ }
+
+ // Interrupts the live scan is the scanId matches the mScanId of the mLiveRequestInfo.
+ private synchronized void doInterruptScan(int scanId) {
+ if (mLiveRequestInfo != null && scanId == mLiveRequestInfo.mScanId) {
+ mLiveRequestInfo.mPhone.stopNetworkScan(mHandler.obtainMessage(
+ EVENT_INTERRUPT_NETWORK_SCAN_DONE, mLiveRequestInfo));
+ } else {
+ Log.e(TAG, "doInterruptScan: scan " + scanId + " does not exist!");
+ }
+ }
+
+ private void interruptScanDone(AsyncResult ar) {
+ NetworkScanRequestInfo nsri = (NetworkScanRequestInfo) ar.userObj;
+ if (nsri == null) {
+ Log.e(TAG, "EVENT_INTERRUPT_NETWORK_SCAN_DONE: nsri is null");
+ return;
+ }
+ nsri.mPhone.mCi.unregisterForNetworkScanResult(mHandler);
+ deleteScanAndMayNotify(nsri, 0, false);
+ }
+
+ // Interrupts the live scan and caches nsri in mPendingRequestInfo. Once the live scan is
+ // stopped, a new scan will automatically start with nsri.
+ // The new scan can interrupt the live scan only when all the below requirements are met:
+ // 1. There is 1 live scan and no other pending scan
+ // 2. The new scan is requested by system process
+ // 3. The live scan is not requested by system process
+ private synchronized boolean interruptLiveScan(NetworkScanRequestInfo nsri) {
+ if (mLiveRequestInfo != null && mPendingRequestInfo == null
+ && nsri.mUid == Process.SYSTEM_UID
+ && mLiveRequestInfo.mUid != Process.SYSTEM_UID) {
+ doInterruptScan(mLiveRequestInfo.mScanId);
+ mPendingRequestInfo = nsri;
+ notifyMessenger(mLiveRequestInfo, TelephonyScanManager.CALLBACK_SCAN_ERROR,
+ NetworkScan.ERROR_INTERRUPTED, null);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean cacheScan(NetworkScanRequestInfo nsri) {
+ // TODO(30954762): Cache periodic scan for OC-MR1.
+ return false;
+ }
+
+ // Starts a new scan with nsri if there is no live scan running.
+ private synchronized boolean startNewScan(NetworkScanRequestInfo nsri) {
+ if (mLiveRequestInfo == null) {
+ mLiveRequestInfo = nsri;
+ nsri.mPhone.startNetworkScan(nsri.getRequest(),
+ mHandler.obtainMessage(EVENT_START_NETWORK_SCAN_DONE, nsri));
+ return true;
+ }
+ return false;
+ }
+
+
+ // Deletes the mLiveRequestInfo and notify the user if it matches nsri.
+ private synchronized void deleteScanAndMayNotify(NetworkScanRequestInfo nsri, int error,
+ boolean notify) {
+ if (mLiveRequestInfo != null && nsri.mScanId == mLiveRequestInfo.mScanId) {
+ if (notify) {
+ if (error == NetworkScan.SUCCESS) {
+ notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_COMPLETE, error,
+ null);
+ } else {
+ notifyMessenger(nsri, TelephonyScanManager.CALLBACK_SCAN_ERROR, error,
+ null);
+ }
+ }
+ mLiveRequestInfo = null;
+ if (mPendingRequestInfo != null) {
+ startNewScan(mPendingRequestInfo);
+ mPendingRequestInfo = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Interrupts an ongoing network scan
+ *
+ * This method is similar to stopNetworkScan, since they both stops an ongoing scan. The
+ * difference is that stopNetworkScan is only used by the callers to stop their own scans, so
+ * sanity check will be done to make sure the request is valid; while this method is only
+ * internally used by NetworkScanRequestTracker so sanity check is not needed.
+ */
+ private void interruptNetworkScan(int scanId) {
+ // scanId will be stored at Message.arg1
+ mHandler.obtainMessage(CMD_INTERRUPT_NETWORK_SCAN, scanId, 0).sendToTarget();
+ }
+
+ /**
+ * Starts a new network scan
+ *
+ * This function only wraps all the incoming information and delegate then to the handler thread
+ * which will actually handles the scan request. So a new scanId will always be generated and
+ * returned to the user, no matter how this scan will be actually handled.
+ */
+ public int startNetworkScan(
+ NetworkScanRequest request, Messenger messenger, IBinder binder, Phone phone) {
+ int scanId = mNextNetworkScanRequestId.getAndIncrement();
+ NetworkScanRequestInfo nsri =
+ new NetworkScanRequestInfo(request, messenger, binder, scanId, phone);
+ // nsri will be stored as Message.obj
+ mHandler.obtainMessage(CMD_START_NETWORK_SCAN, nsri).sendToTarget();
+ return scanId;
+ }
+
+ /**
+ * Stops an ongoing network scan
+ *
+ * The ongoing scan will be stopped only when the input scanId and caller's uid matches the
+ * corresponding information associated with it.
+ */
+ public void stopNetworkScan(int scanId) {
+ synchronized (mScheduler) {
+ if ((mScheduler.mLiveRequestInfo != null
+ && scanId == mScheduler.mLiveRequestInfo.mScanId
+ && Binder.getCallingUid() == mScheduler.mLiveRequestInfo.mUid)
+ || (mScheduler.mPendingRequestInfo != null
+ && scanId == mScheduler.mPendingRequestInfo.mScanId
+ && Binder.getCallingUid() == mScheduler.mPendingRequestInfo.mUid)) {
+ // scanId will be stored at Message.arg1
+ mHandler.obtainMessage(CMD_STOP_NETWORK_SCAN, scanId, 0).sendToTarget();
+ } else {
+ throw new IllegalArgumentException("Scan with id: " + scanId + " does not exist!");
+ }
+ }
+ }
+}
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 80f3c1a..fad0ddb 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -23,6 +23,7 @@
import android.content.SharedPreferences;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
+import android.net.NetworkStats;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.AsyncResult;
@@ -44,6 +45,7 @@
import android.telephony.CellInfoCdma;
import android.telephony.CellLocation;
import android.telephony.ClientRequestStats;
+import android.telephony.ImsiEncryptionInfo;
import android.telephony.PhoneStateListener;
import android.telephony.RadioAccessFamily;
import android.telephony.Rlog;
@@ -57,9 +59,10 @@
import com.android.ims.ImsConfig;
import com.android.ims.ImsManager;
import com.android.internal.R;
+import com.android.internal.telephony.dataconnection.DataConnectionReasons;
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.ims.ImsResolver;
import com.android.internal.telephony.test.SimulatedRadioControl;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
import com.android.internal.telephony.uicc.IccFileHandler;
@@ -96,6 +99,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) {
@@ -138,6 +143,9 @@
// Key used to read/write "disable data connection on boot" pref (used for testing)
public static final String DATA_DISABLED_ON_BOOT_KEY = "disabled_on_boot_key";
+ // Key used to read/write data_roaming_is_user_setting pref
+ public static final String DATA_ROAMING_IS_USER_SETTING_KEY = "data_roaming_is_user_setting_key";
+
/* Event Constants */
protected static final int EVENT_RADIO_AVAILABLE = 1;
/** Supplementary Service Notification received. */
@@ -216,6 +224,9 @@
// Key used to read/write "disable DNS server check" pref (used for testing)
private static final String DNS_SERVER_CHECK_DISABLED_KEY = "dns_server_check_disabled_key";
+ // Integer used to let the calling application know that the we are ignoring auto mode switch.
+ private static final int ALREADY_IN_AUTO_SELECTION = 1;
+
/**
* Small container class used to hold information relevant to
* the carrier selection process. operatorNumeric can be ""
@@ -242,6 +253,7 @@
private int mCallRingContinueToken;
private int mCallRingDelay;
private boolean mIsVoiceCapable = true;
+ private final AppSmsManager mAppSmsManager;
private SimActivationTracker mSimActivationTracker;
// Keep track of whether or not the phone is in Emergency Callback Mode for Phone and
// subclasses
@@ -276,6 +288,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";
@@ -447,6 +464,7 @@
mCi = ci;
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);
@@ -534,22 +552,24 @@
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). Also, when using new ImsResolver APIs, the service will be available soon,
// so start trying to bind.
- ImsManager imsManager = ImsManager.getInstance(mContext, getPhoneId());
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 +1178,11 @@
mCi.setNetworkSelectionModeAutomatic(msg);
} else {
Rlog.d(LOG_TAG, "setNetworkSelectionModeAutomatic - already auto, ignoring");
+ // let the calling application know that the we are ignoring automatic mode switch.
+ if (nsm.message != null) {
+ nsm.message.arg1 = ALREADY_IN_AUTO_SELECTION;
+ }
+
ar.userObj = nsm;
handleSetSelectNetwork(ar);
}
@@ -1316,6 +1341,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()) {
@@ -2145,8 +2172,6 @@
* @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 mIsPhoneInEcmState;
@@ -2280,6 +2305,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() {
@@ -2729,17 +2769,21 @@
/**
* Report on whether data connectivity is allowed.
+ *
+ * @return True if data is allowed to be established.
*/
- public boolean isDataConnectivityPossible() {
- return isDataConnectivityPossible(PhoneConstants.APN_TYPE_DEFAULT);
+ public boolean isDataAllowed() {
+ return ((mDcTracker != null) && (mDcTracker.isDataAllowed(null)));
}
/**
- * Report on whether data connectivity is allowed for an APN.
+ * Report on whether data connectivity is allowed.
+ *
+ * @param reasons The reasons that data can/can't be established. This is an output param.
+ * @return True if data is allowed to be established
*/
- public boolean isDataConnectivityPossible(String apnType) {
- return ((mDcTracker != null) &&
- (mDcTracker.isDataPossible(apnType)));
+ public boolean isDataAllowed(DataConnectionReasons reasons) {
+ return ((mDcTracker != null) && (mDcTracker.isDataAllowed(reasons)));
}
@@ -2932,6 +2976,28 @@
}
/**
+ * Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
+ * @param keyType whether the key is being used for WLAN or ePDG.
+ * @return ImsiEncryptionInfo which includes the Key Type, the Public Key
+ * {@link java.security.PublicKey} and the Key Identifier.
+ * The keyIdentifier This is used by the server to help it locate the private key to
+ * decrypt the permanent identity.
+ */
+ public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
+ return null;
+ }
+
+ /**
+ * Sets the carrier information needed to encrypt the IMSI and IMPI.
+ * @param imsiEncryptionInfo Carrier specific information that will be used to encrypt the
+ * IMSI and IMPI. This includes the Key type, the Public key
+ * {@link java.security.PublicKey} and the Key identifier.
+ */
+ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo) {
+ return;
+ }
+
+ /**
* Return if UT capability of ImsPhone is enabled or not
*/
public boolean isUtEnabled() {
@@ -3270,14 +3336,25 @@
}
/**
+ * Determines if the connection to IMS services are available yet.
+ * @return {@code true} if the connection to IMS services are available.
+ */
+ public boolean isImsAvailable() {
+ if (mImsPhone == null) {
+ return false;
+ }
+
+ return mImsPhone.isImsAvailable();
+ }
+
+ /**
* Determines if video calling is enabled for the phone.
*
* @return {@code true} if video calling is enabled, {@code false} otherwise.
*/
public boolean isVideoEnabled() {
Phone imsPhone = mImsPhone;
- if ((imsPhone != null)
- && (imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)) {
+ if (imsPhone != null) {
return imsPhone.isVideoEnabled();
}
return false;
@@ -3384,7 +3461,7 @@
ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY));
if (wfcWiFiOnly) {
throw new CallStateException(
- CallStateException.ERROR_DISCONNECTED,
+ CallStateException.ERROR_OUT_OF_SERVICE,
"WFC Wi-Fi Only Mode: IMS not registered");
}
}
@@ -3419,9 +3496,16 @@
return this;
}
- public long getVtDataUsage() {
- if (mImsPhone == null) return 0;
- return mImsPhone.getVtDataUsage();
+ /**
+ * Get aggregated video call data usage since boot.
+ * Permissions android.Manifest.permission.READ_NETWORK_USAGE_HISTORY is required.
+ *
+ * @param perUidStats True if requesting data usage per uid, otherwise overall usage.
+ * @return Snapshot of video call data usage
+ */
+ public NetworkStats getVtDataUsage(boolean perUidStats) {
+ if (mImsPhone == null) return null;
+ return mImsPhone.getVtDataUsage(perUidStats);
}
/**
@@ -3441,12 +3525,19 @@
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
+ * Set SIM card power state.
+ * @param state State of SIM (power down, power up, pass through)
+ * - {@link android.telephony.TelephonyManager#CARD_POWER_DOWN}
+ * - {@link android.telephony.TelephonyManager#CARD_POWER_UP}
+ * - {@link android.telephony.TelephonyManager#CARD_POWER_UP_PASS_THROUGH}
**/
- public void setSimPowerState(boolean powerUp) {
- mCi.setSimCardPower(powerUp, null);
+ public void setSimPowerState(int state) {
+ mCi.setSimCardPower(state, null);
}
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
@@ -3483,7 +3574,6 @@
pw.println(" getPhoneType()=" + getPhoneType());
pw.println(" getVoiceMessageCount()=" + getVoiceMessageCount());
pw.println(" getActiveApnTypes()=" + getActiveApnTypes());
- pw.println(" isDataConnectivityPossible()=" + isDataConnectivityPossible());
pw.println(" needsOtaServiceProvisioning=" + needsOtaServiceProvisioning());
pw.flush();
pw.println("++++++++++++++++++++++++++++++++");
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index c506b85..4fcf37e 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -21,12 +21,15 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.net.LocalServerSocket;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.preference.PreferenceManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.telephony.Rlog;
@@ -43,11 +46,13 @@
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;
import java.io.PrintWriter;
import java.util.HashMap;
+import java.util.Map;
/**
* {@hide}
@@ -69,6 +74,7 @@
static private ProxyController sProxyController;
static private UiccController sUiccController;
+ private static IntentBroadcaster sIntentBroadcaster;
static private CommandsInterface sCommandsInterface = null;
static private SubscriptionInfoUpdater sSubInfoRecordUpdater = null;
@@ -80,6 +86,7 @@
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>();
@@ -232,6 +239,10 @@
sProxyController = ProxyController.getInstance(context, sPhones,
sUiccController, sCommandsInterfaces, sPhoneSwitcher);
+ sIntentBroadcaster = IntentBroadcaster.getInstance(context);
+
+ sNotificationChannelController = new NotificationChannelController(context);
+
sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
for (int i = 0; i < numPhones; i++) {
sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(
@@ -473,5 +484,22 @@
pw.flush();
}
pw.decreaseIndent();
+ pw.println("++++++++++++++++++++++++++++++++");
+
+ pw.println("SharedPreferences:");
+ pw.increaseIndent();
+ try {
+ if (sContext != null) {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(sContext);
+ Map spValues = sp.getAll();
+ for (Object key : spValues.keySet()) {
+ pw.println(key + " : " + spValues.get(key));
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ pw.flush();
+ pw.decreaseIndent();
}
}
diff --git a/src/java/com/android/internal/telephony/PhoneInternalInterface.java b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
index 1983169..6cf6358 100644
--- a/src/java/com/android/internal/telephony/PhoneInternalInterface.java
+++ b/src/java/com/android/internal/telephony/PhoneInternalInterface.java
@@ -16,32 +16,20 @@
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.os.WorkSource;
import android.os.ResultReceiver;
-import android.telephony.CellInfo;
-import android.telephony.CellLocation;
+import android.os.WorkSource;
import android.telephony.CarrierConfigManager;
-import android.telephony.PhoneStateListener;
+import android.telephony.CellLocation;
+import android.telephony.ImsiEncryptionInfo;
+import android.telephony.NetworkScanRequest;
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
@@ -119,6 +107,7 @@
static final String REASON_CARRIER_CHANGE = "carrierChange";
static final String REASON_CARRIER_ACTION_DISABLE_METERED_APN =
"carrierActionDisableMeteredApn";
+ static final String REASON_CSS_INDICATOR_CHANGED = "cssIndicatorChanged";
// Used for band mode selection methods
static final int BM_UNSPECIFIED = RILConstants.BAND_MODE_UNSPECIFIED; // automatic
@@ -456,7 +445,8 @@
* @param ussdRequest the USSD command to be executed.
* @param wrappedCallback receives the callback result.
*/
- boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback);
+ boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback)
+ throws CallStateException;
/**
* Handles in-call MMI commands. While in a call, or while receiving a
@@ -657,6 +647,30 @@
void getAvailableNetworks(Message response);
/**
+ * Start a network scan. This method is asynchronous; .
+ * On completion, <code>response.obj</code> is set to an AsyncResult with
+ * one of the following members:.<p>
+ * <ul>
+ * <li><code>response.obj.result</code> will be a <code>NetworkScanResult</code> object, or</li>
+ * <li><code>response.obj.exception</code> will be set with an exception
+ * on failure.</li>
+ * </ul>
+ */
+ void startNetworkScan(NetworkScanRequest nsr, Message response);
+
+ /**
+ * Stop ongoing network scan. This method is asynchronous; .
+ * On completion, <code>response.obj</code> is set to an AsyncResult with
+ * one of the following members:.<p>
+ * <ul>
+ * <li><code>response.obj.result</code> will be a <code>NetworkScanResult</code> object, or</li>
+ * <li><code>response.obj.exception</code> will be set with an exception
+ * on failure.</li>
+ * </ul>
+ */
+ void stopNetworkScan(Message response);
+
+ /**
* Query neighboring cell IDs. <code>response</code> is dispatched when
* this is complete. <code>response.obj</code> will be an AsyncResult,
* and <code>response.obj.exception</code> will be non-null on failure.
@@ -815,4 +829,22 @@
* Callback message is empty on completion
*/
public void setCellBroadcastSmsConfig(int[] configValuesArray, Message response);
+
+ /*
+ * Sets the carrier information needed to encrypt the IMSI and IMPI.
+ * @param imsiEncryptionInfo Carrier specific information that will be used to encrypt the
+ * IMSI and IMPI. This includes the Key type, the Public key
+ * {@link java.security.PublicKey} and the Key identifier.
+ */
+ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo);
+
+ /**
+ * Returns Carrier specific information that will be used to encrypt the IMSI and IMPI.
+ * @param keyType whether the key is being used for WLAN or ePDG.
+ * @return ImsiEncryptionInfo which includes the Key Type, the Public Key
+ * {@link java.security.PublicKey} and the Key Identifier.
+ * The keyIdentifier This is used by the server to help it locate the private key to
+ * decrypt the permanent identity.
+ */
+ public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType);
}
diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
index a867d12..9cd088f 100644
--- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java
+++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java
@@ -24,6 +24,7 @@
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.telephony.ImsiEncryptionInfo;
import android.telephony.PhoneNumberUtils;
import android.telephony.SubscriptionManager;
import android.telephony.Rlog;
@@ -33,6 +34,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;
@@ -103,6 +105,35 @@
}
}
+ public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int subId, int keyType,
+ String callingPackage) {
+ Phone phone = getPhone(subId);
+ if (phone != null) {
+ if (!checkReadPhoneState(callingPackage, "getCarrierInfoForImsiEncryption")) {
+ return null;
+ }
+ return phone.getCarrierInfoForImsiEncryption(keyType);
+ } else {
+ loge("getCarrierInfoForImsiEncryption phone is null for Subscription:" + subId);
+ return null;
+ }
+ }
+
+ public void setCarrierInfoForImsiEncryption(int subId, String callingPackage,
+ ImsiEncryptionInfo imsiEncryptionInfo) {
+ Phone phone = getPhone(subId);
+ if (phone != null) {
+ if (!checkReadPhoneState(callingPackage, "setCarrierInfoForImsiEncryption")) {
+ return;
+ }
+ phone.setCarrierInfoForImsiEncryption(imsiEncryptionInfo);
+ } else {
+ loge("setCarrierInfoForImsiEncryption phone is null for Subscription:" + subId);
+ return;
+ }
+ }
+
+
public String getDeviceSvn(String callingPackage) {
return getDeviceSvnUsingSubId(getDefaultSubscription(), callingPackage);
}
@@ -301,62 +332,102 @@
}
- public String getIsimImpi() {
- Phone phone = getPhone(getDefaultSubscription());
- mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
- "Requires READ_PRIVILEGED_PHONE_STATE");
- IsimRecords isim = phone.getIsimRecords();
- if (isim != null) {
- return isim.getIsimImpi();
+ /**
+ * get the Isim Impi based on subId
+ */
+ public String getIsimImpi(int subId) {
+ Phone phone = getPhone(subId);
+ if (phone != null) {
+ mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+ "Requires READ_PRIVILEGED_PHONE_STATE");
+ IsimRecords isim = phone.getIsimRecords();
+ if (isim != null) {
+ return isim.getIsimImpi();
+ } else {
+ return null;
+ }
} else {
+ loge("getIsimImpi phone is null for Subscription:" + subId);
return null;
}
}
- public String getIsimDomain() {
- Phone phone = getPhone(getDefaultSubscription());
- mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
- "Requires READ_PRIVILEGED_PHONE_STATE");
- IsimRecords isim = phone.getIsimRecords();
- if (isim != null) {
- return isim.getIsimDomain();
+ /**
+ * get the Isim Domain based on subId
+ */
+ public String getIsimDomain(int subId) {
+ Phone phone = getPhone(subId);
+ if (phone != null) {
+ mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+ "Requires READ_PRIVILEGED_PHONE_STATE");
+ IsimRecords isim = phone.getIsimRecords();
+ if (isim != null) {
+ return isim.getIsimDomain();
+ } else {
+ return null;
+ }
} else {
+ loge("getIsimDomain phone is null for Subscription:" + subId);
return null;
}
}
- public String[] getIsimImpu() {
- Phone phone = getPhone(getDefaultSubscription());
- mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
- "Requires READ_PRIVILEGED_PHONE_STATE");
- IsimRecords isim = phone.getIsimRecords();
- if (isim != null) {
- return isim.getIsimImpu();
+ /**
+ * get the Isim Impu based on subId
+ */
+ public String[] getIsimImpu(int subId) {
+ Phone phone = getPhone(subId);
+ if (phone != null) {
+ mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+ "Requires READ_PRIVILEGED_PHONE_STATE");
+ IsimRecords isim = phone.getIsimRecords();
+ if (isim != null) {
+ return isim.getIsimImpu();
+ } else {
+ return null;
+ }
} else {
+ loge("getIsimImpu phone is null for Subscription:" + subId);
return null;
}
}
- public String getIsimIst() throws RemoteException {
- Phone phone = getPhone(getDefaultSubscription());
- mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
- "Requires READ_PRIVILEGED_PHONE_STATE");
- IsimRecords isim = phone.getIsimRecords();
- if (isim != null) {
- return isim.getIsimIst();
+ /**
+ * get the Isim Ist based on subId
+ */
+ public String getIsimIst(int subId) throws RemoteException {
+ Phone phone = getPhone(subId);
+ if (phone != null) {
+ mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+ "Requires READ_PRIVILEGED_PHONE_STATE");
+ IsimRecords isim = phone.getIsimRecords();
+ if (isim != null) {
+ return isim.getIsimIst();
+ } else {
+ return null;
+ }
} else {
+ loge("getIsimIst phone is null for Subscription:" + subId);
return null;
}
}
- public String[] getIsimPcscf() throws RemoteException {
- Phone phone = getPhone(getDefaultSubscription());
- mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
- "Requires READ_PRIVILEGED_PHONE_STATE");
- IsimRecords isim = phone.getIsimRecords();
- if (isim != null) {
- return isim.getIsimPcscf();
+ /**
+ * get the Isim Pcscf based on subId
+ */
+ public String[] getIsimPcscf(int subId) throws RemoteException {
+ Phone phone = getPhone(subId);
+ if (phone != null) {
+ mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+ "Requires READ_PRIVILEGED_PHONE_STATE");
+ IsimRecords isim = phone.getIsimRecords();
+ if (isim != null) {
+ return isim.getIsimPcscf();
+ } else {
+ return null;
+ }
} else {
+ loge("getIsimPcscf phone is null for Subscription:" + subId);
return null;
}
}
@@ -434,7 +505,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 +517,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/ProxyController.java b/src/java/com/android/internal/telephony/ProxyController.java
index 0eb3310..f6d42af 100644
--- a/src/java/com/android/internal/telephony/ProxyController.java
+++ b/src/java/com/android/internal/telephony/ProxyController.java
@@ -16,9 +16,6 @@
package com.android.internal.telephony;
-import java.util.ArrayList;
-import java.util.Random;
-
import android.content.Context;
import android.content.Intent;
import android.os.AsyncResult;
@@ -31,13 +28,12 @@
import android.telephony.TelephonyManager;
import android.util.Log;
-import com.android.internal.telephony.PhoneSwitcher;
import com.android.internal.telephony.uicc.UiccController;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicInteger;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
public class ProxyController {
static final String LOG_TAG = "ProxyController";
@@ -130,7 +126,7 @@
mUiccPhoneBookController = new UiccPhoneBookController(mPhones);
mPhoneSubInfoController = new PhoneSubInfoController(mContext, mPhones);
- mUiccSmsController = new UiccSmsController(mPhones);
+ mUiccSmsController = new UiccSmsController();
mSetRadioAccessFamilyStatus = new int[mPhones.length];
mNewRadioAccessFamily = new int[mPhones.length];
mOldRadioAccessFamily = new int[mPhones.length];
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index dbccd64..3ed591f 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -46,6 +46,7 @@
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;
@@ -67,24 +68,30 @@
import android.service.carrier.CarrierIdentifier;
import android.telephony.CellInfo;
import android.telephony.ClientRequestStats;
+import android.telephony.ImsiEncryptionInfo;
import android.telephony.ModemActivityInfo;
import android.telephony.NeighboringCellInfo;
+import android.telephony.NetworkScanRequest;
import android.telephony.PhoneNumberUtils;
import android.telephony.RadioAccessFamily;
+import android.telephony.RadioAccessSpecifier;
+import android.telephony.RadioNetworkConstants.RadioAccessNetworks;
import android.telephony.Rlog;
import android.telephony.SignalStrength;
import android.telephony.SmsManager;
import android.telephony.TelephonyHistogram;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.Log;
import android.util.SparseArray;
-import com.android.internal.telephony.TelephonyProto.SmsSession;
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.gsm.SmsBroadcastConfigInfo;
import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
import com.android.internal.telephony.uicc.IccUtils;
import java.io.ByteArrayInputStream;
@@ -92,7 +99,6 @@
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
-import java.security.PublicKey;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -315,14 +321,15 @@
final Integer mPhoneId;
- private TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
-
/* 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();
+
boolean mIsMobileNetworkSupported;
RadioResponse mRadioResponse;
RadioIndication mRadioIndication;
@@ -494,6 +501,11 @@
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;
}
@@ -535,6 +547,11 @@
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;
}
@@ -700,8 +717,8 @@
mRILDefaultWorkSource);
if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " aid = " + aid
- + " pin = " + pin);
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " aid = " + aid);
}
try {
@@ -727,8 +744,8 @@
mRILDefaultWorkSource);
if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " puk = " + puk
- + " newPin = " + newPin + " aid = " + aid);
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " aid = " + aid);
}
try {
@@ -755,8 +772,8 @@
mRILDefaultWorkSource);
if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " aid = " + aid
- + " pin = " + pin);
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " aid = " + aid);
}
try {
@@ -782,8 +799,8 @@
mRILDefaultWorkSource);
if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " puk = " + puk
- + " newPin = " + newPin2 + " aid = " + aid);
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " aid = " + aid);
}
try {
@@ -1278,6 +1295,26 @@
}
/**
+ * Convert NV reset type into ResetNvType defined in types.hal.
+ * @param resetType NV reset type.
+ * @return Converted reset type in integer or -1 if param is invalid.
+ */
+ private static int convertToHalResetNvType(int resetType) {
+ /**
+ * resetType values
+ * 1 - reload all NV items
+ * 2 - erase NV reset (SCRTN)
+ * 3 - factory reset (RTN)
+ */
+ switch (resetType) {
+ case 1: return ResetNvType.RELOAD;
+ case 2: return ResetNvType.ERASE;
+ case 3: return ResetNvType.FACTORY_RESET;
+ }
+ return -1;
+ }
+
+ /**
* Convert SetupDataCallResult defined in types.hal into DataCallResponse
* @param dcResult setup data call result
* @return converted DataCallResponse object
@@ -1496,8 +1533,8 @@
cfInfo.reason = cfReason;
cfInfo.serviceClass = serviceClass;
cfInfo.toa = PhoneNumberUtils.toaFromString(number);
- cfInfo.number = number;
- cfInfo.timeSeconds = 0;
+ cfInfo.number = convertNullToEmptyString(number);
+ cfInfo.timeSeconds = timeSeconds;
try {
radioProxy.setCallForward(rr.mSerial, cfInfo);
@@ -1773,6 +1810,101 @@
}
@Override
+ public void startNetworkScan(NetworkScanRequest nsr, Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ android.hardware.radio.V1_1.IRadio radioProxy11 =
+ android.hardware.radio.V1_1.IRadio.castFrom(radioProxy);
+ if (radioProxy11 == null) {
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ }
+ } else {
+ android.hardware.radio.V1_1.NetworkScanRequest request =
+ new android.hardware.radio.V1_1.NetworkScanRequest();
+ request.type = nsr.scanType;
+ request.interval = 60;
+ for (RadioAccessSpecifier ras : nsr.specifiers) {
+ android.hardware.radio.V1_1.RadioAccessSpecifier s =
+ new android.hardware.radio.V1_1.RadioAccessSpecifier();
+ s.radioAccessNetwork = ras.radioAccessNetwork;
+ List<Integer> bands = null;
+ switch (ras.radioAccessNetwork) {
+ case RadioAccessNetworks.GERAN:
+ bands = s.geranBands;
+ break;
+ case RadioAccessNetworks.UTRAN:
+ bands = s.utranBands;
+ break;
+ case RadioAccessNetworks.EUTRAN:
+ bands = s.eutranBands;
+ break;
+ default:
+ Log.wtf(RILJ_LOG_TAG, "radioAccessNetwork " + ras.radioAccessNetwork
+ + " not supported!");
+ return;
+ }
+ if (ras.bands != null) {
+ for (int band : ras.bands) {
+ bands.add(band);
+ }
+ }
+ if (ras.channels != null) {
+ for (int channel : ras.channels) {
+ s.channels.add(channel);
+ }
+ }
+ request.specifiers.add(s);
+ }
+
+ RILRequest rr = obtainRequest(RIL_REQUEST_START_NETWORK_SCAN, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ }
+
+ try {
+ radioProxy11.startNetworkScan(rr.mSerial, request);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "startNetworkScan", e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void stopNetworkScan(Message result) {
+ IRadio radioProxy = getRadioProxy(result);
+ if (radioProxy != null) {
+ android.hardware.radio.V1_1.IRadio radioProxy11 =
+ android.hardware.radio.V1_1.IRadio.castFrom(radioProxy);
+ if (radioProxy11 == null) {
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ }
+ } else {
+ RILRequest rr = obtainRequest(RIL_REQUEST_STOP_NETWORK_SCAN, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
+ }
+
+ try {
+ radioProxy11.stopNetworkScan(rr.mSerial);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "stopNetworkScan", e);
+ }
+ }
+ }
+ }
+
+ @Override
public void startDtmf(char c, Message result) {
IRadio radioProxy = getRadioProxy(result);
if (radioProxy != null) {
@@ -2583,25 +2715,26 @@
RILRequest rr = obtainRequest(RIL_REQUEST_CDMA_SET_BROADCAST_CONFIG, result,
mRILDefaultWorkSource);
- if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
- + " with " + configs.length + " configs : ");
- for (int i = 0; i < configs.length; i++) {
- riljLog(configs[i].toString());
+ ArrayList<CdmaBroadcastSmsConfigInfo> halConfigs = new ArrayList<>();
+
+ for (CdmaSmsBroadcastConfigInfo config: configs) {
+ for (int i = config.getFromServiceCategory();
+ i <= config.getToServiceCategory();
+ i++) {
+ CdmaBroadcastSmsConfigInfo info = new CdmaBroadcastSmsConfigInfo();
+ info.serviceCategory = i;
+ info.language = config.getLanguage();
+ info.selected = config.isSelected();
+ halConfigs.add(info);
}
}
- ArrayList<CdmaBroadcastSmsConfigInfo> halConfigs = new ArrayList<>();
-
- int numOfConfig = configs.length;
- CdmaBroadcastSmsConfigInfo info;
-
- for (int i = 0; i < numOfConfig; i++) {
- info = new CdmaBroadcastSmsConfigInfo();
- info.serviceCategory = configs[i].getFromServiceCategory();
- info.language = configs[i].getLanguage();
- info.selected = configs[i].isSelected();
- halConfigs.add(info);
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ + " with " + halConfigs.size() + " configs : ");
+ for (CdmaBroadcastSmsConfigInfo config : halConfigs) {
+ riljLog(config.toString());
+ }
}
try {
@@ -3210,7 +3343,7 @@
}
try {
- radioProxy.nvResetConfig(rr.mSerial, resetType);
+ radioProxy.nvResetConfig(rr.mSerial, convertToHalResetNvType(resetType));
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "nvResetConfig", e);
}
@@ -3605,27 +3738,53 @@
}
@Override
- public void setSimCardPower(boolean powerUp, Message result) {
+ public void setSimCardPower(int state, Message result) {
IRadio radioProxy = getRadioProxy(result);
if (radioProxy != null) {
RILRequest rr = obtainRequest(RIL_REQUEST_SET_SIM_CARD_POWER, result,
mRILDefaultWorkSource);
if (RILJ_LOGD) {
- riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + powerUp);
+ riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " " + state);
}
-
- try {
- radioProxy.setSimCardPower(rr.mSerial, powerUp);
- } catch (RemoteException | RuntimeException e) {
- handleRadioProxyExceptionForRR(rr, "setSimCardPower", e);
+ android.hardware.radio.V1_1.IRadio radioProxy11 =
+ android.hardware.radio.V1_1.IRadio.castFrom(radioProxy);
+ if (radioProxy11 == null) {
+ try {
+ switch (state) {
+ case TelephonyManager.CARD_POWER_DOWN: {
+ radioProxy.setSimCardPower(rr.mSerial, false);
+ break;
+ }
+ case TelephonyManager.CARD_POWER_UP: {
+ radioProxy.setSimCardPower(rr.mSerial, true);
+ break;
+ }
+ default: {
+ if (result != null) {
+ AsyncResult.forMessage(result, null,
+ CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED));
+ result.sendToTarget();
+ }
+ }
+ }
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "setSimCardPower", e);
+ }
+ } else {
+ try {
+ radioProxy11.setSimCardPower_1_1(rr.mSerial, state);
+ } catch (RemoteException | RuntimeException e) {
+ handleRadioProxyExceptionForRR(rr, "setSimCardPower", e);
+ }
}
}
}
@Override
- public void setCarrierInfoForImsiEncryption(PublicKey publicKey, String keyIdentifier,
+ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo,
Message result) {
+ checkNotNull(imsiEncryptionInfo, "ImsiEncryptionInfo cannot be null.");
IRadio radioProxy = getRadioProxy(result);
if (radioProxy != null) {
android.hardware.radio.V1_1.IRadio radioProxy11 =
@@ -3642,8 +3801,21 @@
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
try {
+ android.hardware.radio.V1_1.ImsiEncryptionInfo halImsiInfo =
+ new android.hardware.radio.V1_1.ImsiEncryptionInfo();
+ halImsiInfo.mnc = imsiEncryptionInfo.getMnc();
+ halImsiInfo.mcc = imsiEncryptionInfo.getMcc();
+ halImsiInfo.keyIdentifier = imsiEncryptionInfo.getKeyIdentifier();
+ if (imsiEncryptionInfo.getExpirationTime() != null) {
+ halImsiInfo.expirationTime =
+ imsiEncryptionInfo.getExpirationTime().getTime();
+ }
+ for (byte b : imsiEncryptionInfo.getPublicKey().getEncoded()) {
+ halImsiInfo.carrierKey.add(new Byte(b));
+ }
+
radioProxy11.setCarrierInfoForImsiEncryption(
- rr.mSerial, publicKeyToArrayList(publicKey), keyIdentifier);
+ rr.mSerial, halImsiInfo);
} catch (RemoteException | RuntimeException e) {
handleRadioProxyExceptionForRR(rr, "setCarrierInfoForImsiEncryption", e);
}
@@ -4209,6 +4381,9 @@
mMetrics.writeRilSrvcc(mPhoneId, state);
}
+ void writeMetricsModemRestartEvent(String reason) {
+ mMetrics.writeModemRestartEvent(mPhoneId, reason);
+ }
/**
* Notify all registrants that the ril has connected or disconnected.
@@ -4554,6 +4729,10 @@
return "RIL_RESPONSE_ACKNOWLEDGEMENT";
case RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION:
return "RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION";
+ case RIL_REQUEST_START_NETWORK_SCAN:
+ return "RIL_REQUEST_START_NETWORK_SCAN";
+ case RIL_REQUEST_STOP_NETWORK_SCAN:
+ return "RIL_REQUEST_STOP_NETWORK_SCAN";
default: return "<unknown request>";
}
}
@@ -4652,8 +4831,12 @@
return "UNSOL_LCE_INFO_RECV";
case RIL_UNSOL_PCO_DATA:
return "UNSOL_PCO_DATA";
+ case RIL_UNSOL_MODEM_RESTART:
+ return "UNSOL_MODEM_RESTART";
case RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION:
return "RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION";
+ case RIL_UNSOL_NETWORK_SCAN_RESULT:
+ return "RIL_UNSOL_NETWORK_SCAN_RESULT";
default:
return "<unknown response>";
}
@@ -4742,19 +4925,6 @@
return arrayList;
}
- /**
- * Method to serialize the Public Key into ArrayList of bytes
- * @param publicKey publicKey to be converted to ArrayList of bytes.
- **/
- public static ArrayList<Byte> publicKeyToArrayList(PublicKey publicKey) {
- byte[] key = publicKey.getEncoded();
- ArrayList<Byte> arrayList = new ArrayList<>(key.length);
- for (byte b : key) {
- arrayList.add(b);
- }
- return arrayList;
- }
-
public static byte[] arrayListToPrimitiveArray(ArrayList<Byte> bytes) {
byte[] ret = new byte[bytes.size()];
for (int i = 0; i < ret.length; i++) {
@@ -4824,7 +4994,7 @@
static ArrayList<Integer> convertHalLceData(LceDataInfo lce, RIL ril) {
final ArrayList<Integer> capacityResponse = new ArrayList<Integer>();
final int capacityDownKbps = lce.lastHopCapacityKbps;
- final int confidenceLevel = lce.confidenceLevel;
+ final int confidenceLevel = Byte.toUnsignedInt(lce.confidenceLevel);
final int lceSuspended = lce.lceSuspended ? 1 : 0;
ril.riljLog("LCE capacity information received:" +
@@ -4939,5 +5109,4 @@
signalStrength.tdScdma.rscp,
false /* gsmFlag - don't care; will be changed by SST */);
}
-
}
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index ce37bf2..663f8a4 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -29,6 +29,8 @@
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NETWORK_SCAN_RESULT;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_NITZ_TIME_RECEIVED;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_SS;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ON_USSD;
@@ -79,6 +81,7 @@
import android.hardware.radio.V1_0.StkCcUnsolSsResult;
import android.hardware.radio.V1_0.SuppSvcNotification;
import android.hardware.radio.V1_1.IRadioIndication;
+import android.hardware.radio.V1_1.KeepaliveStatus;
import android.os.AsyncResult;
import android.os.SystemProperties;
import android.telephony.CellInfo;
@@ -86,12 +89,13 @@
import android.telephony.SignalStrength;
import android.telephony.SmsMessage;
-import com.android.internal.telephony.TelephonyProto.SmsSession;
import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
import com.android.internal.telephony.cdma.CdmaInformationRecords;
+import com.android.internal.telephony.cdma.SmsMessageConverter;
import com.android.internal.telephony.dataconnection.DataCallResponse;
import com.android.internal.telephony.gsm.SsData;
import com.android.internal.telephony.gsm.SuppServiceNotification;
+import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
import com.android.internal.telephony.uicc.IccRefreshResponse;
import com.android.internal.telephony.uicc.IccUtils;
@@ -365,7 +369,7 @@
// todo: conversion from CdmaSmsMessage to SmsMessage should be contained in this class so
// that usage of auto-generated HAL classes is limited to this file
- SmsMessage sms = SmsMessage.newCdmaSmsFromRil(msg);
+ SmsMessage sms = SmsMessageConverter.newSmsMessageFromCdmaSmsMessage(msg);
if (mRil.mCdmaSmsRegistrant != null) {
mRil.mCdmaSmsRegistrant.notifyRegistrant(new AsyncResult(null, sms, null));
}
@@ -630,6 +634,12 @@
mRil.mRilCellInfoListRegistrants.notifyRegistrants(new AsyncResult (null, response, null));
}
+ /** Incremental network scan results */
+ public void networkScanResult(int indicationType,
+ android.hardware.radio.V1_1.NetworkScanResult result) {
+ responseCellInfos(indicationType, result);
+ }
+
public void imsNetworkStateChanged(int indicationType) {
mRil.processIndication(indicationType);
@@ -774,6 +784,10 @@
public void modemReset(int indicationType, String reason) {
mRil.processIndication(indicationType);
+
+ if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_MODEM_RESTART, reason);
+
+ mRil.writeMetricsModemRestartEvent(reason);
}
/**
@@ -789,6 +803,15 @@
new AsyncResult(null, null, null));
}
+ /**
+ * Indicates a change in the status of an ongoing Keepalive session
+ * @param indicationType RadioIndicationType
+ * @param keepaliveStatus Status of the ongoing Keepalive session
+ */
+ public void keepaliveStatus(int indicationType, KeepaliveStatus keepaliveStatus) {
+ throw new UnsupportedOperationException("keepaliveStatus Indications are not implemented");
+ }
+
private CommandsInterface.RadioState getRadioStateFromInt(int stateInt) {
CommandsInterface.RadioState state;
@@ -807,4 +830,15 @@
}
return state;
}
+
+ private void responseCellInfos(int indicationType,
+ android.hardware.radio.V1_1.NetworkScanResult result) {
+ mRil.processIndication(indicationType);
+
+ NetworkScanResult nsr = null;
+ ArrayList<CellInfo> infos = RIL.convertHalCellInfoList(result.networkInfos);
+ nsr = new NetworkScanResult(result.status, result.error, infos);
+ if (RIL.RILJ_LOGD) mRil.unsljLogRet(RIL_UNSOL_NETWORK_SCAN_RESULT, nsr);
+ mRil.mRilNetworkScanResultRegistrants.notifyRegistrants(new AsyncResult(null, nsr, null));
+ }
}
diff --git a/src/java/com/android/internal/telephony/RadioResponse.java b/src/java/com/android/internal/telephony/RadioResponse.java
index 126e4a7..caf4477 100644
--- a/src/java/com/android/internal/telephony/RadioResponse.java
+++ b/src/java/com/android/internal/telephony/RadioResponse.java
@@ -34,6 +34,7 @@
import android.hardware.radio.V1_0.SetupDataCallResult;
import android.hardware.radio.V1_0.VoiceRegStateResult;
import android.hardware.radio.V1_1.IRadioResponse;
+import android.hardware.radio.V1_1.KeepaliveStatus;
import android.os.AsyncResult;
import android.os.Message;
import android.os.SystemClock;
@@ -45,6 +46,7 @@
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import com.android.internal.telephony.dataconnection.DataCallResponse;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
@@ -494,6 +496,22 @@
}
/**
+ *
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ */
+ public void startNetworkScanResponse(RadioResponseInfo responseInfo) {
+ responseScanStatus(responseInfo);
+ }
+
+ /**
+ *
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ */
+ public void stopNetworkScanResponse(RadioResponseInfo responseInfo) {
+ responseScanStatus(responseInfo);
+ }
+
+ /**
* @param responseInfo Response info struct containing response type, serial no. and error
*/
public void startDtmfResponse(RadioResponseInfo responseInfo) {
@@ -1090,11 +1108,9 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- RadioCapability ret = null;
- if (responseInfo.error == RadioError.NONE) {
- ret = RIL.convertHalRadioCapability(rc, mRil);
- } else if (responseInfo.error == RadioError.REQUEST_NOT_SUPPORTED ||
- responseInfo.error == RadioError.GENERIC_FAILURE) {
+ RadioCapability ret = RIL.convertHalRadioCapability(rc, mRil);
+ if (responseInfo.error == RadioError.REQUEST_NOT_SUPPORTED
+ || responseInfo.error == RadioError.GENERIC_FAILURE) {
// we should construct the RAF bitmask the radio
// supports based on preferred network bitmasks
ret = mRil.makeStaticRadioCapability();
@@ -1195,46 +1211,67 @@
responseVoid(responseInfo);
}
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ */
+ public void setSimCardPowerResponse_1_1(RadioResponseInfo responseInfo) {
+ responseVoid(responseInfo);
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ * @param keepaliveStatus status of the keepalive with a handle for the session
+ */
+ public void startKeepaliveResponse(RadioResponseInfo responseInfo,
+ KeepaliveStatus keepaliveStatus) {
+ throw new UnsupportedOperationException("startKeepaliveResponse not implemented");
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ */
+ public void stopKeepaliveResponse(RadioResponseInfo responseInfo) {
+ throw new UnsupportedOperationException("stopKeepaliveResponse not implemented");
+ }
+
private void responseIccCardStatus(RadioResponseInfo responseInfo, CardStatus cardStatus) {
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- Object ret = null;
- if (responseInfo.error == RadioError.NONE) {
- IccCardStatus iccCardStatus = new IccCardStatus();
- iccCardStatus.setCardState(cardStatus.cardState);
- iccCardStatus.setUniversalPinState(cardStatus.universalPinState);
- iccCardStatus.mGsmUmtsSubscriptionAppIndex = cardStatus.gsmUmtsSubscriptionAppIndex;
- iccCardStatus.mCdmaSubscriptionAppIndex = cardStatus.cdmaSubscriptionAppIndex;
- iccCardStatus.mImsSubscriptionAppIndex = cardStatus.imsSubscriptionAppIndex;
- int numApplications = cardStatus.applications.size();
+ IccCardStatus iccCardStatus = new IccCardStatus();
+ iccCardStatus.setCardState(cardStatus.cardState);
+ iccCardStatus.setUniversalPinState(cardStatus.universalPinState);
+ iccCardStatus.mGsmUmtsSubscriptionAppIndex = cardStatus.gsmUmtsSubscriptionAppIndex;
+ iccCardStatus.mCdmaSubscriptionAppIndex = cardStatus.cdmaSubscriptionAppIndex;
+ iccCardStatus.mImsSubscriptionAppIndex = cardStatus.imsSubscriptionAppIndex;
+ int numApplications = cardStatus.applications.size();
- // limit to maximum allowed applications
- if (numApplications
- > com.android.internal.telephony.uicc.IccCardStatus.CARD_MAX_APPS) {
- numApplications =
- com.android.internal.telephony.uicc.IccCardStatus.CARD_MAX_APPS;
- }
- iccCardStatus.mApplications = new IccCardApplicationStatus[numApplications];
- for (int i = 0; i < numApplications; i++) {
- AppStatus rilAppStatus = cardStatus.applications.get(i);
- IccCardApplicationStatus appStatus = new IccCardApplicationStatus();
- appStatus.app_type = appStatus.AppTypeFromRILInt(rilAppStatus.appType);
- appStatus.app_state = appStatus.AppStateFromRILInt(rilAppStatus.appState);
- appStatus.perso_substate = appStatus.PersoSubstateFromRILInt(
- rilAppStatus.persoSubstate);
- appStatus.aid = rilAppStatus.aidPtr;
- appStatus.app_label = rilAppStatus.appLabelPtr;
- appStatus.pin1_replaced = rilAppStatus.pin1Replaced;
- appStatus.pin1 = appStatus.PinStateFromRILInt(rilAppStatus.pin1);
- appStatus.pin2 = appStatus.PinStateFromRILInt(rilAppStatus.pin2);
- iccCardStatus.mApplications[i] = appStatus;
- }
- mRil.riljLog("responseIccCardStatus: from HIDL: " + iccCardStatus);
- ret = iccCardStatus;
- sendMessageResponse(rr.mResult, ret);
+ // limit to maximum allowed applications
+ if (numApplications
+ > com.android.internal.telephony.uicc.IccCardStatus.CARD_MAX_APPS) {
+ numApplications =
+ com.android.internal.telephony.uicc.IccCardStatus.CARD_MAX_APPS;
}
- mRil.processResponseDone(rr, responseInfo, ret);
+ iccCardStatus.mApplications = new IccCardApplicationStatus[numApplications];
+ for (int i = 0; i < numApplications; i++) {
+ AppStatus rilAppStatus = cardStatus.applications.get(i);
+ IccCardApplicationStatus appStatus = new IccCardApplicationStatus();
+ appStatus.app_type = appStatus.AppTypeFromRILInt(rilAppStatus.appType);
+ appStatus.app_state = appStatus.AppStateFromRILInt(rilAppStatus.appState);
+ appStatus.perso_substate = appStatus.PersoSubstateFromRILInt(
+ rilAppStatus.persoSubstate);
+ appStatus.aid = rilAppStatus.aidPtr;
+ appStatus.app_label = rilAppStatus.appLabelPtr;
+ appStatus.pin1_replaced = rilAppStatus.pin1Replaced;
+ appStatus.pin1 = appStatus.PinStateFromRILInt(rilAppStatus.pin1);
+ appStatus.pin2 = appStatus.PinStateFromRILInt(rilAppStatus.pin2);
+ iccCardStatus.mApplications[i] = appStatus;
+ }
+ mRil.riljLog("responseIccCardStatus: from HIDL: " + iccCardStatus);
+ if (responseInfo.error == RadioError.NONE) {
+ sendMessageResponse(rr.mResult, iccCardStatus);
+ }
+ mRil.processResponseDone(rr, responseInfo, iccCardStatus);
}
}
@@ -1250,13 +1287,11 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- Object ret = null;
+ int[] ret = new int[var.size()];
+ for (int i = 0; i < var.size(); i++) {
+ ret[i] = var.get(i);
+ }
if (responseInfo.error == RadioError.NONE) {
- int[] response = new int[var.size()];
- for (int i = 0; i < var.size(); i++) {
- response[i] = var.get(i);
- }
- ret = response;
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1268,82 +1303,77 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- Object ret = null;
- if (responseInfo.error == RadioError.NONE) {
- int num;
- ArrayList<DriverCall> dcCalls;
- DriverCall dc;
+ int num = calls.size();
+ ArrayList<DriverCall> dcCalls = new ArrayList<DriverCall>(num);
+ DriverCall dc;
- num = calls.size();
- dcCalls = new ArrayList<DriverCall>(num);
-
- for (int i = 0; i < num; i++) {
- dc = new DriverCall();
- // TODO: change name of function stateFromCLCC() in DriverCall.java to name
- // clarifying what is CLCC
- dc.state = DriverCall.stateFromCLCC((int) (calls.get(i).state));
- dc.index = calls.get(i).index;
- dc.TOA = calls.get(i).toa;
- dc.isMpty = calls.get(i).isMpty;
- dc.isMT = calls.get(i).isMT;
- dc.als = calls.get(i).als;
- dc.isVoice = calls.get(i).isVoice;
- dc.isVoicePrivacy = calls.get(i).isVoicePrivacy;
- dc.number = calls.get(i).number;
- dc.numberPresentation =
- DriverCall.presentationFromCLIP(
- (int) (calls.get(i).numberPresentation));
- dc.name = calls.get(i).name;
- dc.namePresentation =
- DriverCall.presentationFromCLIP((int) (calls.get(i).namePresentation));
- if (calls.get(i).uusInfo.size() == 1) {
- dc.uusInfo = new UUSInfo();
- dc.uusInfo.setType(calls.get(i).uusInfo.get(0).uusType);
- dc.uusInfo.setDcs(calls.get(i).uusInfo.get(0).uusDcs);
- if (calls.get(i).uusInfo.get(0).uusData != null) {
- byte[] userData = calls.get(i).uusInfo.get(0).uusData.getBytes();
- dc.uusInfo.setUserData(userData);
- } else {
- mRil.riljLog("responseCurrentCalls: uusInfo data is null");
- }
-
- mRil.riljLogv(String.format("Incoming UUS : type=%d, dcs=%d, length=%d",
- dc.uusInfo.getType(), dc.uusInfo.getDcs(),
- dc.uusInfo.getUserData().length));
- mRil.riljLogv("Incoming UUS : data (hex): "
- + IccUtils.bytesToHexString(dc.uusInfo.getUserData()));
+ for (int i = 0; i < num; i++) {
+ dc = new DriverCall();
+ // TODO: change name of function stateFromCLCC() in DriverCall.java to name
+ // clarifying what is CLCC
+ dc.state = DriverCall.stateFromCLCC((int) (calls.get(i).state));
+ dc.index = calls.get(i).index;
+ dc.TOA = calls.get(i).toa;
+ dc.isMpty = calls.get(i).isMpty;
+ dc.isMT = calls.get(i).isMT;
+ dc.als = calls.get(i).als;
+ dc.isVoice = calls.get(i).isVoice;
+ dc.isVoicePrivacy = calls.get(i).isVoicePrivacy;
+ dc.number = calls.get(i).number;
+ dc.numberPresentation =
+ DriverCall.presentationFromCLIP(
+ (int) (calls.get(i).numberPresentation));
+ dc.name = calls.get(i).name;
+ dc.namePresentation =
+ DriverCall.presentationFromCLIP((int) (calls.get(i).namePresentation));
+ if (calls.get(i).uusInfo.size() == 1) {
+ dc.uusInfo = new UUSInfo();
+ dc.uusInfo.setType(calls.get(i).uusInfo.get(0).uusType);
+ dc.uusInfo.setDcs(calls.get(i).uusInfo.get(0).uusDcs);
+ if (!TextUtils.isEmpty(calls.get(i).uusInfo.get(0).uusData)) {
+ byte[] userData = calls.get(i).uusInfo.get(0).uusData.getBytes();
+ dc.uusInfo.setUserData(userData);
} else {
- mRil.riljLogv("Incoming UUS : NOT present!");
+ mRil.riljLog("responseCurrentCalls: uusInfo data is null or empty");
}
- // Make sure there's a leading + on addresses with a TOA of 145
- dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA);
-
- dcCalls.add(dc);
-
- if (dc.isVoicePrivacy) {
- mRil.mVoicePrivacyOnRegistrants.notifyRegistrants();
- mRil.riljLog("InCall VoicePrivacy is enabled");
- } else {
- mRil.mVoicePrivacyOffRegistrants.notifyRegistrants();
- mRil.riljLog("InCall VoicePrivacy is disabled");
- }
+ mRil.riljLogv(String.format("Incoming UUS : type=%d, dcs=%d, length=%d",
+ dc.uusInfo.getType(), dc.uusInfo.getDcs(),
+ dc.uusInfo.getUserData().length));
+ mRil.riljLogv("Incoming UUS : data (hex): "
+ + IccUtils.bytesToHexString(dc.uusInfo.getUserData()));
+ } else {
+ mRil.riljLogv("Incoming UUS : NOT present!");
}
- Collections.sort(dcCalls);
+ // Make sure there's a leading + on addresses with a TOA of 145
+ dc.number = PhoneNumberUtils.stringFromStringAndTOA(dc.number, dc.TOA);
- if ((num == 0) && mRil.mTestingEmergencyCall.getAndSet(false)) {
- if (mRil.mEmergencyCallbackModeRegistrant != null) {
- mRil.riljLog("responseCurrentCalls: call ended, testing emergency call,"
- + " notify ECM Registrants");
- mRil.mEmergencyCallbackModeRegistrant.notifyRegistrant();
- }
+ dcCalls.add(dc);
+
+ if (dc.isVoicePrivacy) {
+ mRil.mVoicePrivacyOnRegistrants.notifyRegistrants();
+ mRil.riljLog("InCall VoicePrivacy is enabled");
+ } else {
+ mRil.mVoicePrivacyOffRegistrants.notifyRegistrants();
+ mRil.riljLog("InCall VoicePrivacy is disabled");
}
-
- ret = dcCalls;
- sendMessageResponse(rr.mResult, ret);
}
- mRil.processResponseDone(rr, responseInfo, ret);
+
+ Collections.sort(dcCalls);
+
+ if ((num == 0) && mRil.mTestingEmergencyCall.getAndSet(false)) {
+ if (mRil.mEmergencyCallbackModeRegistrant != null) {
+ mRil.riljLog("responseCurrentCalls: call ended, testing emergency call,"
+ + " notify ECM Registrants");
+ mRil.mEmergencyCallbackModeRegistrant.notifyRegistrant();
+ }
+ }
+
+ if (responseInfo.error == RadioError.NONE) {
+ sendMessageResponse(rr.mResult, dcCalls);
+ }
+ mRil.processResponseDone(rr, responseInfo, dcCalls);
}
}
@@ -1363,12 +1393,10 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- String ret = null;
if (responseInfo.error == RadioError.NONE) {
- ret = str;
- sendMessageResponse(rr.mResult, ret);
+ sendMessageResponse(rr.mResult, str);
}
- mRil.processResponseDone(rr, responseInfo, ret);
+ mRil.processResponseDone(rr, responseInfo, str);
}
}
@@ -1385,12 +1413,11 @@
RILRequest rr = ril.processResponse(responseInfo);
if (rr != null) {
- String[] ret = null;
+ String[] ret = new String[strings.size()];
+ for (int i = 0; i < strings.size(); i++) {
+ ret[i] = strings.get(i);
+ }
if (responseInfo.error == RadioError.NONE) {
- ret = new String[strings.size()];
- for (int i = 0; i < strings.size(); i++) {
- ret[i] = strings.get(i);
- }
sendMessageResponse(rr.mResult, ret);
}
ril.processResponseDone(rr, responseInfo, ret);
@@ -1402,11 +1429,10 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- LastCallFailCause ret = null;
+ LastCallFailCause ret = new LastCallFailCause();
+ ret.causeCode = fcInfo.causeCode;
+ ret.vendorCause = fcInfo.vendorCause;
if (responseInfo.error == RadioError.NONE) {
- ret = new LastCallFailCause();
- ret.causeCode = fcInfo.causeCode;
- ret.vendorCause = fcInfo.vendorCause;
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1418,9 +1444,8 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- SignalStrength ret = null;
+ SignalStrength ret = RIL.convertHalSignalStrength(sigStrength);
if (responseInfo.error == RadioError.NONE) {
- ret = RIL.convertHalSignalStrength(sigStrength);
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1431,9 +1456,8 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- SmsResponse ret = null;
+ SmsResponse ret = new SmsResponse(sms.messageRef, sms.ackPDU, sms.errorCode);
if (responseInfo.error == RadioError.NONE) {
- ret = new SmsResponse(sms.messageRef, sms.ackPDU, sms.errorCode);
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1458,9 +1482,8 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- IccIoResult ret = null;
+ IccIoResult ret = new IccIoResult(result.sw1, result.sw2, result.simResponse);
if (responseInfo.error == RadioError.NONE) {
- ret = new IccIoResult(result.sw1, result.sw2, result.simResponse);
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1472,18 +1495,17 @@
callForwardInfos) {
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- CallForwardInfo[] ret = null;
+ CallForwardInfo[] ret = new CallForwardInfo[callForwardInfos.size()];
+ for (int i = 0; i < callForwardInfos.size(); i++) {
+ ret[i] = new CallForwardInfo();
+ ret[i].status = callForwardInfos.get(i).status;
+ ret[i].reason = callForwardInfos.get(i).reason;
+ ret[i].serviceClass = callForwardInfos.get(i).serviceClass;
+ ret[i].toa = callForwardInfos.get(i).toa;
+ ret[i].number = callForwardInfos.get(i).number;
+ ret[i].timeSeconds = callForwardInfos.get(i).timeSeconds;
+ }
if (responseInfo.error == RadioError.NONE) {
- ret = new CallForwardInfo[callForwardInfos.size()];
- for (int i = 0; i < callForwardInfos.size(); i++) {
- ret[i] = new CallForwardInfo();
- ret[i].status = callForwardInfos.get(i).status;
- ret[i].reason = callForwardInfos.get(i).reason;
- ret[i].serviceClass = callForwardInfos.get(i).serviceClass;
- ret[i].toa = callForwardInfos.get(i).toa;
- ret[i].number = callForwardInfos.get(i).number;
- ret[i].timeSeconds = callForwardInfos.get(i).timeSeconds;
- }
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1510,31 +1532,43 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- ArrayList<OperatorInfo> ret = null;
+ ArrayList<OperatorInfo> ret = new ArrayList<OperatorInfo>();
+ for (int i = 0; i < networkInfos.size(); i++) {
+ ret.add(new OperatorInfo(networkInfos.get(i).alphaLong,
+ networkInfos.get(i).alphaShort, networkInfos.get(i).operatorNumeric,
+ convertOpertatorInfoToString(networkInfos.get(i).status)));
+ }
if (responseInfo.error == RadioError.NONE) {
- ret = new ArrayList<OperatorInfo>();
- for (int i = 0; i < networkInfos.size(); i++) {
- ret.add(new OperatorInfo(networkInfos.get(i).alphaLong,
- networkInfos.get(i).alphaShort, networkInfos.get(i).operatorNumeric,
- convertOpertatorInfoToString(networkInfos.get(i).status)));
- }
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
}
}
+ private void responseScanStatus(RadioResponseInfo responseInfo) {
+ RILRequest rr = mRil.processResponse(responseInfo);
+
+ if (rr != null) {
+ NetworkScanResult nsr = null;
+ if (responseInfo.error == RadioError.NONE) {
+ nsr = new NetworkScanResult(
+ NetworkScanResult.SCAN_STATUS_PARTIAL, RadioError.NONE, null);
+ sendMessageResponse(rr.mResult, nsr);
+ }
+ mRil.processResponseDone(rr, responseInfo, nsr);
+ }
+ }
+
private void responseDataCallList(RadioResponseInfo responseInfo,
ArrayList<SetupDataCallResult> dataCallResultList) {
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- ArrayList<DataCallResponse> dcResponseList = null;
+ ArrayList<DataCallResponse> dcResponseList = new ArrayList<>();
+ for (SetupDataCallResult dcResult : dataCallResultList) {
+ dcResponseList.add(RIL.convertDataCallResult(dcResult));
+ }
if (responseInfo.error == RadioError.NONE) {
- dcResponseList = new ArrayList<>();
- for (SetupDataCallResult dcResult : dataCallResultList) {
- dcResponseList.add(RIL.convertDataCallResult(dcResult));
- }
sendMessageResponse(rr.mResult, dcResponseList);
}
mRil.processResponseDone(rr, responseInfo, dcResponseList);
@@ -1548,25 +1582,23 @@
if (rr != null) {
int rssi;
String location;
- ArrayList<NeighboringCellInfo> ret = null;
+ ArrayList<NeighboringCellInfo> ret = new ArrayList<NeighboringCellInfo>();
NeighboringCellInfo cell;
- if (responseInfo.error == RadioError.NONE) {
- ret = new ArrayList<NeighboringCellInfo>();
+ int[] subId = SubscriptionManager.getSubId(mRil.mPhoneId);
+ int radioType =
+ ((TelephonyManager) mRil.mContext.getSystemService(
+ Context.TELEPHONY_SERVICE)).getDataNetworkType(subId[0]);
- int[] subId = SubscriptionManager.getSubId(mRil.mPhoneId);
- int radioType =
- ((TelephonyManager) mRil.mContext.getSystemService(
- Context.TELEPHONY_SERVICE)).getDataNetworkType(subId[0]);
-
- if (radioType != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
- for (int i = 0; i < cells.size(); i++) {
- rssi = cells.get(i).rssi;
- location = cells.get(i).cid;
- cell = new NeighboringCellInfo(rssi, location, radioType);
- ret.add(cell);
- }
+ if (radioType != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
+ for (int i = 0; i < cells.size(); i++) {
+ rssi = cells.get(i).rssi;
+ location = cells.get(i).cid;
+ cell = new NeighboringCellInfo(rssi, location, radioType);
+ ret.add(cell);
}
+ }
+ if (responseInfo.error == RadioError.NONE) {
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1578,14 +1610,13 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- ArrayList<SmsBroadcastConfigInfo> ret = null;
+ ArrayList<SmsBroadcastConfigInfo> ret = new ArrayList<SmsBroadcastConfigInfo>();
+ for (int i = 0; i < configs.size(); i++) {
+ ret.add(new SmsBroadcastConfigInfo(configs.get(i).fromServiceId,
+ configs.get(i).toServiceId, configs.get(i).fromCodeScheme,
+ configs.get(i).toCodeScheme, configs.get(i).selected));
+ }
if (responseInfo.error == RadioError.NONE) {
- ret = new ArrayList<SmsBroadcastConfigInfo>();
- for (int i = 0; i < configs.size(); i++) {
- ret.add(new SmsBroadcastConfigInfo(configs.get(i).fromServiceId,
- configs.get(i).toServiceId, configs.get(i).fromCodeScheme,
- configs.get(i).toCodeScheme, configs.get(i).selected));
- }
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1599,41 +1630,41 @@
if (rr != null) {
int[] ret = null;
- if (responseInfo.error == RadioError.NONE) {
- int numServiceCategories = configs.size();
+ int numServiceCategories = configs.size();
- if (numServiceCategories == 0) {
- // TODO: The logic of providing default values should
- // not be done by this transport layer. And needs to
- // be done by the vendor ril or application logic.
- int numInts;
- numInts = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES
- * CDMA_BSI_NO_OF_INTS_STRUCT + 1;
- ret = new int[numInts];
+ if (numServiceCategories == 0) {
+ // TODO: The logic of providing default values should
+ // not be done by this transport layer. And needs to
+ // be done by the vendor ril or application logic.
+ int numInts;
+ numInts = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES
+ * CDMA_BSI_NO_OF_INTS_STRUCT + 1;
+ ret = new int[numInts];
- // Faking a default record for all possible records.
- ret[0] = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES;
+ // Faking a default record for all possible records.
+ ret[0] = CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES;
- // Loop over CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES set 'english' as
- // default language and selection status to false for all.
- for (int i = 1; i < numInts; i += CDMA_BSI_NO_OF_INTS_STRUCT) {
- ret[i + 0] = i / CDMA_BSI_NO_OF_INTS_STRUCT;
- ret[i + 1] = 1;
- ret[i + 2] = 0;
- }
- } else {
- int numInts;
- numInts = (numServiceCategories * CDMA_BSI_NO_OF_INTS_STRUCT) + 1;
- ret = new int[numInts];
-
- ret[0] = numServiceCategories;
- for (int i = 1, j = 0; j < configs.size();
- j++, i = i + CDMA_BSI_NO_OF_INTS_STRUCT) {
- ret[i] = configs.get(j).serviceCategory;
- ret[i + 1] = configs.get(j).language;
- ret[i + 2] = configs.get(j).selected ? 1 : 0;
- }
+ // Loop over CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES set 'english' as
+ // default language and selection status to false for all.
+ for (int i = 1; i < numInts; i += CDMA_BSI_NO_OF_INTS_STRUCT) {
+ ret[i + 0] = i / CDMA_BSI_NO_OF_INTS_STRUCT;
+ ret[i + 1] = 1;
+ ret[i + 2] = 0;
}
+ } else {
+ int numInts;
+ numInts = (numServiceCategories * CDMA_BSI_NO_OF_INTS_STRUCT) + 1;
+ ret = new int[numInts];
+
+ ret[0] = numServiceCategories;
+ for (int i = 1, j = 0; j < configs.size();
+ j++, i = i + CDMA_BSI_NO_OF_INTS_STRUCT) {
+ ret[i] = configs.get(j).serviceCategory;
+ ret[i + 1] = configs.get(j).language;
+ ret[i + 2] = configs.get(j).selected ? 1 : 0;
+ }
+ }
+ if (responseInfo.error == RadioError.NONE) {
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1645,9 +1676,8 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- ArrayList<CellInfo> ret = null;
+ ArrayList<CellInfo> ret = RIL.convertHalCellInfoList(cellInfo);
if (responseInfo.error == RadioError.NONE) {
- ret = RIL.convertHalCellInfoList(cellInfo);
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1686,9 +1716,8 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- ArrayList<HardwareConfig> ret = null;
+ ArrayList<HardwareConfig> ret = RIL.convertHalHwConfigList(config, mRil);
if (responseInfo.error == RadioError.NONE) {
- ret = RIL.convertHalHwConfigList(config, mRil);
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1700,11 +1729,13 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- IccIoResult ret = null;
+ IccIoResult ret = new IccIoResult(
+ result.sw1,
+ result.sw2,
+ (!(result.simResponse).equals(""))
+ ? android.util.Base64.decode(result.simResponse,
+ android.util.Base64.DEFAULT) : (byte[]) null);
if (responseInfo.error == RadioError.NONE) {
- ret = new IccIoResult(result.sw1, result.sw2, (!(result.simResponse).equals(""))
- ? android.util.Base64.decode(result.simResponse,
- android.util.Base64.DEFAULT) : (byte[]) null);
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1716,9 +1747,8 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- RadioCapability ret = null;
+ RadioCapability ret = RIL.convertHalRadioCapability(rc, mRil);
if (responseInfo.error == RadioError.NONE) {
- ret = RIL.convertHalRadioCapability(rc, mRil);
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1729,11 +1759,10 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- ArrayList<Integer> ret = null;
+ ArrayList<Integer> ret = new ArrayList<Integer>();
+ ret.add(statusInfo.lceStatus);
+ ret.add(Byte.toUnsignedInt(statusInfo.actualIntervalMs));
if (responseInfo.error == RadioError.NONE) {
- ret = new ArrayList<Integer>();
- ret.add(statusInfo.lceStatus);
- ret.add((int) statusInfo.actualIntervalMs);
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1744,9 +1773,8 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- ArrayList<Integer> ret = null;
+ ArrayList<Integer> ret = RIL.convertHalLceData(lceInfo, mRil);
if (responseInfo.error == RadioError.NONE) {
- ret = RIL.convertHalLceData(lceInfo, mRil);
sendMessageResponse(rr.mResult, ret);
}
mRil.processResponseDone(rr, responseInfo, ret);
@@ -1758,26 +1786,25 @@
RILRequest rr = mRil.processResponse(responseInfo);
if (rr != null) {
- List<CarrierIdentifier> ret = null;
- if (responseInfo.error == RadioError.NONE) {
- ret = new ArrayList<CarrierIdentifier>();
- for (int i = 0; i < carriers.allowedCarriers.size(); i++) {
- String mcc = carriers.allowedCarriers.get(i).mcc;
- String mnc = carriers.allowedCarriers.get(i).mnc;
- String spn = null, imsi = null, gid1 = null, gid2 = null;
- int matchType = carriers.allowedCarriers.get(i).matchType;
- String matchData = carriers.allowedCarriers.get(i).matchData;
- if (matchType == CarrierIdentifier.MatchType.SPN) {
- spn = matchData;
- } else if (matchType == CarrierIdentifier.MatchType.IMSI_PREFIX) {
- imsi = matchData;
- } else if (matchType == CarrierIdentifier.MatchType.GID1) {
- gid1 = matchData;
- } else if (matchType == CarrierIdentifier.MatchType.GID2) {
- gid2 = matchData;
- }
- ret.add(new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2));
+ List<CarrierIdentifier> ret = new ArrayList<CarrierIdentifier>();
+ for (int i = 0; i < carriers.allowedCarriers.size(); i++) {
+ String mcc = carriers.allowedCarriers.get(i).mcc;
+ String mnc = carriers.allowedCarriers.get(i).mnc;
+ String spn = null, imsi = null, gid1 = null, gid2 = null;
+ int matchType = carriers.allowedCarriers.get(i).matchType;
+ String matchData = carriers.allowedCarriers.get(i).matchData;
+ if (matchType == CarrierIdentifier.MatchType.SPN) {
+ spn = matchData;
+ } else if (matchType == CarrierIdentifier.MatchType.IMSI_PREFIX) {
+ imsi = matchData;
+ } else if (matchType == CarrierIdentifier.MatchType.GID1) {
+ gid1 = matchData;
+ } else if (matchType == CarrierIdentifier.MatchType.GID2) {
+ gid2 = matchData;
}
+ ret.add(new CarrierIdentifier(mcc, mnc, spn, imsi, gid1, gid2));
+ }
+ if (responseInfo.error == RadioError.NONE) {
/* TODO: Handle excluded carriers */
sendMessageResponse(rr.mResult, ret);
}
diff --git a/src/java/com/android/internal/telephony/RetryManager.java b/src/java/com/android/internal/telephony/RetryManager.java
index 684de9a..23c3498 100644
--- a/src/java/com/android/internal/telephony/RetryManager.java
+++ b/src/java/com/android/internal/telephony/RetryManager.java
@@ -27,8 +27,6 @@
import com.android.internal.telephony.dataconnection.ApnSetting;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Random;
@@ -112,6 +110,11 @@
private static final long DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING = 3000;
/**
+ * The default value (in milliseconds) for retrying APN after disconnect
+ */
+ private static final long DEFAULT_APN_RETRY_AFTER_DISCONNECT_DELAY = 10000;
+
+ /**
* The value indicating no retry is needed
*/
public static final long NO_RETRY = -1;
@@ -141,6 +144,12 @@
private long mFailFastInterApnDelay;
/**
+ * The delay (in milliseconds) for APN retrying after disconnect (e.g. Modem suddenly reports
+ * data call lost)
+ */
+ private long mApnRetryAfterDisconnectDelay;
+
+ /**
* Modem suggested delay for retrying the current APN
*/
private long mModemSuggestedDelay = NO_SUGGESTED_RETRY_DELAY;
@@ -337,6 +346,9 @@
mFailFastInterApnDelay = b.getLong(
CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_DELAY_FASTER_LONG,
DEFAULT_INTER_APN_DELAY_FOR_PROVISIONING);
+ mApnRetryAfterDisconnectDelay = b.getLong(
+ CarrierConfigManager.KEY_CARRIER_DATA_CALL_APN_RETRY_AFTER_DISCONNECT_LONG,
+ DEFAULT_APN_RETRY_AFTER_DISCONNECT_DELAY);
// Load all retry patterns for all different APNs.
String[] allConfigStrings = b.getStringArray(
@@ -645,44 +657,21 @@
}
/**
- * Get the delay between APN setting trying. This is the fixed delay used for APN setting trying
- * within the same round, comparing to the exponential delay used for different rounds.
- * @param failFastEnabled True if fail fast mode enabled, which a shorter delay will be used
+ * Get the delay in milliseconds for APN retry after disconnect
* @return The delay in milliseconds
*/
- public long getInterApnDelay(boolean failFastEnabled) {
- return (failFastEnabled) ? mFailFastInterApnDelay : mInterApnDelay;
+ public long getRetryAfterDisconnectDelay() {
+ return mApnRetryAfterDisconnectDelay;
}
public String toString() {
- return "mApnType=" + mApnType + " mRetryCount=" + mRetryCount +
- " mMaxRetryCount=" + mMaxRetryCount + " mCurrentApnIndex=" + mCurrentApnIndex +
- " mSameApnRtryCount=" + mSameApnRetryCount + " mModemSuggestedDelay=" +
- mModemSuggestedDelay + " mRetryForever=" + mRetryForever +
- " mConfig={" + mConfig + "}";
- }
-
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println(" RetryManager");
- pw.println("***************************************");
-
- pw.println(" config = " + mConfig);
- pw.println(" mApnType = " + mApnType);
- pw.println(" mCurrentApnIndex = " + mCurrentApnIndex);
- pw.println(" mRetryCount = " + mRetryCount);
- pw.println(" mMaxRetryCount = " + mMaxRetryCount);
- pw.println(" mSameApnRetryCount = " + mSameApnRetryCount);
- pw.println(" mModemSuggestedDelay = " + mModemSuggestedDelay);
-
- if (mWaitingApns != null) {
- pw.println(" APN list: ");
- for (int i = 0; i < mWaitingApns.size(); i++) {
- pw.println(" [" + i + "]=" + mWaitingApns.get(i));
- }
- }
-
- pw.println("***************************************");
- pw.flush();
+ if (mConfig == null) return "";
+ return "RetryManager: mApnType=" + mApnType + " mRetryCount=" + mRetryCount
+ + " mMaxRetryCount=" + mMaxRetryCount + " mCurrentApnIndex=" + mCurrentApnIndex
+ + " mSameApnRtryCount=" + mSameApnRetryCount + " mModemSuggestedDelay="
+ + mModemSuggestedDelay + " mRetryForever=" + mRetryForever + " mInterApnDelay="
+ + mInterApnDelay + " mApnRetryAfterDisconnectDelay=" + mApnRetryAfterDisconnectDelay
+ + " mConfig={" + mConfig + "}";
}
private void log(String s) {
diff --git a/src/java/com/android/internal/telephony/RilWakelockInfo.java b/src/java/com/android/internal/telephony/RilWakelockInfo.java
index 319f2fa..5d9e54b 100644
--- a/src/java/com/android/internal/telephony/RilWakelockInfo.java
+++ b/src/java/com/android/internal/telephony/RilWakelockInfo.java
@@ -18,7 +18,8 @@
import android.annotation.TargetApi;
import android.os.Build;
-import android.util.Log;
+import android.telephony.Rlog;
+
import com.android.internal.annotations.VisibleForTesting;
@TargetApi(8)
@@ -59,7 +60,7 @@
if(Build.IS_DEBUGGABLE) {
IllegalArgumentException e = new IllegalArgumentException(
"concurrentRequests should always be greater than 0.");
- Log.wtf(LOG_TAG, e);
+ Rlog.e(LOG_TAG, e.toString());
throw e;
} else {
concurrentRequests = 1;
diff --git a/src/java/com/android/internal/telephony/SMSDispatcher.java b/src/java/com/android/internal/telephony/SMSDispatcher.java
index d1e8a0c..2ec5101 100644
--- a/src/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/src/java/com/android/internal/telephony/SMSDispatcher.java
@@ -23,6 +23,8 @@
import static android.telephony.SmsManager.RESULT_ERROR_NO_SERVICE;
import static android.telephony.SmsManager.RESULT_ERROR_NULL_PDU;
import static android.telephony.SmsManager.RESULT_ERROR_RADIO_OFF;
+import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED;
+import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -74,6 +76,7 @@
import android.widget.TextView;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
import com.android.internal.telephony.uicc.UiccCard;
import com.android.internal.telephony.uicc.UiccController;
@@ -313,7 +316,25 @@
case EVENT_STOP_SENDING:
{
SmsTracker tracker = (SmsTracker) msg.obj;
- tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
+ if (msg.arg1 == ConfirmDialogListener.SHORT_CODE_MSG) {
+ if (msg.arg2 == ConfirmDialogListener.NEVER_ALLOW) {
+ tracker.onFailed(mContext,
+ RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, 0/*errorCode*/);
+ Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - "
+ + "sending SHORT_CODE_NEVER_ALLOWED error code.");
+ } else {
+ tracker.onFailed(mContext,
+ RESULT_ERROR_SHORT_CODE_NOT_ALLOWED, 0/*errorCode*/);
+ Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - "
+ + "sending SHORT_CODE_NOT_ALLOWED error code.");
+ }
+ } else if (msg.arg1 == ConfirmDialogListener.RATE_LIMIT) {
+ tracker.onFailed(mContext, RESULT_ERROR_LIMIT_EXCEEDED, 0/*errorCode*/);
+ Rlog.d(TAG, "SMSDispatcher: EVENT_STOP_SENDING - "
+ + "sending LIMIT_EXCEEDED error code.");
+ } else {
+ Rlog.e(TAG, "SMSDispatcher: EVENT_STOP_SENDING - unexpected cases.");
+ }
mPendingTrackerCount--;
break;
}
@@ -950,7 +971,8 @@
* raw pdu of the status report is in the extended data ("pdu").
* -param destAddr the destination phone number (for short code confirmation)
*/
- protected void sendRawPdu(SmsTracker tracker) {
+ @VisibleForTesting
+ public void sendRawPdu(SmsTracker tracker) {
HashMap map = tracker.getData();
byte pdu[] = (byte[]) map.get("pdu");
@@ -1055,7 +1077,7 @@
// Wait for user confirmation unless the user has set permission to always allow/deny
int premiumSmsPermission = mUsageMonitor.getPremiumSmsPermission(
- tracker.mAppInfo.packageName);
+ tracker.getAppPackageName());
if (premiumSmsPermission == SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) {
// First time trying to send to premium SMS.
premiumSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER;
@@ -1068,7 +1090,10 @@
case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW:
Rlog.w(TAG, "User denied this app from sending to premium SMS");
- sendMessage(obtainMessage(EVENT_STOP_SENDING, tracker));
+ Message msg = obtainMessage(EVENT_STOP_SENDING, tracker);
+ msg.arg1 = ConfirmDialogListener.SHORT_CODE_MSG;
+ msg.arg2 = ConfirmDialogListener.NEVER_ALLOW;
+ sendMessage(msg);
return false; // reject this message
case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER:
@@ -1127,11 +1152,13 @@
return; // queue limit reached; error was returned to caller
}
- CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName, tracker.mUserId);
+ CharSequence appLabel = getAppLabel(tracker.getAppPackageName(), tracker.mUserId);
Resources r = Resources.getSystem();
Spanned messageText = Html.fromHtml(r.getString(R.string.sms_control_message, appLabel));
- ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null);
+ // Construct ConfirmDialogListenter for Rate Limit handling
+ ConfirmDialogListener listener = new ConfirmDialogListener(tracker, null,
+ ConfirmDialogListener.RATE_LIMIT);
AlertDialog d = new AlertDialog.Builder(mContext)
.setTitle(R.string.sms_control_title)
@@ -1163,7 +1190,7 @@
detailsId = R.string.sms_short_code_details;
}
- CharSequence appLabel = getAppLabel(tracker.mAppInfo.packageName, tracker.mUserId);
+ CharSequence appLabel = getAppLabel(tracker.getAppPackageName(), tracker.mUserId);
Resources r = Resources.getSystem();
Spanned messageText = Html.fromHtml(r.getString(R.string.sms_short_code_confirm_message,
appLabel, tracker.mDestAddress));
@@ -1172,8 +1199,10 @@
Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.sms_short_code_confirmation_dialog, null);
+ // Construct ConfirmDialogListenter for short code message sending
ConfirmDialogListener listener = new ConfirmDialogListener(tracker,
- (TextView)layout.findViewById(R.id.sms_short_code_remember_undo_instruction));
+ (TextView) layout.findViewById(R.id.sms_short_code_remember_undo_instruction),
+ ConfirmDialogListener.SHORT_CODE_MSG);
TextView messageView = (TextView) layout.findViewById(R.id.sms_short_code_confirm_message);
@@ -1374,6 +1403,14 @@
}
/**
+ * Get the App package name
+ * @return App package name info
+ */
+ public String getAppPackageName() {
+ return mAppInfo != null ? mAppInfo.packageName : null;
+ }
+
+ /**
* Update the status of this message if we persisted it
*/
public void updateSentMessageStatus(Context context, int status) {
@@ -1634,10 +1671,15 @@
private Button mNegativeButton;
private boolean mRememberChoice; // default is unchecked
private final TextView mRememberUndoInstruction;
+ private int mConfirmationType; // 0 - Short Code Msg Sending; 1 - Rate Limit Exceeded
+ private static final int SHORT_CODE_MSG = 0; // Short Code Msg
+ private static final int RATE_LIMIT = 1; // Rate Limit Exceeded
+ private static final int NEVER_ALLOW = 1; // Never Allow
- ConfirmDialogListener(SmsTracker tracker, TextView textView) {
+ ConfirmDialogListener(SmsTracker tracker, TextView textView, int confirmationType) {
mTracker = tracker;
mRememberUndoInstruction = textView;
+ mConfirmationType = confirmationType;
}
void setPositiveButton(Button button) {
@@ -1670,18 +1712,23 @@
EventLog.writeEvent(EventLogTags.EXP_DET_SMS_DENIED_BY_USER,
mTracker.mAppInfo.applicationInfo == null ?
-1 : mTracker.mAppInfo.applicationInfo.uid);
- sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
+ Message msg = obtainMessage(EVENT_STOP_SENDING, mTracker);
+ msg.arg1 = mConfirmationType;
if (mRememberChoice) {
newSmsPermission = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
+ msg.arg2 = ConfirmDialogListener.NEVER_ALLOW;
}
+ sendMessage(msg);
}
- setPremiumSmsPermission(mTracker.mAppInfo.packageName, newSmsPermission);
+ setPremiumSmsPermission(mTracker.getAppPackageName(), newSmsPermission);
}
@Override
public void onCancel(DialogInterface dialog) {
Rlog.d(TAG, "dialog dismissed: don't send SMS");
- sendMessage(obtainMessage(EVENT_STOP_SENDING, mTracker));
+ Message msg = obtainMessage(EVENT_STOP_SENDING, mTracker);
+ msg.arg1 = mConfirmationType;
+ sendMessage(msg);
}
@Override
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index dd4624b..fb8231e 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -86,6 +86,8 @@
import com.android.internal.telephony.uicc.SIMRecords;
import com.android.internal.telephony.uicc.UiccCardApplication;
import com.android.internal.telephony.uicc.UiccController;
+import com.android.internal.telephony.util.NotificationChannelController;
+import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
@@ -128,16 +130,6 @@
// TODO - this should not be public, right now used externally GsmConnetion.
public RestrictedState mRestrictedState;
- /* The otaspMode passed to PhoneStateListener#onOtaspChanged */
- static public final int OTASP_UNINITIALIZED = 0;
- static public final int OTASP_UNKNOWN = 1;
- static public final int OTASP_NEEDED = 2;
- static public final int OTASP_NOT_NEEDED = 3;
- /**
- * OtaUtil has conflict enum 4: OtaUtils.OTASP_FAILURE_SPC_RETRIES
- */
- static public final int OTASP_SIM_UNPROVISIONED = 5;
-
/**
* A unique identifier to track requests associated with a poll
* and ignore stale responses. The value is a count-down of
@@ -185,7 +177,6 @@
protected static final int EVENT_POLL_SIGNAL_STRENGTH = 10;
protected static final int EVENT_NITZ_TIME = 11;
protected static final int EVENT_SIGNAL_STRENGTH_UPDATE = 12;
- protected static final int EVENT_RADIO_AVAILABLE = 13;
protected static final int EVENT_POLL_STATE_NETWORK_SELECTION_MODE = 14;
protected static final int EVENT_GET_LOC_DONE = 15;
protected static final int EVENT_SIM_RECORDS_LOADED = 16;
@@ -491,7 +482,7 @@
public static final String UNACTIVATED_MIN2_VALUE = "000000";
public static final String UNACTIVATED_MIN_VALUE = "1111110111";
// Current Otasp value
- private int mCurrentOtaspMode = OTASP_UNINITIALIZED;
+ private int mCurrentOtaspMode = TelephonyManager.OTASP_UNINITIALIZED;
/** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */
public static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10;
private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing",
@@ -551,6 +542,7 @@
mSubscriptionManager = SubscriptionManager.from(phone.getContext());
mSubscriptionManager
.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
+ mRestrictedState = new RestrictedState();
mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null);
@@ -594,8 +586,9 @@
filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
context.registerReceiver(mIntentReceiver, filter);
- mPhone.notifyOtaspChanged(OTASP_UNINITIALIZED);
+ mPhone.notifyOtaspChanged(TelephonyManager.OTASP_UNINITIALIZED);
+ mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
updatePhoneType();
mCSST = new CarrierServiceStateTracker(phone, this);
@@ -612,12 +605,28 @@
@VisibleForTesting
public void updatePhoneType() {
+ // If we are previously voice roaming, we need to notify that roaming status changed before
+ // we change back to non-roaming.
+ if (mSS != null && mSS.getVoiceRoaming()) {
+ mVoiceRoamingOffRegistrants.notifyRegistrants();
+ }
+
+ // If we are previously data roaming, we need to notify that roaming status changed before
+ // we change back to non-roaming.
+ if (mSS != null && mSS.getDataRoaming()) {
+ mDataRoamingOffRegistrants.notifyRegistrants();
+ }
+
+ // If we are previously in service, we need to notify that we are out of service now.
+ if (mSS != null && mSS.getDataRegState() == ServiceState.STATE_IN_SERVICE) {
+ mDetachedRegistrants.notifyRegistrants();
+ }
+
mSS = new ServiceState();
mNewSS = new ServiceState();
mLastCellInfoListTime = 0;
mLastCellInfoList = null;
mSignalStrength = new SignalStrength();
- mRestrictedState = new RestrictedState();
mStartedGprsRegCheck = false;
mReportedGprsNoReg = false;
mMdn = null;
@@ -642,13 +651,7 @@
mCellLoc = new GsmCellLocation();
mNewCellLoc = new GsmCellLocation();
- mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
- mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
} else {
- //clear GSM regsitrations first
- mCi.unregisterForAvailable(this);
- mCi.unSetOnRestrictedStateChanged(this);
-
if (mPhone.isPhoneTypeCdmaLte()) {
mPhone.registerForSimRecordsLoaded(this, EVENT_SIM_RECORDS_LOADED, null);
}
@@ -683,11 +686,7 @@
logPhoneTypeChange();
- // Tell everybody that we've thrown away state and are starting over with
- // empty, detached ServiceStates.
- mVoiceRoamingOffRegistrants.notifyRegistrants();
- mDataRoamingOffRegistrants.notifyRegistrants();
- mDetachedRegistrants.notifyRegistrants();
+ // Tell everybody that the registration state and RAT have changed.
notifyDataRegStateRilRadioTechnologyChanged();
}
@@ -722,6 +721,7 @@
try {
mPhone.notifySignalStrength();
notified = true;
+ mLastSignalStrength = mSignalStrength;
} catch (NullPointerException ex) {
loge("updateSignalStrength() Phone already destroyed: " + ex
+ "SignalStrength not notified");
@@ -844,12 +844,13 @@
* @param h handler to notify
* @param what what code of message when delivered
* @param obj placed in Message.obj
+ * @param notifyNow notify upon registration if data roaming is off
*/
- public void registerForDataRoamingOff(Handler h, int what, Object obj) {
+ public void registerForDataRoamingOff(Handler h, int what, Object obj, boolean notifyNow) {
Registrant r = new Registrant(h, what, obj);
mDataRoamingOffRegistrants.add(r);
- if (!mSS.getDataRoaming()) {
+ if (notifyNow && !mSS.getDataRoaming()) {
r.notifyRegistrant();
}
}
@@ -1115,12 +1116,7 @@
}
break;
- //GSM
- case EVENT_RADIO_AVAILABLE:
- //this is unnecessary
- //setPowerStateToDesired();
- break;
-
+ // GSM
case EVENT_SIM_READY:
// Reset the mPreviousSubId so we treat a SIM power bounce
// as a first boot. See b/19194287
@@ -1541,27 +1537,27 @@
// if sim is not loaded, return otasp uninitialized
if(!mPhone.getIccRecordsLoaded()) {
if(DBG) log("getOtasp: otasp uninitialized due to sim not loaded");
- return OTASP_UNINITIALIZED;
+ return TelephonyManager.OTASP_UNINITIALIZED;
}
// if voice tech is Gsm, return otasp not needed
if(mPhone.isPhoneTypeGsm()) {
if(DBG) log("getOtasp: otasp not needed for GSM");
- return OTASP_NOT_NEEDED;
+ return TelephonyManager.OTASP_NOT_NEEDED;
}
// for ruim, min is null means require otasp.
if (mIsSubscriptionFromRuim && mMin == null) {
- return OTASP_NEEDED;
+ return TelephonyManager.OTASP_NEEDED;
}
if (mMin == null || (mMin.length() < 6)) {
if (DBG) log("getOtasp: bad mMin='" + mMin + "'");
- provisioningState = OTASP_UNKNOWN;
+ provisioningState = TelephonyManager.OTASP_UNKNOWN;
} else {
if ((mMin.equals(UNACTIVATED_MIN_VALUE)
|| mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
|| SystemProperties.getBoolean("test_cdma_setup", false)) {
- provisioningState = OTASP_NEEDED;
+ provisioningState = TelephonyManager.OTASP_NEEDED;
} else {
- provisioningState = OTASP_NOT_NEEDED;
+ provisioningState = TelephonyManager.OTASP_NOT_NEEDED;
}
}
if (DBG) log("getOtasp: state=" + provisioningState);
@@ -1655,14 +1651,45 @@
// Setting SS Roaming (general)
if (mIsSubscriptionFromRuim) {
- mNewSS.setVoiceRoaming(isRoamingBetweenOperators(mNewSS.getVoiceRoaming(), mNewSS));
+ boolean isRoamingBetweenOperators = isRoamingBetweenOperators(
+ mNewSS.getVoiceRoaming(), mNewSS);
+ if (isRoamingBetweenOperators != mNewSS.getVoiceRoaming()) {
+ log("isRoamingBetweenOperators=" + isRoamingBetweenOperators
+ + ". Override CDMA voice roaming to " + isRoamingBetweenOperators);
+ mNewSS.setVoiceRoaming(isRoamingBetweenOperators);
+ }
}
- // For CDMA, voice and data should have the same roaming status
- final boolean isVoiceInService =
- (mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
- final int dataRegType = mNewSS.getRilDataRadioTechnology();
- if (isVoiceInService && ServiceState.isCdma(dataRegType)) {
- mNewSS.setDataRoaming(mNewSS.getVoiceRoaming());
+ /**
+ * For CDMA, voice and data should have the same roaming status.
+ * If voice is not in service, use TSB58 roaming indicator to set
+ * data roaming status. If TSB58 roaming indicator is not in the
+ * carrier-specified list of ERIs for home system then set roaming.
+ */
+ final int dataRat = mNewSS.getRilDataRadioTechnology();
+ if (ServiceState.isCdma(dataRat)) {
+ final boolean isVoiceInService =
+ (mNewSS.getVoiceRegState() == ServiceState.STATE_IN_SERVICE);
+ if (isVoiceInService) {
+ boolean isVoiceRoaming = mNewSS.getVoiceRoaming();
+ if (mNewSS.getDataRoaming() != isVoiceRoaming) {
+ log("Data roaming != Voice roaming. Override data roaming to "
+ + isVoiceRoaming);
+ mNewSS.setDataRoaming(isVoiceRoaming);
+ }
+ } else {
+ /**
+ * As per VoiceRegStateResult from radio types.hal the TSB58
+ * Roaming Indicator shall be sent if device is registered
+ * on a CDMA or EVDO system.
+ */
+ boolean isRoamIndForHomeSystem = isRoamIndForHomeSystem(
+ Integer.toString(mRoamingIndicator));
+ if (mNewSS.getDataRoaming() == isRoamIndForHomeSystem) {
+ log("isRoamIndForHomeSystem=" + isRoamIndForHomeSystem
+ + ", override data roaming to " + !isRoamIndForHomeSystem);
+ mNewSS.setDataRoaming(!isRoamIndForHomeSystem);
+ }
+ }
}
// Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator
@@ -1769,8 +1796,10 @@
case EVENT_POLL_STATE_REGISTRATION: {
VoiceRegStateResult voiceRegStateResult = (VoiceRegStateResult) ar.result;
int registrationState = getRegStateFromHalRegState(voiceRegStateResult.regState);
+ int cssIndicator = voiceRegStateResult.cssSupported ? 1 : 0;
mNewSS.setVoiceRegState(regCodeToServiceState(registrationState));
+ mNewSS.setCssIndicator(cssIndicator);
mNewSS.setRilVoiceRadioTechnology(voiceRegStateResult.rat);
//Denial reason if registrationState = 3
@@ -1796,8 +1825,6 @@
mEmergencyOnly = false;
}
} else {
- //init with 0, because it is treated as a boolean
- int cssIndicator = voiceRegStateResult.cssSupported ? 1 : 0;
int roamingIndicator = voiceRegStateResult.roamingIndicator;
//Indicates if current system is in PR
@@ -1815,7 +1842,6 @@
&& !isRoamIndForHomeSystem(
Integer.toString(roamingIndicator));
mNewSS.setVoiceRoaming(cdmaRoaming);
- mNewSS.setCssIndicator(cssIndicator);
mRoamingIndicator = roamingIndicator;
mIsInPrl = (systemIsInPrl == 0) ? false : true;
mDefaultRoamingIndicator = defaultRoamingIndicator;
@@ -1866,6 +1892,9 @@
mNewReasonDataDenied = dataRegStateResult.reasonDataDenied;
mNewMaxDataCalls = dataRegStateResult.maxDataCalls;
mDataRoaming = regCodeIsRoaming(regState);
+ // Save the data roaming state reported by modem registration before resource
+ // overlay or carrier config possibly overrides it.
+ mNewSS.setDataRoamingFromRegistration(mDataRoaming);
if (DBG) {
log("handlPollStateResultMessage: GsmSST setDataRegState=" + dataRegState
@@ -1874,7 +1903,11 @@
}
} else if (mPhone.isPhoneTypeCdma()) {
- mNewSS.setDataRoaming(regCodeIsRoaming(regState));
+ boolean isDataRoaming = regCodeIsRoaming(regState);
+ mNewSS.setDataRoaming(isDataRoaming);
+ // Save the data roaming state reported by modem registration before resource
+ // overlay or carrier config possibly overrides it.
+ mNewSS.setDataRoamingFromRegistration(isDataRoaming);
if (DBG) {
log("handlPollStateResultMessage: cdma setDataRegState=" + dataRegState
@@ -1899,11 +1932,15 @@
}
// voice roaming state in done while handling EVENT_POLL_STATE_REGISTRATION_CDMA
- mNewSS.setDataRoaming(regCodeIsRoaming(regState));
+ boolean isDataRoaming = regCodeIsRoaming(regState);
+ mNewSS.setDataRoaming(isDataRoaming);
+ // Save the data roaming state reported by modem registration before resource
+ // overlay or carrier config possibly overrides it.
+ mNewSS.setDataRoamingFromRegistration(isDataRoaming);
if (DBG) {
- log("handlPollStateResultMessage: CdmaLteSST setDataRegState=" + dataRegState
- + " regState=" + regState
- + " dataRadioTechnology=" + newDataRat);
+ log("handlPollStateResultMessage: CdmaLteSST setDataRegState="
+ + dataRegState + " regState=" + regState + " dataRadioTechnology="
+ + newDataRat);
}
}
@@ -1966,7 +2003,7 @@
case EVENT_POLL_STATE_NETWORK_SELECTION_MODE: {
ints = (int[])ar.result;
mNewSS.setIsManualSelection(ints[0] == 1);
- if ((ints[0] == 1) && (!mPhone.isManualNetSelAllowed())) {
+ if ((ints[0] == 1) && (mPhone.shouldForceAutoNetworkSelect())) {
/*
* modem is currently in manual selection but manual
* selection is not allowed in the current mode so
@@ -1993,8 +2030,9 @@
*/
private boolean isRoamIndForHomeSystem(String roamInd) {
// retrieve the carrier-specified list of ERIs for home system
- String[] homeRoamIndicators = mPhone.getContext().getResources()
+ String[] homeRoamIndicators = Resources.getSystem()
.getStringArray(com.android.internal.R.array.config_cdma_home_system);
+ log("isRoamIndForHomeSystem: homeRoamIndicators=" + Arrays.toString(homeRoamIndicators));
if (homeRoamIndicators != null) {
// searches through the comma-separated list for a match,
@@ -2005,10 +2043,12 @@
}
}
// no matches found against the list!
+ log("isRoamIndForHomeSystem: No match found against list for roamInd=" + roamInd);
return false;
}
// no system property found for the roaming indicators for home system
+ log("isRoamIndForHomeSystem: No list found");
return false;
}
@@ -2032,14 +2072,15 @@
* agreements and MVNO's.
*/
boolean roaming = (mGsmRoaming || mDataRoaming);
- if (mGsmRoaming && !isOperatorConsideredRoaming(mNewSS) &&
- (isSameNamedOperators(mNewSS) || isOperatorConsideredNonRoaming(mNewSS))) {
+
+ if (mGsmRoaming && !isOperatorConsideredRoaming(mNewSS)
+ && (isSameNamedOperators(mNewSS) || isOperatorConsideredNonRoaming(mNewSS))) {
+ log("updateRoamingState: resource override set non roaming.isSameNamedOperators="
+ + isSameNamedOperators(mNewSS) + ",isOperatorConsideredNonRoaming="
+ + isOperatorConsideredNonRoaming(mNewSS));
roaming = false;
}
- // Save the roaming state before carrier config possibly overrides it.
- mNewSS.setDataRoamingFromRegistration(roaming);
-
CarrierConfigManager configLoader = (CarrierConfigManager)
mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
@@ -2069,9 +2110,6 @@
mNewSS.setVoiceRoaming(roaming);
mNewSS.setDataRoaming(roaming);
} else {
- // Save the roaming state before carrier config possibly overrides it.
- mNewSS.setDataRoamingFromRegistration(mNewSS.getDataRoaming());
-
CarrierConfigManager configLoader = (CarrierConfigManager)
mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
if (configLoader != null) {
@@ -2270,7 +2308,7 @@
mCurDataSpn = dataSpn;
mCurPlmn = plmn;
} else {
- // mOperatorAlphaLong contains the ERI text
+ // mOperatorAlpha contains the ERI text
String plmn = mSS.getOperatorAlpha();
boolean showPlmn = false;
@@ -2460,16 +2498,13 @@
* that could support voice and data simultaneously.
*/
public boolean isConcurrentVoiceAndDataAllowed() {
- if (mPhone.isPhoneTypeGsm()) {
- return (mSS.getRilVoiceRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
- } else if (mPhone.isPhoneTypeCdma()) {
- // Note: it needs to be confirmed which CDMA network types
- // can support voice and data calls concurrently.
- // For the time-being, the return value will be false.
- return false;
+ if (mSS.getCssIndicator() == 1) {
+ // Checking the Concurrent Service Supported flag first for all phone types.
+ return true;
+ } else if (mPhone.isPhoneTypeGsm()) {
+ return (mSS.getRilDataRadioTechnology() >= ServiceState.RIL_RADIO_TECHNOLOGY_UMTS);
} else {
- // Using the Conncurrent Service Supported flag for CdmaLte devices.
- return mSS.getCssIndicator() == 1;
+ return false;
}
}
@@ -2642,6 +2677,8 @@
boolean hasRejectCauseChanged = mRejectCode != mNewRejectCode;
+ boolean hasCssIndicatorChanged = (mSS.getCssIndicator() != mNewSS.getCssIndicator());
+
boolean has4gHandoff = false;
boolean hasMultiApnSupport = false;
boolean hasLostMultiApnSupport = false;
@@ -2687,7 +2724,8 @@
+ " hasLocationChanged=" + hasLocationChanged
+ " has4gHandoff = " + has4gHandoff
+ " hasMultiApnSupport=" + hasMultiApnSupport
- + " hasLostMultiApnSupport=" + hasLostMultiApnSupport);
+ + " hasLostMultiApnSupport=" + hasLostMultiApnSupport
+ + " hasCssIndicatorChanged=" + hasCssIndicatorChanged);
}
// Add an event log when connection state changes
@@ -2722,6 +2760,11 @@
mNewSS.getRilVoiceRadioTechnology()) + " at cell " + cid);
}
}
+
+ if (hasCssIndicatorChanged) {
+ mPhone.notifyDataConnection(Phone.REASON_CSS_INDICATOR_CHANGED);
+ }
+
mReasonDataDenied = mNewReasonDataDenied;
mMaxDataCalls = mNewMaxDataCalls;
mRejectCode = mNewRejectCode;
@@ -2797,7 +2840,13 @@
tm.setNetworkCountryIsoForPhone(mPhone.getPhoneId(), "");
mGotCountryCode = false;
mNitzUpdatedTime = false;
- } else {
+ } else if (mSS.getRilDataRadioTechnology() != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
+ // Update time zone, ISO, and IDD.
+ //
+ // If the device is on IWLAN, modems manufacture a ServiceState with the MCC/MNC of
+ // the SIM as if we were talking to towers. Telephony code then uses that with
+ // mccTable to suggest a timezone. We shouldn't do that if the MCC/MNC is from IWLAN
+
String iso = "";
String mcc = "";
try {
@@ -2812,31 +2861,7 @@
if (!mNitzUpdatedTime && !mcc.equals("000") && !TextUtils.isEmpty(iso)
&& getAutoTimeZone()) {
-
- // Test both paths if ignore nitz is true
- boolean testOneUniqueOffsetPath = SystemProperties.getBoolean(
- TelephonyProperties.PROPERTY_IGNORE_NITZ, false)
- && ((SystemClock.uptimeMillis() & 1) == 0);
-
- ArrayList<TimeZone> uniqueZones = TimeUtils.getTimeZonesWithUniqueOffsets(iso);
- if ((uniqueZones.size() == 1) || testOneUniqueOffsetPath) {
- TimeZone zone = uniqueZones.get(0);
- if (DBG) {
- log("pollStateDone: no nitz but one TZ for iso-cc=" + iso
- + " with zone.getID=" + zone.getID()
- + " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath);
- }
- mTimeZoneLog.log("pollStateDone: set time zone=" + zone.getID()
- + " mcc=" + mcc + " iso=" + iso);
- setAndBroadcastNetworkSetTimeZone(zone.getID());
- } else {
- if (DBG) {
- log("pollStateDone: there are " + uniqueZones.size()
- + " unique offsets for iso-cc='" + iso
- + " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath
- + "', do nothing");
- }
- }
+ updateTimeZoneByNetworkCountryCode(iso);
}
if (!mPhone.isPhoneTypeGsm()) {
@@ -3126,8 +3151,6 @@
+ mNeedFixZoneAfterNitz + " zone=" + (zone != null ? zone.getID() : "NULL");
mTimeZoneLog.log(tmpLog);
- mNeedFixZoneAfterNitz = false;
-
if (zone != null) {
log("fixTimeZone: zone != null zone.getID=" + zone.getID());
if (getAutoTimeZone()) {
@@ -3135,10 +3158,13 @@
} else {
log("fixTimeZone: skip changing zone as getAutoTimeZone was false");
}
- saveNitzTimeZone(zone.getID());
+ if (mNeedFixZoneAfterNitz) {
+ saveNitzTimeZone(zone.getID());
+ }
} else {
log("fixTimeZone: zone == null, do nothing for zone");
}
+ mNeedFixZoneAfterNitz = false;
}
/**
@@ -3257,7 +3283,8 @@
/**
* Do not set roaming state in case of oprators considered non-roaming.
*
- * Can use mcc or mcc+mnc as item of config_operatorConsideredNonRoaming.
+ * Can use mcc or mcc+mnc as item of
+ * {@link CarrierConfigManager#KEY_NON_ROAMING_OPERATOR_STRING_ARRAY}.
* For example, 302 or 21407. If mcc or mcc+mnc match with operator,
* don't set roaming state.
*
@@ -3266,15 +3293,22 @@
*/
private boolean isOperatorConsideredNonRoaming(ServiceState s) {
String operatorNumeric = s.getOperatorNumeric();
- String[] numericArray = mPhone.getContext().getResources().getStringArray(
- com.android.internal.R.array.config_operatorConsideredNonRoaming);
-
- if (numericArray.length == 0 || operatorNumeric == null) {
+ final CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
+ .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ String[] numericArray = null;
+ if (configManager != null) {
+ PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId());
+ if (config != null) {
+ numericArray = config.getStringArray(
+ CarrierConfigManager.KEY_NON_ROAMING_OPERATOR_STRING_ARRAY);
+ }
+ }
+ if (ArrayUtils.isEmpty(numericArray) || operatorNumeric == null) {
return false;
}
for (String numeric : numericArray) {
- if (operatorNumeric.startsWith(numeric)) {
+ if (!TextUtils.isEmpty(numeric) && operatorNumeric.startsWith(numeric)) {
return true;
}
}
@@ -3283,15 +3317,22 @@
private boolean isOperatorConsideredRoaming(ServiceState s) {
String operatorNumeric = s.getOperatorNumeric();
- String[] numericArray = mPhone.getContext().getResources().getStringArray(
- com.android.internal.R.array.config_sameNamedOperatorConsideredRoaming);
-
- if (numericArray.length == 0 || operatorNumeric == null) {
+ final CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
+ .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ String[] numericArray = null;
+ if (configManager != null) {
+ PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId());
+ if (config != null) {
+ numericArray = config.getStringArray(
+ CarrierConfigManager.KEY_ROAMING_OPERATOR_STRING_ARRAY);
+ }
+ }
+ if (ArrayUtils.isEmpty(numericArray) || operatorNumeric == null) {
return false;
}
for (String numeric : numericArray) {
- if (operatorNumeric.startsWith(numeric)) {
+ if (!TextUtils.isEmpty(numeric) && operatorNumeric.startsWith(numeric)) {
return true;
}
}
@@ -3401,7 +3442,7 @@
public CellLocation getCellLocation(WorkSource workSource) {
if (((GsmCellLocation)mCellLoc).getLac() >= 0 &&
((GsmCellLocation)mCellLoc).getCid() >= 0) {
- if (DBG) log("getCellLocation(): X good mCellLoc=" + mCellLoc);
+ if (VDBG) log("getCellLocation(): X good mCellLoc=" + mCellLoc);
return mCellLoc;
} else {
List<CellInfo> result = getAllCellInfo(workSource);
@@ -3426,7 +3467,7 @@
cellLocOther.setLacAndCid(cellIdentityGsm.getLac(),
cellIdentityGsm.getCid());
cellLocOther.setPsc(cellIdentityGsm.getPsc());
- if (DBG) log("getCellLocation(): X ret GSM info=" + cellLocOther);
+ if (VDBG) log("getCellLocation(): X ret GSM info=" + cellLocOther);
return cellLocOther;
} else if (ci instanceof CellInfoWcdma) {
CellInfoWcdma cellInfoWcdma = (CellInfoWcdma)ci;
@@ -3434,7 +3475,7 @@
cellLocOther.setLacAndCid(cellIdentityWcdma.getLac(),
cellIdentityWcdma.getCid());
cellLocOther.setPsc(cellIdentityWcdma.getPsc());
- if (DBG) log("getCellLocation(): X ret WCDMA info=" + cellLocOther);
+ if (VDBG) log("getCellLocation(): X ret WCDMA info=" + cellLocOther);
return cellLocOther;
} else if ((ci instanceof CellInfoLte) &&
((cellLocOther.getLac() < 0) || (cellLocOther.getCid() < 0))) {
@@ -3446,18 +3487,18 @@
cellLocOther.setLacAndCid(cellIdentityLte.getTac(),
cellIdentityLte.getCi());
cellLocOther.setPsc(0);
- if (DBG) {
+ if (VDBG) {
log("getCellLocation(): possible LTE cellLocOther=" + cellLocOther);
}
}
}
}
- if (DBG) {
+ if (VDBG) {
log("getCellLocation(): X ret best answer cellLocOther=" + cellLocOther);
}
return cellLocOther;
} else {
- if (DBG) {
+ if (VDBG) {
log("getCellLocation(): X empty mCellLoc and CellInfo mCellLoc=" + mCellLoc);
}
return mCellLoc;
@@ -3770,6 +3811,12 @@
mTimeZoneLog.log(tmpLog);
if (mSavedTimeZone != null) {
setAndBroadcastNetworkSetTimeZone(mSavedTimeZone);
+ } else {
+ String iso = ((TelephonyManager) mPhone.getContext().getSystemService(
+ Context.TELEPHONY_SERVICE)).getNetworkCountryIsoForPhone(mPhone.getPhoneId());
+ if (!TextUtils.isEmpty(iso)) {
+ updateTimeZoneByNetworkCountryCode(iso);
+ }
}
}
@@ -3822,7 +3869,7 @@
}
notificationId = PS_NOTIFICATION;
title = context.getText(com.android.internal.R.string.RestrictedOnDataTitle);
- details = context.getText(com.android.internal.R.string.RestrictedOnDataContent);
+ details = context.getText(com.android.internal.R.string.RestrictedStateContent);
break;
case PS_DISABLED:
notificationId = PS_NOTIFICATION;
@@ -3830,16 +3877,16 @@
case CS_ENABLED:
title = context.getText(com.android.internal.R.string.RestrictedOnAllVoiceTitle);
details = context.getText(
- com.android.internal.R.string.RestrictedOnAllVoiceContent);
+ com.android.internal.R.string.RestrictedStateContent);
break;
case CS_NORMAL_ENABLED:
title = context.getText(com.android.internal.R.string.RestrictedOnNormalTitle);
- details = context.getText(com.android.internal.R.string.RestrictedOnNormalContent);
+ details = context.getText(com.android.internal.R.string.RestrictedStateContent);
break;
case CS_EMERGENCY_ENABLED:
title = context.getText(com.android.internal.R.string.RestrictedOnEmergencyTitle);
details = context.getText(
- com.android.internal.R.string.RestrictedOnEmergencyContent);
+ com.android.internal.R.string.RestrictedStateContent);
break;
case CS_DISABLED:
// do nothing and cancel the notification later
@@ -3875,6 +3922,7 @@
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
.setContentText(details)
+ .setChannel(NotificationChannelController.CHANNEL_ID_ALERT)
.build();
NotificationManager notificationManager = (NotificationManager)
@@ -4294,10 +4342,15 @@
*/
protected boolean onSignalStrengthResult(AsyncResult ar) {
boolean isGsm = false;
- //override isGsm for CDMA LTE
- if (mPhone.isPhoneTypeGsm() ||
- (mPhone.isPhoneTypeCdmaLte() &&
- ServiceState.isLte(mSS.getRilDataRadioTechnology()))) {
+ int dataRat = mSS.getRilDataRadioTechnology();
+ int voiceRat = mSS.getRilVoiceRadioTechnology();
+
+ // Override isGsm based on currently camped data and voice RATs
+ // Set isGsm to true if the RAT belongs to GSM family and not IWLAN
+ if ((dataRat != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+ && ServiceState.isGsm(dataRat))
+ || (voiceRat != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+ && ServiceState.isGsm(voiceRat))) {
isGsm = true;
}
@@ -4553,8 +4606,8 @@
pw.println(" mRestrictedState=" + mRestrictedState);
pw.println(" mPendingRadioPowerOffAfterDataOff=" + mPendingRadioPowerOffAfterDataOff);
pw.println(" mPendingRadioPowerOffAfterDataOffTag=" + mPendingRadioPowerOffAfterDataOffTag);
- pw.println(" mCellLoc=" + mCellLoc);
- pw.println(" mNewCellLoc=" + mNewCellLoc);
+ pw.println(" mCellLoc=" + Rlog.pii(VDBG, mCellLoc));
+ pw.println(" mNewCellLoc=" + Rlog.pii(VDBG, mNewCellLoc));
pw.println(" mLastCellInfoListTime=" + mLastCellInfoListTime);
dumpCellInfoList(pw);
pw.flush();
@@ -4637,7 +4690,6 @@
ipw.println(" Radio power Log:");
ipw.increaseIndent();
mRadioPowerLog.dump(fd, ipw, args);
- ipw.decreaseIndent();
ipw.println(" Time Logs:");
ipw.increaseIndent();
@@ -4913,11 +4965,43 @@
protected int getCombinedRegState() {
int regState = mSS.getVoiceRegState();
int dataRegState = mSS.getDataRegState();
- if ((regState == ServiceState.STATE_OUT_OF_SERVICE)
+ if ((regState == ServiceState.STATE_OUT_OF_SERVICE
+ || regState == ServiceState.STATE_POWER_OFF)
&& (dataRegState == ServiceState.STATE_IN_SERVICE)) {
log("getCombinedRegState: return STATE_IN_SERVICE as Data is in service");
regState = dataRegState;
}
return regState;
}
+
+ /**
+ * Update time zone by network country code, works on countries which only have one time zone.
+ * @param iso Country code from network MCC
+ */
+ private void updateTimeZoneByNetworkCountryCode(String iso) {
+ // Test both paths if ignore nitz is true
+ boolean testOneUniqueOffsetPath = SystemProperties.getBoolean(
+ TelephonyProperties.PROPERTY_IGNORE_NITZ, false)
+ && ((SystemClock.uptimeMillis() & 1) == 0);
+
+ List<String> uniqueZoneIds = TimeUtils.getTimeZoneIdsWithUniqueOffsets(iso);
+ if ((uniqueZoneIds.size() == 1) || testOneUniqueOffsetPath) {
+ String zoneId = uniqueZoneIds.get(0);
+ if (DBG) {
+ log("updateTimeZoneByNetworkCountryCode: no nitz but one TZ for iso-cc=" + iso
+ + " with zone.getID=" + zoneId
+ + " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath);
+ }
+ mTimeZoneLog.log("updateTimeZoneByNetworkCountryCode: set time zone=" + zoneId
+ + " iso=" + iso);
+ setAndBroadcastNetworkSetTimeZone(zoneId);
+ } else {
+ if (DBG) {
+ log("updateTimeZoneByNetworkCountryCode: there are " + uniqueZoneIds.size()
+ + " unique offsets for iso-cc='" + iso
+ + " testOneUniqueOffsetPath=" + testOneUniqueOffsetPath
+ + "', do nothing");
+ }
+ }
+ }
}
diff --git a/src/java/com/android/internal/telephony/SettingsObserver.java b/src/java/com/android/internal/telephony/SettingsObserver.java
new file mode 100644
index 0000000..2253c36
--- /dev/null
+++ b/src/java/com/android/internal/telephony/SettingsObserver.java
@@ -0,0 +1,78 @@
+/*
+ * 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.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.telephony.Rlog;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The class to describe settings observer
+ */
+public class SettingsObserver extends ContentObserver {
+ private final Map<Uri, Integer> mUriEventMap;
+ private final Context mContext;
+ private final Handler mHandler;
+ private static final String TAG = "SettingsObserver";
+
+ public SettingsObserver(Context context, Handler handler) {
+ super(null);
+ mUriEventMap = new HashMap<>();
+ mContext = context;
+ mHandler = handler;
+ }
+
+ /**
+ * Start observing a content.
+ * @param uri Content URI
+ * @param what The event to fire if the content changes
+ */
+ public void observe(Uri uri, int what) {
+ mUriEventMap.put(uri, what);
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.registerContentObserver(uri, false, this);
+ }
+
+ /**
+ * Stop observing a content.
+ */
+ public void unobserve() {
+ final ContentResolver resolver = mContext.getContentResolver();
+ resolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ Rlog.e(TAG, "Should never be reached.");
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ final Integer what = mUriEventMap.get(uri);
+ if (what != null) {
+ mHandler.obtainMessage(what.intValue()).sendToTarget();
+ } else {
+ Rlog.e(TAG, "No matching event to send for URI=" + uri);
+ }
+ }
+}
diff --git a/src/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java b/src/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
deleted file mode 100644
index 439eaea..0000000
--- a/src/java/com/android/internal/telephony/Sms7BitEncodingTranslator.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2014 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.Rlog;
-import android.os.Build;
-import android.util.SparseIntArray;
-import android.content.res.Resources;
-import android.content.res.XmlResourceParser;
-import android.telephony.SmsManager;
-import android.telephony.TelephonyManager;
-
-import com.android.internal.util.XmlUtils;
-import com.android.internal.telephony.cdma.sms.UserData;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-public class Sms7BitEncodingTranslator {
- private static final String TAG = "Sms7BitEncodingTranslator";
- private static final boolean DBG = Build.IS_DEBUGGABLE ;
- private static boolean mIs7BitTranslationTableLoaded = false;
- private static SparseIntArray mTranslationTable = null;
- private static SparseIntArray mTranslationTableCommon = null;
- private static SparseIntArray mTranslationTableGSM = null;
- private static SparseIntArray mTranslationTableCDMA = null;
-
- // Parser variables
- private static final String XML_START_TAG = "SmsEnforce7BitTranslationTable";
- private static final String XML_TRANSLATION_TYPE_TAG = "TranslationType";
- private static final String XML_CHARACTOR_TAG = "Character";
- private static final String XML_FROM_TAG = "from";
- private static final String XML_TO_TAG = "to";
-
- /**
- * Translates each message character that is not supported by GSM 7bit
- * alphabet into a supported one
- *
- * @param message
- * message to be translated
- * @param throwsException
- * if true and some error occurs during translation, an exception
- * is thrown; otherwise a null String is returned
- * @return translated message or null if some error occur
- */
- public static String translate(CharSequence message) {
- if (message == null) {
- Rlog.w(TAG, "Null message can not be translated");
- return null;
- }
-
- int size = message.length();
- if (size <= 0) {
- return "";
- }
-
- if (!mIs7BitTranslationTableLoaded) {
- mTranslationTableCommon = new SparseIntArray();
- mTranslationTableGSM = new SparseIntArray();
- mTranslationTableCDMA = new SparseIntArray();
- load7BitTranslationTableFromXml();
- mIs7BitTranslationTableLoaded = true;
- }
-
- if ((mTranslationTableCommon != null && mTranslationTableCommon.size() > 0) ||
- (mTranslationTableGSM != null && mTranslationTableGSM.size() > 0) ||
- (mTranslationTableCDMA != null && mTranslationTableCDMA.size() > 0)) {
- char[] output = new char[size];
- boolean isCdmaFormat = useCdmaFormatForMoSms();
- for (int i = 0; i < size; i++) {
- output[i] = translateIfNeeded(message.charAt(i), isCdmaFormat);
- }
-
- return String.valueOf(output);
- }
-
- return null;
- }
-
- /**
- * Translates a single character into its corresponding acceptable one, if
- * needed, based on GSM 7-bit alphabet
- *
- * @param c
- * character to be translated
- * @return original character, if it's present on GSM 7-bit alphabet; a
- * corresponding character, based on the translation table or white
- * space, if no mapping is found in the translation table for such
- * character
- */
- private static char translateIfNeeded(char c, boolean isCdmaFormat) {
- if (noTranslationNeeded(c, isCdmaFormat)) {
- if (DBG) {
- Rlog.v(TAG, "No translation needed for " + Integer.toHexString(c));
- }
- return c;
- }
-
- /*
- * Trying to translate unicode to Gsm 7-bit alphabet; If c is not
- * present on translation table, c does not belong to Unicode Latin-1
- * (Basic + Supplement), so we don't know how to translate it to a Gsm
- * 7-bit character! We replace c for an empty space and advises the user
- * about it.
- */
- int translation = -1;
-
- if (mTranslationTableCommon != null) {
- translation = mTranslationTableCommon.get(c, -1);
- }
-
- if (translation == -1) {
- if (isCdmaFormat) {
- if (mTranslationTableCDMA != null) {
- translation = mTranslationTableCDMA.get(c, -1);
- }
- } else {
- if (mTranslationTableGSM != null) {
- translation = mTranslationTableGSM.get(c, -1);
- }
- }
- }
-
- if (translation != -1) {
- if (DBG) {
- Rlog.v(TAG, Integer.toHexString(c) + " (" + c + ")" + " translated to "
- + Integer.toHexString(translation) + " (" + (char) translation + ")");
- }
- return (char) translation;
- } else {
- if (DBG) {
- Rlog.w(TAG, "No translation found for " + Integer.toHexString(c)
- + "! Replacing for empty space");
- }
- return ' ';
- }
- }
-
- private static boolean noTranslationNeeded(char c, boolean isCdmaFormat) {
- if (isCdmaFormat) {
- return GsmAlphabet.isGsmSeptets(c) && UserData.charToAscii.get(c, -1) != -1;
- }
- else {
- return GsmAlphabet.isGsmSeptets(c);
- }
- }
-
- private static boolean useCdmaFormatForMoSms() {
- if (!SmsManager.getDefault().isImsSmsSupported()) {
- // use Voice technology to determine SMS format.
- return TelephonyManager.getDefault().getCurrentPhoneType()
- == PhoneConstants.PHONE_TYPE_CDMA;
- }
- // IMS is registered with SMS support, check the SMS format supported
- return (SmsConstants.FORMAT_3GPP2.equals(SmsManager.getDefault().getImsSmsFormat()));
- }
-
- /**
- * Load the whole translation table file from the framework resource
- * encoded in XML.
- */
- private static void load7BitTranslationTableFromXml() {
- XmlResourceParser parser = null;
- Resources r = Resources.getSystem();
-
- if (parser == null) {
- if (DBG) Rlog.d(TAG, "load7BitTranslationTableFromXml: open normal file");
- parser = r.getXml(com.android.internal.R.xml.sms_7bit_translation_table);
- }
-
- try {
- XmlUtils.beginDocument(parser, XML_START_TAG);
- while (true) {
- XmlUtils.nextElement(parser);
- String tag = parser.getName();
- if (DBG) {
- Rlog.d(TAG, "tag: " + tag);
- }
- if (XML_TRANSLATION_TYPE_TAG.equals(tag)) {
- String type = parser.getAttributeValue(null, "Type");
- if (DBG) {
- Rlog.d(TAG, "type: " + type);
- }
- if (type.equals("common")) {
- mTranslationTable = mTranslationTableCommon;
- } else if (type.equals("gsm")) {
- mTranslationTable = mTranslationTableGSM;
- } else if (type.equals("cdma")) {
- mTranslationTable = mTranslationTableCDMA;
- } else {
- Rlog.e(TAG, "Error Parsing 7BitTranslationTable: found incorrect type" + type);
- }
- } else if (XML_CHARACTOR_TAG.equals(tag) && mTranslationTable != null) {
- int from = parser.getAttributeUnsignedIntValue(null,
- XML_FROM_TAG, -1);
- int to = parser.getAttributeUnsignedIntValue(null,
- XML_TO_TAG, -1);
- if ((from != -1) && (to != -1)) {
- if (DBG) {
- Rlog.d(TAG, "Loading mapping " + Integer.toHexString(from)
- .toUpperCase() + " -> " + Integer.toHexString(to)
- .toUpperCase());
- }
- mTranslationTable.put (from, to);
- } else {
- Rlog.d(TAG, "Invalid translation table file format");
- }
- } else {
- break;
- }
- }
- if (DBG) Rlog.d(TAG, "load7BitTranslationTableFromXml: parsing successful, file loaded");
- } catch (Exception e) {
- Rlog.e(TAG, "Got exception while loading 7BitTranslationTable file.", e);
- } finally {
- if (parser instanceof XmlResourceParser) {
- ((XmlResourceParser)parser).close();
- }
- }
- }
-}
diff --git a/src/java/com/android/internal/telephony/SmsAddress.java b/src/java/com/android/internal/telephony/SmsAddress.java
deleted file mode 100644
index b3892cb..0000000
--- a/src/java/com/android/internal/telephony/SmsAddress.java
+++ /dev/null
@@ -1,65 +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 com.android.internal.telephony;
-
-public abstract class SmsAddress {
- // From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118
- // and C.S0005-D table 2.7.1.3.2.4-2
- public static final int TON_UNKNOWN = 0;
- public static final int TON_INTERNATIONAL = 1;
- public static final int TON_NATIONAL = 2;
- public static final int TON_NETWORK = 3;
- public static final int TON_SUBSCRIBER = 4;
- public static final int TON_ALPHANUMERIC = 5;
- public static final int TON_ABBREVIATED = 6;
-
- public int ton;
- public String address;
- public byte[] origBytes;
-
- /**
- * Returns the address of the SMS message in String form or null if unavailable
- */
- public String getAddressString() {
- return address;
- }
-
- /**
- * Returns true if this is an alphanumeric address
- */
- public boolean isAlphanumeric() {
- return ton == TON_ALPHANUMERIC;
- }
-
- /**
- * Returns true if this is a network address
- */
- public boolean isNetworkSpecific() {
- return ton == TON_NETWORK;
- }
-
- public boolean couldBeEmailGateway() {
- // Some carriers seems to send email gateway messages in this form:
- // from: an UNKNOWN TON, 3 or 4 digits long, beginning with a 5
- // PID: 0x00, Data coding scheme 0x03
- // So we just attempt to treat any message from an address length <= 4
- // as an email gateway
-
- return address.length() <= 4;
- }
-
-}
diff --git a/src/java/com/android/internal/telephony/SmsApplication.java b/src/java/com/android/internal/telephony/SmsApplication.java
deleted file mode 100644
index 0d1f205..0000000
--- a/src/java/com/android/internal/telephony/SmsApplication.java
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- * Copyright (C) 2013 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.Manifest.permission;
-import android.app.AppOpsManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.res.Resources;
-import android.net.Uri;
-import android.os.Binder;
-import android.os.Debug;
-import android.os.Process;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Telephony;
-import android.provider.Telephony.Sms.Intents;
-import android.telephony.Rlog;
-import android.telephony.SmsManager;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import com.android.internal.content.PackageMonitor;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.MetricsProto.MetricsEvent;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * Class for managing the primary application that we will deliver SMS/MMS messages to
- *
- * {@hide}
- */
-public final class SmsApplication {
- static final String LOG_TAG = "SmsApplication";
- private static final String PHONE_PACKAGE_NAME = "com.android.phone";
- private static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth";
- private static final String MMS_SERVICE_PACKAGE_NAME = "com.android.mms.service";
- private static final String TELEPHONY_PROVIDER_PACKAGE_NAME = "com.android.providers.telephony";
-
- private static final String SCHEME_SMS = "sms";
- private static final String SCHEME_SMSTO = "smsto";
- private static final String SCHEME_MMS = "mms";
- private static final String SCHEME_MMSTO = "mmsto";
- private static final boolean DEBUG_MULTIUSER = false;
-
- private static SmsPackageMonitor sSmsPackageMonitor = null;
-
- public static class SmsApplicationData {
- /**
- * Name of this SMS app for display.
- */
- private String mApplicationName;
-
- /**
- * Package name for this SMS app.
- */
- public String mPackageName;
-
- /**
- * The class name of the SMS_DELIVER_ACTION receiver in this app.
- */
- private String mSmsReceiverClass;
-
- /**
- * The class name of the WAP_PUSH_DELIVER_ACTION receiver in this app.
- */
- private String mMmsReceiverClass;
-
- /**
- * The class name of the ACTION_RESPOND_VIA_MESSAGE intent in this app.
- */
- private String mRespondViaMessageClass;
-
- /**
- * The class name of the ACTION_SENDTO intent in this app.
- */
- private String mSendToClass;
-
- /**
- * The class name of the ACTION_DEFAULT_SMS_PACKAGE_CHANGED receiver in this app.
- */
- private String mSmsAppChangedReceiverClass;
-
- /**
- * The class name of the ACTION_EXTERNAL_PROVIDER_CHANGE receiver in this app.
- */
- private String mProviderChangedReceiverClass;
-
- /**
- * The class name of the SIM_FULL_ACTION receiver in this app.
- */
- private String mSimFullReceiverClass;
-
- /**
- * The user-id for this application
- */
- private int mUid;
-
- /**
- * Returns true if this SmsApplicationData is complete (all intents handled).
- * @return
- */
- public boolean isComplete() {
- return (mSmsReceiverClass != null && mMmsReceiverClass != null
- && mRespondViaMessageClass != null && mSendToClass != null);
- }
-
- public SmsApplicationData(String packageName, int uid) {
- mPackageName = packageName;
- mUid = uid;
- }
-
- public String getApplicationName(Context context) {
- if (mApplicationName == null) {
- PackageManager pm = context.getPackageManager();
- ApplicationInfo appInfo;
- try {
- appInfo = pm.getApplicationInfoAsUser(mPackageName, 0,
- UserHandle.getUserId(mUid));
- } catch (NameNotFoundException e) {
- return null;
- }
- if (appInfo != null) {
- CharSequence label = pm.getApplicationLabel(appInfo);
- mApplicationName = (label == null) ? null : label.toString();
- }
- }
- return mApplicationName;
- }
-
- @Override
- public String toString() {
- return " mPackageName: " + mPackageName
- + " mSmsReceiverClass: " + mSmsReceiverClass
- + " mMmsReceiverClass: " + mMmsReceiverClass
- + " mRespondViaMessageClass: " + mRespondViaMessageClass
- + " mSendToClass: " + mSendToClass
- + " mSmsAppChangedClass: " + mSmsAppChangedReceiverClass
- + " mProviderChangedReceiverClass: " + mProviderChangedReceiverClass
- + " mSimFullReceiverClass: " + mSimFullReceiverClass
- + " mUid: " + mUid;
- }
- }
-
- /**
- * Returns the userId of the Context object, if called from a system app,
- * otherwise it returns the caller's userId
- * @param context The context object passed in by the caller.
- * @return
- */
- private static int getIncomingUserId(Context context) {
- int contextUserId = context.getUserId();
- final int callingUid = Binder.getCallingUid();
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getIncomingUserHandle caller=" + callingUid + ", myuid="
- + android.os.Process.myUid() + "\n\t" + Debug.getCallers(4));
- }
- if (UserHandle.getAppId(callingUid)
- < android.os.Process.FIRST_APPLICATION_UID) {
- return contextUserId;
- } else {
- return UserHandle.getUserId(callingUid);
- }
- }
-
- /**
- * Returns the list of available SMS apps defined as apps that are registered for both the
- * SMS_RECEIVED_ACTION (SMS) and WAP_PUSH_RECEIVED_ACTION (MMS) broadcasts (and their broadcast
- * receivers are enabled)
- *
- * Requirements to be an SMS application:
- * Implement SMS_DELIVER_ACTION broadcast receiver.
- * Require BROADCAST_SMS permission.
- *
- * Implement WAP_PUSH_DELIVER_ACTION broadcast receiver.
- * Require BROADCAST_WAP_PUSH permission.
- *
- * Implement RESPOND_VIA_MESSAGE intent.
- * Support smsto Uri scheme.
- * Require SEND_RESPOND_VIA_MESSAGE permission.
- *
- * Implement ACTION_SENDTO intent.
- * Support smsto Uri scheme.
- */
- public static Collection<SmsApplicationData> getApplicationCollection(Context context) {
- int userId = getIncomingUserId(context);
- final long token = Binder.clearCallingIdentity();
- try {
- return getApplicationCollectionInternal(context, userId);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- private static Collection<SmsApplicationData> getApplicationCollectionInternal(
- Context context, int userId) {
- PackageManager packageManager = context.getPackageManager();
-
- // Get the list of apps registered for SMS
- Intent intent = new Intent(Intents.SMS_DELIVER_ACTION);
- List<ResolveInfo> smsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
- userId);
-
- HashMap<String, SmsApplicationData> receivers = new HashMap<String, SmsApplicationData>();
-
- // Add one entry to the map for every sms receiver (ignoring duplicate sms receivers)
- for (ResolveInfo resolveInfo : smsReceivers) {
- final ActivityInfo activityInfo = resolveInfo.activityInfo;
- if (activityInfo == null) {
- continue;
- }
- if (!permission.BROADCAST_SMS.equals(activityInfo.permission)) {
- continue;
- }
- final String packageName = activityInfo.packageName;
- if (!receivers.containsKey(packageName)) {
- final SmsApplicationData smsApplicationData = new SmsApplicationData(packageName,
- activityInfo.applicationInfo.uid);
- smsApplicationData.mSmsReceiverClass = activityInfo.name;
- receivers.put(packageName, smsApplicationData);
- }
- }
-
- // Update any existing entries with mms receiver class
- intent = new Intent(Intents.WAP_PUSH_DELIVER_ACTION);
- intent.setDataAndType(null, "application/vnd.wap.mms-message");
- List<ResolveInfo> mmsReceivers = packageManager.queryBroadcastReceiversAsUser(intent, 0,
- userId);
- for (ResolveInfo resolveInfo : mmsReceivers) {
- final ActivityInfo activityInfo = resolveInfo.activityInfo;
- if (activityInfo == null) {
- continue;
- }
- if (!permission.BROADCAST_WAP_PUSH.equals(activityInfo.permission)) {
- continue;
- }
- final String packageName = activityInfo.packageName;
- final SmsApplicationData smsApplicationData = receivers.get(packageName);
- if (smsApplicationData != null) {
- smsApplicationData.mMmsReceiverClass = activityInfo.name;
- }
- }
-
- // Update any existing entries with respond via message intent class.
- intent = new Intent(TelephonyManager.ACTION_RESPOND_VIA_MESSAGE,
- Uri.fromParts(SCHEME_SMSTO, "", null));
- List<ResolveInfo> respondServices = packageManager.queryIntentServicesAsUser(intent, 0,
- userId);
- for (ResolveInfo resolveInfo : respondServices) {
- final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
- if (serviceInfo == null) {
- continue;
- }
- if (!permission.SEND_RESPOND_VIA_MESSAGE.equals(serviceInfo.permission)) {
- continue;
- }
- final String packageName = serviceInfo.packageName;
- final SmsApplicationData smsApplicationData = receivers.get(packageName);
- if (smsApplicationData != null) {
- smsApplicationData.mRespondViaMessageClass = serviceInfo.name;
- }
- }
-
- // Update any existing entries with supports send to.
- intent = new Intent(Intent.ACTION_SENDTO,
- Uri.fromParts(SCHEME_SMSTO, "", null));
- List<ResolveInfo> sendToActivities = packageManager.queryIntentActivitiesAsUser(intent, 0,
- userId);
- for (ResolveInfo resolveInfo : sendToActivities) {
- final ActivityInfo activityInfo = resolveInfo.activityInfo;
- if (activityInfo == null) {
- continue;
- }
- final String packageName = activityInfo.packageName;
- final SmsApplicationData smsApplicationData = receivers.get(packageName);
- if (smsApplicationData != null) {
- smsApplicationData.mSendToClass = activityInfo.name;
- }
- }
-
- // Update any existing entries with the default sms changed handler.
- intent = new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
- List<ResolveInfo> smsAppChangedReceivers =
- packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getApplicationCollectionInternal smsAppChangedActivities=" +
- smsAppChangedReceivers);
- }
- for (ResolveInfo resolveInfo : smsAppChangedReceivers) {
- final ActivityInfo activityInfo = resolveInfo.activityInfo;
- if (activityInfo == null) {
- continue;
- }
- final String packageName = activityInfo.packageName;
- final SmsApplicationData smsApplicationData = receivers.get(packageName);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getApplicationCollectionInternal packageName=" +
- packageName + " smsApplicationData: " + smsApplicationData +
- " activityInfo.name: " + activityInfo.name);
- }
- if (smsApplicationData != null) {
- smsApplicationData.mSmsAppChangedReceiverClass = activityInfo.name;
- }
- }
-
- // Update any existing entries with the external provider changed handler.
- intent = new Intent(Telephony.Sms.Intents.ACTION_EXTERNAL_PROVIDER_CHANGE);
- List<ResolveInfo> providerChangedReceivers =
- packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getApplicationCollectionInternal providerChangedActivities=" +
- providerChangedReceivers);
- }
- for (ResolveInfo resolveInfo : providerChangedReceivers) {
- final ActivityInfo activityInfo = resolveInfo.activityInfo;
- if (activityInfo == null) {
- continue;
- }
- final String packageName = activityInfo.packageName;
- final SmsApplicationData smsApplicationData = receivers.get(packageName);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getApplicationCollectionInternal packageName=" +
- packageName + " smsApplicationData: " + smsApplicationData +
- " activityInfo.name: " + activityInfo.name);
- }
- if (smsApplicationData != null) {
- smsApplicationData.mProviderChangedReceiverClass = activityInfo.name;
- }
- }
-
- // Update any existing entries with the sim full handler.
- intent = new Intent(Intents.SIM_FULL_ACTION);
- List<ResolveInfo> simFullReceivers =
- packageManager.queryBroadcastReceiversAsUser(intent, 0, userId);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getApplicationCollectionInternal simFullReceivers="
- + simFullReceivers);
- }
- for (ResolveInfo resolveInfo : simFullReceivers) {
- final ActivityInfo activityInfo = resolveInfo.activityInfo;
- if (activityInfo == null) {
- continue;
- }
- final String packageName = activityInfo.packageName;
- final SmsApplicationData smsApplicationData = receivers.get(packageName);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getApplicationCollectionInternal packageName="
- + packageName + " smsApplicationData: " + smsApplicationData
- + " activityInfo.name: " + activityInfo.name);
- }
- if (smsApplicationData != null) {
- smsApplicationData.mSimFullReceiverClass = activityInfo.name;
- }
- }
-
- // Remove any entries for which we did not find all required intents.
- for (ResolveInfo resolveInfo : smsReceivers) {
- final ActivityInfo activityInfo = resolveInfo.activityInfo;
- if (activityInfo == null) {
- continue;
- }
- final String packageName = activityInfo.packageName;
- final SmsApplicationData smsApplicationData = receivers.get(packageName);
- if (smsApplicationData != null) {
- if (!smsApplicationData.isComplete()) {
- receivers.remove(packageName);
- }
- }
- }
- return receivers.values();
- }
-
- /**
- * Checks to see if we have a valid installed SMS application for the specified package name
- * @return Data for the specified package name or null if there isn't one
- */
- private static SmsApplicationData getApplicationForPackage(
- Collection<SmsApplicationData> applications, String packageName) {
- if (packageName == null) {
- return null;
- }
- // Is there an entry in the application list for the specified package?
- for (SmsApplicationData application : applications) {
- if (application.mPackageName.contentEquals(packageName)) {
- return application;
- }
- }
- return null;
- }
-
- /**
- * Get the application we will use for delivering SMS/MMS messages.
- *
- * We return the preferred sms application with the following order of preference:
- * (1) User selected SMS app (if selected, and if still valid)
- * (2) Android Messaging (if installed)
- * (3) The currently configured highest priority broadcast receiver
- * (4) Null
- */
- private static SmsApplicationData getApplication(Context context, boolean updateIfNeeded,
- int userId) {
- TelephonyManager tm = (TelephonyManager)
- context.getSystemService(Context.TELEPHONY_SERVICE);
- if (!tm.isSmsCapable()) {
- // No phone, no SMS
- return null;
- }
-
- Collection<SmsApplicationData> applications = getApplicationCollectionInternal(context,
- userId);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getApplication userId=" + userId);
- }
- // Determine which application receives the broadcast
- String defaultApplication = Settings.Secure.getStringForUser(context.getContentResolver(),
- Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getApplication defaultApp=" + defaultApplication);
- }
-
- SmsApplicationData applicationData = null;
- if (defaultApplication != null) {
- applicationData = getApplicationForPackage(applications, defaultApplication);
- }
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getApplication appData=" + applicationData);
- }
- // Picking a new SMS app requires AppOps and Settings.Secure permissions, so we only do
- // this if the caller asked us to.
- if (updateIfNeeded && applicationData == null) {
- // Try to find the default SMS package for this device
- Resources r = context.getResources();
- String defaultPackage =
- r.getString(com.android.internal.R.string.default_sms_application);
- applicationData = getApplicationForPackage(applications, defaultPackage);
-
- if (applicationData == null) {
- // Are there any applications?
- if (applications.size() != 0) {
- applicationData = (SmsApplicationData)applications.toArray()[0];
- }
- }
-
- // If we found a new default app, update the setting
- if (applicationData != null) {
- setDefaultApplicationInternal(applicationData.mPackageName, context, userId);
- }
- }
-
- // If we found a package, make sure AppOps permissions are set up correctly
- if (applicationData != null) {
- AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
-
- // We can only call checkOp if we are privileged (updateIfNeeded) or if the app we
- // are checking is for our current uid. Doing this check from the unprivileged current
- // SMS app allows us to tell the current SMS app that it is not in a good state and
- // needs to ask to be the current SMS app again to work properly.
- if (updateIfNeeded || applicationData.mUid == android.os.Process.myUid()) {
- // Verify that the SMS app has permissions
- int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
- applicationData.mPackageName);
- if (mode != AppOpsManager.MODE_ALLOWED) {
- Rlog.e(LOG_TAG, applicationData.mPackageName + " lost OP_WRITE_SMS: " +
- (updateIfNeeded ? " (fixing)" : " (no permission to fix)"));
- if (updateIfNeeded) {
- appOps.setMode(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
- applicationData.mPackageName, AppOpsManager.MODE_ALLOWED);
- } else {
- // We can not return a package if permissions are not set up correctly
- applicationData = null;
- }
- }
- }
-
- // We can only verify the phone and BT app's permissions from a privileged caller
- if (updateIfNeeded) {
- // Ensure this component is still configured as the preferred activity. Usually the
- // current SMS app will already be the preferred activity - but checking whether or
- // not this is true is just as expensive as reconfiguring the preferred activity so
- // we just reconfigure every time.
- PackageManager packageManager = context.getPackageManager();
- configurePreferredActivity(packageManager, new ComponentName(
- applicationData.mPackageName, applicationData.mSendToClass),
- userId);
- // Assign permission to special system apps
- assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
- PHONE_PACKAGE_NAME);
- assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
- BLUETOOTH_PACKAGE_NAME);
- assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
- MMS_SERVICE_PACKAGE_NAME);
- assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
- TELEPHONY_PROVIDER_PACKAGE_NAME);
- // Give WRITE_SMS AppOps permission to UID 1001 which contains multiple
- // apps, all of them should be able to write to telephony provider.
- // This is to allow the proxy package permission check in telephony provider
- // to pass.
- assignWriteSmsPermissionToSystemUid(appOps, Process.PHONE_UID);
- }
- }
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "getApplication returning appData=" + applicationData);
- }
- return applicationData;
- }
-
- /**
- * Sets the specified package as the default SMS/MMS application. The caller of this method
- * needs to have permission to set AppOps and write to secure settings.
- */
- public static void setDefaultApplication(String packageName, Context context) {
- TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
- if (!tm.isSmsCapable()) {
- // No phone, no SMS
- return;
- }
-
- final int userId = getIncomingUserId(context);
- final long token = Binder.clearCallingIdentity();
- try {
- setDefaultApplicationInternal(packageName, context, userId);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- private static void setDefaultApplicationInternal(String packageName, Context context,
- int userId) {
- // Get old package name
- String oldPackageName = Settings.Secure.getStringForUser(context.getContentResolver(),
- Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
-
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldPackageName +
- " new=" + packageName);
- }
-
- if (packageName != null && oldPackageName != null && packageName.equals(oldPackageName)) {
- // No change
- return;
- }
-
- // We only make the change if the new package is valid
- PackageManager packageManager = context.getPackageManager();
- Collection<SmsApplicationData> applications = getApplicationCollection(context);
- SmsApplicationData oldAppData = oldPackageName != null ?
- getApplicationForPackage(applications, oldPackageName) : null;
- SmsApplicationData applicationData = getApplicationForPackage(applications, packageName);
- if (applicationData != null) {
- // Ignore OP_WRITE_SMS for the previously configured default SMS app.
- AppOpsManager appOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
- if (oldPackageName != null) {
- try {
- PackageInfo info = packageManager.getPackageInfo(oldPackageName,
- PackageManager.GET_UNINSTALLED_PACKAGES);
- appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
- oldPackageName, AppOpsManager.MODE_IGNORED);
- } catch (NameNotFoundException e) {
- Rlog.w(LOG_TAG, "Old SMS package not found: " + oldPackageName);
- }
- }
-
- // Update the secure setting.
- Settings.Secure.putStringForUser(context.getContentResolver(),
- Settings.Secure.SMS_DEFAULT_APPLICATION, applicationData.mPackageName,
- userId);
-
- // Configure this as the preferred activity for SENDTO sms/mms intents
- configurePreferredActivity(packageManager, new ComponentName(
- applicationData.mPackageName, applicationData.mSendToClass), userId);
-
- // Allow OP_WRITE_SMS for the newly configured default SMS app.
- appOps.setMode(AppOpsManager.OP_WRITE_SMS, applicationData.mUid,
- applicationData.mPackageName, AppOpsManager.MODE_ALLOWED);
-
- // Assign permission to special system apps
- assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
- PHONE_PACKAGE_NAME);
- assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
- BLUETOOTH_PACKAGE_NAME);
- assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
- MMS_SERVICE_PACKAGE_NAME);
- assignWriteSmsPermissionToSystemApp(context, packageManager, appOps,
- TELEPHONY_PROVIDER_PACKAGE_NAME);
- // Give WRITE_SMS AppOps permission to UID 1001 which contains multiple
- // apps, all of them should be able to write to telephony provider.
- // This is to allow the proxy package permission check in telephony provider
- // to pass.
- assignWriteSmsPermissionToSystemUid(appOps, Process.PHONE_UID);
-
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "setDefaultApplicationInternal oldAppData=" + oldAppData);
- }
- if (oldAppData != null && oldAppData.mSmsAppChangedReceiverClass != null) {
- // Notify the old sms app that it's no longer the default
- final Intent oldAppIntent =
- new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
- final ComponentName component = new ComponentName(oldAppData.mPackageName,
- oldAppData.mSmsAppChangedReceiverClass);
- oldAppIntent.setComponent(component);
- oldAppIntent.putExtra(Telephony.Sms.Intents.EXTRA_IS_DEFAULT_SMS_APP, false);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "setDefaultApplicationInternal old=" + oldAppData.mPackageName);
- }
- context.sendBroadcast(oldAppIntent);
- }
- // Notify the new sms app that it's now the default (if the new sms app has a receiver
- // to handle the changed default sms intent).
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "setDefaultApplicationInternal new applicationData=" +
- applicationData);
- }
- if (applicationData.mSmsAppChangedReceiverClass != null) {
- final Intent intent =
- new Intent(Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED);
- final ComponentName component = new ComponentName(applicationData.mPackageName,
- applicationData.mSmsAppChangedReceiverClass);
- intent.setComponent(component);
- intent.putExtra(Telephony.Sms.Intents.EXTRA_IS_DEFAULT_SMS_APP, true);
- if (DEBUG_MULTIUSER) {
- Log.i(LOG_TAG, "setDefaultApplicationInternal new=" + packageName);
- }
- context.sendBroadcast(intent);
- }
- MetricsLogger.action(context, MetricsEvent.ACTION_DEFAULT_SMS_APP_CHANGED,
- applicationData.mPackageName);
- }
- }
-
- /**
- * Assign WRITE_SMS AppOps permission to some special system apps.
- *
- * @param context The context
- * @param packageManager The package manager instance
- * @param appOps The AppOps manager instance
- * @param packageName The package name of the system app
- */
- private static void assignWriteSmsPermissionToSystemApp(Context context,
- PackageManager packageManager, AppOpsManager appOps, String packageName) {
- // First check package signature matches the caller's package signature.
- // Since this class is only used internally by the system, this check makes sure
- // the package signature matches system signature.
- final int result = packageManager.checkSignatures(context.getPackageName(), packageName);
- if (result != PackageManager.SIGNATURE_MATCH) {
- Rlog.e(LOG_TAG, packageName + " does not have system signature");
- return;
- }
- try {
- PackageInfo info = packageManager.getPackageInfo(packageName, 0);
- int mode = appOps.checkOp(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
- packageName);
- if (mode != AppOpsManager.MODE_ALLOWED) {
- Rlog.w(LOG_TAG, packageName + " does not have OP_WRITE_SMS: (fixing)");
- appOps.setMode(AppOpsManager.OP_WRITE_SMS, info.applicationInfo.uid,
- packageName, AppOpsManager.MODE_ALLOWED);
- }
- } catch (NameNotFoundException e) {
- // No whitelisted system app on this device
- Rlog.e(LOG_TAG, "Package not found: " + packageName);
- }
-
- }
-
- private static void assignWriteSmsPermissionToSystemUid(AppOpsManager appOps, int uid) {
- appOps.setUidMode(AppOpsManager.OP_WRITE_SMS, uid, AppOpsManager.MODE_ALLOWED);
- }
-
- /**
- * Tracks package changes and ensures that the default SMS app is always configured to be the
- * preferred activity for SENDTO sms/mms intents.
- */
- private static final class SmsPackageMonitor extends PackageMonitor {
- final Context mContext;
-
- public SmsPackageMonitor(Context context) {
- super();
- mContext = context;
- }
-
- @Override
- public void onPackageDisappeared(String packageName, int reason) {
- onPackageChanged();
- }
-
- @Override
- public void onPackageAppeared(String packageName, int reason) {
- onPackageChanged();
- }
-
- @Override
- public void onPackageModified(String packageName) {
- onPackageChanged();
- }
-
- private void onPackageChanged() {
- PackageManager packageManager = mContext.getPackageManager();
- Context userContext = mContext;
- final int userId = getSendingUserId();
- if (userId != UserHandle.USER_SYSTEM) {
- try {
- userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
- new UserHandle(userId));
- } catch (NameNotFoundException nnfe) {
- if (DEBUG_MULTIUSER) {
- Log.w(LOG_TAG, "Unable to create package context for user " + userId);
- }
- }
- }
- // Ensure this component is still configured as the preferred activity
- ComponentName componentName = getDefaultSendToApplication(userContext, true);
- if (componentName != null) {
- configurePreferredActivity(packageManager, componentName, userId);
- }
- }
- }
-
- public static void initSmsPackageMonitor(Context context) {
- sSmsPackageMonitor = new SmsPackageMonitor(context);
- sSmsPackageMonitor.register(context, context.getMainLooper(), UserHandle.ALL, false);
- }
-
- private static void configurePreferredActivity(PackageManager packageManager,
- ComponentName componentName, int userId) {
- // Add the four activity preferences we want to direct to this app.
- replacePreferredActivity(packageManager, componentName, userId, SCHEME_SMS);
- replacePreferredActivity(packageManager, componentName, userId, SCHEME_SMSTO);
- replacePreferredActivity(packageManager, componentName, userId, SCHEME_MMS);
- replacePreferredActivity(packageManager, componentName, userId, SCHEME_MMSTO);
- }
-
- /**
- * Updates the ACTION_SENDTO activity to the specified component for the specified scheme.
- */
- private static void replacePreferredActivity(PackageManager packageManager,
- ComponentName componentName, int userId, String scheme) {
- // Build the set of existing activities that handle this scheme
- Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.fromParts(scheme, "", null));
- List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivitiesAsUser(
- intent, PackageManager.MATCH_DEFAULT_ONLY | PackageManager.GET_RESOLVED_FILTER,
- userId);
-
- // Build the set of ComponentNames for these activities
- final int n = resolveInfoList.size();
- ComponentName[] set = new ComponentName[n];
- for (int i = 0; i < n; i++) {
- ResolveInfo info = resolveInfoList.get(i);
- set[i] = new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
- }
-
- // Update the preferred SENDTO activity for the specified scheme
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_SENDTO);
- intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
- intentFilter.addDataScheme(scheme);
- packageManager.replacePreferredActivityAsUser(intentFilter,
- IntentFilter.MATCH_CATEGORY_SCHEME + IntentFilter.MATCH_ADJUSTMENT_NORMAL,
- set, componentName, userId);
- }
-
- /**
- * Returns SmsApplicationData for this package if this package is capable of being set as the
- * default SMS application.
- */
- public static SmsApplicationData getSmsApplicationData(String packageName, Context context) {
- Collection<SmsApplicationData> applications = getApplicationCollection(context);
- return getApplicationForPackage(applications, packageName);
- }
-
- /**
- * Gets the default SMS application
- * @param context context from the calling app
- * @param updateIfNeeded update the default app if there is no valid default app configured.
- * @return component name of the app and class to deliver SMS messages to
- */
- public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
- int userId = getIncomingUserId(context);
- final long token = Binder.clearCallingIdentity();
- try {
- ComponentName component = null;
- SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
- userId);
- if (smsApplicationData != null) {
- component = new ComponentName(smsApplicationData.mPackageName,
- smsApplicationData.mSmsReceiverClass);
- }
- return component;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Gets the default MMS application
- * @param context context from the calling app
- * @param updateIfNeeded update the default app if there is no valid default app configured.
- * @return component name of the app and class to deliver MMS messages to
- */
- public static ComponentName getDefaultMmsApplication(Context context, boolean updateIfNeeded) {
- int userId = getIncomingUserId(context);
- final long token = Binder.clearCallingIdentity();
- try {
- ComponentName component = null;
- SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
- userId);
- if (smsApplicationData != null) {
- component = new ComponentName(smsApplicationData.mPackageName,
- smsApplicationData.mMmsReceiverClass);
- }
- return component;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Gets the default Respond Via Message application
- * @param context context from the calling app
- * @param updateIfNeeded update the default app if there is no valid default app configured.
- * @return component name of the app and class to direct Respond Via Message intent to
- */
- public static ComponentName getDefaultRespondViaMessageApplication(Context context,
- boolean updateIfNeeded) {
- int userId = getIncomingUserId(context);
- final long token = Binder.clearCallingIdentity();
- try {
- ComponentName component = null;
- SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
- userId);
- if (smsApplicationData != null) {
- component = new ComponentName(smsApplicationData.mPackageName,
- smsApplicationData.mRespondViaMessageClass);
- }
- return component;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Gets the default Send To (smsto) application.
- * <p>
- * Caller must pass in the correct user context if calling from a singleton service.
- * @param context context from the calling app
- * @param updateIfNeeded update the default app if there is no valid default app configured.
- * @return component name of the app and class to direct SEND_TO (smsto) intent to
- */
- public static ComponentName getDefaultSendToApplication(Context context,
- boolean updateIfNeeded) {
- int userId = getIncomingUserId(context);
- final long token = Binder.clearCallingIdentity();
- try {
- ComponentName component = null;
- SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
- userId);
- if (smsApplicationData != null) {
- component = new ComponentName(smsApplicationData.mPackageName,
- smsApplicationData.mSendToClass);
- }
- return component;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Gets the default application that handles external changes to the SmsProvider and
- * MmsProvider.
- * @param context context from the calling app
- * @param updateIfNeeded update the default app if there is no valid default app configured.
- * @return component name of the app and class to deliver change intents to
- */
- public static ComponentName getDefaultExternalTelephonyProviderChangedApplication(
- Context context, boolean updateIfNeeded) {
- int userId = getIncomingUserId(context);
- final long token = Binder.clearCallingIdentity();
- try {
- ComponentName component = null;
- SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
- userId);
- if (smsApplicationData != null
- && smsApplicationData.mProviderChangedReceiverClass != null) {
- component = new ComponentName(smsApplicationData.mPackageName,
- smsApplicationData.mProviderChangedReceiverClass);
- }
- return component;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Gets the default application that handles sim full event.
- * @param context context from the calling app
- * @param updateIfNeeded update the default app if there is no valid default app configured.
- * @return component name of the app and class to deliver change intents to
- */
- public static ComponentName getDefaultSimFullApplication(
- Context context, boolean updateIfNeeded) {
- int userId = getIncomingUserId(context);
- final long token = Binder.clearCallingIdentity();
- try {
- ComponentName component = null;
- SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
- userId);
- if (smsApplicationData != null
- && smsApplicationData.mSimFullReceiverClass != null) {
- component = new ComponentName(smsApplicationData.mPackageName,
- smsApplicationData.mSimFullReceiverClass);
- }
- return component;
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Returns whether need to write the SMS message to SMS database for this package.
- * <p>
- * Caller must pass in the correct user context if calling from a singleton service.
- */
- public static boolean shouldWriteMessageForPackage(String packageName, Context context) {
- if (SmsManager.getDefault().getAutoPersisting()) {
- return true;
- }
- return !isDefaultSmsApplication(context, packageName);
- }
-
- /**
- * Check if a package is default sms app (or equivalent, like bluetooth)
- *
- * @param context context from the calling app
- * @param packageName the name of the package to be checked
- * @return true if the package is default sms app or bluetooth
- */
- public static boolean isDefaultSmsApplication(Context context, String packageName) {
- if (packageName == null) {
- return false;
- }
- final String defaultSmsPackage = getDefaultSmsApplicationPackageName(context);
- if ((defaultSmsPackage != null && defaultSmsPackage.equals(packageName))
- || BLUETOOTH_PACKAGE_NAME.equals(packageName)) {
- return true;
- }
- return false;
- }
-
- private static String getDefaultSmsApplicationPackageName(Context context) {
- final ComponentName component = getDefaultSmsApplication(context, false);
- if (component != null) {
- return component.getPackageName();
- }
- return null;
- }
-}
diff --git a/src/java/com/android/internal/telephony/SmsHeader.java b/src/java/com/android/internal/telephony/SmsHeader.java
deleted file mode 100644
index b519b70..0000000
--- a/src/java/com/android/internal/telephony/SmsHeader.java
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.util.HexDump;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-import java.util.ArrayList;
-
-/**
- * SMS user data header, as specified in TS 23.040 9.2.3.24.
- */
-public class SmsHeader {
-
- // TODO(cleanup): this data structure is generally referred to as
- // the 'user data header' or UDH, and so the class name should
- // change to reflect this...
-
- /** SMS user data header information element identifiers.
- * (see TS 23.040 9.2.3.24)
- */
- public static final int ELT_ID_CONCATENATED_8_BIT_REFERENCE = 0x00;
- public static final int ELT_ID_SPECIAL_SMS_MESSAGE_INDICATION = 0x01;
- public static final int ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT = 0x04;
- public static final int ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT = 0x05;
- public static final int ELT_ID_SMSC_CONTROL_PARAMS = 0x06;
- public static final int ELT_ID_UDH_SOURCE_INDICATION = 0x07;
- public static final int ELT_ID_CONCATENATED_16_BIT_REFERENCE = 0x08;
- public static final int ELT_ID_WIRELESS_CTRL_MSG_PROTOCOL = 0x09;
- public static final int ELT_ID_TEXT_FORMATTING = 0x0A;
- public static final int ELT_ID_PREDEFINED_SOUND = 0x0B;
- public static final int ELT_ID_USER_DEFINED_SOUND = 0x0C;
- public static final int ELT_ID_PREDEFINED_ANIMATION = 0x0D;
- public static final int ELT_ID_LARGE_ANIMATION = 0x0E;
- public static final int ELT_ID_SMALL_ANIMATION = 0x0F;
- public static final int ELT_ID_LARGE_PICTURE = 0x10;
- public static final int ELT_ID_SMALL_PICTURE = 0x11;
- public static final int ELT_ID_VARIABLE_PICTURE = 0x12;
- public static final int ELT_ID_USER_PROMPT_INDICATOR = 0x13;
- public static final int ELT_ID_EXTENDED_OBJECT = 0x14;
- public static final int ELT_ID_REUSED_EXTENDED_OBJECT = 0x15;
- public static final int ELT_ID_COMPRESSION_CONTROL = 0x16;
- public static final int ELT_ID_OBJECT_DISTR_INDICATOR = 0x17;
- public static final int ELT_ID_STANDARD_WVG_OBJECT = 0x18;
- public static final int ELT_ID_CHARACTER_SIZE_WVG_OBJECT = 0x19;
- public static final int ELT_ID_EXTENDED_OBJECT_DATA_REQUEST_CMD = 0x1A;
- public static final int ELT_ID_RFC_822_EMAIL_HEADER = 0x20;
- public static final int ELT_ID_HYPERLINK_FORMAT_ELEMENT = 0x21;
- public static final int ELT_ID_REPLY_ADDRESS_ELEMENT = 0x22;
- public static final int ELT_ID_ENHANCED_VOICE_MAIL_INFORMATION = 0x23;
- public static final int ELT_ID_NATIONAL_LANGUAGE_SINGLE_SHIFT = 0x24;
- public static final int ELT_ID_NATIONAL_LANGUAGE_LOCKING_SHIFT = 0x25;
-
- public static final int PORT_WAP_PUSH = 2948;
- public static final int PORT_WAP_WSP = 9200;
-
- public static class PortAddrs {
- public int destPort;
- public int origPort;
- public boolean areEightBits;
- }
-
- public static class ConcatRef {
- public int refNumber;
- public int seqNumber;
- public int msgCount;
- public boolean isEightBits;
- }
-
- public static class SpecialSmsMsg {
- public int msgIndType;
- public int msgCount;
- }
-
- /**
- * A header element that is not explicitly parsed, meaning not
- * PortAddrs or ConcatRef or SpecialSmsMsg.
- */
- public static class MiscElt {
- public int id;
- public byte[] data;
- }
-
- public PortAddrs portAddrs;
- public ConcatRef concatRef;
- public ArrayList<SpecialSmsMsg> specialSmsMsgList = new ArrayList<SpecialSmsMsg>();
- public ArrayList<MiscElt> miscEltList = new ArrayList<MiscElt>();
-
- /** 7 bit national language locking shift table, or 0 for GSM default 7 bit alphabet. */
- public int languageTable;
-
- /** 7 bit national language single shift table, or 0 for GSM default 7 bit extension table. */
- public int languageShiftTable;
-
- public SmsHeader() {}
-
- /**
- * Create structured SmsHeader object from serialized byte array representation.
- * (see TS 23.040 9.2.3.24)
- * @param data is user data header bytes
- * @return SmsHeader object
- */
- public static SmsHeader fromByteArray(byte[] data) {
- ByteArrayInputStream inStream = new ByteArrayInputStream(data);
- SmsHeader smsHeader = new SmsHeader();
- while (inStream.available() > 0) {
- /**
- * NOTE: as defined in the spec, ConcatRef and PortAddr
- * fields should not reoccur, but if they do the last
- * occurrence is to be used. Also, for ConcatRef
- * elements, if the count is zero, sequence is zero, or
- * sequence is larger than count, the entire element is to
- * be ignored.
- */
- int id = inStream.read();
- int length = inStream.read();
- ConcatRef concatRef;
- PortAddrs portAddrs;
- switch (id) {
- case ELT_ID_CONCATENATED_8_BIT_REFERENCE:
- concatRef = new ConcatRef();
- concatRef.refNumber = inStream.read();
- concatRef.msgCount = inStream.read();
- concatRef.seqNumber = inStream.read();
- concatRef.isEightBits = true;
- if (concatRef.msgCount != 0 && concatRef.seqNumber != 0 &&
- concatRef.seqNumber <= concatRef.msgCount) {
- smsHeader.concatRef = concatRef;
- }
- break;
- case ELT_ID_CONCATENATED_16_BIT_REFERENCE:
- concatRef = new ConcatRef();
- concatRef.refNumber = (inStream.read() << 8) | inStream.read();
- concatRef.msgCount = inStream.read();
- concatRef.seqNumber = inStream.read();
- concatRef.isEightBits = false;
- if (concatRef.msgCount != 0 && concatRef.seqNumber != 0 &&
- concatRef.seqNumber <= concatRef.msgCount) {
- smsHeader.concatRef = concatRef;
- }
- break;
- case ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT:
- portAddrs = new PortAddrs();
- portAddrs.destPort = inStream.read();
- portAddrs.origPort = inStream.read();
- portAddrs.areEightBits = true;
- smsHeader.portAddrs = portAddrs;
- break;
- case ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT:
- portAddrs = new PortAddrs();
- portAddrs.destPort = (inStream.read() << 8) | inStream.read();
- portAddrs.origPort = (inStream.read() << 8) | inStream.read();
- portAddrs.areEightBits = false;
- smsHeader.portAddrs = portAddrs;
- break;
- case ELT_ID_NATIONAL_LANGUAGE_SINGLE_SHIFT:
- smsHeader.languageShiftTable = inStream.read();
- break;
- case ELT_ID_NATIONAL_LANGUAGE_LOCKING_SHIFT:
- smsHeader.languageTable = inStream.read();
- break;
- case ELT_ID_SPECIAL_SMS_MESSAGE_INDICATION:
- SpecialSmsMsg specialSmsMsg = new SpecialSmsMsg();
- specialSmsMsg.msgIndType = inStream.read();
- specialSmsMsg.msgCount = inStream.read();
- smsHeader.specialSmsMsgList.add(specialSmsMsg);
- break;
- default:
- MiscElt miscElt = new MiscElt();
- miscElt.id = id;
- miscElt.data = new byte[length];
- inStream.read(miscElt.data, 0, length);
- smsHeader.miscEltList.add(miscElt);
- }
- }
- return smsHeader;
- }
-
- /**
- * Create serialized byte array representation from structured SmsHeader object.
- * (see TS 23.040 9.2.3.24)
- * @return Byte array representing the SmsHeader
- */
- public static byte[] toByteArray(SmsHeader smsHeader) {
- if ((smsHeader.portAddrs == null) &&
- (smsHeader.concatRef == null) &&
- (smsHeader.specialSmsMsgList.isEmpty()) &&
- (smsHeader.miscEltList.isEmpty()) &&
- (smsHeader.languageShiftTable == 0) &&
- (smsHeader.languageTable == 0)) {
- return null;
- }
-
- ByteArrayOutputStream outStream =
- new ByteArrayOutputStream(SmsConstants.MAX_USER_DATA_BYTES);
- ConcatRef concatRef = smsHeader.concatRef;
- if (concatRef != null) {
- if (concatRef.isEightBits) {
- outStream.write(ELT_ID_CONCATENATED_8_BIT_REFERENCE);
- outStream.write(3);
- outStream.write(concatRef.refNumber);
- } else {
- outStream.write(ELT_ID_CONCATENATED_16_BIT_REFERENCE);
- outStream.write(4);
- outStream.write(concatRef.refNumber >>> 8);
- outStream.write(concatRef.refNumber & 0x00FF);
- }
- outStream.write(concatRef.msgCount);
- outStream.write(concatRef.seqNumber);
- }
- PortAddrs portAddrs = smsHeader.portAddrs;
- if (portAddrs != null) {
- if (portAddrs.areEightBits) {
- outStream.write(ELT_ID_APPLICATION_PORT_ADDRESSING_8_BIT);
- outStream.write(2);
- outStream.write(portAddrs.destPort);
- outStream.write(portAddrs.origPort);
- } else {
- outStream.write(ELT_ID_APPLICATION_PORT_ADDRESSING_16_BIT);
- outStream.write(4);
- outStream.write(portAddrs.destPort >>> 8);
- outStream.write(portAddrs.destPort & 0x00FF);
- outStream.write(portAddrs.origPort >>> 8);
- outStream.write(portAddrs.origPort & 0x00FF);
- }
- }
- if (smsHeader.languageShiftTable != 0) {
- outStream.write(ELT_ID_NATIONAL_LANGUAGE_SINGLE_SHIFT);
- outStream.write(1);
- outStream.write(smsHeader.languageShiftTable);
- }
- if (smsHeader.languageTable != 0) {
- outStream.write(ELT_ID_NATIONAL_LANGUAGE_LOCKING_SHIFT);
- outStream.write(1);
- outStream.write(smsHeader.languageTable);
- }
- for (SpecialSmsMsg specialSmsMsg : smsHeader.specialSmsMsgList) {
- outStream.write(ELT_ID_SPECIAL_SMS_MESSAGE_INDICATION);
- outStream.write(2);
- outStream.write(specialSmsMsg.msgIndType & 0xFF);
- outStream.write(specialSmsMsg.msgCount & 0xFF);
- }
- for (MiscElt miscElt : smsHeader.miscEltList) {
- outStream.write(miscElt.id);
- outStream.write(miscElt.data.length);
- outStream.write(miscElt.data, 0, miscElt.data.length);
- }
- return outStream.toByteArray();
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("UserDataHeader ");
- builder.append("{ ConcatRef ");
- if (concatRef == null) {
- builder.append("unset");
- } else {
- builder.append("{ refNumber=" + concatRef.refNumber);
- builder.append(", msgCount=" + concatRef.msgCount);
- builder.append(", seqNumber=" + concatRef.seqNumber);
- builder.append(", isEightBits=" + concatRef.isEightBits);
- builder.append(" }");
- }
- builder.append(", PortAddrs ");
- if (portAddrs == null) {
- builder.append("unset");
- } else {
- builder.append("{ destPort=" + portAddrs.destPort);
- builder.append(", origPort=" + portAddrs.origPort);
- builder.append(", areEightBits=" + portAddrs.areEightBits);
- builder.append(" }");
- }
- if (languageShiftTable != 0) {
- builder.append(", languageShiftTable=" + languageShiftTable);
- }
- if (languageTable != 0) {
- builder.append(", languageTable=" + languageTable);
- }
- for (SpecialSmsMsg specialSmsMsg : specialSmsMsgList) {
- builder.append(", SpecialSmsMsg ");
- builder.append("{ msgIndType=" + specialSmsMsg.msgIndType);
- builder.append(", msgCount=" + specialSmsMsg.msgCount);
- builder.append(" }");
- }
- for (MiscElt miscElt : miscEltList) {
- builder.append(", MiscElt ");
- builder.append("{ id=" + miscElt.id);
- builder.append(", length=" + miscElt.data.length);
- builder.append(", data=" + HexDump.toHexString(miscElt.data));
- builder.append(" }");
- }
- builder.append(" }");
- return builder.toString();
- }
-
-}
diff --git a/src/java/com/android/internal/telephony/SmsMessageBase.java b/src/java/com/android/internal/telephony/SmsMessageBase.java
deleted file mode 100644
index e5821dc..0000000
--- a/src/java/com/android/internal/telephony/SmsMessageBase.java
+++ /dev/null
@@ -1,433 +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 com.android.internal.telephony;
-
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SmsHeader;
-import java.text.BreakIterator;
-import java.util.Arrays;
-
-import android.provider.Telephony;
-import android.telephony.SmsMessage;
-import android.text.Emoji;
-
-/**
- * Base class declaring the specific methods and members for SmsMessage.
- * {@hide}
- */
-public abstract class SmsMessageBase {
- /** {@hide} The address of the SMSC. May be null */
- protected String mScAddress;
-
- /** {@hide} The address of the sender */
- protected SmsAddress mOriginatingAddress;
-
- /** {@hide} The message body as a string. May be null if the message isn't text */
- protected String mMessageBody;
-
- /** {@hide} */
- protected String mPseudoSubject;
-
- /** {@hide} Non-null if this is an email gateway message */
- protected String mEmailFrom;
-
- /** {@hide} Non-null if this is an email gateway message */
- protected String mEmailBody;
-
- /** {@hide} */
- protected boolean mIsEmail;
-
- /** {@hide} Time when SC (service centre) received the message */
- protected long mScTimeMillis;
-
- /** {@hide} The raw PDU of the message */
- protected byte[] mPdu;
-
- /** {@hide} The raw bytes for the user data section of the message */
- protected byte[] mUserData;
-
- /** {@hide} */
- protected SmsHeader mUserDataHeader;
-
- // "Message Waiting Indication Group"
- // 23.038 Section 4
- /** {@hide} */
- protected boolean mIsMwi;
-
- /** {@hide} */
- protected boolean mMwiSense;
-
- /** {@hide} */
- protected boolean mMwiDontStore;
-
- /**
- * Indicates status for messages stored on the ICC.
- */
- protected int mStatusOnIcc = -1;
-
- /**
- * Record index of message in the EF.
- */
- protected int mIndexOnIcc = -1;
-
- /** TP-Message-Reference - Message Reference of sent message. @hide */
- public int mMessageRef;
-
- // TODO(): This class is duplicated in SmsMessage.java. Refactor accordingly.
- public static abstract class SubmitPduBase {
- public byte[] encodedScAddress; // Null if not applicable.
- public byte[] encodedMessage;
-
- @Override
- public String toString() {
- return "SubmitPdu: encodedScAddress = "
- + Arrays.toString(encodedScAddress)
- + ", encodedMessage = "
- + Arrays.toString(encodedMessage);
- }
- }
-
- /**
- * Returns the address of the SMS service center that relayed this message
- * or null if there is none.
- */
- public String getServiceCenterAddress() {
- return mScAddress;
- }
-
- /**
- * Returns the originating address (sender) of this SMS message in String
- * form or null if unavailable
- */
- public String getOriginatingAddress() {
- if (mOriginatingAddress == null) {
- return null;
- }
-
- return mOriginatingAddress.getAddressString();
- }
-
- /**
- * Returns the originating address, or email from address if this message
- * was from an email gateway. Returns null if originating address
- * unavailable.
- */
- public String getDisplayOriginatingAddress() {
- if (mIsEmail) {
- return mEmailFrom;
- } else {
- return getOriginatingAddress();
- }
- }
-
- /**
- * Returns the message body as a String, if it exists and is text based.
- * @return message body is there is one, otherwise null
- */
- public String getMessageBody() {
- return mMessageBody;
- }
-
- /**
- * Returns the class of this message.
- */
- public abstract SmsConstants.MessageClass getMessageClass();
-
- /**
- * Returns the message body, or email message body if this message was from
- * an email gateway. Returns null if message body unavailable.
- */
- public String getDisplayMessageBody() {
- if (mIsEmail) {
- return mEmailBody;
- } else {
- return getMessageBody();
- }
- }
-
- /**
- * Unofficial convention of a subject line enclosed in parens empty string
- * if not present
- */
- public String getPseudoSubject() {
- return mPseudoSubject == null ? "" : mPseudoSubject;
- }
-
- /**
- * Returns the service centre timestamp in currentTimeMillis() format
- */
- public long getTimestampMillis() {
- return mScTimeMillis;
- }
-
- /**
- * 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 mIsEmail;
- }
-
- /**
- * @return if isEmail() is true, body of the email sent through the gateway.
- * null otherwise
- */
- public String getEmailBody() {
- return mEmailBody;
- }
-
- /**
- * @return if isEmail() is true, email from address of email sent through
- * the gateway. null otherwise
- */
- public String getEmailFrom() {
- return mEmailFrom;
- }
-
- /**
- * Get protocol identifier.
- */
- public abstract int getProtocolIdentifier();
-
- /**
- * See TS 23.040 9.2.3.9 returns true if this is a "replace short message"
- * SMS
- */
- public abstract boolean isReplace();
-
- /**
- * Returns true for CPHS MWI toggle message.
- *
- * @return true if this is a CPHS MWI toggle message See CPHS 4.2 section
- * B.4.2
- */
- public abstract boolean isCphsMwiMessage();
-
- /**
- * returns true if this message is a CPHS voicemail / message waiting
- * indicator (MWI) clear message
- */
- public abstract boolean isMWIClearMessage();
-
- /**
- * returns true if this message is a CPHS voicemail / message waiting
- * indicator (MWI) set message
- */
- public abstract boolean isMWISetMessage();
-
- /**
- * returns true if this message is a "Message Waiting Indication Group:
- * Discard Message" notification and should not be stored.
- */
- public abstract boolean isMwiDontStore();
-
- /**
- * returns the user data section minus the user data header if one was
- * present.
- */
- public byte[] getUserData() {
- return mUserData;
- }
-
- /**
- * Returns an object representing the user data header
- *
- * {@hide}
- */
- public SmsHeader getUserDataHeader() {
- return mUserDataHeader;
- }
-
- /**
- * TODO(cleanup): The term PDU is used in a seemingly non-unique
- * manner -- for example, what is the difference between this byte
- * array and the contents of SubmitPdu objects. Maybe a more
- * illustrative term would be appropriate.
- */
-
- /**
- * Returns the raw PDU for the message.
- */
- public byte[] getPdu() {
- return mPdu;
- }
-
- /**
- * For an SMS-STATUS-REPORT message, this returns the status field from
- * the status report. This field indicates the status of a previously
- * submitted SMS, if requested. See TS 23.040, 9.2.3.15 TP-Status for a
- * description of values.
- *
- * @return 0 indicates the previously sent message was received.
- * See TS 23.040, 9.9.2.3.15 for a description of other possible
- * values.
- */
- public abstract int getStatus();
-
- /**
- * Return true iff the message is a SMS-STATUS-REPORT message.
- */
- public abstract boolean isStatusReportMessage();
-
- /**
- * Returns true iff the <code>TP-Reply-Path</code> bit is set in
- * this message.
- */
- public abstract boolean isReplyPathPresent();
-
- /**
- * Returns the status of the message on the ICC (read, unread, sent, unsent).
- *
- * @return the status of the message on the ICC. These are:
- * SmsManager.STATUS_ON_ICC_FREE
- * SmsManager.STATUS_ON_ICC_READ
- * SmsManager.STATUS_ON_ICC_UNREAD
- * SmsManager.STATUS_ON_ICC_SEND
- * SmsManager.STATUS_ON_ICC_UNSENT
- */
- public int getStatusOnIcc() {
- return mStatusOnIcc;
- }
-
- /**
- * 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 mIndexOnIcc;
- }
-
- protected void parseMessageBody() {
- // originatingAddress could be null if this message is from a status
- // report.
- if (mOriginatingAddress != null && mOriginatingAddress.couldBeEmailGateway()) {
- extractEmailAddressFromMessageBody();
- }
- }
-
- /**
- * Try to parse this message as an email gateway message
- * There are two ways specified in TS 23.040 Section 3.8 :
- * - SMS message "may have its TP-PID set for Internet electronic mail - MT
- * SMS format: [<from-address><space>]<message> - "Depending on the
- * nature of the gateway, the destination/origination address is either
- * derived from the content of the SMS TP-OA or TP-DA field, or the
- * TP-OA/TP-DA field contains a generic gateway address and the to/from
- * address is added at the beginning as shown above." (which is supported here)
- * - Multiple addresses separated by commas, no spaces, Subject field delimited
- * by '()' or '##' and '#' Section 9.2.3.24.11 (which are NOT supported here)
- */
- protected void extractEmailAddressFromMessageBody() {
-
- /* Some carriers may use " /" delimiter as below
- *
- * 1. [x@y][ ]/[subject][ ]/[body]
- * -or-
- * 2. [x@y][ ]/[body]
- */
- String[] parts = mMessageBody.split("( /)|( )", 2);
- if (parts.length < 2) return;
- mEmailFrom = parts[0];
- mEmailBody = parts[1];
- mIsEmail = Telephony.Mms.isEmailAddress(mEmailFrom);
- }
-
- /**
- * Find the next position to start a new fragment of a multipart SMS.
- *
- * @param currentPosition current start position of the fragment
- * @param byteLimit maximum number of bytes in the fragment
- * @param msgBody text of the SMS in UTF-16 encoding
- * @return the position to start the next fragment
- */
- public static int findNextUnicodePosition(
- int currentPosition, int byteLimit, CharSequence msgBody) {
- int nextPos = Math.min(currentPosition + byteLimit / 2, msgBody.length());
- // Check whether the fragment ends in a character boundary. Some characters take 4-bytes
- // in UTF-16 encoding. Many carriers cannot handle
- // a fragment correctly if it does not end at a character boundary.
- if (nextPos < msgBody.length()) {
- BreakIterator breakIterator = BreakIterator.getCharacterInstance();
- breakIterator.setText(msgBody.toString());
- if (!breakIterator.isBoundary(nextPos)) {
- int breakPos = breakIterator.preceding(nextPos);
- while (breakPos + 4 <= nextPos
- && Emoji.isRegionalIndicatorSymbol(
- Character.codePointAt(msgBody, breakPos))
- && Emoji.isRegionalIndicatorSymbol(
- Character.codePointAt(msgBody, breakPos + 2))) {
- // skip forward over flags (pairs of Regional Indicator Symbol)
- breakPos += 4;
- }
- if (breakPos > currentPosition) {
- nextPos = breakPos;
- } else if (Character.isHighSurrogate(msgBody.charAt(nextPos - 1))) {
- // no character boundary in this fragment, try to at least land on a code point
- nextPos -= 1;
- }
- }
- }
- return nextPos;
- }
-
- /**
- * Calculate the TextEncodingDetails of a message encoded in Unicode.
- */
- public static TextEncodingDetails calcUnicodeEncodingDetails(CharSequence msgBody) {
- TextEncodingDetails ted = new TextEncodingDetails();
- int octets = msgBody.length() * 2;
- ted.codeUnitSize = SmsConstants.ENCODING_16BIT;
- ted.codeUnitCount = msgBody.length();
- if (octets > SmsConstants.MAX_USER_DATA_BYTES) {
- // If EMS is not supported, break down EMS into single segment SMS
- // and add page info " x/y".
- // In the case of UCS2 encoding type, 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).
- int maxUserDataBytesWithHeader = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
- if (!SmsMessage.hasEmsSupport()) {
- // make sure total number of segments is less than 10
- if (octets <= 9 * (maxUserDataBytesWithHeader - 2)) {
- maxUserDataBytesWithHeader -= 2;
- }
- }
-
- int pos = 0; // Index in code units.
- int msgCount = 0;
- while (pos < msgBody.length()) {
- int nextPos = findNextUnicodePosition(pos, maxUserDataBytesWithHeader,
- msgBody);
- if (nextPos == msgBody.length()) {
- ted.codeUnitsRemaining = pos + maxUserDataBytesWithHeader / 2 -
- msgBody.length();
- }
- pos = nextPos;
- msgCount++;
- }
- ted.msgCount = msgCount;
- } else {
- ted.msgCount = 1;
- ted.codeUnitsRemaining = (SmsConstants.MAX_USER_DATA_BYTES - octets) / 2;
- }
-
- return ted;
- }
-}
diff --git a/src/java/com/android/internal/telephony/SmsNumberUtils.java b/src/java/com/android/internal/telephony/SmsNumberUtils.java
index b468e7c..bf548d6 100644
--- a/src/java/com/android/internal/telephony/SmsNumberUtils.java
+++ b/src/java/com/android/internal/telephony/SmsNumberUtils.java
@@ -16,21 +16,24 @@
package com.android.internal.telephony;
-import java.util.ArrayList;
-import java.util.HashMap;
-
import android.content.Context;
-import android.os.Build;
-import android.text.TextUtils;
import android.database.Cursor;
import android.database.SQLException;
+import android.os.Binder;
+import android.os.Build;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
-import android.telephony.TelephonyManager;
import android.telephony.Rlog;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import com.android.internal.telephony.HbpcdLookup.MccIdd;
import com.android.internal.telephony.HbpcdLookup.MccLookup;
+import java.util.ArrayList;
+import java.util.HashMap;
+
/**
* This class implements handle the MO SMS target address before sending.
@@ -528,10 +531,11 @@
* Filter the destination number if using VZW sim card.
*/
public static String filterDestAddr(Phone phone, String destAddr) {
- if (DBG) Rlog.d(TAG, "enter filterDestAddr. destAddr=\"" + destAddr + "\"" );
+ if (DBG) Rlog.d(TAG, "enter filterDestAddr. destAddr=\"" + Rlog.pii(TAG, destAddr) + "\"" );
if (destAddr == null || !PhoneNumberUtils.isGlobalPhoneNumber(destAddr)) {
- Rlog.w(TAG, "destAddr" + destAddr + " is not a global phone number! Nothing changed.");
+ Rlog.w(TAG, "destAddr" + Rlog.pii(TAG, destAddr) +
+ " is not a global phone number! Nothing changed.");
return destAddr;
}
@@ -551,7 +555,8 @@
if (DBG) {
Rlog.d(TAG, "destAddr is " + ((result != null)?"formatted.":"not formatted."));
- Rlog.d(TAG, "leave filterDestAddr, new destAddr=\"" + (result != null ? result : destAddr) + "\"" );
+ Rlog.d(TAG, "leave filterDestAddr, new destAddr=\"" + (result != null ? Rlog.pii(TAG,
+ result) : Rlog.pii(TAG, destAddr)) + "\"");
}
return result != null ? result : destAddr;
}
@@ -597,28 +602,24 @@
}
private static boolean needToConvert(Phone phone) {
- boolean bNeedToConvert = false;
- String[] listArray = phone.getContext().getResources()
- .getStringArray(com.android.internal.R.array
- .config_sms_convert_destination_number_support);
- if (listArray != null && listArray.length > 0) {
- for (int i=0; i<listArray.length; i++) {
- if (!TextUtils.isEmpty(listArray[i])) {
- String[] needToConvertArray = listArray[i].split(";");
- if (needToConvertArray != null && needToConvertArray.length > 0) {
- if (needToConvertArray.length == 1) {
- bNeedToConvert = "true".equalsIgnoreCase(needToConvertArray[0]);
- } else if (needToConvertArray.length == 2 &&
- !TextUtils.isEmpty(needToConvertArray[1]) &&
- compareGid1(phone, needToConvertArray[1])) {
- bNeedToConvert = "true".equalsIgnoreCase(needToConvertArray[0]);
- break;
- }
- }
+ // Calling package may not have READ_PHONE_STATE which is required for getConfig().
+ // Clear the calling identity so that it is called as self.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ CarrierConfigManager configManager = (CarrierConfigManager)
+ phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (configManager != null) {
+ PersistableBundle bundle = configManager.getConfig();
+ if (bundle != null) {
+ return bundle.getBoolean(CarrierConfigManager
+ .KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL);
}
}
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
- return bNeedToConvert;
+ // by default this value is false
+ return false;
}
private static boolean compareGid1(Phone phone, String serviceGid1) {
diff --git a/src/java/com/android/internal/telephony/SmsUsageMonitor.java b/src/java/com/android/internal/telephony/SmsUsageMonitor.java
index 73e9a42..402a5ef 100644
--- a/src/java/com/android/internal/telephony/SmsUsageMonitor.java
+++ b/src/java/com/android/internal/telephony/SmsUsageMonitor.java
@@ -29,8 +29,8 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.PhoneNumberUtils;
-import android.util.AtomicFile;
import android.telephony.Rlog;
+import android.util.AtomicFile;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
@@ -48,10 +48,10 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
/**
@@ -85,7 +85,7 @@
static final int CATEGORY_STANDARD_SHORT_CODE = 2;
/** Return value from {@link #checkDestination} for possible premium short codes. */
- static final int CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE = 3;
+ public static final int CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE = 3;
/** Return value from {@link #checkDestination} for premium short codes. */
static final int CATEGORY_PREMIUM_SHORT_CODE = 4;
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 93a3f8d..ff42b25 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -38,7 +38,7 @@
import android.text.TextUtils;
import android.text.format.Time;
import android.util.Log;
-import java.util.Objects;
+
import com.android.internal.telephony.IccCardConstants.State;
import java.io.FileDescriptor;
@@ -46,11 +46,13 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -595,8 +597,6 @@
*/
@Override
public int getActiveSubInfoCount(String callingPackage) {
- if (DBG) logd("[getActiveSubInfoCount]+");
-
if (!canReadPhoneState(callingPackage, "getActiveSubInfoCount")) {
return 0;
}
@@ -607,10 +607,10 @@
List<SubscriptionInfo> records = getActiveSubscriptionInfoList(
mContext.getOpPackageName());
if (records == null) {
- if (DBG) logd("[getActiveSubInfoCount] records null");
+ if (VDBG) logd("[getActiveSubInfoCount] records null");
return 0;
}
- if (DBG) logd("[getActiveSubInfoCount]- count: " + records.size());
+ if (VDBG) logd("[getActiveSubInfoCount]- count: " + records.size());
return records.size();
} finally {
Binder.restoreCallingIdentity(identity);
@@ -739,10 +739,11 @@
do {
int subId = cursor.getInt(cursor.getColumnIndexOrThrow(
SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID));
- // If sSlotIndexToSubId already has a valid subId for a slotIndex/phoneId,
- // do not add another subId for same slotIndex/phoneId.
+ // If sSlotIndexToSubId already has the same subId for a slotIndex/phoneId,
+ // do not add it.
Integer currentSubId = sSlotIndexToSubId.get(slotIndex);
if (currentSubId == null
+ || currentSubId != subId
|| !SubscriptionManager.isValidSubscriptionId(currentSubId)) {
// TODO While two subs active, if user deactivats first
// one, need to update the default subId with second one.
@@ -790,16 +791,15 @@
}
// Set Display name after sub id is set above so as to get valid simCarrierName
- int[] subIds = getSubId(slotIndex);
- if (subIds == null || subIds.length == 0) {
+ int subId = getSubIdUsingPhoneId(slotIndex);
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
if (DBG) {
- logdl("[addSubInfoRecord]- getSubId failed subIds == null || length == 0 subIds="
- + subIds);
+ logdl("[addSubInfoRecord]- getSubId failed invalid subId = " + subId);
}
return -1;
}
if (setDisplayName) {
- String simCarrierName = mTelephonyManager.getSimOperatorName(subIds[0]);
+ String simCarrierName = mTelephonyManager.getSimOperatorName(subId);
String nameToSet;
if (!TextUtils.isEmpty(simCarrierName)) {
@@ -812,7 +812,7 @@
value.put(SubscriptionManager.DISPLAY_NAME, nameToSet);
resolver.update(SubscriptionManager.CONTENT_URI, value,
SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID +
- "=" + Long.toString(subIds[0]), null);
+ "=" + Long.toString(subId), null);
if (DBG) logdl("[addSubInfoRecord] sim name = " + nameToSet);
}
@@ -839,11 +839,10 @@
public boolean setPlmnSpn(int slotIndex, boolean showPlmn, String plmn, boolean showSpn,
String spn) {
synchronized (mLock) {
- int[] subIds = getSubId(slotIndex);
+ int subId = getSubIdUsingPhoneId(slotIndex);
if (mContext.getPackageManager().resolveContentProvider(
SubscriptionManager.CONTENT_URI.getAuthority(), 0) == null ||
- subIds == null ||
- !SubscriptionManager.isValidSubscriptionId(subIds[0])) {
+ !SubscriptionManager.isValidSubscriptionId(subId)) {
// No place to store this info. Notify registrants of the change anyway as they
// might retrieve the SPN/PLMN text from the SST sticky broadcast.
// TODO: This can be removed once SubscriptionController is not running on devices
@@ -867,9 +866,7 @@
} else if (showSpn) {
carrierText = spn;
}
- for (int i = 0; i < subIds.length; i++) {
- setCarrierText(carrierText, subIds[i]);
- }
+ setCarrierText(carrierText, subId);
return true;
}
}
@@ -1347,11 +1344,11 @@
private void broadcastDefaultSmsSubIdChanged(int subId) {
// Broadcast an Intent for default sms sub change
if (DBG) logdl("[broadcastDefaultSmsSubIdChanged] subId=" + subId);
- Intent intent = new Intent(Intent.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED);
+ Intent intent = new Intent(SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
- intent.putExtra(Intent.EXTRA_SUBSCRIPTION_INDEX, subId);
+ intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -1381,7 +1378,8 @@
// Broadcast an Intent for default voice sub change
if (DBG) logdl("[broadcastDefaultVoiceSubIdChanged] subId=" + subId);
Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -1464,7 +1462,8 @@
// Broadcast an Intent for default data sub change
if (DBG) logdl("[broadcastDefaultDataSubIdChanged] subId=" + subId);
Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -1490,7 +1489,8 @@
// Broadcast an Intent for default sub change
Intent intent = new Intent(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId, subId);
if (DBG) {
logdl("[setDefaultFallbackSubId] broadcast default subId changed phoneId=" +
@@ -1566,15 +1566,10 @@
return subIds[0];
}
- public int[] getSubIdUsingSlotIndex(int slotIndex) {
- return getSubId(slotIndex);
- }
-
public List<SubscriptionInfo> getSubInfoUsingSlotIndexWithCheck(int slotIndex,
boolean needCheck,
String callingPackage) {
if (DBG) logd("[getSubInfoUsingSlotIndexWithCheck]+ slotIndex:" + slotIndex);
-
if (!canReadPhoneState(callingPackage, "getSubInfoUsingSlotIndexWithCheck")) {
return null;
}
@@ -1642,7 +1637,7 @@
*/
@Override
public int[] getActiveSubIdList() {
- Set<Entry<Integer, Integer>> simInfoSet = sSlotIndexToSubId.entrySet();
+ Set<Entry<Integer, Integer>> simInfoSet = new HashSet<>(sSlotIndexToSubId.entrySet());
int[] subIdArr = new int[simInfoSet.size()];
int i = 0;
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 74b65fe..ad217c2 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -16,10 +16,8 @@
package com.android.internal.telephony;
-import static android.Manifest.permission.READ_PHONE_STATE;
-
-import android.app.ActivityManagerNative;
-import android.app.IUserSwitchObserver;
+import android.app.ActivityManager;
+import android.app.UserSwitchObserver;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
@@ -34,8 +32,6 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.UserHandle;
-import android.os.UserManager;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
@@ -53,10 +49,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
-import java.util.Map;
/**
*@hide
@@ -107,8 +100,6 @@
private static int[] mInsertSimState = new int[PROJECT_SIM_NUM];
private SubscriptionManager mSubscriptionManager = null;
private IPackageManager mPackageManager;
- private UserManager mUserManager;
- private Map<Integer, Intent> rebroadcastIntentsOnUnlock = new HashMap<>();
// The current foreground user ID.
private int mCurrentlyActiveUserId;
@@ -121,11 +112,9 @@
mPhone = phone;
mSubscriptionManager = SubscriptionManager.from(mContext);
mPackageManager = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
IntentFilter intentFilter = new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
intentFilter.addAction(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
- intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiver(sReceiver, intentFilter);
mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext);
@@ -139,8 +128,7 @@
// -Whenever we switch to a new user
mCurrentlyActiveUserId = 0;
try {
- ActivityManagerNative.getDefault().registerUserSwitchObserver(
- new IUserSwitchObserver.Stub() {
+ ActivityManager.getService().registerUserSwitchObserver(new UserSwitchObserver() {
@Override
public void onUserSwitching(int newUserId, IRemoteCallback reply)
throws RemoteException {
@@ -156,18 +144,8 @@
}
}
}
-
- @Override
- public void onUserSwitchComplete(int newUserId) {
- // Ignore.
- }
-
- @Override
- public void onForegroundProfileSwitch(int newProfileId) throws RemoteException {
- // Ignore.
- }
}, LOG_TAG);
- mCurrentlyActiveUserId = ActivityManagerNative.getDefault().getCurrentUser().id;
+ mCurrentlyActiveUserId = ActivityManager.getService().getCurrentUser().id;
} catch (RemoteException e) {
logd("Couldn't get current user ID; guessing it's 0: " + e.getMessage());
}
@@ -183,22 +161,6 @@
String action = intent.getAction();
logd("Action: " + action);
- if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
- // broadcast pending intents
- Iterator iterator = rebroadcastIntentsOnUnlock.entrySet().iterator();
- while (iterator.hasNext()) {
- Map.Entry pair = (Map.Entry) iterator.next();
- Intent i = (Intent)pair.getValue();
- iterator.remove();
- logd("Broadcasting intent ACTION_SIM_STATE_CHANGED for mCardIndex: " +
- pair.getKey());
- ActivityManagerNative.broadcastStickyIntent(i, READ_PHONE_STATE,
- UserHandle.USER_ALL);
- }
- logd("[Receiver]-");
- return;
- }
-
if (!action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED) &&
!action.equals(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED)) {
return;
@@ -216,7 +178,6 @@
logd("simStatus: " + simStatus);
if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
- rebroadcastIntentsOnUnlock.put(slotIndex, intent);
if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(simStatus)) {
sendMessage(obtainMessage(EVENT_SIM_ABSENT, slotIndex, -1));
} else if (IccCardConstants.INTENT_VALUE_ICC_UNKNOWN.equals(simStatus)) {
@@ -390,111 +351,105 @@
}
private void handleSimLoaded(int slotId) {
- logd("handleSimStateLoadedInternal: slotId: " + slotId);
+ logd("handleSimLoaded: slotId: " + slotId);
// The SIM should be loaded at this state, but it is possible in cases such as SIM being
// removed or a refresh RESET that the IccRecords could be null. The right behavior is to
// not broadcast the SIM loaded.
IccRecords records = mPhone[slotId].getIccCard().getIccRecords();
if (records == null) { // Possibly a race condition.
- logd("onRecieve: IccRecords null");
+ logd("handleSimLoaded: IccRecords null");
return;
}
if (records.getIccId() == null) {
- logd("onRecieve: IccID null");
+ logd("handleSimLoaded: IccID null");
return;
}
mIccId[slotId] = records.getIccId();
if (isAllIccIdQueryDone()) {
updateSubscriptionInfoByIccId();
- }
+ int[] subIds = mSubscriptionManager.getActiveSubscriptionIdList();
+ for (int subId : subIds) {
+ TelephonyManager tm = TelephonyManager.getDefault();
- int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
- int[] subIds = SubscriptionController.getInstance().getSubId(slotId);
- if (subIds != null) { // Why an array?
- subId = subIds[0];
- }
+ String operator = tm.getSimOperatorNumeric(subId);
+ slotId = SubscriptionController.getInstance().getPhoneId(subId);
- if (SubscriptionManager.isValidSubscriptionId(subId)) {
- TelephonyManager tm = TelephonyManager.getDefault();
-
- String operator = tm.getSimOperatorNumericForPhone(slotId);
-
- if (!TextUtils.isEmpty(operator)) {
- if (subId == SubscriptionController.getInstance().getDefaultSubId()) {
- MccTable.updateMccMncConfiguration(mContext, operator, false);
- }
- SubscriptionController.getInstance().setMccMnc(operator, subId);
- } else {
- logd("EVENT_RECORDS_LOADED Operator name is null");
- }
-
- String msisdn = tm.getLine1Number(subId);
- ContentResolver contentResolver = mContext.getContentResolver();
-
- if (msisdn != null) {
- ContentValues number = new ContentValues(1);
- number.put(SubscriptionManager.NUMBER, msisdn);
- contentResolver.update(SubscriptionManager.CONTENT_URI, number,
- SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "="
- + Long.toString(subId), null);
- }
-
- SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
- String nameToSet;
- String simCarrierName = tm.getSimOperatorName(subId);
- ContentValues name = new ContentValues(1);
-
- if (subInfo != null && subInfo.getNameSource() !=
- SubscriptionManager.NAME_SOURCE_USER_INPUT) {
- if (!TextUtils.isEmpty(simCarrierName)) {
- nameToSet = simCarrierName;
+ if (!TextUtils.isEmpty(operator)) {
+ if (subId == SubscriptionController.getInstance().getDefaultSubId()) {
+ MccTable.updateMccMncConfiguration(mContext, operator, false);
+ }
+ SubscriptionController.getInstance().setMccMnc(operator, subId);
} else {
- nameToSet = "CARD " + Integer.toString(slotId + 1);
+ logd("EVENT_RECORDS_LOADED Operator name is null");
}
- name.put(SubscriptionManager.DISPLAY_NAME, nameToSet);
- logd("sim name = " + nameToSet);
- contentResolver.update(SubscriptionManager.CONTENT_URI, name,
- SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID
- + "=" + Long.toString(subId), null);
+
+ String msisdn = tm.getLine1Number(subId);
+ ContentResolver contentResolver = mContext.getContentResolver();
+
+ if (msisdn != null) {
+ ContentValues number = new ContentValues(1);
+ number.put(SubscriptionManager.NUMBER, msisdn);
+ contentResolver.update(SubscriptionManager.CONTENT_URI, number,
+ SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "="
+ + Long.toString(subId), null);
+ }
+
+ SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
+ String nameToSet;
+ String simCarrierName = tm.getSimOperatorName(subId);
+ ContentValues name = new ContentValues(1);
+
+ if (subInfo != null && subInfo.getNameSource() !=
+ SubscriptionManager.NAME_SOURCE_USER_INPUT) {
+ if (!TextUtils.isEmpty(simCarrierName)) {
+ nameToSet = simCarrierName;
+ } else {
+ nameToSet = "CARD " + Integer.toString(slotId + 1);
+ }
+ name.put(SubscriptionManager.DISPLAY_NAME, nameToSet);
+ logd("sim name = " + nameToSet);
+ contentResolver.update(SubscriptionManager.CONTENT_URI, name,
+ SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID
+ + "=" + Long.toString(subId), null);
+ }
+
+ /* Update preferred network type and network selection mode on SIM change.
+ * Storing last subId in SharedPreference for now to detect SIM change. */
+ SharedPreferences sp =
+ PreferenceManager.getDefaultSharedPreferences(mContext);
+ int storedSubId = sp.getInt(CURR_SUBID + slotId, -1);
+
+ if (storedSubId != subId) {
+ int networkType = RILConstants.PREFERRED_NETWORK_MODE;
+
+ // Set the modem network mode
+ mPhone[slotId].setPreferredNetworkType(networkType, null);
+ Settings.Global.putInt(mPhone[slotId].getContext().getContentResolver(),
+ Settings.Global.PREFERRED_NETWORK_MODE + subId,
+ networkType);
+
+ // Only support automatic selection mode on SIM change.
+ mPhone[slotId].getNetworkSelectionMode(
+ obtainMessage(EVENT_GET_NETWORK_SELECTION_MODE_DONE,
+ new Integer(slotId)));
+
+ // Update stored subId
+ SharedPreferences.Editor editor = sp.edit();
+ editor.putInt(CURR_SUBID + slotId, subId);
+ editor.apply();
+ }
+
+ // Update set of enabled carrier apps now that the privilege rules may have changed.
+ CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
+ mPackageManager, TelephonyManager.getDefault(),
+ mContext.getContentResolver(), mCurrentlyActiveUserId);
+
+ broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
+ updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
}
-
- /* Update preferred network type and network selection mode on SIM change.
- * Storing last subId in SharedPreference for now to detect SIM change. */
- SharedPreferences sp =
- PreferenceManager.getDefaultSharedPreferences(mContext);
- int storedSubId = sp.getInt(CURR_SUBID + slotId, -1);
-
- if (storedSubId != subId) {
- int networkType = RILConstants.PREFERRED_NETWORK_MODE;
-
- // Set the modem network mode
- mPhone[slotId].setPreferredNetworkType(networkType, null);
- Settings.Global.putInt(mPhone[slotId].getContext().getContentResolver(),
- Settings.Global.PREFERRED_NETWORK_MODE + subId,
- networkType);
-
- // Only support automatic selection mode on SIM change.
- mPhone[slotId].getNetworkSelectionMode(
- obtainMessage(EVENT_GET_NETWORK_SELECTION_MODE_DONE, new Integer(slotId)));
-
- // Update stored subId
- SharedPreferences.Editor editor = sp.edit();
- editor.putInt(CURR_SUBID + slotId, subId);
- editor.apply();
- }
- } else {
- logd("Invalid subId, could not update ContentResolver");
}
-
- // Update set of enabled carrier apps now that the privilege rules may have changed.
- CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
- mPackageManager, TelephonyManager.getDefault(), mContext.getContentResolver(),
- mCurrentlyActiveUserId);
-
- broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
- updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
}
private void updateCarrierServices(int slotId, String simState) {
@@ -533,8 +488,6 @@
synchronized private void updateSubscriptionInfoByIccId() {
logd("updateSubscriptionInfoByIccId:+ Start");
- mSubscriptionManager.clearSubscriptionInfo();
-
for (int i = 0; i < PROJECT_SIM_NUM; i++) {
mInsertSimState[i] = SIM_NOT_CHANGE;
}
@@ -548,6 +501,13 @@
}
logd("insertedSimCount = " + insertedSimCount);
+ // We only clear the slot-to-sub map when one/some SIM was removed. Note this is a
+ // workaround for some race conditions that the empty map was accessed while we are
+ // rebuilding the map.
+ if (SubscriptionController.getInstance().getActiveSubIdList().length > insertedSimCount) {
+ SubscriptionController.getInstance().clearSubInfo();
+ }
+
int index = 0;
for (int i = 0; i < PROJECT_SIM_NUM; i++) {
if (mInsertSimState[i] == SIM_NOT_INSERT) {
@@ -699,8 +659,7 @@
SubscriptionManager.putPhoneIdAndSubIdExtra(i, slotId);
logd("Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " + reason +
" for mCardIndex: " + slotId);
- ActivityManagerNative.broadcastStickyIntent(i, READ_PHONE_STATE, UserHandle.USER_ALL);
- rebroadcastIntentsOnUnlock.put(slotId, i);
+ IntentBroadcaster.getInstance().broadcastStickyIntent(i, slotId);
}
public void dispose() {
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 1ae1ee6..193d29e 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -133,6 +133,13 @@
return new ImsExternalCallTracker(imsPhone);
}
+ /**
+ * Create an AppSmsManager for per-app SMS message.
+ */
+ public AppSmsManager makeAppSmsManager(Context context) {
+ return new AppSmsManager(context);
+ }
+
public DeviceStateMonitor makeDeviceStateMonitor(Phone phone) {
return new DeviceStateMonitor(phone);
}
diff --git a/src/java/com/android/internal/telephony/TelephonyTester.java b/src/java/com/android/internal/telephony/TelephonyTester.java
index 3de356f..3608c20 100644
--- a/src/java/com/android/internal/telephony/TelephonyTester.java
+++ b/src/java/com/android/internal/telephony/TelephonyTester.java
@@ -20,11 +20,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Build;
-import android.preference.PreferenceManager;
import android.telephony.Rlog;
import android.telephony.ServiceState;
@@ -33,10 +31,10 @@
import com.android.ims.ImsConferenceState;
import com.android.ims.ImsExternalCallState;
import com.android.ims.ImsReasonInfo;
+import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
-import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
import com.android.internal.telephony.test.TestConferenceEventPackageParser;
import java.io.File;
@@ -83,6 +81,17 @@
private static final String ACTION_TEST_HANDOVER_FAIL =
"com.android.internal.telephony.TestHandoverFail";
+ /**
+ * Test-only intent used to trigger signalling of a
+ * {@link com.android.internal.telephony.gsm.SuppServiceNotification} to the {@link ImsPhone}.
+ * Use {@link #EXTRA_CODE} to specify the
+ * {@link com.android.internal.telephony.gsm.SuppServiceNotification#code}.
+ */
+ private static final String ACTION_TEST_SUPP_SRVC_NOTIFICATION =
+ "com.android.internal.telephony.TestSuppSrvcNotification";
+
+ private static final String EXTRA_CODE = "code";
+
private static List<ImsExternalCallState> mImsExternalCallStates = null;
private Phone mPhone;
@@ -111,6 +120,9 @@
} else if (action.equals(ACTION_TEST_HANDOVER_FAIL)) {
log("handle handover fail test intent");
handleHandoverFailedIntent();
+ } else if (action.equals(ACTION_TEST_SUPP_SRVC_NOTIFICATION)) {
+ log("handle supp service notification test intent");
+ sendTestSuppServiceNotification(intent);
} else {
if (DBG) log("onReceive: unknown action=" + action);
}
@@ -137,6 +149,7 @@
filter.addAction(ACTION_TEST_CONFERENCE_EVENT_PACKAGE);
filter.addAction(ACTION_TEST_DIALOG_EVENT_PACKAGE);
filter.addAction(ACTION_TEST_HANDOVER_FAIL);
+ filter.addAction(ACTION_TEST_SUPP_SRVC_NOTIFICATION);
mImsExternalCallStates = new ArrayList<ImsExternalCallState>();
}
@@ -251,4 +264,18 @@
mImsExternalCallStates.add(state);
}
}
+
+ private void sendTestSuppServiceNotification(Intent intent) {
+ if (intent.hasExtra(EXTRA_CODE)) {
+ int code = intent.getIntExtra(EXTRA_CODE, -1);
+ ImsPhone imsPhone = (ImsPhone) mPhone;
+ if (imsPhone == null) {
+ return;
+ }
+ log("Test supp service notification:" + code);
+ SuppServiceNotification suppServiceNotification = new SuppServiceNotification();
+ suppServiceNotification.code = code;
+ imsPhone.notifySuppSvcNotification(suppServiceNotification);
+ }
+ }
}
diff --git a/src/java/com/android/internal/telephony/UiccSmsController.java b/src/java/com/android/internal/telephony/UiccSmsController.java
index 6844dd3..e6cb972 100755
--- a/src/java/com/android/internal/telephony/UiccSmsController.java
+++ b/src/java/com/android/internal/telephony/UiccSmsController.java
@@ -42,16 +42,20 @@
public class UiccSmsController extends ISms.Stub {
static final String LOG_TAG = "RIL_UiccSmsController";
- protected Phone[] mPhone;
-
- protected UiccSmsController(Phone[] phone){
- mPhone = phone;
-
+ protected UiccSmsController() {
if (ServiceManager.getService("isms") == null) {
ServiceManager.addService("isms", this);
}
}
+ private Phone getPhone(int subId) {
+ Phone phone = PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
+ if (phone == null) {
+ phone = PhoneFactory.getDefaultPhone();
+ }
+ return phone;
+ }
+
@Override
public boolean
updateMessageOnIccEfForSubscriber(int subId, String callingPackage, int index, int status,
@@ -320,45 +324,26 @@
}
/**
- * get sms interface manager object based on subscription.
- **/
+ * Get sms interface manager object based on subscription.
+ * @return ICC SMS manager
+ */
private @Nullable IccSmsInterfaceManager getIccSmsInterfaceManager(int subId) {
- if (!isActiveSubId(subId)) {
- Rlog.e(LOG_TAG, "Subscription " + subId + " is inactive.");
- return null;
- }
-
- int phoneId = SubscriptionController.getInstance().getPhoneId(subId) ;
- //Fixme: for multi-subscription case
- if (!SubscriptionManager.isValidPhoneId(phoneId)
- || phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
- phoneId = 0;
- }
-
- try {
- return (IccSmsInterfaceManager)
- ((Phone)mPhone[(int)phoneId]).getIccSmsInterfaceManager();
- } catch (NullPointerException e) {
- Rlog.e(LOG_TAG, "Exception is :"+e.toString()+" For subscription :"+subId );
- e.printStackTrace();
- return null;
- } catch (ArrayIndexOutOfBoundsException e) {
- Rlog.e(LOG_TAG, "Exception is :"+e.toString()+" For subscription :"+subId );
- e.printStackTrace();
- return null;
- }
+ return getPhone(subId).getIccSmsInterfaceManager();
}
/**
- Gets User preferred SMS subscription */
+ * Get User preferred SMS subscription
+ * @return User preferred SMS subscription
+ */
@Override
public int getPreferredSmsSubscription() {
return SubscriptionController.getInstance().getDefaultSmsSubId();
}
/**
- * Get SMS prompt property, enabled or not
- **/
+ * Get SMS prompt property enabled or not
+ * @return True if SMS prompt is enabled.
+ */
@Override
public boolean isSMSPromptEnabled() {
return PhoneFactory.isSMSPromptEnabled();
@@ -392,11 +377,9 @@
}
}
- /*
- * @return true if the subId is active.
- */
- private boolean isActiveSubId(int subId) {
- return SubscriptionController.getInstance().isActiveSubId(subId);
+ @Override
+ public String createAppSpecificSmsToken(int subId, String callingPkg, PendingIntent intent) {
+ return getPhone(subId).getAppSmsManager().createAppSpecificSmsToken(callingPkg, intent);
}
private void sendErrorInPendingIntent(@Nullable PendingIntent intent, int errorCode) {
diff --git a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
index 2daf232..1294762 100644
--- a/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
+++ b/src/java/com/android/internal/telephony/VisualVoicemailSmsFilter.java
@@ -21,6 +21,7 @@
import android.content.Intent;
import android.provider.VoicemailContract;
import android.telecom.PhoneAccountHandle;
+import android.telephony.PhoneNumberUtils;
import android.telephony.SmsMessage;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -29,16 +30,37 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.VisualVoicemailSmsParser.WrappedMessageData;
+import java.nio.ByteBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
+/**
+ * Filters SMS to {@link android.telephony.VisualVoicemailService}, based on the config from {@link
+ * VisualVoicemailSmsFilterSettings}. The SMS is sent to telephony service which will do the actual
+ * dispatching.
+ */
public class VisualVoicemailSmsFilter {
+ /**
+ * Interface to convert subIds so the logic can be replaced in tests.
+ */
+ @VisibleForTesting
+ public interface PhoneAccountHandleConverter {
+
+ /**
+ * Convert the subId to a {@link PhoneAccountHandle}
+ */
+ PhoneAccountHandle fromSubId(int subId);
+ }
+
private static final String TAG = "VvmSmsFilter";
private static final String TELEPHONY_SERVICE_PACKAGE = "com.android.phone";
@@ -49,9 +71,37 @@
private static Map<String, List<Pattern>> sPatterns;
+ private static final PhoneAccountHandleConverter DEFAULT_PHONE_ACCOUNT_HANDLE_CONVERTER =
+ new PhoneAccountHandleConverter() {
+
+ @Override
+ public PhoneAccountHandle fromSubId(int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ return null;
+ }
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ if (phoneId == SubscriptionManager.INVALID_PHONE_INDEX) {
+ return null;
+ }
+ return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT,
+ PhoneFactory.getPhone(phoneId).getFullIccSerialNumber());
+ }
+ };
+
+ private static PhoneAccountHandleConverter sPhoneAccountHandleConverter =
+ DEFAULT_PHONE_ACCOUNT_HANDLE_CONVERTER;
+
+ /**
+ * Wrapper to combine multiple PDU into an SMS message
+ */
+ private static class FullMessage {
+ public SmsMessage firstMessage;
+ public String fullMessageBody;
+ }
+
/**
* Attempt to parse the incoming SMS as a visual voicemail SMS. If the parsing succeeded, A
- * {@link VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED} intent will be sent to telephony
+ * {@link VoicemailContract#ACTION_VOICEMAIL_SMS_RECEIVED} intent will be sent to telephony
* service, and the SMS will be dropped.
*
* <p>The accepted format for a visual voicemail SMS is a generalization of the OMTP format:
@@ -59,8 +109,8 @@
* <p>[clientPrefix]:[prefix]:([key]=[value];)*
*
* Additionally, if the SMS does not match the format, but matches the regex specified by the
- * carrier in {@link com.android.internal.R.array.config_vvmSmsFilterRegexes}, the SMS will
- * still be dropped and a {@link VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED} will be sent.
+ * carrier in {@link com.android.internal.R.array#config_vvmSmsFilterRegexes}, the SMS will
+ * still be dropped and a {@link VoicemailContract#ACTION_VOICEMAIL_SMS_RECEIVED} will be sent.
*
* @return true if the SMS has been parsed to be a visual voicemail SMS and should be dropped
*/
@@ -69,28 +119,29 @@
TelephonyManager telephonyManager =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- VisualVoicemailSmsFilterSettings settings =
- telephonyManager.getActiveVisualVoicemailSmsFilterSettings(subId);
+ VisualVoicemailSmsFilterSettings settings;
+ settings = telephonyManager.getActiveVisualVoicemailSmsFilterSettings(subId);
+
if (settings == null) {
return false;
}
- // TODO: filter base on originating number and destination port.
- PhoneAccountHandle phoneAccountHandle = phoneAccountHandleFromSubId(context, subId);
+ PhoneAccountHandle phoneAccountHandle = sPhoneAccountHandleConverter.fromSubId(subId);
+
if (phoneAccountHandle == null) {
Log.e(TAG, "Unable to convert subId " + subId + " to PhoneAccountHandle");
return false;
}
- String messageBody = getFullMessage(pdus, format);
+ FullMessage fullMessage = getFullMessage(pdus, format);
- if(messageBody == null){
- // Verizon WAP push SMS is not recognized by android, which has a ascii PDU.
+ if (fullMessage == null) {
+ // Carrier WAP push SMS is not recognized by android, which has a ascii PDU.
// Attempt to parse it.
Log.i(TAG, "Unparsable SMS received");
String asciiMessage = parseAsciiPduMessage(pdus);
WrappedMessageData messageData = VisualVoicemailSmsParser
- .parseAlternativeFormat(asciiMessage);
+ .parseAlternativeFormat(asciiMessage);
if (messageData != null) {
sendVvmSmsBroadcast(context, phoneAccountHandle, messageData, null);
}
@@ -98,10 +149,34 @@
// system decide. Usually because it is not parsable it will be dropped.
return false;
}
+
+ String messageBody = fullMessage.fullMessageBody;
String clientPrefix = settings.clientPrefix;
WrappedMessageData messageData = VisualVoicemailSmsParser
- .parse(clientPrefix, messageBody);
+ .parse(clientPrefix, messageBody);
if (messageData != null) {
+ if (settings.destinationPort
+ == VisualVoicemailSmsFilterSettings.DESTINATION_PORT_DATA_SMS) {
+ if (destPort == -1) {
+ // Non-data SMS is directed to the port "-1".
+ Log.i(TAG, "SMS matching VVM format received but is not a DATA SMS");
+ return false;
+ }
+ } else if (settings.destinationPort
+ != VisualVoicemailSmsFilterSettings.DESTINATION_PORT_ANY) {
+ if (settings.destinationPort != destPort) {
+ Log.i(TAG, "SMS matching VVM format received but is not directed to port "
+ + settings.destinationPort);
+ return false;
+ }
+ }
+
+ if (!settings.originatingNumbers.isEmpty()
+ && !isSmsFromNumbers(fullMessage.firstMessage, settings.originatingNumbers)) {
+ Log.i(TAG, "SMS matching VVM format received but is not from originating numbers");
+ return false;
+ }
+
sendVvmSmsBroadcast(context, phoneAccountHandle, messageData, null);
return true;
}
@@ -117,7 +192,7 @@
for (Pattern pattern : patterns) {
if (pattern.matcher(messageBody).matches()) {
Log.w(TAG, "Incoming SMS matches pattern " + pattern + " but has illegal format, "
- + "still dropping as VVM SMS");
+ + "still dropping as VVM SMS");
sendVvmSmsBroadcast(context, phoneAccountHandle, null, messageBody);
return true;
}
@@ -125,6 +200,19 @@
return false;
}
+ /**
+ * override how subId is converted to PhoneAccountHandle for tests
+ */
+ @VisibleForTesting
+ public static void setPhoneAccountHandleConverterForTest(
+ PhoneAccountHandleConverter converter) {
+ if (converter == null) {
+ sPhoneAccountHandleConverter = DEFAULT_PHONE_ACCOUNT_HANDLE_CONVERTER;
+ } else {
+ sPhoneAccountHandleConverter = converter;
+ }
+ }
+
private static void buildPatternsMap(Context context) {
if (sPatterns != null) {
return;
@@ -132,7 +220,7 @@
sPatterns = new ArrayMap<>();
// TODO(twyen): build from CarrierConfig once public API can be updated.
for (String entry : context.getResources()
- .getStringArray(com.android.internal.R.array.config_vvmSmsFilterRegexes)) {
+ .getStringArray(com.android.internal.R.array.config_vvmSmsFilterRegexes)) {
String[] mccMncList = entry.split(";")[0].split(",");
Pattern pattern = Pattern.compile(entry.split(";")[1]);
@@ -146,7 +234,7 @@
}
private static void sendVvmSmsBroadcast(Context context, PhoneAccountHandle phoneAccountHandle,
- @Nullable WrappedMessageData messageData, @Nullable String messageBody) {
+ @Nullable WrappedMessageData messageData, @Nullable String messageBody) {
Log.i(TAG, "VVM SMS received");
Intent intent = new Intent(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED);
VisualVoicemailSms.Builder builder = new VisualVoicemailSms.Builder();
@@ -167,21 +255,39 @@
* @return the message body of the SMS, or {@code null} if it can not be parsed.
*/
@Nullable
- private static String getFullMessage(byte[][] pdus, String format) {
+ private static FullMessage getFullMessage(byte[][] pdus, String format) {
+ FullMessage result = new FullMessage();
StringBuilder builder = new StringBuilder();
+ CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
for (byte pdu[] : pdus) {
SmsMessage message = SmsMessage.createFromPdu(pdu, format);
-
if (message == null) {
// The PDU is not recognized by android
return null;
}
+ if (result.firstMessage == null) {
+ result.firstMessage = message;
+ }
String body = message.getMessageBody();
+ if (body == null && message.getUserData() != null) {
+ // Attempt to interpret the user data as UTF-8. UTF-8 string over data SMS using
+ // 8BIT data coding scheme is our recommended way to send VVM SMS and is used in CTS
+ // Tests. The OMTP visual voicemail specification does not specify the SMS type and
+ // encoding.
+ ByteBuffer byteBuffer = ByteBuffer.wrap(message.getUserData());
+ try {
+ body = decoder.decode(byteBuffer).toString();
+ } catch (CharacterCodingException e) {
+ // User data is not decode-able as UTF-8. Ignoring.
+ return null;
+ }
+ }
if (body != null) {
builder.append(body);
}
}
- return builder.toString();
+ result.fullMessageBody = builder.toString();
+ return result;
}
private static String parseAsciiPduMessage(byte[][] pdus) {
@@ -192,16 +298,17 @@
return builder.toString();
}
- @Nullable
- private static PhoneAccountHandle phoneAccountHandleFromSubId(Context context, int subId) {
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- return null;
+ private static boolean isSmsFromNumbers(SmsMessage message, List<String> numbers) {
+ if (message == null) {
+ Log.e(TAG, "Unable to create SmsMessage from PDU, cannot determine originating number");
+ return false;
}
- int phoneId = SubscriptionManager.getPhoneId(subId);
- if (phoneId == SubscriptionManager.INVALID_PHONE_INDEX) {
- return null;
+
+ for (String number : numbers) {
+ if (PhoneNumberUtils.compare(number, message.getOriginatingAddress())) {
+ return true;
+ }
}
- return new PhoneAccountHandle(PSTN_CONNECTION_SERVICE_COMPONENT,
- PhoneFactory.getPhone(phoneId).getFullIccSerialNumber());
+ return false;
}
}
diff --git a/src/java/com/android/internal/telephony/cat/AppInterface.java b/src/java/com/android/internal/telephony/cat/AppInterface.java
index 6c4eacc..c78b7f8 100644
--- a/src/java/com/android/internal/telephony/cat/AppInterface.java
+++ b/src/java/com/android/internal/telephony/cat/AppInterface.java
@@ -30,11 +30,11 @@
* proactive command, session end, ALPHA during STK CC arrive.
*/
public static final String CAT_CMD_ACTION =
- "android.intent.action.stk.command";
+ "com.android.internal.stk.command";
public static final String CAT_SESSION_END_ACTION =
- "android.intent.action.stk.session_end";
+ "com.android.internal.stk.session_end";
public static final String CAT_ALPHA_NOTIFY_ACTION =
- "android.intent.action.stk.alpha_notify";
+ "com.android.internal.stk.alpha_notify";
//This is used to send ALPHA string from card to STK App.
public static final String ALPHA_STRING = "alpha_string";
@@ -45,7 +45,7 @@
public static final String CARD_STATUS = "card_status";
//Intent's actions are broadcasted by Telephony once IccRefresh occurs.
public static final String CAT_ICC_STATUS_CHANGE =
- "android.intent.action.stk.icc_status_change";
+ "com.android.internal.stk.icc_status_change";
// Permission required by STK command receiver
public static final String STK_PERMISSION = "android.permission.RECEIVE_STK_COMMANDS";
diff --git a/src/java/com/android/internal/telephony/cat/CatService.java b/src/java/com/android/internal/telephony/cat/CatService.java
index a242de4..6e4c899 100644
--- a/src/java/com/android/internal/telephony/cat/CatService.java
+++ b/src/java/com/android/internal/telephony/cat/CatService.java
@@ -881,8 +881,9 @@
// This sends an intent with CARD_ABSENT (0 - false) /CARD_PRESENT (1 - true).
intent.putExtra(AppInterface.CARD_STATUS, cardPresent);
intent.setComponent(AppInterface.getDefaultSTKApplication());
+ intent.putExtra("SLOT_ID", mSlotId);
CatLog.d(this, "Sending Card Status: "
- + cardState + " " + "cardPresent: " + cardPresent);
+ + cardState + " " + "cardPresent: " + cardPresent + "SLOT_ID: " + mSlotId);
mContext.sendBroadcast(intent, AppInterface.STK_PERMISSION);
}
diff --git a/src/java/com/android/internal/telephony/cdma/SmsMessage.java b/src/java/com/android/internal/telephony/cdma/SmsMessage.java
deleted file mode 100644
index 729062b..0000000
--- a/src/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ /dev/null
@@ -1,1058 +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 com.android.internal.telephony.cdma;
-
-import android.hardware.radio.V1_0.CdmaSmsMessage;
-import android.os.Parcel;
-import android.os.SystemProperties;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.SmsCbLocation;
-import android.telephony.SmsCbMessage;
-import android.telephony.TelephonyManager;
-import android.telephony.cdma.CdmaSmsCbProgramData;
-import android.telephony.Rlog;
-import android.util.Log;
-import android.text.TextUtils;
-import android.content.res.Resources;
-
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SmsHeader;
-import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.telephony.cdma.sms.BearerData;
-import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
-import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
-import com.android.internal.telephony.cdma.sms.SmsEnvelope;
-import com.android.internal.telephony.cdma.sms.UserData;
-import com.android.internal.telephony.uicc.IccUtils;
-import com.android.internal.util.BitwiseInputStream;
-import com.android.internal.util.HexDump;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
-
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-
-/**
- * TODO(cleanup): these constants are disturbing... are they not just
- * different interpretations on one number? And if we did not have
- * terrible class name overlap, they would not need to be directly
- * imported like this. The class in this file could just as well be
- * named CdmaSmsMessage, could it not?
- */
-
-/**
- * TODO(cleanup): internally returning null in many places makes
- * debugging very hard (among many other reasons) and should be made
- * more meaningful (replaced with exceptions for example). Null
- * returns should only occur at the very outside of the module/class
- * scope.
- */
-
-/**
- * A Short Message Service message.
- *
- */
-public class SmsMessage extends SmsMessageBase {
- static final String LOG_TAG = "SmsMessage";
- static private final String LOGGABLE_TAG = "CDMA:SMS";
- private static final boolean VDBG = false;
-
- private final static byte TELESERVICE_IDENTIFIER = 0x00;
- private final static byte SERVICE_CATEGORY = 0x01;
- private final static byte ORIGINATING_ADDRESS = 0x02;
- private final static byte ORIGINATING_SUB_ADDRESS = 0x03;
- private final static byte DESTINATION_ADDRESS = 0x04;
- private final static byte DESTINATION_SUB_ADDRESS = 0x05;
- private final static byte BEARER_REPLY_OPTION = 0x06;
- private final static byte CAUSE_CODES = 0x07;
- private final static byte BEARER_DATA = 0x08;
-
- /**
- * Status of a previously submitted SMS.
- * This field applies to SMS Delivery Acknowledge messages. 0 indicates success;
- * Here, the error class is defined by the bits from 9-8, the status code by the bits from 7-0.
- * See C.S0015-B, v2.0, 4.5.21 for a detailed description of possible values.
- */
- private int status;
-
- /** Specifies if a return of an acknowledgment is requested for send SMS */
- private static final int RETURN_NO_ACK = 0;
- private static final int RETURN_ACK = 1;
-
- private SmsEnvelope mEnvelope;
- private BearerData mBearerData;
-
- public static class SubmitPdu extends SubmitPduBase {
- }
-
- /**
- * Create an SmsMessage from a raw PDU.
- * Note: In CDMA the PDU is just a byte representation of the received Sms.
- */
- public static SmsMessage createFromPdu(byte[] pdu) {
- SmsMessage msg = new SmsMessage();
-
- try {
- msg.parsePdu(pdu);
- return msg;
- } catch (RuntimeException ex) {
- Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
- return null;
- } catch (OutOfMemoryError e) {
- Log.e(LOG_TAG, "SMS PDU parsing failed with out of memory: ", e);
- return null;
- }
- }
-
- /**
- * Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp.
- * Note: Only primitive fields are set.
- */
- public static SmsMessage newFromRil(CdmaSmsMessage cdmaSmsMessage) {
- // Note: Parcel.readByte actually reads one Int and masks to byte
- SmsMessage msg = new SmsMessage();
- SmsEnvelope env = new SmsEnvelope();
- CdmaSmsAddress addr = new CdmaSmsAddress();
- CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
- byte[] data;
- byte count;
- int countInt;
- int addressDigitMode;
-
- //currently not supported by the modem-lib: env.mMessageType
- env.teleService = cdmaSmsMessage.teleserviceId;
-
- if (cdmaSmsMessage.isServicePresent) {
- env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST;
- }
- else {
- if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) {
- // assume type ACK
- env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE;
- } else {
- env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
- }
- }
- env.serviceCategory = cdmaSmsMessage.serviceCategory;
-
- // address
- addressDigitMode = cdmaSmsMessage.address.digitMode;
- addr.digitMode = (byte) (0xFF & addressDigitMode);
- addr.numberMode = (byte) (0xFF & cdmaSmsMessage.address.numberMode);
- addr.ton = cdmaSmsMessage.address.numberType;
- addr.numberPlan = (byte) (0xFF & cdmaSmsMessage.address.numberPlan);
- count = (byte) cdmaSmsMessage.address.digits.size();
- addr.numberOfDigits = count;
- data = new byte[count];
- for (int index=0; index < count; index++) {
- data[index] = cdmaSmsMessage.address.digits.get(index);
-
- // convert the value if it is 4-bit DTMF to 8 bit
- if (addressDigitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
- data[index] = msg.convertDtmfToAscii(data[index]);
- }
- }
-
- addr.origBytes = data;
-
- subaddr.type = cdmaSmsMessage.subAddress.subaddressType;
- subaddr.odd = (byte) (cdmaSmsMessage.subAddress.odd ? 1 : 0);
- count = (byte) cdmaSmsMessage.subAddress.digits.size();
-
- if (count < 0) {
- count = 0;
- }
-
- // p_cur->sSubAddress.digits[digitCount] :
-
- data = new byte[count];
-
- for (int index = 0; index < count; ++index) {
- data[index] = cdmaSmsMessage.subAddress.digits.get(index);
- }
-
- subaddr.origBytes = data;
-
- /* currently not supported by the modem-lib:
- env.bearerReply
- env.replySeqNo
- env.errorClass
- env.causeCode
- */
-
- // bearer data
- countInt = cdmaSmsMessage.bearerData.size();
- if (countInt < 0) {
- countInt = 0;
- }
-
- data = new byte[countInt];
- for (int index=0; index < countInt; index++) {
- data[index] = cdmaSmsMessage.bearerData.get(index);
- }
- // BD gets further decoded when accessed in SMSDispatcher
- env.bearerData = data;
-
- // link the the filled objects to the SMS
- env.origAddress = addr;
- env.origSubaddress = subaddr;
- msg.mOriginatingAddress = addr;
- msg.mEnvelope = env;
-
- // create byte stream representation for transportation through the layers.
- msg.createPdu();
-
- return msg;
- }
-
- /**
- * Create an SmsMessage from an SMS EF record.
- *
- * @param index Index of SMS record. This should be index in ArrayList
- * returned by RuimSmsInterfaceManager.getAllMessagesFromIcc + 1.
- * @param data Record data.
- * @return An SmsMessage representing the record.
- *
- * @hide
- */
- public static SmsMessage createFromEfRecord(int index, byte[] data) {
- try {
- SmsMessage msg = new SmsMessage();
-
- msg.mIndexOnIcc = index;
-
- // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT,
- // or STORED_UNSENT
- // See 3GPP2 C.S0023 3.4.27
- if ((data[0] & 1) == 0) {
- Rlog.w(LOG_TAG, "SMS parsing failed: Trying to parse a free record");
- return null;
- } else {
- msg.mStatusOnIcc = data[0] & 0x07;
- }
-
- // Second byte is the MSG_LEN, length of the message
- // See 3GPP2 C.S0023 3.4.27
- int size = data[1];
-
- // Note: Data may include trailing FF's. That's OK; message
- // should still parse correctly.
- byte[] pdu = new byte[size];
- System.arraycopy(data, 2, pdu, 0, size);
- // the message has to be parsed before it can be displayed
- // see gsm.SmsMessage
- msg.parsePduFromEfRecord(pdu);
- return msg;
- } catch (RuntimeException ex) {
- Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
- return null;
- }
-
- }
-
- /**
- * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
- */
- public static int getTPLayerLengthForPDU(String pdu) {
- Rlog.w(LOG_TAG, "getTPLayerLengthForPDU: is not supported in CDMA mode.");
- return 0;
- }
-
- /**
- * TODO(cleanup): why do getSubmitPdu methods take an scAddr input
- * and do nothing with it? GSM allows us to specify a SC (eg,
- * when responding to an SMS that explicitly requests the response
- * is sent to a specific SC), or pass null to use the default
- * value. Is there no similar notion in CDMA? Or do we just not
- * have it hooked up?
- */
-
- /**
- * Get an SMS-SUBMIT PDU for a destination address and a message
- *
- * @param scAddr Service Centre address. Null means use default.
- * @param destAddr Address of the recipient.
- * @param message String representation of the message payload.
- * @param statusReportRequested Indicates whether a report is requested for this message.
- * @param smsHeader Array containing the data for the User Data Header, preceded
- * by the Element Identifiers.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- * @hide
- */
- public static SubmitPdu getSubmitPdu(String scAddr, String destAddr, String message,
- boolean statusReportRequested, SmsHeader smsHeader) {
-
- /**
- * TODO(cleanup): Do we really want silent failure like this?
- * Would it not be much more reasonable to make sure we don't
- * call this function if we really want nothing done?
- */
- if (message == null || destAddr == null) {
- return null;
- }
-
- UserData uData = new UserData();
- uData.payloadStr = message;
- uData.userDataHeader = smsHeader;
- return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
- }
-
- /**
- * Get an SMS-SUBMIT PDU for a data message to a destination address and port.
- *
- * @param scAddr Service Centre address. null == use default
- * @param destAddr the address of the destination for the message
- * @param destPort 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 scAddr, String destAddr, int destPort,
- byte[] data, boolean statusReportRequested) {
-
- /**
- * TODO(cleanup): this is not a general-purpose SMS creation
- * method, but rather something specialized to messages
- * containing OCTET encoded (meaning non-human-readable) user
- * data. The name should reflect that, and not just overload.
- */
-
- SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs();
- portAddrs.destPort = destPort;
- portAddrs.origPort = 0;
- portAddrs.areEightBits = false;
-
- SmsHeader smsHeader = new SmsHeader();
- smsHeader.portAddrs = portAddrs;
-
- UserData uData = new UserData();
- uData.userDataHeader = smsHeader;
- uData.msgEncoding = UserData.ENCODING_OCTET;
- uData.msgEncodingSet = true;
- uData.payload = data;
-
- return privateGetSubmitPdu(destAddr, statusReportRequested, uData);
- }
-
- /**
- * Get an SMS-SUBMIT PDU for a data message to a destination address & port
- *
- * @param destAddr the address of the destination for the message
- * @param userData the data for the message
- * @param statusReportRequested Indicates whether a report is requested for this message.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- */
- public static SubmitPdu getSubmitPdu(String destAddr, UserData userData,
- boolean statusReportRequested) {
- return privateGetSubmitPdu(destAddr, statusReportRequested, userData);
- }
-
- /**
- * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
- */
- @Override
- public int getProtocolIdentifier() {
- Rlog.w(LOG_TAG, "getProtocolIdentifier: is not supported in CDMA mode.");
- // (3GPP TS 23.040): "no interworking, but SME to SME protocol":
- return 0;
- }
-
- /**
- * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
- */
- @Override
- public boolean isReplace() {
- Rlog.w(LOG_TAG, "isReplace: is not supported in CDMA mode.");
- return false;
- }
-
- /**
- * {@inheritDoc}
- * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
- */
- @Override
- public boolean isCphsMwiMessage() {
- Rlog.w(LOG_TAG, "isCphsMwiMessage: is not supported in CDMA mode.");
- return false;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isMWIClearMessage() {
- return ((mBearerData != null) && (mBearerData.numberOfMessages == 0));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isMWISetMessage() {
- return ((mBearerData != null) && (mBearerData.numberOfMessages > 0));
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean isMwiDontStore() {
- return ((mBearerData != null) &&
- (mBearerData.numberOfMessages > 0) &&
- (mBearerData.userData == null));
- }
-
- /**
- * Returns the status for a previously submitted message.
- * For not interfering with status codes from GSM, this status code is
- * shifted to the bits 31-16.
- */
- @Override
- public int getStatus() {
- return (status << 16);
- }
-
- /** Return true iff the bearer data message type is DELIVERY_ACK. */
- @Override
- public boolean isStatusReportMessage() {
- return (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK);
- }
-
- /**
- * Note: This function is a GSM specific functionality which is not supported in CDMA mode.
- */
- @Override
- public boolean isReplyPathPresent() {
- Rlog.w(LOG_TAG, "isReplyPathPresent: is not supported in CDMA mode.");
- return false;
- }
-
- /**
- * Calculate the number of septets needed to encode the message.
- *
- * @param messageBody the message to encode
- * @param use7bitOnly ignore (but still count) illegal characters if true
- * @param isEntireMsg indicates if this is entire msg or a segment in multipart msg
- * @return TextEncodingDetails
- */
- public static TextEncodingDetails calculateLength(CharSequence messageBody,
- boolean use7bitOnly, boolean isEntireMsg) {
- CharSequence newMsgBody = null;
- Resources r = Resources.getSystem();
- if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
- newMsgBody = Sms7BitEncodingTranslator.translate(messageBody);
- }
- if (TextUtils.isEmpty(newMsgBody)) {
- newMsgBody = messageBody;
- }
- return BearerData.calcTextEncodingDetails(newMsgBody, use7bitOnly, isEntireMsg);
- }
-
- /**
- * Returns the teleservice type of the message.
- * @return the teleservice:
- * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_NOT_SET},
- * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WMT},
- * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WEMT},
- * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_VMN},
- * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#TELESERVICE_WAP}
- */
- public int getTeleService() {
- return mEnvelope.teleService;
- }
-
- /**
- * Returns the message type of the message.
- * @return the message type:
- * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_POINT_TO_POINT},
- * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_BROADCAST},
- * {@link com.android.internal.telephony.cdma.sms.SmsEnvelope#MESSAGE_TYPE_ACKNOWLEDGE},
- */
- public int getMessageType() {
- // NOTE: mEnvelope.messageType is not set correctly for cell broadcasts with some RILs.
- // Use the service category parameter to detect CMAS and other cell broadcast messages.
- if (mEnvelope.serviceCategory != 0) {
- return SmsEnvelope.MESSAGE_TYPE_BROADCAST;
- } else {
- return SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
- }
- }
-
- /**
- * Decodes pdu to an empty SMS object.
- * In the CDMA case the pdu is just an internal byte stream representation
- * of the SMS Java-object.
- * @see #createPdu()
- */
- private void parsePdu(byte[] pdu) {
- ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
- DataInputStream dis = new DataInputStream(bais);
- int length;
- int bearerDataLength;
- SmsEnvelope env = new SmsEnvelope();
- CdmaSmsAddress addr = new CdmaSmsAddress();
-
- try {
- env.messageType = dis.readInt();
- env.teleService = dis.readInt();
- env.serviceCategory = dis.readInt();
-
- addr.digitMode = dis.readByte();
- addr.numberMode = dis.readByte();
- addr.ton = dis.readByte();
- addr.numberPlan = dis.readByte();
-
- length = dis.readUnsignedByte();
- addr.numberOfDigits = length;
-
- // sanity check on the length
- if (length > pdu.length) {
- throw new RuntimeException(
- "createFromPdu: Invalid pdu, addr.numberOfDigits " + length
- + " > pdu len " + pdu.length);
- }
- addr.origBytes = new byte[length];
- dis.read(addr.origBytes, 0, length); // digits
-
- env.bearerReply = dis.readInt();
- // CauseCode values:
- env.replySeqNo = dis.readByte();
- env.errorClass = dis.readByte();
- env.causeCode = dis.readByte();
-
- //encoded BearerData:
- bearerDataLength = dis.readInt();
- // sanity check on the length
- if (bearerDataLength > pdu.length) {
- throw new RuntimeException(
- "createFromPdu: Invalid pdu, bearerDataLength " + bearerDataLength
- + " > pdu len " + pdu.length);
- }
- env.bearerData = new byte[bearerDataLength];
- dis.read(env.bearerData, 0, bearerDataLength);
- dis.close();
- } catch (IOException ex) {
- throw new RuntimeException(
- "createFromPdu: conversion from byte array to object failed: " + ex, ex);
- } catch (Exception ex) {
- Rlog.e(LOG_TAG, "createFromPdu: conversion from byte array to object failed: " + ex);
- }
-
- // link the filled objects to this SMS
- mOriginatingAddress = addr;
- env.origAddress = addr;
- mEnvelope = env;
- mPdu = pdu;
-
- parseSms();
- }
-
- /**
- * Decodes 3GPP2 sms stored in CSIM/RUIM cards As per 3GPP2 C.S0015-0
- */
- private void parsePduFromEfRecord(byte[] pdu) {
- ByteArrayInputStream bais = new ByteArrayInputStream(pdu);
- DataInputStream dis = new DataInputStream(bais);
- SmsEnvelope env = new SmsEnvelope();
- CdmaSmsAddress addr = new CdmaSmsAddress();
- CdmaSmsSubaddress subAddr = new CdmaSmsSubaddress();
-
- try {
- env.messageType = dis.readByte();
-
- while (dis.available() > 0) {
- int parameterId = dis.readByte();
- int parameterLen = dis.readUnsignedByte();
- byte[] parameterData = new byte[parameterLen];
-
- switch (parameterId) {
- case TELESERVICE_IDENTIFIER:
- /*
- * 16 bit parameter that identifies which upper layer
- * service access point is sending or should receive
- * this message
- */
- env.teleService = dis.readUnsignedShort();
- Rlog.i(LOG_TAG, "teleservice = " + env.teleService);
- break;
- case SERVICE_CATEGORY:
- /*
- * 16 bit parameter that identifies type of service as
- * in 3GPP2 C.S0015-0 Table 3.4.3.2-1
- */
- env.serviceCategory = dis.readUnsignedShort();
- break;
- case ORIGINATING_ADDRESS:
- case DESTINATION_ADDRESS:
- dis.read(parameterData, 0, parameterLen);
- BitwiseInputStream addrBis = new BitwiseInputStream(parameterData);
- addr.digitMode = addrBis.read(1);
- addr.numberMode = addrBis.read(1);
- int numberType = 0;
- if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
- numberType = addrBis.read(3);
- addr.ton = numberType;
-
- if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK)
- addr.numberPlan = addrBis.read(4);
- }
-
- addr.numberOfDigits = addrBis.read(8);
-
- byte[] data = new byte[addr.numberOfDigits];
- byte b = 0x00;
-
- if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
- /* As per 3GPP2 C.S0005-0 Table 2.7.1.3.2.4-4 */
- for (int index = 0; index < addr.numberOfDigits; index++) {
- b = (byte) (0xF & addrBis.read(4));
- // convert the value if it is 4-bit DTMF to 8
- // bit
- data[index] = convertDtmfToAscii(b);
- }
- } else if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
- if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_NOT_DATA_NETWORK) {
- for (int index = 0; index < addr.numberOfDigits; index++) {
- b = (byte) (0xFF & addrBis.read(8));
- data[index] = b;
- }
-
- } else if (addr.numberMode == CdmaSmsAddress.NUMBER_MODE_DATA_NETWORK) {
- if (numberType == 2)
- Rlog.e(LOG_TAG, "TODO: Originating Addr is email id");
- else
- Rlog.e(LOG_TAG,
- "TODO: Originating Addr is data network address");
- } else {
- Rlog.e(LOG_TAG, "Originating Addr is of incorrect type");
- }
- } else {
- Rlog.e(LOG_TAG, "Incorrect Digit mode");
- }
- addr.origBytes = data;
- Rlog.i(LOG_TAG, "Originating Addr=" + addr.toString());
- break;
- case ORIGINATING_SUB_ADDRESS:
- case DESTINATION_SUB_ADDRESS:
- dis.read(parameterData, 0, parameterLen);
- BitwiseInputStream subAddrBis = new BitwiseInputStream(parameterData);
- subAddr.type = subAddrBis.read(3);
- subAddr.odd = subAddrBis.readByteArray(1)[0];
- int subAddrLen = subAddrBis.read(8);
- byte[] subdata = new byte[subAddrLen];
- for (int index = 0; index < subAddrLen; index++) {
- b = (byte) (0xFF & subAddrBis.read(4));
- // convert the value if it is 4-bit DTMF to 8 bit
- subdata[index] = convertDtmfToAscii(b);
- }
- subAddr.origBytes = subdata;
- break;
- case BEARER_REPLY_OPTION:
- dis.read(parameterData, 0, parameterLen);
- BitwiseInputStream replyOptBis = new BitwiseInputStream(parameterData);
- env.bearerReply = replyOptBis.read(6);
- break;
- case CAUSE_CODES:
- dis.read(parameterData, 0, parameterLen);
- BitwiseInputStream ccBis = new BitwiseInputStream(parameterData);
- env.replySeqNo = ccBis.readByteArray(6)[0];
- env.errorClass = ccBis.readByteArray(2)[0];
- if (env.errorClass != 0x00)
- env.causeCode = ccBis.readByteArray(8)[0];
- break;
- case BEARER_DATA:
- dis.read(parameterData, 0, parameterLen);
- env.bearerData = parameterData;
- break;
- default:
- throw new Exception("unsupported parameterId (" + parameterId + ")");
- }
- }
- bais.close();
- dis.close();
- } catch (Exception ex) {
- Rlog.e(LOG_TAG, "parsePduFromEfRecord: conversion from pdu to SmsMessage failed" + ex);
- }
-
- // link the filled objects to this SMS
- mOriginatingAddress = addr;
- env.origAddress = addr;
- env.origSubaddress = subAddr;
- mEnvelope = env;
- mPdu = pdu;
-
- parseSms();
- }
-
- /**
- * Parses a SMS message from its BearerData stream. (mobile-terminated only)
- */
- public void parseSms() {
- // Message Waiting Info Record defined in 3GPP2 C.S-0005, 3.7.5.6
- // It contains only an 8-bit number with the number of messages waiting
- if (mEnvelope.teleService == SmsEnvelope.TELESERVICE_MWI) {
- mBearerData = new BearerData();
- if (mEnvelope.bearerData != null) {
- mBearerData.numberOfMessages = 0x000000FF & mEnvelope.bearerData[0];
- }
- if (VDBG) {
- Rlog.d(LOG_TAG, "parseSms: get MWI " +
- Integer.toString(mBearerData.numberOfMessages));
- }
- return;
- }
- mBearerData = BearerData.decode(mEnvelope.bearerData);
- if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
- Rlog.d(LOG_TAG, "MT raw BearerData = '" +
- HexDump.toHexString(mEnvelope.bearerData) + "'");
- Rlog.d(LOG_TAG, "MT (decoded) BearerData = " + mBearerData);
- }
- mMessageRef = mBearerData.messageId;
- if (mBearerData.userData != null) {
- mUserData = mBearerData.userData.payload;
- mUserDataHeader = mBearerData.userData.userDataHeader;
- mMessageBody = mBearerData.userData.payloadStr;
- }
-
- if (mOriginatingAddress != null) {
- mOriginatingAddress.address = new String(mOriginatingAddress.origBytes);
- if (mOriginatingAddress.ton == CdmaSmsAddress.TON_INTERNATIONAL_OR_IP) {
- if (mOriginatingAddress.address.charAt(0) != '+') {
- mOriginatingAddress.address = "+" + mOriginatingAddress.address;
- }
- }
- if (VDBG) Rlog.v(LOG_TAG, "SMS originating address: "
- + mOriginatingAddress.address);
- }
-
- if (mBearerData.msgCenterTimeStamp != null) {
- mScTimeMillis = mBearerData.msgCenterTimeStamp.toMillis(true);
- }
-
- if (VDBG) Rlog.d(LOG_TAG, "SMS SC timestamp: " + mScTimeMillis);
-
- // Message Type (See 3GPP2 C.S0015-B, v2, 4.5.1)
- if (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK) {
- // The BearerData MsgStatus subparameter should only be
- // included for DELIVERY_ACK messages. If it occurred for
- // other messages, it would be unclear what the status
- // being reported refers to. The MsgStatus subparameter
- // is primarily useful to indicate error conditions -- a
- // message without this subparameter is assumed to
- // indicate successful delivery (status == 0).
- if (! mBearerData.messageStatusSet) {
- Rlog.d(LOG_TAG, "DELIVERY_ACK message without msgStatus (" +
- (mUserData == null ? "also missing" : "does have") +
- " userData).");
- status = 0;
- } else {
- status = mBearerData.errorClass << 8;
- status |= mBearerData.messageStatus;
- }
- } else if (mBearerData.messageType != BearerData.MESSAGE_TYPE_DELIVER) {
- throw new RuntimeException("Unsupported message type: " + mBearerData.messageType);
- }
-
- if (mMessageBody != null) {
- if (VDBG) Rlog.v(LOG_TAG, "SMS message body: '" + mMessageBody + "'");
- parseMessageBody();
- } else if ((mUserData != null) && VDBG) {
- Rlog.v(LOG_TAG, "SMS payload: '" + IccUtils.bytesToHexString(mUserData) + "'");
- }
- }
-
- /**
- * Parses a broadcast SMS, possibly containing a CMAS alert.
- */
- public SmsCbMessage parseBroadcastSms() {
- BearerData bData = BearerData.decode(mEnvelope.bearerData, mEnvelope.serviceCategory);
- if (bData == null) {
- Rlog.w(LOG_TAG, "BearerData.decode() returned null");
- return null;
- }
-
- if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
- Rlog.d(LOG_TAG, "MT raw BearerData = " + HexDump.toHexString(mEnvelope.bearerData));
- }
-
- String plmn = TelephonyManager.getDefault().getNetworkOperator();
- SmsCbLocation location = new SmsCbLocation(plmn);
-
- return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP2,
- SmsCbMessage.GEOGRAPHICAL_SCOPE_PLMN_WIDE, bData.messageId, location,
- mEnvelope.serviceCategory, bData.getLanguage(), bData.userData.payloadStr,
- bData.priority, null, bData.cmasWarningInfo);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public SmsConstants.MessageClass getMessageClass() {
- if (BearerData.DISPLAY_MODE_IMMEDIATE == mBearerData.displayMode ) {
- return SmsConstants.MessageClass.CLASS_0;
- } else {
- return SmsConstants.MessageClass.UNKNOWN;
- }
- }
-
- /**
- * Calculate the next message id, starting at 1 and iteratively
- * incrementing within the range 1..65535 remembering the state
- * via a persistent system property. (See C.S0015-B, v2.0,
- * 4.3.1.5) Since this routine is expected to be accessed via via
- * binder-call, and hence should be thread-safe, it has been
- * synchronized.
- */
- public synchronized static int getNextMessageId() {
- // Testing and dialog with partners has indicated that
- // msgId==0 is (sometimes?) treated specially by lower levels.
- // Specifically, the ID is not preserved for delivery ACKs.
- // Hence, avoid 0 -- constraining the range to 1..65535.
- int msgId = SystemProperties.getInt(TelephonyProperties.PROPERTY_CDMA_MSG_ID, 1);
- String nextMsgId = Integer.toString((msgId % 0xFFFF) + 1);
- try{
- SystemProperties.set(TelephonyProperties.PROPERTY_CDMA_MSG_ID, nextMsgId);
- if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
- Rlog.d(LOG_TAG, "next " + TelephonyProperties.PROPERTY_CDMA_MSG_ID + " = " + nextMsgId);
- Rlog.d(LOG_TAG, "readback gets " +
- SystemProperties.get(TelephonyProperties.PROPERTY_CDMA_MSG_ID));
- }
- } catch(RuntimeException ex) {
- Rlog.e(LOG_TAG, "set nextMessage ID failed: " + ex);
- }
- return msgId;
- }
-
- /**
- * Creates BearerData and Envelope from parameters for a Submit SMS.
- * @return byte stream for SubmitPdu.
- */
- private static SubmitPdu privateGetSubmitPdu(String destAddrStr, boolean statusReportRequested,
- UserData userData) {
-
- /**
- * TODO(cleanup): give this function a more meaningful name.
- */
-
- /**
- * TODO(cleanup): Make returning null from the getSubmitPdu
- * variations meaningful -- clean up the error feedback
- * mechanism, and avoid null pointer exceptions.
- */
-
- /**
- * North America Plus Code :
- * Convert + code to 011 and dial out for international SMS
- */
- CdmaSmsAddress destAddr = CdmaSmsAddress.parse(
- PhoneNumberUtils.cdmaCheckAndProcessPlusCodeForSms(destAddrStr));
- if (destAddr == null) return null;
-
- BearerData bearerData = new BearerData();
- bearerData.messageType = BearerData.MESSAGE_TYPE_SUBMIT;
-
- bearerData.messageId = getNextMessageId();
-
- bearerData.deliveryAckReq = statusReportRequested;
- bearerData.userAckReq = false;
- bearerData.readAckReq = false;
- bearerData.reportReq = false;
-
- bearerData.userData = userData;
-
- byte[] encodedBearerData = BearerData.encode(bearerData);
- if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
- Rlog.d(LOG_TAG, "MO (encoded) BearerData = " + bearerData);
- Rlog.d(LOG_TAG, "MO raw BearerData = '" + HexDump.toHexString(encodedBearerData) + "'");
- }
- if (encodedBearerData == null) return null;
-
- int teleservice = bearerData.hasUserDataHeader ?
- SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
-
- SmsEnvelope envelope = new SmsEnvelope();
- envelope.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
- envelope.teleService = teleservice;
- envelope.destAddress = destAddr;
- envelope.bearerReply = RETURN_ACK;
- envelope.bearerData = encodedBearerData;
-
- /**
- * TODO(cleanup): envelope looks to be a pointless class, get
- * rid of it. Also -- most of the envelope fields set here
- * are ignored, why?
- */
-
- try {
- /**
- * TODO(cleanup): reference a spec and get rid of the ugly comments
- */
- ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
- DataOutputStream dos = new DataOutputStream(baos);
- dos.writeInt(envelope.teleService);
- dos.writeInt(0); //servicePresent
- dos.writeInt(0); //serviceCategory
- dos.write(destAddr.digitMode);
- dos.write(destAddr.numberMode);
- dos.write(destAddr.ton); // number_type
- dos.write(destAddr.numberPlan);
- dos.write(destAddr.numberOfDigits);
- dos.write(destAddr.origBytes, 0, destAddr.origBytes.length); // digits
- // Subaddress is not supported.
- dos.write(0); //subaddressType
- dos.write(0); //subaddr_odd
- dos.write(0); //subaddr_nbr_of_digits
- dos.write(encodedBearerData.length);
- dos.write(encodedBearerData, 0, encodedBearerData.length);
- dos.close();
-
- SubmitPdu pdu = new SubmitPdu();
- pdu.encodedMessage = baos.toByteArray();
- pdu.encodedScAddress = null;
- return pdu;
- } catch(IOException ex) {
- Rlog.e(LOG_TAG, "creating SubmitPdu failed: " + ex);
- }
- return null;
- }
-
- /**
- * Creates byte array (pseudo pdu) from SMS object.
- * Note: Do not call this method more than once per object!
- */
- private void createPdu() {
- SmsEnvelope env = mEnvelope;
- CdmaSmsAddress addr = env.origAddress;
- ByteArrayOutputStream baos = new ByteArrayOutputStream(100);
- DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(baos));
-
- try {
- dos.writeInt(env.messageType);
- dos.writeInt(env.teleService);
- dos.writeInt(env.serviceCategory);
-
- dos.writeByte(addr.digitMode);
- dos.writeByte(addr.numberMode);
- dos.writeByte(addr.ton);
- dos.writeByte(addr.numberPlan);
- dos.writeByte(addr.numberOfDigits);
- dos.write(addr.origBytes, 0, addr.origBytes.length); // digits
-
- dos.writeInt(env.bearerReply);
- // CauseCode values:
- dos.writeByte(env.replySeqNo);
- dos.writeByte(env.errorClass);
- dos.writeByte(env.causeCode);
- //encoded BearerData:
- dos.writeInt(env.bearerData.length);
- dos.write(env.bearerData, 0, env.bearerData.length);
- dos.close();
-
- /**
- * TODO(cleanup) -- The mPdu field is managed in
- * a fragile manner, and it would be much nicer if
- * accessing the serialized representation used a less
- * fragile mechanism. Maybe the getPdu method could
- * generate a representation if there was not yet one?
- */
-
- mPdu = baos.toByteArray();
- } catch (IOException ex) {
- Rlog.e(LOG_TAG, "createPdu: conversion from object to byte array failed: " + ex);
- }
- }
-
- /**
- * Converts a 4-Bit DTMF encoded symbol from the calling address number to ASCII character
- */
- private byte convertDtmfToAscii(byte dtmfDigit) {
- byte asciiDigit;
-
- switch (dtmfDigit) {
- case 0: asciiDigit = 68; break; // 'D'
- case 1: asciiDigit = 49; break; // '1'
- case 2: asciiDigit = 50; break; // '2'
- case 3: asciiDigit = 51; break; // '3'
- case 4: asciiDigit = 52; break; // '4'
- case 5: asciiDigit = 53; break; // '5'
- case 6: asciiDigit = 54; break; // '6'
- case 7: asciiDigit = 55; break; // '7'
- case 8: asciiDigit = 56; break; // '8'
- case 9: asciiDigit = 57; break; // '9'
- case 10: asciiDigit = 48; break; // '0'
- case 11: asciiDigit = 42; break; // '*'
- case 12: asciiDigit = 35; break; // '#'
- case 13: asciiDigit = 65; break; // 'A'
- case 14: asciiDigit = 66; break; // 'B'
- case 15: asciiDigit = 67; break; // 'C'
- default:
- asciiDigit = 32; // Invalid DTMF code
- break;
- }
-
- return asciiDigit;
- }
-
- /** This function shall be called to get the number of voicemails.
- * @hide
- */
- public int getNumOfVoicemails() {
- return mBearerData.numberOfMessages;
- }
-
- /**
- * Returns a byte array that can be use to uniquely identify a received SMS message.
- * C.S0015-B 4.3.1.6 Unique Message Identification.
- *
- * @return byte array uniquely identifying the message.
- * @hide
- */
- public byte[] getIncomingSmsFingerprint() {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
-
- output.write(mEnvelope.serviceCategory);
- output.write(mEnvelope.teleService);
- output.write(mEnvelope.origAddress.origBytes, 0, mEnvelope.origAddress.origBytes.length);
- output.write(mEnvelope.bearerData, 0, mEnvelope.bearerData.length);
- output.write(mEnvelope.origSubaddress.origBytes, 0,
- mEnvelope.origSubaddress.origBytes.length);
-
- return output.toByteArray();
- }
-
- /**
- * Returns the list of service category program data, if present.
- * @return a list of CdmaSmsCbProgramData objects, or null if not present
- * @hide
- */
- public ArrayList<CdmaSmsCbProgramData> getSmsCbProgramData() {
- return mBearerData.serviceCategoryProgramData;
- }
-}
diff --git a/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java b/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java
new file mode 100644
index 0000000..4ac2dea
--- /dev/null
+++ b/src/java/com/android/internal/telephony/cdma/SmsMessageConverter.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.cdma;
+
+import android.hardware.radio.V1_0.CdmaSmsMessage;
+import android.os.Parcel;
+import android.os.SystemProperties;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.SmsCbLocation;
+import android.telephony.SmsCbMessage;
+import android.telephony.TelephonyManager;
+import android.telephony.cdma.CdmaSmsCbProgramData;
+import android.telephony.Rlog;
+import android.util.Log;
+import android.text.TextUtils;
+import android.content.res.Resources;
+
+import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
+import com.android.internal.telephony.SmsConstants;
+import com.android.internal.telephony.SmsHeader;
+import com.android.internal.telephony.SmsMessageBase;
+import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.cdma.sms.BearerData;
+import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
+import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
+import com.android.internal.telephony.cdma.sms.SmsEnvelope;
+import com.android.internal.telephony.cdma.sms.UserData;
+import com.android.internal.telephony.uicc.IccUtils;
+import com.android.internal.util.BitwiseInputStream;
+import com.android.internal.util.HexDump;
+import com.android.internal.telephony.Sms7BitEncodingTranslator;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * A Factory class to convert from RIL to Framework SMS
+ *
+ */
+public class SmsMessageConverter {
+ static final String LOG_TAG = "SmsMessageConverter";
+ static private final String LOGGABLE_TAG = "CDMA:SMS";
+ private static final boolean VDBG = false;
+
+ /**
+ * Create a "raw" CDMA SmsMessage from a Parcel that was forged in ril.cpp.
+ * Note: Only primitive fields are set.
+ */
+ public static SmsMessage newCdmaSmsMessageFromRil(
+ CdmaSmsMessage cdmaSmsMessage) {
+ // Note: Parcel.readByte actually reads one Int and masks to byte
+ SmsEnvelope env = new SmsEnvelope();
+ CdmaSmsAddress addr = new CdmaSmsAddress();
+ CdmaSmsSubaddress subaddr = new CdmaSmsSubaddress();
+ byte[] data;
+ byte count;
+ int countInt;
+ int addressDigitMode;
+
+ //currently not supported by the modem-lib: env.mMessageType
+ env.teleService = cdmaSmsMessage.teleserviceId;
+
+ if (cdmaSmsMessage.isServicePresent) {
+ env.messageType = SmsEnvelope.MESSAGE_TYPE_BROADCAST;
+ }
+ else {
+ if (SmsEnvelope.TELESERVICE_NOT_SET == env.teleService) {
+ // assume type ACK
+ env.messageType = SmsEnvelope.MESSAGE_TYPE_ACKNOWLEDGE;
+ } else {
+ env.messageType = SmsEnvelope.MESSAGE_TYPE_POINT_TO_POINT;
+ }
+ }
+ env.serviceCategory = cdmaSmsMessage.serviceCategory;
+
+ // address
+ addressDigitMode = cdmaSmsMessage.address.digitMode;
+ addr.digitMode = (byte) (0xFF & addressDigitMode);
+ addr.numberMode = (byte) (0xFF & cdmaSmsMessage.address.numberMode);
+ addr.ton = cdmaSmsMessage.address.numberType;
+ addr.numberPlan = (byte) (0xFF & cdmaSmsMessage.address.numberPlan);
+ count = (byte) cdmaSmsMessage.address.digits.size();
+ addr.numberOfDigits = count;
+ data = new byte[count];
+ for (int index=0; index < count; index++) {
+ data[index] = cdmaSmsMessage.address.digits.get(index);
+
+ // convert the value if it is 4-bit DTMF to 8 bit
+ if (addressDigitMode == CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF) {
+ data[index] = SmsMessage.convertDtmfToAscii(data[index]);
+ }
+ }
+
+ addr.origBytes = data;
+
+ subaddr.type = cdmaSmsMessage.subAddress.subaddressType;
+ subaddr.odd = (byte) (cdmaSmsMessage.subAddress.odd ? 1 : 0);
+ count = (byte) cdmaSmsMessage.subAddress.digits.size();
+
+ if (count < 0) {
+ count = 0;
+ }
+
+ // p_cur->sSubAddress.digits[digitCount] :
+
+ data = new byte[count];
+
+ for (int index = 0; index < count; ++index) {
+ data[index] = cdmaSmsMessage.subAddress.digits.get(index);
+ }
+
+ subaddr.origBytes = data;
+
+ /* currently not supported by the modem-lib:
+ env.bearerReply
+ env.replySeqNo
+ env.errorClass
+ env.causeCode
+ */
+
+ // bearer data
+ countInt = cdmaSmsMessage.bearerData.size();
+ if (countInt < 0) {
+ countInt = 0;
+ }
+
+ data = new byte[countInt];
+ for (int index=0; index < countInt; index++) {
+ data[index] = cdmaSmsMessage.bearerData.get(index);
+ }
+ // BD gets further decoded when accessed in SMSDispatcher
+ env.bearerData = data;
+
+ // link the the filled objects to the SMS
+ env.origAddress = addr;
+ env.origSubaddress = subaddr;
+
+ SmsMessage msg = new SmsMessage(addr, env);
+
+ return msg;
+ }
+
+ public static android.telephony.SmsMessage newSmsMessageFromCdmaSmsMessage(
+ CdmaSmsMessage msg) {
+ return new android.telephony.SmsMessage((SmsMessageBase)newCdmaSmsMessageFromRil(msg));
+ }
+}
diff --git a/src/java/com/android/internal/telephony/cdma/sms/BearerData.java b/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
deleted file mode 100644
index 1de72db..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ /dev/null
@@ -1,2000 +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 com.android.internal.telephony.cdma.sms;
-
-import android.content.res.Resources;
-import android.telephony.SmsCbCmasInfo;
-import android.telephony.cdma.CdmaSmsCbProgramData;
-import android.telephony.cdma.CdmaSmsCbProgramResults;
-import android.text.format.Time;
-import android.telephony.Rlog;
-
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SmsHeader;
-import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.uicc.IccUtils;
-import com.android.internal.util.BitwiseInputStream;
-import com.android.internal.util.BitwiseOutputStream;
-
-import java.util.ArrayList;
-import java.util.TimeZone;
-
-/**
- * An object to encode and decode CDMA SMS bearer data.
- */
-public final class BearerData {
- private final static String LOG_TAG = "BearerData";
-
- /**
- * Bearer Data Subparameter Identifiers
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5-1)
- * NOTE: Commented subparameter types are not implemented.
- */
- private final static byte SUBPARAM_MESSAGE_IDENTIFIER = 0x00;
- private final static byte SUBPARAM_USER_DATA = 0x01;
- private final static byte SUBPARAM_USER_RESPONSE_CODE = 0x02;
- private final static byte SUBPARAM_MESSAGE_CENTER_TIME_STAMP = 0x03;
- private final static byte SUBPARAM_VALIDITY_PERIOD_ABSOLUTE = 0x04;
- private final static byte SUBPARAM_VALIDITY_PERIOD_RELATIVE = 0x05;
- private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE = 0x06;
- private final static byte SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE = 0x07;
- private final static byte SUBPARAM_PRIORITY_INDICATOR = 0x08;
- private final static byte SUBPARAM_PRIVACY_INDICATOR = 0x09;
- private final static byte SUBPARAM_REPLY_OPTION = 0x0A;
- private final static byte SUBPARAM_NUMBER_OF_MESSAGES = 0x0B;
- private final static byte SUBPARAM_ALERT_ON_MESSAGE_DELIVERY = 0x0C;
- private final static byte SUBPARAM_LANGUAGE_INDICATOR = 0x0D;
- private final static byte SUBPARAM_CALLBACK_NUMBER = 0x0E;
- private final static byte SUBPARAM_MESSAGE_DISPLAY_MODE = 0x0F;
- //private final static byte SUBPARAM_MULTIPLE_ENCODING_USER_DATA = 0x10;
- private final static byte SUBPARAM_MESSAGE_DEPOSIT_INDEX = 0x11;
- private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA = 0x12;
- private final static byte SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS = 0x13;
- private final static byte SUBPARAM_MESSAGE_STATUS = 0x14;
- //private final static byte SUBPARAM_TP_FAILURE_CAUSE = 0x15;
- //private final static byte SUBPARAM_ENHANCED_VMN = 0x16;
- //private final static byte SUBPARAM_ENHANCED_VMN_ACK = 0x17;
-
- // All other values after this are reserved.
- private final static byte SUBPARAM_ID_LAST_DEFINED = 0x17;
-
- /**
- * Supported message types for CDMA SMS messages
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5.1-1)
- */
- public static final int MESSAGE_TYPE_DELIVER = 0x01;
- public static final int MESSAGE_TYPE_SUBMIT = 0x02;
- public static final int MESSAGE_TYPE_CANCELLATION = 0x03;
- public static final int MESSAGE_TYPE_DELIVERY_ACK = 0x04;
- public static final int MESSAGE_TYPE_USER_ACK = 0x05;
- public static final int MESSAGE_TYPE_READ_ACK = 0x06;
- public static final int MESSAGE_TYPE_DELIVER_REPORT = 0x07;
- public static final int MESSAGE_TYPE_SUBMIT_REPORT = 0x08;
-
- public int messageType;
-
- /**
- * 16-bit value indicating the message ID, which increments modulo 65536.
- * (Special rules apply for WAP-messages.)
- * (See 3GPP2 C.S0015-B, v2, 4.5.1)
- */
- public int messageId;
-
- /**
- * Supported priority modes for CDMA SMS messages
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1)
- */
- public static final int PRIORITY_NORMAL = 0x0;
- public static final int PRIORITY_INTERACTIVE = 0x1;
- public static final int PRIORITY_URGENT = 0x2;
- public static final int PRIORITY_EMERGENCY = 0x3;
-
- public boolean priorityIndicatorSet = false;
- public int priority = PRIORITY_NORMAL;
-
- /**
- * Supported privacy modes for CDMA SMS messages
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5.10-1)
- */
- public static final int PRIVACY_NOT_RESTRICTED = 0x0;
- public static final int PRIVACY_RESTRICTED = 0x1;
- public static final int PRIVACY_CONFIDENTIAL = 0x2;
- public static final int PRIVACY_SECRET = 0x3;
-
- public boolean privacyIndicatorSet = false;
- public int privacy = PRIVACY_NOT_RESTRICTED;
-
- /**
- * Supported alert priority modes for CDMA SMS messages
- * (See 3GPP2 C.S0015-B, v2.0, table 4.5.13-1)
- */
- public static final int ALERT_DEFAULT = 0x0;
- public static final int ALERT_LOW_PRIO = 0x1;
- public static final int ALERT_MEDIUM_PRIO = 0x2;
- public static final int ALERT_HIGH_PRIO = 0x3;
-
- public boolean alertIndicatorSet = false;
- public int alert = ALERT_DEFAULT;
-
- /**
- * Supported display modes for CDMA SMS messages. Display mode is
- * a 2-bit value used to indicate to the mobile station when to
- * display the received message. (See 3GPP2 C.S0015-B, v2,
- * 4.5.16)
- */
- public static final int DISPLAY_MODE_IMMEDIATE = 0x0;
- public static final int DISPLAY_MODE_DEFAULT = 0x1;
- public static final int DISPLAY_MODE_USER = 0x2;
-
- public boolean displayModeSet = false;
- public int displayMode = DISPLAY_MODE_DEFAULT;
-
- /**
- * Language Indicator values. NOTE: the spec (3GPP2 C.S0015-B,
- * v2, 4.5.14) is ambiguous as to the meaning of this field, as it
- * refers to C.R1001-D but that reference has been crossed out.
- * It would seem reasonable to assume the values from C.R1001-F
- * (table 9.2-1) are to be used instead.
- */
- public static final int LANGUAGE_UNKNOWN = 0x00;
- public static final int LANGUAGE_ENGLISH = 0x01;
- public static final int LANGUAGE_FRENCH = 0x02;
- public static final int LANGUAGE_SPANISH = 0x03;
- public static final int LANGUAGE_JAPANESE = 0x04;
- public static final int LANGUAGE_KOREAN = 0x05;
- public static final int LANGUAGE_CHINESE = 0x06;
- public static final int LANGUAGE_HEBREW = 0x07;
-
- public boolean languageIndicatorSet = false;
- public int language = LANGUAGE_UNKNOWN;
-
- /**
- * SMS Message Status Codes. The first component of the Message
- * status indicates if an error has occurred and whether the error
- * is considered permanent or temporary. The second component of
- * the Message status indicates the cause of the error (if any).
- * (See 3GPP2 C.S0015-B, v2.0, 4.5.21)
- */
- /* no-error codes */
- public static final int ERROR_NONE = 0x00;
- public static final int STATUS_ACCEPTED = 0x00;
- public static final int STATUS_DEPOSITED_TO_INTERNET = 0x01;
- public static final int STATUS_DELIVERED = 0x02;
- public static final int STATUS_CANCELLED = 0x03;
- /* temporary-error and permanent-error codes */
- public static final int ERROR_TEMPORARY = 0x02;
- public static final int STATUS_NETWORK_CONGESTION = 0x04;
- public static final int STATUS_NETWORK_ERROR = 0x05;
- public static final int STATUS_UNKNOWN_ERROR = 0x1F;
- /* permanent-error codes */
- public static final int ERROR_PERMANENT = 0x03;
- public static final int STATUS_CANCEL_FAILED = 0x06;
- public static final int STATUS_BLOCKED_DESTINATION = 0x07;
- public static final int STATUS_TEXT_TOO_LONG = 0x08;
- public static final int STATUS_DUPLICATE_MESSAGE = 0x09;
- public static final int STATUS_INVALID_DESTINATION = 0x0A;
- public static final int STATUS_MESSAGE_EXPIRED = 0x0D;
- /* undefined-status codes */
- public static final int ERROR_UNDEFINED = 0xFF;
- public static final int STATUS_UNDEFINED = 0xFF;
-
- public boolean messageStatusSet = false;
- public int errorClass = ERROR_UNDEFINED;
- public int messageStatus = STATUS_UNDEFINED;
-
- /**
- * 1-bit value that indicates whether a User Data Header (UDH) is present.
- * (See 3GPP2 C.S0015-B, v2, 4.5.1)
- *
- * NOTE: during encoding, this value will be set based on the
- * presence of a UDH in the structured data, any existing setting
- * will be overwritten.
- */
- public boolean hasUserDataHeader;
-
- /**
- * provides the information for the user data
- * (e.g. padding bits, user data, user data header, etc)
- * (See 3GPP2 C.S.0015-B, v2, 4.5.2)
- */
- public UserData userData;
-
- /**
- * The User Response Code subparameter is used in the SMS User
- * Acknowledgment Message to respond to previously received short
- * messages. This message center-specific element carries the
- * identifier of a predefined response. (See 3GPP2 C.S.0015-B, v2,
- * 4.5.3)
- */
- public boolean userResponseCodeSet = false;
- public int userResponseCode;
-
- /**
- * 6-byte-field, see 3GPP2 C.S0015-B, v2, 4.5.4
- */
- public static class TimeStamp extends Time {
-
- public TimeStamp() {
- super(TimeZone.getDefault().getID()); // 3GPP2 timestamps use the local timezone
- }
-
- public static TimeStamp fromByteArray(byte[] data) {
- TimeStamp ts = new TimeStamp();
- // C.S0015-B v2.0, 4.5.4: range is 1996-2095
- int year = IccUtils.cdmaBcdByteToInt(data[0]);
- if (year > 99 || year < 0) return null;
- ts.year = year >= 96 ? year + 1900 : year + 2000;
- int month = IccUtils.cdmaBcdByteToInt(data[1]);
- if (month < 1 || month > 12) return null;
- ts.month = month - 1;
- int day = IccUtils.cdmaBcdByteToInt(data[2]);
- if (day < 1 || day > 31) return null;
- ts.monthDay = day;
- int hour = IccUtils.cdmaBcdByteToInt(data[3]);
- if (hour < 0 || hour > 23) return null;
- ts.hour = hour;
- int minute = IccUtils.cdmaBcdByteToInt(data[4]);
- if (minute < 0 || minute > 59) return null;
- ts.minute = minute;
- int second = IccUtils.cdmaBcdByteToInt(data[5]);
- if (second < 0 || second > 59) return null;
- ts.second = second;
- return ts;
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("TimeStamp ");
- builder.append("{ year=" + year);
- builder.append(", month=" + month);
- builder.append(", day=" + monthDay);
- builder.append(", hour=" + hour);
- builder.append(", minute=" + minute);
- builder.append(", second=" + second);
- builder.append(" }");
- return builder.toString();
- }
- }
-
- public TimeStamp msgCenterTimeStamp;
- public TimeStamp validityPeriodAbsolute;
- public TimeStamp deferredDeliveryTimeAbsolute;
-
- /**
- * Relative time is specified as one byte, the value of which
- * falls into a series of ranges, as specified below. The idea is
- * that shorter time intervals allow greater precision -- the
- * value means minutes from zero until the MINS_LIMIT (inclusive),
- * upon which it means hours until the HOURS_LIMIT, and so
- * forth. (See 3GPP2 C.S0015-B, v2, 4.5.6-1)
- */
- public static final int RELATIVE_TIME_MINS_LIMIT = 143;
- public static final int RELATIVE_TIME_HOURS_LIMIT = 167;
- public static final int RELATIVE_TIME_DAYS_LIMIT = 196;
- public static final int RELATIVE_TIME_WEEKS_LIMIT = 244;
- public static final int RELATIVE_TIME_INDEFINITE = 245;
- public static final int RELATIVE_TIME_NOW = 246;
- public static final int RELATIVE_TIME_MOBILE_INACTIVE = 247;
- public static final int RELATIVE_TIME_RESERVED = 248;
-
- public boolean validityPeriodRelativeSet;
- public int validityPeriodRelative;
- public boolean deferredDeliveryTimeRelativeSet;
- public int deferredDeliveryTimeRelative;
-
- /**
- * The Reply Option subparameter contains 1-bit values which
- * indicate whether SMS acknowledgment is requested or not. (See
- * 3GPP2 C.S0015-B, v2, 4.5.11)
- */
- public boolean userAckReq;
- public boolean deliveryAckReq;
- public boolean readAckReq;
- public boolean reportReq;
-
- /**
- * The Number of Messages subparameter (8-bit value) is a decimal
- * number in the 0 to 99 range representing the number of messages
- * stored at the Voice Mail System. This element is used by the
- * Voice Mail Notification service. (See 3GPP2 C.S0015-B, v2,
- * 4.5.12)
- */
- public int numberOfMessages;
-
- /**
- * The Message Deposit Index subparameter is assigned by the
- * message center as a unique index to the contents of the User
- * Data subparameter in each message sent to a particular mobile
- * station. The mobile station, when replying to a previously
- * received short message which included a Message Deposit Index
- * subparameter, may include the Message Deposit Index of the
- * received message to indicate to the message center that the
- * original contents of the message are to be included in the
- * reply. (See 3GPP2 C.S0015-B, v2, 4.5.18)
- */
- public int depositIndex;
-
- /**
- * 4-bit or 8-bit value that indicates the number to be dialed in reply to a
- * received SMS message.
- * (See 3GPP2 C.S0015-B, v2, 4.5.15)
- */
- public CdmaSmsAddress callbackNumber;
-
- /**
- * CMAS warning notification information.
- * @see #decodeCmasUserData(BearerData, int)
- */
- public SmsCbCmasInfo cmasWarningInfo;
-
- /**
- * The Service Category Program Data subparameter is used to enable and disable
- * SMS broadcast service categories to display. If this subparameter is present,
- * this field will contain a list of one or more
- * {@link android.telephony.cdma.CdmaSmsCbProgramData} objects containing the
- * operation(s) to perform.
- */
- public ArrayList<CdmaSmsCbProgramData> serviceCategoryProgramData;
-
- /**
- * The Service Category Program Results subparameter informs the message center
- * of the results of a Service Category Program Data request.
- */
- public ArrayList<CdmaSmsCbProgramResults> serviceCategoryProgramResults;
-
-
- private static class CodingException extends Exception {
- public CodingException(String s) {
- super(s);
- }
- }
-
- /**
- * Returns the language indicator as a two-character ISO 639 string.
- * @return a two character ISO 639 language code
- */
- public String getLanguage() {
- return getLanguageCodeForValue(language);
- }
-
- /**
- * Converts a CDMA language indicator value to an ISO 639 two character language code.
- * @param languageValue the CDMA language value to convert
- * @return the two character ISO 639 language code for the specified value, or null if unknown
- */
- private static String getLanguageCodeForValue(int languageValue) {
- switch (languageValue) {
- case LANGUAGE_ENGLISH:
- return "en";
-
- case LANGUAGE_FRENCH:
- return "fr";
-
- case LANGUAGE_SPANISH:
- return "es";
-
- case LANGUAGE_JAPANESE:
- return "ja";
-
- case LANGUAGE_KOREAN:
- return "ko";
-
- case LANGUAGE_CHINESE:
- return "zh";
-
- case LANGUAGE_HEBREW:
- return "he";
-
- default:
- return null;
- }
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("BearerData ");
- builder.append("{ messageType=" + messageType);
- builder.append(", messageId=" + messageId);
- builder.append(", priority=" + (priorityIndicatorSet ? priority : "unset"));
- builder.append(", privacy=" + (privacyIndicatorSet ? privacy : "unset"));
- builder.append(", alert=" + (alertIndicatorSet ? alert : "unset"));
- builder.append(", displayMode=" + (displayModeSet ? displayMode : "unset"));
- builder.append(", language=" + (languageIndicatorSet ? language : "unset"));
- builder.append(", errorClass=" + (messageStatusSet ? errorClass : "unset"));
- builder.append(", msgStatus=" + (messageStatusSet ? messageStatus : "unset"));
- builder.append(", msgCenterTimeStamp=" +
- ((msgCenterTimeStamp != null) ? msgCenterTimeStamp : "unset"));
- builder.append(", validityPeriodAbsolute=" +
- ((validityPeriodAbsolute != null) ? validityPeriodAbsolute : "unset"));
- builder.append(", validityPeriodRelative=" +
- ((validityPeriodRelativeSet) ? validityPeriodRelative : "unset"));
- builder.append(", deferredDeliveryTimeAbsolute=" +
- ((deferredDeliveryTimeAbsolute != null) ? deferredDeliveryTimeAbsolute : "unset"));
- builder.append(", deferredDeliveryTimeRelative=" +
- ((deferredDeliveryTimeRelativeSet) ? deferredDeliveryTimeRelative : "unset"));
- builder.append(", userAckReq=" + userAckReq);
- builder.append(", deliveryAckReq=" + deliveryAckReq);
- builder.append(", readAckReq=" + readAckReq);
- builder.append(", reportReq=" + reportReq);
- builder.append(", numberOfMessages=" + numberOfMessages);
- builder.append(", callbackNumber=" + Rlog.pii(LOG_TAG, callbackNumber));
- builder.append(", depositIndex=" + depositIndex);
- builder.append(", hasUserDataHeader=" + hasUserDataHeader);
- builder.append(", userData=" + userData);
- builder.append(" }");
- return builder.toString();
- }
-
- private static void encodeMessageId(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- outStream.write(8, 3);
- outStream.write(4, bData.messageType);
- outStream.write(8, bData.messageId >> 8);
- outStream.write(8, bData.messageId);
- outStream.write(1, bData.hasUserDataHeader ? 1 : 0);
- outStream.skip(3);
- }
-
- private static int countAsciiSeptets(CharSequence msg, boolean force) {
- int msgLen = msg.length();
- if (force) return msgLen;
- for (int i = 0; i < msgLen; i++) {
- if (UserData.charToAscii.get(msg.charAt(i), -1) == -1) {
- return -1;
- }
- }
- return msgLen;
- }
-
- /**
- * Calculate the message text encoding length, fragmentation, and other details.
- *
- * @param msg message text
- * @param force7BitEncoding ignore (but still count) illegal characters if true
- * @param isEntireMsg indicates if this is entire msg or a segment in multipart msg
- * @return septet count, or -1 on failure
- */
- public static TextEncodingDetails calcTextEncodingDetails(CharSequence msg,
- boolean force7BitEncoding, boolean isEntireMsg) {
- TextEncodingDetails ted;
- int septets = countAsciiSeptets(msg, force7BitEncoding);
- if (septets != -1 && septets <= SmsConstants.MAX_USER_DATA_SEPTETS) {
- ted = new TextEncodingDetails();
- ted.msgCount = 1;
- ted.codeUnitCount = septets;
- ted.codeUnitsRemaining = SmsConstants.MAX_USER_DATA_SEPTETS - septets;
- ted.codeUnitSize = SmsConstants.ENCODING_7BIT;
- } else {
- ted = com.android.internal.telephony.gsm.SmsMessage.calculateLength(
- msg, force7BitEncoding);
- if (ted.msgCount == 1 && ted.codeUnitSize == SmsConstants.ENCODING_7BIT &&
- isEntireMsg) {
- // We don't support single-segment EMS, so calculate for 16-bit
- // TODO: Consider supporting single-segment EMS
- return SmsMessageBase.calcUnicodeEncodingDetails(msg);
- }
- }
- return ted;
- }
-
- private static byte[] encode7bitAscii(String msg, boolean force)
- throws CodingException
- {
- try {
- BitwiseOutputStream outStream = new BitwiseOutputStream(msg.length());
- int msgLen = msg.length();
- for (int i = 0; i < msgLen; i++) {
- int charCode = UserData.charToAscii.get(msg.charAt(i), -1);
- if (charCode == -1) {
- if (force) {
- outStream.write(7, UserData.UNENCODABLE_7_BIT_CHAR);
- } else {
- throw new CodingException("cannot ASCII encode (" + msg.charAt(i) + ")");
- }
- } else {
- outStream.write(7, charCode);
- }
- }
- return outStream.toByteArray();
- } catch (BitwiseOutputStream.AccessException ex) {
- throw new CodingException("7bit ASCII encode failed: " + ex);
- }
- }
-
- private static byte[] encodeUtf16(String msg)
- throws CodingException
- {
- try {
- return msg.getBytes("utf-16be");
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("UTF-16 encode failed: " + ex);
- }
- }
-
- private static class Gsm7bitCodingResult {
- int septets;
- byte[] data;
- }
-
- private static Gsm7bitCodingResult encode7bitGsm(String msg, int septetOffset, boolean force)
- throws CodingException
- {
- try {
- /*
- * TODO(cleanup): It would be nice if GsmAlphabet provided
- * an option to produce just the data without prepending
- * the septet count, as this function is really just a
- * wrapper to strip that off. Not to mention that the
- * septet count is generally known prior to invocation of
- * the encoder. Note that it cannot be derived from the
- * resulting array length, since that cannot distinguish
- * if the last contains either 1 or 8 valid bits.
- *
- * TODO(cleanup): The BitwiseXStreams could also be
- * extended with byte-wise reversed endianness read/write
- * routines to allow a corresponding implementation of
- * stringToGsm7BitPacked, and potentially directly support
- * access to the main bitwise stream from encode/decode.
- */
- byte[] fullData = GsmAlphabet.stringToGsm7BitPacked(msg, septetOffset, !force, 0, 0);
- Gsm7bitCodingResult result = new Gsm7bitCodingResult();
- result.data = new byte[fullData.length - 1];
- System.arraycopy(fullData, 1, result.data, 0, fullData.length - 1);
- result.septets = fullData[0] & 0x00FF;
- return result;
- } catch (com.android.internal.telephony.EncodeException ex) {
- throw new CodingException("7bit GSM encode failed: " + ex);
- }
- }
-
- private static void encode7bitEms(UserData uData, byte[] udhData, boolean force)
- throws CodingException
- {
- int udhBytes = udhData.length + 1; // Add length octet.
- int udhSeptets = ((udhBytes * 8) + 6) / 7;
- Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, udhSeptets, force);
- uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET;
- uData.msgEncodingSet = true;
- uData.numFields = gcr.septets;
- uData.payload = gcr.data;
- uData.payload[0] = (byte)udhData.length;
- System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
- }
-
- private static void encode16bitEms(UserData uData, byte[] udhData)
- throws CodingException
- {
- byte[] payload = encodeUtf16(uData.payloadStr);
- int udhBytes = udhData.length + 1; // Add length octet.
- int udhCodeUnits = (udhBytes + 1) / 2;
- int payloadCodeUnits = payload.length / 2;
- uData.msgEncoding = UserData.ENCODING_UNICODE_16;
- uData.msgEncodingSet = true;
- uData.numFields = udhCodeUnits + payloadCodeUnits;
- uData.payload = new byte[uData.numFields * 2];
- uData.payload[0] = (byte)udhData.length;
- System.arraycopy(udhData, 0, uData.payload, 1, udhData.length);
- System.arraycopy(payload, 0, uData.payload, udhBytes, payload.length);
- }
-
- private static void encodeEmsUserDataPayload(UserData uData)
- throws CodingException
- {
- byte[] headerData = SmsHeader.toByteArray(uData.userDataHeader);
- if (uData.msgEncodingSet) {
- if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
- encode7bitEms(uData, headerData, true);
- } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
- encode16bitEms(uData, headerData);
- } else {
- throw new CodingException("unsupported EMS user data encoding (" +
- uData.msgEncoding + ")");
- }
- } else {
- try {
- encode7bitEms(uData, headerData, false);
- } catch (CodingException ex) {
- encode16bitEms(uData, headerData);
- }
- }
- }
-
- private static byte[] encodeShiftJis(String msg) throws CodingException {
- try {
- return msg.getBytes("Shift_JIS");
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("Shift-JIS encode failed: " + ex);
- }
- }
-
- private static void encodeUserDataPayload(UserData uData)
- throws CodingException
- {
- if ((uData.payloadStr == null) && (uData.msgEncoding != UserData.ENCODING_OCTET)) {
- Rlog.e(LOG_TAG, "user data with null payloadStr");
- uData.payloadStr = "";
- }
-
- if (uData.userDataHeader != null) {
- encodeEmsUserDataPayload(uData);
- return;
- }
-
- if (uData.msgEncodingSet) {
- if (uData.msgEncoding == UserData.ENCODING_OCTET) {
- if (uData.payload == null) {
- Rlog.e(LOG_TAG, "user data with octet encoding but null payload");
- uData.payload = new byte[0];
- uData.numFields = 0;
- } else {
- uData.numFields = uData.payload.length;
- }
- } else {
- if (uData.payloadStr == null) {
- Rlog.e(LOG_TAG, "non-octet user data with null payloadStr");
- uData.payloadStr = "";
- }
- if (uData.msgEncoding == UserData.ENCODING_GSM_7BIT_ALPHABET) {
- Gsm7bitCodingResult gcr = encode7bitGsm(uData.payloadStr, 0, true);
- uData.payload = gcr.data;
- uData.numFields = gcr.septets;
- } else if (uData.msgEncoding == UserData.ENCODING_7BIT_ASCII) {
- uData.payload = encode7bitAscii(uData.payloadStr, true);
- uData.numFields = uData.payloadStr.length();
- } else if (uData.msgEncoding == UserData.ENCODING_UNICODE_16) {
- uData.payload = encodeUtf16(uData.payloadStr);
- uData.numFields = uData.payloadStr.length();
- } else if (uData.msgEncoding == UserData.ENCODING_SHIFT_JIS) {
- uData.payload = encodeShiftJis(uData.payloadStr);
- uData.numFields = uData.payload.length;
- } else {
- throw new CodingException("unsupported user data encoding (" +
- uData.msgEncoding + ")");
- }
- }
- } else {
- try {
- uData.payload = encode7bitAscii(uData.payloadStr, false);
- uData.msgEncoding = UserData.ENCODING_7BIT_ASCII;
- } catch (CodingException ex) {
- uData.payload = encodeUtf16(uData.payloadStr);
- uData.msgEncoding = UserData.ENCODING_UNICODE_16;
- }
- uData.numFields = uData.payloadStr.length();
- uData.msgEncodingSet = true;
- }
- }
-
- private static void encodeUserData(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException, CodingException
- {
- /*
- * TODO(cleanup): Do we really need to set userData.payload as
- * a side effect of encoding? If not, we could avoid data
- * copies by passing outStream directly.
- */
- encodeUserDataPayload(bData.userData);
- bData.hasUserDataHeader = bData.userData.userDataHeader != null;
-
- if (bData.userData.payload.length > SmsConstants.MAX_USER_DATA_BYTES) {
- throw new CodingException("encoded user data too large (" +
- bData.userData.payload.length +
- " > " + SmsConstants.MAX_USER_DATA_BYTES + " bytes)");
- }
-
- /*
- * TODO(cleanup): figure out what the right answer is WRT paddingBits field
- *
- * userData.paddingBits = (userData.payload.length * 8) - (userData.numFields * 7);
- * userData.paddingBits = 0; // XXX this seems better, but why?
- *
- */
- int dataBits = (bData.userData.payload.length * 8) - bData.userData.paddingBits;
- int paramBits = dataBits + 13;
- if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
- (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
- paramBits += 8;
- }
- int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
- int paddingBits = (paramBytes * 8) - paramBits;
- outStream.write(8, paramBytes);
- outStream.write(5, bData.userData.msgEncoding);
- if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
- (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
- outStream.write(8, bData.userData.msgType);
- }
- outStream.write(8, bData.userData.numFields);
- outStream.writeByteArray(dataBits, bData.userData.payload);
- if (paddingBits > 0) outStream.write(paddingBits, 0);
- }
-
- private static void encodeReplyOption(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- outStream.write(8, 1);
- outStream.write(1, bData.userAckReq ? 1 : 0);
- outStream.write(1, bData.deliveryAckReq ? 1 : 0);
- outStream.write(1, bData.readAckReq ? 1 : 0);
- outStream.write(1, bData.reportReq ? 1 : 0);
- outStream.write(4, 0);
- }
-
- private static byte[] encodeDtmfSmsAddress(String address) {
- int digits = address.length();
- int dataBits = digits * 4;
- int dataBytes = (dataBits / 8);
- dataBytes += (dataBits % 8) > 0 ? 1 : 0;
- byte[] rawData = new byte[dataBytes];
- for (int i = 0; i < digits; i++) {
- char c = address.charAt(i);
- int val = 0;
- if ((c >= '1') && (c <= '9')) val = c - '0';
- else if (c == '0') val = 10;
- else if (c == '*') val = 11;
- else if (c == '#') val = 12;
- else return null;
- rawData[i / 2] |= val << (4 - ((i % 2) * 4));
- }
- return rawData;
- }
-
- /*
- * TODO(cleanup): CdmaSmsAddress encoding should make use of
- * CdmaSmsAddress.parse provided that DTMF encoding is unified,
- * and the difference in 4-bit vs. 8-bit is resolved.
- */
-
- private static void encodeCdmaSmsAddress(CdmaSmsAddress addr) throws CodingException {
- if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
- try {
- addr.origBytes = addr.address.getBytes("US-ASCII");
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("invalid SMS address, cannot convert to ASCII");
- }
- } else {
- addr.origBytes = encodeDtmfSmsAddress(addr.address);
- }
- }
-
- private static void encodeCallbackNumber(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException, CodingException
- {
- CdmaSmsAddress addr = bData.callbackNumber;
- encodeCdmaSmsAddress(addr);
- int paramBits = 9;
- int dataBits = 0;
- if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
- paramBits += 7;
- dataBits = addr.numberOfDigits * 8;
- } else {
- dataBits = addr.numberOfDigits * 4;
- }
- paramBits += dataBits;
- int paramBytes = (paramBits / 8) + ((paramBits % 8) > 0 ? 1 : 0);
- int paddingBits = (paramBytes * 8) - paramBits;
- outStream.write(8, paramBytes);
- outStream.write(1, addr.digitMode);
- if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
- outStream.write(3, addr.ton);
- outStream.write(4, addr.numberPlan);
- }
- outStream.write(8, addr.numberOfDigits);
- outStream.writeByteArray(dataBits, addr.origBytes);
- if (paddingBits > 0) outStream.write(paddingBits, 0);
- }
-
- private static void encodeMsgStatus(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- outStream.write(8, 1);
- outStream.write(2, bData.errorClass);
- outStream.write(6, bData.messageStatus);
- }
-
- private static void encodeMsgCount(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- outStream.write(8, 1);
- outStream.write(8, bData.numberOfMessages);
- }
-
- private static void encodeValidityPeriodRel(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- outStream.write(8, 1);
- outStream.write(8, bData.validityPeriodRelative);
- }
-
- private static void encodePrivacyIndicator(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- outStream.write(8, 1);
- outStream.write(2, bData.privacy);
- outStream.skip(6);
- }
-
- private static void encodeLanguageIndicator(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- outStream.write(8, 1);
- outStream.write(8, bData.language);
- }
-
- private static void encodeDisplayMode(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- outStream.write(8, 1);
- outStream.write(2, bData.displayMode);
- outStream.skip(6);
- }
-
- private static void encodePriorityIndicator(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- outStream.write(8, 1);
- outStream.write(2, bData.priority);
- outStream.skip(6);
- }
-
- private static void encodeMsgDeliveryAlert(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- outStream.write(8, 1);
- outStream.write(2, bData.alert);
- outStream.skip(6);
- }
-
- private static void encodeScpResults(BearerData bData, BitwiseOutputStream outStream)
- throws BitwiseOutputStream.AccessException
- {
- ArrayList<CdmaSmsCbProgramResults> results = bData.serviceCategoryProgramResults;
- outStream.write(8, (results.size() * 4)); // 4 octets per program result
- for (CdmaSmsCbProgramResults result : results) {
- int category = result.getCategory();
- outStream.write(8, category >> 8);
- outStream.write(8, category);
- outStream.write(8, result.getLanguage());
- outStream.write(4, result.getCategoryResult());
- outStream.skip(4);
- }
- }
-
- /**
- * Create serialized representation for BearerData object.
- * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
- *
- * @param bData an instance of BearerData.
- *
- * @return byte array of raw encoded SMS bearer data.
- */
- public static byte[] encode(BearerData bData) {
- bData.hasUserDataHeader = ((bData.userData != null) &&
- (bData.userData.userDataHeader != null));
- try {
- BitwiseOutputStream outStream = new BitwiseOutputStream(200);
- outStream.write(8, SUBPARAM_MESSAGE_IDENTIFIER);
- encodeMessageId(bData, outStream);
- if (bData.userData != null) {
- outStream.write(8, SUBPARAM_USER_DATA);
- encodeUserData(bData, outStream);
- }
- if (bData.callbackNumber != null) {
- outStream.write(8, SUBPARAM_CALLBACK_NUMBER);
- encodeCallbackNumber(bData, outStream);
- }
- if (bData.userAckReq || bData.deliveryAckReq || bData.readAckReq || bData.reportReq) {
- outStream.write(8, SUBPARAM_REPLY_OPTION);
- encodeReplyOption(bData, outStream);
- }
- if (bData.numberOfMessages != 0) {
- outStream.write(8, SUBPARAM_NUMBER_OF_MESSAGES);
- encodeMsgCount(bData, outStream);
- }
- if (bData.validityPeriodRelativeSet) {
- outStream.write(8, SUBPARAM_VALIDITY_PERIOD_RELATIVE);
- encodeValidityPeriodRel(bData, outStream);
- }
- if (bData.privacyIndicatorSet) {
- outStream.write(8, SUBPARAM_PRIVACY_INDICATOR);
- encodePrivacyIndicator(bData, outStream);
- }
- if (bData.languageIndicatorSet) {
- outStream.write(8, SUBPARAM_LANGUAGE_INDICATOR);
- encodeLanguageIndicator(bData, outStream);
- }
- if (bData.displayModeSet) {
- outStream.write(8, SUBPARAM_MESSAGE_DISPLAY_MODE);
- encodeDisplayMode(bData, outStream);
- }
- if (bData.priorityIndicatorSet) {
- outStream.write(8, SUBPARAM_PRIORITY_INDICATOR);
- encodePriorityIndicator(bData, outStream);
- }
- if (bData.alertIndicatorSet) {
- outStream.write(8, SUBPARAM_ALERT_ON_MESSAGE_DELIVERY);
- encodeMsgDeliveryAlert(bData, outStream);
- }
- if (bData.messageStatusSet) {
- outStream.write(8, SUBPARAM_MESSAGE_STATUS);
- encodeMsgStatus(bData, outStream);
- }
- if (bData.serviceCategoryProgramResults != null) {
- outStream.write(8, SUBPARAM_SERVICE_CATEGORY_PROGRAM_RESULTS);
- encodeScpResults(bData, outStream);
- }
- return outStream.toByteArray();
- } catch (BitwiseOutputStream.AccessException ex) {
- Rlog.e(LOG_TAG, "BearerData encode failed: " + ex);
- } catch (CodingException ex) {
- Rlog.e(LOG_TAG, "BearerData encode failed: " + ex);
- }
- return null;
- }
-
- private static boolean decodeMessageId(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 3 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.messageType = inStream.read(4);
- bData.messageId = inStream.read(8) << 8;
- bData.messageId |= inStream.read(8);
- bData.hasUserDataHeader = (inStream.read(1) == 1);
- inStream.skip(3);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "MESSAGE_IDENTIFIER decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- return decodeSuccess;
- }
-
- private static boolean decodeReserved(
- BearerData bData, BitwiseInputStream inStream, int subparamId)
- throws BitwiseInputStream.AccessException, CodingException
- {
- boolean decodeSuccess = false;
- int subparamLen = inStream.read(8); // SUBPARAM_LEN
- int paramBits = subparamLen * 8;
- if (paramBits <= inStream.available()) {
- decodeSuccess = true;
- inStream.skip(paramBits);
- }
- Rlog.d(LOG_TAG, "RESERVED bearer data subparameter " + subparamId + " decode "
- + (decodeSuccess ? "succeeded" : "failed") + " (param bits = " + paramBits + ")");
- if (!decodeSuccess) {
- throw new CodingException("RESERVED bearer data subparameter " + subparamId
- + " had invalid SUBPARAM_LEN " + subparamLen);
- }
-
- return decodeSuccess;
- }
-
- private static boolean decodeUserData(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException
- {
- int paramBits = inStream.read(8) * 8;
- bData.userData = new UserData();
- bData.userData.msgEncoding = inStream.read(5);
- bData.userData.msgEncodingSet = true;
- bData.userData.msgType = 0;
- int consumedBits = 5;
- if ((bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) ||
- (bData.userData.msgEncoding == UserData.ENCODING_GSM_DCS)) {
- bData.userData.msgType = inStream.read(8);
- consumedBits += 8;
- }
- bData.userData.numFields = inStream.read(8);
- consumedBits += 8;
- int dataBits = paramBits - consumedBits;
- bData.userData.payload = inStream.readByteArray(dataBits);
- return true;
- }
-
- private static String decodeUtf8(byte[] data, int offset, int numFields)
- throws CodingException
- {
- return decodeCharset(data, offset, numFields, 1, "UTF-8");
- }
-
- private static String decodeUtf16(byte[] data, int offset, int numFields)
- throws CodingException
- {
- // Subtract header and possible padding byte (at end) from num fields.
- int padding = offset % 2;
- numFields -= (offset + padding) / 2;
- return decodeCharset(data, offset, numFields, 2, "utf-16be");
- }
-
- private static String decodeCharset(byte[] data, int offset, int numFields, int width,
- String charset) throws CodingException
- {
- if (numFields < 0 || (numFields * width + offset) > data.length) {
- // Try to decode the max number of characters in payload
- int padding = offset % width;
- int maxNumFields = (data.length - offset - padding) / width;
- if (maxNumFields < 0) {
- throw new CodingException(charset + " decode failed: offset out of range");
- }
- Rlog.e(LOG_TAG, charset + " decode error: offset = " + offset + " numFields = "
- + numFields + " data.length = " + data.length + " maxNumFields = "
- + maxNumFields);
- numFields = maxNumFields;
- }
- try {
- return new String(data, offset, numFields * width, charset);
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException(charset + " decode failed: " + ex);
- }
- }
-
- private static String decode7bitAscii(byte[] data, int offset, int numFields)
- throws CodingException
- {
- try {
- offset *= 8;
- StringBuffer strBuf = new StringBuffer(numFields);
- BitwiseInputStream inStream = new BitwiseInputStream(data);
- int wantedBits = (offset * 8) + (numFields * 7);
- if (inStream.available() < wantedBits) {
- throw new CodingException("insufficient data (wanted " + wantedBits +
- " bits, but only have " + inStream.available() + ")");
- }
- inStream.skip(offset);
- for (int i = 0; i < numFields; i++) {
- int charCode = inStream.read(7);
- if ((charCode >= UserData.ASCII_MAP_BASE_INDEX) &&
- (charCode <= UserData.ASCII_MAP_MAX_INDEX)) {
- strBuf.append(UserData.ASCII_MAP[charCode - UserData.ASCII_MAP_BASE_INDEX]);
- } else if (charCode == UserData.ASCII_NL_INDEX) {
- strBuf.append('\n');
- } else if (charCode == UserData.ASCII_CR_INDEX) {
- strBuf.append('\r');
- } else {
- /* For other charCodes, they are unprintable, and so simply use SPACE. */
- strBuf.append(' ');
- }
- }
- return strBuf.toString();
- } catch (BitwiseInputStream.AccessException ex) {
- throw new CodingException("7bit ASCII decode failed: " + ex);
- }
- }
-
- private static String decode7bitGsm(byte[] data, int offset, int numFields)
- throws CodingException
- {
- // Start reading from the next 7-bit aligned boundary after offset.
- int offsetBits = offset * 8;
- int offsetSeptets = (offsetBits + 6) / 7;
- numFields -= offsetSeptets;
- int paddingBits = (offsetSeptets * 7) - offsetBits;
- String result = GsmAlphabet.gsm7BitPackedToString(data, offset, numFields, paddingBits,
- 0, 0);
- if (result == null) {
- throw new CodingException("7bit GSM decoding failed");
- }
- return result;
- }
-
- private static String decodeLatin(byte[] data, int offset, int numFields)
- throws CodingException
- {
- return decodeCharset(data, offset, numFields, 1, "ISO-8859-1");
- }
-
- private static String decodeShiftJis(byte[] data, int offset, int numFields)
- throws CodingException
- {
- return decodeCharset(data, offset, numFields, 1, "Shift_JIS");
- }
-
- private static void decodeUserDataPayload(UserData userData, boolean hasUserDataHeader)
- throws CodingException
- {
- int offset = 0;
- if (hasUserDataHeader) {
- int udhLen = userData.payload[0] & 0x00FF;
- offset += udhLen + 1;
- byte[] headerData = new byte[udhLen];
- System.arraycopy(userData.payload, 1, headerData, 0, udhLen);
- userData.userDataHeader = SmsHeader.fromByteArray(headerData);
- }
- switch (userData.msgEncoding) {
- case UserData.ENCODING_OCTET:
- /*
- * Octet decoding depends on the carrier service.
- */
- boolean decodingtypeUTF8 = Resources.getSystem()
- .getBoolean(com.android.internal.R.bool.config_sms_utf8_support);
-
- // Strip off any padding bytes, meaning any differences between the length of the
- // array and the target length specified by numFields. This is to avoid any
- // confusion by code elsewhere that only considers the payload array length.
- byte[] payload = new byte[userData.numFields];
- int copyLen = userData.numFields < userData.payload.length
- ? userData.numFields : userData.payload.length;
-
- System.arraycopy(userData.payload, 0, payload, 0, copyLen);
- userData.payload = payload;
-
- if (!decodingtypeUTF8) {
- // There are many devices in the market that send 8bit text sms (latin encoded) as
- // octet encoded.
- userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
- } else {
- userData.payloadStr = decodeUtf8(userData.payload, offset, userData.numFields);
- }
- break;
-
- case UserData.ENCODING_IA5:
- case UserData.ENCODING_7BIT_ASCII:
- userData.payloadStr = decode7bitAscii(userData.payload, offset, userData.numFields);
- break;
- case UserData.ENCODING_UNICODE_16:
- userData.payloadStr = decodeUtf16(userData.payload, offset, userData.numFields);
- break;
- case UserData.ENCODING_GSM_7BIT_ALPHABET:
- userData.payloadStr = decode7bitGsm(userData.payload, offset, userData.numFields);
- break;
- case UserData.ENCODING_LATIN:
- userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
- break;
- case UserData.ENCODING_SHIFT_JIS:
- userData.payloadStr = decodeShiftJis(userData.payload, offset, userData.numFields);
- break;
- default:
- throw new CodingException("unsupported user data encoding ("
- + userData.msgEncoding + ")");
- }
- }
-
- /**
- * IS-91 Voice Mail message decoding
- * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1)
- * (For character encodings, see TIA/EIA/IS-91, Annex B)
- *
- * Protocol Summary: The user data payload may contain 3-14
- * characters. The first two characters are parsed as a number
- * and indicate the number of voicemails. The third character is
- * either a SPACE or '!' to indicate normal or urgent priority,
- * respectively. Any following characters are treated as normal
- * text user data payload.
- *
- * Note that the characters encoding is 6-bit packed.
- */
- private static void decodeIs91VoicemailStatus(BearerData bData)
- throws BitwiseInputStream.AccessException, CodingException
- {
- BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
- int dataLen = inStream.available() / 6; // 6-bit packed character encoding.
- int numFields = bData.userData.numFields;
- if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) {
- throw new CodingException("IS-91 voicemail status decoding failed");
- }
- try {
- StringBuffer strbuf = new StringBuffer(dataLen);
- while (inStream.available() >= 6) {
- strbuf.append(UserData.ASCII_MAP[inStream.read(6)]);
- }
- String data = strbuf.toString();
- bData.numberOfMessages = Integer.parseInt(data.substring(0, 2));
- char prioCode = data.charAt(2);
- if (prioCode == ' ') {
- bData.priority = PRIORITY_NORMAL;
- } else if (prioCode == '!') {
- bData.priority = PRIORITY_URGENT;
- } else {
- throw new CodingException("IS-91 voicemail status decoding failed: " +
- "illegal priority setting (" + prioCode + ")");
- }
- bData.priorityIndicatorSet = true;
- bData.userData.payloadStr = data.substring(3, numFields - 3);
- } catch (java.lang.NumberFormatException ex) {
- throw new CodingException("IS-91 voicemail status decoding failed: " + ex);
- } catch (java.lang.IndexOutOfBoundsException ex) {
- throw new CodingException("IS-91 voicemail status decoding failed: " + ex);
- }
- }
-
- /**
- * IS-91 Short Message decoding
- * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1)
- * (For character encodings, see TIA/EIA/IS-91, Annex B)
- *
- * Protocol Summary: The user data payload may contain 1-14
- * characters, which are treated as normal text user data payload.
- * Note that the characters encoding is 6-bit packed.
- */
- private static void decodeIs91ShortMessage(BearerData bData)
- throws BitwiseInputStream.AccessException, CodingException
- {
- BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
- int dataLen = inStream.available() / 6; // 6-bit packed character encoding.
- int numFields = bData.userData.numFields;
- // dataLen may be > 14 characters due to octet padding
- if ((numFields > 14) || (dataLen < numFields)) {
- throw new CodingException("IS-91 short message decoding failed");
- }
- StringBuffer strbuf = new StringBuffer(dataLen);
- for (int i = 0; i < numFields; i++) {
- strbuf.append(UserData.ASCII_MAP[inStream.read(6)]);
- }
- bData.userData.payloadStr = strbuf.toString();
- }
-
- /**
- * IS-91 CLI message (callback number) decoding
- * (See 3GPP2 C.S0015-A, Table 4.3.1.4.1-1)
- *
- * Protocol Summary: The data payload may contain 1-32 digits,
- * encoded using standard 4-bit DTMF, which are treated as a
- * callback number.
- */
- private static void decodeIs91Cli(BearerData bData) throws CodingException {
- BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
- int dataLen = inStream.available() / 4; // 4-bit packed DTMF digit encoding.
- int numFields = bData.userData.numFields;
- if ((dataLen > 14) || (dataLen < 3) || (dataLen < numFields)) {
- throw new CodingException("IS-91 voicemail status decoding failed");
- }
- CdmaSmsAddress addr = new CdmaSmsAddress();
- addr.digitMode = CdmaSmsAddress.DIGIT_MODE_4BIT_DTMF;
- addr.origBytes = bData.userData.payload;
- addr.numberOfDigits = (byte)numFields;
- decodeSmsAddress(addr);
- bData.callbackNumber = addr;
- }
-
- private static void decodeIs91(BearerData bData)
- throws BitwiseInputStream.AccessException, CodingException
- {
- switch (bData.userData.msgType) {
- case UserData.IS91_MSG_TYPE_VOICEMAIL_STATUS:
- decodeIs91VoicemailStatus(bData);
- break;
- case UserData.IS91_MSG_TYPE_CLI:
- decodeIs91Cli(bData);
- break;
- case UserData.IS91_MSG_TYPE_SHORT_MESSAGE_FULL:
- case UserData.IS91_MSG_TYPE_SHORT_MESSAGE:
- decodeIs91ShortMessage(bData);
- break;
- default:
- throw new CodingException("unsupported IS-91 message type (" +
- bData.userData.msgType + ")");
- }
- }
-
- private static boolean decodeReplyOption(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.userAckReq = (inStream.read(1) == 1);
- bData.deliveryAckReq = (inStream.read(1) == 1);
- bData.readAckReq = (inStream.read(1) == 1);
- bData.reportReq = (inStream.read(1) == 1);
- inStream.skip(4);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "REPLY_OPTION decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- return decodeSuccess;
- }
-
- private static boolean decodeMsgCount(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.numberOfMessages = IccUtils.cdmaBcdByteToInt((byte)inStream.read(8));
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "NUMBER_OF_MESSAGES decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- return decodeSuccess;
- }
-
- private static boolean decodeDepositIndex(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 2 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.depositIndex = (inStream.read(8) << 8) | inStream.read(8);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "MESSAGE_DEPOSIT_INDEX decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- return decodeSuccess;
- }
-
- private static String decodeDtmfSmsAddress(byte[] rawData, int numFields)
- throws CodingException
- {
- /* DTMF 4-bit digit encoding, defined in at
- * 3GPP2 C.S005-D, v2.0, table 2.7.1.3.2.4-4 */
- StringBuffer strBuf = new StringBuffer(numFields);
- for (int i = 0; i < numFields; i++) {
- int val = 0x0F & (rawData[i / 2] >>> (4 - ((i % 2) * 4)));
- if ((val >= 1) && (val <= 9)) strBuf.append(Integer.toString(val, 10));
- else if (val == 10) strBuf.append('0');
- else if (val == 11) strBuf.append('*');
- else if (val == 12) strBuf.append('#');
- else throw new CodingException("invalid SMS address DTMF code (" + val + ")");
- }
- return strBuf.toString();
- }
-
- private static void decodeSmsAddress(CdmaSmsAddress addr) throws CodingException {
- if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
- try {
- /* As specified in 3GPP2 C.S0015-B, v2, 4.5.15 -- actually
- * just 7-bit ASCII encoding, with the MSB being zero. */
- addr.address = new String(addr.origBytes, 0, addr.origBytes.length, "US-ASCII");
- } catch (java.io.UnsupportedEncodingException ex) {
- throw new CodingException("invalid SMS address ASCII code");
- }
- } else {
- addr.address = decodeDtmfSmsAddress(addr.origBytes, addr.numberOfDigits);
- }
- }
-
- private static boolean decodeCallbackNumber(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException, CodingException
- {
- final int EXPECTED_PARAM_SIZE = 1 * 8; //at least
- int paramBits = inStream.read(8) * 8;
- if (paramBits < EXPECTED_PARAM_SIZE) {
- inStream.skip(paramBits);
- return false;
- }
- CdmaSmsAddress addr = new CdmaSmsAddress();
- addr.digitMode = inStream.read(1);
- byte fieldBits = 4;
- byte consumedBits = 1;
- if (addr.digitMode == CdmaSmsAddress.DIGIT_MODE_8BIT_CHAR) {
- addr.ton = inStream.read(3);
- addr.numberPlan = inStream.read(4);
- fieldBits = 8;
- consumedBits += 7;
- }
- addr.numberOfDigits = inStream.read(8);
- consumedBits += 8;
- int remainingBits = paramBits - consumedBits;
- int dataBits = addr.numberOfDigits * fieldBits;
- int paddingBits = remainingBits - dataBits;
- if (remainingBits < dataBits) {
- throw new CodingException("CALLBACK_NUMBER subparam encoding size error (" +
- "remainingBits + " + remainingBits + ", dataBits + " +
- dataBits + ", paddingBits + " + paddingBits + ")");
- }
- addr.origBytes = inStream.readByteArray(dataBits);
- inStream.skip(paddingBits);
- decodeSmsAddress(addr);
- bData.callbackNumber = addr;
- return true;
- }
-
- private static boolean decodeMsgStatus(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.errorClass = inStream.read(2);
- bData.messageStatus = inStream.read(6);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "MESSAGE_STATUS decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- bData.messageStatusSet = decodeSuccess;
- return decodeSuccess;
- }
-
- private static boolean decodeMsgCenterTimeStamp(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 6 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.msgCenterTimeStamp = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "MESSAGE_CENTER_TIME_STAMP decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- return decodeSuccess;
- }
-
- private static boolean decodeValidityAbs(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 6 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.validityPeriodAbsolute = TimeStamp.fromByteArray(inStream.readByteArray(6 * 8));
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "VALIDITY_PERIOD_ABSOLUTE decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- return decodeSuccess;
- }
-
- private static boolean decodeDeferredDeliveryAbs(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 6 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.deferredDeliveryTimeAbsolute = TimeStamp.fromByteArray(
- inStream.readByteArray(6 * 8));
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_ABSOLUTE decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- return decodeSuccess;
- }
-
- private static boolean decodeValidityRel(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.deferredDeliveryTimeRelative = inStream.read(8);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "VALIDITY_PERIOD_RELATIVE decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- bData.deferredDeliveryTimeRelativeSet = decodeSuccess;
- return decodeSuccess;
- }
-
- private static boolean decodeDeferredDeliveryRel(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.validityPeriodRelative = inStream.read(8);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "DEFERRED_DELIVERY_TIME_RELATIVE decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- bData.validityPeriodRelativeSet = decodeSuccess;
- return decodeSuccess;
- }
-
- private static boolean decodePrivacyIndicator(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.privacy = inStream.read(2);
- inStream.skip(6);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "PRIVACY_INDICATOR decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- bData.privacyIndicatorSet = decodeSuccess;
- return decodeSuccess;
- }
-
- private static boolean decodeLanguageIndicator(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.language = inStream.read(8);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "LANGUAGE_INDICATOR decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- bData.languageIndicatorSet = decodeSuccess;
- return decodeSuccess;
- }
-
- private static boolean decodeDisplayMode(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.displayMode = inStream.read(2);
- inStream.skip(6);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "DISPLAY_MODE decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- bData.displayModeSet = decodeSuccess;
- return decodeSuccess;
- }
-
- private static boolean decodePriorityIndicator(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.priority = inStream.read(2);
- inStream.skip(6);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "PRIORITY_INDICATOR decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- bData.priorityIndicatorSet = decodeSuccess;
- return decodeSuccess;
- }
-
- private static boolean decodeMsgDeliveryAlert(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.alert = inStream.read(2);
- inStream.skip(6);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "ALERT_ON_MESSAGE_DELIVERY decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- bData.alertIndicatorSet = decodeSuccess;
- return decodeSuccess;
- }
-
- private static boolean decodeUserResponseCode(BearerData bData, BitwiseInputStream inStream)
- throws BitwiseInputStream.AccessException {
- final int EXPECTED_PARAM_SIZE = 1 * 8;
- boolean decodeSuccess = false;
- int paramBits = inStream.read(8) * 8;
- if (paramBits >= EXPECTED_PARAM_SIZE) {
- paramBits -= EXPECTED_PARAM_SIZE;
- decodeSuccess = true;
- bData.userResponseCode = inStream.read(8);
- }
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "USER_RESPONSE_CODE decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ")");
- }
- inStream.skip(paramBits);
- bData.userResponseCodeSet = decodeSuccess;
- return decodeSuccess;
- }
-
- private static boolean decodeServiceCategoryProgramData(BearerData bData,
- BitwiseInputStream inStream) throws BitwiseInputStream.AccessException, CodingException
- {
- if (inStream.available() < 13) {
- throw new CodingException("SERVICE_CATEGORY_PROGRAM_DATA decode failed: only "
- + inStream.available() + " bits available");
- }
-
- int paramBits = inStream.read(8) * 8;
- int msgEncoding = inStream.read(5);
- paramBits -= 5;
-
- if (inStream.available() < paramBits) {
- throw new CodingException("SERVICE_CATEGORY_PROGRAM_DATA decode failed: only "
- + inStream.available() + " bits available (" + paramBits + " bits expected)");
- }
-
- ArrayList<CdmaSmsCbProgramData> programDataList = new ArrayList<CdmaSmsCbProgramData>();
-
- final int CATEGORY_FIELD_MIN_SIZE = 6 * 8;
- boolean decodeSuccess = false;
- while (paramBits >= CATEGORY_FIELD_MIN_SIZE) {
- int operation = inStream.read(4);
- int category = (inStream.read(8) << 8) | inStream.read(8);
- int language = inStream.read(8);
- int maxMessages = inStream.read(8);
- int alertOption = inStream.read(4);
- int numFields = inStream.read(8);
- paramBits -= CATEGORY_FIELD_MIN_SIZE;
-
- int textBits = getBitsForNumFields(msgEncoding, numFields);
- if (paramBits < textBits) {
- throw new CodingException("category name is " + textBits + " bits in length,"
- + " but there are only " + paramBits + " bits available");
- }
-
- UserData userData = new UserData();
- userData.msgEncoding = msgEncoding;
- userData.msgEncodingSet = true;
- userData.numFields = numFields;
- userData.payload = inStream.readByteArray(textBits);
- paramBits -= textBits;
-
- decodeUserDataPayload(userData, false);
- String categoryName = userData.payloadStr;
- CdmaSmsCbProgramData programData = new CdmaSmsCbProgramData(operation, category,
- language, maxMessages, alertOption, categoryName);
- programDataList.add(programData);
-
- decodeSuccess = true;
- }
-
- if ((! decodeSuccess) || (paramBits > 0)) {
- Rlog.d(LOG_TAG, "SERVICE_CATEGORY_PROGRAM_DATA decode " +
- (decodeSuccess ? "succeeded" : "failed") +
- " (extra bits = " + paramBits + ')');
- }
-
- inStream.skip(paramBits);
- bData.serviceCategoryProgramData = programDataList;
- return decodeSuccess;
- }
-
- private static int serviceCategoryToCmasMessageClass(int serviceCategory) {
- switch (serviceCategory) {
- case SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT:
- return SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT;
-
- case SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT:
- return SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT;
-
- case SmsEnvelope.SERVICE_CATEGORY_CMAS_SEVERE_THREAT:
- return SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT;
-
- case SmsEnvelope.SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY:
- return SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY;
-
- case SmsEnvelope.SERVICE_CATEGORY_CMAS_TEST_MESSAGE:
- return SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST;
-
- default:
- return SmsCbCmasInfo.CMAS_CLASS_UNKNOWN;
- }
- }
-
- /**
- * Calculates the number of bits to read for the specified number of encoded characters.
- * @param msgEncoding the message encoding to use
- * @param numFields the number of characters to read. For Shift-JIS and Korean encodings,
- * this is the number of bytes to read.
- * @return the number of bits to read from the stream
- * @throws CodingException if the specified encoding is not supported
- */
- private static int getBitsForNumFields(int msgEncoding, int numFields)
- throws CodingException {
- switch (msgEncoding) {
- case UserData.ENCODING_OCTET:
- case UserData.ENCODING_SHIFT_JIS:
- case UserData.ENCODING_KOREAN:
- case UserData.ENCODING_LATIN:
- case UserData.ENCODING_LATIN_HEBREW:
- return numFields * 8;
-
- case UserData.ENCODING_IA5:
- case UserData.ENCODING_7BIT_ASCII:
- case UserData.ENCODING_GSM_7BIT_ALPHABET:
- return numFields * 7;
-
- case UserData.ENCODING_UNICODE_16:
- return numFields * 16;
-
- default:
- throw new CodingException("unsupported message encoding (" + msgEncoding + ')');
- }
- }
-
- /**
- * CMAS message decoding.
- * (See TIA-1149-0-1, CMAS over CDMA)
- *
- * @param serviceCategory is the service category from the SMS envelope
- */
- private static void decodeCmasUserData(BearerData bData, int serviceCategory)
- throws BitwiseInputStream.AccessException, CodingException {
- BitwiseInputStream inStream = new BitwiseInputStream(bData.userData.payload);
- if (inStream.available() < 8) {
- throw new CodingException("emergency CB with no CMAE_protocol_version");
- }
- int protocolVersion = inStream.read(8);
- if (protocolVersion != 0) {
- throw new CodingException("unsupported CMAE_protocol_version " + protocolVersion);
- }
-
- int messageClass = serviceCategoryToCmasMessageClass(serviceCategory);
- int category = SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN;
- int responseType = SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN;
- int severity = SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN;
- int urgency = SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN;
- int certainty = SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN;
-
- while (inStream.available() >= 16) {
- int recordType = inStream.read(8);
- int recordLen = inStream.read(8);
- switch (recordType) {
- case 0: // Type 0 elements (Alert text)
- UserData alertUserData = new UserData();
- alertUserData.msgEncoding = inStream.read(5);
- alertUserData.msgEncodingSet = true;
- alertUserData.msgType = 0;
-
- int numFields; // number of chars to decode
- switch (alertUserData.msgEncoding) {
- case UserData.ENCODING_OCTET:
- case UserData.ENCODING_LATIN:
- numFields = recordLen - 1; // subtract 1 byte for encoding
- break;
-
- case UserData.ENCODING_IA5:
- case UserData.ENCODING_7BIT_ASCII:
- case UserData.ENCODING_GSM_7BIT_ALPHABET:
- numFields = ((recordLen * 8) - 5) / 7; // subtract 5 bits for encoding
- break;
-
- case UserData.ENCODING_UNICODE_16:
- numFields = (recordLen - 1) / 2;
- break;
-
- default:
- numFields = 0; // unsupported encoding
- }
-
- alertUserData.numFields = numFields;
- alertUserData.payload = inStream.readByteArray(recordLen * 8 - 5);
- decodeUserDataPayload(alertUserData, false);
- bData.userData = alertUserData;
- break;
-
- case 1: // Type 1 elements
- category = inStream.read(8);
- responseType = inStream.read(8);
- severity = inStream.read(4);
- urgency = inStream.read(4);
- certainty = inStream.read(4);
- inStream.skip(recordLen * 8 - 28);
- break;
-
- default:
- Rlog.w(LOG_TAG, "skipping unsupported CMAS record type " + recordType);
- inStream.skip(recordLen * 8);
- break;
- }
- }
-
- bData.cmasWarningInfo = new SmsCbCmasInfo(messageClass, category, responseType, severity,
- urgency, certainty);
- }
-
- /**
- * Create BearerData object from serialized representation.
- * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
- *
- * @param smsData byte array of raw encoded SMS bearer data.
- * @return an instance of BearerData.
- */
- public static BearerData decode(byte[] smsData) {
- return decode(smsData, 0);
- }
-
- private static boolean isCmasAlertCategory(int category) {
- return category >= SmsEnvelope.SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT
- && category <= SmsEnvelope.SERVICE_CATEGORY_CMAS_LAST_RESERVED_VALUE;
- }
-
- /**
- * Create BearerData object from serialized representation.
- * (See 3GPP2 C.R1001-F, v1.0, section 4.5 for layout details)
- *
- * @param smsData byte array of raw encoded SMS bearer data.
- * @param serviceCategory the envelope service category (for CMAS alert handling)
- * @return an instance of BearerData.
- */
- public static BearerData decode(byte[] smsData, int serviceCategory) {
- try {
- BitwiseInputStream inStream = new BitwiseInputStream(smsData);
- BearerData bData = new BearerData();
- int foundSubparamMask = 0;
- while (inStream.available() > 0) {
- int subparamId = inStream.read(8);
- int subparamIdBit = 1 << subparamId;
- // int is 4 bytes. This duplicate check has a limit to Id number up to 32 (4*8)
- // as 32th bit is the max bit in int.
- // Per 3GPP2 C.S0015-B Table 4.5-1 Bearer Data Subparameter Identifiers:
- // last defined subparam ID is 23 (00010111 = 0x17 = 23).
- // Only do duplicate subparam ID check if subparam is within defined value as
- // reserved subparams are just skipped.
- if ((foundSubparamMask & subparamIdBit) != 0 &&
- (subparamId >= SUBPARAM_MESSAGE_IDENTIFIER &&
- subparamId <= SUBPARAM_ID_LAST_DEFINED)) {
- throw new CodingException("illegal duplicate subparameter (" +
- subparamId + ")");
- }
- boolean decodeSuccess;
- switch (subparamId) {
- case SUBPARAM_MESSAGE_IDENTIFIER:
- decodeSuccess = decodeMessageId(bData, inStream);
- break;
- case SUBPARAM_USER_DATA:
- decodeSuccess = decodeUserData(bData, inStream);
- break;
- case SUBPARAM_USER_RESPONSE_CODE:
- decodeSuccess = decodeUserResponseCode(bData, inStream);
- break;
- case SUBPARAM_REPLY_OPTION:
- decodeSuccess = decodeReplyOption(bData, inStream);
- break;
- case SUBPARAM_NUMBER_OF_MESSAGES:
- decodeSuccess = decodeMsgCount(bData, inStream);
- break;
- case SUBPARAM_CALLBACK_NUMBER:
- decodeSuccess = decodeCallbackNumber(bData, inStream);
- break;
- case SUBPARAM_MESSAGE_STATUS:
- decodeSuccess = decodeMsgStatus(bData, inStream);
- break;
- case SUBPARAM_MESSAGE_CENTER_TIME_STAMP:
- decodeSuccess = decodeMsgCenterTimeStamp(bData, inStream);
- break;
- case SUBPARAM_VALIDITY_PERIOD_ABSOLUTE:
- decodeSuccess = decodeValidityAbs(bData, inStream);
- break;
- case SUBPARAM_VALIDITY_PERIOD_RELATIVE:
- decodeSuccess = decodeValidityRel(bData, inStream);
- break;
- case SUBPARAM_DEFERRED_DELIVERY_TIME_ABSOLUTE:
- decodeSuccess = decodeDeferredDeliveryAbs(bData, inStream);
- break;
- case SUBPARAM_DEFERRED_DELIVERY_TIME_RELATIVE:
- decodeSuccess = decodeDeferredDeliveryRel(bData, inStream);
- break;
- case SUBPARAM_PRIVACY_INDICATOR:
- decodeSuccess = decodePrivacyIndicator(bData, inStream);
- break;
- case SUBPARAM_LANGUAGE_INDICATOR:
- decodeSuccess = decodeLanguageIndicator(bData, inStream);
- break;
- case SUBPARAM_MESSAGE_DISPLAY_MODE:
- decodeSuccess = decodeDisplayMode(bData, inStream);
- break;
- case SUBPARAM_PRIORITY_INDICATOR:
- decodeSuccess = decodePriorityIndicator(bData, inStream);
- break;
- case SUBPARAM_ALERT_ON_MESSAGE_DELIVERY:
- decodeSuccess = decodeMsgDeliveryAlert(bData, inStream);
- break;
- case SUBPARAM_MESSAGE_DEPOSIT_INDEX:
- decodeSuccess = decodeDepositIndex(bData, inStream);
- break;
- case SUBPARAM_SERVICE_CATEGORY_PROGRAM_DATA:
- decodeSuccess = decodeServiceCategoryProgramData(bData, inStream);
- break;
- default:
- decodeSuccess = decodeReserved(bData, inStream, subparamId);
- }
- if (decodeSuccess &&
- (subparamId >= SUBPARAM_MESSAGE_IDENTIFIER &&
- subparamId <= SUBPARAM_ID_LAST_DEFINED)) {
- foundSubparamMask |= subparamIdBit;
- }
- }
- if ((foundSubparamMask & (1 << SUBPARAM_MESSAGE_IDENTIFIER)) == 0) {
- throw new CodingException("missing MESSAGE_IDENTIFIER subparam");
- }
- if (bData.userData != null) {
- if (isCmasAlertCategory(serviceCategory)) {
- decodeCmasUserData(bData, serviceCategory);
- } else if (bData.userData.msgEncoding == UserData.ENCODING_IS91_EXTENDED_PROTOCOL) {
- if ((foundSubparamMask ^
- (1 << SUBPARAM_MESSAGE_IDENTIFIER) ^
- (1 << SUBPARAM_USER_DATA))
- != 0) {
- Rlog.e(LOG_TAG, "IS-91 must occur without extra subparams (" +
- foundSubparamMask + ")");
- }
- decodeIs91(bData);
- } else {
- decodeUserDataPayload(bData.userData, bData.hasUserDataHeader);
- }
- }
- return bData;
- } catch (BitwiseInputStream.AccessException ex) {
- Rlog.e(LOG_TAG, "BearerData decode failed: " + ex);
- } catch (CodingException ex) {
- Rlog.e(LOG_TAG, "BearerData decode failed: " + ex);
- }
- return null;
- }
-}
diff --git a/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java b/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
deleted file mode 100644
index 5f2e561..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsAddress.java
+++ /dev/null
@@ -1,228 +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 com.android.internal.telephony.cdma.sms;
-
-import android.util.SparseBooleanArray;
-
-import com.android.internal.telephony.SmsAddress;
-import com.android.internal.telephony.cdma.sms.UserData;
-import com.android.internal.util.HexDump;
-
-public class CdmaSmsAddress extends SmsAddress {
-
- /**
- * Digit Mode Indicator is a 1-bit value that indicates whether
- * the address digits are 4-bit DTMF codes or 8-bit codes. (See
- * 3GPP2 C.S0015-B, v2, 3.4.3.3)
- */
- static public final int DIGIT_MODE_4BIT_DTMF = 0x00;
- static public final int DIGIT_MODE_8BIT_CHAR = 0x01;
-
- public int digitMode;
-
- /**
- * Number Mode Indicator is 1-bit value that indicates whether the
- * address type is a data network address or not. (See 3GPP2
- * C.S0015-B, v2, 3.4.3.3)
- */
- static public final int NUMBER_MODE_NOT_DATA_NETWORK = 0x00;
- static public final int NUMBER_MODE_DATA_NETWORK = 0x01;
-
- public int numberMode;
-
- /**
- * Number Types for data networks.
- * (See 3GPP2 C.S005-D, table2.7.1.3.2.4-2 for complete table)
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.3 for data network subset)
- * NOTE: value is stored in the parent class ton field.
- */
- static public final int TON_UNKNOWN = 0x00;
- static public final int TON_INTERNATIONAL_OR_IP = 0x01;
- static public final int TON_NATIONAL_OR_EMAIL = 0x02;
- static public final int TON_NETWORK = 0x03;
- static public final int TON_SUBSCRIBER = 0x04;
- static public final int TON_ALPHANUMERIC = 0x05;
- static public final int TON_ABBREVIATED = 0x06;
- static public final int TON_RESERVED = 0x07;
-
- /**
- * Maximum lengths for fields as defined in ril_cdma_sms.h.
- */
- static public final int SMS_ADDRESS_MAX = 36;
- static public final int SMS_SUBADDRESS_MAX = 36;
-
- /**
- * This field shall be set to the number of address digits
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
- */
- public int numberOfDigits;
-
- /**
- * Numbering Plan identification is a 0 or 4-bit value that
- * indicates which numbering plan identification is set. (See
- * 3GPP2, C.S0015-B, v2, 3.4.3.3 and C.S005-D, table2.7.1.3.2.4-3)
- */
- static public final int NUMBERING_PLAN_UNKNOWN = 0x0;
- static public final int NUMBERING_PLAN_ISDN_TELEPHONY = 0x1;
- //static protected final int NUMBERING_PLAN_DATA = 0x3;
- //static protected final int NUMBERING_PLAN_TELEX = 0x4;
- //static protected final int NUMBERING_PLAN_PRIVATE = 0x9;
-
- public int numberPlan;
-
- /**
- * NOTE: the parsed string address and the raw byte array values
- * are stored in the parent class address and origBytes fields,
- * respectively.
- */
-
- public CdmaSmsAddress(){
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("CdmaSmsAddress ");
- builder.append("{ digitMode=" + digitMode);
- builder.append(", numberMode=" + numberMode);
- builder.append(", numberPlan=" + numberPlan);
- builder.append(", numberOfDigits=" + numberOfDigits);
- builder.append(", ton=" + ton);
- builder.append(", address=\"" + address + "\"");
- builder.append(", origBytes=" + HexDump.toHexString(origBytes));
- builder.append(" }");
- return builder.toString();
- }
-
- /*
- * TODO(cleanup): Refactor the parsing for addresses to better
- * share code and logic with GSM. Also, gather all DTMF/BCD
- * processing code in one place.
- */
-
- private static byte[] parseToDtmf(String address) {
- int digits = address.length();
- byte[] result = new byte[digits];
- for (int i = 0; i < digits; i++) {
- char c = address.charAt(i);
- int val = 0;
- if ((c >= '1') && (c <= '9')) val = c - '0';
- else if (c == '0') val = 10;
- else if (c == '*') val = 11;
- else if (c == '#') val = 12;
- else return null;
- result[i] = (byte)val;
- }
- return result;
- }
-
- private static final char[] numericCharsDialable = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '#'
- };
-
- private static final char[] numericCharsSugar = {
- '(', ')', ' ', '-', '+', '.', '/', '\\'
- };
-
- private static final SparseBooleanArray numericCharDialableMap = new SparseBooleanArray (
- numericCharsDialable.length + numericCharsSugar.length);
- static {
- for (int i = 0; i < numericCharsDialable.length; i++) {
- numericCharDialableMap.put(numericCharsDialable[i], true);
- }
- for (int i = 0; i < numericCharsSugar.length; i++) {
- numericCharDialableMap.put(numericCharsSugar[i], false);
- }
- }
-
- /**
- * Given a numeric address string, return the string without
- * syntactic sugar, meaning parens, spaces, hyphens/minuses, or
- * plus signs. If the input string contains non-numeric
- * non-punctuation characters, return null.
- */
- private static String filterNumericSugar(String address) {
- StringBuilder builder = new StringBuilder();
- int len = address.length();
- for (int i = 0; i < len; i++) {
- char c = address.charAt(i);
- int mapIndex = numericCharDialableMap.indexOfKey(c);
- if (mapIndex < 0) return null;
- if (! numericCharDialableMap.valueAt(mapIndex)) continue;
- builder.append(c);
- }
- return builder.toString();
- }
-
- /**
- * Given a string, return the string without whitespace,
- * including CR/LF.
- */
- private static String filterWhitespace(String address) {
- StringBuilder builder = new StringBuilder();
- int len = address.length();
- for (int i = 0; i < len; i++) {
- char c = address.charAt(i);
- if ((c == ' ') || (c == '\r') || (c == '\n') || (c == '\t')) continue;
- builder.append(c);
- }
- return builder.toString();
- }
-
- /**
- * Given a string, create a corresponding CdmaSmsAddress object.
- *
- * The result will be null if the input string is not
- * representable using printable ASCII.
- *
- * For numeric addresses, the string is cleaned up by removing
- * common punctuation. For alpha addresses, the string is cleaned
- * up by removing whitespace.
- */
- public static CdmaSmsAddress parse(String address) {
- CdmaSmsAddress addr = new CdmaSmsAddress();
- addr.address = address;
- addr.ton = CdmaSmsAddress.TON_UNKNOWN;
- byte[] origBytes = null;
- String filteredAddr = filterNumericSugar(address);
- if (filteredAddr != null) {
- origBytes = parseToDtmf(filteredAddr);
- }
- if (origBytes != null) {
- addr.digitMode = DIGIT_MODE_4BIT_DTMF;
- addr.numberMode = NUMBER_MODE_NOT_DATA_NETWORK;
- if (address.indexOf('+') != -1) {
- addr.ton = TON_INTERNATIONAL_OR_IP;
- }
- } else {
- filteredAddr = filterWhitespace(address);
- origBytes = UserData.stringToAscii(filteredAddr);
- if (origBytes == null) {
- return null;
- }
- addr.digitMode = DIGIT_MODE_8BIT_CHAR;
- addr.numberMode = NUMBER_MODE_DATA_NETWORK;
- if (address.indexOf('@') != -1) {
- addr.ton = TON_NATIONAL_OR_EMAIL;
- }
- }
- addr.origBytes = origBytes;
- addr.numberOfDigits = origBytes.length;
- return addr;
- }
-
-}
diff --git a/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java b/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java
deleted file mode 100644
index 0d5b502..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/CdmaSmsSubaddress.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.cdma.sms;
-
-public class CdmaSmsSubaddress {
- public int type;
-
- public byte odd;
-
- public byte[] origBytes;
-}
-
diff --git a/src/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java b/src/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
deleted file mode 100644
index f73df56..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/SmsEnvelope.java
+++ /dev/null
@@ -1,130 +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 com.android.internal.telephony.cdma.sms;
-
-
-import com.android.internal.telephony.cdma.sms.CdmaSmsSubaddress;
-
-public final class SmsEnvelope {
- /**
- * Message Types
- * (See 3GPP2 C.S0015-B 3.4.1)
- */
- static public final int MESSAGE_TYPE_POINT_TO_POINT = 0x00;
- static public final int MESSAGE_TYPE_BROADCAST = 0x01;
- static public final int MESSAGE_TYPE_ACKNOWLEDGE = 0x02;
-
- /**
- * Supported Teleservices
- * (See 3GPP2 N.S0005 and TIA-41)
- */
- static public final int TELESERVICE_NOT_SET = 0x0000;
- static public final int TELESERVICE_WMT = 0x1002;
- static public final int TELESERVICE_VMN = 0x1003;
- static public final int TELESERVICE_WAP = 0x1004;
- static public final int TELESERVICE_WEMT = 0x1005;
- static public final int TELESERVICE_SCPT = 0x1006;
-
- /**
- * The following are defined as extensions to the standard teleservices
- */
- // Voice mail notification through Message Waiting Indication in CDMA mode or Analog mode.
- // Defined in 3GPP2 C.S-0005, 3.7.5.6, an Info Record containing an 8-bit number with the
- // number of messages waiting, it's used by some CDMA carriers for a voice mail count.
- static public final int TELESERVICE_MWI = 0x40000;
-
- // Service Categories for Cell Broadcast, see 3GPP2 C.R1001 table 9.3.1-1
- // static final int SERVICE_CATEGORY_EMERGENCY = 0x0001;
- //...
-
- // CMAS alert service category assignments, see 3GPP2 C.R1001 table 9.3.3-1
- public static final int SERVICE_CATEGORY_CMAS_PRESIDENTIAL_LEVEL_ALERT = 0x1000;
- public static final int SERVICE_CATEGORY_CMAS_EXTREME_THREAT = 0x1001;
- public static final int SERVICE_CATEGORY_CMAS_SEVERE_THREAT = 0x1002;
- public static final int SERVICE_CATEGORY_CMAS_CHILD_ABDUCTION_EMERGENCY = 0x1003;
- public static final int SERVICE_CATEGORY_CMAS_TEST_MESSAGE = 0x1004;
- public static final int SERVICE_CATEGORY_CMAS_LAST_RESERVED_VALUE = 0x10ff;
-
- /**
- * Provides the type of a SMS message like point to point, broadcast or acknowledge
- */
- public int messageType;
-
- /**
- * The 16-bit Teleservice parameter identifies which upper layer service access point is sending
- * or receiving the message.
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.1)
- */
- public int teleService = TELESERVICE_NOT_SET;
-
- /**
- * The 16-bit service category parameter identifies the type of service provided
- * by the SMS message.
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.2)
- */
- public int serviceCategory;
-
- /**
- * The origination address identifies the originator of the SMS message.
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
- */
- public CdmaSmsAddress origAddress;
-
- /**
- * The destination address identifies the target of the SMS message.
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.3)
- */
- public CdmaSmsAddress destAddress;
-
- /**
- * The origination subaddress identifies the originator of the SMS message.
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.4)
- */
- public CdmaSmsSubaddress origSubaddress;
-
- /**
- * The 6-bit bearer reply parameter is used to request the return of a
- * SMS Acknowledge Message.
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.5)
- */
- public int bearerReply;
-
- /**
- * Cause Code values:
- * The cause code parameters are an indication whether an SMS error has occurred and if so,
- * whether the condition is considered temporary or permanent.
- * ReplySeqNo 6-bit value,
- * ErrorClass 2-bit value,
- * CauseCode 0-bit or 8-bit value
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.6)
- */
- public byte replySeqNo;
- public byte errorClass;
- public byte causeCode;
-
- /**
- * encoded bearer data
- * (See 3GPP2 C.S0015-B, v2, 3.4.3.7)
- */
- public byte[] bearerData;
-
- public SmsEnvelope() {
- // nothing to see here
- }
-
-}
-
diff --git a/src/java/com/android/internal/telephony/cdma/sms/UserData.java b/src/java/com/android/internal/telephony/cdma/sms/UserData.java
deleted file mode 100644
index 599c2b3..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/UserData.java
+++ /dev/null
@@ -1,165 +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 com.android.internal.telephony.cdma.sms;
-
-import android.util.SparseIntArray;
-
-import com.android.internal.telephony.SmsHeader;
-import com.android.internal.util.HexDump;
-
-public class UserData {
-
- /**
- * User data encoding types.
- * (See 3GPP2 C.R1001-F, v1.0, table 9.1-1)
- */
- public static final int ENCODING_OCTET = 0x00;
- public static final int ENCODING_IS91_EXTENDED_PROTOCOL = 0x01;
- public static final int ENCODING_7BIT_ASCII = 0x02;
- public static final int ENCODING_IA5 = 0x03;
- public static final int ENCODING_UNICODE_16 = 0x04;
- public static final int ENCODING_SHIFT_JIS = 0x05;
- public static final int ENCODING_KOREAN = 0x06;
- public static final int ENCODING_LATIN_HEBREW = 0x07;
- public static final int ENCODING_LATIN = 0x08;
- public static final int ENCODING_GSM_7BIT_ALPHABET = 0x09;
- public static final int ENCODING_GSM_DCS = 0x0A;
-
- /**
- * IS-91 message types.
- * (See TIA/EIS/IS-91-A-ENGL 1999, table 3.7.1.1-3)
- */
- public static final int IS91_MSG_TYPE_VOICEMAIL_STATUS = 0x82;
- public static final int IS91_MSG_TYPE_SHORT_MESSAGE_FULL = 0x83;
- public static final int IS91_MSG_TYPE_CLI = 0x84;
- public static final int IS91_MSG_TYPE_SHORT_MESSAGE = 0x85;
-
- /**
- * US ASCII character mapping table.
- *
- * This table contains only the printable ASCII characters, with a
- * 0x20 offset, meaning that the ASCII SPACE character is at index
- * 0, with the resulting code of 0x20.
- *
- * Note this mapping is also equivalent to that used by both the
- * IA5 and the IS-91 encodings. For the former this is defined
- * using CCITT Rec. T.50 Tables 1 and 3. For the latter IS 637 B,
- * Table 4.3.1.4.1-1 -- and note the encoding uses only 6 bits,
- * and hence only maps entries up to the '_' character.
- *
- */
- public static final char[] ASCII_MAP = {
- ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
- '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
- 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
- '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
- 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~'};
-
- /**
- * Character to use when forced to encode otherwise unencodable
- * characters, meaning those not in the respective ASCII or GSM
- * 7-bit encoding tables. Current choice is SPACE, which is 0x20
- * in both the GSM-7bit and ASCII-7bit encodings.
- */
- static final byte UNENCODABLE_7_BIT_CHAR = 0x20;
-
- /**
- * Only elements between these indices in the ASCII table are printable.
- */
- public static final int PRINTABLE_ASCII_MIN_INDEX = 0x20;
- public static final int ASCII_NL_INDEX = 0x0A;
- public static final int ASCII_CR_INDEX = 0x0D;
- public static final SparseIntArray charToAscii = new SparseIntArray();
- static {
- for (int i = 0; i < ASCII_MAP.length; i++) {
- charToAscii.put(ASCII_MAP[i], PRINTABLE_ASCII_MIN_INDEX + i);
- }
- charToAscii.put('\n', ASCII_NL_INDEX);
- charToAscii.put('\r', ASCII_CR_INDEX);
- }
-
- /*
- * TODO(cleanup): Move this very generic functionality somewhere
- * more general.
- */
- /**
- * Given a string generate a corresponding ASCII-encoded byte
- * array, but limited to printable characters. If the input
- * contains unprintable characters, return null.
- */
- public static byte[] stringToAscii(String str) {
- int len = str.length();
- byte[] result = new byte[len];
- for (int i = 0; i < len; i++) {
- int charCode = charToAscii.get(str.charAt(i), -1);
- if (charCode == -1) return null;
- result[i] = (byte)charCode;
- }
- return result;
- }
-
- /**
- * Mapping for ASCII values less than 32 are flow control signals
- * and not used here.
- */
- public static final int ASCII_MAP_BASE_INDEX = 0x20;
- public static final int ASCII_MAP_MAX_INDEX = ASCII_MAP_BASE_INDEX + ASCII_MAP.length - 1;
-
- /**
- * Contains the data header of the user data
- */
- public SmsHeader userDataHeader;
-
- /**
- * Contains the data encoding type for the SMS message
- */
- public int msgEncoding;
- public boolean msgEncodingSet = false;
-
- public int msgType;
-
- /**
- * Number of invalid bits in the last byte of data.
- */
- public int paddingBits;
-
- public int numFields;
-
- /**
- * Contains the user data of a SMS message
- * (See 3GPP2 C.S0015-B, v2, 4.5.2)
- */
- public byte[] payload;
- public String payloadStr;
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- builder.append("UserData ");
- builder.append("{ msgEncoding=" + (msgEncodingSet ? msgEncoding : "unset"));
- builder.append(", msgType=" + msgType);
- builder.append(", paddingBits=" + paddingBits);
- builder.append(", numFields=" + numFields);
- builder.append(", userDataHeader=" + userDataHeader);
- builder.append(", payload='" + HexDump.toHexString(payload) + "'");
- builder.append(", payloadStr='" + payloadStr + "'");
- builder.append(" }");
- return builder.toString();
- }
-
-}
diff --git a/src/java/com/android/internal/telephony/cdma/sms/package.html b/src/java/com/android/internal/telephony/cdma/sms/package.html
deleted file mode 100644
index b2bc736..0000000
--- a/src/java/com/android/internal/telephony/cdma/sms/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<BODY>
-Provides CDMA-specific features for text/data/PDU SMS messages
-@hide
-</BODY>
-</HTML>
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
index 7865bc4..3cd804d 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnContext.java
@@ -17,7 +17,6 @@
package com.android.internal.telephony.dataconnection;
import android.app.PendingIntent;
-import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
@@ -536,8 +535,8 @@
return mConnectionGeneration.get();
}
- public long getInterApnDelay(boolean failFastEnabled) {
- return mRetryManager.getInterApnDelay(failFastEnabled || isFastRetryReason());
+ long getRetryAfterDisconnectDelay() {
+ return mRetryManager.getRetryAfterDisconnectDelay();
}
public static int apnIdForType(int networkType) {
@@ -726,7 +725,7 @@
l.dump(fd, pw, args);
}
pw.decreaseIndent();
- pw.println("mRetryManager={" + mRetryManager.toString() + "}");
+ pw.println(mRetryManager);
}
}
}
diff --git a/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java b/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java
index 00c77bc..ce8318d 100644
--- a/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java
+++ b/src/java/com/android/internal/telephony/dataconnection/ApnSetting.java
@@ -24,6 +24,8 @@
import android.telephony.ServiceState;
import android.text.TextUtils;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.uicc.IccRecords;
@@ -32,6 +34,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
/**
* This class represents a apn setting for create PDP link
@@ -41,6 +44,7 @@
static final String LOG_TAG = "ApnSetting";
private static final boolean DBG = false;
+ private static final boolean VDBG = false;
static final String V2_FORMAT_REGEX = "^\\[ApnSettingV2\\]\\s*";
static final String V3_FORMAT_REGEX = "^\\[ApnSettingV3\\]\\s*";
@@ -404,15 +408,41 @@
return false;
}
- public static boolean isMeteredApnType(String type, Context context, int subId,
- boolean isRoaming) {
+ /**
+ * Check if this APN type is metered.
+ *
+ * @param type The APN type
+ * @param phone The phone object
+ * @return True if the APN type is metered, otherwise false.
+ */
+ public static boolean isMeteredApnType(String type, Phone phone) {
+ if (phone == null) {
+ return true;
+ }
- String carrierConfig = (isRoaming) ?
- CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS :
- CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS;
+ boolean isRoaming = phone.getServiceState().getDataRoaming();
+ boolean isIwlan = phone.getServiceState().getRilDataRadioTechnology()
+ == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+ int subId = phone.getSubId();
+
+ String carrierConfig;
+ // First check if the device is in IWLAN mode. If yes, use the IWLAN metered APN list. Then
+ // check if the device is roaming. If yes, use the roaming metered APN list. Otherwise, use
+ // the normal metered APN list.
+ if (isIwlan) {
+ carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS;
+ } else if (isRoaming) {
+ carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS;
+ } else {
+ carrierConfig = CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS;
+ }
+
+ if (DBG) {
+ Rlog.d(LOG_TAG, "isMeteredApnType: isRoaming=" + isRoaming + ", isIwlan=" + isIwlan);
+ }
CarrierConfigManager configManager = (CarrierConfigManager)
- context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
if (configManager == null) {
Rlog.e(LOG_TAG, "Carrier config service is not available");
return true;
@@ -432,44 +462,49 @@
HashSet<String> meteredApnSet = new HashSet<>(Arrays.asList(meteredApnTypes));
if (DBG) {
- Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " +
- Arrays.toString(meteredApnSet.toArray()) +
- " isRoaming: " + isRoaming);
+ Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are "
+ + Arrays.toString(meteredApnSet.toArray()));
}
// If all types of APN are metered, then this APN setting must be metered.
if (meteredApnSet.contains(PhoneConstants.APN_TYPE_ALL)) {
- if (DBG) Rlog.d(LOG_TAG, "All APN types are metered. isRoaming: " + isRoaming);
+ if (DBG) Rlog.d(LOG_TAG, "All APN types are metered.");
return true;
}
if (meteredApnSet.contains(type)) {
- if (DBG) Rlog.d(LOG_TAG, type + " is metered. isRoaming: " + isRoaming);
+ if (DBG) Rlog.d(LOG_TAG, type + " is metered.");
return true;
} else if (type.equals(PhoneConstants.APN_TYPE_ALL)) {
// Assuming no configuration error, if at least one APN type is
// metered, then this APN setting is metered.
if (meteredApnSet.size() > 0) {
- if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered. isRoaming: " +
- isRoaming);
+ if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered.");
return true;
}
}
- if (DBG) Rlog.d(LOG_TAG, type + " is not metered. isRoaming: " + isRoaming);
+ if (DBG) Rlog.d(LOG_TAG, type + " is not metered.");
return false;
}
- public boolean isMetered(Context context, int subId, boolean isRoaming ) {
+ /**
+ * Check if this APN setting is metered.
+ *
+ * @param phone The phone object
+ * @return True if this APN setting is metered, otherwise false.
+ */
+ public boolean isMetered(Phone phone) {
+ if (phone == null) {
+ return true;
+ }
+
for (String type : types) {
// If one of the APN type is metered, then this APN setting is metered.
- if (isMeteredApnType(type, context, subId, isRoaming)) {
- if (DBG) Rlog.d(LOG_TAG, "Metered. APN = " + toString() +
- "isRoaming: " + isRoaming);
+ if (isMeteredApnType(type, phone)) {
return true;
}
}
- if (DBG) Rlog.d(LOG_TAG, "Not metered. APN = " + toString() + "isRoaming: " + isRoaming);
return false;
}
@@ -512,6 +547,116 @@
&& mvnoMatchData.equals(other.mvnoMatchData);
}
+ /**
+ * Compare two APN settings
+ *
+ * Note: This method does not compare 'id', 'bearer', 'bearerBitmask'. We only use this for
+ * determining if tearing a data call is needed when conditions change. See
+ * cleanUpConnectionsOnUpdatedApns in DcTracker.
+ *
+ * @param o the other object to compare
+ * @param isDataRoaming True if the device is on data roaming
+ * @return True if the two APN settings are same
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public boolean equals(Object o, boolean isDataRoaming) {
+ if (!(o instanceof ApnSetting)) {
+ return false;
+ }
+
+ ApnSetting other = (ApnSetting) o;
+
+ return carrier.equals(other.carrier)
+ && numeric.equals(other.numeric)
+ && apn.equals(other.apn)
+ && proxy.equals(other.proxy)
+ && mmsc.equals(other.mmsc)
+ && mmsProxy.equals(other.mmsProxy)
+ && TextUtils.equals(mmsPort, other.mmsPort)
+ && port.equals(other.port)
+ && TextUtils.equals(user, other.user)
+ && TextUtils.equals(password, other.password)
+ && authType == other.authType
+ && Arrays.deepEquals(types, other.types)
+ && typesBitmap == other.typesBitmap
+ && (isDataRoaming || protocol.equals(other.protocol))
+ && (!isDataRoaming || roamingProtocol.equals(other.roamingProtocol))
+ && carrierEnabled == other.carrierEnabled
+ && profileId == other.profileId
+ && modemCognitive == other.modemCognitive
+ && maxConns == other.maxConns
+ && waitTime == other.waitTime
+ && maxConnsTime == other.maxConnsTime
+ && mtu == other.mtu
+ && mvnoType.equals(other.mvnoType)
+ && mvnoMatchData.equals(other.mvnoMatchData);
+ }
+
+ /**
+ * Check if neither mention DUN and are substantially similar
+ *
+ * @param other The other APN settings to compare
+ * @return True if two APN settings are similar
+ */
+ public boolean similar(ApnSetting other) {
+ return (!this.canHandleType(PhoneConstants.APN_TYPE_DUN)
+ && !other.canHandleType(PhoneConstants.APN_TYPE_DUN)
+ && Objects.equals(this.apn, other.apn)
+ && !typeSameAny(this, other)
+ && xorEquals(this.proxy, other.proxy)
+ && xorEquals(this.port, other.port)
+ && xorEquals(this.protocol, other.protocol)
+ && xorEquals(this.roamingProtocol, other.roamingProtocol)
+ && this.carrierEnabled == other.carrierEnabled
+ && this.bearerBitmask == other.bearerBitmask
+ && this.profileId == other.profileId
+ && Objects.equals(this.mvnoType, other.mvnoType)
+ && Objects.equals(this.mvnoMatchData, other.mvnoMatchData)
+ && xorEquals(this.mmsc, other.mmsc)
+ && xorEquals(this.mmsProxy, other.mmsProxy)
+ && xorEquals(this.mmsPort, other.mmsPort));
+ }
+
+ // check whether the types of two APN same (even only one type of each APN is same)
+ private boolean typeSameAny(ApnSetting first, ApnSetting second) {
+ if (VDBG) {
+ StringBuilder apnType1 = new StringBuilder(first.apn + ": ");
+ for (int index1 = 0; index1 < first.types.length; index1++) {
+ apnType1.append(first.types[index1]);
+ apnType1.append(",");
+ }
+
+ StringBuilder apnType2 = new StringBuilder(second.apn + ": ");
+ for (int index1 = 0; index1 < second.types.length; index1++) {
+ apnType2.append(second.types[index1]);
+ apnType2.append(",");
+ }
+ Rlog.d(LOG_TAG, "APN1: is " + apnType1);
+ Rlog.d(LOG_TAG, "APN2: is " + apnType2);
+ }
+
+ for (int index1 = 0; index1 < first.types.length; index1++) {
+ for (int index2 = 0; index2 < second.types.length; index2++) {
+ if (first.types[index1].equals(PhoneConstants.APN_TYPE_ALL)
+ || second.types[index2].equals(PhoneConstants.APN_TYPE_ALL)
+ || first.types[index1].equals(second.types[index2])) {
+ if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return true");
+ return true;
+ }
+ }
+ }
+
+ if (VDBG) Rlog.d(LOG_TAG, "typeSameAny: return false");
+ return false;
+ }
+
+ // equal or one is not specified
+ private boolean xorEquals(String first, String second) {
+ return (Objects.equals(first, second)
+ || TextUtils.isEmpty(first)
+ || TextUtils.isEmpty(second));
+ }
+
// Helper function to convert APN string into a 32-bit bitmask.
private static int getApnBitmask(String apn) {
switch (apn) {
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
index ffc5b6f..6f7a13b 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnection.java
@@ -36,9 +36,9 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Pair;
-import android.util.Patterns;
import android.util.TimeUtils;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.CallTracker;
import com.android.internal.telephony.CarrierSignalAgent;
import com.android.internal.telephony.CommandException;
@@ -259,10 +259,6 @@
/* Getter functions */
- NetworkCapabilities getCopyNetworkCapabilities() {
- return makeNetworkCapabilities();
- }
-
LinkProperties getCopyLinkProperties() {
return new LinkProperties(mLinkProperties);
}
@@ -471,9 +467,18 @@
DataProfile dp = new DataProfile(mApnSetting, cp.mProfileId);
- mPhone.mCi.setupDataCall(cp.mRilRat, dp,
- mPhone.getServiceState().getDataRoamingFromRegistration(),
- mPhone.getDataRoamingEnabled(), msg);
+ // We need to use the actual modem roaming state instead of the framework roaming state
+ // here. This flag is only passed down to ril_service for picking the correct protocol (for
+ // old modem backward compatibility).
+ boolean isModemRoaming = mPhone.getServiceState().getDataRoamingFromRegistration();
+
+ // Set this flag to true if the user turns on data roaming. Or if we override the roaming
+ // state in framework, we should set this flag to true as well so the modem will not reject
+ // the data call setup (because the modem actually thinks the device is roaming).
+ boolean allowRoaming = mPhone.getDataRoamingEnabled()
+ || (isModemRoaming && !mPhone.getServiceState().getDataRoaming());
+
+ mPhone.mCi.setupDataCall(cp.mRilRat, dp, isModemRoaming, allowRoaming, msg);
}
/**
@@ -495,21 +500,12 @@
discReason = RILConstants.DEACTIVATE_REASON_PDP_RESET;
}
}
- if (mPhone.mCi.getRadioState().isOn()
- || (mPhone.getServiceState().getRilDataRadioTechnology()
- == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN )) {
- String str = "tearDownData radio is on, call deactivateDataCall";
- if (DBG) log(str);
- if (apnContext != null) apnContext.requestLog(str);
- mPhone.mCi.deactivateDataCall(mCid, discReason,
- obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, o));
- } else {
- String str = "tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately";
- if (DBG) log(str);
- if (apnContext != null) apnContext.requestLog(str);
- AsyncResult ar = new AsyncResult(o, null, null);
- sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, ar));
- }
+
+ String str = "tearDownData. mCid=" + mCid + ", reason=" + discReason;
+ if (DBG) log(str);
+ if (apnContext != null) apnContext.requestLog(str);
+ mPhone.mCi.deactivateDataCall(mCid, discReason,
+ obtainMessage(EVENT_DEACTIVATE_DONE, mTag, 0, o));
}
private void notifyAllWithEvent(ApnContext alreadySent, int event, String reason) {
@@ -821,7 +817,7 @@
*
* This gets set once per connection setup and is based on conditions at that time.
* We could theoretically have dynamic capabilities but now is not a good time to
- * experiement with that.
+ * experiment with that.
*
* This flag overrides the APN-based restriction capability, restricting the network
* based on both having a NetworkRequest with restricted AND needing a restricted
@@ -856,8 +852,7 @@
// Do we need a restricted network to satisfy the request?
// Is this network metered? If not, then don't add restricted
- if (!mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(),
- mPhone.getServiceState().getDataRoaming())) {
+ if (!mApnSetting.isMetered(mPhone)) {
return;
}
@@ -865,17 +860,16 @@
mRestrictedNetworkOverride = !mDct.isDataEnabled();
}
- private NetworkCapabilities makeNetworkCapabilities() {
+ NetworkCapabilities getNetworkCapabilities() {
NetworkCapabilities result = new NetworkCapabilities();
result.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
if (mApnSetting != null) {
+ ApnSetting securedDunApn = mDct.fetchDunApn();
for (String type : mApnSetting.types) {
if (!mRestrictedNetworkOverride
&& (mConnectionParams != null && mConnectionParams.mUnmeteredUseOnly)
- && ApnSetting.isMeteredApnType(type,
- mPhone.getContext(), mPhone.getSubId(),
- mPhone.getServiceState().getDataRoaming())) {
+ && ApnSetting.isMeteredApnType(type, mPhone)) {
log("Dropped the metered " + type + " for the unmetered data call.");
continue;
}
@@ -888,6 +882,11 @@
result.addCapability(NetworkCapabilities.NET_CAPABILITY_IMS);
result.addCapability(NetworkCapabilities.NET_CAPABILITY_CBS);
result.addCapability(NetworkCapabilities.NET_CAPABILITY_IA);
+ // check if this is the DUN apn as well as returned by fetchDunApn().
+ // If yes, add DUN capability too.
+ if (mApnSetting.equals(securedDunApn)) {
+ result.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
+ }
break;
}
case PhoneConstants.APN_TYPE_DEFAULT: {
@@ -903,7 +902,6 @@
break;
}
case PhoneConstants.APN_TYPE_DUN: {
- ApnSetting securedDunApn = mDct.fetchDunApn();
if (securedDunApn == null || securedDunApn.equals(mApnSetting)) {
result.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
}
@@ -938,8 +936,7 @@
// 2. The non-restricted data and is intended for unmetered use only.
if (((mConnectionParams != null && mConnectionParams.mUnmeteredUseOnly)
&& !mRestrictedNetworkOverride)
- || !mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId(),
- mPhone.getServiceState().getDataRoaming())) {
+ || !mApnSetting.isMetered(mPhone)) {
result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
mNetworkInfo.setMetered(false);
} else {
@@ -984,10 +981,14 @@
return result;
}
- private boolean isIpAddress(String address) {
+ /**
+ * @return {@code} true iff. {@code address} is a literal IPv4 or IPv6 address.
+ */
+ @VisibleForTesting
+ public static boolean isIpAddress(String address) {
if (address == null) return false;
- return Patterns.IP_ADDRESS.matcher(address).matches();
+ return InetAddress.isNumeric(address);
}
private DataCallResponse.SetupResult setLinkProperties(DataCallResponse response,
@@ -1057,7 +1058,7 @@
mPhone.getServiceStateTracker().registerForDataRoamingOn(getHandler(),
DataConnection.EVENT_DATA_CONNECTION_ROAM_ON, null);
mPhone.getServiceStateTracker().registerForDataRoamingOff(getHandler(),
- DataConnection.EVENT_DATA_CONNECTION_ROAM_OFF, null);
+ DataConnection.EVENT_DATA_CONNECTION_ROAM_OFF, null, true);
// Add ourselves to the list of data connections
mDcController.addDc(DataConnection.this);
@@ -1158,7 +1159,7 @@
break;
}
case DcAsyncChannel.REQ_GET_NETWORK_CAPABILITIES: {
- NetworkCapabilities nc = getCopyNetworkCapabilities();
+ NetworkCapabilities nc = getNetworkCapabilities();
if (VDBG) log("REQ_GET_NETWORK_CAPABILITIES networkCapabilities" + nc);
mAc.replyToMessage(msg, DcAsyncChannel.RSP_GET_NETWORK_CAPABILITIES, nc);
break;
@@ -1220,7 +1221,7 @@
TelephonyManager.getNetworkTypeName(networkType));
if (mNetworkAgent != null) {
updateNetworkInfoSuspendState();
- mNetworkAgent.sendNetworkCapabilities(makeNetworkCapabilities());
+ mNetworkAgent.sendNetworkCapabilities(getNetworkCapabilities());
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
mNetworkAgent.sendLinkProperties(mLinkProperties);
}
@@ -1463,8 +1464,8 @@
+ " result.isRestartRadioFail=" +
result.mFailCause.isRestartRadioFail(mPhone.getContext(),
mPhone.getSubId())
- + " result.isPermanentFail=" +
- mDct.isPermanentFail(result.mFailCause);
+ + " isPermanentFailure=" +
+ mDct.isPermanentFailure(result.mFailCause);
if (DBG) log(str);
if (cp.mApnContext != null) cp.mApnContext.requestLog(str);
@@ -1545,34 +1546,23 @@
// verify and get updated information in case these things
// are obsolete
- {
- ServiceState ss = mPhone.getServiceState();
- final int networkType = ss.getDataNetworkType();
- if (mNetworkInfo.getSubtype() != networkType) {
- log("DcActiveState with incorrect subtype (" + mNetworkInfo.getSubtype() +
- ", " + networkType + "), updating.");
- }
- mNetworkInfo.setSubtype(networkType, TelephonyManager.getNetworkTypeName(networkType));
- final boolean roaming = ss.getDataRoaming();
- if (roaming != mNetworkInfo.isRoaming()) {
- log("DcActiveState with incorrect roaming (" + mNetworkInfo.isRoaming() +
- ", " + roaming +"), updating.");
- }
- mNetworkInfo.setRoaming(roaming);
+ ServiceState ss = mPhone.getServiceState();
+ final int networkType = ss.getDataNetworkType();
+ if (mNetworkInfo.getSubtype() != networkType) {
+ log("DcActiveState with incorrect subtype (" + mNetworkInfo.getSubtype()
+ + ", " + networkType + "), updating.");
+ }
+ mNetworkInfo.setSubtype(networkType, TelephonyManager.getNetworkTypeName(networkType));
+ final boolean roaming = ss.getDataRoaming();
+ if (roaming != mNetworkInfo.isRoaming()) {
+ log("DcActiveState with incorrect roaming (" + mNetworkInfo.isRoaming()
+ + ", " + roaming + "), updating.");
}
- boolean createNetworkAgent = true;
- // If a disconnect is already pending, avoid notifying all of connected
- if (hasMessages(EVENT_DISCONNECT) ||
- hasMessages(EVENT_DISCONNECT_ALL) ||
- hasDeferredMessages(EVENT_DISCONNECT) ||
- hasDeferredMessages(EVENT_DISCONNECT_ALL)) {
- log("DcActiveState: skipping notifyAllOfConnected()");
- createNetworkAgent = false;
- } else {
- // If we were retrying there maybe more than one, otherwise they'll only be one.
- notifyAllOfConnected(Phone.REASON_CONNECTED);
- }
+ mNetworkInfo.setRoaming(roaming);
+
+ // If we were retrying there maybe more than one, otherwise they'll only be one.
+ notifyAllOfConnected(Phone.REASON_CONNECTED);
mPhone.getCallTracker().registerForVoiceCallStarted(getHandler(),
DataConnection.EVENT_DATA_CONNECTION_VOICE_CALL_STARTED, null);
@@ -1597,12 +1587,10 @@
}
misc.subscriberId = mPhone.getSubscriberId();
- if (createNetworkAgent) {
- setNetworkRestriction();
- mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
- "DcNetworkAgent", mNetworkInfo, makeNetworkCapabilities(), mLinkProperties,
- 50, misc);
- }
+ setNetworkRestriction();
+ mNetworkAgent = new DcNetworkAgent(getHandler().getLooper(), mPhone.getContext(),
+ "DcNetworkAgent", mNetworkInfo, getNetworkCapabilities(), mLinkProperties,
+ 50, misc);
}
@Override
@@ -1722,7 +1710,7 @@
} else {
final ArrayList<Integer> capInfo = (ArrayList<Integer>)ar.result;
final int lceBwDownKbps = capInfo.get(0);
- NetworkCapabilities nc = makeNetworkCapabilities();
+ NetworkCapabilities nc = getNetworkCapabilities();
if (mPhone.getLceStatus() == RILConstants.LCE_ACTIVE) {
nc.setLinkDownstreamBandwidthKbps(lceBwDownKbps);
if (mNetworkAgent != null) {
@@ -2075,7 +2063,7 @@
+ " mLastFailCause=" + mLastFailCause
+ " mTag=" + mTag
+ " mLinkProperties=" + mLinkProperties
- + " linkCapabilities=" + makeNetworkCapabilities()
+ + " linkCapabilities=" + getNetworkCapabilities()
+ " mRestrictedNetworkOverride=" + mRestrictedNetworkOverride;
}
@@ -2125,7 +2113,7 @@
pw.flush();
pw.println(" mDataRegState=" + mDataRegState);
pw.println(" mRilRat=" + mRilRat);
- pw.println(" mNetworkCapabilities=" + makeNetworkCapabilities());
+ pw.println(" mNetworkCapabilities=" + getNetworkCapabilities());
pw.println(" mCreateTime=" + TimeUtils.logTimeOfDay(mCreateTime));
pw.println(" mLastFailTime=" + TimeUtils.logTimeOfDay(mLastFailTime));
pw.println(" mLastFailCause=" + mLastFailCause);
@@ -2136,4 +2124,3 @@
pw.flush();
}
}
-
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java b/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java
new file mode 100644
index 0000000..e7afdff
--- /dev/null
+++ b/src/java/com/android/internal/telephony/dataconnection/DataConnectionReasons.java
@@ -0,0 +1,142 @@
+/*
+ * 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.dataconnection;
+
+import java.util.HashSet;
+
+/**
+ * The class to describe the reasons of allowing or disallowing to establish a data connection.
+ */
+public class DataConnectionReasons {
+ private HashSet<DataDisallowedReasonType> mDataDisallowedReasonSet = new HashSet<>();
+ private DataAllowedReasonType mDataAllowedReason = DataAllowedReasonType.NONE;
+
+ public DataConnectionReasons() {}
+
+ void add(DataDisallowedReasonType reason) {
+ // Adding a disallowed reason will clean up the allowed reason because they are
+ // mutual exclusive.
+ mDataAllowedReason = DataAllowedReasonType.NONE;
+ mDataDisallowedReasonSet.add(reason);
+ }
+
+ void add(DataAllowedReasonType reason) {
+ // Adding an allowed reason will clean up the disallowed reasons because they are
+ // mutual exclusive.
+ mDataDisallowedReasonSet.clear();
+
+ // Only higher priority allowed reason can overwrite the old one. See
+ // DataAllowedReasonType for the oder.
+ if (reason.ordinal() > mDataAllowedReason.ordinal()) {
+ mDataAllowedReason = reason;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder reasonStr = new StringBuilder();
+ if (mDataDisallowedReasonSet.size() > 0) {
+ reasonStr.append("Data disallowed, reasons:");
+ for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) {
+ reasonStr.append(" ").append(reason);
+ }
+ } else {
+ reasonStr.append("Data allowed, reason:");
+ reasonStr.append(" ").append(mDataAllowedReason);
+ }
+ return reasonStr.toString();
+ }
+
+ void copyFrom(DataConnectionReasons reasons) {
+ this.mDataDisallowedReasonSet = reasons.mDataDisallowedReasonSet;
+ this.mDataAllowedReason = reasons.mDataAllowedReason;
+ }
+
+ boolean allowed() {
+ return mDataDisallowedReasonSet.size() == 0;
+ }
+
+ boolean contains(DataDisallowedReasonType reason) {
+ return mDataDisallowedReasonSet.contains(reason);
+ }
+
+ /**
+ * Check if only one disallowed reason prevent data connection.
+ *
+ * @param reason The given reason to check
+ * @return True if the given reason is the only one that prevents data connection
+ */
+ public boolean containsOnly(DataDisallowedReasonType reason) {
+ return mDataDisallowedReasonSet.size() == 1 && contains(reason);
+ }
+
+ boolean contains(DataAllowedReasonType reason) {
+ return reason == mDataAllowedReason;
+ }
+
+ boolean containsHardDisallowedReasons() {
+ for (DataDisallowedReasonType reason : mDataDisallowedReasonSet) {
+ if (reason.isHardReason()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Disallowed reasons. There could be multiple reasons if data connection is not allowed.
+ public enum DataDisallowedReasonType {
+ // Soft failure reasons. Normally the reasons from users or policy settings.
+ DATA_DISABLED(false), // Data is disabled by the user or policy.
+ ROAMING_DISABLED(false), // Data roaming is disabled by the user.
+
+ // Belows are all hard failure reasons.
+ NOT_ATTACHED(true),
+ RECORD_NOT_LOADED(true),
+ INVALID_PHONE_STATE(true),
+ CONCURRENT_VOICE_DATA_NOT_ALLOWED(true),
+ PS_RESTRICTED(true),
+ UNDESIRED_POWER_STATE(true),
+ INTERNAL_DATA_DISABLED(true),
+ DEFAULT_DATA_UNSELECTED(true),
+ RADIO_DISABLED_BY_CARRIER(true),
+ APN_NOT_CONNECTABLE(true),
+ ON_IWLAN(true),
+ IN_ECBM(true);
+
+ private boolean mIsHardReason;
+
+ boolean isHardReason() {
+ return mIsHardReason;
+ }
+
+ DataDisallowedReasonType(boolean isHardReason) {
+ mIsHardReason = isHardReason;
+ }
+ }
+
+ // Data allowed reasons. There will be only one reason if data is allowed.
+ enum DataAllowedReasonType {
+ // Note that unlike disallowed reasons, we only have one allowed reason every time
+ // when we check data is allowed or not. The order of these allowed reasons is very
+ // important. The lower ones take precedence over the upper ones.
+ NONE,
+ NORMAL,
+ UNMETERED_APN,
+ RESTRICTED_REQUEST,
+ EMERGENCY_APN,
+ }
+}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
index ea54538..a8bffd3 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DataEnabledSettings.java
@@ -63,6 +63,13 @@
private final RegistrantList mDataEnabledChangedRegistrants = new RegistrantList();
+ @Override
+ public String toString() {
+ return "[mInternalDataEnabled=" + mInternalDataEnabled + ", mUserDataEnabled="
+ + mUserDataEnabled + ", mPolicyDataEnabled=" + mPolicyDataEnabled
+ + ", mCarrierDataEnabled=" + mCarrierDataEnabled + "]";
+ }
+
public synchronized void setInternalDataEnabled(boolean enabled) {
boolean prevDataEnabled = isDataEnabled();
mInternalDataEnabled = enabled;
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java b/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
index 77cd6b5..67d91d3 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcAsyncChannel.java
@@ -342,7 +342,7 @@
value = null;
}
} else {
- value = mDc.getCopyNetworkCapabilities();
+ value = mDc.getNetworkCapabilities();
}
return value;
}
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index b168756..291d6f5 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -275,7 +275,7 @@
+ failCause);
}
mDct.sendRestartRadio();
- } else if (mDct.isPermanentFail(failCause)) {
+ } else if (mDct.isPermanentFailure(failCause)) {
if (DBG) {
log("onDataStateChanged: inactive, add to cleanup list. "
+ "failCause=" + failCause);
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcFailCause.java b/src/java/com/android/internal/telephony/dataconnection/DcFailCause.java
index f34076a..b3762e5 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcFailCause.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcFailCause.java
@@ -19,7 +19,9 @@
import android.content.res.Resources;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
+
import java.util.HashMap;
+import java.util.HashSet;
/**
* Returned as the reason for a connection failure as defined
@@ -105,8 +107,8 @@
// specified in ril.h
REGISTRATION_FAIL(-1),
GPRS_REGISTRATION_FAIL(-2),
- SIGNAL_LOST(-3),
- PREF_RADIO_TECH_CHANGED(-4), /* no retry */
+ SIGNAL_LOST(-3), /* no retry */
+ PREF_RADIO_TECH_CHANGED(-4),
RADIO_POWER_OFF(-5), /* no retry */
TETHERED_CALL_ACTIVE(-6), /* no retry */
ERROR_UNSPECIFIED(0xFFFF),
@@ -129,6 +131,12 @@
}
}
+ /**
+ * Map of subId -> set of data call setup permanent failure for the carrier.
+ */
+ private static final HashMap<Integer, HashSet<DcFailCause>> sPermanentFailureCache =
+ new HashMap<>();
+
DcFailCause(int errorCode) {
mErrorCode = errorCode;
}
@@ -160,16 +168,62 @@
return false;
}
- public boolean isPermanentFail() {
- return (this == OPERATOR_BARRED) || (this == MISSING_UNKNOWN_APN) ||
- (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) ||
- (this == ACTIVATION_REJECT_GGSN) || (this == SERVICE_OPTION_NOT_SUPPORTED) ||
- (this == SERVICE_OPTION_NOT_SUBSCRIBED) || (this == NSAPI_IN_USE) ||
- (this == ONLY_IPV4_ALLOWED) || (this == ONLY_IPV6_ALLOWED) ||
- (this == PROTOCOL_ERRORS) ||
- (this == RADIO_POWER_OFF) || (this == TETHERED_CALL_ACTIVE) ||
- (this == RADIO_NOT_AVAILABLE) || (this == UNACCEPTABLE_NETWORK_PARAMETER) ||
- (this == SIGNAL_LOST);
+ public boolean isPermanentFailure(Context context, int subId) {
+
+ synchronized (sPermanentFailureCache) {
+
+ HashSet<DcFailCause> permanentFailureSet = sPermanentFailureCache.get(subId);
+
+ // In case of cache miss, we need to look up the settings from carrier config.
+ if (permanentFailureSet == null) {
+ // Retrieve the permanent failure from carrier config
+ CarrierConfigManager configManager = (CarrierConfigManager)
+ context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (configManager != null) {
+ PersistableBundle b = configManager.getConfigForSubId(subId);
+ if (b != null) {
+ String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager.
+ KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS);
+
+ if (permanentFailureStrings != null) {
+ permanentFailureSet = new HashSet<>();
+ for (String failure : permanentFailureStrings) {
+ permanentFailureSet.add(DcFailCause.valueOf(failure));
+ }
+ }
+ }
+ }
+
+ // If we are not able to find the configuration from carrier config, use the default
+ // ones.
+ if (permanentFailureSet == null) {
+ permanentFailureSet = new HashSet<DcFailCause>() {
+ {
+ add(OPERATOR_BARRED);
+ add(MISSING_UNKNOWN_APN);
+ add(UNKNOWN_PDP_ADDRESS_TYPE);
+ add(USER_AUTHENTICATION);
+ add(ACTIVATION_REJECT_GGSN);
+ add(SERVICE_OPTION_NOT_SUPPORTED);
+ add(SERVICE_OPTION_NOT_SUBSCRIBED);
+ add(NSAPI_IN_USE);
+ add(ONLY_IPV4_ALLOWED);
+ add(ONLY_IPV6_ALLOWED);
+ add(PROTOCOL_ERRORS);
+ add(RADIO_POWER_OFF);
+ add(TETHERED_CALL_ACTIVE);
+ add(RADIO_NOT_AVAILABLE);
+ add(UNACCEPTABLE_NETWORK_PARAMETER);
+ add(SIGNAL_LOST);
+ }
+ };
+ }
+
+ sPermanentFailureCache.put(subId, permanentFailureSet);
+ }
+
+ return permanentFailureSet.contains(this);
+ }
}
public boolean isEventLoggable() {
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index dfcc19b..1faa9f2 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -84,8 +84,10 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.ServiceStateTracker;
+import com.android.internal.telephony.SettingsObserver;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataAllowedReasonType;
+import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.UiccController;
@@ -98,9 +100,7 @@
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map.Entry;
-import java.util.Objects;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -160,57 +160,6 @@
private static final String INTENT_DATA_STALL_ALARM =
"com.android.internal.telephony.data-stall";
- @VisibleForTesting
- public static class DataAllowFailReason {
- private HashSet<DataAllowFailReasonType> mDataAllowFailReasonSet = new HashSet<>();
-
- public void addDataAllowFailReason(DataAllowFailReasonType type) {
- mDataAllowFailReasonSet.add(type);
- }
-
- public String getDataAllowFailReason() {
- StringBuilder failureReason = new StringBuilder();
- failureReason.append("isDataAllowed: No");
- for(DataAllowFailReasonType reason : mDataAllowFailReasonSet) {
- failureReason.append(reason.mFailReasonStr);
- }
- return failureReason.toString();
- }
-
- public boolean isFailForSingleReason(DataAllowFailReasonType failReasonType) {
- return (mDataAllowFailReasonSet.size() == 1) &&
- (mDataAllowFailReasonSet.contains(failReasonType));
- }
-
- public void clearAllReasons() {
- mDataAllowFailReasonSet.clear();
- }
-
- public boolean isFailed() {
- return mDataAllowFailReasonSet.size() > 0;
- }
- }
-
- @VisibleForTesting
- public enum DataAllowFailReasonType {
- NOT_ATTACHED(" - Not attached"),
- RECORD_NOT_LOADED(" - SIM not loaded"),
- ROAMING_DISABLED(" - Roaming and data roaming not enabled"),
- INVALID_PHONE_STATE(" - PhoneState is not idle"),
- CONCURRENT_VOICE_DATA_NOT_ALLOWED(" - Concurrent voice and data not allowed"),
- PS_RESTRICTED(" - mIsPsRestricted= true"),
- UNDESIRED_POWER_STATE(" - desiredPowerState= false"),
- INTERNAL_DATA_DISABLED(" - mInternalDataEnabled= false"),
- DEFAULT_DATA_UNSELECTED(" - defaultDataSelected= false"),
- RADIO_DISABLED_BY_CARRIER(" - powerStateFromCarrier= false");
-
- public String mFailReasonStr;
-
- DataAllowFailReasonType(String reason) {
- mFailReasonStr = reason;
- }
- }
-
private DcTesterFailBringUpAll mDcTesterFailBringUpAll;
private DcController mDcc;
@@ -314,12 +263,8 @@
+ " mIsWifiConnected=" + mIsWifiConnected);
}
} else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
- CarrierConfigManager configMgr = (CarrierConfigManager)
- mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
- if (configMgr != null) {
- PersistableBundle cfg = configMgr.getConfigForSubId(mPhone.getSubId());
- if (cfg != null) mAllowUserEditTetherApn =
- cfg.getBoolean(CarrierConfigManager.KEY_EDITABLE_TETHER_APN_BOOL);
+ if (mIccRecords.get() != null && mIccRecords.get().getRecordsLoaded()) {
+ setDefaultDataRoamingEnabled();
}
} else {
if (DBG) log("onReceive: Unknown action=" + action);
@@ -372,46 +317,6 @@
}
};
- private static class SettingsObserver extends ContentObserver {
- final private HashMap<Uri, Integer> mUriEventMap;
- final private Context mContext;
- final private Handler mHandler;
- final private static String TAG = "DcTracker.SettingsObserver";
-
- SettingsObserver(Context context, Handler handler) {
- super(null);
- mUriEventMap = new HashMap<Uri, Integer>();
- mContext = context;
- mHandler = handler;
- }
-
- void observe(Uri uri, int what) {
- mUriEventMap.put(uri, what);
- final ContentResolver resolver = mContext.getContentResolver();
- resolver.registerContentObserver(uri, false, this);
- }
-
- void unobserve() {
- final ContentResolver resolver = mContext.getContentResolver();
- resolver.unregisterContentObserver(this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- Rlog.e(TAG, "Should never be reached.");
- }
-
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- final Integer what = mUriEventMap.get(uri);
- if (what != null) {
- mHandler.obtainMessage(what.intValue()).sendToTarget();
- } else {
- Rlog.e(TAG, "No matching event to send for URI=" + uri);
- }
- }
- }
-
private final SettingsObserver mSettingsObserver;
private void registerSettingsObserver() {
@@ -473,13 +378,19 @@
}
private void onActionIntentReconnectAlarm(Intent intent) {
- String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
- String apnType = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
+ Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT);
+ msg.setData(intent.getExtras());
+ sendMessage(msg);
+ }
+
+ private void onDataReconnect(Bundle bundle) {
+ String reason = bundle.getString(INTENT_RECONNECT_ALARM_EXTRA_REASON);
+ String apnType = bundle.getString(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
int phoneSubId = mPhone.getSubId();
- int currSubId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+ int currSubId = bundle.getInt(PhoneConstants.SUBSCRIPTION_KEY,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- log("onActionIntentReconnectAlarm: currSubId = " + currSubId + " phoneSubId=" + phoneSubId);
+ log("onDataReconnect: currSubId = " + currSubId + " phoneSubId=" + phoneSubId);
// Stop reconnect if not current subId is not correct.
// FIXME STOPSHIP - phoneSubId is coming up as -1 way after boot and failing this?
@@ -491,33 +402,33 @@
ApnContext apnContext = mApnContexts.get(apnType);
if (DBG) {
- log("onActionIntentReconnectAlarm: mState=" + mState + " reason=" + reason +
- " apnType=" + apnType + " apnContext=" + apnContext +
- " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap);
+ log("onDataReconnect: mState=" + mState + " reason=" + reason + " apnType=" + apnType
+ + " apnContext=" + apnContext + " mDataConnectionAsyncChannels="
+ + mDataConnectionAcHashMap);
}
if ((apnContext != null) && (apnContext.isEnabled())) {
apnContext.setReason(reason);
DctConstants.State apnContextState = apnContext.getState();
if (DBG) {
- log("onActionIntentReconnectAlarm: apnContext state=" + apnContextState);
+ log("onDataReconnect: apnContext state=" + apnContextState);
}
if ((apnContextState == DctConstants.State.FAILED)
|| (apnContextState == DctConstants.State.IDLE)) {
if (DBG) {
- log("onActionIntentReconnectAlarm: state is FAILED|IDLE, disassociate");
+ log("onDataReconnect: state is FAILED|IDLE, disassociate");
}
DcAsyncChannel dcac = apnContext.getDcAc();
if (dcac != null) {
if (DBG) {
- log("onActionIntentReconnectAlarm: tearDown apnContext=" + apnContext);
+ log("onDataReconnect: tearDown apnContext=" + apnContext);
}
dcac.tearDown(apnContext, "", null);
}
apnContext.setDataConnectionAc(null);
apnContext.setState(DctConstants.State.IDLE);
} else {
- if (DBG) log("onActionIntentReconnectAlarm: keep associated");
+ if (DBG) log("onDataReconnect: keep associated");
}
// TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA???
sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
@@ -623,11 +534,13 @@
private boolean mMeteredApnDisabled = false;
/**
- * Whether carrier allow user edited tether APN. Updated by carrier config
- * KEY_EDITABLE_TETHER_APN_BOOL
- * If true, APN with dun type from database will be used, see fetchDunApn for details.
+ * int to remember whether has setDataProfiles and with roaming or not.
+ * 0: default, has never set data profile
+ * 1: has set data profile with home protocol
+ * 2: has set data profile with roaming protocol
+ * This is not needed once RIL command is updated to support both home and roaming protocol.
*/
- private boolean mAllowUserEditTetherApn = false;
+ private int mSetDataProfileStatus = 0;
/**
* Handles changes to the APN db.
@@ -697,7 +610,6 @@
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(INTENT_DATA_STALL_ALARM);
filter.addAction(INTENT_PROVISIONING_APN_ALARM);
- filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
// TODO - redundent with update call below?
mDataEnabledSettings.setUserDataEnabled(getDataEnabled());
@@ -761,7 +673,7 @@
mPhone.getServiceStateTracker().registerForDataRoamingOn(this,
DctConstants.EVENT_ROAMING_ON, null);
mPhone.getServiceStateTracker().registerForDataRoamingOff(this,
- DctConstants.EVENT_ROAMING_OFF, null);
+ DctConstants.EVENT_ROAMING_OFF, null, true);
mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this,
DctConstants.EVENT_PS_RESTRICT_ENABLED, null);
mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this,
@@ -940,17 +852,17 @@
if (dcac != null) {
final NetworkCapabilities netCaps = dcac.getNetworkCapabilitiesSync();
if (netCaps != null && !netCaps.hasCapability(NetworkCapabilities
- .NET_CAPABILITY_NOT_RESTRICTED)) {
+ .NET_CAPABILITY_NOT_RESTRICTED) && !netCaps.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_METERED)) {
if (DBG) {
- log("Tearing down restricted net:" + apnContext);
+ log("Tearing down restricted metered net:" + apnContext);
}
- // Tearing down the restricted data call (metered or unmetered) when
+ // Tearing down the restricted metered data call when
// conditions change. This will allow reestablishing a new unrestricted
// data connection.
apnContext.setReason(Phone.REASON_DATA_ENABLED);
cleanUpConnection(true, apnContext);
- } else if (apnContext.getApnSetting().isMetered(mPhone.getContext(),
- mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())
+ } else if (apnContext.getApnSetting().isMetered(mPhone)
&& (netCaps != null && netCaps.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_METERED))) {
if (DBG) {
@@ -1092,38 +1004,6 @@
}
}
- public boolean isDataPossible(String apnType) {
- ApnContext apnContext = mApnContexts.get(apnType);
- if (apnContext == null) {
- return false;
- }
- boolean apnContextIsEnabled = apnContext.isEnabled();
- DctConstants.State apnContextState = apnContext.getState();
- boolean apnTypePossible = !(apnContextIsEnabled &&
- (apnContextState == DctConstants.State.FAILED));
- boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
- // Set the emergency APN availability status as TRUE irrespective of conditions checked in
- // isDataAllowed() like IN_SERVICE, MOBILE DATA status etc.
- boolean dataAllowed = isEmergencyApn || isDataAllowed(null);
- boolean possible = dataAllowed && apnTypePossible;
-
- if ((apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
- || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA))
- && (mPhone.getServiceState().getRilDataRadioTechnology()
- == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) {
- log("Default data call activation not possible in iwlan.");
- possible = false;
- }
-
- if (VDBG) {
- log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " +
- "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s",
- apnType, possible, dataAllowed, apnTypePossible,
- apnContextIsEnabled, apnContextState));
- }
- return possible;
- }
-
@Override
protected void finalize() {
if(DBG && mPhone != null) log("finalize");
@@ -1307,47 +1187,11 @@
}
}
- /**
- * Report on whether data connectivity is enabled for any APN.
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public boolean getAnyDataEnabled() {
- if (!mDataEnabledSettings.isDataEnabled()) return false;
- DataAllowFailReason failureReason = new DataAllowFailReason();
- if (!isDataAllowed(failureReason)) {
- if (DBG) log(failureReason.getDataAllowFailReason());
- return false;
- }
- for (ApnContext apnContext : mApnContexts.values()) {
- // Make sure we don't have a context that is going down
- // and is explicitly disabled.
- if (isDataAllowedForApn(apnContext)) {
- return true;
- }
- }
- return false;
- }
-
@VisibleForTesting
public boolean isDataEnabled() {
return mDataEnabledSettings.isDataEnabled();
}
- private boolean isDataAllowedForApn(ApnContext apnContext) {
- //If RAT is iwlan then dont allow default/IA PDP at all.
- //Rest of APN types can be evaluated for remaining conditions.
- if ((apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
- || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA))
- && (mPhone.getServiceState().getRilDataRadioTechnology()
- == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) {
- log("Default data call activation not allowed in iwlan.");
- return false;
- }
-
- return apnContext.isReady();
- }
-
//****** Called from ServiceStateTracker
/**
* Invoked when ServiceStateTracker observes a transition from GPRS
@@ -1383,30 +1227,58 @@
setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED);
}
- private boolean isDataAllowed(DataAllowFailReason failureReason) {
- final boolean internalDataEnabled;
- internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled();
+ /**
+ * Check if it is allowed to make a data connection (without checking APN context specific
+ * conditions).
+ *
+ * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output
+ * param. It's okay to pass null here and no reasons will be
+ * provided.
+ * @return True if data connection is allowed, otherwise false.
+ */
+ public boolean isDataAllowed(DataConnectionReasons dataConnectionReasons) {
+ return isDataAllowed(null, dataConnectionReasons);
+ }
+ /**
+ * Check if it is allowed to make a data connection for a given APN type.
+ *
+ * @param apnContext APN context. If passing null, then will only check general but not APN
+ * specific conditions (e.g. APN state, metered/unmetered APN).
+ * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output
+ * param. It's okay to pass null here and no reasons will be
+ * provided.
+ * @return True if data connection is allowed, otherwise false.
+ */
+ boolean isDataAllowed(ApnContext apnContext, DataConnectionReasons dataConnectionReasons) {
+ // Step 1: Get all environment conditions.
+ // Step 2: Special handling for emergency APN.
+ // Step 3. Build disallowed reasons.
+ // Step 4: Determine if data should be allowed in some special conditions.
+
+ DataConnectionReasons reasons = new DataConnectionReasons();
+
+ // Step 1: Get all environment conditions.
+ final boolean internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled();
boolean attachedState = mAttached.get();
boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier();
+ // TODO: Remove this hack added by ag/641832.
int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
desiredPowerState = true;
radioStateFromCarrier = true;
}
- IccRecords r = mIccRecords.get();
- boolean recordsLoaded = false;
- if (r != null) {
- recordsLoaded = r.getRecordsLoaded();
- if (DBG && !recordsLoaded) log("isDataAllowed getRecordsLoaded=" + recordsLoaded);
- }
+ boolean recordsLoaded = mIccRecords.get() != null && mIccRecords.get().getRecordsLoaded();
- int dataSub = SubscriptionManager.getDefaultDataSubscriptionId();
- boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId(dataSub);
+ boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId(
+ SubscriptionManager.getDefaultDataSubscriptionId());
- PhoneConstants.State state = PhoneConstants.State.IDLE;
+ boolean isMeteredApnType = apnContext == null
+ || ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone);
+
+ PhoneConstants.State phoneState = PhoneConstants.State.IDLE;
// Note this is explicitly not using mPhone.getState. See b/19090488.
// mPhone.getState reports the merge of CS and PS (volte) voice call state
// but we only care about CS calls here for data/voice concurrency issues.
@@ -1415,52 +1287,110 @@
// This should be redesigned to ask explicitly what we want:
// voiceCallStateAllowDataCall, or dataCallAllowed or something similar.
if (mPhone.getCallTracker() != null) {
- state = mPhone.getCallTracker().getState();
+ phoneState = mPhone.getCallTracker().getState();
}
- if (failureReason != null) failureReason.clearAllReasons();
+ // Step 2: Special handling for emergency APN.
+ if (apnContext != null
+ && apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY)
+ && apnContext.isConnectable()) {
+ // If this is an emergency APN, as long as the APN is connectable, we
+ // should allow it.
+ if (dataConnectionReasons != null) {
+ dataConnectionReasons.add(DataAllowedReasonType.EMERGENCY_APN);
+ }
+ // Bail out without further checks.
+ return true;
+ }
+
+ // Step 3. Build disallowed reasons.
+ if (apnContext != null && !apnContext.isConnectable()) {
+ reasons.add(DataDisallowedReasonType.APN_NOT_CONNECTABLE);
+ }
+
+ // If RAT is IWLAN then don't allow default/IA PDP at all.
+ // Rest of APN types can be evaluated for remaining conditions.
+ if ((apnContext != null && (apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
+ || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA)))
+ && (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) {
+ reasons.add(DataDisallowedReasonType.ON_IWLAN);
+ }
+
+ if (isEmergency()) {
+ reasons.add(DataDisallowedReasonType.IN_ECBM);
+ }
+
if (!(attachedState || mAutoAttachOnCreation.get())) {
- if(failureReason == null) return false;
- failureReason.addDataAllowFailReason(DataAllowFailReasonType.NOT_ATTACHED);
+ reasons.add(DataDisallowedReasonType.NOT_ATTACHED);
}
if (!recordsLoaded) {
- if(failureReason == null) return false;
- failureReason.addDataAllowFailReason(DataAllowFailReasonType.RECORD_NOT_LOADED);
+ reasons.add(DataDisallowedReasonType.RECORD_NOT_LOADED);
}
- if (state != PhoneConstants.State.IDLE &&
- !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
- if(failureReason == null) return false;
- failureReason.addDataAllowFailReason(DataAllowFailReasonType.INVALID_PHONE_STATE);
- failureReason.addDataAllowFailReason(
- DataAllowFailReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED);
+ if (phoneState != PhoneConstants.State.IDLE
+ && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
+ reasons.add(DataDisallowedReasonType.INVALID_PHONE_STATE);
+ reasons.add(DataDisallowedReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED);
}
if (!internalDataEnabled) {
- if(failureReason == null) return false;
- failureReason.addDataAllowFailReason(DataAllowFailReasonType.INTERNAL_DATA_DISABLED);
+ reasons.add(DataDisallowedReasonType.INTERNAL_DATA_DISABLED);
}
if (!defaultDataSelected) {
- if(failureReason == null) return false;
- failureReason.addDataAllowFailReason(
- DataAllowFailReasonType.DEFAULT_DATA_UNSELECTED);
+ reasons.add(DataDisallowedReasonType.DEFAULT_DATA_UNSELECTED);
}
if (mPhone.getServiceState().getDataRoaming() && !getDataRoamingEnabled()) {
- if(failureReason == null) return false;
- failureReason.addDataAllowFailReason(DataAllowFailReasonType.ROAMING_DISABLED);
+ reasons.add(DataDisallowedReasonType.ROAMING_DISABLED);
}
if (mIsPsRestricted) {
- if(failureReason == null) return false;
- failureReason.addDataAllowFailReason(DataAllowFailReasonType.PS_RESTRICTED);
+ reasons.add(DataDisallowedReasonType.PS_RESTRICTED);
}
if (!desiredPowerState) {
- if(failureReason == null) return false;
- failureReason.addDataAllowFailReason(DataAllowFailReasonType.UNDESIRED_POWER_STATE);
+ reasons.add(DataDisallowedReasonType.UNDESIRED_POWER_STATE);
}
if (!radioStateFromCarrier) {
- if(failureReason == null) return false;
- failureReason.addDataAllowFailReason(DataAllowFailReasonType.RADIO_DISABLED_BY_CARRIER);
+ reasons.add(DataDisallowedReasonType.RADIO_DISABLED_BY_CARRIER);
+ }
+ if (!mDataEnabledSettings.isDataEnabled()) {
+ reasons.add(DataDisallowedReasonType.DATA_DISABLED);
}
- return failureReason == null || !failureReason.isFailed();
+ // If there are hard disallowed reasons, we should not allow data connection no matter what.
+ if (reasons.containsHardDisallowedReasons()) {
+ if (dataConnectionReasons != null) {
+ dataConnectionReasons.copyFrom(reasons);
+ }
+ return false;
+ }
+
+ // Step 4: Determine if data should be allowed in some special conditions.
+
+ // At this point, if data is not allowed, it must be because of the soft reasons. We
+ // should start to check some special conditions that data will be allowed.
+
+ // If the request APN type is unmetered and there are soft disallowed reasons (e.g. data
+ // disabled, data roaming disabled) existing, we should allow the data because the user
+ // won't be charged anyway.
+ if (!isMeteredApnType && !reasons.allowed()) {
+ reasons.add(DataAllowedReasonType.UNMETERED_APN);
+ }
+
+ // If the request is restricted and there are only soft disallowed reasons (e.g. data
+ // disabled, data roaming disabled) existing, we should allow the data.
+ if (apnContext != null
+ && !apnContext.hasNoRestrictedRequests(true)
+ && !reasons.allowed()) {
+ reasons.add(DataAllowedReasonType.RESTRICTED_REQUEST);
+ }
+
+ // If at this point, we still haven't built any disallowed reasons, we should allow data.
+ if (reasons.allowed()) {
+ reasons.add(DataAllowedReasonType.NORMAL);
+ }
+
+ if (dataConnectionReasons != null) {
+ dataConnectionReasons.copyFrom(reasons);
+ }
+
+ return reasons.allowed();
}
// arg for setupDataOnConnectableApns
@@ -1494,8 +1424,6 @@
}
for (ApnContext apnContext : mPrioritySortedApnContexts) {
- ArrayList<ApnSetting> waitingApns = null;
-
if (VDBG) log("setupDataOnConnectableApns: apnContext " + apnContext);
if (apnContext.getState() == DctConstants.State.FAILED
@@ -1506,27 +1434,12 @@
mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
// RetryFailures.ONLY_ON_CHANGE - check if voice concurrency has changed
apnContext.releaseDataConnection(reason);
- } else {
- // RetryFailures.ONLY_ON_CHANGE - check if the apns have changed
- int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
- ArrayList<ApnSetting> originalApns = apnContext.getWaitingApns();
- if (originalApns != null && originalApns.isEmpty() == false) {
- waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech);
- if (originalApns.size() != waitingApns.size() ||
- originalApns.containsAll(waitingApns) == false) {
- apnContext.releaseDataConnection(reason);
- } else {
- continue;
- }
- } else {
- continue;
- }
}
}
if (apnContext.isConnectable()) {
log("isConnectable() call trySetupData");
apnContext.setReason(reason);
- trySetupData(apnContext, waitingApns);
+ trySetupData(apnContext);
}
}
}
@@ -1538,15 +1451,6 @@
}
private boolean trySetupData(ApnContext apnContext) {
- return trySetupData(apnContext, null);
- }
-
- private boolean trySetupData(ApnContext apnContext, ArrayList<ApnSetting> waitingApns) {
- if (DBG) {
- log("trySetupData for type:" + apnContext.getApnType() +
- " due to " + apnContext.getReason() + ", mIsPsRestricted=" + mIsPsRestricted);
- }
- apnContext.requestLog("trySetupData due to " + apnContext.getReason());
if (mPhone.getSimulatedRadioControl() != null) {
// Assume data is connected on the simulator
@@ -1558,58 +1462,13 @@
return true;
}
- // Allow SETUP_DATA request for E-APN to be completed during emergency call
- // and MOBILE DATA On/Off cases as well.
- boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
- final ServiceStateTracker sst = mPhone.getServiceStateTracker();
-
- DataAllowFailReason failureReason = new DataAllowFailReason();
-
- boolean unmeteredUseOnly = false;
- boolean isDataAllowed = isDataAllowed(failureReason);
- boolean isMeteredApnType = ApnSetting.isMeteredApnType(apnContext.getApnType(),
- mPhone.getContext(), mPhone.getSubId(), mPhone.getServiceState().getDataRoaming());
- if (!isDataAllowed) {
- // If the data not allowed due to roaming disabled, but the request APN type is not
- // metered, we should allow data (because the user won't be charged anyway)
- if (failureReason.isFailForSingleReason(DataAllowFailReasonType.ROAMING_DISABLED)
- && !isMeteredApnType) {
- isDataAllowed = true;
- unmeteredUseOnly = true;
- }
- }
-
+ DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
+ boolean isDataAllowed = isDataAllowed(apnContext, dataConnectionReasons);
+ String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: "
+ + apnContext.getReason() + ". " + dataConnectionReasons.toString();
+ if (DBG) log(logStr);
+ apnContext.requestLog(logStr);
if (isDataAllowed) {
- if (!mDataEnabledSettings.isDataEnabled()) {
- // If the data is turned off, we should not allow a data connection.
- isDataAllowed = false;
-
- // But there are some exceptions we should allow data even when data is turned off.
- if (!apnContext.hasNoRestrictedRequests(true /*exclude DUN */)) {
- // A restricted request can request data even when data is turned off.
- // Note this takes precedence over unmetered request.
- isDataAllowed = true;
- unmeteredUseOnly = false;
- } else if (!isMeteredApnType) {
- // If the APN is unmetered, we should allow data even if data is turned off.
- // This will allow users to make VoLTE calls or send MMS while data is
- // turned off.
- isDataAllowed = true;
-
- // When data is off, if we allow a data call because it's unmetered, we
- // should restrict it for unmetered use only. For example, if one
- // carrier has both internet (metered) and MMS (unmetered) APNs mixed in one
- // APN setting, when we bring up a data call for MMS purpose, we should
- // restrict it for unmetered use only. We should not allow it for other
- // metered purposes such as internet.
- unmeteredUseOnly = true;
- }
- }
- }
-
- if (apnContext.isConnectable()
- && (isEmergencyApn
- || (isDataAllowed && isDataAllowedForApn(apnContext) && !isEmergency()))) {
if (apnContext.getState() == DctConstants.State.FAILED) {
String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable";
if (DBG) log(str);
@@ -1617,11 +1476,11 @@
apnContext.setState(DctConstants.State.IDLE);
}
int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
- apnContext.setConcurrentVoiceAndDataAllowed(sst.isConcurrentVoiceAndDataAllowed());
+ apnContext.setConcurrentVoiceAndDataAllowed(mPhone.getServiceStateTracker()
+ .isConcurrentVoiceAndDataAllowed());
if (apnContext.getState() == DctConstants.State.IDLE) {
- if (waitingApns == null) {
- waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech);
- }
+ ArrayList<ApnSetting> waitingApns =
+ buildWaitingApns(apnContext.getApnType(), radioTech);
if (waitingApns.isEmpty()) {
notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext);
notifyOffApnsOfAvailability(apnContext.getReason());
@@ -1638,7 +1497,8 @@
}
}
- boolean retValue = setupData(apnContext, radioTech, unmeteredUseOnly);
+ boolean retValue = setupData(apnContext, radioTech, dataConnectionReasons.contains(
+ DataAllowedReasonType.UNMETERED_APN));
notifyOffApnsOfAvailability(apnContext.getReason());
if (DBG) log("trySetupData: X retValue=" + retValue);
@@ -1652,48 +1512,30 @@
StringBuilder str = new StringBuilder();
- str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType() +
- ", mState=" + apnContext.getState() + ", mDataEnabled=" +
- apnContext.isEnabled() + ", mDependencyMet=" +
- apnContext.getDependencyMet() + "] ");
+ str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType()
+ + ", mState=" + apnContext.getState() + ", apnEnabled="
+ + apnContext.isEnabled() + ", mDependencyMet="
+ + apnContext.getDependencyMet() + "] ");
- if (!apnContext.isConnectable()) {
- str.append("isConnectable = false. ");
- }
- if (!isDataAllowed) {
- str.append("data not allowed: " + failureReason.getDataAllowFailReason() + ". ");
- }
- if (!isDataAllowedForApn(apnContext)) {
- str.append("isDataAllowedForApn = false. RAT = " +
- mPhone.getServiceState().getRilDataRadioTechnology());
- }
if (!mDataEnabledSettings.isDataEnabled()) {
- str.append("isDataEnabled() = false. "
- + "isInternalDataEnabled = " + mDataEnabledSettings.isInternalDataEnabled()
- + ", userDataEnabled = " + mDataEnabledSettings.isUserDataEnabled()
- + ", isPolicyDataEnabled = " + mDataEnabledSettings.isPolicyDataEnabled()
- + ", isCarrierDataEnabled = "
- + mDataEnabledSettings.isCarrierDataEnabled());
+ str.append("isDataEnabled() = false. " + mDataEnabledSettings);
}
- if (isEmergency()) {
- str.append("emergency = true");
+
+ // If this is a data retry, we should set the APN state to FAILED so it won't stay
+ // in SCANNING forever.
+ if (apnContext.getState() == DctConstants.State.SCANNING) {
+ apnContext.setState(DctConstants.State.FAILED);
+ str.append(" Stop retrying.");
}
if (DBG) log(str.toString());
apnContext.requestLog(str.toString());
-
return false;
}
}
// Disabled apn's still need avail/unavail notifications - send them out
private void notifyOffApnsOfAvailability(String reason) {
- if (DBG) {
- DataAllowFailReason failureReason = new DataAllowFailReason();
- if (!isDataAllowed(failureReason)) {
- log(failureReason.getDataAllowFailReason());
- }
- }
for (ApnContext apnContext : mApnContexts.values()) {
if (!mAttached.get() || !apnContext.isReady()) {
if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
@@ -1738,8 +1580,7 @@
// Use ApnSetting to decide metered or non-metered.
// Tear down all metered data connections.
ApnSetting apnSetting = apnContext.getApnSetting();
- if (apnSetting != null && apnSetting.isMetered(mPhone.getContext(),
- mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())) {
+ if (apnSetting != null && apnSetting.isMetered(mPhone)) {
if (DBG) log("clean up metered ApnContext Type: " + apnContext.getApnType());
apnContext.setReason(reason);
cleanUpConnection(tearDown, apnContext);
@@ -1876,7 +1717,12 @@
apnContext.requestLog(str);
}
- ApnSetting fetchDunApn() {
+ /**
+ * Fetch dun apn
+ * @return ApnSetting to be used for dun
+ */
+ @VisibleForTesting
+ public ApnSetting fetchDunApn() {
if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) {
log("fetchDunApn: net.tethering.noprovisioning=true ret: null");
return null;
@@ -1887,32 +1733,39 @@
ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
ApnSetting retDunSetting = null;
- // Places to look for tether APN in order: TETHER_DUN_APN setting, APN database if
- // carrier allows it, and config_tether_apndata resource.
+ // Places to look for tether APN in order: TETHER_DUN_APN setting (to be deprecated soon),
+ // APN database, and config_tether_apndata resource (to be deprecated soon).
String apnData = Settings.Global.getString(mResolver, Settings.Global.TETHER_DUN_APN);
if (!TextUtils.isEmpty(apnData)) {
dunCandidates.addAll(ApnSetting.arrayFromString(apnData));
if (VDBG) log("fetchDunApn: dunCandidates from Setting: " + dunCandidates);
- } else if (mAllowUserEditTetherApn) {
- for (ApnSetting apn : mAllApnSettings) {
- if (apn.canHandleType(PhoneConstants.APN_TYPE_DUN)) {
- dunCandidates.add(apn);
- }
- }
- if (VDBG) log("fetchDunApn: dunCandidates from database: " + dunCandidates);
}
- // If TETHER_DUN_APN isn't set or
- // mAllowUserEditTetherApn is true but APN database doesn't have dun APN,
+
+ // todo: remove this and config_tether_apndata after APNs are moved from overlay to apns xml
+ // If TETHER_DUN_APN isn't set or APN database doesn't have dun APN,
// try the resource as last resort.
if (dunCandidates.isEmpty()) {
String[] apnArrayData = mPhone.getContext().getResources()
.getStringArray(R.array.config_tether_apndata);
- for (String apnString : apnArrayData) {
- ApnSetting apn = ApnSetting.fromString(apnString);
- // apn may be null if apnString isn't valid or has error parsing
- if (apn != null) dunCandidates.add(apn);
+ if (!ArrayUtils.isEmpty(apnArrayData)) {
+ for (String apnString : apnArrayData) {
+ ApnSetting apn = ApnSetting.fromString(apnString);
+ // apn may be null if apnString isn't valid or has error parsing
+ if (apn != null) dunCandidates.add(apn);
+ }
+ if (VDBG) log("fetchDunApn: dunCandidates from resource: " + dunCandidates);
}
- if (VDBG) log("fetchDunApn: dunCandidates from resource: " + dunCandidates);
+ }
+
+ if (dunCandidates.isEmpty()) {
+ if (!ArrayUtils.isEmpty(mAllApnSettings)) {
+ for (ApnSetting apn : mAllApnSettings) {
+ if (apn.canHandleType(PhoneConstants.APN_TYPE_DUN)) {
+ dunCandidates.add(apn);
+ }
+ }
+ if (VDBG) log("fetchDunApn: dunCandidates from database: " + dunCandidates);
+ }
}
for (ApnSetting dunSetting : dunCandidates) {
@@ -1986,8 +1839,8 @@
return result;
}
- boolean isPermanentFail(DcFailCause dcFailCause) {
- return (dcFailCause.isPermanentFail() &&
+ boolean isPermanentFailure(DcFailCause dcFailCause) {
+ return (dcFailCause.isPermanentFailure(mPhone.getContext(), mPhone.getSubId()) &&
(mAttached.get() == false || dcFailCause != DcFailCause.SIGNAL_LOST));
}
@@ -2099,6 +1952,15 @@
return null;
}
+ /**
+ * Setup a data connection based on given APN type.
+ *
+ * @param apnContext APN context
+ * @param radioTech RAT of the data connection
+ * @param unmeteredUseOnly True if this data connection should be only used for unmetered
+ * purposes only.
+ * @return True if successful, otherwise false.
+ */
private boolean setupData(ApnContext apnContext, int radioTech, boolean unmeteredUseOnly) {
if (DBG) log("setupData: apnContext=" + apnContext);
apnContext.requestLog("setupData");
@@ -2243,7 +2105,7 @@
if (DBG) log("setInitialAttachApn: X selected Apn=" + initialAttachApnSetting);
mPhone.mCi.setInitialAttachApn(new DataProfile(initialAttachApnSetting),
- mPhone.getServiceState().getDataRoaming(), null);
+ mPhone.getServiceState().getDataRoamingFromRegistration(), null);
}
}
@@ -2265,7 +2127,7 @@
if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections");
createAllApnList();
setInitialAttachApn();
- cleanUpConnectionsOnUpdatedApns(!isDisconnected);
+ cleanUpConnectionsOnUpdatedApns(!isDisconnected, Phone.REASON_APN_CHANGED);
// FIXME: See bug 17426028 maybe no conditional is needed.
if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubscriptionId()) {
@@ -2316,7 +2178,7 @@
private boolean isOnlySingleDcAllowed(int rilRadioTech) {
// Default single dc rats with no knowledge of carrier
int[] singleDcRats = null;
- // get the carrier specific value, if it exists, from CarrierConfigManager
+ // get the carrier specific value, if it exists, from CarrierConfigManager.
// generally configManager and bundle should not be null, but if they are it should be okay
// to leave singleDcRats null as well
CarrierConfigManager configManager = (CarrierConfigManager)
@@ -2416,7 +2278,7 @@
private void notifyNoData(DcFailCause lastFailCauseCode,
ApnContext apnContext) {
if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
- if (isPermanentFail(lastFailCauseCode)
+ if (isPermanentFailure(lastFailCauseCode)
&& (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT))) {
mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
}
@@ -2460,7 +2322,7 @@
if (!enabled) {
// Send otasp_sim_unprovisioned so that SuW is able to proceed and notify users
- mPhone.notifyOtaspChanged(ServiceStateTracker.OTASP_SIM_UNPROVISIONED);
+ mPhone.notifyOtaspChanged(TelephonyManager.OTASP_SIM_UNPROVISIONED);
// Tear down all metered apns
cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
} else {
@@ -2512,12 +2374,12 @@
private void onSetPolicyDataEnabled(boolean enabled) {
synchronized (mDataEnabledSettings) {
- final boolean prevEnabled = getAnyDataEnabled();
+ final boolean prevEnabled = isDataEnabled();
if (mDataEnabledSettings.isPolicyDataEnabled() != enabled) {
mDataEnabledSettings.setPolicyDataEnabled(enabled);
// TODO: We should register for DataEnabledSetting's data enabled/disabled event and
// handle the rest from there.
- if (prevEnabled != getAnyDataEnabled()) {
+ if (prevEnabled != isDataEnabled()) {
if (!prevEnabled) {
reevaluateDataConnections();
onTrySetupData(Phone.REASON_DATA_ENABLED);
@@ -2544,7 +2406,6 @@
DctConstants.State state = apnContext.getState();
switch(state) {
case CONNECTING:
- case SCANNING:
case CONNECTED:
case DISCONNECTING:
// We're "READY" and active so just return
@@ -2554,6 +2415,7 @@
case IDLE:
// fall through: this is unexpected but if it happens cleanup and try setup
case FAILED:
+ case SCANNING:
case RETRYING: {
// We're "READY" but not active so disconnect (cleanup = true) and
// connect (trySetup = true) to be sure we retry the connection.
@@ -2766,9 +2628,9 @@
}
/**
- * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value.
+ * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value for user modification only
*/
- public void setDataRoamingEnabled(boolean enabled) {
+ public void setDataRoamingEnabledByUser(boolean enabled) {
final int phoneSubId = mPhone.getSubId();
if (getDataRoamingEnabled() != enabled) {
int roaming = enabled ? 1 : 0;
@@ -2776,6 +2638,7 @@
// For single SIM phones, this is a per phone property.
if (TelephonyManager.getDefault().getSimCount() == 1) {
Settings.Global.putInt(mResolver, Settings.Global.DATA_ROAMING, roaming);
+ setDataRoamingFromUserAction(true);
} else {
Settings.Global.putInt(mResolver, Settings.Global.DATA_ROAMING +
phoneSubId, roaming);
@@ -2784,12 +2647,12 @@
mSubscriptionManager.setDataRoaming(roaming, phoneSubId);
// will trigger handleDataOnRoamingChange() through observer
if (DBG) {
- log("setDataRoamingEnabled: set phoneSubId=" + phoneSubId
+ log("setDataRoamingEnabledByUser: set phoneSubId=" + phoneSubId
+ " isRoaming=" + enabled);
}
} else {
if (DBG) {
- log("setDataRoamingEnabled: unchanged phoneSubId=" + phoneSubId
+ log("setDataRoamingEnabledByUser: unchanged phoneSubId=" + phoneSubId
+ " isRoaming=" + enabled);
}
}
@@ -2799,21 +2662,21 @@
* Return current {@link android.provider.Settings.Global#DATA_ROAMING} value.
*/
public boolean getDataRoamingEnabled() {
- boolean isDataRoamingEnabled = "true".equalsIgnoreCase(SystemProperties.get(
- "ro.com.android.dataroaming", "false"));
+ boolean isDataRoamingEnabled;
final int phoneSubId = mPhone.getSubId();
try {
// For single SIM phones, this is a per phone property.
if (TelephonyManager.getDefault().getSimCount() == 1) {
isDataRoamingEnabled = Settings.Global.getInt(mResolver,
- Settings.Global.DATA_ROAMING, isDataRoamingEnabled ? 1 : 0) != 0;
+ Settings.Global.DATA_ROAMING, getDefaultDataRoamingEnabled() ? 1 : 0) != 0;
} else {
isDataRoamingEnabled = TelephonyManager.getIntWithSubId(mResolver,
Settings.Global.DATA_ROAMING, phoneSubId) != 0;
}
} catch (SettingNotFoundException snfe) {
if (DBG) log("getDataRoamingEnabled: SettingNofFoundException snfe=" + snfe);
+ isDataRoamingEnabled = getDefaultDataRoamingEnabled();
}
if (VDBG) {
log("getDataRoamingEnabled: phoneSubId=" + phoneSubId
@@ -2822,6 +2685,70 @@
return isDataRoamingEnabled;
}
+ /**
+ * get default values for {@link Settings.Global#DATA_ROAMING}
+ * return {@code true} if either
+ * {@link CarrierConfigManager#KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL} or
+ * system property ro.com.android.dataroaming is set to true. otherwise return {@code false}
+ */
+ private boolean getDefaultDataRoamingEnabled() {
+ final CarrierConfigManager configMgr = (CarrierConfigManager)
+ mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ boolean isDataRoamingEnabled = "true".equalsIgnoreCase(SystemProperties.get(
+ "ro.com.android.dataroaming", "false"));
+ isDataRoamingEnabled |= configMgr.getConfigForSubId(mPhone.getSubId()).getBoolean(
+ CarrierConfigManager.KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL);
+ return isDataRoamingEnabled;
+ }
+
+ /**
+ * Set default value for {@link android.provider.Settings.Global#DATA_ROAMING}
+ * if the setting is not from user actions. default value is based on carrier config and system
+ * properties.
+ */
+ private void setDefaultDataRoamingEnabled() {
+ // For single SIM phones, this is a per phone property.
+ String setting = Settings.Global.DATA_ROAMING;
+ boolean useCarrierSpecificDefault = false;
+ if (TelephonyManager.getDefault().getSimCount() != 1) {
+ setting = setting + mPhone.getSubId();
+ try {
+ Settings.Global.getInt(mResolver, setting);
+ } catch (SettingNotFoundException ex) {
+ // For msim, update to carrier default if uninitialized.
+ useCarrierSpecificDefault = true;
+ }
+ } else if (!isDataRoamingFromUserAction()) {
+ // for single sim device, update to carrier default if user action is not set
+ useCarrierSpecificDefault = true;
+ }
+ if (useCarrierSpecificDefault) {
+ boolean defaultVal = getDefaultDataRoamingEnabled();
+ log("setDefaultDataRoamingEnabled: " + setting + "default value: " + defaultVal);
+ Settings.Global.putInt(mResolver, setting, defaultVal ? 1 : 0);
+ mSubscriptionManager.setDataRoaming(defaultVal ? 1 : 0, mPhone.getSubId());
+ }
+ }
+
+ private boolean isDataRoamingFromUserAction() {
+ final SharedPreferences sp = PreferenceManager
+ .getDefaultSharedPreferences(mPhone.getContext());
+ // since we don't want to unset user preference from system update, pass true as the default
+ // value if shared pref does not exist and set shared pref to false explicitly from factory
+ // reset.
+ if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)
+ && Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
+ sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit();
+ }
+ return sp.getBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true);
+ }
+
+ private void setDataRoamingFromUserAction(boolean isUserAction) {
+ final SharedPreferences.Editor sp = PreferenceManager
+ .getDefaultSharedPreferences(mPhone.getContext()).edit();
+ sp.putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, isUserAction).commit();
+ }
+
// When the data roaming status changes from roaming to non-roaming.
private void onDataRoamingOff() {
if (DBG) log("onDataRoamingOff");
@@ -3118,7 +3045,7 @@
// If the data call failure cause is a permanent failure, we mark the APN as permanent
// failed.
- if (isPermanentFail(cause)) {
+ if (isPermanentFailure(cause)) {
log("cause = " + cause + ", mark apn as permanent failed. apn = " + apn);
apnContext.markApnPermanentFailed(apn);
}
@@ -3251,7 +3178,7 @@
// we're not tying up the RIL command channel.
// This also helps in any external dependency to turn off the context.
if (DBG) log("onDisconnectDone: attached, ready and retry after disconnect");
- long delay = apnContext.getInterApnDelay(mFailFast);
+ long delay = apnContext.getRetryAfterDisconnectDelay();
if (delay > 0) {
// Data connection is in IDLE state, so when we reconnect later, we'll rebuild
// the waiting APN list, which will also reset/reconfigure the retry manager.
@@ -3376,7 +3303,6 @@
if (DBG) log("setDataProfilesAsNeeded");
if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) {
ArrayList<DataProfile> dps = new ArrayList<DataProfile>();
- boolean isRoaming = mPhone.getServiceState().getDataRoaming();
for (ApnSetting apn : mAllApnSettings) {
if (apn.modemCognitive) {
DataProfile dp = new DataProfile(apn);
@@ -3387,7 +3313,7 @@
}
if (dps.size() > 0) {
mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[0]),
- mPhone.getServiceState().getDataRoaming(), null);
+ mPhone.getServiceState().getDataRoamingFromRegistration(), null);
}
}
}
@@ -3454,7 +3380,7 @@
int j = i + 1;
while (j < mAllApnSettings.size()) {
second = mAllApnSettings.get(j);
- if (apnsSimilar(first, second)) {
+ if (first.similar(second)) {
ApnSetting newApn = mergeApns(first, second);
mAllApnSettings.set(i, newApn);
first = newApn;
@@ -3467,64 +3393,6 @@
}
}
- //check whether the types of two APN same (even only one type of each APN is same)
- private boolean apnTypeSameAny(ApnSetting first, ApnSetting second) {
- if(VDBG) {
- StringBuilder apnType1 = new StringBuilder(first.apn + ": ");
- for(int index1 = 0; index1 < first.types.length; index1++) {
- apnType1.append(first.types[index1]);
- apnType1.append(",");
- }
-
- StringBuilder apnType2 = new StringBuilder(second.apn + ": ");
- for(int index1 = 0; index1 < second.types.length; index1++) {
- apnType2.append(second.types[index1]);
- apnType2.append(",");
- }
- log("APN1: is " + apnType1);
- log("APN2: is " + apnType2);
- }
-
- for(int index1 = 0; index1 < first.types.length; index1++) {
- for(int index2 = 0; index2 < second.types.length; index2++) {
- if(first.types[index1].equals(PhoneConstants.APN_TYPE_ALL) ||
- second.types[index2].equals(PhoneConstants.APN_TYPE_ALL) ||
- first.types[index1].equals(second.types[index2])) {
- if(VDBG)log("apnTypeSameAny: return true");
- return true;
- }
- }
- }
-
- if(VDBG)log("apnTypeSameAny: return false");
- return false;
- }
-
- // Check if neither mention DUN and are substantially similar
- private boolean apnsSimilar(ApnSetting first, ApnSetting second) {
- return (first.canHandleType(PhoneConstants.APN_TYPE_DUN) == false &&
- second.canHandleType(PhoneConstants.APN_TYPE_DUN) == false &&
- Objects.equals(first.apn, second.apn) &&
- !apnTypeSameAny(first, second) &&
- xorEquals(first.proxy, second.proxy) &&
- xorEquals(first.port, second.port) &&
- first.carrierEnabled == second.carrierEnabled &&
- first.bearerBitmask == second.bearerBitmask &&
- first.profileId == second.profileId &&
- Objects.equals(first.mvnoType, second.mvnoType) &&
- Objects.equals(first.mvnoMatchData, second.mvnoMatchData) &&
- xorEquals(first.mmsc, second.mmsc) &&
- xorEquals(first.mmsProxy, second.mmsProxy) &&
- xorEquals(first.mmsPort, second.mmsPort));
- }
-
- // equal or one is not specified
- private boolean xorEquals(String first, String second) {
- return (Objects.equals(first, second) ||
- TextUtils.isEmpty(first) ||
- TextUtils.isEmpty(second));
- }
-
private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) {
int id = dest.id;
ArrayList<String> resultTypes = new ArrayList<String>();
@@ -3853,6 +3721,15 @@
break;
case DctConstants.EVENT_DATA_RAT_CHANGED:
+ if (mPhone.getServiceState().getRilDataRadioTechnology()
+ == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
+ // unknown rat is an exception for data rat change. It's only received when out
+ // of service and is not applicable for apn bearer bitmask. We should bypass the
+ // check of waiting apn list and keep the data connection on, and no need to
+ // setup a new one.
+ break;
+ }
+ cleanUpConnectionsOnUpdatedApns(false, Phone.REASON_NW_TYPE_CHANGED);
//May new Network allow setupData, so try it here
setupDataOnConnectableApns(Phone.REASON_NW_TYPE_CHANGED,
RetryFailures.ONLY_ON_CHANGE);
@@ -4092,6 +3969,9 @@
case DctConstants.EVENT_SET_CARRIER_DATA_ENABLED:
onSetCarrierDataEnabled((AsyncResult) msg.obj);
break;
+ case DctConstants.EVENT_DATA_RECONNECT:
+ onDataReconnect(msg.getData());
+ break;
default:
Rlog.e("DcTracker", "Unhandled event=" + msg);
break;
@@ -4274,9 +4154,8 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("DcTracker:");
pw.println(" RADIO_TESTS=" + RADIO_TESTS);
- pw.println(" isInternalDataEnabled=" + mDataEnabledSettings.isInternalDataEnabled());
- pw.println(" isUserDataEnabled=" + mDataEnabledSettings.isUserDataEnabled());
- pw.println(" isPolicyDataEnabled=" + mDataEnabledSettings.isPolicyDataEnabled());
+ pw.println(" mDataEnabledSettings=" + mDataEnabledSettings);
+ pw.println(" isDataAllowed=" + isDataAllowed(null));
pw.flush();
pw.println(" mRequestedApnType=" + mRequestedApnType);
pw.println(" mPhone=" + mPhone.getPhoneName());
@@ -4452,39 +4331,48 @@
}
}
- private void cleanUpConnectionsOnUpdatedApns(boolean tearDown) {
+ private boolean containsAllApns(ArrayList<ApnSetting> oldApnList,
+ ArrayList<ApnSetting> newApnList) {
+ for (ApnSetting newApnSetting : newApnList) {
+ boolean canHandle = false;
+ for (ApnSetting oldApnSetting : oldApnList) {
+ // Make sure at least one of the APN from old list can cover the new APN
+ if (oldApnSetting.equals(newApnSetting,
+ mPhone.getServiceState().getDataRoamingFromRegistration())) {
+ canHandle = true;
+ break;
+ }
+ }
+ if (!canHandle) return false;
+ }
+ return true;
+ }
+
+ private void cleanUpConnectionsOnUpdatedApns(boolean tearDown, String reason) {
if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown);
- if (mAllApnSettings.isEmpty()) {
+ if (mAllApnSettings != null && mAllApnSettings.isEmpty()) {
cleanUpAllConnections(tearDown, Phone.REASON_APN_CHANGED);
} else {
for (ApnContext apnContext : mApnContexts.values()) {
- if (VDBG) log("cleanUpConnectionsOnUpdatedApns for "+ apnContext);
-
- boolean cleanUpApn = true;
ArrayList<ApnSetting> currentWaitingApns = apnContext.getWaitingApns();
-
- if ((currentWaitingApns != null) && (!apnContext.isDisconnected())) {
- int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
- ArrayList<ApnSetting> waitingApns = buildWaitingApns(
- apnContext.getApnType(), radioTech);
- if (VDBG) log("new waitingApns:" + waitingApns);
- if (waitingApns.size() == currentWaitingApns.size()) {
- cleanUpApn = false;
- for (int i = 0; i < waitingApns.size(); i++) {
- if (!currentWaitingApns.get(i).equals(waitingApns.get(i))) {
- if (VDBG) log("new waiting apn is different at " + i);
- cleanUpApn = true;
- apnContext.setWaitingApns(waitingApns);
- break;
- }
- }
+ ArrayList<ApnSetting> waitingApns = buildWaitingApns(
+ apnContext.getApnType(),
+ mPhone.getServiceState().getRilDataRadioTechnology());
+ if (VDBG) log("new waitingApns:" + waitingApns);
+ if ((currentWaitingApns != null)
+ && ((waitingApns.size() != currentWaitingApns.size())
+ // Check if the existing waiting APN list can cover the newly built APN
+ // list. If yes, then we don't need to tear down the existing data call.
+ // TODO: We probably need to rebuild APN list when roaming status changes.
+ || !containsAllApns(currentWaitingApns, waitingApns))) {
+ if (VDBG) log("new waiting apn is different for " + apnContext);
+ apnContext.setWaitingApns(waitingApns);
+ if (!apnContext.isDisconnected()) {
+ if (VDBG) log("cleanUpConnectionsOnUpdatedApns for " + apnContext);
+ apnContext.setReason(reason);
+ cleanUpConnection(true, apnContext);
}
}
-
- if (cleanUpApn) {
- apnContext.setReason(Phone.REASON_APN_CHANGED);
- cleanUpConnection(true, apnContext);
- }
}
}
@@ -4859,7 +4747,7 @@
intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag);
mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ mAlarmManager.set(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent);
} else {
if (VDBG_STALL) {
diff --git a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index 355629a..ad325ea 100644
--- a/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/src/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -791,14 +791,14 @@
processCode() throws CallStateException {
try {
if (isShortCode()) {
- Rlog.d(LOG_TAG, "isShortCode");
+ Rlog.d(LOG_TAG, "processCode: isShortCode");
// These just get treated as USSD.
sendUssd(mDialingNumber);
} else if (mDialingNumber != null) {
// We should have no dialing numbers here
throw new RuntimeException ("Invalid or Unsupported MMI Code");
} else if (mSc != null && mSc.equals(SC_CLIP)) {
- Rlog.d(LOG_TAG, "is CLIP");
+ Rlog.d(LOG_TAG, "processCode: is CLIP");
if (isInterrogate()) {
mPhone.mCi.queryCLIP(
obtainMessage(EVENT_QUERY_COMPLETE, this));
@@ -806,7 +806,7 @@
throw new RuntimeException ("Invalid or Unsupported MMI Code");
}
} else if (mSc != null && mSc.equals(SC_CLIR)) {
- Rlog.d(LOG_TAG, "is CLIR");
+ Rlog.d(LOG_TAG, "processCode: is CLIR");
if (isActivate()) {
mPhone.mCi.setCLIR(CommandsInterface.CLIR_INVOCATION,
obtainMessage(EVENT_SET_COMPLETE, this));
@@ -820,7 +820,7 @@
throw new RuntimeException ("Invalid or Unsupported MMI Code");
}
} else if (isServiceCodeCallForwarding(mSc)) {
- Rlog.d(LOG_TAG, "is CF");
+ Rlog.d(LOG_TAG, "processCode: is CF");
String dialingNumber = mSia;
int serviceClass = siToServiceClass(mSib);
@@ -866,7 +866,7 @@
((cfAction == CommandsInterface.CF_ACTION_ENABLE) ||
(cfAction == CommandsInterface.CF_ACTION_REGISTRATION)) ? 1 : 0;
- Rlog.d(LOG_TAG, "is CF setCallForward");
+ Rlog.d(LOG_TAG, "processCode: is CF setCallForward");
mPhone.mCi.setCallForward(cfAction, reason, serviceClass,
dialingNumber, time, obtainMessage(
EVENT_SET_CFF_COMPLETE,
@@ -957,7 +957,8 @@
// Sim is puk-locked
handlePasswordError(com.android.internal.R.string.needPuk);
} else if (mUiccApplication != null) {
- Rlog.d(LOG_TAG, "process mmi service code using UiccApp sc=" + mSc);
+ Rlog.d(LOG_TAG,
+ "processCode: process mmi service code using UiccApp sc=" + mSc);
// We have an app and the pre-checks are OK
if (mSc.equals(SC_PIN)) {
@@ -984,11 +985,13 @@
} else if (mPoundString != null) {
sendUssd(mPoundString);
} else {
+ Rlog.d(LOG_TAG, "processCode: Invalid or Unsupported MMI Code");
throw new RuntimeException ("Invalid or Unsupported MMI Code");
}
} catch (RuntimeException exc) {
mState = State.FAILED;
mMessage = mContext.getText(com.android.internal.R.string.mmiError);
+ Rlog.d(LOG_TAG, "processCode: RuntimeException=" + exc);
mPhone.onMMIDone(this);
}
}
@@ -1014,7 +1017,8 @@
public void
onUssdFinished(String ussdMessage, boolean isUssdRequest) {
if (mState == State.PENDING) {
- if (ussdMessage == null) {
+ if (TextUtils.isEmpty(ussdMessage)) {
+ Rlog.d(LOG_TAG, "onUssdFinished: no network provided message; using default.");
mMessage = mContext.getText(com.android.internal.R.string.mmiComplete);
} else {
mMessage = ussdMessage;
@@ -1024,7 +1028,7 @@
if (!isUssdRequest) {
mState = State.COMPLETE;
}
-
+ Rlog.d(LOG_TAG, "onUssdFinished: ussdMessage=" + ussdMessage);
mPhone.onMMIDone(this);
}
}
@@ -1040,7 +1044,7 @@
if (mState == State.PENDING) {
mState = State.FAILED;
mMessage = mContext.getText(com.android.internal.R.string.mmiError);
-
+ Rlog.d(LOG_TAG, "onUssdFinishedError");
mPhone.onMMIDone(this);
}
}
@@ -1059,7 +1063,7 @@
if (mState == State.PENDING) {
mState = State.COMPLETE;
mMessage = null;
-
+ Rlog.d(LOG_TAG, "onUssdRelease");
mPhone.onMMIDone(this);
}
}
@@ -1301,6 +1305,7 @@
}
mMessage = sb;
+ Rlog.d(LOG_TAG, "onSetComplete mmi=" + this);
mPhone.onMMIDone(this);
}
@@ -1382,6 +1387,7 @@
}
mMessage = sb;
+ Rlog.d(LOG_TAG, "onGetClirComplete: mmi=" + this);
mPhone.onMMIDone(this);
}
@@ -1534,6 +1540,7 @@
}
mMessage = sb;
+ Rlog.d(LOG_TAG, "onQueryCfComplete: mmi=" + this);
mPhone.onMMIDone(this);
}
@@ -1571,6 +1578,7 @@
}
mMessage = sb;
+ Rlog.d(LOG_TAG, "onQueryComplete: mmi=" + this);
mPhone.onMMIDone(this);
}
@@ -1629,8 +1637,11 @@
if (mSib != null) sb.append(" sib=" + Rlog.pii(LOG_TAG, mSib));
if (mSic != null) sb.append(" sic=" + Rlog.pii(LOG_TAG, mSic));
if (mPoundString != null) sb.append(" poundString=" + Rlog.pii(LOG_TAG, mPoundString));
- if (mDialingNumber != null) sb.append(" dialingNumber=" + mDialingNumber);
- if (mPwd != null) sb.append(" pwd=" + mPwd);
+ if (mDialingNumber != null) {
+ sb.append(" dialingNumber=" + Rlog.pii(LOG_TAG, mDialingNumber));
+ }
+ if (mPwd != null) sb.append(" pwd=" + Rlog.pii(LOG_TAG, mPwd));
+ if (mCallbackReceiver != null) sb.append(" hasReceiver");
sb.append("}");
return sb.toString();
}
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSmsAddress.java b/src/java/com/android/internal/telephony/gsm/GsmSmsAddress.java
deleted file mode 100644
index 2fbf7ed..0000000
--- a/src/java/com/android/internal/telephony/gsm/GsmSmsAddress.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.telephony.PhoneNumberUtils;
-import java.text.ParseException;
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.SmsAddress;
-
-public class GsmSmsAddress extends SmsAddress {
-
- static final int OFFSET_ADDRESS_LENGTH = 0;
-
- static final int OFFSET_TOA = 1;
-
- static final int OFFSET_ADDRESS_VALUE = 2;
-
- /**
- * New GsmSmsAddress from TS 23.040 9.1.2.5 Address Field
- *
- * @param offset the offset of the Address-Length byte
- * @param length the length in bytes rounded up, e.g. "2 +
- * (addressLength + 1) / 2"
- * @throws ParseException
- */
-
- public GsmSmsAddress(byte[] data, int offset, int length) throws ParseException {
- origBytes = new byte[length];
- System.arraycopy(data, offset, origBytes, 0, length);
-
- // addressLength is the count of semi-octets, not bytes
- int addressLength = origBytes[OFFSET_ADDRESS_LENGTH] & 0xff;
-
- int toa = origBytes[OFFSET_TOA] & 0xff;
- ton = 0x7 & (toa >> 4);
-
- // TOA must have its high bit set
- if ((toa & 0x80) != 0x80) {
- throw new ParseException("Invalid TOA - high bit must be set. toa = " + toa,
- offset + OFFSET_TOA);
- }
-
- if (isAlphanumeric()) {
- // An alphanumeric address
- int countSeptets = addressLength * 4 / 7;
-
- address = GsmAlphabet.gsm7BitPackedToString(origBytes,
- OFFSET_ADDRESS_VALUE, countSeptets);
- } else {
- // TS 23.040 9.1.2.5 says
- // that "the MS shall interpret reserved values as 'Unknown'
- // but shall store them exactly as received"
-
- byte lastByte = origBytes[length - 1];
-
- if ((addressLength & 1) == 1) {
- // Make sure the final unused BCD digit is 0xf
- origBytes[length - 1] |= 0xf0;
- }
- address = PhoneNumberUtils.calledPartyBCDToString(origBytes,
- OFFSET_TOA, length - OFFSET_TOA);
-
- // And restore origBytes
- origBytes[length - 1] = lastByte;
- }
- }
-
- @Override
- public String getAddressString() {
- return address;
- }
-
- /**
- * Returns true if this is an alphanumeric address
- */
- @Override
- public boolean isAlphanumeric() {
- return ton == TON_ALPHANUMERIC;
- }
-
- @Override
- public boolean isNetworkSpecific() {
- return ton == TON_NETWORK;
- }
-
- /**
- * Returns true of this is a valid CPHS voice message waiting indicator
- * address
- */
- public boolean isCphsVoiceMessageIndicatorAddress() {
- // CPHS-style MWI message
- // See CPHS 4.7 B.4.2.1
- //
- // Basically:
- //
- // - Originating address should be 4 bytes long and alphanumeric
- // - Decode will result with two chars:
- // - Char 1
- // 76543210
- // ^ set/clear indicator (0 = clear)
- // ^^^ type of indicator (000 = voice)
- // ^^^^ must be equal to 0001
- // - Char 2:
- // 76543210
- // ^ line number (0 = line 1)
- // ^^^^^^^ set to 0
- //
- // Remember, since the alpha address is stored in 7-bit compact form,
- // the "line number" is really the top bit of the first address value
- // byte
-
- return (origBytes[OFFSET_ADDRESS_LENGTH] & 0xff) == 4
- && isAlphanumeric() && (origBytes[OFFSET_TOA] & 0x0f) == 0;
- }
-
- /**
- * Returns true if this is a valid CPHS voice message waiting indicator
- * address indicating a "set" of "indicator 1" of type "voice message
- * waiting"
- */
- public boolean isCphsVoiceMessageSet() {
- // 0x11 means "set" "voice message waiting" "indicator 1"
- return isCphsVoiceMessageIndicatorAddress()
- && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x11;
-
- }
-
- /**
- * Returns true if this is a valid CPHS voice message waiting indicator
- * address indicating a "clear" of "indicator 1" of type "voice message
- * waiting"
- */
- public boolean isCphsVoiceMessageClear() {
- // 0x10 means "clear" "voice message waiting" "indicator 1"
- return isCphsVoiceMessageIndicatorAddress()
- && (origBytes[OFFSET_ADDRESS_VALUE] & 0xff) == 0x10;
-
- }
-}
diff --git a/src/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java b/src/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
deleted file mode 100644
index 6bf22a0..0000000
--- a/src/java/com/android/internal/telephony/gsm/GsmSmsCbMessage.java
+++ /dev/null
@@ -1,314 +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 com.android.internal.telephony.gsm;
-
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_OTHER_EMERGENCY;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_TEST_MESSAGE;
-import static android.telephony.SmsCbEtwsInfo.ETWS_WARNING_TYPE_TSUNAMI;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.telephony.SmsCbLocation;
-import android.telephony.SmsCbMessage;
-import android.util.Pair;
-
-import com.android.internal.R;
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.SmsConstants;
-
-import java.io.UnsupportedEncodingException;
-
-/**
- * Parses a GSM or UMTS format SMS-CB message into an {@link SmsCbMessage} object. The class is
- * public because {@link #createSmsCbMessage(SmsCbLocation, byte[][])} is used by some test cases.
- */
-public class GsmSmsCbMessage {
-
- /**
- * Languages in the 0000xxxx DCS group as defined in 3GPP TS 23.038, section 5.
- */
- private static final String[] LANGUAGE_CODES_GROUP_0 = {
- "de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi", "no", "el", "tr", "hu",
- "pl", null
- };
-
- /**
- * Languages in the 0010xxxx DCS group as defined in 3GPP TS 23.038, section 5.
- */
- private static final String[] LANGUAGE_CODES_GROUP_2 = {
- "cs", "he", "ar", "ru", "is", null, null, null, null, null, null, null, null, null,
- null, null
- };
-
- private static final char CARRIAGE_RETURN = 0x0d;
-
- private static final int PDU_BODY_PAGE_LENGTH = 82;
-
- /** Utility class with only static methods. */
- private GsmSmsCbMessage() { }
-
- /**
- * Get built-in ETWS primary messages by category. ETWS primary message does not contain text,
- * so we have to show the pre-built messages to the user.
- *
- * @param context Device context
- * @param category ETWS message category defined in SmsCbConstants
- * @return ETWS text message in string. Return an empty string if no match.
- */
- private static String getEtwsPrimaryMessage(Context context, int category) {
- final Resources r = context.getResources();
- switch (category) {
- case ETWS_WARNING_TYPE_EARTHQUAKE:
- return r.getString(R.string.etws_primary_default_message_earthquake);
- case ETWS_WARNING_TYPE_TSUNAMI:
- return r.getString(R.string.etws_primary_default_message_tsunami);
- case ETWS_WARNING_TYPE_EARTHQUAKE_AND_TSUNAMI:
- return r.getString(R.string.etws_primary_default_message_earthquake_and_tsunami);
- case ETWS_WARNING_TYPE_TEST_MESSAGE:
- return r.getString(R.string.etws_primary_default_message_test);
- case ETWS_WARNING_TYPE_OTHER_EMERGENCY:
- return r.getString(R.string.etws_primary_default_message_others);
- default:
- return "";
- }
- }
-
- /**
- * Create a new SmsCbMessage object from a header object plus one or more received PDUs.
- *
- * @param pdus PDU bytes
- */
- public static SmsCbMessage createSmsCbMessage(Context context, SmsCbHeader header,
- SmsCbLocation location, byte[][] pdus)
- throws IllegalArgumentException {
- if (header.isEtwsPrimaryNotification()) {
- // ETSI TS 23.041 ETWS Primary Notification message
- // ETWS primary message only contains 4 fields including serial number,
- // message identifier, warning type, and warning security information.
- // There is no field for the content/text so we get the text from the resources.
- return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP, header.getGeographicalScope(),
- header.getSerialNumber(), location, header.getServiceCategory(), null,
- getEtwsPrimaryMessage(context, header.getEtwsInfo().getWarningType()),
- SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY, header.getEtwsInfo(),
- header.getCmasInfo());
- } else {
- String language = null;
- StringBuilder sb = new StringBuilder();
- for (byte[] pdu : pdus) {
- Pair<String, String> p = parseBody(header, pdu);
- language = p.first;
- sb.append(p.second);
- }
- int priority = header.isEmergencyMessage() ? SmsCbMessage.MESSAGE_PRIORITY_EMERGENCY
- : SmsCbMessage.MESSAGE_PRIORITY_NORMAL;
-
- return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP,
- header.getGeographicalScope(), header.getSerialNumber(), location,
- header.getServiceCategory(), language, sb.toString(), priority,
- header.getEtwsInfo(), header.getCmasInfo());
- }
- }
-
- /**
- * Parse and unpack the body text according to the encoding in the DCS.
- * After completing successfully this method will have assigned the body
- * text into mBody, and optionally the language code into mLanguage
- *
- * @param header the message header to use
- * @param pdu the PDU to decode
- * @return a Pair of Strings containing the language and body of the message
- */
- private static Pair<String, String> parseBody(SmsCbHeader header, byte[] pdu) {
- int encoding;
- String language = null;
- boolean hasLanguageIndicator = false;
- int dataCodingScheme = header.getDataCodingScheme();
-
- // Extract encoding and language from DCS, as defined in 3gpp TS 23.038,
- // section 5.
- switch ((dataCodingScheme & 0xf0) >> 4) {
- case 0x00:
- encoding = SmsConstants.ENCODING_7BIT;
- language = LANGUAGE_CODES_GROUP_0[dataCodingScheme & 0x0f];
- break;
-
- case 0x01:
- hasLanguageIndicator = true;
- if ((dataCodingScheme & 0x0f) == 0x01) {
- encoding = SmsConstants.ENCODING_16BIT;
- } else {
- encoding = SmsConstants.ENCODING_7BIT;
- }
- break;
-
- case 0x02:
- encoding = SmsConstants.ENCODING_7BIT;
- language = LANGUAGE_CODES_GROUP_2[dataCodingScheme & 0x0f];
- break;
-
- case 0x03:
- encoding = SmsConstants.ENCODING_7BIT;
- break;
-
- case 0x04:
- case 0x05:
- switch ((dataCodingScheme & 0x0c) >> 2) {
- case 0x01:
- encoding = SmsConstants.ENCODING_8BIT;
- break;
-
- case 0x02:
- encoding = SmsConstants.ENCODING_16BIT;
- break;
-
- case 0x00:
- default:
- encoding = SmsConstants.ENCODING_7BIT;
- break;
- }
- break;
-
- case 0x06:
- case 0x07:
- // Compression not supported
- case 0x09:
- // UDH structure not supported
- case 0x0e:
- // Defined by the WAP forum not supported
- throw new IllegalArgumentException("Unsupported GSM dataCodingScheme "
- + dataCodingScheme);
-
- case 0x0f:
- if (((dataCodingScheme & 0x04) >> 2) == 0x01) {
- encoding = SmsConstants.ENCODING_8BIT;
- } else {
- encoding = SmsConstants.ENCODING_7BIT;
- }
- break;
-
- default:
- // Reserved values are to be treated as 7-bit
- encoding = SmsConstants.ENCODING_7BIT;
- break;
- }
-
- if (header.isUmtsFormat()) {
- // Payload may contain multiple pages
- int nrPages = pdu[SmsCbHeader.PDU_HEADER_LENGTH];
-
- if (pdu.length < SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1)
- * nrPages) {
- throw new IllegalArgumentException("Pdu length " + pdu.length + " does not match "
- + nrPages + " pages");
- }
-
- StringBuilder sb = new StringBuilder();
-
- for (int i = 0; i < nrPages; i++) {
- // Each page is 82 bytes followed by a length octet indicating
- // the number of useful octets within those 82
- int offset = SmsCbHeader.PDU_HEADER_LENGTH + 1 + (PDU_BODY_PAGE_LENGTH + 1) * i;
- int length = pdu[offset + PDU_BODY_PAGE_LENGTH];
-
- if (length > PDU_BODY_PAGE_LENGTH) {
- throw new IllegalArgumentException("Page length " + length
- + " exceeds maximum value " + PDU_BODY_PAGE_LENGTH);
- }
-
- Pair<String, String> p = unpackBody(pdu, encoding, offset, length,
- hasLanguageIndicator, language);
- language = p.first;
- sb.append(p.second);
- }
- return new Pair<String, String>(language, sb.toString());
- } else {
- // Payload is one single page
- int offset = SmsCbHeader.PDU_HEADER_LENGTH;
- int length = pdu.length - offset;
-
- return unpackBody(pdu, encoding, offset, length, hasLanguageIndicator, language);
- }
- }
-
- /**
- * Unpack body text from the pdu using the given encoding, position and
- * length within the pdu
- *
- * @param pdu The pdu
- * @param encoding The encoding, as derived from the DCS
- * @param offset Position of the first byte to unpack
- * @param length Number of bytes to unpack
- * @param hasLanguageIndicator true if the body text is preceded by a
- * language indicator. If so, this method will as a side-effect
- * assign the extracted language code into mLanguage
- * @param language the language to return if hasLanguageIndicator is false
- * @return a Pair of Strings containing the language and body of the message
- */
- private static Pair<String, String> unpackBody(byte[] pdu, int encoding, int offset, int length,
- boolean hasLanguageIndicator, String language) {
- String body = null;
-
- switch (encoding) {
- case SmsConstants.ENCODING_7BIT:
- body = GsmAlphabet.gsm7BitPackedToString(pdu, offset, length * 8 / 7);
-
- if (hasLanguageIndicator && body != null && body.length() > 2) {
- // Language is two GSM characters followed by a CR.
- // The actual body text is offset by 3 characters.
- language = body.substring(0, 2);
- body = body.substring(3);
- }
- break;
-
- case SmsConstants.ENCODING_16BIT:
- if (hasLanguageIndicator && pdu.length >= offset + 2) {
- // Language is two GSM characters.
- // The actual body text is offset by 2 bytes.
- language = GsmAlphabet.gsm7BitPackedToString(pdu, offset, 2);
- offset += 2;
- length -= 2;
- }
-
- try {
- body = new String(pdu, offset, (length & 0xfffe), "utf-16");
- } catch (UnsupportedEncodingException e) {
- // Apparently it wasn't valid UTF-16.
- throw new IllegalArgumentException("Error decoding UTF-16 message", e);
- }
- break;
-
- default:
- break;
- }
-
- if (body != null) {
- // Remove trailing carriage return
- for (int i = body.length() - 1; i >= 0; i--) {
- if (body.charAt(i) != CARRIAGE_RETURN) {
- body = body.substring(0, i + 1);
- break;
- }
- }
- } else {
- body = "";
- }
-
- return new Pair<String, String>(language, body);
- }
-}
diff --git a/src/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java b/src/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java
deleted file mode 100644
index f4f4036..0000000
--- a/src/java/com/android/internal/telephony/gsm/SmsBroadcastConfigInfo.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-/**
- * SmsBroadcastConfigInfo defines one configuration of Cell Broadcast
- * Message (CBM) to be received by the ME
- *
- * fromServiceId - toServiceId defines a range of CBM message identifiers
- * whose value is 0x0000 - 0xFFFF as defined in TS 23.041 9.4.1.2.2 for GMS
- * and 9.4.4.2.2 for UMTS. All other values can be treated as empty
- * CBM message ID.
- *
- * fromCodeScheme - toCodeScheme defines a range of CBM data coding schemes
- * whose value is 0x00 - 0xFF as defined in TS 23.041 9.4.1.2.3 for GMS
- * and 9.4.4.2.3 for UMTS.
- * All other values can be treated as empty CBM data coding scheme.
- *
- * selected false means message types specified in {@code <fromServiceId, toServiceId>}
- * and {@code <fromCodeScheme, toCodeScheme>} are not accepted, while true means accepted.
- *
- */
-public final class SmsBroadcastConfigInfo {
- private int mFromServiceId;
- private int mToServiceId;
- private int mFromCodeScheme;
- private int mToCodeScheme;
- private boolean mSelected;
-
- /**
- * Initialize the object from rssi and cid.
- */
- public SmsBroadcastConfigInfo(int fromId, int toId, int fromScheme,
- int toScheme, boolean selected) {
- mFromServiceId = fromId;
- mToServiceId = toId;
- mFromCodeScheme = fromScheme;
- mToCodeScheme = toScheme;
- mSelected = selected;
- }
-
- /**
- * @param fromServiceId the fromServiceId to set
- */
- public void setFromServiceId(int fromServiceId) {
- mFromServiceId = fromServiceId;
- }
-
- /**
- * @return the fromServiceId
- */
- public int getFromServiceId() {
- return mFromServiceId;
- }
-
- /**
- * @param toServiceId the toServiceId to set
- */
- public void setToServiceId(int toServiceId) {
- mToServiceId = toServiceId;
- }
-
- /**
- * @return the toServiceId
- */
- public int getToServiceId() {
- return mToServiceId;
- }
-
- /**
- * @param fromCodeScheme the fromCodeScheme to set
- */
- public void setFromCodeScheme(int fromCodeScheme) {
- mFromCodeScheme = fromCodeScheme;
- }
-
- /**
- * @return the fromCodeScheme
- */
- public int getFromCodeScheme() {
- return mFromCodeScheme;
- }
-
- /**
- * @param toCodeScheme the toCodeScheme to set
- */
- public void setToCodeScheme(int toCodeScheme) {
- mToCodeScheme = toCodeScheme;
- }
-
- /**
- * @return the toCodeScheme
- */
- public int getToCodeScheme() {
- return mToCodeScheme;
- }
-
- /**
- * @param selected the selected to set
- */
- public void setSelected(boolean selected) {
- mSelected = selected;
- }
-
- /**
- * @return the selected
- */
- public boolean isSelected() {
- return mSelected;
- }
-
- @Override
- public String toString() {
- return "SmsBroadcastConfigInfo: Id [" +
- mFromServiceId + ',' + mToServiceId + "] Code [" +
- mFromCodeScheme + ',' + mToCodeScheme + "] " +
- (mSelected ? "ENABLED" : "DISABLED");
- }
-}
diff --git a/src/java/com/android/internal/telephony/gsm/SmsCbConstants.java b/src/java/com/android/internal/telephony/gsm/SmsCbConstants.java
deleted file mode 100644
index bce5680..0000000
--- a/src/java/com/android/internal/telephony/gsm/SmsCbConstants.java
+++ /dev/null
@@ -1,217 +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 com.android.internal.telephony.gsm;
-
-/**
- * Constants used in SMS Cell Broadcast messages (see 3GPP TS 23.041). This class is used by the
- * boot-time broadcast channel enable and database upgrade code in CellBroadcastReceiver, so it
- * is public, but should be avoided in favor of the radio technology independent constants in
- * {@link android.telephony.SmsCbMessage}, {@link android.telephony.SmsCbEtwsInfo}, and
- * {@link android.telephony.SmsCbCmasInfo} classes.
- *
- * {@hide}
- */
-public class SmsCbConstants {
-
- /** Private constructor for utility class. */
- private SmsCbConstants() { }
-
- /** Channel 50 required by Brazil. ID 0~999 is allocated by GSMA */
- public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_50
- = 0x0032;
-
- /** Channel 911 required by Taiwan NCC. ID 0~999 is allocated by GSMA */
- public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_911
- = 0x038F; // 911
-
- /** Channel 919 required by Taiwan NCC and Israel. ID 0~999 is allocated by GSMA */
- public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_919
- = 0x0397; // 919
-
- /** Channel 928 required by Israel. ID 0~999 is allocated by GSMA */
- public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_928
- = 0x03A0; // 928
-
- /** Start of PWS Message Identifier range (includes ETWS and CMAS). */
- public static final int MESSAGE_ID_PWS_FIRST_IDENTIFIER
- = 0x1100; // 4352
-
- /** Bitmask for messages of ETWS type (including future extensions). */
- public static final int MESSAGE_ID_ETWS_TYPE_MASK
- = 0xFFF8;
-
- /** Value for messages of ETWS type after applying {@link #MESSAGE_ID_ETWS_TYPE_MASK}. */
- public static final int MESSAGE_ID_ETWS_TYPE
- = 0x1100; // 4352
-
- /** ETWS Message Identifier for earthquake warning message. */
- public static final int MESSAGE_ID_ETWS_EARTHQUAKE_WARNING
- = 0x1100; // 4352
-
- /** ETWS Message Identifier for tsunami warning message. */
- public static final int MESSAGE_ID_ETWS_TSUNAMI_WARNING
- = 0x1101; // 4353
-
- /** ETWS Message Identifier for earthquake and tsunami combined warning message. */
- public static final int MESSAGE_ID_ETWS_EARTHQUAKE_AND_TSUNAMI_WARNING
- = 0x1102; // 4354
-
- /** ETWS Message Identifier for test message. */
- public static final int MESSAGE_ID_ETWS_TEST_MESSAGE
- = 0x1103; // 4355
-
- /** ETWS Message Identifier for messages related to other emergency types. */
- public static final int MESSAGE_ID_ETWS_OTHER_EMERGENCY_TYPE
- = 0x1104; // 4356
-
- /** Start of CMAS Message Identifier range. */
- public static final int MESSAGE_ID_CMAS_FIRST_IDENTIFIER
- = 0x1112; // 4370
-
- /** CMAS Message Identifier for Presidential Level alerts. */
- public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL
- = 0x1112; // 4370
-
- /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed. */
- public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED
- = 0x1113; // 4371
-
- /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely. */
- public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY
- = 0x1114; // 4372
-
- /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed. */
- public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED
- = 0x1115; // 4373
-
- /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely. */
- public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY
- = 0x1116; // 4374
-
- /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed. */
- public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED
- = 0x1117; // 4375
-
- /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely. */
- public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY
- = 0x1118; // 4376
-
- /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed. */
- public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED
- = 0x1119; // 4377
-
- /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely. */
- public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY
- = 0x111A; // 4378
-
- /** CMAS Message Identifier for Child Abduction Emergency (Amber Alert). */
- public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY
- = 0x111B; // 4379
-
- /** CMAS Message Identifier for the Required Monthly Test. */
- public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST
- = 0x111C; // 4380
-
- /** CMAS Message Identifier for CMAS Exercise. */
- public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE
- = 0x111D; // 4381
-
- /** CMAS Message Identifier for operator defined use. */
- public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE
- = 0x111E; // 4382
-
- /** CMAS Message Identifier for Presidential Level alerts for additional languages
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE
- = 0x111F; // 4383
-
- /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Observed
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE
- = 0x1120; // 4384
-
- /** CMAS Message Identifier for Extreme alerts, Urgency=Immediate, Certainty=Likely
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE
- = 0x1121; // 4385
-
- /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Observed
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE
- = 0x1122; // 4386
-
- /** CMAS Message Identifier for Extreme alerts, Urgency=Expected, Certainty=Likely
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE
- = 0x1123; // 4387
-
- /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Observed
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE
- = 0x1124; // 4388
-
- /** CMAS Message Identifier for Severe alerts, Urgency=Immediate, Certainty=Likely
- * for additional languages.*/
- public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE
- = 0x1125; // 4389
-
- /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Observed
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE
- = 0x1126; // 4390
-
- /** CMAS Message Identifier for Severe alerts, Urgency=Expected, Certainty=Likely
- * for additional languages.*/
- public static final int MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE
- = 0x1127; // 4391
-
- /** CMAS Message Identifier for Child Abduction Emergency (Amber Alert)
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE
- = 0x1128; // 4392
-
- /** CMAS Message Identifier for the Required Monthly Test
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE
- = 0x1129; // 4393
-
- /** CMAS Message Identifier for CMAS Exercise
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_EXERCISE_LANGUAGE
- = 0x112A; // 4394
-
- /** CMAS Message Identifier for operator defined use
- * for additional languages. */
- public static final int MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE
- = 0x112B; // 4395
-
- /** End of CMAS Message Identifier range (including future extensions). */
- public static final int MESSAGE_ID_CMAS_LAST_IDENTIFIER
- = 0x112F; // 4399
-
- /** End of PWS Message Identifier range (includes ETWS, CMAS, and future extensions). */
- public static final int MESSAGE_ID_PWS_LAST_IDENTIFIER
- = 0x18FF; // 6399
-
- /** ETWS serial number flag to activate the popup display. */
- public static final int SERIAL_NUMBER_ETWS_ACTIVATE_POPUP
- = 0x1000; // 4096
-
- /** ETWS serial number flag to activate the emergency user alert. */
- public static final int SERIAL_NUMBER_ETWS_EMERGENCY_USER_ALERT
- = 0x2000; // 8192
-}
diff --git a/src/java/com/android/internal/telephony/gsm/SmsCbHeader.java b/src/java/com/android/internal/telephony/gsm/SmsCbHeader.java
deleted file mode 100644
index d267ad2..0000000
--- a/src/java/com/android/internal/telephony/gsm/SmsCbHeader.java
+++ /dev/null
@@ -1,450 +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 com.android.internal.telephony.gsm;
-
-import android.telephony.SmsCbCmasInfo;
-import android.telephony.SmsCbEtwsInfo;
-
-import java.util.Arrays;
-
-/**
- * Parses a 3GPP TS 23.041 cell broadcast message header. This class is public for use by
- * CellBroadcastReceiver test cases, but should not be used by applications.
- *
- * All relevant header information is now sent as a Parcelable
- * {@link android.telephony.SmsCbMessage} object in the "message" extra of the
- * {@link android.provider.Telephony.Sms.Intents#SMS_CB_RECEIVED_ACTION} or
- * {@link android.provider.Telephony.Sms.Intents#SMS_EMERGENCY_CB_RECEIVED_ACTION} intent.
- * The raw PDU is no longer sent to SMS CB applications.
- */
-public class SmsCbHeader {
-
- /**
- * Length of SMS-CB header
- */
- static final int PDU_HEADER_LENGTH = 6;
-
- /**
- * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1
- */
- static final int FORMAT_GSM = 1;
-
- /**
- * UMTS pdu format, as defined in 3gpp TS 23.041, section 9.4.2
- */
- static final int FORMAT_UMTS = 2;
-
- /**
- * GSM pdu format, as defined in 3gpp TS 23.041, section 9.4.1.3
- */
- static final int FORMAT_ETWS_PRIMARY = 3;
-
- /**
- * Message type value as defined in 3gpp TS 25.324, section 11.1.
- */
- private static final int MESSAGE_TYPE_CBS_MESSAGE = 1;
-
- /**
- * Length of GSM pdus
- */
- private static final int PDU_LENGTH_GSM = 88;
-
- /**
- * Maximum length of ETWS primary message GSM pdus
- */
- private static final int PDU_LENGTH_ETWS = 56;
-
- private final int mGeographicalScope;
-
- /** The serial number combines geographical scope, message code, and update number. */
- private final int mSerialNumber;
-
- /** The Message Identifier in 3GPP is the same as the Service Category in CDMA. */
- private final int mMessageIdentifier;
-
- private final int mDataCodingScheme;
-
- private final int mPageIndex;
-
- private final int mNrOfPages;
-
- private final int mFormat;
-
- /** ETWS warning notification info. */
- private final SmsCbEtwsInfo mEtwsInfo;
-
- /** CMAS warning notification info. */
- private final SmsCbCmasInfo mCmasInfo;
-
- public SmsCbHeader(byte[] pdu) throws IllegalArgumentException {
- if (pdu == null || pdu.length < PDU_HEADER_LENGTH) {
- throw new IllegalArgumentException("Illegal PDU");
- }
-
- if (pdu.length <= PDU_LENGTH_GSM) {
- // can be ETWS or GSM format.
- // Per TS23.041 9.4.1.2 and 9.4.1.3.2, GSM and ETWS format both
- // contain serial number which contains GS, Message Code, and Update Number
- // per 9.4.1.2.1, and message identifier in same octets
- mGeographicalScope = (pdu[0] & 0xc0) >>> 6;
- mSerialNumber = ((pdu[0] & 0xff) << 8) | (pdu[1] & 0xff);
- mMessageIdentifier = ((pdu[2] & 0xff) << 8) | (pdu[3] & 0xff);
- if (isEtwsMessage() && pdu.length <= PDU_LENGTH_ETWS) {
- mFormat = FORMAT_ETWS_PRIMARY;
- mDataCodingScheme = -1;
- mPageIndex = -1;
- mNrOfPages = -1;
- boolean emergencyUserAlert = (pdu[4] & 0x1) != 0;
- boolean activatePopup = (pdu[5] & 0x80) != 0;
- int warningType = (pdu[4] & 0xfe) >>> 1;
- byte[] warningSecurityInfo;
- // copy the Warning-Security-Information, if present
- if (pdu.length > PDU_HEADER_LENGTH) {
- warningSecurityInfo = Arrays.copyOfRange(pdu, 6, pdu.length);
- } else {
- warningSecurityInfo = null;
- }
- mEtwsInfo = new SmsCbEtwsInfo(warningType, emergencyUserAlert, activatePopup,
- true, warningSecurityInfo);
- mCmasInfo = null;
- return; // skip the ETWS/CMAS initialization code for regular notifications
- } else {
- // GSM pdus are no more than 88 bytes
- mFormat = FORMAT_GSM;
- mDataCodingScheme = pdu[4] & 0xff;
-
- // Check for invalid page parameter
- int pageIndex = (pdu[5] & 0xf0) >>> 4;
- int nrOfPages = pdu[5] & 0x0f;
-
- if (pageIndex == 0 || nrOfPages == 0 || pageIndex > nrOfPages) {
- pageIndex = 1;
- nrOfPages = 1;
- }
-
- mPageIndex = pageIndex;
- mNrOfPages = nrOfPages;
- }
- } else {
- // UMTS pdus are always at least 90 bytes since the payload includes
- // a number-of-pages octet and also one length octet per page
- mFormat = FORMAT_UMTS;
-
- int messageType = pdu[0];
-
- if (messageType != MESSAGE_TYPE_CBS_MESSAGE) {
- throw new IllegalArgumentException("Unsupported message type " + messageType);
- }
-
- mMessageIdentifier = ((pdu[1] & 0xff) << 8) | pdu[2] & 0xff;
- mGeographicalScope = (pdu[3] & 0xc0) >>> 6;
- mSerialNumber = ((pdu[3] & 0xff) << 8) | (pdu[4] & 0xff);
- mDataCodingScheme = pdu[5] & 0xff;
-
- // We will always consider a UMTS message as having one single page
- // since there's only one instance of the header, even though the
- // actual payload may contain several pages.
- mPageIndex = 1;
- mNrOfPages = 1;
- }
-
- if (isEtwsMessage()) {
- boolean emergencyUserAlert = isEtwsEmergencyUserAlert();
- boolean activatePopup = isEtwsPopupAlert();
- int warningType = getEtwsWarningType();
- mEtwsInfo = new SmsCbEtwsInfo(warningType, emergencyUserAlert, activatePopup,
- false, null);
- mCmasInfo = null;
- } else if (isCmasMessage()) {
- int messageClass = getCmasMessageClass();
- int severity = getCmasSeverity();
- int urgency = getCmasUrgency();
- int certainty = getCmasCertainty();
- mEtwsInfo = null;
- mCmasInfo = new SmsCbCmasInfo(messageClass, SmsCbCmasInfo.CMAS_CATEGORY_UNKNOWN,
- SmsCbCmasInfo.CMAS_RESPONSE_TYPE_UNKNOWN, severity, urgency, certainty);
- } else {
- mEtwsInfo = null;
- mCmasInfo = null;
- }
- }
-
- int getGeographicalScope() {
- return mGeographicalScope;
- }
-
- int getSerialNumber() {
- return mSerialNumber;
- }
-
- int getServiceCategory() {
- return mMessageIdentifier;
- }
-
- int getDataCodingScheme() {
- return mDataCodingScheme;
- }
-
- int getPageIndex() {
- return mPageIndex;
- }
-
- int getNumberOfPages() {
- return mNrOfPages;
- }
-
- SmsCbEtwsInfo getEtwsInfo() {
- return mEtwsInfo;
- }
-
- SmsCbCmasInfo getCmasInfo() {
- return mCmasInfo;
- }
-
- /**
- * Return whether this broadcast is an emergency (PWS) message type.
- * @return true if this message is emergency type; false otherwise
- */
- boolean isEmergencyMessage() {
- return mMessageIdentifier >= SmsCbConstants.MESSAGE_ID_PWS_FIRST_IDENTIFIER
- && mMessageIdentifier <= SmsCbConstants.MESSAGE_ID_PWS_LAST_IDENTIFIER;
- }
-
- /**
- * Return whether this broadcast is an ETWS emergency message type.
- * @return true if this message is ETWS emergency type; false otherwise
- */
- private boolean isEtwsMessage() {
- return (mMessageIdentifier & SmsCbConstants.MESSAGE_ID_ETWS_TYPE_MASK)
- == SmsCbConstants.MESSAGE_ID_ETWS_TYPE;
- }
-
- /**
- * Return whether this broadcast is an ETWS primary notification.
- * @return true if this message is an ETWS primary notification; false otherwise
- */
- boolean isEtwsPrimaryNotification() {
- return mFormat == FORMAT_ETWS_PRIMARY;
- }
-
- /**
- * Return whether this broadcast is in UMTS format.
- * @return true if this message is in UMTS format; false otherwise
- */
- boolean isUmtsFormat() {
- return mFormat == FORMAT_UMTS;
- }
-
- /**
- * Return whether this message is a CMAS emergency message type.
- * @return true if this message is CMAS emergency type; false otherwise
- */
- private boolean isCmasMessage() {
- return mMessageIdentifier >= SmsCbConstants.MESSAGE_ID_CMAS_FIRST_IDENTIFIER
- && mMessageIdentifier <= SmsCbConstants.MESSAGE_ID_CMAS_LAST_IDENTIFIER;
- }
-
- /**
- * Return whether the popup alert flag is set for an ETWS warning notification.
- * This method assumes that the message ID has already been checked for ETWS type.
- *
- * @return true if the message code indicates a popup alert should be displayed
- */
- private boolean isEtwsPopupAlert() {
- return (mSerialNumber & SmsCbConstants.SERIAL_NUMBER_ETWS_ACTIVATE_POPUP) != 0;
- }
-
- /**
- * Return whether the emergency user alert flag is set for an ETWS warning notification.
- * This method assumes that the message ID has already been checked for ETWS type.
- *
- * @return true if the message code indicates an emergency user alert
- */
- private boolean isEtwsEmergencyUserAlert() {
- return (mSerialNumber & SmsCbConstants.SERIAL_NUMBER_ETWS_EMERGENCY_USER_ALERT) != 0;
- }
-
- /**
- * Returns the warning type for an ETWS warning notification.
- * This method assumes that the message ID has already been checked for ETWS type.
- *
- * @return the ETWS warning type defined in 3GPP TS 23.041 section 9.3.24
- */
- private int getEtwsWarningType() {
- return mMessageIdentifier - SmsCbConstants.MESSAGE_ID_ETWS_EARTHQUAKE_WARNING;
- }
-
- /**
- * Returns the message class for a CMAS warning notification.
- * This method assumes that the message ID has already been checked for CMAS type.
- * @return the CMAS message class as defined in {@link SmsCbCmasInfo}
- */
- private int getCmasMessageClass() {
- switch (mMessageIdentifier) {
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_PRESIDENTIAL_LEVEL_LANGUAGE:
- return SmsCbCmasInfo.CMAS_CLASS_PRESIDENTIAL_LEVEL_ALERT;
-
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
- return SmsCbCmasInfo.CMAS_CLASS_EXTREME_THREAT;
-
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
- return SmsCbCmasInfo.CMAS_CLASS_SEVERE_THREAT;
-
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_CHILD_ABDUCTION_EMERGENCY_LANGUAGE:
- return SmsCbCmasInfo.CMAS_CLASS_CHILD_ABDUCTION_EMERGENCY;
-
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_REQUIRED_MONTHLY_TEST_LANGUAGE:
- return SmsCbCmasInfo.CMAS_CLASS_REQUIRED_MONTHLY_TEST;
-
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXERCISE_LANGUAGE:
- return SmsCbCmasInfo.CMAS_CLASS_CMAS_EXERCISE;
-
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_OPERATOR_DEFINED_USE_LANGUAGE:
- return SmsCbCmasInfo.CMAS_CLASS_OPERATOR_DEFINED_USE;
-
- default:
- return SmsCbCmasInfo.CMAS_CLASS_UNKNOWN;
- }
- }
-
- /**
- * Returns the severity for a CMAS warning notification. This is only available for extreme
- * and severe alerts, not for other types such as Presidential Level and AMBER alerts.
- * This method assumes that the message ID has already been checked for CMAS type.
- * @return the CMAS severity as defined in {@link SmsCbCmasInfo}
- */
- private int getCmasSeverity() {
- switch (mMessageIdentifier) {
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
- return SmsCbCmasInfo.CMAS_SEVERITY_EXTREME;
-
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
- return SmsCbCmasInfo.CMAS_SEVERITY_SEVERE;
-
- default:
- return SmsCbCmasInfo.CMAS_SEVERITY_UNKNOWN;
- }
- }
-
- /**
- * Returns the urgency for a CMAS warning notification. This is only available for extreme
- * and severe alerts, not for other types such as Presidential Level and AMBER alerts.
- * This method assumes that the message ID has already been checked for CMAS type.
- * @return the CMAS urgency as defined in {@link SmsCbCmasInfo}
- */
- private int getCmasUrgency() {
- switch (mMessageIdentifier) {
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
- return SmsCbCmasInfo.CMAS_URGENCY_IMMEDIATE;
-
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
- return SmsCbCmasInfo.CMAS_URGENCY_EXPECTED;
-
- default:
- return SmsCbCmasInfo.CMAS_URGENCY_UNKNOWN;
- }
- }
-
- /**
- * Returns the certainty for a CMAS warning notification. This is only available for extreme
- * and severe alerts, not for other types such as Presidential Level and AMBER alerts.
- * This method assumes that the message ID has already been checked for CMAS type.
- * @return the CMAS certainty as defined in {@link SmsCbCmasInfo}
- */
- private int getCmasCertainty() {
- switch (mMessageIdentifier) {
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_OBSERVED_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_OBSERVED_LANGUAGE:
- return SmsCbCmasInfo.CMAS_CERTAINTY_OBSERVED;
-
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_IMMEDIATE_LIKELY_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_EXTREME_EXPECTED_LIKELY_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_IMMEDIATE_LIKELY_LANGUAGE:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY:
- case SmsCbConstants.MESSAGE_ID_CMAS_ALERT_SEVERE_EXPECTED_LIKELY_LANGUAGE:
- return SmsCbCmasInfo.CMAS_CERTAINTY_LIKELY;
-
- default:
- return SmsCbCmasInfo.CMAS_CERTAINTY_UNKNOWN;
- }
- }
-
- @Override
- public String toString() {
- return "SmsCbHeader{GS=" + mGeographicalScope + ", serialNumber=0x" +
- Integer.toHexString(mSerialNumber) +
- ", messageIdentifier=0x" + Integer.toHexString(mMessageIdentifier) +
- ", DCS=0x" + Integer.toHexString(mDataCodingScheme) +
- ", page " + mPageIndex + " of " + mNrOfPages + '}';
- }
-}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/gsm/SmsMessage.java b/src/java/com/android/internal/telephony/gsm/SmsMessage.java
deleted file mode 100644
index 582506a..0000000
--- a/src/java/com/android/internal/telephony/gsm/SmsMessage.java
+++ /dev/null
@@ -1,1369 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.gsm;
-
-import android.telephony.PhoneNumberUtils;
-import android.text.format.Time;
-import android.telephony.Rlog;
-import android.content.res.Resources;
-import android.text.TextUtils;
-
-import com.android.internal.telephony.EncodeException;
-import com.android.internal.telephony.GsmAlphabet;
-import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails;
-import com.android.internal.telephony.uicc.IccUtils;
-import com.android.internal.telephony.SmsHeader;
-import com.android.internal.telephony.SmsMessageBase;
-import com.android.internal.telephony.Sms7BitEncodingTranslator;
-
-import java.io.ByteArrayOutputStream;
-import java.io.UnsupportedEncodingException;
-import java.text.ParseException;
-
-import static com.android.internal.telephony.SmsConstants.MessageClass;
-import static com.android.internal.telephony.SmsConstants.ENCODING_UNKNOWN;
-import static com.android.internal.telephony.SmsConstants.ENCODING_7BIT;
-import static com.android.internal.telephony.SmsConstants.ENCODING_8BIT;
-import static com.android.internal.telephony.SmsConstants.ENCODING_16BIT;
-import static com.android.internal.telephony.SmsConstants.ENCODING_KSC5601;
-import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_SEPTETS;
-import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES;
-import static com.android.internal.telephony.SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
-
-/**
- * A Short Message Service message.
- *
- */
-public class SmsMessage extends SmsMessageBase {
- static final String LOG_TAG = "SmsMessage";
- private static final boolean VDBG = false;
-
- private MessageClass messageClass;
-
- /**
- * TP-Message-Type-Indicator
- * 9.2.3
- */
- private int mMti;
-
- /** TP-Protocol-Identifier (TP-PID) */
- private int mProtocolIdentifier;
-
- // TP-Data-Coding-Scheme
- // see TS 23.038
- private int mDataCodingScheme;
-
- // TP-Reply-Path
- // e.g. 23.040 9.2.2.1
- private boolean mReplyPathPresent = false;
-
- /** The address of the receiver. */
- private GsmSmsAddress mRecipientAddress;
-
- /**
- * TP-Status - status of a previously submitted SMS.
- * This field applies to SMS-STATUS-REPORT messages. 0 indicates success;
- * see TS 23.040, 9.2.3.15 for description of other possible values.
- */
- private int mStatus;
-
- /**
- * TP-Status - status of a previously submitted SMS.
- * This field is true iff the message is a SMS-STATUS-REPORT message.
- */
- private boolean mIsStatusReportMessage = false;
-
- private int mVoiceMailCount = 0;
-
- public static class SubmitPdu extends SubmitPduBase {
- }
-
- /**
- * Create an SmsMessage from a raw PDU.
- */
- public static SmsMessage createFromPdu(byte[] pdu) {
- try {
- SmsMessage msg = new SmsMessage();
- msg.parsePdu(pdu);
- return msg;
- } catch (RuntimeException ex) {
- Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
- return null;
- } catch (OutOfMemoryError e) {
- Rlog.e(LOG_TAG, "SMS PDU parsing failed with out of memory: ", e);
- return null;
- }
- }
-
- /**
- * 3GPP TS 23.040 9.2.3.9 specifies that Type Zero messages are indicated
- * by TP_PID field set to value 0x40
- */
- public boolean isTypeZero() {
- return (mProtocolIdentifier == 0x40);
- }
-
- /**
- * TS 27.005 3.4.1 lines[0] and lines[1] are the two lines read from the
- * +CMT unsolicited response (PDU mode, of course)
- * +CMT: [<alpha>],<length><CR><LF><pdu>
- *
- * Only public for debugging
- *
- * {@hide}
- */
- public static SmsMessage newFromCMT(byte[] pdu) {
- try {
- SmsMessage msg = new SmsMessage();
- msg.parsePdu(pdu);
- return msg;
- } catch (RuntimeException ex) {
- Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
- return null;
- }
- }
-
- /** @hide */
- public static SmsMessage newFromCDS(byte[] pdu) {
- try {
- SmsMessage msg = new SmsMessage();
- msg.parsePdu(pdu);
- return msg;
- } catch (RuntimeException ex) {
- Rlog.e(LOG_TAG, "CDS SMS PDU parsing failed: ", ex);
- return null;
- }
- }
-
- /**
- * 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) {
- try {
- SmsMessage msg = new SmsMessage();
-
- msg.mIndexOnIcc = index;
-
- // First byte is status: RECEIVED_READ, RECEIVED_UNREAD, STORED_SENT,
- // or STORED_UNSENT
- // See TS 51.011 10.5.3
- if ((data[0] & 1) == 0) {
- Rlog.w(LOG_TAG,
- "SMS parsing failed: Trying to parse a free record");
- return null;
- } else {
- msg.mStatusOnIcc = data[0] & 0x07;
- }
-
- int size = data.length - 1;
-
- // Note: Data may include trailing FF's. That's OK; message
- // should still parse correctly.
- byte[] pdu = new byte[size];
- System.arraycopy(data, 1, pdu, 0, size);
- msg.parsePdu(pdu);
- return msg;
- } catch (RuntimeException ex) {
- Rlog.e(LOG_TAG, "SMS PDU parsing failed: ", ex);
- 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
- */
- public static int getTPLayerLengthForPDU(String pdu) {
- int len = pdu.length() / 2;
- int smscLen = Integer.parseInt(pdu.substring(0, 2), 16);
-
- return len - smscLen - 1;
- }
-
- /**
- * Get an SMS-SUBMIT PDU for a destination address and a message
- *
- * @param scAddress Service Centre address. Null means use default.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- * @hide
- */
- public static SubmitPdu getSubmitPdu(String scAddress,
- String destinationAddress, String message,
- boolean statusReportRequested, byte[] header) {
- return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, header,
- ENCODING_UNKNOWN, 0, 0);
- }
-
-
- /**
- * Get an SMS-SUBMIT PDU for a destination address and a message using the
- * specified encoding.
- *
- * @param scAddress Service Centre address. Null means use default.
- * @param encoding Encoding defined by constants in
- * com.android.internal.telephony.SmsConstants.ENCODING_*
- * @param languageTable
- * @param languageShiftTable
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- * @hide
- */
- public static SubmitPdu getSubmitPdu(String scAddress,
- String destinationAddress, String message,
- boolean statusReportRequested, byte[] header, int encoding,
- int languageTable, int languageShiftTable) {
-
- // Perform null parameter checks.
- if (message == null || destinationAddress == null) {
- return null;
- }
-
- if (encoding == ENCODING_UNKNOWN) {
- // Find the best encoding to use
- TextEncodingDetails ted = calculateLength(message, false);
- encoding = ted.codeUnitSize;
- languageTable = ted.languageTable;
- languageShiftTable = ted.languageShiftTable;
-
- if (encoding == ENCODING_7BIT &&
- (languageTable != 0 || languageShiftTable != 0)) {
- if (header != null) {
- SmsHeader smsHeader = SmsHeader.fromByteArray(header);
- if (smsHeader.languageTable != languageTable
- || smsHeader.languageShiftTable != languageShiftTable) {
- Rlog.w(LOG_TAG, "Updating language table in SMS header: "
- + smsHeader.languageTable + " -> " + languageTable + ", "
- + smsHeader.languageShiftTable + " -> " + languageShiftTable);
- smsHeader.languageTable = languageTable;
- smsHeader.languageShiftTable = languageShiftTable;
- header = SmsHeader.toByteArray(smsHeader);
- }
- } else {
- SmsHeader smsHeader = new SmsHeader();
- smsHeader.languageTable = languageTable;
- smsHeader.languageShiftTable = languageShiftTable;
- header = SmsHeader.toByteArray(smsHeader);
- }
- }
- }
-
- SubmitPdu ret = new SubmitPdu();
- // MTI = SMS-SUBMIT, UDHI = header != null
- byte mtiByte = (byte)(0x01 | (header != null ? 0x40 : 0x00));
- ByteArrayOutputStream bo = getSubmitPduHead(
- scAddress, destinationAddress, mtiByte,
- statusReportRequested, ret);
-
- // User Data (and length)
- byte[] userData;
- try {
- if (encoding == ENCODING_7BIT) {
- userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header,
- languageTable, languageShiftTable);
- } else { //assume UCS-2
- try {
- userData = encodeUCS2(message, header);
- } catch(UnsupportedEncodingException uex) {
- Rlog.e(LOG_TAG,
- "Implausible UnsupportedEncodingException ",
- uex);
- return null;
- }
- }
- } catch (EncodeException ex) {
- // Encoding to the 7-bit alphabet failed. Let's see if we can
- // send it as a UCS-2 encoded message
- try {
- userData = encodeUCS2(message, header);
- encoding = ENCODING_16BIT;
- } catch(UnsupportedEncodingException uex) {
- Rlog.e(LOG_TAG,
- "Implausible UnsupportedEncodingException ",
- uex);
- return null;
- }
- }
-
- if (encoding == ENCODING_7BIT) {
- if ((0xff & userData[0]) > MAX_USER_DATA_SEPTETS) {
- // Message too long
- Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " septets)");
- return null;
- }
- // TP-Data-Coding-Scheme
- // Default encoding, uncompressed
- // To test writing messages to the SIM card, change this value 0x00
- // to 0x12, which means "bits 1 and 0 contain message class, and the
- // class is 2". Note that this takes effect for the sender. In other
- // words, messages sent by the phone with this change will end up on
- // the receiver's SIM card. You can then send messages to yourself
- // (on a phone with this change) and they'll end up on the SIM card.
- bo.write(0x00);
- } else { // assume UCS-2
- if ((0xff & userData[0]) > MAX_USER_DATA_BYTES) {
- // Message too long
- Rlog.e(LOG_TAG, "Message too long (" + (0xff & userData[0]) + " bytes)");
- return null;
- }
- // TP-Data-Coding-Scheme
- // UCS-2 encoding, uncompressed
- bo.write(0x08);
- }
-
- // (no TP-Validity-Period)
- bo.write(userData, 0, userData.length);
- ret.encodedMessage = bo.toByteArray();
- return ret;
- }
-
- /**
- * Packs header and UCS-2 encoded message. Includes TP-UDL & TP-UDHL if necessary
- *
- * @return encoded message as UCS2
- * @throws UnsupportedEncodingException
- */
- private static byte[] encodeUCS2(String message, byte[] header)
- throws UnsupportedEncodingException {
- byte[] userData, textPart;
- textPart = message.getBytes("utf-16be");
-
- if (header != null) {
- // Need 1 byte for UDHL
- userData = new byte[header.length + textPart.length + 1];
-
- userData[0] = (byte)header.length;
- System.arraycopy(header, 0, userData, 1, header.length);
- System.arraycopy(textPart, 0, userData, header.length + 1, textPart.length);
- }
- else {
- userData = textPart;
- }
- byte[] ret = new byte[userData.length+1];
- ret[0] = (byte) (userData.length & 0xff );
- System.arraycopy(userData, 0, ret, 1, userData.length);
- return ret;
- }
-
- /**
- * Get an SMS-SUBMIT PDU for a destination address and a message
- *
- * @param scAddress Service Centre address. Null means use default.
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- */
- public static SubmitPdu getSubmitPdu(String scAddress,
- String destinationAddress, String message,
- boolean statusReportRequested) {
-
- return getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested, null);
- }
-
- /**
- * Get an SMS-SUBMIT PDU for a data message to a destination address & port
- *
- * @param scAddress Service Centre address. null == use default
- * @param destinationAddress the address of the destination for the message
- * @param destinationPort the port to deliver the message to at the
- * destination
- * @param data the data for the message
- * @return a <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message.
- * Returns null on encode error.
- */
- public static SubmitPdu getSubmitPdu(String scAddress,
- String destinationAddress, int destinationPort, byte[] data,
- boolean statusReportRequested) {
-
- SmsHeader.PortAddrs portAddrs = new SmsHeader.PortAddrs();
- portAddrs.destPort = destinationPort;
- portAddrs.origPort = 0;
- portAddrs.areEightBits = false;
-
- SmsHeader smsHeader = new SmsHeader();
- smsHeader.portAddrs = portAddrs;
-
- byte[] smsHeaderData = SmsHeader.toByteArray(smsHeader);
-
- if ((data.length + smsHeaderData.length + 1) > MAX_USER_DATA_BYTES) {
- Rlog.e(LOG_TAG, "SMS data message may only contain "
- + (MAX_USER_DATA_BYTES - smsHeaderData.length - 1) + " bytes");
- return null;
- }
-
- SubmitPdu ret = new SubmitPdu();
- ByteArrayOutputStream bo = getSubmitPduHead(
- scAddress, destinationAddress, (byte) 0x41, // MTI = SMS-SUBMIT,
- // TP-UDHI = true
- statusReportRequested, ret);
-
- // TP-Data-Coding-Scheme
- // No class, 8 bit data
- bo.write(0x04);
-
- // (no TP-Validity-Period)
-
- // Total size
- bo.write(data.length + smsHeaderData.length + 1);
-
- // User data header
- bo.write(smsHeaderData.length);
- bo.write(smsHeaderData, 0, smsHeaderData.length);
-
- // User data
- bo.write(data, 0, data.length);
-
- ret.encodedMessage = bo.toByteArray();
- return ret;
- }
-
- /**
- * Create the beginning of a SUBMIT PDU. This is the part of the
- * SUBMIT PDU that is common to the two versions of {@link #getSubmitPdu},
- * one of which takes a byte array and the other of which takes a
- * <code>String</code>.
- *
- * @param scAddress Service Centre address. null == use default
- * @param destinationAddress the address of the destination for the message
- * @param mtiByte
- * @param ret <code>SubmitPdu</code> containing the encoded SC
- * address, if applicable, and the encoded message
- */
- private static ByteArrayOutputStream getSubmitPduHead(
- String scAddress, String destinationAddress, byte mtiByte,
- boolean statusReportRequested, SubmitPdu ret) {
- ByteArrayOutputStream bo = new ByteArrayOutputStream(
- MAX_USER_DATA_BYTES + 40);
-
- // SMSC address with length octet, or 0
- if (scAddress == null) {
- ret.encodedScAddress = null;
- } else {
- ret.encodedScAddress = PhoneNumberUtils.networkPortionToCalledPartyBCDWithLength(
- scAddress);
- }
-
- // TP-Message-Type-Indicator (and friends)
- if (statusReportRequested) {
- // Set TP-Status-Report-Request bit.
- mtiByte |= 0x20;
- if (VDBG) Rlog.d(LOG_TAG, "SMS status report requested");
- }
- bo.write(mtiByte);
-
- // space for TP-Message-Reference
- bo.write(0);
-
- byte[] daBytes;
-
- daBytes = PhoneNumberUtils.networkPortionToCalledPartyBCD(destinationAddress);
-
- // destination address length in BCD digits, ignoring TON byte and pad
- // TODO Should be better.
- bo.write((daBytes.length - 1) * 2
- - ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0));
-
- // destination address
- bo.write(daBytes, 0, daBytes.length);
-
- // TP-Protocol-Identifier
- bo.write(0);
- return bo;
- }
-
- private static class PduParser {
- byte mPdu[];
- int mCur;
- SmsHeader mUserDataHeader;
- byte[] mUserData;
- int mUserDataSeptetPadding;
-
- PduParser(byte[] pdu) {
- mPdu = pdu;
- mCur = 0;
- mUserDataSeptetPadding = 0;
- }
-
- /**
- * Parse and return the SC address prepended to SMS messages coming via
- * the TS 27.005 / AT interface. Returns null on invalid address
- */
- String getSCAddress() {
- int len;
- String ret;
-
- // length of SC Address
- len = getByte();
-
- if (len == 0) {
- // no SC address
- ret = null;
- } else {
- // SC address
- try {
- ret = PhoneNumberUtils
- .calledPartyBCDToString(mPdu, mCur, len);
- } catch (RuntimeException tr) {
- Rlog.d(LOG_TAG, "invalid SC address: ", tr);
- ret = null;
- }
- }
-
- mCur += len;
-
- return ret;
- }
-
- /**
- * returns non-sign-extended byte value
- */
- int getByte() {
- return mPdu[mCur++] & 0xff;
- }
-
- /**
- * Any address except the SC address (eg, originating address) See TS
- * 23.040 9.1.2.5
- */
- GsmSmsAddress getAddress() {
- GsmSmsAddress ret;
-
- // "The Address-Length field is an integer representation of
- // the number field, i.e. excludes any semi-octet containing only
- // fill bits."
- // The TOA field is not included as part of this
- int addressLength = mPdu[mCur] & 0xff;
- int lengthBytes = 2 + (addressLength + 1) / 2;
-
- try {
- ret = new GsmSmsAddress(mPdu, mCur, lengthBytes);
- } catch (ParseException e) {
- ret = null;
- //This is caught by createFromPdu(byte[] pdu)
- throw new RuntimeException(e.getMessage());
- }
-
- mCur += lengthBytes;
-
- return ret;
- }
-
- /**
- * Parses an SC timestamp and returns a currentTimeMillis()-style
- * timestamp
- */
-
- long getSCTimestampMillis() {
- // TP-Service-Centre-Time-Stamp
- int year = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
- int month = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
- int day = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
- int hour = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
- int minute = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
- int second = IccUtils.gsmBcdByteToInt(mPdu[mCur++]);
-
- // 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 = mPdu[mCur++];
-
- // Mask out sign bit.
- int timezoneOffset = IccUtils.gsmBcdByteToInt((byte) (tzByte & (~0x08)));
-
- timezoneOffset = ((tzByte & 0x08) == 0) ? timezoneOffset : -timezoneOffset;
-
- Time time = new Time(Time.TIMEZONE_UTC);
-
- // It's 2006. Should I really support years < 2000?
- time.year = year >= 90 ? year + 1900 : 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);
- }
-
- /**
- * Pulls the user data out of the PDU, and separates the payload from
- * the header if there is one.
- *
- * @param hasUserDataHeader true if there is a user data header
- * @param dataInSeptets true if the data payload is in septets instead
- * of octets
- * @return the number of septets or octets in the user data payload
- */
- int constructUserData(boolean hasUserDataHeader, boolean dataInSeptets) {
- int offset = mCur;
- int userDataLength = mPdu[offset++] & 0xff;
- int headerSeptets = 0;
- int userDataHeaderLength = 0;
-
- if (hasUserDataHeader) {
- userDataHeaderLength = mPdu[offset++] & 0xff;
-
- byte[] udh = new byte[userDataHeaderLength];
- System.arraycopy(mPdu, offset, udh, 0, userDataHeaderLength);
- mUserDataHeader = SmsHeader.fromByteArray(udh);
- offset += userDataHeaderLength;
-
- int headerBits = (userDataHeaderLength + 1) * 8;
- headerSeptets = headerBits / 7;
- headerSeptets += (headerBits % 7) > 0 ? 1 : 0;
- mUserDataSeptetPadding = (headerSeptets * 7) - headerBits;
- }
-
- int bufferLen;
- if (dataInSeptets) {
- /*
- * Here we just create the user data length to be the remainder of
- * the pdu minus the user data header, since userDataLength means
- * the number of uncompressed septets.
- */
- bufferLen = mPdu.length - offset;
- } else {
- /*
- * userDataLength is the count of octets, so just subtract the
- * user data header.
- */
- bufferLen = userDataLength - (hasUserDataHeader ? (userDataHeaderLength + 1) : 0);
- if (bufferLen < 0) {
- bufferLen = 0;
- }
- }
-
- mUserData = new byte[bufferLen];
- System.arraycopy(mPdu, offset, mUserData, 0, mUserData.length);
- mCur = offset;
-
- if (dataInSeptets) {
- // Return the number of septets
- int count = userDataLength - headerSeptets;
- // If count < 0, return 0 (means UDL was probably incorrect)
- return count < 0 ? 0 : count;
- } else {
- // Return the number of octets
- return mUserData.length;
- }
- }
-
- /**
- * Returns the user data payload, not including the headers
- *
- * @return the user data payload, not including the headers
- */
- byte[] getUserData() {
- return mUserData;
- }
-
- /**
- * Returns an object representing the user data headers
- *
- * {@hide}
- */
- SmsHeader getUserDataHeader() {
- return mUserDataHeader;
- }
-
- /**
- * Interprets the user data payload as packed GSM 7bit characters, and
- * decodes them into a String.
- *
- * @param septetCount the number of septets in the user data payload
- * @return a String with the decoded characters
- */
- String getUserDataGSM7Bit(int septetCount, int languageTable,
- int languageShiftTable) {
- String ret;
-
- ret = GsmAlphabet.gsm7BitPackedToString(mPdu, mCur, septetCount,
- mUserDataSeptetPadding, languageTable, languageShiftTable);
-
- mCur += (septetCount * 7) / 8;
-
- return ret;
- }
-
- /**
- * Interprets the user data payload as pack GSM 8-bit (a GSM alphabet string that's
- * stored in 8-bit unpacked format) characters, and decodes them into a String.
- *
- * @param byteCount the number of byest in the user data payload
- * @return a String with the decoded characters
- */
- String getUserDataGSM8bit(int byteCount) {
- String ret;
-
- ret = GsmAlphabet.gsm8BitUnpackedToString(mPdu, mCur, byteCount);
-
- mCur += byteCount;
-
- return ret;
- }
-
- /**
- * Interprets the user data payload as UCS2 characters, and
- * decodes them into a String.
- *
- * @param byteCount the number of bytes in the user data payload
- * @return a String with the decoded characters
- */
- String getUserDataUCS2(int byteCount) {
- String ret;
-
- try {
- ret = new String(mPdu, mCur, byteCount, "utf-16");
- } catch (UnsupportedEncodingException ex) {
- ret = "";
- Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
- }
-
- mCur += byteCount;
- return ret;
- }
-
- /**
- * Interprets the user data payload as KSC-5601 characters, and
- * decodes them into a String.
- *
- * @param byteCount the number of bytes in the user data payload
- * @return a String with the decoded characters
- */
- String getUserDataKSC5601(int byteCount) {
- String ret;
-
- try {
- ret = new String(mPdu, mCur, byteCount, "KSC5601");
- } catch (UnsupportedEncodingException ex) {
- ret = "";
- Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException", ex);
- }
-
- mCur += byteCount;
- return ret;
- }
-
- boolean moreDataPresent() {
- return (mPdu.length > mCur);
- }
- }
-
- /**
- * 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 ignore (but still count) illegal characters if true
- * @return TextEncodingDetails
- */
- public static TextEncodingDetails calculateLength(CharSequence msgBody,
- boolean use7bitOnly) {
- CharSequence newMsgBody = null;
- Resources r = Resources.getSystem();
- if (r.getBoolean(com.android.internal.R.bool.config_sms_force_7bit_encoding)) {
- newMsgBody = Sms7BitEncodingTranslator.translate(msgBody);
- }
- if (TextUtils.isEmpty(newMsgBody)) {
- newMsgBody = msgBody;
- }
- TextEncodingDetails ted = GsmAlphabet.countGsmSeptets(newMsgBody, use7bitOnly);
- if (ted == null) {
- return SmsMessageBase.calcUnicodeEncodingDetails(newMsgBody);
- }
- return ted;
- }
-
- /** {@inheritDoc} */
- @Override
- public int getProtocolIdentifier() {
- return mProtocolIdentifier;
- }
-
- /**
- * Returns the TP-Data-Coding-Scheme byte, for acknowledgement of SMS-PP download messages.
- * @return the TP-DCS field of the SMS header
- */
- int getDataCodingScheme() {
- return mDataCodingScheme;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isReplace() {
- return (mProtocolIdentifier & 0xc0) == 0x40
- && (mProtocolIdentifier & 0x3f) > 0
- && (mProtocolIdentifier & 0x3f) < 8;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isCphsMwiMessage() {
- return ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageClear()
- || ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageSet();
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isMWIClearMessage() {
- if (mIsMwi && !mMwiSense) {
- return true;
- }
-
- return mOriginatingAddress != null
- && ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageClear();
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isMWISetMessage() {
- if (mIsMwi && mMwiSense) {
- return true;
- }
-
- return mOriginatingAddress != null
- && ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageSet();
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isMwiDontStore() {
- if (mIsMwi && mMwiDontStore) {
- return true;
- }
-
- if (isCphsMwiMessage()) {
- // See CPHS 4.2 Section B.4.2.1
- // If the user data is a single space char, do not store
- // the message. Otherwise, store and display as usual
- if (" ".equals(getMessageBody())) {
- return true;
- }
- }
-
- return false;
- }
-
- /** {@inheritDoc} */
- @Override
- public int getStatus() {
- return mStatus;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isStatusReportMessage() {
- return mIsStatusReportMessage;
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isReplyPathPresent() {
- return mReplyPathPresent;
- }
-
- /**
- * TS 27.005 3.1, <pdu> definition "In the case of SMS: 3GPP TS 24.011 [6]
- * SC address followed by 3GPP TS 23.040 [3] TPDU in hexadecimal format:
- * ME/TA converts each octet of TP data unit into two IRA character long
- * hex number (e.g. octet with integer value 42 is presented to TE as two
- * characters 2A (IRA 50 and 65))" ...in the case of cell broadcast,
- * something else...
- */
- private void parsePdu(byte[] pdu) {
- mPdu = pdu;
- // Rlog.d(LOG_TAG, "raw sms message:");
- // Rlog.d(LOG_TAG, s);
-
- PduParser p = new PduParser(pdu);
-
- mScAddress = p.getSCAddress();
-
- if (mScAddress != null) {
- if (VDBG) Rlog.d(LOG_TAG, "SMS SC address: " + mScAddress);
- }
-
- // TODO(mkf) support reply path, user data header indicator
-
- // TP-Message-Type-Indicator
- // 9.2.3
- int firstByte = p.getByte();
-
- mMti = firstByte & 0x3;
- switch (mMti) {
- // TP-Message-Type-Indicator
- // 9.2.3
- case 0:
- case 3: //GSM 03.40 9.2.3.1: MTI == 3 is Reserved.
- //This should be processed in the same way as MTI == 0 (Deliver)
- parseSmsDeliver(p, firstByte);
- break;
- case 1:
- parseSmsSubmit(p, firstByte);
- break;
- case 2:
- parseSmsStatusReport(p, firstByte);
- break;
- default:
- // TODO(mkf) the rest of these
- throw new RuntimeException("Unsupported message type");
- }
- }
-
- /**
- * Parses a SMS-STATUS-REPORT message.
- *
- * @param p A PduParser, cued past the first byte.
- * @param firstByte The first byte of the PDU, which contains MTI, etc.
- */
- private void parseSmsStatusReport(PduParser p, int firstByte) {
- mIsStatusReportMessage = true;
-
- // TP-Message-Reference
- mMessageRef = p.getByte();
- // TP-Recipient-Address
- mRecipientAddress = p.getAddress();
- // TP-Service-Centre-Time-Stamp
- mScTimeMillis = p.getSCTimestampMillis();
- p.getSCTimestampMillis();
- // TP-Status
- mStatus = p.getByte();
-
- // The following are optional fields that may or may not be present.
- if (p.moreDataPresent()) {
- // TP-Parameter-Indicator
- int extraParams = p.getByte();
- int moreExtraParams = extraParams;
- while ((moreExtraParams & 0x80) != 0) {
- // We only know how to parse a few extra parameters, all
- // indicated in the first TP-PI octet, so skip over any
- // additional TP-PI octets.
- moreExtraParams = p.getByte();
- }
- // As per 3GPP 23.040 section 9.2.3.27 TP-Parameter-Indicator,
- // only process the byte if the reserved bits (bits3 to 6) are zero.
- if ((extraParams & 0x78) == 0) {
- // TP-Protocol-Identifier
- if ((extraParams & 0x01) != 0) {
- mProtocolIdentifier = p.getByte();
- }
- // TP-Data-Coding-Scheme
- if ((extraParams & 0x02) != 0) {
- mDataCodingScheme = p.getByte();
- }
- // TP-User-Data-Length (implies existence of TP-User-Data)
- if ((extraParams & 0x04) != 0) {
- boolean hasUserDataHeader = (firstByte & 0x40) == 0x40;
- parseUserData(p, hasUserDataHeader);
- }
- }
- }
- }
-
- private void parseSmsDeliver(PduParser p, int firstByte) {
- mReplyPathPresent = (firstByte & 0x80) == 0x80;
-
- mOriginatingAddress = p.getAddress();
-
- if (mOriginatingAddress != null) {
- if (VDBG) Rlog.v(LOG_TAG, "SMS originating address: "
- + mOriginatingAddress.address);
- }
-
- // TP-Protocol-Identifier (TP-PID)
- // TS 23.040 9.2.3.9
- mProtocolIdentifier = p.getByte();
-
- // TP-Data-Coding-Scheme
- // see TS 23.038
- mDataCodingScheme = p.getByte();
-
- if (VDBG) {
- Rlog.v(LOG_TAG, "SMS TP-PID:" + mProtocolIdentifier
- + " data coding scheme: " + mDataCodingScheme);
- }
-
- mScTimeMillis = p.getSCTimestampMillis();
-
- if (VDBG) Rlog.d(LOG_TAG, "SMS SC timestamp: " + mScTimeMillis);
-
- boolean hasUserDataHeader = (firstByte & 0x40) == 0x40;
-
- parseUserData(p, hasUserDataHeader);
- }
-
- /**
- * Parses a SMS-SUBMIT message.
- *
- * @param p A PduParser, cued past the first byte.
- * @param firstByte The first byte of the PDU, which contains MTI, etc.
- */
- private void parseSmsSubmit(PduParser p, int firstByte) {
- mReplyPathPresent = (firstByte & 0x80) == 0x80;
-
- // TP-MR (TP-Message Reference)
- mMessageRef = p.getByte();
-
- mRecipientAddress = p.getAddress();
-
- if (mRecipientAddress != null) {
- if (VDBG) Rlog.v(LOG_TAG, "SMS recipient address: " + mRecipientAddress.address);
- }
-
- // TP-Protocol-Identifier (TP-PID)
- // TS 23.040 9.2.3.9
- mProtocolIdentifier = p.getByte();
-
- // TP-Data-Coding-Scheme
- // see TS 23.038
- mDataCodingScheme = p.getByte();
-
- if (VDBG) {
- Rlog.v(LOG_TAG, "SMS TP-PID:" + mProtocolIdentifier
- + " data coding scheme: " + mDataCodingScheme);
- }
-
- // TP-Validity-Period-Format
- int validityPeriodLength = 0;
- int validityPeriodFormat = ((firstByte>>3) & 0x3);
- if (0x0 == validityPeriodFormat) /* 00, TP-VP field not present*/
- {
- validityPeriodLength = 0;
- }
- else if (0x2 == validityPeriodFormat) /* 10, TP-VP: relative format*/
- {
- validityPeriodLength = 1;
- }
- else /* other case, 11 or 01, TP-VP: absolute or enhanced format*/
- {
- validityPeriodLength = 7;
- }
-
- // TP-Validity-Period is not used on phone, so just ignore it for now.
- while (validityPeriodLength-- > 0)
- {
- p.getByte();
- }
-
- boolean hasUserDataHeader = (firstByte & 0x40) == 0x40;
-
- parseUserData(p, hasUserDataHeader);
- }
-
- /**
- * Parses the User Data of an SMS.
- *
- * @param p The current PduParser.
- * @param hasUserDataHeader Indicates whether a header is present in the
- * User Data.
- */
- private void parseUserData(PduParser p, boolean hasUserDataHeader) {
- boolean hasMessageClass = false;
- boolean userDataCompressed = false;
-
- int encodingType = ENCODING_UNKNOWN;
-
- // Look up the data encoding scheme
- if ((mDataCodingScheme & 0x80) == 0) {
- userDataCompressed = (0 != (mDataCodingScheme & 0x20));
- hasMessageClass = (0 != (mDataCodingScheme & 0x10));
-
- if (userDataCompressed) {
- Rlog.w(LOG_TAG, "4 - Unsupported SMS data coding scheme "
- + "(compression) " + (mDataCodingScheme & 0xff));
- } else {
- switch ((mDataCodingScheme >> 2) & 0x3) {
- case 0: // GSM 7 bit default alphabet
- encodingType = ENCODING_7BIT;
- break;
-
- case 2: // UCS 2 (16bit)
- encodingType = ENCODING_16BIT;
- break;
-
- case 1: // 8 bit data
- //Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet string
- //that's stored in 8-bit unpacked format) characters.
- Resources r = Resources.getSystem();
- if (r.getBoolean(com.android.internal.
- R.bool.config_sms_decode_gsm_8bit_data)) {
- encodingType = ENCODING_8BIT;
- break;
- }
-
- case 3: // reserved
- Rlog.w(LOG_TAG, "1 - Unsupported SMS data coding scheme "
- + (mDataCodingScheme & 0xff));
- encodingType = ENCODING_8BIT;
- break;
- }
- }
- } else if ((mDataCodingScheme & 0xf0) == 0xf0) {
- hasMessageClass = true;
- userDataCompressed = false;
-
- if (0 == (mDataCodingScheme & 0x04)) {
- // GSM 7 bit default alphabet
- encodingType = ENCODING_7BIT;
- } else {
- // 8 bit data
- encodingType = ENCODING_8BIT;
- }
- } else if ((mDataCodingScheme & 0xF0) == 0xC0
- || (mDataCodingScheme & 0xF0) == 0xD0
- || (mDataCodingScheme & 0xF0) == 0xE0) {
- // 3GPP TS 23.038 V7.0.0 (2006-03) section 4
-
- // 0xC0 == 7 bit, don't store
- // 0xD0 == 7 bit, store
- // 0xE0 == UCS-2, store
-
- if ((mDataCodingScheme & 0xF0) == 0xE0) {
- encodingType = ENCODING_16BIT;
- } else {
- encodingType = ENCODING_7BIT;
- }
-
- userDataCompressed = false;
- boolean active = ((mDataCodingScheme & 0x08) == 0x08);
- // bit 0x04 reserved
-
- // VM - If TP-UDH is present, these values will be overwritten
- if ((mDataCodingScheme & 0x03) == 0x00) {
- mIsMwi = true; /* Indicates vmail */
- mMwiSense = active;/* Indicates vmail notification set/clear */
- mMwiDontStore = ((mDataCodingScheme & 0xF0) == 0xC0);
-
- /* Set voice mail count based on notification bit */
- if (active == true) {
- mVoiceMailCount = -1; // unknown number of messages waiting
- } else {
- mVoiceMailCount = 0; // no unread messages
- }
-
- Rlog.w(LOG_TAG, "MWI in DCS for Vmail. DCS = "
- + (mDataCodingScheme & 0xff) + " Dont store = "
- + mMwiDontStore + " vmail count = " + mVoiceMailCount);
-
- } else {
- mIsMwi = false;
- Rlog.w(LOG_TAG, "MWI in DCS for fax/email/other: "
- + (mDataCodingScheme & 0xff));
- }
- } else if ((mDataCodingScheme & 0xC0) == 0x80) {
- // 3GPP TS 23.038 V7.0.0 (2006-03) section 4
- // 0x80..0xBF == Reserved coding groups
- if (mDataCodingScheme == 0x84) {
- // This value used for KSC5601 by carriers in Korea.
- encodingType = ENCODING_KSC5601;
- } else {
- Rlog.w(LOG_TAG, "5 - Unsupported SMS data coding scheme "
- + (mDataCodingScheme & 0xff));
- }
- } else {
- Rlog.w(LOG_TAG, "3 - Unsupported SMS data coding scheme "
- + (mDataCodingScheme & 0xff));
- }
-
- // set both the user data and the user data header.
- int count = p.constructUserData(hasUserDataHeader,
- encodingType == ENCODING_7BIT);
- this.mUserData = p.getUserData();
- this.mUserDataHeader = p.getUserDataHeader();
-
- /*
- * Look for voice mail indication in TP_UDH TS23.040 9.2.3.24
- * ieid = 1 (0x1) (SPECIAL_SMS_MSG_IND)
- * ieidl =2 octets
- * ieda msg_ind_type = 0x00 (voice mail; discard sms )or
- * = 0x80 (voice mail; store sms)
- * msg_count = 0x00 ..0xFF
- */
- if (hasUserDataHeader && (mUserDataHeader.specialSmsMsgList.size() != 0)) {
- for (SmsHeader.SpecialSmsMsg msg : mUserDataHeader.specialSmsMsgList) {
- int msgInd = msg.msgIndType & 0xff;
- /*
- * TS 23.040 V6.8.1 Sec 9.2.3.24.2
- * bits 1 0 : basic message indication type
- * bits 4 3 2 : extended message indication type
- * bits 6 5 : Profile id bit 7 storage type
- */
- if ((msgInd == 0) || (msgInd == 0x80)) {
- mIsMwi = true;
- if (msgInd == 0x80) {
- /* Store message because TP_UDH indicates so*/
- mMwiDontStore = false;
- } else if (mMwiDontStore == false) {
- /* Storage bit is not set by TP_UDH
- * Check for conflict
- * between message storage bit in TP_UDH
- * & DCS. The message shall be stored if either of
- * the one indicates so.
- * TS 23.040 V6.8.1 Sec 9.2.3.24.2
- */
- if (!((((mDataCodingScheme & 0xF0) == 0xD0)
- || ((mDataCodingScheme & 0xF0) == 0xE0))
- && ((mDataCodingScheme & 0x03) == 0x00))) {
- /* Even DCS did not have voice mail with Storage bit
- * 3GPP TS 23.038 V7.0.0 section 4
- * So clear this flag*/
- mMwiDontStore = true;
- }
- }
-
- mVoiceMailCount = msg.msgCount & 0xff;
-
- /*
- * In the event of a conflict between message count setting
- * and DCS then the Message Count in the TP-UDH shall
- * override the indication in the TP-DCS. Set voice mail
- * notification based on count in TP-UDH
- */
- if (mVoiceMailCount > 0)
- mMwiSense = true;
- else
- mMwiSense = false;
-
- Rlog.w(LOG_TAG, "MWI in TP-UDH for Vmail. Msg Ind = " + msgInd
- + " Dont store = " + mMwiDontStore + " Vmail count = "
- + mVoiceMailCount);
-
- /*
- * There can be only one IE for each type of message
- * indication in TP_UDH. In the event they are duplicated
- * last occurence will be used. Hence the for loop
- */
- } else {
- Rlog.w(LOG_TAG, "TP_UDH fax/email/"
- + "extended msg/multisubscriber profile. Msg Ind = " + msgInd);
- }
- } // end of for
- } // end of if UDH
-
- switch (encodingType) {
- case ENCODING_UNKNOWN:
- mMessageBody = null;
- break;
-
- case ENCODING_8BIT:
- //Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet string
- //that's stored in 8-bit unpacked format) characters.
- Resources r = Resources.getSystem();
- if (r.getBoolean(com.android.internal.
- R.bool.config_sms_decode_gsm_8bit_data)) {
- mMessageBody = p.getUserDataGSM8bit(count);
- } else {
- mMessageBody = null;
- }
- break;
-
- case ENCODING_7BIT:
- mMessageBody = p.getUserDataGSM7Bit(count,
- hasUserDataHeader ? mUserDataHeader.languageTable : 0,
- hasUserDataHeader ? mUserDataHeader.languageShiftTable : 0);
- break;
-
- case ENCODING_16BIT:
- mMessageBody = p.getUserDataUCS2(count);
- break;
-
- case ENCODING_KSC5601:
- mMessageBody = p.getUserDataKSC5601(count);
- break;
- }
-
- if (VDBG) Rlog.v(LOG_TAG, "SMS message body (raw): '" + mMessageBody + "'");
-
- if (mMessageBody != null) {
- parseMessageBody();
- }
-
- if (!hasMessageClass) {
- messageClass = MessageClass.UNKNOWN;
- } else {
- switch (mDataCodingScheme & 0x3) {
- case 0:
- messageClass = MessageClass.CLASS_0;
- break;
- case 1:
- messageClass = MessageClass.CLASS_1;
- break;
- case 2:
- messageClass = MessageClass.CLASS_2;
- break;
- case 3:
- messageClass = MessageClass.CLASS_3;
- break;
- }
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public MessageClass getMessageClass() {
- return messageClass;
- }
-
- /**
- * Returns true if this is a (U)SIM data download type SM.
- * See 3GPP TS 31.111 section 9.1 and TS 23.040 section 9.2.3.9.
- *
- * @return true if this is a USIM data download message; false otherwise
- */
- boolean isUsimDataDownload() {
- return messageClass == MessageClass.CLASS_2 &&
- (mProtocolIdentifier == 0x7f || mProtocolIdentifier == 0x7c);
- }
-
- public int getNumOfVoicemails() {
- /*
- * Order of priority if multiple indications are present is 1.UDH,
- * 2.DCS, 3.CPHS.
- * Voice mail count if voice mail present indication is
- * received
- * 1. UDH (or both UDH & DCS): mVoiceMailCount = 0 to 0xff. Ref[TS 23. 040]
- * 2. DCS only: count is unknown mVoiceMailCount= -1
- * 3. CPHS only: count is unknown mVoiceMailCount = 0xff. Ref[GSM-BTR-1-4700]
- * Voice mail clear, mVoiceMailCount = 0.
- */
- if ((!mIsMwi) && isCphsMwiMessage()) {
- if (mOriginatingAddress != null
- && ((GsmSmsAddress) mOriginatingAddress).isCphsVoiceMessageSet()) {
- mVoiceMailCount = 0xff;
- } else {
- mVoiceMailCount = 0;
- }
- Rlog.v(LOG_TAG, "CPHS voice mail message");
- }
- return mVoiceMailCount;
- }
-}
diff --git a/src/java/com/android/internal/telephony/ims/ImsServiceController.java b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
index 2362348..5257dad 100644
--- a/src/java/com/android/internal/telephony/ims/ImsServiceController.java
+++ b/src/java/com/android/internal/telephony/ims/ImsServiceController.java
@@ -284,7 +284,7 @@
}
/**
- * Calls {@link IImsServiceController#removeImsFeature(int, int)} on all features that the
+ * Calls {@link IImsServiceController#removeImsFeature} on all features that the
* ImsService supports and then unbinds the service.
*/
public void unbind() throws RemoteException {
@@ -459,7 +459,15 @@
Log.w(LOG_TAG, "removeImsServiceFeature called with null values.");
return;
}
- mIImsServiceController.removeImsFeature(featurePair.first, featurePair.second);
+ ImsFeatureStatusCallback callbackToRemove = mFeatureStatusCallbacks.stream().filter(c ->
+ c.mSlotId == featurePair.first && c.mFeatureType == featurePair.second)
+ .findFirst().orElse(null);
+ // Remove status callbacks from list.
+ if (callbackToRemove != null) {
+ mFeatureStatusCallbacks.remove(callbackToRemove);
+ }
+ mIImsServiceController.removeImsFeature(featurePair.first, featurePair.second,
+ (callbackToRemove != null ? callbackToRemove.getCallback() : null));
// Signal ImsResolver to change supported ImsFeatures for this ImsServiceController
mCallbacks.imsServiceFeatureRemoved(featurePair.first, featurePair.second, this);
// Send callback to ImsServiceProxy to change supported ImsFeatures
@@ -467,9 +475,6 @@
// ImsManager requests the ImsService while it is being removed in ImsResolver, this
// callback will clean it up after.
sendImsFeatureRemovedCallback(featurePair.first, featurePair.second);
- // Remove status callbacks from list.
- mFeatureStatusCallbacks.removeIf(c -> c.mSlotId == featurePair.first
- && c.mFeatureType == featurePair.second);
}
private void notifyAllFeaturesRemoved() {
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index 563252a..9b86712 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -16,14 +16,36 @@
package com.android.internal.telephony.imsphone;
+import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC;
+import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr;
+import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC;
+import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOIC;
+import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOICxH;
+import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL;
+import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO;
+import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT;
+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_NONE;
+import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
+
import android.app.Activity;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.net.NetworkStats;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Bundle;
@@ -31,14 +53,12 @@
import android.os.Message;
import android.os.PersistableBundle;
import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.ResultReceiver;
-import android.os.PowerManager.WakeLock;
import android.os.SystemProperties;
import android.os.UserHandle;
-
-import android.provider.Telephony;
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
@@ -55,33 +75,9 @@
import com.android.ims.ImsEcbmStateListener;
import com.android.ims.ImsException;
import com.android.ims.ImsManager;
-import com.android.ims.ImsMultiEndpoint;
import com.android.ims.ImsReasonInfo;
import com.android.ims.ImsSsInfo;
import com.android.ims.ImsUtInterface;
-
-import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOC;
-import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOIC;
-import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAOICxH;
-import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAIC;
-import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BAICr;
-import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_ALL;
-import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MO;
-import static com.android.internal.telephony.CommandsInterface.CB_FACILITY_BA_MT;
-
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_DISABLE;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ERASURE;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_REGISTRATION;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_ALL_CONDITIONAL;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_NO_REPLY;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_NOT_REACHABLE;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_BUSY;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
-import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_VOICE;
-import static com.android.internal.telephony.CommandsInterface.SERVICE_CLASS_NONE;
-
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallForwardInfo;
@@ -101,10 +97,13 @@
import com.android.internal.telephony.UUSInfo;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.uicc.IccRecords;
+import com.android.internal.telephony.util.NotificationChannelController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Deque;
import java.util.List;
/**
@@ -136,7 +135,6 @@
ImsPhoneCallTracker mCT;
ImsExternalCallTracker mExternalCallTracker;
private ArrayList <ImsPhoneMmiCode> mPendingMMIs = new ArrayList<ImsPhoneMmiCode>();
-
private ServiceState mSS = new ServiceState();
// To redial silently through GSM or CDMA when dialing through IMS fails
@@ -226,7 +224,10 @@
.registerForDataRegStateOrRatChanged(this,
EVENT_DEFAULT_PHONE_DATA_STATE_CHANGED, null);
}
- updateDataServiceState();
+ // Sets the Voice reg state to STATE_OUT_OF_SERVICE and also queries the data service
+ // state. We don't ever need the voice reg state to be anything other than in or out of
+ // service.
+ setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
mDefaultPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
// Force initial roaming state update later, on EVENT_CARRIER_CONFIG_CHANGED.
@@ -344,6 +345,11 @@
return mCT.mRingingCall;
}
+ @Override
+ public boolean isImsAvailable() {
+ return mCT.isImsServiceReady();
+ }
+
private boolean handleCallDeflectionIncallSupplementaryService(
String dialString) {
if (dialString.length() > 1) {
@@ -370,15 +376,42 @@
return true;
}
+ 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) {
- try {
- dialInternal(ussdRequest, VideoProfile.STATE_AUDIO_ONLY, null, wrappedCallback);
- return true;
- } catch (Exception e) {
- Rlog.d(LOG_TAG, "exception" + e);
- return false;
+ public boolean handleUssdRequest(String ussdRequest, ResultReceiver wrappedCallback)
+ throws CallStateException {
+ if (mPendingMMIs.size() > 0) {
+ // There are MMI codes in progress; fail attempt now.
+ Rlog.i(LOG_TAG, "handleUssdRequest: queue full: " + Rlog.pii(LOG_TAG, ussdRequest));
+ sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
+ wrappedCallback );
+ return true;
}
+ try {
+ dialInternal(ussdRequest, VideoProfile.STATE_AUDIO_ONLY, null, wrappedCallback);
+ } catch (CallStateException cse) {
+ if (CS_FALLBACK.equals(cse.getMessage())) {
+ throw cse;
+ } else {
+ Rlog.w(LOG_TAG, "Could not execute USSD " + cse);
+ sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
+ wrappedCallback);
+ }
+ } catch (Exception e) {
+ Rlog.w(LOG_TAG, "Could not execute USSD " + e);
+ sendUssdResponse(ussdRequest, null, TelephonyManager.USSD_RETURN_FAILURE,
+ wrappedCallback);
+ return false;
+ }
+ return true;
}
private boolean handleCallWaitingIncallSupplementaryService(
@@ -593,9 +626,9 @@
// Only look at the Network portion for mmi
String networkPortion = PhoneNumberUtils.extractNetworkPortionAlt(newDialString);
ImsPhoneMmiCode mmi =
- ImsPhoneMmiCode.newFromDialString(networkPortion, this);
+ ImsPhoneMmiCode.newFromDialString(networkPortion, this, wrappedCallback);
if (DBG) Rlog.d(LOG_TAG,
- "dialing w/ mmi '" + mmi + "'...");
+ "dialInternal: dialing w/ mmi '" + mmi + "'...");
if (mmi == null) {
return mCT.dial(dialString, videoState, intentExtras);
@@ -604,11 +637,26 @@
} else if (!mmi.isSupportedOverImsPhone()) {
// If the mmi is not supported by IMS service,
// try to initiate dialing with default phone
+ // Note: This code is never reached; there is a bug in isSupportedOverImsPhone which
+ // causes it to return true even though the "processCode" method ultimately throws the
+ // exception.
+ Rlog.i(LOG_TAG, "dialInternal: USSD not supported by IMS; fallback to CS.");
throw new CallStateException(CS_FALLBACK);
} else {
mPendingMMIs.add(mmi);
mMmiRegistrants.notifyRegistrants(new AsyncResult(null, mmi, null));
- mmi.processCode();
+
+ try {
+ mmi.processCode();
+ } catch (CallStateException cse) {
+ if (CS_FALLBACK.equals(cse.getMessage())) {
+ Rlog.i(LOG_TAG, "dialInternal: fallback to GSM required.");
+ // Make sure we remove from the list of pending MMIs since it will handover to
+ // GSM.
+ mPendingMMIs.remove(mmi);
+ throw cse;
+ }
+ }
return null;
}
@@ -656,6 +704,11 @@
}
@Override
+ public void setTTYMode(int ttyMode, Message onComplete) {
+ mCT.setTtyMode(ttyMode);
+ }
+
+ @Override
public void setUiTTYMode(int uiTtyMode, Message onComplete) {
mCT.setUiTTYMode(uiTtyMode, onComplete);
}
@@ -1032,18 +1085,17 @@
} else {
found.onUssdFinished(ussdMessage, isUssdRequest);
}
- } else { // pending USSD not found
- // The network may initiate its own USSD request
+ } 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) {
+ // ignore everything that isnt a Notify or a Request
+ // also, discard if there is no message to present
ImsPhoneMmiCode mmi;
mmi = ImsPhoneMmiCode.newNetworkInitiatedUssd(ussdMessage,
isUssdRequest,
this);
onNetworkInitiatedUssd(mmi);
- }
}
}
@@ -1058,16 +1110,16 @@
* The exception is cancellation of an incoming USSD-REQUEST, which is
* not on the list.
*/
+ Rlog.d(LOG_TAG, "onMMIDone: mmi=" + mmi);
if (mPendingMMIs.remove(mmi) || mmi.isUssdRequest()) {
ResultReceiver receiverCallback = mmi.getUssdCallbackReceiver();
if (receiverCallback != null) {
- UssdResponse response = new UssdResponse(mmi.getDialString(), mmi.getMessage());
- Bundle returnData = new Bundle();
- returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response);
int returnCode = (mmi.getState() == MmiCode.State.COMPLETE) ?
TelephonyManager.USSD_RETURN_SUCCESS : TelephonyManager.USSD_RETURN_FAILURE;
- receiverCallback.send(returnCode, returnData);
+ sendUssdResponse(mmi.getDialString(), mmi.getMessage(), returnCode,
+ receiverCallback );
} else {
+ Rlog.v(LOG_TAG, "onMMIDone: notifyRegistrants");
mMmiCompleteRegistrants.notifyRegistrants(
new AsyncResult(null, mmi, null));
}
@@ -1338,8 +1390,8 @@
Intent intent = new Intent(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
intent.putExtra(PhoneConstants.PHONE_IN_ECM_STATE, isInEcm());
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, getPhoneId());
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
- if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallbackModeChange");
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
+ if (DBG) Rlog.d(LOG_TAG, "sendEmergencyCallbackModeChange: isInEcm=" + isInEcm());
}
@Override
@@ -1502,14 +1554,15 @@
PendingIntent.FLAG_UPDATE_CURRENT
);
- final Notification notification =
- new Notification.Builder(mContext)
+ final Notification notification = new Notification.Builder(mContext)
.setSmallIcon(android.R.drawable.stat_sys_warning)
.setContentTitle(title)
.setContentText(messageNotification)
.setAutoCancel(true)
.setContentIntent(resultPendingIntent)
- .setStyle(new Notification.BigTextStyle().bigText(messageNotification))
+ .setStyle(new Notification.BigTextStyle()
+ .bigText(messageNotification))
+ .setChannelId(NotificationChannelController.CHANNEL_ID_WFC)
.build();
final String notificationTag = "wifi_calling";
final int notificationId = 1;
@@ -1529,95 +1582,103 @@
public void processDisconnectReason(ImsReasonInfo imsReasonInfo) {
if (imsReasonInfo.mCode == imsReasonInfo.CODE_REGISTRATION_ERROR
&& imsReasonInfo.mExtraMessage != null) {
+ // Suppress WFC Registration notifications if WFC is not enabled by the user.
+ if (ImsManager.isWfcEnabledByUser(mContext)) {
+ processWfcDisconnectForNotification(imsReasonInfo);
+ }
+ }
+ }
- CarrierConfigManager configManager =
- (CarrierConfigManager)mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- if (configManager == null) {
- Rlog.e(LOG_TAG, "processDisconnectReason: CarrierConfigManager is not ready");
- return;
- }
- PersistableBundle pb = configManager.getConfigForSubId(getSubId());
- if (pb == null) {
- Rlog.e(LOG_TAG, "processDisconnectReason: no config for subId " + getSubId());
- return;
- }
- final String[] wfcOperatorErrorCodes =
- pb.getStringArray(
- CarrierConfigManager.KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY);
- if (wfcOperatorErrorCodes == null) {
- // no operator-specific error codes
- return;
+ // Processes an IMS disconnect cause for possible WFC registration errors and optionally
+ // disable WFC.
+ private void processWfcDisconnectForNotification(ImsReasonInfo imsReasonInfo) {
+ CarrierConfigManager configManager =
+ (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (configManager == null) {
+ Rlog.e(LOG_TAG, "processDisconnectReason: CarrierConfigManager is not ready");
+ return;
+ }
+ PersistableBundle pb = configManager.getConfigForSubId(getSubId());
+ if (pb == null) {
+ Rlog.e(LOG_TAG, "processDisconnectReason: no config for subId " + getSubId());
+ return;
+ }
+ final String[] wfcOperatorErrorCodes =
+ pb.getStringArray(
+ CarrierConfigManager.KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY);
+ if (wfcOperatorErrorCodes == null) {
+ // no operator-specific error codes
+ return;
+ }
+
+ final String[] wfcOperatorErrorAlertMessages =
+ mContext.getResources().getStringArray(
+ com.android.internal.R.array.wfcOperatorErrorAlertMessages);
+ final String[] wfcOperatorErrorNotificationMessages =
+ mContext.getResources().getStringArray(
+ com.android.internal.R.array.wfcOperatorErrorNotificationMessages);
+
+ for (int i = 0; i < wfcOperatorErrorCodes.length; i++) {
+ String[] codes = wfcOperatorErrorCodes[i].split("\\|");
+ if (codes.length != 2) {
+ Rlog.e(LOG_TAG, "Invalid carrier config: " + wfcOperatorErrorCodes[i]);
+ continue;
}
- final String[] wfcOperatorErrorAlertMessages =
- mContext.getResources().getStringArray(
- com.android.internal.R.array.wfcOperatorErrorAlertMessages);
- final String[] wfcOperatorErrorNotificationMessages =
- mContext.getResources().getStringArray(
- com.android.internal.R.array.wfcOperatorErrorNotificationMessages);
-
- for (int i = 0; i < wfcOperatorErrorCodes.length; i++) {
- String[] codes = wfcOperatorErrorCodes[i].split("\\|");
- if (codes.length != 2) {
- Rlog.e(LOG_TAG, "Invalid carrier config: " + wfcOperatorErrorCodes[i]);
- continue;
- }
-
- // Match error code.
- if (!imsReasonInfo.mExtraMessage.startsWith(
- codes[0])) {
- continue;
- }
- // If there is no delimiter at the end of error code string
- // then we need to verify that we are not matching partial code.
- // EXAMPLE: "REG9" must not match "REG99".
- // NOTE: Error code must not be empty.
- int codeStringLength = codes[0].length();
- char lastChar = codes[0].charAt(codeStringLength - 1);
- if (Character.isLetterOrDigit(lastChar)) {
- if (imsReasonInfo.mExtraMessage.length() > codeStringLength) {
- char nextChar = imsReasonInfo.mExtraMessage.charAt(codeStringLength);
- if (Character.isLetterOrDigit(nextChar)) {
- continue;
- }
+ // Match error code.
+ if (!imsReasonInfo.mExtraMessage.startsWith(
+ codes[0])) {
+ continue;
+ }
+ // If there is no delimiter at the end of error code string
+ // then we need to verify that we are not matching partial code.
+ // EXAMPLE: "REG9" must not match "REG99".
+ // NOTE: Error code must not be empty.
+ int codeStringLength = codes[0].length();
+ char lastChar = codes[0].charAt(codeStringLength - 1);
+ if (Character.isLetterOrDigit(lastChar)) {
+ if (imsReasonInfo.mExtraMessage.length() > codeStringLength) {
+ char nextChar = imsReasonInfo.mExtraMessage.charAt(codeStringLength);
+ if (Character.isLetterOrDigit(nextChar)) {
+ continue;
}
}
-
- final CharSequence title = mContext.getText(
- com.android.internal.R.string.wfcRegErrorTitle);
-
- int idx = Integer.parseInt(codes[1]);
- if (idx < 0 ||
- idx >= wfcOperatorErrorAlertMessages.length ||
- idx >= wfcOperatorErrorNotificationMessages.length) {
- Rlog.e(LOG_TAG, "Invalid index: " + wfcOperatorErrorCodes[i]);
- continue;
- }
- CharSequence messageAlert = imsReasonInfo.mExtraMessage;
- CharSequence messageNotification = imsReasonInfo.mExtraMessage;
- if (!wfcOperatorErrorAlertMessages[idx].isEmpty()) {
- messageAlert = wfcOperatorErrorAlertMessages[idx];
- }
- if (!wfcOperatorErrorNotificationMessages[idx].isEmpty()) {
- messageNotification = wfcOperatorErrorNotificationMessages[idx];
- }
-
- // UX requirement is to disable WFC in case of "permanent" registration failures.
- ImsManager.setWfcSetting(mContext, false);
-
- // If WfcSettings are active then alert will be shown
- // otherwise notification will be added.
- Intent intent = new Intent(ImsManager.ACTION_IMS_REGISTRATION_ERROR);
- intent.putExtra(EXTRA_KEY_ALERT_TITLE, title);
- intent.putExtra(EXTRA_KEY_ALERT_MESSAGE, messageAlert);
- intent.putExtra(EXTRA_KEY_NOTIFICATION_MESSAGE, messageNotification);
- mContext.sendOrderedBroadcast(intent, null, mResultReceiver,
- null, Activity.RESULT_OK, null, null);
-
- // We can only match a single error code
- // so should break the loop after a successful match.
- break;
}
+
+ final CharSequence title = mContext.getText(
+ com.android.internal.R.string.wfcRegErrorTitle);
+
+ int idx = Integer.parseInt(codes[1]);
+ if (idx < 0
+ || idx >= wfcOperatorErrorAlertMessages.length
+ || idx >= wfcOperatorErrorNotificationMessages.length) {
+ Rlog.e(LOG_TAG, "Invalid index: " + wfcOperatorErrorCodes[i]);
+ continue;
+ }
+ CharSequence messageAlert = imsReasonInfo.mExtraMessage;
+ CharSequence messageNotification = imsReasonInfo.mExtraMessage;
+ if (!wfcOperatorErrorAlertMessages[idx].isEmpty()) {
+ messageAlert = wfcOperatorErrorAlertMessages[idx];
+ }
+ if (!wfcOperatorErrorNotificationMessages[idx].isEmpty()) {
+ messageNotification = wfcOperatorErrorNotificationMessages[idx];
+ }
+
+ // UX requirement is to disable WFC in case of "permanent" registration failures.
+ ImsManager.setWfcSetting(mContext, false);
+
+ // If WfcSettings are active then alert will be shown
+ // otherwise notification will be added.
+ Intent intent = new Intent(ImsManager.ACTION_IMS_REGISTRATION_ERROR);
+ intent.putExtra(EXTRA_KEY_ALERT_TITLE, title);
+ intent.putExtra(EXTRA_KEY_ALERT_MESSAGE, messageAlert);
+ intent.putExtra(EXTRA_KEY_NOTIFICATION_MESSAGE, messageNotification);
+ mContext.sendOrderedBroadcast(intent, null, mResultReceiver,
+ null, Activity.RESULT_OK, null, null);
+
+ // We can only match a single error code
+ // so should break the loop after a successful match.
+ break;
}
}
@@ -1642,8 +1703,8 @@
}
@Override
- public long getVtDataUsage() {
- return mCT.getVtDataUsage();
+ public NetworkStats getVtDataUsage(boolean perUidStats) {
+ return mCT.getVtDataUsage(perUidStats);
}
private void updateRoamingState(boolean newRoaming) {
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
index 5eeadbe..ed24d22 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneBase.java
@@ -26,14 +26,14 @@
import android.os.WorkSource;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
+import android.telephony.NetworkScanRequest;
+import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
-import android.telephony.Rlog;
import android.util.Pair;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.Connection;
-import com.android.internal.telephony.dataconnection.DataConnection;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
import com.android.internal.telephony.MmiCode;
@@ -42,6 +42,7 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.PhoneNotifier;
import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.dataconnection.DataConnection;
import com.android.internal.telephony.uicc.IccFileHandler;
import java.util.ArrayList;
@@ -427,6 +428,14 @@
}
@Override
+ public void startNetworkScan(NetworkScanRequest nsr, Message response) {
+ }
+
+ @Override
+ public void stopNetworkScan(Message response) {
+ }
+
+ @Override
public void setNetworkSelectionModeAutomatic(Message response) {
}
@@ -483,7 +492,7 @@
}
@Override
- public boolean isDataConnectivityPossible() {
+ public boolean isDataAllowed() {
return false;
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java
index a011f757..52636f5 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCall.java
@@ -267,6 +267,7 @@
long conferenceConnectTime = imsPhoneConnection.getConferenceConnectTime();
if (conferenceConnectTime > 0) {
imsPhoneConnection.setConnectTime(conferenceConnectTime);
+ imsPhoneConnection.setConnectTimeReal(imsPhoneConnection.getConnectTimeReal());
} else {
if (DBG) {
Rlog.d(LOG_TAG, "merge: conference connect time is 0");
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
index 46a0289..9b4aced 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCallTracker.java
@@ -22,8 +22,10 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
+import android.net.NetworkStats;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Bundle;
@@ -33,15 +35,17 @@
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.telecom.ConferenceParticipant;
+import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
-import android.telephony.PreciseDisconnectCause;
import android.telephony.PhoneNumberUtils;
+import android.telephony.PreciseDisconnectCause;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
@@ -49,10 +53,10 @@
import android.telephony.ims.ImsServiceProxy;
import android.telephony.ims.feature.ImsFeature;
import android.text.TextUtils;
-import android.util.SparseIntArray;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
+import android.util.SparseIntArray;
import com.android.ims.ImsCall;
import com.android.ims.ImsCallProfile;
@@ -71,6 +75,7 @@
import com.android.ims.internal.ImsVideoCallProviderWrapper;
import com.android.ims.internal.VideoPauseTracker;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.SomeArgs;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.CallTracker;
@@ -80,12 +85,13 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyProperties;
-import com.android.internal.telephony.TelephonyProto.ImsConnectionState;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.ImsCommand;
import com.android.internal.telephony.dataconnection.DataEnabledSettings;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.metrics.TelephonyMetrics;
+import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.ImsCommand;
+import com.android.server.net.NetworkStatsService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -93,6 +99,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
/**
@@ -106,6 +113,10 @@
void onPhoneStateChanged(PhoneConstants.State oldState, PhoneConstants.State newState);
}
+ public interface SharedPreferenceProxy {
+ SharedPreferences getDefaultSharedPreferences(Context context);
+ }
+
private static final boolean DBG = true;
// When true, dumps the state of ImsPhoneCallTracker after changes to foreground and background
@@ -121,6 +132,7 @@
"UTLTE", "UTWiFi"};
private TelephonyMetrics mMetrics;
+ private boolean mCarrierConfigLoaded = false;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
@@ -205,6 +217,10 @@
log("onReceive : Updating mAllowEmergencyVideoCalls = " +
mAllowEmergencyVideoCalls);
}
+ mCarrierConfigLoaded = true;
+ } else if (TelecomManager.ACTION_CHANGE_DEFAULT_DIALER.equals(intent.getAction())) {
+ mDefaultDialerUid.set(getPackageUid(context, intent.getStringExtra(
+ TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME)));
}
}
};
@@ -222,6 +238,7 @@
private static final int EVENT_DATA_ENABLED_CHANGED = 23;
private static final int EVENT_GET_IMS_SERVICE = 24;
private static final int EVENT_CHECK_FOR_WIFI_HANDOVER = 25;
+ private static final int EVENT_ON_FEATURE_CAPABILITY_CHANGED = 26;
private static final int TIMEOUT_HANGUP_PENDINGMO = 500;
@@ -249,7 +266,11 @@
// Hold aggregated video call data usage for each video call since boot.
// The ImsCall's call id is the key of the map.
private final HashMap<Integer, Long> mVtDataUsageMap = new HashMap<>();
- private volatile long mTotalVtDataUsage = 0;
+
+ private volatile NetworkStats mVtDataUsageSnapshot = null;
+ private volatile NetworkStats mVtDataUsageUidSnapshot = null;
+
+ private final AtomicInteger mDefaultDialerUid = new AtomicInteger(NetworkStats.UID_ALL);
private ImsPhoneConnection mPendingMO;
private int mClirMode = CommandsInterface.CLIR_DEFAULT;
@@ -283,6 +304,7 @@
private ImsCall mCallExpectedToResume = null;
private boolean mAllowEmergencyVideoCalls = false;
private boolean mIgnoreDataEnabledChangedForVideoCalls = false;
+ private boolean mIsViLteDataMetered = false;
/**
* Listeners to changes in the phone state. Intended for use by other interested IMS components
@@ -335,6 +357,8 @@
PreciseDisconnectCause.LOCAL_IMS_SERVICE_DOWN);
PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_NO_PENDING_CALL,
PreciseDisconnectCause.LOCAL_NO_PENDING_CALL);
+ PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE,
+ PreciseDisconnectCause.NORMAL);
PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_POWER_OFF,
PreciseDisconnectCause.LOCAL_POWER_OFF);
PRECISE_CAUSE_MAP.append(ImsReasonInfo.CODE_LOCAL_LOW_BATTERY,
@@ -569,6 +593,7 @@
*/
private Map<Pair<Integer, String>, Integer> mImsReasonCodeMap = new ArrayMap<>();
+
/**
* TODO: Remove this code; it is a workaround.
* When {@code true}, forces {@link ImsManager#updateImsServiceConfig(Context, int, boolean)} to
@@ -580,6 +605,13 @@
*/
private boolean mShouldUpdateImsConfigOnDisconnect = false;
+ /**
+ * Default implementation for retrieving shared preferences; uses the actual PreferencesManager.
+ */
+ private SharedPreferenceProxy mSharedPreferenceProxy = (Context context) -> {
+ return PreferenceManager.getDefaultSharedPreferences(context);
+ };
+
// Callback fires when ImsManager MMTel Feature changes state
private ImsServiceProxy.INotifyStatusChanged mNotifyStatusChangedCallback = () -> {
try {
@@ -637,6 +669,7 @@
IntentFilter intentfilter = new IntentFilter();
intentfilter.addAction(ImsManager.ACTION_IMS_INCOMING_CALL);
intentfilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ intentfilter.addAction(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
mPhone.getContext().registerReceiver(mReceiver, intentfilter);
cacheCarrierConfiguration(mPhone.getSubId());
@@ -644,11 +677,47 @@
this, EVENT_DATA_ENABLED_CHANGED, null);
mImsServiceRetryCount = 0;
+
+ final TelecomManager telecomManager =
+ (TelecomManager) mPhone.getContext().getSystemService(Context.TELECOM_SERVICE);
+ mDefaultDialerUid.set(
+ getPackageUid(mPhone.getContext(), telecomManager.getDefaultDialerPackage()));
+
+ long currentTime = SystemClock.elapsedRealtime();
+ mVtDataUsageSnapshot = new NetworkStats(currentTime, 1);
+ mVtDataUsageUidSnapshot = new NetworkStats(currentTime, 1);
+
// Send a message to connect to the Ims Service and open a connection through
// getImsService().
sendEmptyMessage(EVENT_GET_IMS_SERVICE);
}
+ /**
+ * Test-only method used to mock out access to the shared preferences through the
+ * {@link PreferenceManager}.
+ * @param sharedPreferenceProxy
+ */
+ @VisibleForTesting
+ public void setSharedPreferenceProxy(SharedPreferenceProxy sharedPreferenceProxy) {
+ mSharedPreferenceProxy = sharedPreferenceProxy;
+ }
+
+ private int getPackageUid(Context context, String pkg) {
+ if (pkg == null) {
+ return NetworkStats.UID_ALL;
+ }
+
+ // Initialize to UID_ALL so at least it can be counted to overall data usage if
+ // the dialer's package uid is not available.
+ int uid = NetworkStats.UID_ALL;
+ try {
+ uid = context.getPackageManager().getPackageUid(pkg, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ loge("Cannot find package uid. pkg = " + pkg);
+ }
+ return uid;
+ }
+
private PendingIntent createIncomingCallPendingIntent() {
Intent intent = new Intent(ImsManager.ACTION_IMS_INCOMING_CALL);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -692,10 +761,16 @@
multiEndpoint.setExternalCallStateListener(
mPhone.getExternalCallTracker().getExternalCallStateListener());
}
+
+ if (mCarrierConfigLoaded) {
+ ImsManager.updateImsServiceConfig(mPhone.getContext(),
+ mPhone.getPhoneId(), true);
+ }
}
private void stopListeningForCalls() {
try {
+ resetImsCapabilities();
// Only close on valid session.
if (mImsManager != null && mServiceId > 0) {
mImsManager.close(mServiceId);
@@ -751,8 +826,16 @@
public Connection dial(String dialString, int videoState, Bundle intentExtras) throws
CallStateException {
- SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
- int oirMode = sp.getInt(Phone.CLIR_KEY, CommandsInterface.CLIR_DEFAULT);
+ int oirMode;
+ if (mSharedPreferenceProxy != null && mPhone.getDefaultPhone() != null) {
+ SharedPreferences sp = mSharedPreferenceProxy.getDefaultSharedPreferences(
+ mPhone.getContext());
+ oirMode = sp.getInt(Phone.CLIR_KEY + mPhone.getDefaultPhone().getPhoneId(),
+ CommandsInterface.CLIR_DEFAULT);
+ } else {
+ loge("dial; could not get default CLIR mode.");
+ oirMode = CommandsInterface.CLIR_DEFAULT;
+ }
return dial(dialString, oirMode, videoState, intentExtras);
}
@@ -859,6 +942,14 @@
return mPendingMO;
}
+ boolean isImsServiceReady() {
+ if (mImsManager == null) {
+ return false;
+ }
+
+ return mImsManager.isServiceAvailable();
+ }
+
/**
* Caches frequently used carrier configuration items locally.
*
@@ -894,9 +985,11 @@
mSupportDowngradeVtToAudio = carrierConfig.getBoolean(
CarrierConfigManager.KEY_SUPPORT_DOWNGRADE_VT_TO_AUDIO_BOOL);
mNotifyHandoverVideoFromWifiToLTE = carrierConfig.getBoolean(
- CarrierConfigManager.KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL);
+ CarrierConfigManager.KEY_NOTIFY_HANDOVER_VIDEO_FROM_WIFI_TO_LTE_BOOL);
mIgnoreDataEnabledChangedForVideoCalls = carrierConfig.getBoolean(
CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS);
+ mIsViLteDataMetered = carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_VILTE_DATA_IS_METERED_BOOL);
mSupportPauseVideo = carrierConfig.getBoolean(
CarrierConfigManager.KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL);
@@ -1117,7 +1210,7 @@
// Swap the ImsCalls pointed to by the foreground and background ImsPhoneCalls.
// If hold or resume later fails, we will swap them back.
- boolean switchingWithWaitingCall = mBackgroundCall.getImsCall() == null &&
+ boolean switchingWithWaitingCall = !mBackgroundCall.getState().isAlive() &&
mRingingCall != null &&
mRingingCall.getState() == ImsPhoneCall.State.WAITING;
@@ -1186,6 +1279,13 @@
ImsPhoneConnection foregroundConnection = mForegroundCall.getFirstConnection();
if (foregroundConnection != null) {
foregroundConnection.setConferenceConnectTime(conferenceConnectTime);
+ foregroundConnection.onConnectionEvent(android.telecom.Connection.EVENT_MERGE_START,
+ null);
+ }
+ ImsPhoneConnection backgroundConnection = findConnection(bgImsCall);
+ if (backgroundConnection != null) {
+ backgroundConnection.onConnectionEvent(android.telecom.Connection.EVENT_MERGE_START,
+ null);
}
try {
@@ -1218,19 +1318,16 @@
&& !mForegroundCall.isFull();
}
- public boolean
- canDial() {
+ public boolean canDial() {
boolean ret;
- int serviceState = mPhone.getServiceState().getState();
String disableCall = SystemProperties.get(
TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
- ret = (serviceState != ServiceState.STATE_POWER_OFF)
- && mPendingMO == null
- && !mRingingCall.isRinging()
- && !disableCall.equals("true")
- && (!mForegroundCall.getState().isAlive()
- || !mBackgroundCall.getState().isAlive());
+ ret = mPendingMO == null
+ && !mRingingCall.isRinging()
+ && !disableCall.equals("true")
+ && (!mForegroundCall.getState().isAlive()
+ || !mBackgroundCall.getState().isAlive());
return ret;
}
@@ -1327,7 +1424,27 @@
}
//***** Called from ImsPhone
+ /**
+ * Set the TTY mode. This is the actual tty mode (varies depending on peripheral status)
+ */
+ public void setTtyMode(int ttyMode) {
+ if (mImsManager == null) {
+ Log.w(LOG_TAG, "ImsManager is null when setting TTY mode");
+ return;
+ }
+ try {
+ mImsManager.setTtyMode(ttyMode);
+ } catch (ImsException e) {
+ loge("setTtyMode : " + e);
+ retryGetImsService();
+ }
+ }
+
+ /**
+ * Sets the UI TTY mode. This is the preferred TTY mode that the user sets in the call
+ * settings screen.
+ */
public void setUiTTYMode(int uiTtyMode, Message onComplete) {
if (mImsManager == null) {
mPhone.sendErrorResponse(onComplete, getImsManagerIsNullException());
@@ -1337,7 +1454,7 @@
try {
mImsManager.setUiTTYMode(mPhone.getContext(), uiTtyMode, onComplete);
} catch (ImsException e) {
- loge("setTTYMode : " + e);
+ loge("setUITTYMode : " + e);
mPhone.sendErrorResponse(onComplete, e);
retryGetImsService();
}
@@ -1703,10 +1820,17 @@
return code;
}
- private int getDisconnectCauseFromReasonInfo(ImsReasonInfo reasonInfo) {
+ /**
+ * Maps an {@link ImsReasonInfo} reason code to a {@link DisconnectCause} cause code.
+ * The {@link Call.State} provided is the state of the call prior to disconnection.
+ * @param reasonInfo the {@link ImsReasonInfo} for the disconnection.
+ * @param callState The {@link Call.State} prior to disconnection.
+ * @return The {@link DisconnectCause} code.
+ */
+ @VisibleForTesting
+ public int getDisconnectCauseFromReasonInfo(ImsReasonInfo reasonInfo, Call.State callState) {
int cause = DisconnectCause.ERROR_UNSPECIFIED;
- //int type = reasonInfo.getReasonType();
int code = maybeRemapReasonCode(reasonInfo);
switch (code) {
case ImsReasonInfo.CODE_SIP_BAD_ADDRESS:
@@ -1719,6 +1843,9 @@
case ImsReasonInfo.CODE_USER_TERMINATED:
return DisconnectCause.LOCAL;
+ case ImsReasonInfo.CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE:
+ return DisconnectCause.IMS_MERGED_SUCCESSFULLY;
+
case ImsReasonInfo.CODE_LOCAL_CALL_DECLINE:
case ImsReasonInfo.CODE_REMOTE_CALL_DECLINE:
// If the call has been declined locally (on this device), or on remotely (on
@@ -1759,13 +1886,24 @@
case ImsReasonInfo.CODE_TIMEOUT_NO_ANSWER_CALL_UPDATE:
return DisconnectCause.TIMED_OUT;
- case ImsReasonInfo.CODE_LOCAL_LOW_BATTERY:
case ImsReasonInfo.CODE_LOCAL_POWER_OFF:
return DisconnectCause.POWER_OFF;
+ case ImsReasonInfo.CODE_LOCAL_LOW_BATTERY:
+ case ImsReasonInfo.CODE_LOW_BATTERY: {
+ if (callState == Call.State.DIALING) {
+ return DisconnectCause.DIAL_LOW_BATTERY;
+ } else {
+ return DisconnectCause.LOW_BATTERY;
+ }
+ }
+
case ImsReasonInfo.CODE_FDN_BLOCKED:
return DisconnectCause.FDN_BLOCKED;
+ case ImsReasonInfo.CODE_IMEI_NOT_ACCEPTED:
+ return DisconnectCause.IMEI_NOT_ACCEPTED;
+
case ImsReasonInfo.CODE_ANSWERED_ELSEWHERE:
return DisconnectCause.ANSWERED_ELSEWHERE;
@@ -1783,6 +1921,16 @@
case ImsReasonInfo.CODE_WIFI_LOST:
return DisconnectCause.WIFI_LOST;
+
+ case ImsReasonInfo.CODE_ACCESS_CLASS_BLOCKED:
+ return DisconnectCause.IMS_ACCESS_BLOCKED;
+
+ case ImsReasonInfo.CODE_EMERGENCY_TEMP_FAILURE:
+ return DisconnectCause.EMERGENCY_TEMP_FAILURE;
+
+ case ImsReasonInfo.CODE_EMERGENCY_PERM_FAILURE:
+ return DisconnectCause.EMERGENCY_PERM_FAILURE;
+
default:
}
@@ -1904,8 +2052,18 @@
return;
} else {
mPendingMO = null;
- int cause = getDisconnectCauseFromReasonInfo(reasonInfo);
ImsPhoneConnection conn = findConnection(imsCall);
+ Call.State callState;
+ if (conn != null) {
+ callState = conn.getState();
+ } else {
+ // Need to fall back in case connection is null; it shouldn't be, but a sane
+ // fallback is to assume we're dialing. This state is only used to
+ // determine which disconnect string to show in the case of a low battery
+ // disconnect.
+ callState = Call.State.DIALING;
+ }
+ int cause = getDisconnectCauseFromReasonInfo(reasonInfo, callState);
if(conn != null) {
conn.setPreciseDisconnectCause(
@@ -1923,8 +2081,18 @@
public void onCallTerminated(ImsCall imsCall, ImsReasonInfo reasonInfo) {
if (DBG) log("onCallTerminated reasonCode=" + reasonInfo.getCode());
- int cause = getDisconnectCauseFromReasonInfo(reasonInfo);
ImsPhoneConnection conn = findConnection(imsCall);
+ Call.State callState;
+ if (conn != null) {
+ callState = conn.getState();
+ } else {
+ // Connection shouldn't be null, but if it is, we can assume the call was active.
+ // This call state is only used for determining which disconnect message to show in
+ // the case of the device's battery being low resulting in a call drop.
+ callState = Call.State.ACTIVE;
+ }
+ int cause = getDisconnectCauseFromReasonInfo(reasonInfo, callState);
+
if (DBG) log("cause = " + cause + " conn = " + conn);
if (conn != null) {
@@ -2176,10 +2344,21 @@
mPhone.stopOnHoldTone(conn);
mOnHoldToneStarted = false;
}
-
conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_REMOTELY_UNHELD, null);
}
+ boolean useVideoPauseWorkaround = mPhone.getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_useVideoPauseWorkaround);
+ if (useVideoPauseWorkaround && mSupportPauseVideo &&
+ VideoProfile.isVideo(conn.getVideoState())) {
+ // If we are using the video pause workaround, the vendor IMS code has issues
+ // with video pause signalling. In this case, when a call is remotely
+ // held, the modem does not reliably change the video state of the call to be
+ // paused.
+ // As a workaround, we will turn on that bit now.
+ conn.changeToUnPausedState();
+ }
+
SuppServiceNotification supp = new SuppServiceNotification();
// Type of notification: 0 = MO; 1 = MT
// Refer SuppServiceNotification class documentation.
@@ -2201,8 +2380,19 @@
mOnHoldToneStarted = true;
mOnHoldToneId = System.identityHashCode(conn);
}
-
conn.onConnectionEvent(android.telecom.Connection.EVENT_CALL_REMOTELY_HELD, null);
+
+ boolean useVideoPauseWorkaround = mPhone.getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_useVideoPauseWorkaround);
+ if (useVideoPauseWorkaround && mSupportPauseVideo &&
+ VideoProfile.isVideo(conn.getVideoState())) {
+ // If we are using the video pause workaround, the vendor IMS code has issues
+ // with video pause signalling. In this case, when a call is remotely
+ // held, the modem does not reliably change the video state of the call to be
+ // paused.
+ // As a workaround, we will turn on that bit now.
+ conn.changeToPausedState();
+ }
}
SuppServiceNotification supp = new SuppServiceNotification();
@@ -2289,6 +2479,7 @@
ImsPhoneConnection conn = findConnection(call);
if (conn != null) {
conn.onConferenceMergeFailed();
+ conn.onConnectionEvent(android.telecom.Connection.EVENT_MERGE_COMPLETE, null);
}
}
@@ -2319,28 +2510,40 @@
ImsReasonInfo reasonInfo) {
if (DBG) {
log("onCallHandover :: srcAccessTech=" + srcAccessTech + ", targetAccessTech=" +
- targetAccessTech + ", reasonInfo=" + reasonInfo);
+ targetAccessTech + ", reasonInfo=" + reasonInfo);
}
- boolean isHandoverToWifi = srcAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN &&
- targetAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+ // Only consider it a valid handover to WIFI if the source radio tech is known.
+ boolean isHandoverToWifi = srcAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
+ && srcAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+ && targetAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
if (isHandoverToWifi) {
// If we handed over to wifi successfully, don't check for failure in the future.
removeMessages(EVENT_CHECK_FOR_WIFI_HANDOVER);
}
- boolean isHandoverFromWifi =
- srcAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN &&
- targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
- if (mNotifyHandoverVideoFromWifiToLTE && isHandoverFromWifi && imsCall.isVideoCall()) {
- log("onCallHandover :: notifying of WIFI to LTE handover.");
- ImsPhoneConnection conn = findConnection(imsCall);
- if (conn != null) {
- conn.onConnectionEvent(
- TelephonyManager.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE, null);
- } else {
- loge("onCallHandover :: failed to notify of handover; connection is null.");
+ ImsPhoneConnection conn = findConnection(imsCall);
+ if (conn != null) {
+ // Only consider it a handover from WIFI if the source and target radio tech is known.
+ boolean isHandoverFromWifi =
+ srcAccessTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN
+ && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN
+ && targetAccessTech != ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+ if (isHandoverFromWifi && imsCall.isVideoCall()) {
+ if (mNotifyHandoverVideoFromWifiToLTE && mIsDataEnabled) {
+ log("onCallHandover :: notifying of WIFI to LTE handover.");
+ conn.onConnectionEvent(
+ TelephonyManager.EVENT_HANDOVER_VIDEO_FROM_WIFI_TO_LTE, null);
+ }
+
+ if (!mIsDataEnabled && mIsViLteDataMetered) {
+ // Call was downgraded from WIFI to LTE and data is metered; downgrade the
+ // call now.
+ downgradeVideoCall(ImsReasonInfo.CODE_WIFI_LOST, conn);
+ }
}
+ } else {
+ loge("onCallHandover :: connection null.");
}
mMetrics.writeOnImsCallHandoverEvent(mPhone.getPhoneId(),
@@ -2492,8 +2695,8 @@
private ImsConnectionStateListener mImsConnectionStateListener =
new ImsConnectionStateListener() {
@Override
- public void onImsConnected() {
- if (DBG) log("onImsConnected");
+ public void onImsConnected(int imsRadioTech) {
+ if (DBG) log("onImsConnected imsRadioTech=" + imsRadioTech);
mPhone.setServiceState(ServiceState.STATE_IN_SERVICE);
mPhone.setImsRegistered(true);
mMetrics.writeOnImsConnectionState(mPhone.getPhoneId(),
@@ -2503,6 +2706,7 @@
@Override
public void onImsDisconnected(ImsReasonInfo imsReasonInfo) {
if (DBG) log("onImsDisconnected imsReasonInfo=" + imsReasonInfo);
+ resetImsCapabilities();
mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
mPhone.setImsRegistered(false);
mPhone.processDisconnectReason(imsReasonInfo);
@@ -2511,8 +2715,8 @@
}
@Override
- public void onImsProgressing() {
- if (DBG) log("onImsProgressing");
+ public void onImsProgressing(int imsRadioTech) {
+ if (DBG) log("onImsProgressing imsRadioTech=" + imsRadioTech);
mPhone.setServiceState(ServiceState.STATE_OUT_OF_SERVICE);
mPhone.setImsRegistered(false);
mMetrics.writeOnImsConnectionState(mPhone.getPhoneId(),
@@ -2539,59 +2743,14 @@
@Override
public void onFeatureCapabilityChanged(int serviceClass,
int[] enabledFeatures, int[] disabledFeatures) {
- if (serviceClass == ImsServiceClass.MMTEL) {
- boolean tmpIsVideoCallEnabled = isVideoCallEnabled();
- // Check enabledFeatures to determine capabilities. We ignore disabledFeatures.
- StringBuilder sb;
- if (DBG) {
- sb = new StringBuilder(120);
- sb.append("onFeatureCapabilityChanged: ");
- }
- for (int i = ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE;
- i <= ImsConfig.FeatureConstants.FEATURE_TYPE_UT_OVER_WIFI &&
- i < enabledFeatures.length; i++) {
- if (enabledFeatures[i] == i) {
- // If the feature is set to its own integer value it is enabled.
- if (DBG) {
- sb.append(mImsFeatureStrings[i]);
- sb.append(":true ");
- }
-
- mImsFeatureEnabled[i] = true;
- } else if (enabledFeatures[i]
- == ImsConfig.FeatureConstants.FEATURE_TYPE_UNKNOWN) {
- // FEATURE_TYPE_UNKNOWN indicates that a feature is disabled.
- if (DBG) {
- sb.append(mImsFeatureStrings[i]);
- sb.append(":false ");
- }
-
- mImsFeatureEnabled[i] = false;
- } else {
- // Feature has unknown state; it is not its own value or -1.
- if (DBG) {
- loge("onFeatureCapabilityChanged(" + i + ", " + mImsFeatureStrings[i]
- + "): unexpectedValue=" + enabledFeatures[i]);
- }
- }
- }
- if (DBG) {
- log(sb.toString());
- }
- if (tmpIsVideoCallEnabled != isVideoCallEnabled()) {
- mPhone.notifyForVideoCapabilityChanged(isVideoCallEnabled());
- }
-
- if (DBG) log("onFeatureCapabilityChanged: isVolteEnabled=" + isVolteEnabled()
- + ", isVideoCallEnabled=" + isVideoCallEnabled()
- + ", isVowifiEnabled=" + isVowifiEnabled()
- + ", isUtEnabled=" + isUtEnabled());
-
- mPhone.onFeatureCapabilityChanged();
-
- mMetrics.writeOnImsCapabilities(
- mPhone.getPhoneId(), mImsFeatureEnabled);
- }
+ if (DBG) log("onFeatureCapabilityChanged");
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = serviceClass;
+ args.arg1 = enabledFeatures;
+ args.arg2 = disabledFeatures;
+ // Remove any pending updates; they're already stale, so no need to process them.
+ removeMessages(EVENT_ON_FEATURE_CAPABILITY_CHANGED);
+ obtainMessage(EVENT_ON_FEATURE_CAPABILITY_CHANGED, args).sendToTarget();
}
@Override
@@ -2740,13 +2899,9 @@
ImsCall call = (ImsCall) ar.userObj;
Long usage = (long) ar.result;
log("VT data usage update. usage = " + usage + ", imsCall = " + call);
-
- Long oldUsage = 0L;
- if (mVtDataUsageMap.containsKey(call.uniqueId)) {
- oldUsage = mVtDataUsageMap.get(call.uniqueId);
+ if (usage > 0) {
+ updateVtDataUsage(call, usage);
}
- mTotalVtDataUsage += (usage - oldUsage);
- mVtDataUsageMap.put(call.uniqueId, usage);
break;
case EVENT_DATA_ENABLED_CHANGED:
ar = (AsyncResult) msg.obj;
@@ -2775,9 +2930,76 @@
}
}
break;
+ case EVENT_ON_FEATURE_CAPABILITY_CHANGED: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ int serviceClass = args.argi1;
+ int[] enabledFeatures = (int[]) args.arg1;
+ int[] disabledFeatures = (int[]) args.arg2;
+ handleFeatureCapabilityChanged(serviceClass, enabledFeatures, disabledFeatures);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
}
}
+ /**
+ * Update video call data usage
+ *
+ * @param call The IMS call
+ * @param dataUsage The aggregated data usage for the call
+ */
+ private void updateVtDataUsage(ImsCall call, long dataUsage) {
+ long oldUsage = 0L;
+ if (mVtDataUsageMap.containsKey(call.uniqueId)) {
+ oldUsage = mVtDataUsageMap.get(call.uniqueId);
+ }
+
+ long delta = dataUsage - oldUsage;
+ mVtDataUsageMap.put(call.uniqueId, dataUsage);
+
+ log("updateVtDataUsage: call=" + call + ", delta=" + delta);
+
+ long currentTime = SystemClock.elapsedRealtime();
+ int isRoaming = mPhone.getServiceState().getDataRoaming() ? 1 : 0;
+
+ // Create the snapshot of total video call data usage.
+ NetworkStats vtDataUsageSnapshot = new NetworkStats(currentTime, 1);
+ vtDataUsageSnapshot.combineAllValues(mVtDataUsageSnapshot);
+ // Since the modem only reports the total vt data usage rather than rx/tx separately,
+ // the only thing we can do here is splitting the usage into half rx and half tx.
+ // Uid -1 indicates this is for the overall device data usage.
+ vtDataUsageSnapshot.combineValues(new NetworkStats.Entry(
+ NetworkStatsService.VT_INTERFACE, -1, NetworkStats.SET_FOREGROUND,
+ NetworkStats.TAG_NONE, 1, isRoaming, delta / 2, 0, delta / 2, 0, 0));
+ mVtDataUsageSnapshot = vtDataUsageSnapshot;
+
+ // Create the snapshot of video call data usage per dialer. combineValues will create
+ // a separate entry if uid is different from the previous snapshot.
+ NetworkStats vtDataUsageUidSnapshot = new NetworkStats(currentTime, 1);
+ vtDataUsageUidSnapshot.combineAllValues(mVtDataUsageUidSnapshot);
+
+ // The dialer uid might not be initialized correctly during boot up due to telecom service
+ // not ready or its default dialer cache not ready. So we double check again here to see if
+ // default dialer uid is really not available.
+ if (mDefaultDialerUid.get() == NetworkStats.UID_ALL) {
+ final TelecomManager telecomManager =
+ (TelecomManager) mPhone.getContext().getSystemService(Context.TELECOM_SERVICE);
+ mDefaultDialerUid.set(
+ getPackageUid(mPhone.getContext(), telecomManager.getDefaultDialerPackage()));
+ }
+
+ // Since the modem only reports the total vt data usage rather than rx/tx separately,
+ // the only thing we can do here is splitting the usage into half rx and half tx.
+ vtDataUsageUidSnapshot.combineValues(new NetworkStats.Entry(
+ NetworkStatsService.VT_INTERFACE, mDefaultDialerUid.get(),
+ NetworkStats.SET_FOREGROUND, NetworkStats.TAG_NONE, 1, isRoaming, delta / 2,
+ 0, delta / 2, 0, 0));
+ mVtDataUsageUidSnapshot = vtDataUsageUidSnapshot;
+ }
+
@Override
protected void log(String msg) {
Rlog.d(LOG_TAG, "[ImsPhoneCallTracker] " + msg);
@@ -2833,10 +3055,9 @@
pw.println(" " + mImsFeatureStrings[i] + ": "
+ ((mImsFeatureEnabled[i]) ? "enabled" : "disabled"));
}
- pw.println(" mTotalVtDataUsage=" + mTotalVtDataUsage);
- for (Map.Entry<Integer, Long> entry : mVtDataUsageMap.entrySet()) {
- pw.println(" id=" + entry.getKey() + " ,usage=" + entry.getValue());
- }
+ pw.println(" mDefaultDialerUid=" + mDefaultDialerUid.get());
+ pw.println(" mVtDataUsageSnapshot=" + mVtDataUsageSnapshot);
+ pw.println(" mVtDataUsageUidSnapshot=" + mVtDataUsageUidSnapshot);
pw.flush();
pw.println("++++++++++++++++++++++++++++++++");
@@ -2929,8 +3150,15 @@
IImsVideoCallProvider imsVideoCallProvider =
imsCall.getCallSession().getVideoCallProvider();
if (imsVideoCallProvider != null) {
+ // TODO: Remove this when we can better formalize the format of session modify requests.
+ boolean useVideoPauseWorkaround = mPhone.getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_useVideoPauseWorkaround);
+
ImsVideoCallProviderWrapper imsVideoCallProviderWrapper =
new ImsVideoCallProviderWrapper(imsVideoCallProvider);
+ if (useVideoPauseWorkaround) {
+ imsVideoCallProviderWrapper.setUseVideoPauseWorkaround(useVideoPauseWorkaround);
+ }
conn.setVideoProvider(imsVideoCallProviderWrapper);
imsVideoCallProviderWrapper.registerForDataUsageUpdate
(this, EVENT_VT_DATA_USAGE_UPDATE, imsCall);
@@ -3076,11 +3304,13 @@
return isActiveCallVideo && isActiveCallOnWifi && isIncomingCallAudio && !isVoWifiEnabled;
}
- /** Get aggregated video call data usage since boot.
+ /**
+ * Get aggregated video call data usage since boot.
*
- * @return data usage in bytes
+ * @param perUidStats True if requesting data usage per uid, otherwise overall usage.
+ * @return Snapshot of video call data usage
*/
- public long getVtDataUsage() {
+ public NetworkStats getVtDataUsage(boolean perUidStats) {
// If there is an ongoing VT call, request the latest VT usage from the modem. The latest
// usage will return asynchronously so it won't be counted in this round, but it will be
@@ -3094,7 +3324,7 @@
}
}
- return mTotalVtDataUsage;
+ return perUidStats ? mVtDataUsageUidSnapshot : mVtDataUsageSnapshot;
}
public void registerPhoneStateListener(PhoneStateListener listener) {
@@ -3148,27 +3378,46 @@
ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId()).setDataEnabled(enabled);
mIsDataEnabled = enabled;
- if (mIgnoreDataEnabledChangedForVideoCalls) {
- log("Ignore data " + ((enabled) ? "enabled" : "disabled") + " due to carrier policy.");
+ if (!mIsViLteDataMetered) {
+ log("Ignore data " + ((enabled) ? "enabled" : "disabled") + " - carrier policy "
+ + "indicates that data is not metered for ViLTE calls.");
return;
}
- if (mIgnoreDataEnabledChangedForVideoCalls) {
- log("Ignore data " + ((enabled) ? "enabled" : "disabled") + " due to carrier policy.");
- return;
+ // Inform connections that data has been disabled to ensure we turn off video capability
+ // if this is an LTE call.
+ for (ImsPhoneConnection conn : mConnections) {
+ conn.handleDataEnabledChange(enabled);
}
+ int reasonCode;
+ if (reason == DataEnabledSettings.REASON_POLICY_DATA_ENABLED) {
+ reasonCode = ImsReasonInfo.CODE_DATA_LIMIT_REACHED;
+ } else if (reason == DataEnabledSettings.REASON_USER_DATA_ENABLED) {
+ reasonCode = ImsReasonInfo.CODE_DATA_DISABLED;
+ } else {
+ // Unexpected code, default to data disabled.
+ reasonCode = ImsReasonInfo.CODE_DATA_DISABLED;
+ }
+
+ // Potentially send connection events so the InCall UI knows that video calls are being
+ // downgraded due to data being enabled/disabled.
+ maybeNotifyDataDisabled(enabled, reasonCode);
+ // Handle video state changes required as a result of data being enabled/disabled.
+ handleDataEnabledChange(enabled, reasonCode);
+
+ // We do not want to update the ImsConfig for REASON_REGISTERED, since it can happen before
+ // the carrier config has loaded and will deregister IMS.
+ if (!mShouldUpdateImsConfigOnDisconnect
+ && reason != DataEnabledSettings.REASON_REGISTERED) {
+ // This will call into updateVideoCallFeatureValue and eventually all clients will be
+ // asynchronously notified that the availability of VT over LTE has changed.
+ ImsManager.updateImsServiceConfig(mPhone.getContext(), mPhone.getPhoneId(), true);
+ }
+ }
+
+ private void maybeNotifyDataDisabled(boolean enabled, int reasonCode) {
if (!enabled) {
- int reasonCode;
- if (reason == DataEnabledSettings.REASON_POLICY_DATA_ENABLED) {
- reasonCode = ImsReasonInfo.CODE_DATA_LIMIT_REACHED;
- } else if (reason == DataEnabledSettings.REASON_USER_DATA_ENABLED) {
- reasonCode = ImsReasonInfo.CODE_DATA_DISABLED;
- } else {
- // Unexpected code, default to data disabled.
- reasonCode = ImsReasonInfo.CODE_DATA_DISABLED;
- }
-
// If data is disabled while there are ongoing VT calls which are not taking place over
// wifi, then they should be disconnected to prevent the user from incurring further
// data charges.
@@ -3188,27 +3437,38 @@
conn.onConnectionEvent(
TelephonyManager.EVENT_DOWNGRADE_DATA_LIMIT_REACHED, null);
}
- modifyVideoCall(imsCall, VideoProfile.STATE_AUDIO_ONLY);
- } else if (mSupportPauseVideo) {
- // The carrier supports video pause signalling, so pause the video.
- mShouldUpdateImsConfigOnDisconnect = true;
- conn.pauseVideo(VideoPauseTracker.SOURCE_DATA_ENABLED);
- } else {
- // At this point the only choice we have is to terminate the call.
- try {
- imsCall.terminate(ImsReasonInfo.CODE_USER_TERMINATED, reasonCode);
- } catch (ImsException ie) {
- loge("Couldn't terminate call " + imsCall);
- }
}
}
}
+ }
+ }
+
+ /**
+ * Handles changes to the enabled state of mobile data.
+ * When data is disabled, handles auto-downgrade of video calls over LTE.
+ * When data is enabled, handled resuming of video calls paused when data was disabled.
+ * @param enabled {@code true} if mobile data is enabled, {@code false} if mobile data is
+ * disabled.
+ * @param reasonCode The {@link ImsReasonInfo} code for the data enabled state change.
+ */
+ private void handleDataEnabledChange(boolean enabled, int reasonCode) {
+ if (!enabled) {
+ // If data is disabled while there are ongoing VT calls which are not taking place over
+ // wifi, then they should be disconnected to prevent the user from incurring further
+ // data charges.
+ for (ImsPhoneConnection conn : mConnections) {
+ ImsCall imsCall = conn.getImsCall();
+ if (imsCall != null && imsCall.isVideoCall() && !imsCall.isWifiCall()) {
+ log("handleDataEnabledChange - downgrading " + conn);
+ downgradeVideoCall(reasonCode, conn);
+ }
+ }
} else if (mSupportPauseVideo) {
// Data was re-enabled, so un-pause previously paused video calls.
for (ImsPhoneConnection conn : mConnections) {
// If video is paused, check to see if there are any pending pauses due to enabled
// state of data changing.
- log("onDataEnabledChanged - resuming " + conn);
+ log("handleDataEnabledChange - resuming " + conn);
if (VideoProfile.isPaused(conn.getVideoState()) &&
conn.wasVideoPausedFromSource(VideoPauseTracker.SOURCE_DATA_ENABLED)) {
// The data enabled state was a cause of a pending pause, so potentially
@@ -3218,11 +3478,47 @@
}
mShouldUpdateImsConfigOnDisconnect = false;
}
+ }
- if (!mShouldUpdateImsConfigOnDisconnect) {
- // This will call into updateVideoCallFeatureValue and eventually all clients will be
- // asynchronously notified that the availability of VT over LTE has changed.
- ImsManager.updateImsServiceConfig(mPhone.getContext(), mPhone.getPhoneId(), true);
+ /**
+ * Handles downgrading a video call. The behavior depends on carrier capabilities; we will
+ * attempt to take one of the following actions (in order of precedence):
+ * 1. If supported by the carrier, the call will be downgraded to an audio-only call.
+ * 2. If the carrier supports video pause signalling, the video will be paused.
+ * 3. The call will be disconnected.
+ * @param reasonCode The {@link ImsReasonInfo} reason code for the downgrade.
+ * @param conn The {@link ImsPhoneConnection} to downgrade.
+ */
+ private void downgradeVideoCall(int reasonCode, ImsPhoneConnection conn) {
+ ImsCall imsCall = conn.getImsCall();
+ if (imsCall != null) {
+ if (conn.hasCapabilities(
+ Connection.Capability.SUPPORTS_DOWNGRADE_TO_VOICE_LOCAL |
+ Connection.Capability.SUPPORTS_DOWNGRADE_TO_VOICE_REMOTE)) {
+
+ // If the carrier supports downgrading to voice, then we can simply issue a
+ // downgrade to voice instead of terminating the call.
+ modifyVideoCall(imsCall, VideoProfile.STATE_AUDIO_ONLY);
+ } else if (mSupportPauseVideo && reasonCode != ImsReasonInfo.CODE_WIFI_LOST) {
+ // The carrier supports video pause signalling, so pause the video if we didn't just
+ // lose wifi; in that case just disconnect.
+ mShouldUpdateImsConfigOnDisconnect = true;
+ conn.pauseVideo(VideoPauseTracker.SOURCE_DATA_ENABLED);
+ } else {
+ // At this point the only choice we have is to terminate the call.
+ try {
+ imsCall.terminate(ImsReasonInfo.CODE_USER_TERMINATED, reasonCode);
+ } catch (ImsException ie) {
+ loge("Couldn't terminate call " + imsCall);
+ }
+ }
+ }
+ }
+
+ private void resetImsCapabilities() {
+ log("Resetting Capabilities...");
+ for (int i = 0; i < mImsFeatureEnabled.length; i++) {
+ mImsFeatureEnabled[i] = false;
}
}
@@ -3247,4 +3543,71 @@
public boolean isCarrierDowngradeOfVtCallSupported() {
return mSupportDowngradeVtToAudio;
}
+
+ private void handleFeatureCapabilityChanged(int serviceClass,
+ int[] enabledFeatures, int[] disabledFeatures) {
+ if (serviceClass == ImsServiceClass.MMTEL) {
+ boolean tmpIsVideoCallEnabled = isVideoCallEnabled();
+ // Check enabledFeatures to determine capabilities. We ignore disabledFeatures.
+ StringBuilder sb;
+ if (DBG) {
+ sb = new StringBuilder(120);
+ sb.append("handleFeatureCapabilityChanged: ");
+ }
+ for (int i = ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE;
+ i <= ImsConfig.FeatureConstants.FEATURE_TYPE_UT_OVER_WIFI &&
+ i < enabledFeatures.length; i++) {
+ if (enabledFeatures[i] == i) {
+ // If the feature is set to its own integer value it is enabled.
+ if (DBG) {
+ sb.append(mImsFeatureStrings[i]);
+ sb.append(":true ");
+ }
+
+ mImsFeatureEnabled[i] = true;
+ } else if (enabledFeatures[i]
+ == ImsConfig.FeatureConstants.FEATURE_TYPE_UNKNOWN) {
+ // FEATURE_TYPE_UNKNOWN indicates that a feature is disabled.
+ if (DBG) {
+ sb.append(mImsFeatureStrings[i]);
+ sb.append(":false ");
+ }
+
+ mImsFeatureEnabled[i] = false;
+ } else {
+ // Feature has unknown state; it is not its own value or -1.
+ if (DBG) {
+ loge("handleFeatureCapabilityChanged(" + i + ", " + mImsFeatureStrings[i]
+ + "): unexpectedValue=" + enabledFeatures[i]);
+ }
+ }
+ }
+ boolean isVideoEnabled = isVideoCallEnabled();
+ boolean isVideoEnabledStatechanged = tmpIsVideoCallEnabled != isVideoEnabled;
+ if (DBG) {
+ sb.append(" isVideoEnabledStateChanged=");
+ sb.append(isVideoEnabledStatechanged);
+ }
+
+ if (isVideoEnabledStatechanged) {
+ log("handleFeatureCapabilityChanged - notifyForVideoCapabilityChanged=" +
+ isVideoEnabled);
+ mPhone.notifyForVideoCapabilityChanged(isVideoEnabled);
+ }
+
+ if (DBG) {
+ log(sb.toString());
+ }
+
+ if (DBG) log("handleFeatureCapabilityChanged: isVolteEnabled=" + isVolteEnabled()
+ + ", isVideoCallEnabled=" + isVideoCallEnabled()
+ + ", isVowifiEnabled=" + isVowifiEnabled()
+ + ", isUtEnabled=" + isUtEnabled());
+
+ mPhone.onFeatureCapabilityChanged();
+
+ mMetrics.writeOnImsCapabilities(
+ mPhone.getPhoneId(), mImsFeatureEnabled);
+ }
+ }
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
index 853b937..60a50b9 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneCommandInterface.java
@@ -20,6 +20,8 @@
import android.os.Handler;
import android.os.Message;
import android.service.carrier.CarrierIdentifier;
+import android.telephony.ImsiEncryptionInfo;
+import android.telephony.NetworkScanRequest;
import com.android.internal.telephony.BaseCommands;
import com.android.internal.telephony.CommandsInterface;
@@ -29,7 +31,6 @@
import com.android.internal.telephony.dataconnection.DataProfile;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
-import java.security.PublicKey;
import java.util.List;
/**
@@ -334,6 +335,14 @@
}
@Override
+ public void startNetworkScan(NetworkScanRequest nsr, Message response) {
+ }
+
+ @Override
+ public void stopNetworkScan(Message response) {
+ }
+
+ @Override
public void setCallForward(int action, int cfReason, int serviceClass,
String number, int timeSeconds, Message response) {
}
@@ -616,7 +625,7 @@
}
@Override
- public void setCarrierInfoForImsiEncryption(PublicKey publicKey, String keyIdentifier,
+ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo,
Message result) {
}
@@ -637,6 +646,6 @@
}
@Override
- public void setSimCardPower(boolean powerUp, Message result) {
+ public void setSimCardPower(int state, Message result) {
}
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
index dae275f..0ad81d2 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneConnection.java
@@ -107,6 +107,14 @@
private ImsRttTextHandler mRttTextHandler;
private android.telecom.Connection.RttTextStream mRttTextStream;
+ /**
+ * Used as an override to determine whether video is locally available for this call.
+ * This allows video availability to be overridden in the case that the modem says video is
+ * currently available, but mobile data is off and the carrier is metering data for video
+ * calls.
+ */
+ private boolean mIsVideoEnabled = true;
+
//***** Event Constants
private static final int EVENT_DTMF_DONE = 1;
private static final int EVENT_PAUSE_DONE = 2;
@@ -242,11 +250,15 @@
return (a == null) ? (b == null) : (b != null && a.startsWith (b));
}
- private static int applyLocalCallCapabilities(ImsCallProfile localProfile, int capabilities) {
- Rlog.w(LOG_TAG, "applyLocalCallCapabilities - localProfile = "+localProfile);
+ private int applyLocalCallCapabilities(ImsCallProfile localProfile, int capabilities) {
+ Rlog.i(LOG_TAG, "applyLocalCallCapabilities - localProfile = " + localProfile);
capabilities = removeCapability(capabilities,
Connection.Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL);
+ if (!mIsVideoEnabled) {
+ Rlog.i(LOG_TAG, "applyLocalCallCapabilities - disabling video (overidden)");
+ return capabilities;
+ }
switch (localProfile.mCallType) {
case ImsCallProfile.CALL_TYPE_VT:
// Fall-through
@@ -418,8 +430,10 @@
} else {
Rlog.d(LOG_TAG, "onDisconnect: no parent");
}
- if (mImsCall != null) mImsCall.close();
- mImsCall = null;
+ synchronized (this) {
+ if (mImsCall != null) mImsCall.close();
+ mImsCall = null;
+ }
}
releaseWakeLock();
return changed;
@@ -616,7 +630,7 @@
}
@Override
- public boolean isMultiparty() {
+ public synchronized boolean isMultiparty() {
return mImsCall != null && mImsCall.isMultiparty();
}
@@ -629,11 +643,8 @@
* {@code false} otherwise.
*/
@Override
- public boolean isConferenceHost() {
- if (mImsCall == null) {
- return false;
- }
- return mImsCall.isConferenceHost();
+ public synchronized boolean isConferenceHost() {
+ return mImsCall != null && mImsCall.isConferenceHost();
}
@Override
@@ -641,11 +652,11 @@
return !isConferenceHost();
}
- public ImsCall getImsCall() {
+ public synchronized ImsCall getImsCall() {
return mImsCall;
}
- public void setImsCall(ImsCall imsCall) {
+ public synchronized void setImsCall(ImsCall imsCall) {
mImsCall = imsCall;
}
@@ -829,7 +840,7 @@
}
if (!mShouldIgnoreVideoStateChanges) {
- setVideoState(newVideoState);
+ updateVideoState(newVideoState);
changed = true;
} else {
Rlog.d(LOG_TAG, "updateMediaCapabilities - ignoring video state change " +
@@ -892,6 +903,13 @@
return changed;
}
+ private void updateVideoState(int newVideoState) {
+ if (mImsVideoCallProviderWrapper != null) {
+ mImsVideoCallProviderWrapper.onVideoStateChanged(newVideoState);
+ }
+ setVideoState(newVideoState);
+ }
+
public void sendRttModifyRequest(android.telecom.Connection.RttTextStream textStream) {
getImsCall().sendRttModifyRequest();
setCurrentRttTextStream(textStream);
@@ -1060,10 +1078,12 @@
sb.append(" address: ");
sb.append(Rlog.pii(LOG_TAG, getAddress()));
sb.append(" ImsCall: ");
- if (mImsCall == null) {
- sb.append("null");
- } else {
- sb.append(mImsCall);
+ synchronized (this) {
+ if (mImsCall == null) {
+ sb.append("null");
+ } else {
+ sb.append(mImsCall);
+ }
}
sb.append("]");
return sb.toString();
@@ -1171,4 +1191,31 @@
return mImsVideoCallProviderWrapper.wasVideoPausedFromSource(source);
}
+
+ public void changeToPausedState() {
+ int newVideoState = getVideoState() | VideoProfile.STATE_PAUSED;
+ Rlog.i(LOG_TAG, "ImsPhoneConnection: changeToPausedState - setting paused bit; "
+ + "newVideoState=" + VideoProfile.videoStateToString(newVideoState));
+ updateVideoState(newVideoState);
+ mShouldIgnoreVideoStateChanges = true;
+ }
+
+ public void changeToUnPausedState() {
+ int newVideoState = getVideoState() & ~VideoProfile.STATE_PAUSED;
+ Rlog.i(LOG_TAG, "ImsPhoneConnection: changeToUnPausedState - unsetting paused bit; "
+ + "newVideoState=" + VideoProfile.videoStateToString(newVideoState));
+ updateVideoState(newVideoState);
+ mShouldIgnoreVideoStateChanges = false;
+ }
+
+ public void handleDataEnabledChange(boolean isDataEnabled) {
+ mIsVideoEnabled = isDataEnabled;
+ Rlog.i(LOG_TAG, "handleDataEnabledChange: isDataEnabled=" + isDataEnabled
+ + "; updating local video availability.");
+ updateMediaCapabilities(getImsCall());
+ if (mImsVideoCallProviderWrapper != null) {
+ mImsVideoCallProviderWrapper.setIsVideoEnabled(
+ hasCapabilities(Connection.Capability.SUPPORTS_VT_LOCAL_BIDIRECTIONAL));
+ }
+ }
}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
index 2387fb1..b1013b1 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java
@@ -756,14 +756,14 @@
processCode () throws CallStateException {
try {
if (isShortCode()) {
- Rlog.d(LOG_TAG, "isShortCode");
+ Rlog.d(LOG_TAG, "processCode: isShortCode");
// These just get treated as USSD.
- Rlog.d(LOG_TAG, "Sending short code '"
+ Rlog.d(LOG_TAG, "processCode: Sending short code '"
+ mDialingNumber + "' over CS pipe.");
throw new CallStateException(Phone.CS_FALLBACK);
} else if (isServiceCodeCallForwarding(mSc)) {
- Rlog.d(LOG_TAG, "is CF");
+ Rlog.d(LOG_TAG, "processCode: is CF");
String dialingNumber = mSia;
int reason = scToCallForwardReason(mSc);
@@ -806,7 +806,7 @@
((cfAction == CommandsInterface.CF_ACTION_ENABLE) ||
(cfAction == CommandsInterface.CF_ACTION_REGISTRATION)) ? 1 : 0;
- Rlog.d(LOG_TAG, "is CF setCallForward");
+ Rlog.d(LOG_TAG, "processCode: is CF setCallForward");
mPhone.setCallForwardingOption(cfAction, reason,
dialingNumber, serviceClass, time, obtainMessage(
EVENT_SET_CFF_COMPLETE,
@@ -839,21 +839,21 @@
mPhone.mCT.getUtInterface().updateCLIR(CommandsInterface.CLIR_INVOCATION,
obtainMessage(EVENT_SET_COMPLETE, this));
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for updateCLIR.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for updateCLIR.");
}
} else if (isDeactivate()) {
try {
mPhone.mCT.getUtInterface().updateCLIR(CommandsInterface.CLIR_SUPPRESSION,
obtainMessage(EVENT_SET_COMPLETE, this));
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for updateCLIR.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for updateCLIR.");
}
} else if (isInterrogate()) {
try {
mPhone.mCT.getUtInterface()
.queryCLIR(obtainMessage(EVENT_GET_CLIR_COMPLETE, this));
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for queryCLIR.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for queryCLIR.");
}
} else {
throw new RuntimeException ("Invalid or Unsupported MMI Code");
@@ -865,14 +865,14 @@
mPhone.mCT.getUtInterface()
.queryCLIP(obtainMessage(EVENT_SUPP_SVC_QUERY_COMPLETE, this));
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for queryCLIP.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for queryCLIP.");
}
} else if (isActivate() || isDeactivate()) {
try {
mPhone.mCT.getUtInterface().updateCLIP(isActivate(),
obtainMessage(EVENT_SET_COMPLETE, this));
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for updateCLIP.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for updateCLIP.");
}
} else {
throw new RuntimeException ("Invalid or Unsupported MMI Code");
@@ -884,14 +884,14 @@
mPhone.mCT.getUtInterface()
.queryCOLP(obtainMessage(EVENT_SUPP_SVC_QUERY_COMPLETE, this));
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for queryCOLP.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for queryCOLP.");
}
} else if (isActivate() || isDeactivate()) {
try {
mPhone.mCT.getUtInterface().updateCOLP(isActivate(),
obtainMessage(EVENT_SET_COMPLETE, this));
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for updateCOLP.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for updateCOLP.");
}
} else {
throw new RuntimeException ("Invalid or Unsupported MMI Code");
@@ -903,21 +903,21 @@
mPhone.mCT.getUtInterface().updateCOLR(NUM_PRESENTATION_RESTRICTED,
obtainMessage(EVENT_SET_COMPLETE, this));
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for updateCOLR.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for updateCOLR.");
}
} else if (isDeactivate()) {
try {
mPhone.mCT.getUtInterface().updateCOLR(NUM_PRESENTATION_ALLOWED,
obtainMessage(EVENT_SET_COMPLETE, this));
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for updateCOLR.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for updateCOLR.");
}
} else if (isInterrogate()) {
try {
mPhone.mCT.getUtInterface()
.queryCOLR(obtainMessage(EVENT_SUPP_SVC_QUERY_COMPLETE, this));
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for queryCOLR.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for queryCOLR.");
}
} else {
throw new RuntimeException ("Invalid or Unsupported MMI Code");
@@ -933,7 +933,7 @@
}
// TODO: isRegister() case needs to be handled.
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for ICB.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for ICB.");
}
} else if (mSc != null && mSc.equals(SC_BAICa)) {
int callAction =0;
@@ -956,7 +956,7 @@
null);
}
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for ICBa.");
+ Rlog.d(LOG_TAG, "processCode: Could not get UT handle for ICBa.");
}
} else if (mSc != null && mSc.equals(SC_WAIT)) {
// sia = basic service group
@@ -971,15 +971,17 @@
throw new RuntimeException ("Invalid or Unsupported MMI Code");
}
} else if (mPoundString != null) {
- Rlog.d(LOG_TAG, "Sending pound string '"
+ Rlog.d(LOG_TAG, "processCode: Sending pound string '"
+ mDialingNumber + "' over CS pipe.");
throw new CallStateException(Phone.CS_FALLBACK);
} else {
+ Rlog.d(LOG_TAG, "processCode: invalid or unsupported MMI");
throw new RuntimeException ("Invalid or Unsupported MMI Code");
}
} catch (RuntimeException exc) {
mState = State.FAILED;
mMessage = mContext.getText(com.android.internal.R.string.mmiError);
+ Rlog.d(LOG_TAG, "processCode: RuntimeException = " + exc);
mPhone.onMMIDone(this);
}
}
@@ -996,9 +998,11 @@
void
onUssdFinished(String ussdMessage, boolean isUssdRequest) {
if (mState == State.PENDING) {
- if (ussdMessage == null) {
+ if (TextUtils.isEmpty(ussdMessage)) {
mMessage = mContext.getText(com.android.internal.R.string.mmiComplete);
+ Rlog.v(LOG_TAG, "onUssdFinished: no message; using: " + mMessage);
} else {
+ Rlog.v(LOG_TAG, "onUssdFinished: message: " + ussdMessage);
mMessage = ussdMessage;
}
mIsUssdRequest = isUssdRequest;
@@ -1006,7 +1010,6 @@
if (!isUssdRequest) {
mState = State.COMPLETE;
}
-
mPhone.onMMIDone(this);
}
}
@@ -1022,7 +1025,7 @@
if (mState == State.PENDING) {
mState = State.FAILED;
mMessage = mContext.getText(com.android.internal.R.string.mmiError);
-
+ Rlog.d(LOG_TAG, "onUssdFinishedError: mmi=" + this);
mPhone.onMMIDone(this);
}
}
@@ -1140,7 +1143,7 @@
obtainMessage(EVENT_SET_COMPLETE,this),
icbNum);
} catch (ImsException e) {
- Rlog.d(LOG_TAG, "Could not get UT handle for updating ICB.");
+ Rlog.d(LOG_TAG, "processIcbMmiCodeForUpdate:Could not get UT handle for updating ICB.");
}
}
@@ -1230,6 +1233,7 @@
}
mMessage = sb;
+ Rlog.d(LOG_TAG, "onSetComplete: mmi=" + this);
mPhone.onMMIDone(this);
}
@@ -1384,6 +1388,7 @@
}
mMessage = sb;
+ Rlog.d(LOG_TAG, "onQueryCfComplete: mmi=" + this);
mPhone.onMMIDone(this);
}
@@ -1409,12 +1414,13 @@
mState = State.FAILED;
ImsSsInfo ssInfo = null;
if (ar.result instanceof Bundle) {
- Rlog.d(LOG_TAG, "Received CLIP/COLP/COLR Response.");
+ Rlog.d(LOG_TAG, "onSuppSvcQueryComplete: Received CLIP/COLP/COLR Response.");
// Response for CLIP, COLP and COLR queries.
Bundle ssInfoResp = (Bundle) ar.result;
ssInfo = (ImsSsInfo) ssInfoResp.getParcelable(UT_BUNDLE_KEY_SSINFO);
if (ssInfo != null) {
- Rlog.d(LOG_TAG, "ImsSsInfo mStatus = " + ssInfo.mStatus);
+ Rlog.d(LOG_TAG,
+ "onSuppSvcQueryComplete: ImsSsInfo mStatus = " + ssInfo.mStatus);
if (ssInfo.mStatus == ImsSsInfo.DISABLED) {
sb.append(mContext.getText(com.android.internal.R.string.serviceDisabled));
mState = State.COMPLETE;
@@ -1429,7 +1435,7 @@
}
} else {
- Rlog.d(LOG_TAG, "Received Call Barring Response.");
+ Rlog.d(LOG_TAG, "onSuppSvcQueryComplete: Received Call Barring Response.");
// Response for Call Barring queries.
int[] cbInfos = (int[]) ar.result;
if (cbInfos[0] == 1) {
@@ -1443,11 +1449,12 @@
}
mMessage = sb;
+ Rlog.d(LOG_TAG, "onSuppSvcQueryComplete mmi=" + this);
mPhone.onMMIDone(this);
}
private void onIcbQueryComplete(AsyncResult ar) {
- Rlog.d(LOG_TAG, "onIcbQueryComplete ");
+ Rlog.d(LOG_TAG, "onIcbQueryComplete mmi=" + this);
StringBuilder sb = new StringBuilder(getScString());
sb.append("\n");
@@ -1508,7 +1515,7 @@
int[] clirInfo = ssInfo.getIntArray(UT_BUNDLE_KEY_CLIR);
// clirInfo[0] = The 'n' parameter from TS 27.007 7.7
// clirInfo[1] = The 'm' parameter from TS 27.007 7.7
- Rlog.d(LOG_TAG, "CLIR param n=" + clirInfo[0]
+ Rlog.d(LOG_TAG, "onQueryClirComplete: CLIR param n=" + clirInfo[0]
+ " m=" + clirInfo[1]);
// 'm' parameter.
@@ -1579,6 +1586,7 @@
}
mMessage = sb;
+ Rlog.d(LOG_TAG, "onQueryClirComplete mmi=" + this);
mPhone.onMMIDone(this);
}
@@ -1623,6 +1631,7 @@
}
mMessage = sb;
+ Rlog.d(LOG_TAG, "onQueryComplete mmi=" + this);
mPhone.onMMIDone(this);
}
@@ -1665,9 +1674,11 @@
if (mSia != null) sb.append(" sia=" + mSia);
if (mSib != null) sb.append(" sib=" + mSib);
if (mSic != null) sb.append(" sic=" + mSic);
- if (mPoundString != null) sb.append(" poundString=" + mPoundString);
- if (mDialingNumber != null) sb.append(" dialingNumber=" + mDialingNumber);
- if (mPwd != null) sb.append(" pwd=" + mPwd);
+ if (mPoundString != null) sb.append(" poundString=" + Rlog.pii(LOG_TAG, mPoundString));
+ if (mDialingNumber != null) sb.append(" dialingNumber="
+ + Rlog.pii(LOG_TAG, mDialingNumber));
+ if (mPwd != null) sb.append(" pwd=" + Rlog.pii(LOG_TAG, mPwd));
+ if (mCallbackReceiver != null) sb.append(" hasReceiver");
sb.append("}");
return sb.toString();
}
diff --git a/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java b/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java
index 42d38a4..a8221b4 100644
--- a/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java
+++ b/src/java/com/android/internal/telephony/metrics/CallSessionEventBuilder.java
@@ -16,14 +16,14 @@
package com.android.internal.telephony.metrics;
-import com.android.internal.telephony.TelephonyProto.ImsCapabilities;
-import com.android.internal.telephony.TelephonyProto.ImsConnectionState;
-import com.android.internal.telephony.TelephonyProto.ImsReasonInfo;
-import com.android.internal.telephony.TelephonyProto.RilDataCall;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.RilCall;
-import com.android.internal.telephony.TelephonyProto.TelephonyServiceState;
-import com.android.internal.telephony.TelephonyProto.TelephonySettings;
+import com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities;
+import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
+import com.android.internal.telephony.nano.TelephonyProto.ImsReasonInfo;
+import com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.RilCall;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonySettings;
public class CallSessionEventBuilder {
private final TelephonyCallSession.Event mEvent = new TelephonyCallSession.Event();
@@ -33,46 +33,46 @@
}
public CallSessionEventBuilder(int type) {
- mEvent.setType(type);
+ mEvent.type = type;
}
public CallSessionEventBuilder setDelay(int delay) {
- mEvent.setDelay(delay);
+ mEvent.delay = delay;
return this;
}
public CallSessionEventBuilder setRilRequest(int rilRequestType) {
- mEvent.setRilRequest(rilRequestType);
+ mEvent.rilRequest = rilRequestType;
return this;
}
public CallSessionEventBuilder setRilRequestId(int rilRequestId) {
- mEvent.setRilRequestId(rilRequestId);
+ mEvent.rilRequestId = rilRequestId;
return this;
}
public CallSessionEventBuilder setRilError(int rilError) {
- mEvent.setError(rilError);
+ mEvent.error = rilError;
return this;
}
public CallSessionEventBuilder setCallIndex(int callIndex) {
- mEvent.setCallIndex(callIndex);
+ mEvent.callIndex = callIndex;
return this;
}
public CallSessionEventBuilder setCallState(int state) {
- mEvent.setCallState(state);
+ mEvent.callState = state;
return this;
}
public CallSessionEventBuilder setSrvccState(int srvccState) {
- mEvent.setSrvccState(srvccState);
+ mEvent.srvccState = srvccState;
return this;
}
public CallSessionEventBuilder setImsCommand(int imsCommand) {
- mEvent.setImsCommand(imsCommand);
+ mEvent.imsCommand = imsCommand;
return this;
}
@@ -82,12 +82,12 @@
}
public CallSessionEventBuilder setSrcAccessTech(int tech) {
- mEvent.setSrcAccessTech(tech);
+ mEvent.srcAccessTech = tech;
return this;
}
public CallSessionEventBuilder setTargetAccessTech(int tech) {
- mEvent.setTargetAccessTech(tech);
+ mEvent.targetAccessTech = tech;
return this;
}
@@ -117,12 +117,12 @@
}
public CallSessionEventBuilder setPhoneState(int phoneState) {
- mEvent.setPhoneState(phoneState);
+ mEvent.phoneState = phoneState;
return this;
}
public CallSessionEventBuilder setNITZ(long timestamp) {
- mEvent.setNitzTimestampMillis(timestamp);
+ mEvent.nitzTimestampMillis = timestamp;
return this;
}
diff --git a/src/java/com/android/internal/telephony/metrics/InProgressCallSession.java b/src/java/com/android/internal/telephony/metrics/InProgressCallSession.java
index 49a7ee4..748fe7d 100644
--- a/src/java/com/android/internal/telephony/metrics/InProgressCallSession.java
+++ b/src/java/com/android/internal/telephony/metrics/InProgressCallSession.java
@@ -18,7 +18,7 @@
import android.os.SystemClock;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
import java.util.ArrayDeque;
import java.util.Deque;
@@ -47,6 +47,9 @@
/** Indicating events dropped */
private boolean mEventsDropped = false;
+ /** Last known phone state */
+ private int mLastKnownPhoneState;
+
/** Check if events dropped */
public boolean isEventsDropped() { return mEventsDropped; }
@@ -91,4 +94,34 @@
events.add(builder.build());
mLastElapsedTimeMs = timestamp;
}
-}
\ No newline at end of file
+
+ /**
+ * Check if the Call Session contains CS calls
+ * @return true if there are CS calls in the call list
+ */
+ public boolean containsCsCalls() {
+ for (TelephonyCallSession.Event event : events) {
+ if (event.type == TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Set Phone State
+ * @param state
+ */
+ public void setLastKnownPhoneState(int state) {
+ mLastKnownPhoneState = state;
+ }
+
+ /**
+ * Checks if Phone is in Idle state
+ * @return true if device is in Phone is idle state.
+ *
+ */
+ public boolean isPhoneIdle() {
+ return (mLastKnownPhoneState == TelephonyCallSession.Event.PhoneState.STATE_IDLE);
+ }
+}
diff --git a/src/java/com/android/internal/telephony/metrics/InProgressSmsSession.java b/src/java/com/android/internal/telephony/metrics/InProgressSmsSession.java
index 4a01161..9da6536 100644
--- a/src/java/com/android/internal/telephony/metrics/InProgressSmsSession.java
+++ b/src/java/com/android/internal/telephony/metrics/InProgressSmsSession.java
@@ -18,7 +18,7 @@
import android.os.SystemClock;
-import com.android.internal.telephony.TelephonyProto.SmsSession;
+import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
import java.util.ArrayDeque;
import java.util.Deque;
diff --git a/src/java/com/android/internal/telephony/metrics/SmsSessionEventBuilder.java b/src/java/com/android/internal/telephony/metrics/SmsSessionEventBuilder.java
index aeaac19..530be1d 100644
--- a/src/java/com/android/internal/telephony/metrics/SmsSessionEventBuilder.java
+++ b/src/java/com/android/internal/telephony/metrics/SmsSessionEventBuilder.java
@@ -16,12 +16,12 @@
package com.android.internal.telephony.metrics;
-import com.android.internal.telephony.TelephonyProto.ImsCapabilities;
-import com.android.internal.telephony.TelephonyProto.ImsConnectionState;
-import com.android.internal.telephony.TelephonyProto.RilDataCall;
-import com.android.internal.telephony.TelephonyProto.SmsSession;
-import com.android.internal.telephony.TelephonyProto.TelephonyServiceState;
-import com.android.internal.telephony.TelephonyProto.TelephonySettings;
+import com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities;
+import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
+import com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
+import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonySettings;
public class SmsSessionEventBuilder {
SmsSession.Event mEvent = new SmsSession.Event();
@@ -31,26 +31,26 @@
}
public SmsSessionEventBuilder(int type) {
- mEvent.setType(type);
+ mEvent.type = type;
}
public SmsSessionEventBuilder setDelay(int delay) {
- mEvent.setDelay(delay);
+ mEvent.delay = delay;
return this;
}
public SmsSessionEventBuilder setTech(int tech) {
- mEvent.setTech(tech);
+ mEvent.tech = tech;
return this;
}
public SmsSessionEventBuilder setErrorCode(int code) {
- mEvent.setErrorCode(code);
+ mEvent.errorCode = code;
return this;
}
public SmsSessionEventBuilder setRilErrno(int errno) {
- mEvent.setError(errno);
+ mEvent.error = errno;
return this;
}
@@ -80,12 +80,12 @@
}
public SmsSessionEventBuilder setRilRequestId(int id) {
- mEvent.setRilRequestId(id);
+ mEvent.rilRequestId = id;
return this;
}
public SmsSessionEventBuilder setFormat(int format) {
- mEvent.setFormat(format);
+ mEvent.format = format;
return this;
}
}
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
index 16dbb83..6530802 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyEventBuilder.java
@@ -16,17 +16,18 @@
package com.android.internal.telephony.metrics;
-import android.os.SystemClock;
+import static com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities;
+import static com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
+import static com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
+import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
+import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart;
+import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
+import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCall;
+import static com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse;
+import static com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState;
+import static com.android.internal.telephony.nano.TelephonyProto.TelephonySettings;
-import static com.android.internal.telephony.TelephonyProto.ImsCapabilities;
-import static com.android.internal.telephony.TelephonyProto.ImsConnectionState;
-import static com.android.internal.telephony.TelephonyProto.RilDataCall;
-import static com.android.internal.telephony.TelephonyProto.TelephonyEvent;
-import static com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
-import static com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilSetupDataCall;
-import static com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse;
-import static com.android.internal.telephony.TelephonyProto.TelephonyServiceState;
-import static com.android.internal.telephony.TelephonyProto.TelephonySettings;
+import android.os.SystemClock;
public class TelephonyEventBuilder {
private final TelephonyEvent mEvent = new TelephonyEvent();
@@ -40,73 +41,79 @@
}
public TelephonyEventBuilder(long timestamp, int phoneId) {
- mEvent.setTimestampMillis(timestamp);
- mEvent.setPhoneId(phoneId);
+ mEvent.timestampMillis = timestamp;
+ mEvent.phoneId = phoneId;
}
public TelephonyEventBuilder setSettings(TelephonySettings settings) {
- mEvent.setType(TelephonyEvent.Type.SETTINGS_CHANGED);
+ mEvent.type = TelephonyEvent.Type.SETTINGS_CHANGED;
mEvent.settings = settings;
return this;
}
public TelephonyEventBuilder setServiceState(TelephonyServiceState state) {
- mEvent.setType(TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED);
+ mEvent.type = TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED;
mEvent.serviceState = state;
return this;
}
public TelephonyEventBuilder setImsConnectionState(ImsConnectionState state) {
- mEvent.setType(TelephonyEvent.Type.IMS_CONNECTION_STATE_CHANGED);
+ mEvent.type = TelephonyEvent.Type.IMS_CONNECTION_STATE_CHANGED;
mEvent.imsConnectionState = state;
return this;
}
public TelephonyEventBuilder setImsCapabilities(ImsCapabilities capabilities) {
- mEvent.setType(TelephonyEvent.Type.IMS_CAPABILITIES_CHANGED);
+ mEvent.type = TelephonyEvent.Type.IMS_CAPABILITIES_CHANGED;
mEvent.imsCapabilities = capabilities;
return this;
}
public TelephonyEventBuilder setDataStallRecoveryAction(int action) {
- mEvent.setType(TelephonyEvent.Type.DATA_STALL_ACTION);
- mEvent.setDataStallAction(action);
+ mEvent.type = TelephonyEvent.Type.DATA_STALL_ACTION;
+ mEvent.dataStallAction = action;
return this;
}
public TelephonyEventBuilder setSetupDataCall(RilSetupDataCall request) {
- mEvent.setType(TelephonyEvent.Type.DATA_CALL_SETUP);
+ mEvent.type = TelephonyEvent.Type.DATA_CALL_SETUP;
mEvent.setupDataCall = request;
return this;
}
public TelephonyEventBuilder setSetupDataCallResponse(RilSetupDataCallResponse rsp) {
- mEvent.setType(TelephonyEvent.Type.DATA_CALL_SETUP_RESPONSE);
+ mEvent.type = TelephonyEvent.Type.DATA_CALL_SETUP_RESPONSE;
mEvent.setupDataCallResponse = rsp;
return this;
}
public TelephonyEventBuilder setDeactivateDataCall(RilDeactivateDataCall request) {
- mEvent.setType(TelephonyEvent.Type.DATA_CALL_DEACTIVATE);
+ mEvent.type = TelephonyEvent.Type.DATA_CALL_DEACTIVATE;
mEvent.deactivateDataCall = request;
return this;
}
public TelephonyEventBuilder setDeactivateDataCallResponse(int errno) {
- mEvent.setType(TelephonyEvent.Type.DATA_CALL_DEACTIVATE_RESPONSE);
- mEvent.setError(errno);
+ mEvent.type = TelephonyEvent.Type.DATA_CALL_DEACTIVATE_RESPONSE;
+ mEvent.error = errno;
return this;
}
public TelephonyEventBuilder setDataCalls(RilDataCall[] dataCalls) {
- mEvent.setType(TelephonyEvent.Type.DATA_CALL_LIST_CHANGED);
+ mEvent.type = TelephonyEvent.Type.DATA_CALL_LIST_CHANGED;
mEvent.dataCalls = dataCalls;
return this;
}
public TelephonyEventBuilder setNITZ(long timestamp) {
- mEvent.setType(TelephonyEvent.Type.NITZ_TIME);
- mEvent.setNitzTimestampMillis(timestamp);
+ mEvent.type = TelephonyEvent.Type.NITZ_TIME;
+ mEvent.nitzTimestampMillis = timestamp;
+ return this;
+ }
+
+ public TelephonyEventBuilder setModemRestart(ModemRestart modemRestart) {
+ mEvent.type = TelephonyEvent.Type.MODEM_RESTART;
+ mEvent.modemRestart = modemRestart;
return this;
}
}
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index eddb1c0..4c642c0 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -16,53 +16,6 @@
package com.android.internal.telephony.metrics;
-import android.os.SystemClock;
-import android.telephony.Rlog;
-import android.telephony.ServiceState;
-import android.telephony.TelephonyHistogram;
-import android.util.Base64;
-import android.util.Log;
-import android.util.SparseArray;
-
-import com.android.ims.ImsConfig;
-import com.android.ims.ImsReasonInfo;
-import com.android.ims.internal.ImsCallSession;
-import com.android.internal.telephony.Call;
-import com.android.internal.telephony.GsmCdmaConnection;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.RIL;
-import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.SmsResponse;
-import com.android.internal.telephony.TelephonyProto;
-import com.android.internal.telephony.TelephonyProto.ImsCapabilities;
-import com.android.internal.telephony.TelephonyProto.ImsConnectionState;
-import com.android.internal.telephony.TelephonyProto.RilDataCall;
-import com.android.internal.telephony.TelephonyProto.SmsSession;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.RilCall;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.RilCall.Type.*;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.CallState.*;
-import com.android.internal.telephony.TelephonyProto.TelephonyEvent;
-import com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
-import com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilSetupDataCall;
-import com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse;
-import com.android.internal.telephony.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse.RilDataCallFailCause;
-import com.android.internal.telephony.TelephonyProto.TelephonyLog;
-import com.android.internal.telephony.TelephonyProto.TelephonyServiceState;
-import com.android.internal.telephony.TelephonyProto.TelephonySettings;
-import com.android.internal.telephony.TelephonyProto.TimeInterval;
-import com.android.internal.telephony.UUSInfo;
-import com.android.internal.telephony.dataconnection.DataCallResponse;
-import com.android.internal.telephony.imsphone.ImsPhoneCall;
-import com.android.internal.util.IndentingPrintWriter;
-
-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 static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_ANSWER;
@@ -70,17 +23,68 @@
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE_DATA_CALL;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DIAL;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP;
-import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND;
+import static com.android.internal.telephony.RILConstants
+ .RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IMS_SEND_SMS;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_IP;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_IPV6;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_PPP;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_UNKNOWN;
+import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IP;
+import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;
+import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV6;
+import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_PPP;
+import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_UNKNOWN;
+
+import android.os.Build;
+import android.os.SystemClock;
+import android.telephony.Rlog;
+import android.telephony.ServiceState;
+import android.telephony.TelephonyHistogram;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.SparseArray;
+
+import com.android.ims.ImsConfig;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.internal.ImsCallSession;
+import com.android.internal.telephony.GsmCdmaConnection;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.RIL;
+import com.android.internal.telephony.RILConstants;
+import com.android.internal.telephony.SmsResponse;
+import com.android.internal.telephony.UUSInfo;
+import com.android.internal.telephony.dataconnection.DataCallResponse;
+import com.android.internal.telephony.imsphone.ImsPhoneCall;
+import com.android.internal.telephony.nano.TelephonyProto;
+import com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities;
+import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
+import com.android.internal.telephony.nano.TelephonyProto.RilDataCall;
+import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.CallState;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.RilCall;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.RilCall.Type;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.ModemRestart;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilDeactivateDataCall;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCall;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent.RilSetupDataCallResponse
+ .RilDataCallFailCause;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyLog;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonySettings;
+import com.android.internal.telephony.nano.TelephonyProto.TimeInterval;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.List;
/**
* Telephony metrics holds all metrics events and convert it into telephony proto buf.
@@ -142,6 +146,11 @@
*/
private final SparseArray<ImsConnectionState> mLastImsConnectionState = new SparseArray<>();
+ /**
+ * Last settings state. This is for deduping same settings event logged.
+ */
+ private final SparseArray<TelephonySettings> mLastSettings = new SparseArray<>();
+
/** The start system time of the TelephonyLog in milliseconds*/
private long mStartSystemTimeMs;
@@ -326,23 +335,20 @@
pw.println("Telephony events:");
pw.increaseIndent();
for (TelephonyEvent event : mTelephonyEvents) {
- if (event.hasTimestampMillis()) {
- pw.print(event.getTimestampMillis());
- pw.print(" [");
- if (event.hasPhoneId()) pw.print(event.getPhoneId());
- pw.print("] ");
+ pw.print(event.timestampMillis);
+ pw.print(" [");
+ pw.print(event.phoneId);
+ pw.print("] ");
- if (event.hasType()) {
- pw.print("T=");
- if (event.getType() == TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED) {
- pw.print(telephonyEventToString(event.getType())
- + "(" + event.serviceState.getDataRat() + ")");
- } else {
- pw.print(telephonyEventToString(event.getType()));
- }
- }
- pw.println("");
+ pw.print("T=");
+ if (event.type == TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED) {
+ pw.print(telephonyEventToString(event.type)
+ + "(" + event.serviceState.dataRat + ")");
+ } else {
+ pw.print(telephonyEventToString(event.type));
}
+
+ pw.println("");
}
pw.decreaseIndent();
@@ -350,22 +356,28 @@
pw.increaseIndent();
for (TelephonyCallSession callSession : mCompletedCallSessions) {
- if (callSession.hasStartTimeMinutes()) {
- pw.println("Start time in minutes: " + callSession.getStartTimeMinutes());
- }
- if (callSession.hasEventsDropped()) {
- pw.println("Events dropped: " + callSession.getEventsDropped());
- }
+ pw.println("Start time in minutes: " + callSession.startTimeMinutes);
+ pw.println("Events dropped: " + callSession.eventsDropped);
+
pw.println("Events: ");
pw.increaseIndent();
for (TelephonyCallSession.Event event : callSession.events) {
- pw.print(event.getDelay());
+ pw.print(event.delay);
pw.print(" T=");
- if (event.getType() == TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED) {
- pw.println(callSessionEventToString(event.getType())
- + "(" + event.serviceState.getDataRat() + ")");
+ if (event.type == TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED) {
+ pw.println(callSessionEventToString(event.type)
+ + "(" + event.serviceState.dataRat + ")");
+ } else if (event.type == TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED) {
+ pw.println(callSessionEventToString(event.type));
+ pw.increaseIndent();
+ for (RilCall call : event.calls) {
+ pw.println(call.index + ". Type = " + call.type + " State = "
+ + call.state + " End Reason " + call.callEndReason
+ + " isMultiparty = " + call.isMultiparty);
+ }
+ pw.decreaseIndent();
} else {
- pw.println(callSessionEventToString(event.getType()));
+ pw.println(callSessionEventToString(event.type));
}
}
pw.decreaseIndent();
@@ -378,19 +390,18 @@
int count = 0;
for (SmsSession smsSession : mCompletedSmsSessions) {
count++;
- if (smsSession.hasStartTimeMinutes()) {
- pw.print("[" + count + "] Start time in minutes: "
- + smsSession.getStartTimeMinutes());
- }
- if (smsSession.hasEventsDropped()) {
- pw.println(", events dropped: " + smsSession.getEventsDropped());
+ pw.print("[" + count + "] Start time in minutes: "
+ + smsSession.startTimeMinutes);
+
+ if (smsSession.eventsDropped) {
+ pw.println(", events dropped: " + smsSession.eventsDropped);
}
pw.println("Events: ");
pw.increaseIndent();
for (SmsSession.Event event : smsSession.events) {
- pw.print(event.getDelay());
+ pw.print(event.delay);
pw.print(" T=");
- pw.println(smsSessionEventToString(event.getType()));
+ pw.println(smsSessionEventToString(event.type));
}
pw.decreaseIndent();
}
@@ -460,7 +471,7 @@
// Build telephony events
log.events = new TelephonyEvent[mTelephonyEvents.size()];
mTelephonyEvents.toArray(log.events);
- log.setEventsDropped(mTelephonyEventsDropped);
+ log.eventsDropped = mTelephonyEventsDropped;
// Build call sessions
log.callSessions = new TelephonyCallSession[mCompletedCallSessions.size()];
@@ -478,25 +489,25 @@
TelephonyHistogram rilHistogram = rilHistograms.get(i);
TelephonyProto.TelephonyHistogram histogramProto = log.histograms[i];
- histogramProto.setCategory(rilHistogram.getCategory());
- histogramProto.setId(rilHistogram.getId());
- histogramProto.setMinTimeMillis(rilHistogram.getMinTime());
- histogramProto.setMaxTimeMillis(rilHistogram.getMaxTime());
- histogramProto.setAvgTimeMillis(rilHistogram.getAverageTime());
- histogramProto.setCount(rilHistogram.getSampleCount());
- histogramProto.setBucketCount(rilHistogram.getBucketCount());
+ histogramProto.category = rilHistogram.getCategory();
+ histogramProto.id = rilHistogram.getId();
+ histogramProto.minTimeMillis = rilHistogram.getMinTime();
+ histogramProto.maxTimeMillis = rilHistogram.getMaxTime();
+ histogramProto.avgTimeMillis = rilHistogram.getAverageTime();
+ histogramProto.count = rilHistogram.getSampleCount();
+ histogramProto.bucketCount = rilHistogram.getBucketCount();
histogramProto.bucketEndPoints = rilHistogram.getBucketEndPoints();
histogramProto.bucketCounters = rilHistogram.getBucketCounters();
}
// Log the starting system time
log.startTime = new TelephonyProto.Time();
- log.startTime.setSystemTimestampMillis(mStartSystemTimeMs);
- log.startTime.setElapsedTimestampMillis(mStartElapsedTimeMs);
+ log.startTime.systemTimestampMillis = mStartSystemTimeMs;
+ log.startTime.elapsedTimestampMillis = mStartElapsedTimeMs;
log.endTime = new TelephonyProto.Time();
- log.endTime.setSystemTimestampMillis(System.currentTimeMillis());
- log.endTime.setElapsedTimestampMillis(SystemClock.elapsedRealtime());
+ log.endTime.systemTimestampMillis = System.currentTimeMillis();
+ log.endTime.elapsedTimestampMillis = SystemClock.elapsedRealtime();
return log;
}
@@ -573,39 +584,39 @@
private TelephonyServiceState toServiceStateProto(ServiceState serviceState) {
TelephonyServiceState ssProto = new TelephonyServiceState();
- ssProto.setVoiceRoamingType(serviceState.getVoiceRoamingType());
- ssProto.setDataRoamingType(serviceState.getDataRoamingType());
+ ssProto.voiceRoamingType = serviceState.getVoiceRoamingType();
+ ssProto.dataRoamingType = serviceState.getDataRoamingType();
ssProto.voiceOperator = new TelephonyServiceState.TelephonyOperator();
if (serviceState.getVoiceOperatorAlphaLong() != null) {
- ssProto.voiceOperator.setAlphaLong(serviceState.getVoiceOperatorAlphaLong());
+ ssProto.voiceOperator.alphaLong = serviceState.getVoiceOperatorAlphaLong();
}
if (serviceState.getVoiceOperatorAlphaShort() != null) {
- ssProto.voiceOperator.setAlphaShort(serviceState.getVoiceOperatorAlphaShort());
+ ssProto.voiceOperator.alphaShort = serviceState.getVoiceOperatorAlphaShort();
}
if (serviceState.getVoiceOperatorNumeric() != null) {
- ssProto.voiceOperator.setNumeric(serviceState.getVoiceOperatorNumeric());
+ ssProto.voiceOperator.numeric = serviceState.getVoiceOperatorNumeric();
}
ssProto.dataOperator = new TelephonyServiceState.TelephonyOperator();
if (serviceState.getDataOperatorAlphaLong() != null) {
- ssProto.dataOperator.setAlphaLong(serviceState.getDataOperatorAlphaLong());
+ ssProto.dataOperator.alphaLong = serviceState.getDataOperatorAlphaLong();
}
if (serviceState.getDataOperatorAlphaShort() != null) {
- ssProto.dataOperator.setAlphaShort(serviceState.getDataOperatorAlphaShort());
+ ssProto.dataOperator.alphaShort = serviceState.getDataOperatorAlphaShort();
}
if (serviceState.getDataOperatorNumeric() != null) {
- ssProto.dataOperator.setNumeric(serviceState.getDataOperatorNumeric());
+ ssProto.dataOperator.numeric = serviceState.getDataOperatorNumeric();
}
- ssProto.setVoiceRat(serviceState.getRilVoiceRadioTechnology());
- ssProto.setDataRat(serviceState.getRilDataRadioTechnology());
+ ssProto.voiceRat = serviceState.getRilVoiceRadioTechnology();
+ ssProto.dataRat = serviceState.getRilDataRadioTechnology();
return ssProto;
}
@@ -726,9 +737,9 @@
TelephonyCallSession callSession = new TelephonyCallSession();
callSession.events = new TelephonyCallSession.Event[inProgressCallSession.events.size()];
inProgressCallSession.events.toArray(callSession.events);
- callSession.setStartTimeMinutes(inProgressCallSession.startSystemTimeMin);
- callSession.setPhoneId(inProgressCallSession.phoneId);
- callSession.setEventsDropped(inProgressCallSession.isEventsDropped());
+ callSession.startTimeMinutes = inProgressCallSession.startSystemTimeMin;
+ callSession.phoneId = inProgressCallSession.phoneId;
+ callSession.eventsDropped = inProgressCallSession.isEventsDropped();
if (mCompletedCallSessions.size() >= MAX_COMPLETED_CALL_SESSIONS) {
mCompletedCallSessions.removeFirst();
}
@@ -747,9 +758,9 @@
SmsSession smsSession = new SmsSession();
smsSession.events = new SmsSession.Event[inProgressSmsSession.events.size()];
inProgressSmsSession.events.toArray(smsSession.events);
- smsSession.setStartTimeMinutes(inProgressSmsSession.startSystemTimeMin);
- smsSession.setPhoneId(inProgressSmsSession.phoneId);
- smsSession.setEventsDropped(inProgressSmsSession.isEventsDropped());
+ smsSession.startTimeMinutes = inProgressSmsSession.startSystemTimeMin;
+ smsSession.phoneId = inProgressSmsSession.phoneId;
+ smsSession.eventsDropped = inProgressSmsSession.isEventsDropped();
if (mCompletedSmsSessions.size() >= MAX_COMPLETED_SMS_SESSIONS) {
mCompletedSmsSessions.removeFirst();
}
@@ -783,14 +794,21 @@
TelephonyEvent event = new TelephonyEventBuilder(phoneId)
.setServiceState(toServiceStateProto(serviceState)).build();
+ // If service state doesn't change, we don't log the event.
+ if (mLastServiceState.get(phoneId) != null &&
+ Arrays.equals(TelephonyServiceState.toByteArray(mLastServiceState.get(phoneId)),
+ TelephonyServiceState.toByteArray(event.serviceState))) {
+ return;
+ }
+
mLastServiceState.put(phoneId, event.serviceState);
addTelephonyEvent(event);
- annotateInProgressCallSession(event.getTimestampMillis(), phoneId,
+ annotateInProgressCallSession(event.timestampMillis, phoneId,
new CallSessionEventBuilder(
TelephonyCallSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
.setServiceState(event.serviceState));
- annotateInProgressSmsSession(event.getTimestampMillis(), phoneId,
+ annotateInProgressSmsSession(event.timestampMillis, phoneId,
new SmsSessionEventBuilder(
SmsSession.Event.Type.RIL_SERVICE_STATE_CHANGED)
.setServiceState(event.serviceState));
@@ -821,26 +839,35 @@
TelephonySettings s = new TelephonySettings();
switch (feature) {
case ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE:
- s.setIsEnhanced4GLteModeEnabled(value != 0);
+ s.isEnhanced4GLteModeEnabled = (value != 0);
break;
case ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_WIFI:
- s.setIsWifiCallingEnabled(value != 0);
+ s.isWifiCallingEnabled = (value != 0);
break;
case ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_LTE:
- s.setIsVtOverLteEnabled(value != 0);
+ s.isVtOverLteEnabled = (value != 0);
break;
case ImsConfig.FeatureConstants.FEATURE_TYPE_VIDEO_OVER_WIFI:
- s.setIsVtOverWifiEnabled(value != 0);
+ s.isVtOverWifiEnabled = (value != 0);
break;
}
+ // If the settings don't change, we don't log the event.
+ if (mLastSettings.get(phoneId) != null &&
+ Arrays.equals(TelephonySettings.toByteArray(mLastSettings.get(phoneId)),
+ TelephonySettings.toByteArray(s))) {
+ return;
+ }
+
+ mLastSettings.put(phoneId, s);
+
TelephonyEvent event = new TelephonyEventBuilder(phoneId).setSettings(s).build();
addTelephonyEvent(event);
- annotateInProgressCallSession(event.getTimestampMillis(), phoneId,
+ annotateInProgressCallSession(event.timestampMillis, phoneId,
new CallSessionEventBuilder(TelephonyCallSession.Event.Type.SETTINGS_CHANGED)
.setSettings(s));
- annotateInProgressSmsSession(event.getTimestampMillis(), phoneId,
+ annotateInProgressSmsSession(event.timestampMillis, phoneId,
new SmsSessionEventBuilder(SmsSession.Event.Type.SETTINGS_CHANGED)
.setSettings(s));
}
@@ -853,7 +880,17 @@
*/
public void writeSetPreferredNetworkType(int phoneId, int networkType) {
TelephonySettings s = new TelephonySettings();
- s.setPreferredNetworkMode(networkType);
+ s.preferredNetworkMode = networkType + 1;
+
+ // If the settings don't change, we don't log the event.
+ if (mLastSettings.get(phoneId) != null &&
+ Arrays.equals(TelephonySettings.toByteArray(mLastSettings.get(phoneId)),
+ TelephonySettings.toByteArray(s))) {
+ return;
+ }
+
+ mLastSettings.put(phoneId, s);
+
addTelephonyEvent(new TelephonyEventBuilder(phoneId).setSettings(s).build());
}
@@ -867,31 +904,39 @@
public synchronized void writeOnImsConnectionState(int phoneId, int state,
ImsReasonInfo reasonInfo) {
ImsConnectionState imsState = new ImsConnectionState();
- imsState.setState(state);
- mLastImsConnectionState.put(phoneId, imsState);
+ imsState.state = state;
if (reasonInfo != null) {
TelephonyProto.ImsReasonInfo ri = new TelephonyProto.ImsReasonInfo();
- ri.setReasonCode(reasonInfo.getCode());
- ri.setExtraCode(reasonInfo.getExtraCode());
+ ri.reasonCode = reasonInfo.getCode();
+ ri.extraCode = reasonInfo.getExtraCode();
String extraMessage = reasonInfo.getExtraMessage();
if (extraMessage != null) {
- ri.setExtraMessage(extraMessage);
+ ri.extraMessage = extraMessage;
}
imsState.reasonInfo = ri;
}
+ // If the connection state does not change, do not log it.
+ if (mLastImsConnectionState.get(phoneId) != null &&
+ Arrays.equals(ImsConnectionState.toByteArray(mLastImsConnectionState.get(phoneId)),
+ ImsConnectionState.toByteArray(imsState))) {
+ return;
+ }
+
+ mLastImsConnectionState.put(phoneId, imsState);
+
TelephonyEvent event = new TelephonyEventBuilder(phoneId)
.setImsConnectionState(imsState).build();
addTelephonyEvent(event);
- annotateInProgressCallSession(event.getTimestampMillis(), phoneId,
+ annotateInProgressCallSession(event.timestampMillis, phoneId,
new CallSessionEventBuilder(
TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED)
.setImsConnectionState(event.imsConnectionState));
- annotateInProgressSmsSession(event.getTimestampMillis(), phoneId,
+ annotateInProgressSmsSession(event.timestampMillis, phoneId,
new SmsSessionEventBuilder(
SmsSession.Event.Type.IMS_CONNECTION_STATE_CHANGED)
.setImsConnectionState(event.imsConnectionState));
@@ -906,22 +951,30 @@
public synchronized void writeOnImsCapabilities(int phoneId, boolean[] capabilities) {
ImsCapabilities cap = new ImsCapabilities();
- cap.setVoiceOverLte(capabilities[0]);
- cap.setVideoOverLte(capabilities[1]);
- cap.setVoiceOverWifi(capabilities[2]);
- cap.setVideoOverWifi(capabilities[3]);
- cap.setUtOverLte(capabilities[4]);
- cap.setUtOverWifi(capabilities[5]);
+ cap.voiceOverLte = capabilities[0];
+ cap.videoOverLte = capabilities[1];
+ cap.voiceOverWifi = capabilities[2];
+ cap.videoOverWifi = capabilities[3];
+ cap.utOverLte = capabilities[4];
+ cap.utOverWifi = capabilities[5];
TelephonyEvent event = new TelephonyEventBuilder(phoneId).setImsCapabilities(cap).build();
+
+ // If the capabilities don't change, we don't log the event.
+ if (mLastImsCapabilities.get(phoneId) != null &&
+ Arrays.equals(ImsCapabilities.toByteArray(mLastImsCapabilities.get(phoneId)),
+ ImsCapabilities.toByteArray(cap))) {
+ return;
+ }
+
mLastImsCapabilities.put(phoneId, cap);
addTelephonyEvent(event);
- annotateInProgressCallSession(event.getTimestampMillis(), phoneId,
+ annotateInProgressCallSession(event.timestampMillis, phoneId,
new CallSessionEventBuilder(
TelephonyCallSession.Event.Type.IMS_CAPABILITIES_CHANGED)
.setImsCapabilities(event.imsCapabilities));
- annotateInProgressSmsSession(event.getTimestampMillis(), phoneId,
+ annotateInProgressSmsSession(event.timestampMillis, phoneId,
new SmsSessionEventBuilder(
SmsSession.Event.Type.IMS_CAPABILITIES_CHANGED)
.setImsCapabilities(event.imsCapabilities));
@@ -963,13 +1016,13 @@
String apn, int authType, String protocol) {
RilSetupDataCall setupDataCall = new RilSetupDataCall();
- setupDataCall.setRat(radioTechnology);
- setupDataCall.setDataProfile(profile + 1); // off by 1 between proto and RIL constants.
+ setupDataCall.rat = radioTechnology;
+ setupDataCall.dataProfile = profile + 1; // off by 1 between proto and RIL constants.
if (apn != null) {
- setupDataCall.setApn(apn);
+ setupDataCall.apn = apn;
}
if (protocol != null) {
- setupDataCall.setType(toPdpType(protocol));
+ setupDataCall.type = toPdpType(protocol);
}
addTelephonyEvent(new TelephonyEventBuilder(phoneId).setSetupDataCall(
@@ -987,8 +1040,8 @@
public void writeRilDeactivateDataCall(int phoneId, int rilSerial, int cid, int reason) {
RilDeactivateDataCall deactivateDataCall = new RilDeactivateDataCall();
- deactivateDataCall.setCid(cid);
- deactivateDataCall.setReason(reason + 1);
+ deactivateDataCall.cid = cid;
+ deactivateDataCall.reason = reason + 1;
addTelephonyEvent(new TelephonyEventBuilder(phoneId).setDeactivateDataCall(
deactivateDataCall).build());
@@ -1006,12 +1059,12 @@
for (int i = 0; i < dcsList.size(); i++) {
dataCalls[i] = new RilDataCall();
- dataCalls[i].setCid(dcsList.get(i).cid);
- if (dcsList.get(i).ifname != null) {
- dataCalls[i].setIframe(dcsList.get(i).ifname);
+ dataCalls[i].cid = dcsList.get(i).cid;
+ if (!TextUtils.isEmpty(dcsList.get(i).ifname)) {
+ dataCalls[i].iframe = dcsList.get(i).ifname;
}
- if (dcsList.get(i).type != null) {
- dataCalls[i].setType(toPdpType(dcsList.get(i).type));
+ if (!TextUtils.isEmpty(dcsList.get(i).type)) {
+ dataCalls[i].type = toPdpType(dcsList.get(i).type);
}
}
@@ -1038,15 +1091,25 @@
TelephonyCallSession.Event.Type.RIL_CALL_LIST_CHANGED)
.setRilCalls(calls)
);
- if (VDBG) Rlog.v(TAG, "Logged Call list changed");
+ if (VDBG) Rlog.v(TAG, "Logged Call list changed");
+ if (callSession.isPhoneIdle() && disconnectReasonsKnown(calls)) {
+ finishCallSession(callSession);
+ }
}
}
+ private boolean disconnectReasonsKnown(RilCall[] calls) {
+ for (RilCall call : calls) {
+ if (call.callEndReason == 0) return false;
+ }
+ return true;
+ }
+
private RilCall[] convertConnectionsToRilCalls(ArrayList<GsmCdmaConnection> mConnections) {
RilCall[] calls = new RilCall[mConnections.size()];
for (int i = 0; i < mConnections.size(); i++) {
calls[i] = new RilCall();
- calls[i].setIndex(i);
+ calls[i].index = i;
convertConnectionToRilCall(mConnections.get(i), calls[i]);
}
return calls;
@@ -1054,44 +1117,44 @@
private void convertConnectionToRilCall(GsmCdmaConnection conn, RilCall call) {
if (conn.isIncoming()) {
- call.setType(TelephonyCallSession.Event.RilCall.Type.MT);
+ call.type = Type.MT;
} else {
- call.setType(TelephonyCallSession.Event.RilCall.Type.MO);
+ call.type = Type.MO;
}
switch (conn.getState()) {
case IDLE:
- call.setState(TelephonyCallSession.Event.CallState.CALL_IDLE);
+ call.state = CallState.CALL_IDLE;
break;
case ACTIVE:
- call.setState(TelephonyCallSession.Event.CallState.CALL_ACTIVE);
+ call.state = CallState.CALL_ACTIVE;
break;
case HOLDING:
- call.setState(TelephonyCallSession.Event.CallState.CALL_HOLDING);
+ call.state = CallState.CALL_HOLDING;
break;
case DIALING:
- call.setState(TelephonyCallSession.Event.CallState.CALL_DIALING);
+ call.state = CallState.CALL_DIALING;
break;
case ALERTING:
- call.setState(TelephonyCallSession.Event.CallState.CALL_ALERTING);
+ call.state = CallState.CALL_ALERTING;
break;
case INCOMING:
- call.setState(TelephonyCallSession.Event.CallState.CALL_INCOMING);
+ call.state = CallState.CALL_INCOMING;
break;
case WAITING:
- call.setState(TelephonyCallSession.Event.CallState.CALL_WAITING);
+ call.state = CallState.CALL_WAITING;
break;
case DISCONNECTED:
- call.setState(TelephonyCallSession.Event.CallState.CALL_DISCONNECTED);
+ call.state = CallState.CALL_DISCONNECTED;
break;
case DISCONNECTING:
- call.setState(TelephonyCallSession.Event.CallState.CALL_DISCONNECTING);
+ call.state = CallState.CALL_DISCONNECTING;
break;
default:
- call.setState(TelephonyCallSession.Event.CallState.CALL_UNKNOWN);
+ call.state = CallState.CALL_UNKNOWN;
break;
}
- call.setCallEndReason(conn.getDisconnectCause());
- call.setIsMultiparty(conn.isMultiparty());
+ call.callEndReason = conn.getDisconnectCause();
+ call.isMultiparty = conn.isMultiparty();
}
/**
@@ -1111,7 +1174,7 @@
} else {
RilCall[] calls = new RilCall[1];
calls[0] = new RilCall();
- calls[0].setIndex(-1);
+ calls[0].index = -1;
convertConnectionToRilCall(conn, calls[0]);
callSession.addEvent(callSession.startElapsedTimeMs,
new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST)
@@ -1148,7 +1211,7 @@
} else {
RilCall[] calls = new RilCall[1];
calls[0] = new RilCall();
- calls[0].setIndex(callId);
+ calls[0].index = callId;
convertConnectionToRilCall(conn, calls[0]);
callSession.addEvent(
new CallSessionEventBuilder(TelephonyCallSession.Event.Type.RIL_REQUEST)
@@ -1244,17 +1307,17 @@
RilDataCall dataCall = new RilDataCall();
if (response != null) {
- setupDataCallResponse.setStatus(
- response.status == 0 ? RilDataCallFailCause.PDP_FAIL_NONE : response.status);
- setupDataCallResponse.setSuggestedRetryTimeMillis(response.suggestedRetryTime);
+ setupDataCallResponse.status =
+ (response.status == 0 ? RilDataCallFailCause.PDP_FAIL_NONE : response.status);
+ setupDataCallResponse.suggestedRetryTimeMillis = response.suggestedRetryTime;
- dataCall.setCid(response.cid);
- if (response.type != null) {
- dataCall.setType(toPdpType(response.type));
+ dataCall.cid = response.cid;
+ if (!TextUtils.isEmpty(response.type)) {
+ dataCall.type = toPdpType(response.type);
}
- if (response.ifname != null) {
- dataCall.setIframe(response.ifname);
+ if (!TextUtils.isEmpty(response.ifname)) {
+ dataCall.iframe = response.ifname;
}
}
setupDataCallResponse.call = dataCall;
@@ -1281,7 +1344,7 @@
TelephonyCallSession.Event.Type.RIL_RESPONSE)
.setRilRequest(toCallSessionRilRequest(rilRequest))
.setRilRequestId(rilSerial)
- .setRilError(rilError));
+ .setRilError(rilError + 1));
}
}
@@ -1309,7 +1372,7 @@
smsSession.addEvent(new SmsSessionEventBuilder(
SmsSession.Event.Type.SMS_SEND_RESULT)
.setErrorCode(errorCode)
- .setRilErrno(rilError)
+ .setRilErrno(rilError + 1)
.setRilRequestId(rilSerial)
);
@@ -1392,7 +1455,12 @@
if (callSession == null) {
Rlog.e(TAG, "writePhoneState: Call session is missing");
} else {
- if (state == TelephonyCallSession.Event.PhoneState.STATE_IDLE) {
+ // For CS Calls Finish the Call Session after Receiving the Last Call Fail Cause
+ // For IMS calls we receive the Disconnect Cause along with Call End event.
+ // So we can finish the call session here.
+ callSession.setLastKnownPhoneState(state);
+ if ((state == TelephonyCallSession.Event.PhoneState.STATE_IDLE)
+ && (!callSession.containsCsCalls())) {
finishCallSession(callSession);
}
callSession.addEvent(new CallSessionEventBuilder(
@@ -1485,7 +1553,11 @@
* @param session IMS call session
*/
public void writeOnImsCallReceive(int phoneId, ImsCallSession session) {
- writeOnImsCallStart(phoneId, session);
+ InProgressCallSession callSession = startNewCallSessionIfNeeded(phoneId);
+
+ callSession.addEvent(
+ new CallSessionEventBuilder(TelephonyCallSession.Event.Type.IMS_CALL_RECEIVE)
+ .setCallIndex(getCallId(session)));
}
/**
@@ -1517,11 +1589,11 @@
private TelephonyProto.ImsReasonInfo toImsReasonInfoProto(ImsReasonInfo reasonInfo) {
TelephonyProto.ImsReasonInfo ri = new TelephonyProto.ImsReasonInfo();
if (reasonInfo != null) {
- ri.setReasonCode(reasonInfo.getCode());
- ri.setExtraCode(reasonInfo.getExtraCode());
+ ri.reasonCode = reasonInfo.getCode();
+ ri.extraCode = reasonInfo.getExtraCode();
String extraMessage = reasonInfo.getExtraMessage();
if (extraMessage != null) {
- ri.setExtraMessage(extraMessage);
+ ri.extraMessage = extraMessage;
}
}
return ri;
@@ -1621,12 +1693,28 @@
TelephonyEvent event = new TelephonyEventBuilder(phoneId).setNITZ(timestamp).build();
addTelephonyEvent(event);
- annotateInProgressCallSession(event.getTimestampMillis(), phoneId,
+ annotateInProgressCallSession(event.timestampMillis, phoneId,
new CallSessionEventBuilder(
TelephonyCallSession.Event.Type.NITZ_TIME)
.setNITZ(timestamp));
}
+ /**
+ * Write Modem Restart event
+ *
+ * @param phoneId Phone id
+ * @param reason Reason for the modem reset.
+ */
+ public void writeModemRestartEvent(int phoneId, String reason) {
+ final ModemRestart modemRestart = new ModemRestart();
+ String basebandVersion = Build.getRadioVersion();
+ if (basebandVersion != null) modemRestart.basebandVersion = basebandVersion;
+ if (reason != null) modemRestart.reason = reason;
+ TelephonyEvent event = new TelephonyEventBuilder(phoneId).setModemRestart(
+ modemRestart).build();
+ addTelephonyEvent(event);
+ }
+
//TODO: Expand the proto in the future
public void writeOnImsCallProgressing(int phoneId, ImsCallSession session) {}
public void writeOnImsCallStarted(int phoneId, ImsCallSession session) {}
diff --git a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
index 0d726d2..fe1d7c5 100644
--- a/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/src/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -20,6 +20,8 @@
import android.os.Handler;
import android.os.Message;
import android.service.carrier.CarrierIdentifier;
+import android.telephony.ImsiEncryptionInfo;
+import android.telephony.NetworkScanRequest;
import com.android.internal.telephony.BaseCommands;
import com.android.internal.telephony.CommandsInterface;
@@ -28,7 +30,6 @@
import com.android.internal.telephony.dataconnection.DataProfile;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
-import java.security.PublicKey;
import java.util.List;
/**
@@ -335,6 +336,14 @@
}
@Override
+ public void startNetworkScan(NetworkScanRequest nsr, Message response) {
+ }
+
+ @Override
+ public void stopNetworkScan(Message response) {
+ }
+
+ @Override
public void setCallForward(int action, int cfReason, int serviceClass,
String number, int timeSeconds, Message response) {
}
@@ -618,7 +627,7 @@
}
@Override
- public void setCarrierInfoForImsiEncryption(PublicKey carrierPublicKey, String keyIdentifier,
+ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo,
Message result) {
}
@@ -639,6 +648,6 @@
}
@Override
- public void setSimCardPower(boolean powerUp, Message result) {
+ public void setSimCardPower(int state, Message result) {
}
}
diff --git a/src/java/com/android/internal/telephony/sip/SipPhoneBase.java b/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
index 1cd2a15..7bdfad8 100755
--- a/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
+++ b/src/java/com/android/internal/telephony/sip/SipPhoneBase.java
@@ -21,29 +21,30 @@
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
-import android.os.ResultReceiver;
import android.os.Message;
import android.os.RegistrantList;
+import android.os.ResultReceiver;
import android.os.SystemProperties;
import android.os.WorkSource;
import android.telephony.CellLocation;
+import android.telephony.NetworkScanRequest;
+import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
-import android.telephony.Rlog;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Connection;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.dataconnection.DataConnection;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.IccPhoneBookInterfaceManager;
import com.android.internal.telephony.MmiCode;
import com.android.internal.telephony.OperatorInfo;
+import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.PhoneNotifier;
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.UUSInfo;
+import com.android.internal.telephony.dataconnection.DataConnection;
import com.android.internal.telephony.uicc.IccFileHandler;
import java.util.ArrayList;
@@ -394,6 +395,14 @@
}
@Override
+ public void startNetworkScan(NetworkScanRequest nsr, Message response) {
+ }
+
+ @Override
+ public void stopNetworkScan(Message response) {
+ }
+
+ @Override
public void setNetworkSelectionModeAutomatic(Message response) {
}
@@ -453,7 +462,7 @@
}
@Override
- public boolean isDataConnectivityPossible() {
+ public boolean isDataAllowed() {
return false;
}
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommands.java b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
index 44701db..3360058 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -30,6 +30,8 @@
import android.telephony.CellInfo;
import android.telephony.CellInfoGsm;
import android.telephony.IccOpenLogicalChannelResponse;
+import android.telephony.ImsiEncryptionInfo;
+import android.telephony.NetworkScanRequest;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -53,7 +55,6 @@
import com.android.internal.telephony.uicc.IccCardStatus;
import com.android.internal.telephony.uicc.IccIoResult;
-import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -151,6 +152,12 @@
mPin2Code = DEFAULT_SIM_PIN2_CODE;
}
+ public void dispose() {
+ if (mHandlerThread != null) {
+ mHandlerThread.quit();
+ }
+ }
+
private void log(String str) {
Rlog.d(LOG_TAG, str);
}
@@ -1355,7 +1362,25 @@
* ((AsyncResult)response.obj).result is a List of NetworkInfo objects
*/
@Override
- public void getAvailableNetworks(Message result) {unimplemented(result);}
+ public void getAvailableNetworks(Message result) {
+ unimplemented(result);
+ }
+
+ /**
+ * Starts a network scan
+ */
+ @Override
+ public void startNetworkScan(NetworkScanRequest nsr, Message result) {
+ unimplemented(result);
+ }
+
+ /**
+ * Stops an ongoing network scan
+ */
+ @Override
+ public void stopNetworkScan(Message result) {
+ unimplemented(result);
+ }
@Override
public void getBasebandVersion (Message result) {
@@ -1430,11 +1455,11 @@
}
@Override
- public void setCarrierInfoForImsiEncryption(PublicKey publicKey, String keyIdentifier,
+ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo,
Message response) {
// Just echo back data
if (response != null) {
- AsyncResult.forMessage(response).result = publicKey;
+ AsyncResult.forMessage(response).result = imsiEncryptionInfo;
response.sendToTarget();
}
}
@@ -2116,7 +2141,7 @@
}
@Override
- public void setSimCardPower(boolean powerUp, Message result) {
+ public void setSimCardPower(int state, Message result) {
}
@VisibleForTesting
@@ -2126,4 +2151,10 @@
new AsyncResult(null, restrictedState, null));
}
}
+
+ @Override
+ public void setOnRestrictedStateChanged(Handler h, int what, Object obj) {
+ super.setOnRestrictedStateChanged(h, what, obj);
+ SimulatedCommandsVerifier.getInstance().setOnRestrictedStateChanged(h, what, obj);
+ }
}
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
index 4c57e7f..91b86e3 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
@@ -19,6 +19,8 @@
import android.os.Handler;
import android.os.Message;
import android.service.carrier.CarrierIdentifier;
+import android.telephony.ImsiEncryptionInfo;
+import android.telephony.NetworkScanRequest;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.RadioCapability;
@@ -27,7 +29,6 @@
import com.android.internal.telephony.dataconnection.DataProfile;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
-import java.security.PublicKey;
import java.util.List;
public class SimulatedCommandsVerifier implements CommandsInterface {
@@ -946,6 +947,16 @@
}
@Override
+ public void startNetworkScan(NetworkScanRequest nsr, Message response) {
+
+ }
+
+ @Override
+ public void stopNetworkScan(Message response) {
+
+ }
+
+ @Override
public void getBasebandVersion(Message response) {
}
@@ -1339,7 +1350,7 @@
}
@Override
- public void setCarrierInfoForImsiEncryption(PublicKey carrierPublicKey, String keyIdentifier,
+ public void setCarrierInfoForImsiEncryption(ImsiEncryptionInfo imsiEncryptionInfo,
Message result) {
}
@@ -1371,7 +1382,7 @@
}
@Override
- public void setSimCardPower(boolean powerUp, Message result) {
+ public void setSimCardPower(int state, Message result) {
}
@Override
@@ -1379,6 +1390,14 @@
}
@Override
+ public void registerForNetworkScanResult(Handler h, int what, Object obj) {
+ }
+
+ @Override
+ public void unregisterForNetworkScanResult(Handler h) {
+ }
+
+ @Override
public void unregisterForCarrierInfoForImsiEncryption(Handler h) {
}
}
diff --git a/src/java/com/android/internal/telephony/uicc/AdnRecord.java b/src/java/com/android/internal/telephony/uicc/AdnRecord.java
index 203236c..4414caf 100644
--- a/src/java/com/android/internal/telephony/uicc/AdnRecord.java
+++ b/src/java/com/android/internal/telephony/uicc/AdnRecord.java
@@ -19,8 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.PhoneNumberUtils;
-import android.text.TextUtils;
import android.telephony.Rlog;
+import android.text.TextUtils;
import com.android.internal.telephony.GsmAlphabet;
@@ -248,7 +248,8 @@
Rlog.w(LOG_TAG, "[buildAdnString] Max length of tag is " + footerOffset);
return null;
} else {
- bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(mNumber);
+ bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(
+ mNumber, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
System.arraycopy(bcdNumber, 0, adnString,
footerOffset + ADN_TON_AND_NPI, bcdNumber.length);
@@ -289,7 +290,10 @@
}
mNumber += PhoneNumberUtils.calledPartyBCDFragmentToString(
- extRecord, 2, 0xff & extRecord[1]);
+ extRecord,
+ 2,
+ 0xff & extRecord[1],
+ PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
// We don't support ext record chaining.
@@ -327,7 +331,10 @@
// the ME (see note 2)."
mNumber = PhoneNumberUtils.calledPartyBCDToString(
- record, footerOffset + 1, numberLength);
+ record,
+ footerOffset + 1,
+ numberLength,
+ PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
mExtRecord = 0xff & record[record.length - 1];
diff --git a/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java b/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java
new file mode 100644
index 0000000..18d2937
--- /dev/null
+++ b/src/java/com/android/internal/telephony/uicc/CarrierTestOverride.java
@@ -0,0 +1,165 @@
+/*
+ * 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.uicc;
+
+import android.os.Environment;
+import android.telephony.Rlog;
+import android.util.Xml;
+
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * Provide a machanism to override MVNO paramteres under CarrierConfig through a config file.
+ */
+public class CarrierTestOverride {
+ static final String LOG_TAG = "CarrierTestOverride";
+
+ /**
+ * Config file that can be created and adb-pushed by tester/developer
+ *
+ * Sample xml:
+ * <carrierTestOverrides>
+ <carrierTestOverride key="isInTestMode" value="true"/>
+ <carrierTestOverride key="gid1" value="bae0000000000000"/>
+ <carrierTestOverride key="gid2" value="ffffffffffffffff"/>
+ <carrierTestOverride key="imsi" value="310010123456789"/>
+ <carrierTestOverride key="spn" value="Verizon"/>
+ </carrierTestOverrides>
+ */
+ static final String DATA_CARRIER_TEST_OVERRIDE_PATH =
+ "/user_de/0/com.android.phone/files/carrier_test_conf.xml";
+ static final String CARRIER_TEST_XML_HEADER = "carrierTestOverrides";
+ static final String CARRIER_TEST_XML_SUBHEADER = "carrierTestOverride";
+ static final String CARRIER_TEST_XML_ITEM_KEY = "key";
+ static final String CARRIER_TEST_XML_ITEM_VALUE = "value";
+ static final String CARRIER_TEST_XML_ITEM_KEY_STRING_ISINTESTMODE = "isInTestMode";
+ static final String CARRIER_TEST_XML_ITEM_KEY_STRING_GID1 = "gid1";
+ static final String CARRIER_TEST_XML_ITEM_KEY_STRING_GID2 = "gid2";
+ static final String CARRIER_TEST_XML_ITEM_KEY_STRING_IMSI = "imsi";
+ static final String CARRIER_TEST_XML_ITEM_KEY_STRING_SPN = "spn";
+
+ private HashMap<String, String> mCarrierTestParamMap;
+
+ CarrierTestOverride() {
+ mCarrierTestParamMap = new HashMap<String, String>();
+ loadCarrierTestOverrides();
+ }
+
+ boolean isInTestMode() {
+ return mCarrierTestParamMap.containsKey(CARRIER_TEST_XML_ITEM_KEY_STRING_ISINTESTMODE)
+ && mCarrierTestParamMap.get(CARRIER_TEST_XML_ITEM_KEY_STRING_ISINTESTMODE)
+ .equals("true");
+ }
+
+ String getFakeSpn() {
+ try {
+ String spn = mCarrierTestParamMap.get(CARRIER_TEST_XML_ITEM_KEY_STRING_SPN);
+ Rlog.d(LOG_TAG, "reading spn from CarrierTestConfig file: " + spn);
+ return spn;
+ } catch (NullPointerException e) {
+ Rlog.w(LOG_TAG, "No spn in CarrierTestConfig file ");
+ return null;
+ }
+ }
+
+ String getFakeIMSI() {
+ try {
+ String imsi = mCarrierTestParamMap.get(CARRIER_TEST_XML_ITEM_KEY_STRING_IMSI);
+ Rlog.d(LOG_TAG, "reading imsi from CarrierTestConfig file: " + imsi);
+ return imsi;
+ } catch (NullPointerException e) {
+ Rlog.w(LOG_TAG, "No imsi in CarrierTestConfig file ");
+ return null;
+ }
+ }
+
+ String getFakeGid1() {
+ try {
+ String gid1 = mCarrierTestParamMap.get(CARRIER_TEST_XML_ITEM_KEY_STRING_GID1);
+ Rlog.d(LOG_TAG, "reading gid1 from CarrierTestConfig file: " + gid1);
+ return gid1;
+ } catch (NullPointerException e) {
+ Rlog.w(LOG_TAG, "No gid1 in CarrierTestConfig file ");
+ return null;
+ }
+ }
+
+ String getFakeGid2() {
+ try {
+ String gid2 = mCarrierTestParamMap.get(CARRIER_TEST_XML_ITEM_KEY_STRING_GID2);
+ Rlog.d(LOG_TAG, "reading gid2 from CarrierTestConfig file: " + gid2);
+ return gid2;
+ } catch (NullPointerException e) {
+ Rlog.w(LOG_TAG, "No gid2 in CarrierTestConfig file ");
+ return null;
+ }
+ }
+
+ private void loadCarrierTestOverrides() {
+
+ FileReader carrierTestConfigReader;
+
+ File carrierTestConfigFile = new File(Environment.getDataDirectory(),
+ DATA_CARRIER_TEST_OVERRIDE_PATH);
+
+ try {
+ carrierTestConfigReader = new FileReader(carrierTestConfigFile);
+ Rlog.d(LOG_TAG, "CarrierTestConfig file Modified Timestamp: "
+ + carrierTestConfigFile.lastModified());
+ } catch (FileNotFoundException e) {
+ Rlog.w(LOG_TAG, "Can not open " + carrierTestConfigFile.getAbsolutePath());
+ return;
+ }
+
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(carrierTestConfigReader);
+
+ XmlUtils.beginDocument(parser, CARRIER_TEST_XML_HEADER);
+
+ while (true) {
+ XmlUtils.nextElement(parser);
+
+ String name = parser.getName();
+ if (!CARRIER_TEST_XML_SUBHEADER.equals(name)) {
+ break;
+ }
+
+ String key = parser.getAttributeValue(null, CARRIER_TEST_XML_ITEM_KEY);
+ String value = parser.getAttributeValue(null, CARRIER_TEST_XML_ITEM_VALUE);
+
+ Rlog.d(LOG_TAG,
+ "extracting key-values from CarrierTestConfig file: " + key + "|" + value);
+ mCarrierTestParamMap.put(key, value);
+ }
+ carrierTestConfigReader.close();
+ } catch (XmlPullParserException e) {
+ Rlog.w(LOG_TAG, "Exception in carrier_test_conf parser " + e);
+ } catch (IOException e) {
+ Rlog.w(LOG_TAG, "Exception in carrier_test_conf parser " + e);
+ }
+ }
+}
diff --git a/src/java/com/android/internal/telephony/uicc/IccCardProxy.java b/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
index 2235654..241f211 100644
--- a/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
+++ b/src/java/com/android/internal/telephony/uicc/IccCardProxy.java
@@ -16,9 +16,7 @@
package com.android.internal.telephony.uicc;
-import static android.Manifest.permission.READ_PHONE_STATE;
-
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncResult;
@@ -34,9 +32,11 @@
import android.text.TextUtils;
import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.CommandsInterface.RadioState;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.IccCardConstants.State;
+import com.android.internal.telephony.IntentBroadcaster;
import com.android.internal.telephony.MccTable;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
@@ -47,7 +47,6 @@
import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
import com.android.internal.telephony.uicc.IccCardStatus.CardState;
import com.android.internal.telephony.uicc.IccCardStatus.PinState;
-import com.android.internal.telephony.uicc.UiccController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -88,7 +87,7 @@
private static final int EVENT_ICC_RECORD_EVENTS = 500;
private static final int EVENT_SUBSCRIPTION_ACTIVATED = 501;
private static final int EVENT_SUBSCRIPTION_DEACTIVATED = 502;
- private static final int EVENT_CARRIER_PRIVILIGES_LOADED = 503;
+ private static final int EVENT_CARRIER_PRIVILEGES_LOADED = 503;
private Integer mPhoneId = null;
@@ -107,7 +106,7 @@
private UiccCardApplication mUiccApplication = null;
private IccRecords mIccRecords = null;
private CdmaSubscriptionSourceManager mCdmaSSM = null;
- private boolean mRadioOn = false;
+ private RadioState mRadioState = RadioState.RADIO_UNAVAILABLE;
private boolean mQuietMode = false; // when set to true IccCardProxy will not broadcast
// ACTION_SIM_STATE_CHANGED intents
private boolean mInitialized = false;
@@ -130,7 +129,6 @@
ci.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_UNAVAILABLE, null);
resetProperties();
- setExternalState(State.NOT_READY, false);
}
public void dispose() {
@@ -169,17 +167,31 @@
*/
private void updateQuietMode() {
synchronized (mLock) {
+ boolean oldQuietMode = mQuietMode;
boolean newQuietMode;
int cdmaSource = Phone.CDMA_SUBSCRIPTION_UNKNOWN;
+ boolean isLteOnCdmaMode = TelephonyManager.getLteOnCdmaModeStatic()
+ == PhoneConstants.LTE_ON_CDMA_TRUE;
if (mCurrentAppType == UiccController.APP_FAM_3GPP) {
newQuietMode = false;
if (DBG) log("updateQuietMode: 3GPP subscription -> newQuietMode=" + newQuietMode);
} else {
+ if (isLteOnCdmaMode) {
+ log("updateQuietMode: is cdma/lte device, force IccCardProxy into 3gpp mode");
+ mCurrentAppType = UiccController.APP_FAM_3GPP;
+ }
cdmaSource = mCdmaSSM != null ?
mCdmaSSM.getCdmaSubscriptionSource() : Phone.CDMA_SUBSCRIPTION_UNKNOWN;
newQuietMode = (cdmaSource == Phone.CDMA_SUBSCRIPTION_NV)
- && (mCurrentAppType == UiccController.APP_FAM_3GPP2);
+ && (mCurrentAppType == UiccController.APP_FAM_3GPP2)
+ && !isLteOnCdmaMode;
+ if (DBG) {
+ log("updateQuietMode: cdmaSource=" + cdmaSource
+ + " mCurrentAppType=" + mCurrentAppType
+ + " isLteOnCdmaMode=" + isLteOnCdmaMode
+ + " newQuietMode=" + newQuietMode);
+ }
}
if (mQuietMode == false && newQuietMode == true) {
@@ -200,7 +212,8 @@
}
if (DBG) {
log("updateQuietMode: QuietMode is " + mQuietMode + " (app_type="
- + mCurrentAppType + " cdmaSource=" + cdmaSource + ")");
+ + mCurrentAppType + " isLteOnCdmaMode=" + isLteOnCdmaMode
+ + " cdmaSource=" + cdmaSource + ")");
}
mInitialized = true;
sendMessage(obtainMessage(EVENT_ICC_CHANGED));
@@ -211,15 +224,18 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case EVENT_RADIO_OFF_OR_UNAVAILABLE:
- mRadioOn = false;
- if (CommandsInterface.RadioState.RADIO_UNAVAILABLE == mCi.getRadioState()) {
- setExternalState(State.NOT_READY);
- }
+ mRadioState = mCi.getRadioState();
+ updateExternalState();
break;
case EVENT_RADIO_ON:
- mRadioOn = true;
+ mRadioState = RadioState.RADIO_ON;
if (!mInitialized) {
updateQuietMode();
+ } else {
+ // updateQuietMode() triggers ICC_CHANGED, which eventually
+ // calls updateExternalState; thus, we don't need this in the
+ // above case
+ updateExternalState();
}
break;
case EVENT_ICC_CHANGED:
@@ -258,7 +274,7 @@
}
if (mUiccCard != null && !mUiccCard.areCarrierPriviligeRulesLoaded()) {
mUiccCard.registerForCarrierPrivilegeRulesLoaded(
- this, EVENT_CARRIER_PRIVILIGES_LOADED, null);
+ this, EVENT_CARRIER_PRIVILEGES_LOADED, null);
} else {
onRecordsLoaded();
}
@@ -294,7 +310,7 @@
}
break;
- case EVENT_CARRIER_PRIVILIGES_LOADED:
+ case EVENT_CARRIER_PRIVILEGES_LOADED:
log("EVENT_CARRIER_PRIVILEGES_LOADED");
if (mUiccCard != null) {
mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this);
@@ -326,11 +342,9 @@
private void updateIccAvailability() {
synchronized (mLock) {
UiccCard newCard = mUiccController.getUiccCard(mPhoneId);
- CardState state = CardState.CARDSTATE_ABSENT;
UiccCardApplication newApp = null;
IccRecords newRecords = null;
if (newCard != null) {
- state = newCard.getCardState();
newApp = newCard.getApplication(mCurrentAppType);
if (newApp != null) {
newRecords = newApp.getIccRecords();
@@ -338,7 +352,7 @@
}
if (mIccRecords != newRecords || mUiccApplication != newApp || mUiccCard != newCard) {
- if (DBG) log("Icc changed. Reregestering.");
+ if (DBG) log("Icc changed. Reregistering.");
unregisterUiccCardEvents();
mUiccCard = newCard;
mUiccApplication = newApp;
@@ -368,15 +382,27 @@
// mUiccCard could be null at bootup, before valid card states have
// been received from UiccController.
if (mUiccCard == null) {
- setExternalState(State.NOT_READY);
+ setExternalState(State.UNKNOWN);
return;
}
if (mUiccCard.getCardState() == CardState.CARDSTATE_ABSENT) {
- if (mRadioOn) {
- setExternalState(State.ABSENT);
+ /*
+ * Both IccCardProxy and UiccController are registered for
+ * RadioState changes. When the UiccController receives a radio
+ * state changed to Unknown it will dispose of all of the IccCard
+ * objects, which will then notify the IccCardProxy and the null
+ * object will force the state to unknown. However, because the
+ * IccCardProxy is also registered for RadioState changes, it will
+ * recieve that signal first. By triggering on radio state changes
+ * directly, we reduce the time window during which the modem is
+ * UNAVAILABLE but the IccStatus is reported as something valid.
+ * This is not ideal.
+ */
+ if (mRadioState == RadioState.RADIO_UNAVAILABLE) {
+ setExternalState(State.UNKNOWN);
} else {
- setExternalState(State.NOT_READY);
+ setExternalState(State.ABSENT);
}
return;
}
@@ -396,9 +422,20 @@
return;
}
+ // By process of elimination, the UICC Card State = PRESENT
switch (mUiccApplication.getState()) {
case APPSTATE_UNKNOWN:
- setExternalState(State.UNKNOWN);
+ /*
+ * APPSTATE_UNKNOWN is a catch-all state reported whenever the app
+ * is not explicitly in one of the other states. To differentiate the
+ * case where we know that there is a card present, but the APP is not
+ * ready, we choose NOT_READY here instead of unknown. This is possible
+ * in at least two cases:
+ * 1) A transient during the process of the SIM bringup
+ * 2) There is no valid App on the SIM to load, which can be the case with an
+ * eSIM/soft SIM.
+ */
+ setExternalState(State.NOT_READY);
break;
case APPSTATE_DETECTED:
HandleDetectedState();
@@ -445,6 +482,7 @@
private void unregisterUiccCardEvents() {
if (mUiccCard != null) mUiccCard.unregisterForAbsent(this);
+ if (mUiccCard != null) mUiccCard.unregisterForCarrierPrivilegeRulesLoaded(this);
if (mUiccApplication != null) mUiccApplication.unregisterForReady(this);
if (mUiccApplication != null) mUiccApplication.unregisterForLocked(this);
if (mUiccApplication != null) mUiccApplication.unregisterForNetworkLocked(this);
@@ -484,8 +522,7 @@
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhoneId);
log("broadcastIccStateChangedIntent intent ACTION_SIM_STATE_CHANGED value=" + value
+ " reason=" + reason + " for mPhoneId=" + mPhoneId);
- ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
- UserHandle.USER_ALL);
+ IntentBroadcaster.getInstance().broadcastStickyIntent(intent, mPhoneId);
}
}
@@ -503,8 +540,9 @@
intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
intent.putExtra(PhoneConstants.PHONE_KEY, mPhoneId); // SubId may not be valid.
- log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED" + " for mPhoneId : " + mPhoneId);
- ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
+ log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED value=" + value
+ + " for mPhoneId : " + mPhoneId);
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
}
}
@@ -516,15 +554,16 @@
}
if (!override && newState == mExternalState) {
- loge("setExternalState: !override and newstate unchanged from " + newState);
+ log("setExternalState: !override and newstate unchanged from " + newState);
return;
}
mExternalState = newState;
- loge("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
+ log("setExternalState: set mPhoneId=" + mPhoneId + " mExternalState=" + mExternalState);
mTelephonyManager.setSimStateForPhone(mPhoneId, getState().toString());
// For locked states, we should be sending internal broadcast.
- if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(getIccStateIntentString(mExternalState))) {
+ if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(
+ getIccStateIntentString(mExternalState))) {
broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState),
getIccStateReason(mExternalState));
} else {
@@ -937,7 +976,7 @@
pw.println(" mUiccApplication=" + mUiccApplication);
pw.println(" mIccRecords=" + mIccRecords);
pw.println(" mCdmaSSM=" + mCdmaSSM);
- pw.println(" mRadioOn=" + mRadioOn);
+ pw.println(" mRadioState=" + mRadioState);
pw.println(" mQuietMode=" + mQuietMode);
pw.println(" mInitialized=" + mInitialized);
pw.println(" mExternalState=" + mExternalState);
diff --git a/src/java/com/android/internal/telephony/uicc/IccCardStatus.java b/src/java/com/android/internal/telephony/uicc/IccCardStatus.java
index 8992e9f..f14f21d 100644
--- a/src/java/com/android/internal/telephony/uicc/IccCardStatus.java
+++ b/src/java/com/android/internal/telephony/uicc/IccCardStatus.java
@@ -116,30 +116,33 @@
StringBuilder sb = new StringBuilder();
sb.append("IccCardState {").append(mCardState).append(",")
.append(mUniversalPinState)
- .append(",num_apps=").append(mApplications.length)
- .append(",gsm_id=").append(mGsmUmtsSubscriptionAppIndex);
- if (mGsmUmtsSubscriptionAppIndex >=0
- && mGsmUmtsSubscriptionAppIndex <CARD_MAX_APPS) {
+ .append(",num_apps=").append(mApplications.length);
+
+ sb.append(",gsm_id=").append(mGsmUmtsSubscriptionAppIndex);
+ if (mApplications != null
+ && mGsmUmtsSubscriptionAppIndex >= 0
+ && mGsmUmtsSubscriptionAppIndex < mApplications.length) {
app = mApplications[mGsmUmtsSubscriptionAppIndex];
sb.append(app == null ? "null" : app);
}
sb.append(",cdma_id=").append(mCdmaSubscriptionAppIndex);
- if (mCdmaSubscriptionAppIndex >=0
- && mCdmaSubscriptionAppIndex <CARD_MAX_APPS) {
+ if (mApplications != null
+ && mCdmaSubscriptionAppIndex >= 0
+ && mCdmaSubscriptionAppIndex < mApplications.length) {
app = mApplications[mCdmaSubscriptionAppIndex];
sb.append(app == null ? "null" : app);
}
sb.append(",ims_id=").append(mImsSubscriptionAppIndex);
- if (mImsSubscriptionAppIndex >=0
- && mImsSubscriptionAppIndex <CARD_MAX_APPS) {
+ if (mApplications != null
+ && mImsSubscriptionAppIndex >= 0
+ && mImsSubscriptionAppIndex < mApplications.length) {
app = mApplications[mImsSubscriptionAppIndex];
sb.append(app == null ? "null" : app);
}
sb.append("}");
-
return sb.toString();
}
diff --git a/src/java/com/android/internal/telephony/uicc/IccConstants.java b/src/java/com/android/internal/telephony/uicc/IccConstants.java
index 970bf35..0f41f1e 100644
--- a/src/java/com/android/internal/telephony/uicc/IccConstants.java
+++ b/src/java/com/android/internal/telephony/uicc/IccConstants.java
@@ -97,11 +97,6 @@
//Search interval for higher priority PLMNs
static final int EF_HPPLMN = 0x6F31;
- // SMS record length from TS 51.011 10.5.3
- static public final int SMS_RECORD_LENGTH = 176;
- // SMS record length from C.S0023 3.4.27
- static public final int CDMA_SMS_RECORD_LENGTH = 255;
-
static final String MF_SIM = "3F00";
static final String DF_TELECOM = "7F10";
static final String DF_PHONEBOOK = "5F3A";
diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java
index cf33498..af26f5c 100644
--- a/src/java/com/android/internal/telephony/uicc/IccRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java
@@ -78,15 +78,20 @@
protected String mNewVoiceMailTag = null;
protected boolean mIsVoiceMailFixed = false;
protected String mImsi;
+ protected String mFakeImsi;
private IccIoResult auth_rsp;
protected int mMncLength = UNINITIALIZED;
protected int mMailboxIndex = 0; // 0 is no mailbox dailing number associated
private String mSpn;
+ private String mFakeSpn;
protected String mGid1;
+ protected String mFakeGid1;
protected String mGid2;
+ protected String mFakeGid2;
+
protected String mPrefLang;
protected PlmnActRecord[] mHplmnActRecords;
@@ -98,6 +103,8 @@
private final Object mLock = new Object();
+ CarrierTestOverride mCarrierTestOverride;
+
//Arbitrary offset for the Handler
protected static final int HANDLER_ACTION_BASE = 0x12E500;
protected static final int HANDLER_ACTION_NONE = HANDLER_ACTION_BASE + 0;
@@ -157,9 +164,13 @@
+ " isVoiceMailFixed=" + mIsVoiceMailFixed
+ " mImsi=" + ((mImsi != null) ?
mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)) : "null")
+ + (mCarrierTestOverride.isInTestMode()
+ ? (" mFakeImsi=" + ((mFakeImsi != null) ? mFakeImsi : "null")) : "")
+ " mncLength=" + mMncLength
+ " mailboxIndex=" + mMailboxIndex
- + " spn=" + mSpn;
+ + " spn=" + mSpn
+ + (mCarrierTestOverride.isInTestMode()
+ ? (" mFakeSpn=" + ((mFakeSpn != null) ? mFakeSpn : "null")) : "");
}
@@ -187,6 +198,22 @@
mParentApp = app;
mTelephonyManager = (TelephonyManager) mContext.getSystemService(
Context.TELEPHONY_SERVICE);
+
+ mCarrierTestOverride = new CarrierTestOverride();
+
+ if (mCarrierTestOverride.isInTestMode()) {
+ mFakeImsi = mCarrierTestOverride.getFakeIMSI();
+ log("load mFakeImsi: " + mFakeImsi);
+
+ mFakeGid1 = mCarrierTestOverride.getFakeGid1();
+ log("load mFakeGid1: " + mFakeGid1);
+
+ mFakeGid2 = mCarrierTestOverride.getFakeGid2();
+ log("load mFakeGid2: " + mFakeGid2);
+
+ mFakeSpn = mCarrierTestOverride.getFakeSpn();
+ log("load mFakeSpn: " + mFakeSpn);
+ }
}
/**
@@ -279,7 +306,7 @@
Registrant r = new Registrant(h, what, obj);
mImsiReadyRegistrants.add(r);
- if (mImsi != null) {
+ if (getIMSI() != null) {
r.notifyRegistrant(new AsyncResult(null, null, null));
}
}
@@ -325,7 +352,11 @@
* @return null if SIM is not yet ready or unavailable
*/
public String getIMSI() {
- return null;
+ if (mCarrierTestOverride.isInTestMode() && mFakeImsi != null) {
+ return mFakeImsi;
+ } else {
+ return mImsi;
+ }
}
/**
@@ -356,7 +387,11 @@
* @return null if SIM is not yet ready
*/
public String getGid1() {
- return null;
+ if (mCarrierTestOverride.isInTestMode() && mFakeGid1 != null) {
+ return mFakeGid1;
+ } else {
+ return mGid1;
+ }
}
/**
@@ -364,7 +399,11 @@
* @return null if SIM is not yet ready
*/
public String getGid2() {
- return null;
+ if (mCarrierTestOverride.isInTestMode() && mFakeGid2 != null) {
+ return mFakeGid2;
+ } else {
+ return mGid2;
+ }
}
public void setMsisdnNumber(String alphaTag, String number,
@@ -390,6 +429,9 @@
* @return null if SIM is not yet ready or no RUIM entry
*/
public String getServiceProviderName() {
+ if (mCarrierTestOverride.isInTestMode() && mFakeSpn != null) {
+ return mFakeSpn;
+ }
String providerName = mSpn;
// Check for null pointers, mParentApp can be null after dispose,
@@ -476,6 +518,7 @@
*/
protected void onIccRefreshInit() {
mAdnCache.reset();
+ mMncLength = UNINITIALIZED;
UiccCardApplication parentApp = mParentApp;
if ((parentApp != null) &&
(parentApp.getState() == AppState.APPSTATE_READY)) {
@@ -777,9 +820,15 @@
pw.println(" mIsVoiceMailFixed=" + mIsVoiceMailFixed);
pw.println(" mImsi=" + ((mImsi != null) ?
mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)) : "null"));
+ if (mCarrierTestOverride.isInTestMode()) {
+ pw.println(" mFakeImsi=" + ((mFakeImsi != null) ? mFakeImsi : "null"));
+ }
pw.println(" mMncLength=" + mMncLength);
pw.println(" mMailboxIndex=" + mMailboxIndex);
pw.println(" mSpn=" + mSpn);
+ if (mCarrierTestOverride.isInTestMode()) {
+ pw.println(" mFakeSpn=" + ((mFakeSpn != null) ? mFakeSpn : "null"));
+ }
pw.flush();
}
}
diff --git a/src/java/com/android/internal/telephony/uicc/IccUtils.java b/src/java/com/android/internal/telephony/uicc/IccUtils.java
deleted file mode 100644
index 67de87f..0000000
--- a/src/java/com/android/internal/telephony/uicc/IccUtils.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony.uicc;
-
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.telephony.Rlog;
-
-import com.android.internal.telephony.GsmAlphabet;
-
-import java.io.UnsupportedEncodingException;
-
-/**
- * Various methods, useful for dealing with SIM data.
- */
-public class IccUtils {
- static final String LOG_TAG="IccUtils";
-
- /**
- * Many fields in GSM SIM's are stored as nibble-swizzled BCD
- *
- * Assumes left-justified field that may be padded right with 0xf
- * values.
- *
- * Stops on invalid BCD value, returning string so far
- */
- public static String
- bcdToString(byte[] data, int offset, int length) {
- StringBuilder ret = new StringBuilder(length*2);
-
- for (int i = offset ; i < offset + length ; i++) {
- int v;
-
- v = data[i] & 0xf;
- if (v > 9) break;
- ret.append((char)('0' + v));
-
- v = (data[i] >> 4) & 0xf;
- // Some PLMNs have 'f' as high nibble, ignore it
- if (v == 0xf) continue;
- if (v > 9) break;
- ret.append((char)('0' + v));
- }
-
- return ret.toString();
- }
-
- /**
- * PLMN (MCC/MNC) is encoded as per 24.008 10.5.1.3
- * Returns a concatenated string of MCC+MNC, stripping
- * a trailing character for a 2-digit MNC
- */
- public static String bcdPlmnToString(byte[] data, int offset) {
- if (offset + 3 > data.length) {
- return null;
- }
- byte[] trans = new byte[3];
- trans[0] = (byte) ((data[0 + offset] << 4) | ((data[0 + offset] >> 4) & 0xF));
- trans[1] = (byte) ((data[1 + offset] << 4) | (data[2 + offset] & 0xF));
- trans[2] = (byte) ((data[2 + offset] & 0xF0) | ((data[1 + offset] >> 4) & 0xF));
- String ret = bytesToHexString(trans);
-
- // For a 2-digit MNC we trim the trailing 'f'
- if (ret.endsWith("f")) {
- ret = ret.substring(0, ret.length() - 1);
- }
- return ret;
- }
-
- /**
- * Some fields (like ICC ID) in GSM SIMs are stored as nibble-swizzled BCH
- */
- public static String
- bchToString(byte[] data, int offset, int length) {
- StringBuilder ret = new StringBuilder(length*2);
-
- for (int i = offset ; i < offset + length ; i++) {
- int v;
-
- v = data[i] & 0xf;
- ret.append("0123456789abcdef".charAt(v));
-
- v = (data[i] >> 4) & 0xf;
- ret.append("0123456789abcdef".charAt(v));
- }
-
- return ret.toString();
- }
-
- /**
- * Decode cdma byte into String.
- */
- public static String
- cdmaBcdToString(byte[] data, int offset, int length) {
- StringBuilder ret = new StringBuilder(length);
-
- int count = 0;
- for (int i = offset; count < length; i++) {
- int v;
- v = data[i] & 0xf;
- if (v > 9) v = 0;
- ret.append((char)('0' + v));
-
- if (++count == length) break;
-
- v = (data[i] >> 4) & 0xf;
- if (v > 9) v = 0;
- ret.append((char)('0' + v));
- ++count;
- }
- return ret.toString();
- }
-
- /**
- * Decodes a GSM-style BCD byte, returning an int ranging from 0-99.
- *
- * In GSM land, the least significant BCD digit is stored in the most
- * significant nibble.
- *
- * Out-of-range digits are treated as 0 for the sake of the time stamp,
- * because of this:
- *
- * TS 23.040 section 9.2.3.11
- * "if the MS receives a non-integer value in the SCTS, it shall
- * assume the digit is set to 0 but shall store the entire field
- * exactly as received"
- */
- public static int
- gsmBcdByteToInt(byte b) {
- int ret = 0;
-
- // treat out-of-range BCD values as 0
- if ((b & 0xf0) <= 0x90) {
- ret = (b >> 4) & 0xf;
- }
-
- if ((b & 0x0f) <= 0x09) {
- ret += (b & 0xf) * 10;
- }
-
- return ret;
- }
-
- /**
- * Decodes a CDMA style BCD byte like {@link #gsmBcdByteToInt}, but
- * opposite nibble format. The least significant BCD digit
- * is in the least significant nibble and the most significant
- * is in the most significant nibble.
- */
- public static int
- cdmaBcdByteToInt(byte b) {
- int ret = 0;
-
- // treat out-of-range BCD values as 0
- if ((b & 0xf0) <= 0x90) {
- ret = ((b >> 4) & 0xf) * 10;
- }
-
- if ((b & 0x0f) <= 0x09) {
- ret += (b & 0xf);
- }
-
- return ret;
- }
-
- /**
- * Decodes a string field that's formatted like the EF[ADN] alpha
- * identifier
- *
- * From TS 51.011 10.5.1:
- * Coding:
- * this alpha tagging shall use either
- * - the SMS default 7 bit coded alphabet as defined in
- * TS 23.038 [12] with bit 8 set to 0. The alpha identifier
- * shall be left justified. Unused bytes shall be set to 'FF'; or
- * - one of the UCS2 coded options as defined in annex B.
- *
- * Annex B from TS 11.11 V8.13.0:
- * 1) If the first octet in the alpha string is '80', then the
- * remaining octets are 16 bit UCS2 characters ...
- * 2) if the first octet in the alpha string is '81', then the
- * second octet contains a value indicating the number of
- * characters in the string, and the third octet contains an
- * 8 bit number which defines bits 15 to 8 of a 16 bit
- * base pointer, where bit 16 is set to zero and bits 7 to 1
- * are also set to zero. These sixteen bits constitute a
- * base pointer to a "half page" in the UCS2 code space, to be
- * used with some or all of the remaining octets in the string.
- * The fourth and subsequent octets contain codings as follows:
- * If bit 8 of the octet is set to zero, the remaining 7 bits
- * of the octet contain a GSM Default Alphabet character,
- * whereas if bit 8 of the octet is set to one, then the
- * remaining seven bits are an offset value added to the
- * 16 bit base pointer defined earlier...
- * 3) If the first octet of the alpha string is set to '82', then
- * the second octet contains a value indicating the number of
- * characters in the string, and the third and fourth octets
- * contain a 16 bit number which defines the complete 16 bit
- * base pointer to a "half page" in the UCS2 code space...
- */
- public static String
- adnStringFieldToString(byte[] data, int offset, int length) {
- if (length == 0) {
- return "";
- }
- if (length >= 1) {
- if (data[offset] == (byte) 0x80) {
- int ucslen = (length - 1) / 2;
- String ret = null;
-
- try {
- ret = new String(data, offset + 1, ucslen * 2, "utf-16be");
- } catch (UnsupportedEncodingException ex) {
- Rlog.e(LOG_TAG, "implausible UnsupportedEncodingException",
- ex);
- }
-
- if (ret != null) {
- // trim off trailing FFFF characters
-
- ucslen = ret.length();
- while (ucslen > 0 && ret.charAt(ucslen - 1) == '\uFFFF')
- ucslen--;
-
- return ret.substring(0, ucslen);
- }
- }
- }
-
- boolean isucs2 = false;
- char base = '\0';
- int len = 0;
-
- if (length >= 3 && data[offset] == (byte) 0x81) {
- len = data[offset + 1] & 0xFF;
- if (len > length - 3)
- len = length - 3;
-
- base = (char) ((data[offset + 2] & 0xFF) << 7);
- offset += 3;
- isucs2 = true;
- } else if (length >= 4 && data[offset] == (byte) 0x82) {
- len = data[offset + 1] & 0xFF;
- if (len > length - 4)
- len = length - 4;
-
- base = (char) (((data[offset + 2] & 0xFF) << 8) |
- (data[offset + 3] & 0xFF));
- offset += 4;
- isucs2 = true;
- }
-
- if (isucs2) {
- StringBuilder ret = new StringBuilder();
-
- while (len > 0) {
- // UCS2 subset case
-
- if (data[offset] < 0) {
- ret.append((char) (base + (data[offset] & 0x7F)));
- offset++;
- len--;
- }
-
- // GSM character set case
-
- int count = 0;
- while (count < len && data[offset + count] >= 0)
- count++;
-
- ret.append(GsmAlphabet.gsm8BitUnpackedToString(data,
- offset, count));
-
- offset += count;
- len -= count;
- }
-
- return ret.toString();
- }
-
- Resources resource = Resources.getSystem();
- String defaultCharset = "";
- try {
- defaultCharset =
- resource.getString(com.android.internal.R.string.gsm_alphabet_default_charset);
- } catch (NotFoundException e) {
- // Ignore Exception and defaultCharset is set to a empty string.
- }
- return GsmAlphabet.gsm8BitUnpackedToString(data, offset, length, defaultCharset.trim());
- }
-
- static int
- hexCharToInt(char c) {
- if (c >= '0' && c <= '9') return (c - '0');
- if (c >= 'A' && c <= 'F') return (c - 'A' + 10);
- if (c >= 'a' && c <= 'f') return (c - 'a' + 10);
-
- throw new RuntimeException ("invalid hex char '" + c + "'");
- }
-
- /**
- * Converts a hex String to a byte array.
- *
- * @param s A string of hexadecimal characters, must be an even number of
- * chars long
- *
- * @return byte array representation
- *
- * @throws RuntimeException on invalid format
- */
- public static byte[]
- hexStringToBytes(String s) {
- byte[] ret;
-
- if (s == null) return null;
-
- int sz = s.length();
-
- ret = new byte[sz/2];
-
- for (int i=0 ; i <sz ; i+=2) {
- ret[i/2] = (byte) ((hexCharToInt(s.charAt(i)) << 4)
- | hexCharToInt(s.charAt(i+1)));
- }
-
- return ret;
- }
-
-
- /**
- * Converts a byte array into a String of hexadecimal characters.
- *
- * @param bytes an array of bytes
- *
- * @return hex string representation of bytes array
- */
- public static String
- bytesToHexString(byte[] bytes) {
- if (bytes == null) return null;
-
- StringBuilder ret = new StringBuilder(2*bytes.length);
-
- for (int i = 0 ; i < bytes.length ; i++) {
- int b;
-
- b = 0x0f & (bytes[i] >> 4);
-
- ret.append("0123456789abcdef".charAt(b));
-
- b = 0x0f & bytes[i];
-
- ret.append("0123456789abcdef".charAt(b));
- }
-
- return ret.toString();
- }
-
-
- /**
- * Convert a TS 24.008 Section 10.5.3.5a Network Name field to a string
- * "offset" points to "octet 3", the coding scheme byte
- * empty string returned on decode error
- */
- public static String
- networkNameToString(byte[] data, int offset, int length) {
- String ret;
-
- if ((data[offset] & 0x80) != 0x80 || length < 1) {
- return "";
- }
-
- switch ((data[offset] >>> 4) & 0x7) {
- case 0:
- // SMS character set
- int countSeptets;
- int unusedBits = data[offset] & 7;
- countSeptets = (((length - 1) * 8) - unusedBits) / 7 ;
- ret = GsmAlphabet.gsm7BitPackedToString(data, offset + 1, countSeptets);
- break;
- case 1:
- // UCS2
- try {
- ret = new String(data,
- offset + 1, length - 1, "utf-16");
- } catch (UnsupportedEncodingException ex) {
- ret = "";
- Rlog.e(LOG_TAG,"implausible UnsupportedEncodingException", ex);
- }
- break;
-
- // unsupported encoding
- default:
- ret = "";
- break;
- }
-
- // "Add CI"
- // "The MS should add the letters for the Country's Initials and
- // a separator (e.g. a space) to the text string"
-
- if ((data[offset] & 0x40) != 0) {
- // FIXME(mkf) add country initials here
-
- }
-
- return ret;
- }
-
- /**
- * Convert a TS 131.102 image instance of code scheme '11' into Bitmap
- * @param data The raw data
- * @param length The length of image body
- * @return The bitmap
- */
- public static Bitmap parseToBnW(byte[] data, int length){
- int valueIndex = 0;
- int width = data[valueIndex++] & 0xFF;
- int height = data[valueIndex++] & 0xFF;
- int numOfPixels = width*height;
-
- int[] pixels = new int[numOfPixels];
-
- int pixelIndex = 0;
- int bitIndex = 7;
- byte currentByte = 0x00;
- while (pixelIndex < numOfPixels) {
- // reassign data and index for every byte (8 bits).
- if (pixelIndex % 8 == 0) {
- currentByte = data[valueIndex++];
- bitIndex = 7;
- }
- pixels[pixelIndex++] = bitToRGB((currentByte >> bitIndex-- ) & 0x01);
- }
-
- if (pixelIndex != numOfPixels) {
- Rlog.e(LOG_TAG, "parse end and size error");
- }
- return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888);
- }
-
- private static int bitToRGB(int bit){
- if(bit == 1){
- return Color.WHITE;
- } else {
- return Color.BLACK;
- }
- }
-
- /**
- * a TS 131.102 image instance of code scheme '11' into color Bitmap
- *
- * @param data The raw data
- * @param length the length of image body
- * @param transparency with or without transparency
- * @return The color bitmap
- */
- public static Bitmap parseToRGB(byte[] data, int length,
- boolean transparency) {
- int valueIndex = 0;
- int width = data[valueIndex++] & 0xFF;
- int height = data[valueIndex++] & 0xFF;
- int bits = data[valueIndex++] & 0xFF;
- int colorNumber = data[valueIndex++] & 0xFF;
- int clutOffset = ((data[valueIndex++] & 0xFF) << 8)
- | (data[valueIndex++] & 0xFF);
-
- int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber);
- if (true == transparency) {
- colorIndexArray[colorNumber - 1] = Color.TRANSPARENT;
- }
-
- int[] resultArray = null;
- if (0 == (8 % bits)) {
- resultArray = mapTo2OrderBitColor(data, valueIndex,
- (width * height), colorIndexArray, bits);
- } else {
- resultArray = mapToNon2OrderBitColor(data, valueIndex,
- (width * height), colorIndexArray, bits);
- }
-
- return Bitmap.createBitmap(resultArray, width, height,
- Bitmap.Config.RGB_565);
- }
-
- private static int[] mapTo2OrderBitColor(byte[] data, int valueIndex,
- int length, int[] colorArray, int bits) {
- if (0 != (8 % bits)) {
- Rlog.e(LOG_TAG, "not event number of color");
- return mapToNon2OrderBitColor(data, valueIndex, length, colorArray,
- bits);
- }
-
- int mask = 0x01;
- switch (bits) {
- case 1:
- mask = 0x01;
- break;
- case 2:
- mask = 0x03;
- break;
- case 4:
- mask = 0x0F;
- break;
- case 8:
- mask = 0xFF;
- break;
- }
-
- int[] resultArray = new int[length];
- int resultIndex = 0;
- int run = 8 / bits;
- while (resultIndex < length) {
- byte tempByte = data[valueIndex++];
- for (int runIndex = 0; runIndex < run; ++runIndex) {
- int offset = run - runIndex - 1;
- resultArray[resultIndex++] = colorArray[(tempByte >> (offset * bits))
- & mask];
- }
- }
- return resultArray;
- }
-
- private static int[] mapToNon2OrderBitColor(byte[] data, int valueIndex,
- int length, int[] colorArray, int bits) {
- if (0 == (8 % bits)) {
- Rlog.e(LOG_TAG, "not odd number of color");
- return mapTo2OrderBitColor(data, valueIndex, length, colorArray,
- bits);
- }
-
- int[] resultArray = new int[length];
- // TODO fix me:
- return resultArray;
- }
-
- private static int[] getCLUT(byte[] rawData, int offset, int number) {
- if (null == rawData) {
- return null;
- }
-
- int[] result = new int[number];
- int endIndex = offset + (number * 3); // 1 color use 3 bytes
- int valueIndex = offset;
- int colorIndex = 0;
- int alpha = 0xff << 24;
- do {
- result[colorIndex++] = alpha
- | ((rawData[valueIndex++] & 0xFF) << 16)
- | ((rawData[valueIndex++] & 0xFF) << 8)
- | ((rawData[valueIndex++] & 0xFF));
- } while (valueIndex < endIndex);
- return result;
- }
-}
diff --git a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java
index 83f7e02..194d259 100644
--- a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java
@@ -16,13 +16,18 @@
package com.android.internal.telephony.uicc;
+import static com.android.internal.telephony.uicc.IccConstants.EF_DOMAIN;
+import static com.android.internal.telephony.uicc.IccConstants.EF_IMPI;
+import static com.android.internal.telephony.uicc.IccConstants.EF_IMPU;
+import static com.android.internal.telephony.uicc.IccConstants.EF_IST;
+import static com.android.internal.telephony.uicc.IccConstants.EF_PCSCF;
+
import android.content.Context;
+import android.content.Intent;
import android.os.AsyncResult;
-import android.os.Handler;
import android.os.Message;
import android.telephony.Rlog;
-import android.content.Intent;
-
+import android.text.TextUtils;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.gsm.SimTlv;
@@ -34,12 +39,6 @@
import java.util.ArrayList;
import java.util.Arrays;
-import static com.android.internal.telephony.uicc.IccConstants.EF_DOMAIN;
-import static com.android.internal.telephony.uicc.IccConstants.EF_IMPI;
-import static com.android.internal.telephony.uicc.IccConstants.EF_IMPU;
-import static com.android.internal.telephony.uicc.IccConstants.EF_IST;
-import static com.android.internal.telephony.uicc.IccConstants.EF_PCSCF;
-
/**
* {@hide}
*/
@@ -349,8 +348,8 @@
return;
}
- if (refreshResponse.aid != null &&
- !refreshResponse.aid.equals(mParentApp.getAid())) {
+ if (!TextUtils.isEmpty(refreshResponse.aid)
+ && !refreshResponse.aid.equals(mParentApp.getAid())) {
// This is for different app. Ignore.
if (DBG) log("handleIsimRefresh received different app");
return;
diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
index 4e486d2..b303ca8 100644
--- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java
@@ -18,31 +18,31 @@
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_TEST_CSIM;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Locale;
import android.content.Context;
+import android.content.res.Resources;
import android.os.AsyncResult;
import android.os.Message;
import android.os.SystemProperties;
+import android.telephony.Rlog;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
-import android.telephony.Rlog;
import android.text.TextUtils;
import android.util.Log;
-import android.content.res.Resources;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.MccTable;
import com.android.internal.telephony.SubscriptionController;
-
import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
import com.android.internal.util.BitwiseInputStream;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Locale;
+
/**
* {@hide}
*/
@@ -153,11 +153,6 @@
mRecordsRequested = false;
}
- @Override
- public String getIMSI() {
- return mImsi;
- }
-
public String getMdnNumber() {
return mMyMobileNumber;
}
@@ -215,21 +210,23 @@
* provided the RUIM card. Returns null of RUIM is not yet ready
*/
public String getRUIMOperatorNumeric() {
- if (mImsi == null) {
+ String imsi = getIMSI();
+
+ if (imsi == null) {
return null;
}
if (mMncLength != UNINITIALIZED && mMncLength != UNKNOWN) {
// Length = length of MCC + length of MNC
// length of mcc = 3 (3GPP2 C.S0005 - Section 2.3)
- return mImsi.substring(0, 3 + mMncLength);
+ return imsi.substring(0, 3 + mMncLength);
}
// Guess the MNC length based on the MCC if we don't
// have a valid value in ef[ad]
- int mcc = Integer.parseInt(mImsi.substring(0,3));
- return mImsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
+ int mcc = Integer.parseInt(imsi.substring(0, 3));
+ return imsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc));
}
// Refer to ETSI TS 102.221
@@ -774,12 +771,14 @@
log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping");
}
- if (!TextUtils.isEmpty(mImsi)) {
- log("onAllRecordsLoaded set mcc imsi=" + (VDBG ? ("=" + mImsi) : ""));
+ String imsi = getIMSI();
+
+ if (!TextUtils.isEmpty(imsi)) {
+ log("onAllRecordsLoaded set mcc imsi=" + (VDBG ? ("=" + imsi) : ""));
mTelephonyManager.setSimCountryIsoForPhone(
mParentApp.getPhoneId(),
MccTable.countryCodeForMcc(
- Integer.parseInt(mImsi.substring(0,3))));
+ Integer.parseInt(imsi.substring(0, 3))));
} else {
log("onAllRecordsLoaded empty imsi skipping setting mcc");
}
@@ -796,9 +795,9 @@
// TODO: The below is hacky since the SubscriptionController may not be ready at this time.
if (!TextUtils.isEmpty(mMdn)) {
int phoneId = mParentApp.getUiccCard().getPhoneId();
- int[] subIds = SubscriptionController.getInstance().getSubId(phoneId);
- if (subIds != null) {
- SubscriptionManager.from(mContext).setDisplayNumber(mMdn, subIds[0]);
+ int subId = SubscriptionController.getInstance().getSubIdUsingPhoneId(phoneId);
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ SubscriptionManager.from(mContext).setDisplayNumber(mMdn, subId);
} else {
log("Cannot call setDisplayNumber: invalid subId");
}
@@ -918,8 +917,8 @@
return;
}
- if (refreshResponse.aid != null &&
- !refreshResponse.aid.equals(mParentApp.getAid())) {
+ if (!TextUtils.isEmpty(refreshResponse.aid)
+ && !refreshResponse.aid.equals(mParentApp.getAid())) {
// This is for different app. Ignore.
return;
}
diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
index 61ce151..dad1ee2 100755
--- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java
+++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java
@@ -33,7 +33,6 @@
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.MccTable;
import com.android.internal.telephony.SmsConstants;
-import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.gsm.SimTlv;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
@@ -251,6 +250,7 @@
mCi.unSetOnSmsOnSim(this);
mParentApp.unregisterForReady(this);
mParentApp.unregisterForLocked(this);
+ mContext.unregisterReceiver(mReceiver);
resetRecords();
super.dispose();
}
@@ -296,33 +296,14 @@
mRecordsRequested = false;
}
-
//***** Public Methods
- /**
- * {@inheritDoc}
- */
- @Override
- public String getIMSI() {
- return mImsi;
- }
-
@Override
public String getMsisdnNumber() {
return mMsisdn;
}
@Override
- public String getGid1() {
- return mGid1;
- }
-
- @Override
- public String getGid2() {
- return mGid2;
- }
-
- @Override
public UsimServiceTable getUsimServiceTable() {
return mUsimServiceTable;
}
@@ -582,7 +563,8 @@
// Spec reference for EF_CFIS contents, TS 51.011 section 10.3.46.
if (enable && !TextUtils.isEmpty(dialNumber)) {
logv("EF_CFIS: updating cf number, " + Rlog.pii(LOG_TAG, dialNumber));
- byte[] bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(dialNumber);
+ byte[] bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(
+ dialNumber, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
System.arraycopy(bcdNumber, 0, mEfCfis, CFIS_TON_NPI_OFFSET, bcdNumber.length);
@@ -639,7 +621,8 @@
*/
@Override
public String getOperatorNumeric() {
- if (mImsi == null) {
+ String imsi = getIMSI();
+ if (imsi == null) {
log("getOperatorNumeric: IMSI == null");
return null;
}
@@ -650,7 +633,11 @@
// Length = length of MCC + length of MNC
// length of mcc = 3 (TS 23.003 Section 2.2)
- return mImsi.substring(0, 3 + mMncLength);
+ if (imsi.length() >= 3 + mMncLength) {
+ return imsi.substring(0, 3 + mMncLength);
+ } else {
+ return null;
+ }
}
// ***** Overridden from Handler
@@ -700,11 +687,17 @@
}
log("IMSI: mMncLength=" + mMncLength);
- log("IMSI: " + mImsi.substring(0, 6) + Rlog.pii(LOG_TAG, mImsi.substring(6)));
+
+ if (mImsi != null && mImsi.length() >= 6) {
+ log("IMSI: " + mImsi.substring(0, 6)
+ + Rlog.pii(LOG_TAG, mImsi.substring(6)));
+ }
+
+ String imsi = getIMSI();
if (((mMncLength == UNKNOWN) || (mMncLength == 2))
- && ((mImsi != null) && (mImsi.length() >= 6))) {
- String mccmncCode = mImsi.substring(0, 6);
+ && ((imsi != null) && (imsi.length() >= 6))) {
+ String mccmncCode = imsi.substring(0, 6);
for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
if (mccmnc.equals(mccmncCode)) {
mMncLength = 3;
@@ -718,7 +711,7 @@
// the SIM has told us all it knows, but it didn't know the mnc length.
// guess using the mcc
try {
- int mcc = Integer.parseInt(mImsi.substring(0, 3));
+ int mcc = Integer.parseInt(imsi.substring(0, 3));
mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
log("setting2 mMncLength=" + mMncLength);
} catch (NumberFormatException e) {
@@ -727,12 +720,13 @@
}
}
- if (mMncLength != UNKNOWN && mMncLength != UNINITIALIZED) {
- log("update mccmnc=" + mImsi.substring(0, 3 + mMncLength));
+ if (mMncLength != UNKNOWN && mMncLength != UNINITIALIZED
+ && imsi.length() >= 3 + mMncLength) {
+ log("update mccmnc=" + imsi.substring(0, 3 + mMncLength));
// finally have both the imsi and the mncLength and
// can parse the imsi properly
MccTable.updateMccMncConfiguration(mContext,
- mImsi.substring(0, 3 + mMncLength), false);
+ imsi.substring(0, 3 + mMncLength), false);
}
mImsiReadyRegistrants.notifyRegistrants();
break;
@@ -926,28 +920,40 @@
try {
isRecordLoadResponse = true;
- ar = (AsyncResult) msg.obj;
- data = (byte[]) ar.result;
+ if (mCarrierTestOverride.isInTestMode() && getIMSI() != null) {
+ imsi = getIMSI();
+ try {
+ int mcc = Integer.parseInt(imsi.substring(0, 3));
+ mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
+ log("[TestMode] mMncLength=" + mMncLength);
+ } catch (NumberFormatException e) {
+ mMncLength = UNKNOWN;
+ loge("[TestMode] Corrupt IMSI! mMncLength=" + mMncLength);
+ }
+ } else {
+ ar = (AsyncResult) msg.obj;
+ data = (byte[]) ar.result;
- if (ar.exception != null) {
- break;
+ if (ar.exception != null) {
+ break;
+ }
+
+ log("EF_AD: " + IccUtils.bytesToHexString(data));
+
+ if (data.length < 3) {
+ log("Corrupt AD data on SIM");
+ break;
+ }
+
+ if (data.length == 3) {
+ log("MNC length not present in EF_AD");
+ break;
+ }
+
+ mMncLength = data[3] & 0xf;
+ log("setting4 mMncLength=" + mMncLength);
}
- log("EF_AD: " + IccUtils.bytesToHexString(data));
-
- if (data.length < 3) {
- log("Corrupt AD data on SIM");
- break;
- }
-
- if (data.length == 3) {
- log("MNC length not present in EF_AD");
- break;
- }
-
- mMncLength = data[3] & 0xf;
- log("setting4 mMncLength=" + mMncLength);
-
if (mMncLength == 0xf) {
mMncLength = UNKNOWN;
log("setting5 mMncLength=" + mMncLength);
@@ -956,10 +962,14 @@
log("setting5 mMncLength=" + mMncLength);
}
} finally {
+
+ // IMSI could be a value reading from Sim or a fake IMSI if in the test mode
+ imsi = getIMSI();
+
if (((mMncLength == UNINITIALIZED) || (mMncLength == UNKNOWN)
- || (mMncLength == 2)) && ((mImsi != null)
- && (mImsi.length() >= 6))) {
- String mccmncCode = mImsi.substring(0, 6);
+ || (mMncLength == 2)) && ((imsi != null)
+ && (imsi.length() >= 6))) {
+ String mccmncCode = imsi.substring(0, 6);
log("mccmncCode=" + mccmncCode);
for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
if (mccmnc.equals(mccmncCode)) {
@@ -971,9 +981,9 @@
}
if (mMncLength == UNKNOWN || mMncLength == UNINITIALIZED) {
- if (mImsi != null) {
+ if (imsi != null) {
try {
- int mcc = Integer.parseInt(mImsi.substring(0, 3));
+ int mcc = Integer.parseInt(imsi.substring(0, 3));
mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
log("setting7 mMncLength=" + mMncLength);
@@ -988,12 +998,13 @@
+ "mMncLength=" + mMncLength);
}
}
- if (mImsi != null && mMncLength != UNKNOWN) {
+ if (imsi != null && mMncLength != UNKNOWN
+ && imsi.length() >= 3 + mMncLength) {
// finally have both imsi and the length of the mnc and can parse
// the imsi properly
- log("update mccmnc=" + mImsi.substring(0, 3 + mMncLength));
+ log("update mccmnc=" + imsi.substring(0, 3 + mMncLength));
MccTable.updateMccMncConfiguration(mContext,
- mImsi.substring(0, 3 + mMncLength), false);
+ imsi.substring(0, 3 + mMncLength), false);
}
}
break;
@@ -1249,7 +1260,9 @@
mGid1 = null;
break;
}
+
mGid1 = IccUtils.bytesToHexString(data);
+
log("GID1: " + mGid1);
break;
@@ -1264,12 +1277,15 @@
mGid2 = null;
break;
}
+
mGid2 = IccUtils.bytesToHexString(data);
+
log("GID2: " + mGid2);
break;
case EVENT_GET_PLMN_W_ACT_DONE:
+ isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
@@ -1284,6 +1300,7 @@
break;
case EVENT_GET_OPLMN_W_ACT_DONE:
+ isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
@@ -1299,6 +1316,7 @@
break;
case EVENT_GET_HPLMN_W_ACT_DONE:
+ isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
@@ -1313,6 +1331,7 @@
break;
case EVENT_GET_EHPLMN_DONE:
+ isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null || data == null) {
@@ -1438,8 +1457,8 @@
return;
}
- if (refreshResponse.aid != null &&
- !refreshResponse.aid.equals(mParentApp.getAid())) {
+ if (!TextUtils.isEmpty(refreshResponse.aid)
+ && !refreshResponse.aid.equals(mParentApp.getAid())) {
// This is for different app. Ignore.
return;
}
@@ -1588,20 +1607,19 @@
if (!TextUtils.isEmpty(operator)) {
log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
operator + "'");
- log("update icc_operator_numeric=" + operator);
mTelephonyManager.setSimOperatorNumericForPhone(
mParentApp.getPhoneId(), operator);
- final SubscriptionController subController = SubscriptionController.getInstance();
- subController.setMccMnc(operator, subController.getDefaultSubId());
} else {
log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping");
}
- if (!TextUtils.isEmpty(mImsi)) {
- log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + mImsi) : ""));
+ String imsi = getIMSI();
+
+ if (!TextUtils.isEmpty(imsi) && imsi.length() >= 3) {
+ log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + imsi) : ""));
mTelephonyManager.setSimCountryIsoForPhone(
mParentApp.getPhoneId(), MccTable.countryCodeForMcc(
- Integer.parseInt(mImsi.substring(0,3))));
+ Integer.parseInt(imsi.substring(0, 3))));
} else {
log("onAllRecordsLoaded empty imsi skipping setting mcc");
}
@@ -1753,12 +1771,16 @@
mRecordsToLoad++;
mFh.loadEFTransparent(EF_PLMN_W_ACT, obtainMessage(EVENT_GET_PLMN_W_ACT_DONE));
+ mRecordsToLoad++;
mFh.loadEFTransparent(EF_OPLMN_W_ACT, obtainMessage(EVENT_GET_OPLMN_W_ACT_DONE));
+ mRecordsToLoad++;
mFh.loadEFTransparent(EF_HPLMN_W_ACT, obtainMessage(EVENT_GET_HPLMN_W_ACT_DONE));
+ mRecordsToLoad++;
mFh.loadEFTransparent(EF_EHPLMN, obtainMessage(EVENT_GET_EHPLMN_DONE));
+ mRecordsToLoad++;
mFh.loadEFTransparent(EF_FPLMN, obtainMessage(
EVENT_GET_FPLMN_DONE, HANDLER_ACTION_NONE, -1));
@@ -1905,7 +1927,7 @@
mSpnDisplayCondition = 0xff & data[0];
setServiceProviderName(IccUtils.adnStringFieldToString(
- data, 1, data.length - 1));
+ data, 1, data.length - 1));
// for card double-check and brand override
// we have to do this:
final String spn = getServiceProviderName();
@@ -1939,7 +1961,7 @@
data = (byte[]) ar.result;
setServiceProviderName(IccUtils.adnStringFieldToString(
- data, 0, data.length));
+ data, 0, data.length));
// for card double-check and brand override
// we have to do this:
final String spn = getServiceProviderName();
@@ -1971,7 +1993,7 @@
data = (byte[]) ar.result;
setServiceProviderName(IccUtils.adnStringFieldToString(
- data, 0, data.length));
+ data, 0, data.length));
// for card double-check and brand override
// we have to do this:
final String spn = getServiceProviderName();
@@ -2029,10 +2051,10 @@
for (int i = 0 ; i + 2 < plmnEntries.length ; i += 3) {
String plmnCode;
- plmnCode = IccUtils.bcdToString(plmnEntries, i, 3);
+ plmnCode = IccUtils.bcdPlmnToString(plmnEntries, i);
// Valid operator codes are 5 or 6 digits
- if (plmnCode.length() >= 5) {
+ if (plmnCode != null && plmnCode.length() >= 5) {
log("EF_SPDI network: " + plmnCode);
mSpdiNetworks.add(plmnCode);
}
@@ -2154,7 +2176,13 @@
pw.println(" mPnnHomeName=" + mPnnHomeName);
pw.println(" mUsimServiceTable=" + mUsimServiceTable);
pw.println(" mGid1=" + mGid1);
+ if (mCarrierTestOverride.isInTestMode()) {
+ pw.println(" mFakeGid1=" + ((mFakeGid1 != null) ? mFakeGid1 : "null"));
+ }
pw.println(" mGid2=" + mGid2);
+ if (mCarrierTestOverride.isInTestMode()) {
+ pw.println(" mFakeGid2=" + ((mFakeGid2 != null) ? mFakeGid2 : "null"));
+ }
pw.println(" mPlmnActRecords[]=" + Arrays.toString(mPlmnActRecords));
pw.println(" mOplmnActRecords[]=" + Arrays.toString(mOplmnActRecords));
pw.println(" mHplmnActRecords[]=" + Arrays.toString(mHplmnActRecords));
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java
index 1a038cf..baad60b 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCard.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java
@@ -44,18 +44,16 @@
import android.util.LocalLog;
import android.view.WindowManager;
+import com.android.internal.R;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.CommandsInterface.RadioState;
+import com.android.internal.telephony.cat.CatService;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
import com.android.internal.telephony.uicc.IccCardStatus.CardState;
import com.android.internal.telephony.uicc.IccCardStatus.PinState;
-import com.android.internal.telephony.cat.CatService;
-
-import com.android.internal.R;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -96,27 +94,19 @@
private static final int EVENT_TRANSMIT_APDU_LOGICAL_CHANNEL_DONE = 17;
private static final int EVENT_TRANSMIT_APDU_BASIC_CHANNEL_DONE = 18;
private static final int EVENT_SIM_IO_DONE = 19;
- private static final int EVENT_CARRIER_PRIVILIGES_LOADED = 20;
+ private static final int EVENT_CARRIER_PRIVILEGES_LOADED = 20;
private static final LocalLog mLocalLog = new LocalLog(100);
- private int mPhoneId;
-
- public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics) {
- if (DBG) log("Creating");
- mCardState = ics.mCardState;
- update(c, ci, ics);
- }
+ private final int mPhoneId;
public UiccCard(Context c, CommandsInterface ci, IccCardStatus ics, int phoneId) {
+ if (DBG) log("Creating");
mCardState = ics.mCardState;
mPhoneId = phoneId;
update(c, ci, ics);
}
- protected UiccCard() {
- }
-
public void dispose() {
synchronized (mLock) {
if (DBG) log("Disposing card");
@@ -162,18 +152,19 @@
}
}
- createAndUpdateCatService();
+ createAndUpdateCatServiceLocked();
// Reload the carrier privilege rules if necessary.
log("Before privilege rules: " + mCarrierPrivilegeRules + " : " + mCardState);
if (mCarrierPrivilegeRules == null && mCardState == CardState.CARDSTATE_PRESENT) {
mCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(this,
- mHandler.obtainMessage(EVENT_CARRIER_PRIVILIGES_LOADED));
- } else if (mCarrierPrivilegeRules != null && mCardState != CardState.CARDSTATE_PRESENT) {
+ mHandler.obtainMessage(EVENT_CARRIER_PRIVILEGES_LOADED));
+ } else if (mCarrierPrivilegeRules != null
+ && mCardState != CardState.CARDSTATE_PRESENT) {
mCarrierPrivilegeRules = null;
}
- sanitizeApplicationIndexes();
+ sanitizeApplicationIndexesLocked();
RadioState radioState = mCi.getRadioState();
if (DBG) log("update: radioState=" + radioState + " mLastRadioState="
@@ -195,13 +186,13 @@
}
}
- protected void createAndUpdateCatService() {
+ private void createAndUpdateCatServiceLocked() {
if (mUiccApplications.length > 0 && mUiccApplications[0] != null) {
// Initialize or Reinitialize CatService
if (mCatService == null) {
mCatService = CatService.getInstance(mCi, mContext, this, mPhoneId);
} else {
- ((CatService)mCatService).update(mCi, mContext, this);
+ mCatService.update(mCi, mContext, this);
}
} else {
if (mCatService != null) {
@@ -211,10 +202,6 @@
}
}
- public CatService getCatService() {
- return mCatService;
- }
-
@Override
protected void finalize() {
if (DBG) log("UiccCard finalized");
@@ -225,16 +212,18 @@
* and resets invalid indexes. (This should never happen, but in case
* RIL misbehaves we need to manage situation gracefully)
*/
- private void sanitizeApplicationIndexes() {
+ private void sanitizeApplicationIndexesLocked() {
mGsmUmtsSubscriptionAppIndex =
- checkIndex(mGsmUmtsSubscriptionAppIndex, AppType.APPTYPE_SIM, AppType.APPTYPE_USIM);
+ checkIndexLocked(
+ mGsmUmtsSubscriptionAppIndex, AppType.APPTYPE_SIM, AppType.APPTYPE_USIM);
mCdmaSubscriptionAppIndex =
- checkIndex(mCdmaSubscriptionAppIndex, AppType.APPTYPE_RUIM, AppType.APPTYPE_CSIM);
+ checkIndexLocked(
+ mCdmaSubscriptionAppIndex, AppType.APPTYPE_RUIM, AppType.APPTYPE_CSIM);
mImsSubscriptionAppIndex =
- checkIndex(mImsSubscriptionAppIndex, AppType.APPTYPE_ISIM, null);
+ checkIndexLocked(mImsSubscriptionAppIndex, AppType.APPTYPE_ISIM, null);
}
- private int checkIndex(int index, AppType expectedAppType, AppType altExpectedAppType) {
+ private int checkIndexLocked(int index, AppType expectedAppType, AppType altExpectedAppType) {
if (mUiccApplications == null || index >= mUiccApplications.length) {
loge("App index " + index + " is invalid since there are no applications");
return -1;
@@ -395,7 +384,7 @@
AsyncResult.forMessage((Message)ar.userObj, ar.result, ar.exception);
((Message)ar.userObj).sendToTarget();
break;
- case EVENT_CARRIER_PRIVILIGES_LOADED:
+ case EVENT_CARRIER_PRIVILEGES_LOADED:
onCarrierPriviligesLoadedMessage();
break;
default:
@@ -562,22 +551,31 @@
synchronized (mLock) {
boolean changed = false;
for (int i = 0; i < mUiccApplications.length; i++) {
- if (mUiccApplications[i] != null &&
- (aid == null || aid.equals(mUiccApplications[i].getAid()))) {
+ if (mUiccApplications[i] != null
+ && (TextUtils.isEmpty(aid) || aid.equals(mUiccApplications[i].getAid()))) {
// Delete removed applications
mUiccApplications[i].dispose();
mUiccApplications[i] = null;
changed = true;
}
}
+ if (TextUtils.isEmpty(aid)) {
+ if (mCarrierPrivilegeRules != null) {
+ mCarrierPrivilegeRules = null;
+ changed = true;
+ }
+ if (mCatService != null) {
+ mCatService.dispose();
+ mCatService = null;
+ changed = true;
+ }
+ }
return changed;
}
- // TODO: For a card level notification, we should delete the CarrierPrivilegeRules and the
- // CAT service.
}
/**
- * Exposes {@link CommandsInterface.iccOpenLogicalChannel}
+ * Exposes {@link CommandsInterface#iccOpenLogicalChannel}
*/
public void iccOpenLogicalChannel(String AID, int p2, Message response) {
loglocal("Open Logical Channel: " + AID + " , " + p2 + " by pid:" + Binder.getCallingPid()
@@ -587,7 +585,7 @@
}
/**
- * Exposes {@link CommandsInterface.iccCloseLogicalChannel}
+ * Exposes {@link CommandsInterface#iccCloseLogicalChannel}
*/
public void iccCloseLogicalChannel(int channel, Message response) {
loglocal("Close Logical Channel: " + channel);
@@ -596,7 +594,7 @@
}
/**
- * Exposes {@link CommandsInterface.iccTransmitApduLogicalChannel}
+ * Exposes {@link CommandsInterface#iccTransmitApduLogicalChannel}
*/
public void iccTransmitApduLogicalChannel(int channel, int cla, int command,
int p1, int p2, int p3, String data, Message response) {
@@ -605,7 +603,7 @@
}
/**
- * Exposes {@link CommandsInterface.iccTransmitApduBasicChannel}
+ * Exposes {@link CommandsInterface#iccTransmitApduBasicChannel}
*/
public void iccTransmitApduBasicChannel(int cla, int command,
int p1, int p2, int p3, String data, Message response) {
@@ -614,7 +612,7 @@
}
/**
- * Exposes {@link CommandsInterface.iccIO}
+ * Exposes {@link CommandsInterface#iccIO}
*/
public void iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
String pathID, Message response) {
@@ -623,7 +621,7 @@
}
/**
- * Exposes {@link CommandsInterface.sendEnvelopeWithStatus}
+ * Exposes {@link CommandsInterface#sendEnvelopeWithStatus}
*/
public void sendEnvelopeWithStatus(String contents, Message response) {
mCi.sendEnvelopeWithStatus(contents, response);
@@ -648,62 +646,76 @@
* Returns true iff carrier privileges rules are null (dont need to be loaded) or loaded.
*/
public boolean areCarrierPriviligeRulesLoaded() {
- return mCarrierPrivilegeRules == null
- || mCarrierPrivilegeRules.areCarrierPriviligeRulesLoaded();
+ UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
+ return carrierPrivilegeRules == null
+ || carrierPrivilegeRules.areCarrierPriviligeRulesLoaded();
}
/**
* Returns true if there are some carrier privilege rules loaded and specified.
*/
public boolean hasCarrierPrivilegeRules() {
- return mCarrierPrivilegeRules != null
- && mCarrierPrivilegeRules.hasCarrierPrivilegeRules();
+ UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
+ return carrierPrivilegeRules != null && carrierPrivilegeRules.hasCarrierPrivilegeRules();
}
/**
- * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatus}.
+ * Exposes {@link UiccCarrierPrivilegeRules#getCarrierPrivilegeStatus}.
*/
public int getCarrierPrivilegeStatus(Signature signature, String packageName) {
- return mCarrierPrivilegeRules == null ?
- TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
- mCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature, packageName);
+ UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
+ return carrierPrivilegeRules == null
+ ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
+ carrierPrivilegeRules.getCarrierPrivilegeStatus(signature, packageName);
}
/**
- * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatus}.
+ * Exposes {@link UiccCarrierPrivilegeRules#getCarrierPrivilegeStatus}.
*/
public int getCarrierPrivilegeStatus(PackageManager packageManager, String packageName) {
- return mCarrierPrivilegeRules == null ?
- TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
- mCarrierPrivilegeRules.getCarrierPrivilegeStatus(packageManager, packageName);
+ UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
+ return carrierPrivilegeRules == null
+ ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
+ carrierPrivilegeRules.getCarrierPrivilegeStatus(packageManager, packageName);
}
/**
- * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatus}.
+ * Exposes {@link UiccCarrierPrivilegeRules#getCarrierPrivilegeStatus}.
*/
public int getCarrierPrivilegeStatus(PackageInfo packageInfo) {
- return mCarrierPrivilegeRules == null ?
- TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
- mCarrierPrivilegeRules.getCarrierPrivilegeStatus(packageInfo);
+ UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
+ return carrierPrivilegeRules == null
+ ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
+ carrierPrivilegeRules.getCarrierPrivilegeStatus(packageInfo);
}
/**
- * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPrivilegeStatusForCurrentTransaction}.
+ * Exposes {@link UiccCarrierPrivilegeRules#getCarrierPrivilegeStatusForCurrentTransaction}.
*/
public int getCarrierPrivilegeStatusForCurrentTransaction(PackageManager packageManager) {
- return mCarrierPrivilegeRules == null ?
- TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
- mCarrierPrivilegeRules.getCarrierPrivilegeStatusForCurrentTransaction(packageManager);
+ UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
+ return carrierPrivilegeRules == null
+ ? TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED :
+ carrierPrivilegeRules.getCarrierPrivilegeStatusForCurrentTransaction(
+ packageManager);
}
/**
- * Exposes {@link UiccCarrierPrivilegeRules.getCarrierPackageNamesForIntent}.
+ * Exposes {@link UiccCarrierPrivilegeRules#getCarrierPackageNamesForIntent}.
*/
public List<String> getCarrierPackageNamesForIntent(
PackageManager packageManager, Intent intent) {
- return mCarrierPrivilegeRules == null ? null :
- mCarrierPrivilegeRules.getCarrierPackageNamesForIntent(
- packageManager, intent);
+ UiccCarrierPrivilegeRules carrierPrivilegeRules = getCarrierPrivilegeRules();
+ return carrierPrivilegeRules == null ? null :
+ carrierPrivilegeRules.getCarrierPackageNamesForIntent(
+ packageManager, intent);
+ }
+
+ /** Returns a reference to the current {@link UiccCarrierPrivilegeRules}. */
+ private UiccCarrierPrivilegeRules getCarrierPrivilegeRules() {
+ synchronized (mLock) {
+ return mCarrierPrivilegeRules;
+ }
}
public boolean setOperatorBrandOverride(String brand) {
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
index 3ec7f34..68b72c8 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRules.java
@@ -31,20 +31,11 @@
import android.text.TextUtils;
import com.android.internal.telephony.CommandException;
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.uicc.IccUtils;
-import java.io.ByteArrayInputStream;
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.lang.IllegalArgumentException;
-import java.lang.IndexOutOfBoundsException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -65,7 +56,10 @@
private static final String LOG_TAG = "UiccCarrierPrivilegeRules";
private static final boolean DBG = false;
- private static final String AID = "A00000015141434C00";
+ private static final String ARAM_AID = "A00000015141434C00";
+ private static final String ARAD_AID = "A00000015144414300";
+ private static final int ARAM = 1;
+ private static final int ARAD = 0;
private static final int CLA = 0x80;
private static final int COMMAND = 0xCA;
private static final int P1 = 0xFF;
@@ -103,6 +97,8 @@
private static final String TAG_PKG_REF_DO = "CA";
private static final String TAG_AR_DO = "E3";
private static final String TAG_PERM_AR_DO = "DB";
+ private static final String TAG_AID_REF_DO = "4F";
+ private static final String CARRIER_PRIVILEGE_AID = "FFFFFFFFFFFF";
private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 1;
private static final int EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE = 2;
@@ -217,18 +213,21 @@
private String mStatusMessage; // Only used for debugging.
private int mChannelId; // Channel Id for communicating with UICC.
private int mRetryCount; // Number of retries for open logical channel.
+ private boolean mCheckedRules = false; // Flag that used to mark whether get rules from ARA-D.
+ private int mAIDInUse; // Message component to identify which AID is currently in-use.
private final Runnable mRetryRunnable = new Runnable() {
@Override
public void run() {
- openChannel();
+ openChannel(mAIDInUse);
}
};
- private void openChannel() {
+ private void openChannel(int aidId) {
// Send open logical channel request.
+ String aid = (aidId == ARAD) ? ARAD_AID : ARAM_AID;
int p2 = 0x00;
- mUiccCard.iccOpenLogicalChannel(AID, p2, /* supported p2 value */
- obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, null));
+ mUiccCard.iccOpenLogicalChannel(aid, p2, /* supported p2 value */
+ obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE, 0, aidId, null));
}
public UiccCarrierPrivilegeRules(UiccCard uiccCard, Message loadedCallback) {
@@ -240,7 +239,9 @@
mRules = "";
mAccessRules = new ArrayList<AccessRule>();
- openChannel();
+ // Open logical channel with ARA_D.
+ mAIDInUse = ARAD;
+ openChannel(mAIDInUse);
}
/**
@@ -419,91 +420,120 @@
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
+ mAIDInUse = msg.arg2; // 0 means ARA-D and 1 means ARA-M.
switch (msg.what) {
- case EVENT_OPEN_LOGICAL_CHANNEL_DONE:
- log("EVENT_OPEN_LOGICAL_CHANNEL_DONE");
- ar = (AsyncResult) msg.obj;
- if (ar.exception == null && ar.result != null) {
- mChannelId = ((int[]) ar.result)[0];
- mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2, P3, DATA,
- obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(mChannelId)));
- } else {
- // MISSING_RESOURCE could be due to logical channels temporarily unavailable,
- // so we retry up to MAX_RETRY times, with an interval of RETRY_INTERVAL_MS.
- if (ar.exception instanceof CommandException && mRetryCount < MAX_RETRY &&
- ((CommandException) (ar.exception)).getCommandError() ==
- CommandException.Error.MISSING_RESOURCE) {
- mRetryCount++;
- removeCallbacks(mRetryRunnable);
- postDelayed(mRetryRunnable, RETRY_INTERVAL_MS);
- } else {
- // if rules cannot be read from ARA applet,
- // fallback to PKCS15-based ARF.
- log("No ARA, try ARF next.");
- mUiccPkcs15 = new UiccPkcs15(mUiccCard,
- obtainMessage(EVENT_PKCS15_READ_DONE));
- }
- }
- break;
+ case EVENT_OPEN_LOGICAL_CHANNEL_DONE:
+ log("EVENT_OPEN_LOGICAL_CHANNEL_DONE");
+ ar = (AsyncResult) msg.obj;
+ if (ar.exception == null && ar.result != null) {
+ mChannelId = ((int[]) ar.result)[0];
+ mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2, P3,
+ DATA, obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, mChannelId,
+ mAIDInUse));
+ } else {
+ // MISSING_RESOURCE could be due to logical channels temporarily unavailable,
+ // so we retry up to MAX_RETRY times, with an interval of RETRY_INTERVAL_MS.
+ if (ar.exception instanceof CommandException && mRetryCount < MAX_RETRY
+ && ((CommandException) (ar.exception)).getCommandError()
+ == CommandException.Error.MISSING_RESOURCE) {
+ mRetryCount++;
+ removeCallbacks(mRetryRunnable);
+ postDelayed(mRetryRunnable, RETRY_INTERVAL_MS);
+ } else {
+ if (mAIDInUse == ARAD) {
+ // Open logical channel with ARA_M.
+ mRules = "";
+ openChannel(1);
+ }
+ if (mAIDInUse == ARAM) {
+ if (mCheckedRules) {
+ updateState(STATE_LOADED, "Success!");
+ } else {
+ // if rules cannot be read from both ARA_D and ARA_M applet,
+ // fallback to PKCS15-based ARF.
+ log("No ARA, try ARF next.");
+ mUiccPkcs15 = new UiccPkcs15(mUiccCard,
+ obtainMessage(EVENT_PKCS15_READ_DONE));
+ }
+ }
+ }
+ }
+ break;
- case EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE:
- log("EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE");
- ar = (AsyncResult) msg.obj;
- if (ar.exception == null && ar.result != null) {
- IccIoResult response = (IccIoResult) ar.result;
- if (response.sw1 == 0x90 && response.sw2 == 0x00 &&
- response.payload != null && response.payload.length > 0) {
- try {
- mRules += IccUtils.bytesToHexString(response.payload).toUpperCase(Locale.US);
- if (isDataComplete()) {
- mAccessRules = parseRules(mRules);
- updateState(STATE_LOADED, "Success!");
- } else {
- mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND, P1, P2_EXTENDED_DATA, P3, DATA,
- obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE, new Integer(mChannelId)));
- break;
- }
- } catch (IllegalArgumentException ex) {
- updateState(STATE_ERROR, "Error parsing rules: " + ex);
- } catch (IndexOutOfBoundsException ex) {
- updateState(STATE_ERROR, "Error parsing rules: " + ex);
- }
- } else {
- String errorMsg = "Invalid response: payload=" + response.payload +
- " sw1=" + response.sw1 + " sw2=" + response.sw2;
- updateState(STATE_ERROR, errorMsg);
- }
- } else {
- updateState(STATE_ERROR, "Error reading value from SIM.");
- }
+ case EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE:
+ log("EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE");
+ ar = (AsyncResult) msg.obj;
+ if (ar.exception == null && ar.result != null) {
+ IccIoResult response = (IccIoResult) ar.result;
+ if (response.sw1 == 0x90 && response.sw2 == 0x00
+ && response.payload != null && response.payload.length > 0) {
+ try {
+ mRules += IccUtils.bytesToHexString(response.payload)
+ .toUpperCase(Locale.US);
+ if (isDataComplete()) {
+ mAccessRules.addAll(parseRules(mRules));
+ if (mAIDInUse == ARAD) {
+ mCheckedRules = true;
+ } else {
+ updateState(STATE_LOADED, "Success!");
+ }
+ } else {
+ mUiccCard.iccTransmitApduLogicalChannel(mChannelId, CLA, COMMAND,
+ P1, P2_EXTENDED_DATA, P3, DATA,
+ obtainMessage(EVENT_TRANSMIT_LOGICAL_CHANNEL_DONE,
+ mChannelId, mAIDInUse));
+ break;
+ }
+ } catch (IllegalArgumentException | IndexOutOfBoundsException ex) {
+ if (mAIDInUse == ARAM) {
+ updateState(STATE_ERROR, "Error parsing rules: " + ex);
+ }
+ }
+ } else {
+ if (mAIDInUse == ARAM) {
+ String errorMsg = "Invalid response: payload=" + response.payload
+ + " sw1=" + response.sw1 + " sw2=" + response.sw2;
+ updateState(STATE_ERROR, errorMsg);
+ }
+ }
+ } else {
+ if (mAIDInUse == ARAM) {
+ updateState(STATE_ERROR, "Error reading value from SIM.");
+ }
+ }
- mUiccCard.iccCloseLogicalChannel(mChannelId, obtainMessage(
- EVENT_CLOSE_LOGICAL_CHANNEL_DONE));
- mChannelId = -1;
- break;
+ mUiccCard.iccCloseLogicalChannel(mChannelId, obtainMessage(
+ EVENT_CLOSE_LOGICAL_CHANNEL_DONE, 0, mAIDInUse));
+ mChannelId = -1;
+ break;
- case EVENT_CLOSE_LOGICAL_CHANNEL_DONE:
- log("EVENT_CLOSE_LOGICAL_CHANNEL_DONE");
- break;
+ case EVENT_CLOSE_LOGICAL_CHANNEL_DONE:
+ log("EVENT_CLOSE_LOGICAL_CHANNEL_DONE");
+ if (mAIDInUse == ARAD) {
+ // Close logical channel with ARA_D and then open logical channel with ARA_M.
+ mRules = "";
+ openChannel(1);
+ }
+ break;
- case EVENT_PKCS15_READ_DONE:
- log("EVENT_PKCS15_READ_DONE");
- if (mUiccPkcs15 == null || mUiccPkcs15.getRules() == null) {
- updateState(STATE_ERROR, "No ARA or ARF.");
- } else {
- for (String cert : mUiccPkcs15.getRules()) {
- AccessRule accessRule = new AccessRule(
- IccUtils.hexStringToBytes(cert), "", 0x00);
- mAccessRules.add(accessRule);
- }
- updateState(STATE_LOADED, "Success!");
- }
- break;
+ case EVENT_PKCS15_READ_DONE:
+ log("EVENT_PKCS15_READ_DONE");
+ if (mUiccPkcs15 == null || mUiccPkcs15.getRules() == null) {
+ updateState(STATE_ERROR, "No ARA or ARF.");
+ } else {
+ for (String cert : mUiccPkcs15.getRules()) {
+ AccessRule accessRule = new AccessRule(
+ IccUtils.hexStringToBytes(cert), "", 0x00);
+ mAccessRules.add(accessRule);
+ }
+ updateState(STATE_LOADED, "Success!");
+ }
+ break;
- default:
- Rlog.e(LOG_TAG, "Unknown event " + msg.what);
+ default:
+ Rlog.e(LOG_TAG, "Unknown event " + msg.what);
}
}
@@ -518,7 +548,7 @@
String lengthBytes = allRules.parseLength(mRules);
log("isDataComplete lengthBytes: " + lengthBytes);
if (mRules.length() == TAG_ALL_REF_AR_DO.length() + lengthBytes.length() +
- allRules.length) {
+ allRules.length) {
log("isDataComplete yes");
return true;
} else {
@@ -548,7 +578,7 @@
if (accessRule != null) {
accessRules.add(accessRule);
} else {
- Rlog.e(LOG_TAG, "Skip unrecognized rule." + refArDo.value);
+ Rlog.e(LOG_TAG, "Skip unrecognized rule." + refArDo.value);
}
}
return accessRules;
@@ -569,37 +599,52 @@
if (rule.startsWith(TAG_REF_DO)) {
TLV refDo = new TLV(TAG_REF_DO); //E1
rule = refDo.parse(rule, false);
-
- // Skip unrelated rules.
- if (!refDo.value.startsWith(TAG_DEVICE_APP_ID_REF_DO)) {
+ // Allow 4F tag with a default value "FF FF FF FF FF FF" to be compatible with
+ // devices having GP access control enforcer:
+ // - If no 4F tag is present, it's a CP rule.
+ // - If 4F tag has value "FF FF FF FF FF FF", it's a CP rule.
+ // - If 4F tag has other values, it's not a CP rule and Android should ignore it.
+ TLV deviceDo = new TLV(TAG_DEVICE_APP_ID_REF_DO); //C1
+ if (refDo.value.startsWith(TAG_AID_REF_DO)) {
+ TLV cpDo = new TLV(TAG_AID_REF_DO); //4F
+ String remain = cpDo.parse(refDo.value, false);
+ if (!cpDo.lengthBytes.equals("06") || !cpDo.value.equals(CARRIER_PRIVILEGE_AID)
+ || remain.isEmpty() || !remain.startsWith(TAG_DEVICE_APP_ID_REF_DO)) {
+ return null;
+ }
+ tmp = deviceDo.parse(remain, false);
+ certificateHash = deviceDo.value;
+ } else if (refDo.value.startsWith(TAG_DEVICE_APP_ID_REF_DO)) {
+ tmp = deviceDo.parse(refDo.value, false);
+ certificateHash = deviceDo.value;
+ } else {
return null;
}
-
- TLV deviceDo = new TLV(TAG_DEVICE_APP_ID_REF_DO); //C1
- tmp = deviceDo.parse(refDo.value, false);
- certificateHash = deviceDo.value;
-
if (!tmp.isEmpty()) {
- if (!tmp.startsWith(TAG_PKG_REF_DO)) {
- return null;
- }
- TLV pkgDo = new TLV(TAG_PKG_REF_DO); //CA
- pkgDo.parse(tmp, true);
- packageName = new String(IccUtils.hexStringToBytes(pkgDo.value));
+ if (!tmp.startsWith(TAG_PKG_REF_DO)) {
+ return null;
+ }
+ TLV pkgDo = new TLV(TAG_PKG_REF_DO); //CA
+ pkgDo.parse(tmp, true);
+ packageName = new String(IccUtils.hexStringToBytes(pkgDo.value));
} else {
- packageName = null;
+ packageName = null;
}
} else if (rule.startsWith(TAG_AR_DO)) {
TLV arDo = new TLV(TAG_AR_DO); //E3
rule = arDo.parse(rule, false);
-
- // Skip unrelated rules.
- if (!arDo.value.startsWith(TAG_PERM_AR_DO)) {
+ // Skip all the irrelevant tags (All the optional tags here are two bytes
+ // according to the spec GlobalPlatform Secure Element Access Control).
+ String remain = arDo.value;
+ while (!remain.isEmpty() && !remain.startsWith(TAG_PERM_AR_DO)) {
+ TLV tmpDo = new TLV(remain.substring(0, 2));
+ remain = tmpDo.parse(remain, false);
+ }
+ if (remain.isEmpty()) {
return null;
}
-
TLV permDo = new TLV(TAG_PERM_AR_DO); //DB
- permDo.parse(arDo.value, true);
+ permDo.parse(remain, true);
} else {
// Spec requires it must be either TAG_REF_DO or TAG_AR_DO.
throw new RuntimeException("Invalid Rule type");
@@ -668,15 +713,15 @@
* Converts state into human readable format.
*/
private String getStateString(int state) {
- switch (state) {
- case STATE_LOADING:
- return "STATE_LOADING";
- case STATE_LOADED:
- return "STATE_LOADED";
- case STATE_ERROR:
- return "STATE_ERROR";
- default:
- return "UNKNOWN";
- }
+ switch (state) {
+ case STATE_LOADING:
+ return "STATE_LOADING";
+ case STATE_LOADED:
+ return "STATE_LOADED";
+ case STATE_ERROR:
+ return "STATE_ERROR";
+ default:
+ return "UNKNOWN";
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/uicc/UiccController.java b/src/java/com/android/internal/telephony/uicc/UiccController.java
index 65aacd1..a948b75 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccController.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccController.java
@@ -89,8 +89,6 @@
private static final int EVENT_RADIO_UNAVAILABLE = 3;
private static final int EVENT_SIM_REFRESH = 4;
- private static final String DECRYPT_STATE = "trigger_restart_framework";
-
private CommandsInterface[] mCis;
private UiccCard[] mUiccCards = new UiccCard[TelephonyManager.getDefault().getPhoneCount()];
@@ -125,12 +123,11 @@
Integer index = new Integer(i);
mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, index);
// TODO remove this once modem correctly notifies the unsols
- // If the device has been decrypted or FBE is supported, read SIM when radio state is
- // available.
+ // If the device is unencrypted or has been decrypted or FBE is supported,
+ // i.e. not in cryptkeeper bounce, read SIM when radio state isavailable.
// Else wait for radio to be on. This is needed for the scenario when SIM is locked --
// to avoid overlap of CryptKeeper and SIM unlock screen.
- if (DECRYPT_STATE.equals(SystemProperties.get("vold.decrypt")) ||
- StorageManager.isFileEncryptedNativeOrEmulated()) {
+ if (!StorageManager.inCryptKeeperBounce()) {
mCis[i].registerForAvailable(this, EVENT_ICC_STATUS_CHANGED, index);
} else {
mCis[i].registerForOn(this, EVENT_ICC_STATUS_CHANGED, index);
@@ -342,7 +339,7 @@
if (requirePowerOffOnSimRefreshReset) {
mCis[index].setRadioPower(false, null);
} else {
- mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE));
+ mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
}
mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
}
diff --git a/src/java/com/android/internal/telephony/util/NotificationChannelController.java b/src/java/com/android/internal/telephony/util/NotificationChannelController.java
new file mode 100644
index 0000000..09519c4
--- /dev/null
+++ b/src/java/com/android/internal/telephony/util/NotificationChannelController.java
@@ -0,0 +1,131 @@
+/*
+ * 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.util;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.media.AudioAttributes;
+import android.net.Uri;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+
+import com.android.internal.R;
+
+import java.util.Arrays;
+import java.util.List;
+
+
+public class NotificationChannelController {
+
+ /**
+ * list of {@link android.app.NotificationChannel} for telephony service.
+ */
+ public static final String CHANNEL_ID_ALERT = "alert";
+ public static final String CHANNEL_ID_CALL_FORWARD = "callForward";
+ public static final String CHANNEL_ID_MOBILE_DATA_ALERT = "mobileDataAlert";
+ public static final String CHANNEL_ID_SMS = "sms";
+ public static final String CHANNEL_ID_VOICE_MAIL = "voiceMail";
+ public static final String CHANNEL_ID_WFC = "wfc";
+
+ /**
+ * Creates all notification channels and registers with NotificationManager. If a channel
+ * with the same ID is already registered, NotificationManager will ignore this call.
+ */
+ private static void createAll(Context context) {
+ final NotificationChannel alertChannel = new NotificationChannel(
+ CHANNEL_ID_ALERT,
+ context.getText(R.string.notification_channel_network_alert),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ alertChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build());
+
+ context.getSystemService(NotificationManager.class)
+ .createNotificationChannels(Arrays.asList(
+ new NotificationChannel(CHANNEL_ID_CALL_FORWARD,
+ context.getText(R.string.notification_channel_call_forward),
+ NotificationManager.IMPORTANCE_LOW),
+ new NotificationChannel(CHANNEL_ID_MOBILE_DATA_ALERT,
+ context.getText(R.string.notification_channel_mobile_data_alert),
+ NotificationManager.IMPORTANCE_DEFAULT),
+ new NotificationChannel(CHANNEL_ID_SMS,
+ context.getText(R.string.notification_channel_sms),
+ NotificationManager.IMPORTANCE_HIGH),
+ new NotificationChannel(CHANNEL_ID_WFC,
+ context.getText(R.string.notification_channel_wfc),
+ NotificationManager.IMPORTANCE_LOW),
+ alertChannel));
+ // only for update
+ if (getChannel(CHANNEL_ID_VOICE_MAIL, context) != null) {
+ migrateVoicemailNotificationSettings(context);
+ }
+ }
+
+ public NotificationChannelController(Context context) {
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ intentFilter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
+ context.registerReceiver(mBroadcastReceiver, intentFilter);
+ createAll(context);
+ }
+
+ public static NotificationChannel getChannel(String channelId, Context context) {
+ return context.getSystemService(NotificationManager.class)
+ .getNotificationChannel(channelId);
+ }
+
+ /**
+ * migrate deprecated voicemail notification settings to initial notification channel settings
+ * {@link VoicemailNotificationSettingsUtil#getRingTonePreference(Context)}}
+ * {@link VoicemailNotificationSettingsUtil#getVibrationPreference(Context)}
+ * notification settings are based on subId, only migrate if sub id matches.
+ * otherwise fallback to predefined voicemail channel settings.
+ * @param context
+ */
+ private static void migrateVoicemailNotificationSettings(Context context) {
+ final NotificationChannel voiceMailChannel = new NotificationChannel(
+ CHANNEL_ID_VOICE_MAIL,
+ context.getText(R.string.notification_channel_voice_mail),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ voiceMailChannel.enableVibration(
+ VoicemailNotificationSettingsUtil.getVibrationPreference(context));
+ Uri sound = VoicemailNotificationSettingsUtil.getRingTonePreference(context);
+ voiceMailChannel.setSound(
+ (sound == null) ? Settings.System.DEFAULT_NOTIFICATION_URI : sound,
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build());
+ context.getSystemService(NotificationManager.class)
+ .createNotificationChannel(voiceMailChannel);
+ }
+
+ private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
+ // rename all notification channels on locale change
+ createAll(context);
+ } else if (Intent.ACTION_SIM_STATE_CHANGED.equals(intent.getAction())) {
+ // migrate voicemail notification settings on sim load
+ if (SubscriptionManager.INVALID_SUBSCRIPTION_ID !=
+ SubscriptionManager.getDefaultSubscriptionId()) {
+ migrateVoicemailNotificationSettings(context);
+ }
+ }
+ }
+ };
+}
diff --git a/src/java/com/android/internal/telephony/util/VoicemailNotificationSettingsUtil.java b/src/java/com/android/internal/telephony/util/VoicemailNotificationSettingsUtil.java
new file mode 100644
index 0000000..d8988e3
--- /dev/null
+++ b/src/java/com/android/internal/telephony/util/VoicemailNotificationSettingsUtil.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2014 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.util;
+
+import android.app.NotificationChannel;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.preference.PreferenceManager;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+public class VoicemailNotificationSettingsUtil {
+ private static final String VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY_PREFIX =
+ "voicemail_notification_ringtone_";
+ private static final String VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY_PREFIX =
+ "voicemail_notification_vibrate_";
+
+ // Old voicemail notification vibration string constants used for migration.
+ private static final String OLD_VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY =
+ "button_voicemail_notification_ringtone_key";
+ private static final String OLD_VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY =
+ "button_voicemail_notification_vibrate_key";
+ private static final String OLD_VOICEMAIL_VIBRATE_WHEN_SHARED_PREFS_KEY =
+ "button_voicemail_notification_vibrate_when_key";
+ private static final String OLD_VOICEMAIL_RINGTONE_SHARED_PREFS_KEY =
+ "button_voicemail_notification_ringtone_key";
+ private static final String OLD_VOICEMAIL_VIBRATION_ALWAYS = "always";
+ private static final String OLD_VOICEMAIL_VIBRATION_NEVER = "never";
+
+ public static void setVibrationEnabled(Context context, boolean isEnabled) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(getVoicemailVibrationSharedPrefsKey(), isEnabled);
+ editor.commit();
+ }
+
+ public static boolean isVibrationEnabled(Context context) {
+ final NotificationChannel channel = NotificationChannelController.getChannel(
+ NotificationChannelController.CHANNEL_ID_VOICE_MAIL, context);
+ return (channel != null) ? channel.shouldVibrate() : getVibrationPreference(context);
+ }
+
+ public static boolean getVibrationPreference(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ migrateVoicemailVibrationSettingsIfNeeded(context, prefs);
+ return prefs.getBoolean(getVoicemailVibrationSharedPrefsKey(), false /* defValue */);
+ }
+
+ public static void setRingtoneUri(Context context, Uri ringtoneUri) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ String ringtoneUriStr = ringtoneUri != null ? ringtoneUri.toString() : "";
+
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(getVoicemailRingtoneSharedPrefsKey(), ringtoneUriStr);
+ editor.commit();
+ }
+
+ public static Uri getRingtoneUri(Context context) {
+ final NotificationChannel channel = NotificationChannelController.getChannel(
+ NotificationChannelController.CHANNEL_ID_VOICE_MAIL, context);
+ return (channel != null) ? channel.getSound() : getRingTonePreference(context);
+ }
+
+ public static Uri getRingTonePreference(Context context) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ migrateVoicemailRingtoneSettingsIfNeeded(context, prefs);
+ String uriString = prefs.getString(
+ getVoicemailRingtoneSharedPrefsKey(),
+ Settings.System.DEFAULT_NOTIFICATION_URI.toString());
+ return !TextUtils.isEmpty(uriString) ? Uri.parse(uriString) : null;
+ }
+
+ /**
+ * Migrate voicemail settings from {@link #OLD_VIBRATE_WHEN_KEY} or
+ * {@link #OLD_VOICEMAIL_NOTIFICATION_VIBRATE_KEY}.
+ *
+ * TODO: Add helper which migrates settings from old version to new version.
+ */
+ private static void migrateVoicemailVibrationSettingsIfNeeded(
+ Context context, SharedPreferences prefs) {
+ String key = getVoicemailVibrationSharedPrefsKey();
+ TelephonyManager telephonyManager = TelephonyManager.from(context);
+
+ // Skip if a preference exists, or if phone is MSIM.
+ if (prefs.contains(key) || telephonyManager.getPhoneCount() != 1) {
+ return;
+ }
+
+ if (prefs.contains(OLD_VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY)) {
+ boolean voicemailVibrate = prefs.getBoolean(
+ OLD_VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY, false /* defValue */);
+
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(key, voicemailVibrate)
+ .remove(OLD_VOICEMAIL_VIBRATE_WHEN_SHARED_PREFS_KEY)
+ .commit();
+ }
+
+ if (prefs.contains(OLD_VOICEMAIL_VIBRATE_WHEN_SHARED_PREFS_KEY)) {
+ // If vibrateWhen is always, then voicemailVibrate should be true.
+ // If it is "only in silent mode", or "never", then voicemailVibrate should be false.
+ String vibrateWhen = prefs.getString(
+ OLD_VOICEMAIL_VIBRATE_WHEN_SHARED_PREFS_KEY, OLD_VOICEMAIL_VIBRATION_NEVER);
+ boolean voicemailVibrate = vibrateWhen.equals(OLD_VOICEMAIL_VIBRATION_ALWAYS);
+
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(key, voicemailVibrate)
+ .remove(OLD_VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY)
+ .commit();
+ }
+ }
+
+ /**
+ * Migrate voicemail settings from OLD_VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY.
+ *
+ * TODO: Add helper which migrates settings from old version to new version.
+ */
+ private static void migrateVoicemailRingtoneSettingsIfNeeded(
+ Context context, SharedPreferences prefs) {
+ String key = getVoicemailRingtoneSharedPrefsKey();
+ TelephonyManager telephonyManager = TelephonyManager.from(context);
+
+ // Skip if a preference exists, or if phone is MSIM.
+ if (prefs.contains(key) || telephonyManager.getPhoneCount() != 1) {
+ return;
+ }
+
+ if (prefs.contains(OLD_VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY)) {
+ String uriString = prefs.getString(
+ OLD_VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY, null /* defValue */);
+
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(key, uriString)
+ .remove(OLD_VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY)
+ .commit();
+ }
+ }
+
+ private static String getVoicemailVibrationSharedPrefsKey() {
+ return VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY_PREFIX
+ + SubscriptionManager.getDefaultSubscriptionId();
+ }
+
+ private static String getVoicemailRingtoneSharedPrefsKey() {
+ return VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY_PREFIX
+ + SubscriptionManager.getDefaultSubscriptionId();
+ }
+}
diff --git a/src/java/com/google/android/mms/pdu/PduPersister.java b/src/java/com/google/android/mms/pdu/PduPersister.java
index 4adcbf8..e32d121 100755
--- a/src/java/com/google/android/mms/pdu/PduPersister.java
+++ b/src/java/com/google/android/mms/pdu/PduPersister.java
@@ -17,15 +17,6 @@
package com.google.android.mms.pdu;
-import com.google.android.mms.ContentType;
-import com.google.android.mms.InvalidHeaderValueException;
-import com.google.android.mms.MmsException;
-import com.google.android.mms.util.DownloadDrmHelper;
-import com.google.android.mms.util.DrmConvertSession;
-import com.google.android.mms.util.PduCache;
-import com.google.android.mms.util.PduCacheEntry;
-import com.google.android.mms.util.SqliteWrapper;
-
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -38,17 +29,26 @@
import android.provider.MediaStore;
import android.provider.Telephony;
import android.provider.Telephony.Mms;
-import android.provider.Telephony.MmsSms;
-import android.provider.Telephony.Threads;
import android.provider.Telephony.Mms.Addr;
import android.provider.Telephony.Mms.Part;
+import android.provider.Telephony.MmsSms;
import android.provider.Telephony.MmsSms.PendingMessages;
-import android.telephony.SubscriptionManager;
+import android.provider.Telephony.Threads;
import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
+import com.google.android.mms.ContentType;
+import com.google.android.mms.InvalidHeaderValueException;
+import com.google.android.mms.MmsException;
+import com.google.android.mms.util.DownloadDrmHelper;
+import com.google.android.mms.util.DrmConvertSession;
+import com.google.android.mms.util.PduCache;
+import com.google.android.mms.util.PduCacheEntry;
+import com.google.android.mms.util.SqliteWrapper;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
@@ -60,10 +60,8 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
import java.util.Map.Entry;
-
-import com.google.android.mms.pdu.EncodedStringValue;
+import java.util.Set;
/**
* This class is the high-level manager of PDU storage.
@@ -838,7 +836,7 @@
os = mContentResolver.openOutputStream(uri);
if (data == null) {
dataUri = part.getDataUri();
- if ((dataUri == null) || (dataUri == uri)) {
+ if ((dataUri == null) || (dataUri.equals(uri))) {
Log.w(TAG, "Can't find data for this part.");
return;
}
@@ -1138,7 +1136,7 @@
// 1. New binary data supplied or
// 2. The Uri of the part is different from the current one.
if ((part.getData() != null)
- || (uri != part.getDataUri())) {
+ || (!uri.equals(part.getDataUri()))) {
persistData(part, uri, contentType, preOpenedFiles);
}
}
@@ -1183,7 +1181,8 @@
for (int i = 0; i < partsNum; i++) {
PduPart part = body.getPart(i);
Uri partUri = part.getDataUri();
- if ((partUri == null) || !partUri.getAuthority().startsWith("mms")) {
+ if ((partUri == null) || TextUtils.isEmpty(partUri.getAuthority())
+ || !partUri.getAuthority().startsWith("mms")) {
toBeCreated.add(part);
} else {
toBeUpdated.put(partUri, part);
diff --git a/tests/telephonytests/Android.mk b/tests/telephonytests/Android.mk
index 1324279..334d62f 100644
--- a/tests/telephonytests/Android.mk
+++ b/tests/telephonytests/Android.mk
@@ -9,7 +9,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common ims-common services.core
LOCAL_STATIC_JAVA_LIBRARIES := guava \
- mockito-target \
+ mockito-target-minus-junit4 \
android-support-test \
platform-test-annotations \
legacy-android-test
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsCallProfileTest.java b/tests/telephonytests/src/android/telephony/ims/ImsCallProfileTest.java
new file mode 100644
index 0000000..bc8d4e1
--- /dev/null
+++ b/tests/telephonytests/src/android/telephony/ims/ImsCallProfileTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+// Note: Package name is intentionally wrong for this test; the internal junk class is used to test
+// that parcelables of types other than android.* are stripped out.
+package com.android.telephony.ims;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.test.runner.AndroidJUnit4;
+import android.telecom.DisconnectCause;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.ims.ImsCallProfile;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for the {@link com.android.ims.ImsCallProfile} class.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ImsCallProfileTest {
+ // A test-only parcelable class which is not in the android.* namespace.
+ private static class JunkParcelable implements Parcelable {
+ private int mTest;
+
+ JunkParcelable() {
+ }
+
+ protected JunkParcelable(Parcel in) {
+ mTest = in.readInt();
+ }
+
+ public static final Creator<JunkParcelable> CREATOR = new Creator<JunkParcelable>() {
+ @Override
+ public JunkParcelable createFromParcel(Parcel in) {
+ return new JunkParcelable(in);
+ }
+
+ @Override
+ public JunkParcelable[] newArray(int size) {
+ return new JunkParcelable[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mTest);
+ }
+ }
+
+ /**
+ * Ensures that the {@link ImsCallProfile} will discard invalid extras when it is parceled.
+ */
+ @Test
+ @SmallTest
+ public void testExtrasCleanup() {
+ ImsCallProfile srcParcel = new ImsCallProfile();
+ // Put in a private parcelable type.
+ srcParcel.mCallExtras.putParcelable("JUNK", new JunkParcelable());
+ // Put in an api defined parcelable type.
+ srcParcel.mCallExtras.putParcelable("NOTJUNK", new DisconnectCause(DisconnectCause.BUSY));
+ // Put in some valid things.
+ srcParcel.mCallExtras.putInt("INT", 1);
+ srcParcel.mCallExtras.putString("STRING", "hello");
+
+ // Parcel it.
+ Parcel parcel = Parcel.obtain();
+ srcParcel.writeToParcel(parcel, 0);
+ byte[] parcelBytes = parcel.marshall();
+ parcel.recycle();
+
+ // Unparcel it.
+ parcel = Parcel.obtain();
+ parcel.unmarshall(parcelBytes, 0, parcelBytes.length);
+ parcel.setDataPosition(0);
+ ImsCallProfile unparceledProfile = ImsCallProfile.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertNotNull(unparceledProfile.mCallExtras);
+ assertEquals(3, unparceledProfile.mCallExtras.size());
+ assertEquals(1, unparceledProfile.getCallExtraInt("INT"));
+ assertEquals("hello", unparceledProfile.getCallExtra("STRING"));
+ assertFalse(unparceledProfile.mCallExtras.containsKey("JUNK"));
+
+ DisconnectCause parceledCause = unparceledProfile.mCallExtras.getParcelable("NOTJUNK");
+ assertEquals(DisconnectCause.BUSY, parceledCause.getCode());
+ }
+}
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
index 8248c08..acd4e19 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
@@ -43,6 +43,8 @@
@Mock
private IImsFeatureStatusCallback mTestStatusCallback;
@Mock
+ private IImsFeatureStatusCallback mTestStatusCallback2;
+ @Mock
private ImsFeature.INotifyFeatureRemoved mTestRemovedCallback;
private class TestImsFeature extends ImsFeature {
@@ -73,19 +75,23 @@
@Test
@SmallTest
public void testSetCallbackAndNotify() throws Exception {
- mTestImsService.setImsFeatureStatusCallback(mTestStatusCallback);
+ mTestImsService.addImsFeatureStatusCallback(mTestStatusCallback);
+ mTestImsService.addImsFeatureStatusCallback(mTestStatusCallback2);
verify(mTestStatusCallback).notifyImsFeatureStatus(eq(ImsFeature.STATE_NOT_AVAILABLE));
+ verify(mTestStatusCallback2).notifyImsFeatureStatus(eq(ImsFeature.STATE_NOT_AVAILABLE));
}
@Test
@SmallTest
public void testSetFeatureAndCheckCallback() throws Exception {
- mTestImsService.setImsFeatureStatusCallback(mTestStatusCallback);
+ mTestImsService.addImsFeatureStatusCallback(mTestStatusCallback);
+ mTestImsService.addImsFeatureStatusCallback(mTestStatusCallback2);
mTestImsService.testSetFeatureState(ImsFeature.STATE_READY);
verify(mTestStatusCallback).notifyImsFeatureStatus(eq(ImsFeature.STATE_READY));
+ verify(mTestStatusCallback2).notifyImsFeatureStatus(eq(ImsFeature.STATE_READY));
assertEquals(ImsFeature.STATE_READY, mTestImsService.getFeatureState());
}
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java b/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java
index cdb95a3..8887027 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsServiceTest.java
@@ -16,10 +16,32 @@
package android.telephony.ims;
+import static android.Manifest.permission.MODIFY_PHONE_STATE;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+
+import static com.android.internal.telephony.ims.ImsResolver.SERVICE_INTERFACE;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.nullable;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.RemoteException;
+import android.support.test.filters.FlakyTest;
import android.support.test.runner.AndroidJUnit4;
import android.telephony.ims.feature.ImsFeature;
import android.test.suitebuilder.annotation.SmallTest;
@@ -31,30 +53,13 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import static android.Manifest.permission.MODIFY_PHONE_STATE;
-import static android.Manifest.permission.READ_PHONE_STATE;
-import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
-import static com.android.internal.telephony.ims.ImsResolver.SERVICE_INTERFACE;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertNull;
-import static junit.framework.Assert.fail;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.nullable;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
/**
* Unit tests for ImsService
*/
@@ -98,7 +103,7 @@
mTestImsService.getImsFeatureFromType(features, ImsFeature.MMTEL));
// Verify that upon creating a feature, we assign the callback and get the set feature state
// when querying it.
- verify(mTestImsService.mSpyMMTelFeature).setImsFeatureStatusCallback(eq(mTestCallback));
+ verify(mTestImsService.mSpyMMTelFeature).addImsFeatureStatusCallback(eq(mTestCallback));
assertEquals(ImsFeature.STATE_READY, mTestImsServiceBinder.getFeatureStatus(TEST_SLOT_0,
ImsFeature.MMTEL));
}
@@ -108,10 +113,10 @@
public void testRemoveMMTelFeature() throws RemoteException {
mTestImsServiceBinder.createImsFeature(TEST_SLOT_0, ImsFeature.MMTEL, mTestCallback);
- mTestImsServiceBinder.removeImsFeature(TEST_SLOT_0, ImsFeature.MMTEL);
+ mTestImsServiceBinder.removeImsFeature(TEST_SLOT_0, ImsFeature.MMTEL, mTestCallback);
verify(mTestImsService.mSpyMMTelFeature).notifyFeatureRemoved(eq(0));
- verify(mTestImsService.mSpyMMTelFeature).setImsFeatureStatusCallback(null);
+ verify(mTestImsService.mSpyMMTelFeature).removeImsFeatureStatusCallback(mTestCallback);
SparseArray<ImsFeature> features = mTestImsService.getImsFeatureMap(TEST_SLOT_0);
assertNull(mTestImsService.getImsFeatureFromType(features, ImsFeature.MMTEL));
}
@@ -152,8 +157,9 @@
}
}
+ @FlakyTest
+ @Ignore
@Test
- @SmallTest
public void testMethodWithNoPermissions() throws RemoteException {
when(mMockContext.checkCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE)).thenReturn(
PackageManager.PERMISSION_DENIED);
@@ -184,14 +190,11 @@
mTestImsService.mSpyMMTelFeature.sendSetFeatureState(ImsFeature.STATE_READY);
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mMockContext, times(2)).sendBroadcast(intentCaptor.capture());
+ verify(mMockContext).sendBroadcast(intentCaptor.capture());
try {
- // IMS_SERVICE_DOWN is always sent when createImsFeature completes
- assertNotNull(intentCaptor.getAllValues().get(0));
- verifyServiceDownSent(intentCaptor.getAllValues().get(0));
// Verify IMS_SERVICE_UP is sent
- assertNotNull(intentCaptor.getAllValues().get(1));
- verifyServiceUpSent(intentCaptor.getAllValues().get(1));
+ assertNotNull(intentCaptor.getValue());
+ verifyServiceUpSent(intentCaptor.getValue());
} catch (IndexOutOfBoundsException e) {
fail("Did not receive all intents");
}
@@ -209,37 +212,16 @@
mTestImsService.mSpyMMTelFeature.sendSetFeatureState(ImsFeature.STATE_INITIALIZING);
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mMockContext, times(2)).sendBroadcast(intentCaptor.capture());
+ verify(mMockContext).sendBroadcast(intentCaptor.capture());
try {
- // IMS_SERVICE_DOWN is always sent when createImsFeature completes.
- assertNotNull(intentCaptor.getAllValues().get(0));
- verifyServiceDownSent(intentCaptor.getAllValues().get(0));
// IMS_SERVICE_DOWN is sent when the service is STATE_INITIALIZING.
- assertNotNull(intentCaptor.getAllValues().get(1));
- verifyServiceDownSent(intentCaptor.getAllValues().get(1));
+ assertNotNull(intentCaptor.getValue());
+ verifyServiceDownSent(intentCaptor.getValue());
} catch (IndexOutOfBoundsException e) {
fail("Did not receive all intents");
}
}
- /**
- * Tests that the new ImsService still sends the IMS_SERVICE_DOWN broadcast when the feature is
- * set to not available.
- */
- @Test
- @SmallTest
- public void testImsServiceDownSentCompatNotAvailable() throws RemoteException {
- mTestImsServiceBinder.createImsFeature(TEST_SLOT_0, ImsFeature.MMTEL, mTestCallback);
-
- // The ImsService will send the STATE_NOT_AVAILABLE status as soon as the feature is
- // created.
-
- ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- verify(mMockContext).sendBroadcast(intentCaptor.capture());
- assertNotNull(intentCaptor.getValue());
- verifyServiceDownSent(intentCaptor.getValue());
- }
-
private void verifyServiceDownSent(Intent testIntent) {
assertEquals(ImsManager.ACTION_IMS_SERVICE_DOWN, testIntent.getAction());
assertEquals(TEST_SLOT_0, testIntent.getIntExtra(ImsManager.EXTRA_PHONE_ID, -1));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallManagerTest.java
index a255f26..8231d06 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CallManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CallManagerTest.java
@@ -122,7 +122,7 @@
@After
public void tearDown() throws Exception {
CallManager.getInstance().unregisterPhone(mPhone);
- mCallManagerHandlerThread.quitSafely();
+ mCallManagerHandlerThread.quit();
super.tearDown();
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CallStateExceptionTest.java b/tests/telephonytests/src/com/android/internal/telephony/CallStateExceptionTest.java
index bac3dd1..7b6c2b7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CallStateExceptionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CallStateExceptionTest.java
@@ -15,10 +15,12 @@
*/
package com.android.internal.telephony;
+import static org.junit.Assert.assertEquals;
+
import android.test.suitebuilder.annotation.SmallTest;
+
import org.junit.After;
import org.junit.Test;
-import static org.junit.Assert.assertEquals;
public class CallStateExceptionTest {
private CallStateException mCallStateException;
@@ -39,9 +41,9 @@
@Test
@SmallTest
public void testCallStateExceptionWithErrCode() {
- mCallStateException = new CallStateException(mCallStateException.ERROR_DISCONNECTED,
+ mCallStateException = new CallStateException(mCallStateException.ERROR_OUT_OF_SERVICE,
"sanity test with err code");
assertEquals("sanity test with err code", mCallStateException.getMessage());
- assertEquals(mCallStateException.ERROR_DISCONNECTED, mCallStateException.getError());
+ assertEquals(mCallStateException.ERROR_OUT_OF_SERVICE, mCallStateException.getError());
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierActionAgentTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierActionAgentTest.java
new file mode 100644
index 0000000..ca21914
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierActionAgentTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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 com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.provider.Settings;
+import android.provider.Telephony;
+import android.telephony.CarrierConfigManager;
+import android.test.mock.MockContentResolver;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+
+public class CarrierActionAgentTest extends TelephonyTest {
+ private CarrierActionAgent mCarrierActionAgentUT;
+ private FakeContentResolver mFakeContentResolver;
+ private static int DATA_CARRIER_ACTION_EVENT = 0;
+ private static int RADIO_CARRIER_ACTION_EVENT = 1;
+ private CarrierActionAgentHandler mCarrierActionAgentHandler;
+ @Mock
+ private Handler mDataActionHandler;
+ @Mock
+ private Handler mRadioActionHandler;
+
+ private class FakeContentResolver extends MockContentResolver {
+ @Override
+ public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+ super.notifyChange(uri, observer, syncToNetwork);
+ logd("onChanged(uri=" + uri + ")" + observer);
+ if (observer != null) {
+ observer.dispatchChange(false, uri);
+ } else {
+ mCarrierActionAgentUT.getContentObserver().dispatchChange(false, uri);
+ }
+ }
+ }
+
+ private class CarrierActionAgentHandler extends HandlerThread {
+
+ private CarrierActionAgentHandler(String name) {
+ super(name);
+ }
+
+ @Override
+ public void onLooperPrepared() {
+ mCarrierActionAgentUT = new CarrierActionAgent(mPhone);
+ mCarrierActionAgentUT.registerForCarrierAction(
+ CarrierActionAgent.CARRIER_ACTION_SET_METERED_APNS_ENABLED, mDataActionHandler,
+ DATA_CARRIER_ACTION_EVENT, null, false);
+ mCarrierActionAgentUT.registerForCarrierAction(
+ CarrierActionAgent.CARRIER_ACTION_SET_RADIO_ENABLED, mRadioActionHandler,
+ RADIO_CARRIER_ACTION_EVENT, null, false);
+ setReady(true);
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ logd("CarrierActionAgentTest +Setup!");
+ super.setUp(getClass().getSimpleName());
+ mFakeContentResolver = new FakeContentResolver();
+ doReturn(mFakeContentResolver).when(mContext).getContentResolver();
+ mCarrierActionAgentHandler = new CarrierActionAgentHandler(getClass().getSimpleName());
+ mCarrierActionAgentHandler.start();
+ waitUntilReady();
+ logd("CarrierActionAgentTest -Setup!");
+ }
+
+ @Test
+ @SmallTest
+ public void testCarrierActionResetOnAPM() {
+ // setting observer register at sim loading
+ final Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
+ IccCardConstants.INTENT_VALUE_ICC_LOADED);
+ mContext.sendBroadcast(intent);
+ waitForMs(200);
+
+ // carrier actions triggered from sim loading
+ ArgumentCaptor<Message> message = ArgumentCaptor.forClass(Message.class);
+ verify(mDataActionHandler).sendMessageAtTime(message.capture(), anyLong());
+ assertEquals(DATA_CARRIER_ACTION_EVENT, message.getValue().what);
+
+ verify(mRadioActionHandler).sendMessageAtTime(message.capture(), anyLong());
+ assertEquals(RADIO_CARRIER_ACTION_EVENT, message.getValue().what);
+
+ // simulate APM change from off -> on
+ Settings.Global.putInt(mFakeContentResolver, Settings.Global.AIRPLANE_MODE_ON, 1);
+ mFakeContentResolver.notifyChange(
+ Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), null);
+ waitForMs(200);
+
+ // carrier actions triggered from APM
+ verify(mDataActionHandler, times(2)).sendMessageAtTime(message.capture(), anyLong());
+ assertEquals(DATA_CARRIER_ACTION_EVENT, message.getValue().what);
+
+ verify(mRadioActionHandler, times(2)).sendMessageAtTime(message.capture(), anyLong());
+ assertEquals(RADIO_CARRIER_ACTION_EVENT, message.getValue().what);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ Settings.Global.putInt(mFakeContentResolver, Settings.Global.AIRPLANE_MODE_ON, 0);
+ mCarrierActionAgentHandler.quit();
+ super.tearDown();
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java
index dcc13bb..7cb7d45 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierSignalAgentTest.java
@@ -17,6 +17,7 @@
import android.content.Intent;
import android.content.pm.ResolveInfo;
+import android.os.Message;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.test.suitebuilder.annotation.SmallTest;
@@ -35,6 +36,7 @@
import static com.android.internal.telephony.TelephonyIntents.ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED;
import static com.android.internal.telephony.TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE;
import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
@@ -102,11 +104,11 @@
logd(mCaptorIntent.getAllValues().toString());
Intent capturedIntent = mCaptorIntent.getAllValues().get(1);
assertEquals(ACTION_CARRIER_SIGNAL_PCO_VALUE, capturedIntent.getAction());
- assertEquals(PCO_RECEIVER, capturedIntent.getComponent().flattenToString());
+ assertEquals(DC_ERROR_RECEIVER, capturedIntent.getComponent().flattenToString());
capturedIntent = mCaptorIntent.getAllValues().get(2);
assertEquals(ACTION_CARRIER_SIGNAL_PCO_VALUE, capturedIntent.getAction());
- assertEquals(DC_ERROR_RECEIVER, capturedIntent.getComponent().flattenToString());
+ assertEquals(PCO_RECEIVER, capturedIntent.getComponent().flattenToString());
}
@Test
@@ -210,4 +212,43 @@
mCaptorIntent = ArgumentCaptor.forClass(Intent.class);
verify(mContext, times(++count)).sendBroadcast(mCaptorIntent.capture());
}
+
+
+ @Test
+ @SmallTest
+ public void testCarrierConfigChange() {
+ // default config value
+ mBundle.putStringArray(
+ CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
+ new String[]{ PCO_RECEIVER + ":" + ACTION_CARRIER_SIGNAL_PCO_VALUE + ","
+ + ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED });
+ mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+ waitForMs(50);
+ // verify no reset action on initial config load
+ verify(mCarrierActionAgent, times(0)).sendMessageAtTime(any(Message.class), anyLong());
+
+ // new carrier config with different receiver intent order
+ mBundle.putStringArray(
+ CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
+ new String[]{ PCO_RECEIVER + ":" + ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+ + "," + ACTION_CARRIER_SIGNAL_PCO_VALUE});
+ mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+ waitForMs(50);
+ // verify no reset action for the same config (different order)
+ verify(mCarrierActionAgent, times(0)).sendMessageAtTime(any(Message.class), anyLong());
+
+ // new different config value
+ mBundle.putStringArray(
+ CarrierConfigManager.KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
+ new String[]{ DC_ERROR_RECEIVER + ":" + ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+ + "," + ACTION_CARRIER_SIGNAL_PCO_VALUE});
+ mContext.sendBroadcast(new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+ waitForMs(50);
+ // verify there is no reset action
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mCarrierActionAgent, times(1))
+ .sendMessageAtTime(messageArgumentCaptor.capture(), anyLong());
+ assertEquals(CarrierActionAgent.CARRIER_ACTION_RESET,
+ messageArgumentCaptor.getValue().what);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockAccountantTest.java b/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockAccountantTest.java
index 2167c13..f7132b8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockAccountantTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ClientWakelockAccountantTest.java
@@ -18,7 +18,6 @@
import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
-import android.test.TestRunner;
import android.os.Build;
import android.util.Log;
import android.telephony.Rlog;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index 419e61b..23e30a2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -59,6 +59,7 @@
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.provider.Telephony.ServiceStateTable;
+import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -234,6 +235,8 @@
return mUsageStatManager;
case Context.BATTERY_SERVICE:
return mBatteryManager;
+ case Context.TELECOM_SERVICE:
+ return mTelecomManager;
case Context.DISPLAY_SERVICE:
case Context.POWER_SERVICE:
// PowerManager and DisplayManager are final classes so cannot be mocked,
@@ -436,7 +439,14 @@
@Override
public int checkCallingOrSelfPermission(String permission) {
- return PackageManager.PERMISSION_GRANTED;
+ if (mPermissionTable.contains(permission)
+ || mPermissionTable.contains(PERMISSION_ENABLE_ALL)) {
+ logd("checkCallingOrSelfPermission: " + permission + " return GRANTED");
+ return PackageManager.PERMISSION_GRANTED;
+ } else {
+ logd("checkCallingOrSelfPermission: " + permission + " return DENIED");
+ return PackageManager.PERMISSION_DENIED;
+ }
}
@Override
@@ -492,6 +502,7 @@
private final UsageStatsManager mUsageStatManager = null;
private final WifiManager mWifiManager = mock(WifiManager.class);
private final BatteryManager mBatteryManager = mock(BatteryManager.class);
+ private final TelecomManager mTelecomManager = mock(TelecomManager.class);
private final ContentProvider mContentProvider = spy(new FakeContentProvider());
@@ -530,6 +541,9 @@
doReturn(mConfiguration).when(mResources).getConfiguration();
mContentResolver.addProvider(Settings.AUTHORITY, mContentProvider);
+ // Settings caches the provider after first get/set call, this is needed to make sure
+ // Settings is using mContentProvider as the cached provider across all tests.
+ Settings.Global.getInt(mContentResolver, Settings.Global.AIRPLANE_MODE_ON, 0);
mContentResolver.addProvider(ServiceStateTable.AUTHORITY, mContentProvider);
mPermissionTable.add(PERMISSION_ENABLE_ALL);
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
index 3f6cd4a..5299b3f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DefaultPhoneNotifierTest.java
@@ -266,11 +266,11 @@
@Test @SmallTest
public void testNotifyOtaspChanged() throws Exception {
- mDefaultPhoneNotifierUT.notifyOtaspChanged(mPhone, ServiceStateTracker.OTASP_NEEDED);
- verify(mTelephonyRegisteryMock).notifyOtaspChanged(ServiceStateTracker.OTASP_NEEDED);
+ mDefaultPhoneNotifierUT.notifyOtaspChanged(mPhone, TelephonyManager.OTASP_NEEDED);
+ verify(mTelephonyRegisteryMock).notifyOtaspChanged(TelephonyManager.OTASP_NEEDED);
- mDefaultPhoneNotifierUT.notifyOtaspChanged(mPhone, ServiceStateTracker.OTASP_UNKNOWN);
- verify(mTelephonyRegisteryMock).notifyOtaspChanged(ServiceStateTracker.OTASP_UNKNOWN);
+ mDefaultPhoneNotifierUT.notifyOtaspChanged(mPhone, TelephonyManager.OTASP_UNKNOWN);
+ verify(mTelephonyRegisteryMock).notifyOtaspChanged(TelephonyManager.OTASP_UNKNOWN);
}
@Test @SmallTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
index 0745092..591b111 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
@@ -33,14 +33,14 @@
import android.os.HandlerThread;
import android.os.Message;
import android.support.test.filters.FlakyTest;
-import android.test.suitebuilder.annotation.SmallTest;
import org.junit.After;
import org.junit.Before;
-import org.junit.Test;
+import org.junit.Ignore;
import java.util.ArrayList;
+@Ignore
public class DeviceStateMonitorTest extends TelephonyTest {
private DeviceStateMonitor mDSM;
@@ -71,13 +71,11 @@
@After
public void tearDown() throws Exception {
mDeviceStateMonitor = null;
- mDeviceStateMonitorTestHandler.quitSafely();
+ mDeviceStateMonitorTestHandler.quit();
super.tearDown();
}
@FlakyTest
- @Test
- @SmallTest
public void testTethering() throws Exception {
// Turn tethering on
Intent intent = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
@@ -103,8 +101,6 @@
}
@FlakyTest
- @Test
- @SmallTest
public void testCharging() throws Exception {
// Charging
Intent intent = new Intent(BatteryManager.ACTION_CHARGING);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
index 077610b..ebb8dad 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaCallTrackerTest.java
@@ -15,7 +15,21 @@
*/
package com.android.internal.telephony;
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.isA;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.os.Handler;
import android.os.HandlerThread;
+import android.os.Message;
import android.support.test.filters.FlakyTest;
import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
@@ -23,21 +37,13 @@
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
-import android.os.Message;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
-import org.mockito.Mock;
import org.mockito.ArgumentCaptor;
-import android.os.Handler;
-
-import static org.junit.Assert.assertNotNull;
-import static org.mockito.Mockito.doReturn;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.*;
-import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
-
+import org.mockito.Mock;
public class GsmCdmaCallTrackerTest extends TelephonyTest {
private static final int VOICE_CALL_STARTED_EVENT = 0;
@@ -47,7 +53,7 @@
private GsmCdmaCallTracker mCTUT;
private GsmCdmaCTHandlerThread mGsmCdmaCTHandlerThread;
@Mock
- GsmCdmaCall mCall;
+ GsmCdmaConnection mConnection;
@Mock
private Handler mHandler;
@@ -68,8 +74,6 @@
super.setUp(this.getClass().getSimpleName());
mSimulatedCommands.setRadioPower(true, null);
mPhone.mCi = this.mSimulatedCommands;
- mContextFixture.putStringArrayResource(com.android.internal.R.array.dial_string_replace,
- new String[]{});
mGsmCdmaCTHandlerThread = new GsmCdmaCTHandlerThread(TAG);
mGsmCdmaCTHandlerThread.start();
@@ -85,7 +89,7 @@
@After
public void tearDown() throws Exception {
mCTUT = null;
- mGsmCdmaCTHandlerThread.quitSafely();
+ mGsmCdmaCTHandlerThread.quit();
super.tearDown();
}
@@ -128,6 +132,8 @@
assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState());
}
+ @FlakyTest
+ @Ignore
@Test
@MediumTest
public void testMOCallHangup() {
@@ -150,6 +156,8 @@
assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
}
+ @FlakyTest
+ @Ignore
@Test
@MediumTest
public void testMOCallDialPickUpHangup() {
@@ -158,8 +166,8 @@
assertEquals(PhoneConstants.State.OFFHOOK, mCTUT.getState());
assertEquals(1, mCTUT.mForegroundCall.getConnections().size());
/* get the reference of the connection before reject */
- Connection mConnection = mCTUT.mForegroundCall.getConnections().get(0);
- assertEquals(DisconnectCause.NOT_DISCONNECTED, mConnection.getDisconnectCause());
+ Connection connection = mCTUT.mForegroundCall.getConnections().get(0);
+ assertEquals(DisconnectCause.NOT_DISCONNECTED, connection.getDisconnectCause());
logd("hang up MO call after pickup");
try {
mCTUT.hangup(mCTUT.mForegroundCall);
@@ -172,7 +180,7 @@
assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState());
assertEquals(0, mCTUT.mForegroundCall.getConnections().size());
assertEquals(PhoneConstants.State.IDLE, mCTUT.getState());
- assertEquals(DisconnectCause.LOCAL, mConnection.getDisconnectCause());
+ assertEquals(DisconnectCause.LOCAL, connection.getDisconnectCause());
}
@@ -223,6 +231,8 @@
@Test
@SmallTest
+ @FlakyTest
+ @Ignore
public void testMTCallRinging() {
/* Mock there is a MT call mRinging call and try to accept this MT call */
/* if we got a active state followed by another MT call-> move to background call */
@@ -239,6 +249,8 @@
@Test
@SmallTest
+ @FlakyTest
+ @Ignore
public void testMTCallAccept() {
testMTCallRinging();
assertEquals(mCTUT.mForegroundCall.getConnections().size(),0);
@@ -264,9 +276,9 @@
testMTCallRinging();
logd("MT call ringing and rejected ");
/* get the reference of the connection before reject */
- Connection mConnection = mCTUT.mRingingCall.getConnections().get(0);
- assertNotNull(mConnection);
- assertEquals(DisconnectCause.NOT_DISCONNECTED, mConnection.getDisconnectCause());
+ Connection connection = mCTUT.mRingingCall.getConnections().get(0);
+ assertNotNull(connection);
+ assertEquals(DisconnectCause.NOT_DISCONNECTED, connection.getDisconnectCause());
try {
mCTUT.rejectCall();
} catch(Exception ex) {
@@ -278,10 +290,11 @@
assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mForegroundCall.getState());
assertEquals(0, mCTUT.mForegroundCall.getConnections().size());
/* ? why rejectCall didnt -> hang up locally to set the cause to LOCAL? */
- assertEquals(DisconnectCause.INCOMING_MISSED, mConnection.getDisconnectCause());
+ assertEquals(DisconnectCause.INCOMING_MISSED, connection.getDisconnectCause());
}
+ @FlakyTest
@Test
@MediumTest
public void testMOCallSwitchHangupForeGround() {
@@ -300,6 +313,8 @@
assertEquals(GsmCdmaCall.State.HOLDING, mCTUT.mBackgroundCall.getState());
}
+ @FlakyTest
+ @Ignore
@Test
@MediumTest
public void testMOCallPickUpHangUpResumeBackGround() {
@@ -338,11 +353,14 @@
testMOCallPickUp();
ArgumentCaptor<Message> mCaptorMessage = ArgumentCaptor.forClass(Message.class);
ArgumentCaptor<Long> mCaptorLong = ArgumentCaptor.forClass(Long.class);
- verify(mHandler,times(1)).sendMessageAtTime(mCaptorMessage.capture(), mCaptorLong.capture());
+ verify(mHandler, times(1))
+ .sendMessageAtTime(mCaptorMessage.capture(), mCaptorLong.capture());
assertEquals(VOICE_CALL_STARTED_EVENT, mCaptorMessage.getValue().what);
}
+ @FlakyTest
+ @Ignore
@Test @SmallTest
public void testVoiceCallEndedListener(){
logd("register for voice call ended event");
@@ -350,7 +368,8 @@
ArgumentCaptor<Message> mCaptorMessage = ArgumentCaptor.forClass(Message.class);
ArgumentCaptor<Long> mCaptorLong = ArgumentCaptor.forClass(Long.class);
testMOCallHangup();
- verify(mHandler,times(1)).sendMessageAtTime(mCaptorMessage.capture(), mCaptorLong.capture());
+ verify(mHandler, times(1))
+ .sendMessageAtTime(mCaptorMessage.capture(), mCaptorLong.capture());
assertEquals(VOICE_CALL_ENDED_EVENT, mCaptorMessage.getValue().what);
}
@@ -390,5 +409,27 @@
assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mBackgroundCall.getState());
assertEquals(GsmCdmaCall.State.IDLE, mCTUT.mRingingCall.getState());
}
-}
+ @Test
+ @SmallTest
+ public void testUpdatePhoneTypeWithActiveCall() {
+ // verify getCurrentCalls is called on init
+ verify(mSimulatedCommandsVerifier).getCurrentCalls(any(Message.class));
+
+ // fake connection
+ mCTUT.mConnections[0] = mConnection;
+
+ // update phone type (call the function on same thread as the call tracker)
+ Handler updatePhoneTypeHandler = new Handler(mCTUT.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ mCTUT.updatePhoneType();
+ }
+ };
+ updatePhoneTypeHandler.sendEmptyMessage(0);
+ waitForMs(100);
+
+ // verify that the active call is disconnected
+ verify(mConnection).onDisconnect(DisconnectCause.ERROR_UNSPECIFIED);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 39fdf13..3a80fe0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -16,6 +16,24 @@
package com.android.internal.telephony;
+import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
+import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.nullable;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import android.app.Activity;
import android.app.IApplicationThread;
import android.content.IIntentReceiver;
@@ -44,29 +62,13 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import java.util.List;
-import static com.android.internal.telephony.CommandsInterface.CF_ACTION_ENABLE;
-import static com.android.internal.telephony.CommandsInterface.CF_REASON_UNCONDITIONAL;
-import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Matchers.nullable;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.atLeast;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
public class GsmCdmaPhoneTest extends TelephonyTest {
@Mock
private Handler mTestHandler;
@@ -132,7 +134,7 @@
public void tearDown() throws Exception {
mPhoneUT.removeCallbacksAndMessages(null);
mPhoneUT = null;
- mGsmCdmaPhoneTestHandler.quitSafely();
+ mGsmCdmaPhoneTestHandler.quit();
super.tearDown();
}
@@ -403,7 +405,7 @@
@FlakyTest
@Test
- @SmallTest
+ @Ignore
public void testVoiceMailCount() {
// initial value
assertEquals(0, mPhoneUT.getVoiceMessageCount());
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
index f2e5da1..06cd54f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmSmsTest.java
@@ -41,6 +41,10 @@
assertEquals("+14155551212", sms.getServiceCenterAddress());
assertEquals("+16505551111", sms.getOriginatingAddress());
assertEquals("(Subject)Test", sms.getMessageBody());
+
+ pdu = "07914151551512F20409E1BADCBE5AF100006060605130308A04D4F29C0E";
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+ assertEquals("*#abc#*51", sms.getOriginatingAddress());
}
@SmallTest
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsSMSDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsSMSDispatcherTest.java
index 24c1283..105e0f8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ImsSMSDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ImsSMSDispatcherTest.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony;
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -24,11 +26,11 @@
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -36,13 +38,13 @@
import android.content.IntentFilter;
import android.os.HandlerThread;
import android.os.Message;
+import android.test.FlakyTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Singleton;
-import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
-
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -95,11 +97,11 @@
@After
public void tearDown() throws Exception {
mImsSmsDispatcher = null;
- mImsSmsDispatcherTestHandler.quitSafely();
+ mImsSmsDispatcherTestHandler.quit();
super.tearDown();
}
- @Test @SmallTest
+ @Test @SmallTest @FlakyTest @Ignore
public void testSmsHandleStateUpdate() throws Exception {
assertEquals(SmsConstants.FORMAT_UNKNOWN, mImsSmsDispatcher.getImsSmsFormat());
//Mock ImsNetWorkStateChange with GSM phone type
@@ -113,7 +115,7 @@
assertTrue(mImsSmsDispatcher.isIms());
}
- @Test @SmallTest
+ @Test @SmallTest @FlakyTest @Ignore
public void testSendImsGmsTest() throws Exception {
switchImsSmsFormat(PhoneConstants.PHONE_TYPE_GSM);
mImsSmsDispatcher.sendText("111"/* desAddr*/, "222" /*scAddr*/, TAG,
@@ -172,7 +174,7 @@
// unmock ActivityManager to be able to register receiver, create real PendingIntent and
// receive TEST_INTENT
restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton);
- restoreInstance(ActivityManagerNative.class, "gDefault", null);
+ restoreInstance(ActivityManager.class, "IActivityManagerSingleton", null);
Context realContext = TestApplication.getAppContext();
realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ImsiEncryptionInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/ImsiEncryptionInfoTest.java
new file mode 100644
index 0000000..761bd5f
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/ImsiEncryptionInfoTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.telephony.ImsiEncryptionInfo;
+import android.telephony.TelephonyManager;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Base64;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.PublicKey;
+import java.security.cert.CertificateFactory;
+import java.util.Date;
+
+public class ImsiEncryptionInfoTest {
+ private ImsiEncryptionInfo mImsiEncryptionInfo;
+ private PublicKey mPublicKey;
+ private Date mDate = new Date(1496795015);
+
+ private static final String TEST_CERT = ""
+ + "MIIDsjCCAxugAwIBAgIJAPLf2gS0zYGUMA0GCSqGSIb3DQEBBQUAMIGYMQswCQYDVQQGEwJVUzET"
+ + "MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEPMA0GA1UEChMGR29v"
+ + "Z2xlMRAwDgYDVQQLEwd0ZXN0aW5nMRYwFAYDVQQDEw1HZXJlbXkgQ29uZHJhMSEwHwYJKoZIhvcN"
+ + "AQkBFhJnY29uZHJhQGdvb2dsZS5jb20wHhcNMTIwNzE0MTc1MjIxWhcNMTIwODEzMTc1MjIxWjCB"
+ + "mDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZp"
+ + "ZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHdGVzdGluZzEWMBQGA1UEAxMNR2VyZW15IENv"
+ + "bmRyYTEhMB8GCSqGSIb3DQEJARYSZ2NvbmRyYUBnb29nbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUA"
+ + "A4GNADCBiQKBgQCjGGHATBYlmas+0sEECkno8LZ1KPglb/mfe6VpCT3GhSr+7br7NG/ZwGZnEhLq"
+ + "E7YIH4fxltHmQC3Tz+jM1YN+kMaQgRRjo/LBCJdOKaMwUbkVynAH6OYsKevjrOPk8lfM5SFQzJMG"
+ + "sA9+Tfopr5xg0BwZ1vA/+E3mE7Tr3M2UvwIDAQABo4IBADCB/TAdBgNVHQ4EFgQUhzkS9E6G+x8W"
+ + "L4EsmRjDxu28tHUwgc0GA1UdIwSBxTCBwoAUhzkS9E6G+x8WL4EsmRjDxu28tHWhgZ6kgZswgZgx"
+ + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3"
+ + "MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB3Rlc3RpbmcxFjAUBgNVBAMTDUdlcmVteSBDb25k"
+ + "cmExITAfBgkqhkiG9w0BCQEWEmdjb25kcmFAZ29vZ2xlLmNvbYIJAPLf2gS0zYGUMAwGA1UdEwQF"
+ + "MAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAYiugFDmbDOQ2U/+mqNt7o8ftlEo9SJrns6O8uTtK6AvR"
+ + "orDrR1AXTXkuxwLSbmVfedMGOZy7Awh7iZa8hw5x9XmUudfNxvmrKVEwGQY2DZ9PXbrnta/dwbhK"
+ + "mWfoepESVbo7CKIhJp8gRW0h1Z55ETXD57aGJRvQS4pxkP8ANhM=";
+
+ @After
+ public void tearDown() throws Exception {
+ mImsiEncryptionInfo = null;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ mPublicKey = createPublicKey(TEST_CERT);
+ mImsiEncryptionInfo = new ImsiEncryptionInfo("310", "270", TelephonyManager.KEY_TYPE_WLAN,
+ "key1=value", mPublicKey, mDate);
+ }
+
+ private static PublicKey createPublicKey(String cert) throws Exception {
+ byte[] derCert = Base64.decode(cert.getBytes(), Base64.DEFAULT);
+ InputStream istream = new ByteArrayInputStream(derCert);
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ return cf.generateCertificate(istream).getPublicKey();
+ }
+
+ /**
+ * Tests that all the class variables are set correctly.
+ */
+ @Test
+ @SmallTest
+ public void testSubProperties() {
+ assertEquals("310", mImsiEncryptionInfo.getMcc());
+ assertEquals("270", mImsiEncryptionInfo.getMnc());
+ assertEquals(TelephonyManager.KEY_TYPE_WLAN, mImsiEncryptionInfo.getKeyType());
+ assertEquals("key1=value", mImsiEncryptionInfo.getKeyIdentifier());
+ Date date = mImsiEncryptionInfo.getExpirationTime();
+ assertEquals(mDate, mImsiEncryptionInfo.getExpirationTime());
+ }
+
+ /**
+ * Tests the parceling/un-parceling of the object.
+ */
+ @Test
+ @SmallTest
+ public void testParcel() {
+ Parcel p = Parcel.obtain();
+ p.setDataPosition(0);
+ mImsiEncryptionInfo.writeToParcel(p, 0);
+ p.setDataPosition(0);
+ ImsiEncryptionInfo nw = new ImsiEncryptionInfo(p);
+ assertEquals("310", mImsiEncryptionInfo.getMcc());
+ assertEquals("270", mImsiEncryptionInfo.getMnc());
+ assertEquals(TelephonyManager.KEY_TYPE_WLAN, mImsiEncryptionInfo.getKeyType());
+ assertEquals("key1=value", mImsiEncryptionInfo.getKeyIdentifier());
+ assertEquals(mPublicKey, mImsiEncryptionInfo.getPublicKey());
+ assertEquals(mDate, mImsiEncryptionInfo.getExpirationTime());
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java b/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
index e88a783..de98c67 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/MccTableTest.java
@@ -33,6 +33,9 @@
assertEquals("Asia/Tokyo", MccTable.defaultTimeZoneForMcc(441));
assertEquals("Asia/Singapore", MccTable.defaultTimeZoneForMcc(525));
assertEquals("Europe/Stockholm", MccTable.defaultTimeZoneForMcc(240));
+
+ /* A test for the special handling for MCC 505. http://b/33228250. */
+ assertEquals("Australia/Sydney", MccTable.defaultTimeZoneForMcc(505));
assertEquals(null, MccTable.defaultTimeZoneForMcc(0)); // mcc not defined, hence default
assertEquals(null, MccTable.defaultTimeZoneForMcc(2000)); // mcc not defined, hence default
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java b/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java
index b63dc71..f49fffd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/NeighboringCellInfoTest.java
@@ -18,7 +18,7 @@
import android.os.Parcel;
import android.test.AndroidTestCase;
import android.telephony.NeighboringCellInfo;
-import android.test. suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.SmallTest;
import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
import static android.telephony.TelephonyManager.NETWORK_TYPE_EDGE;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java
new file mode 100644
index 0000000..fe75088
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanRequestTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.telephony.NetworkScanRequest;
+import android.telephony.RadioAccessSpecifier;
+import android.telephony.RadioNetworkConstants.EutranBands;
+import android.telephony.RadioNetworkConstants.GeranBands;
+import android.telephony.RadioNetworkConstants.RadioAccessNetworks;
+
+import org.junit.Test;
+
+/** Unit tests for {@link NetworkScanRequest}. */
+
+public class NetworkScanRequestTest {
+
+ @Test
+ @SmallTest
+ public void testParcel() {
+ int ranGsm = RadioAccessNetworks.GERAN;
+ int[] gsmBands = {GeranBands.BAND_T380, GeranBands.BAND_T410};
+ int[] gsmChannels = {1, 2, 3, 4};
+ RadioAccessSpecifier gsm = new RadioAccessSpecifier(ranGsm, gsmBands, gsmChannels);
+ int ranLte = RadioAccessNetworks.EUTRAN;
+ int[] lteBands = {EutranBands.BAND_10, EutranBands.BAND_11};
+ int[] lteChannels = {5, 6, 7, 8};
+ RadioAccessSpecifier lte = new RadioAccessSpecifier(ranLte, lteBands, lteChannels);
+ RadioAccessSpecifier[] ras = {gsm, lte};
+ NetworkScanRequest nsq = new NetworkScanRequest(NetworkScanRequest.SCAN_TYPE_ONE_SHOT, ras);
+
+ Parcel p = Parcel.obtain();
+ nsq.writeToParcel(p, 0);
+ p.setDataPosition(0);
+
+ NetworkScanRequest newNsq = NetworkScanRequest.CREATOR.createFromParcel(p);
+ assertEquals(nsq, newNsq);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java
new file mode 100644
index 0000000..f149211
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkScanResultTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.telephony.CellIdentityGsm;
+import android.telephony.CellIdentityLte;
+import android.telephony.CellInfo;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellSignalStrengthGsm;
+import android.telephony.CellSignalStrengthLte;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+/** Unit tests for {@link NetworkScanResult}. */
+
+public class NetworkScanResultTest {
+
+ @Test
+ @SmallTest
+ public void testParcel() {
+ ArrayList<CellInfo> infos = new ArrayList<CellInfo>();
+
+ CellIdentityGsm cig = new CellIdentityGsm(310, 310, 1, 2, 3, 4);
+ CellSignalStrengthGsm cssg = new CellSignalStrengthGsm();
+ cssg.initialize(5, 6, 7);
+ CellInfoGsm gsm = new CellInfoGsm();
+ gsm.setRegistered(true);
+ gsm.setTimeStampType(8);
+ gsm.setTimeStamp(9);
+ gsm.setCellIdentity(cig);
+ gsm.setCellSignalStrength(cssg);
+ infos.add(gsm);
+
+ CellIdentityLte cil = new CellIdentityLte(320, 320, 11, 12, 13, 14);
+ CellSignalStrengthLte cssl = new CellSignalStrengthLte();
+ cssl.initialize(15, 16, 17, 18, 19, 20);
+ CellInfoLte lte = new CellInfoLte();
+ lte.setRegistered(false);
+ lte.setTimeStampType(21);
+ lte.setTimeStamp(22);
+ lte.setCellIdentity(cil);
+ lte.setCellSignalStrength(cssl);
+ infos.add(lte);
+
+ NetworkScanResult nsr = new NetworkScanResult(0, 0, infos);
+
+ Parcel p = Parcel.obtain();
+ nsr.writeToParcel(p, 0);
+ p.setDataPosition(0);
+
+ NetworkScanResult newNsr = NetworkScanResult.CREATOR.createFromParcel(p);
+ assertEquals(nsr, newNsr);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index 0c8c3aa..faeabd5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -16,16 +16,24 @@
package com.android.internal.telephony;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
import android.net.Uri;
import android.support.test.filters.FlakyTest;
import android.telephony.PhoneNumberUtils;
-import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.SpannableStringBuilder;
-public class PhoneNumberUtilsTest extends AndroidTestCase {
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class PhoneNumberUtilsTest {
@SmallTest
+ @Test
public void testExtractNetworkPortion() throws Exception {
assertEquals(
"+17005554141",
@@ -192,6 +200,21 @@
}
@SmallTest
+ @Test
+ public void testNonIntegerAddress() {
+ byte[] b = new byte[6];
+ b[0] = (byte) 0x81; b[1] = (byte) 0xba; b[2] = (byte) 0xdc; b[3] = (byte) 0xbe;
+ b[4] = (byte) 0x5a; b[5] = (byte) 0xf1;
+ assertEquals("*#abc#*51",
+ PhoneNumberUtils.calledPartyBCDToString(
+ b, 0, 6, PhoneNumberUtils.BCD_EXTENDED_TYPE_CALLED_PARTY));
+ assertEquals("*#,N;#*51",
+ PhoneNumberUtils.calledPartyBCDToString(
+ b, 0, 6, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN));
+ }
+
+ @SmallTest
+ @Test
public void testExtractNetworkPortionAlt() throws Exception {
assertEquals(
"+17005554141",
@@ -254,6 +277,7 @@
}
@SmallTest
+ @Test
public void testB() throws Exception {
assertEquals("", PhoneNumberUtils.extractPostDialPortion("+17005554141"));
assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-4141"));
@@ -265,6 +289,7 @@
}
@SmallTest
+ @Test
public void testCompare() throws Exception {
// this is odd
assertFalse(PhoneNumberUtils.compare("", ""));
@@ -330,8 +355,8 @@
assertTrue(PhoneNumberUtils.compare("404-04", "40404"));
}
-
@SmallTest
+ @Test
public void testToCallerIDIndexable() throws Exception {
assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("17005554141"));
assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141"));
@@ -349,6 +374,7 @@
}
@SmallTest
+ @Test
public void testGetIndexable() throws Exception {
assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141"));
assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141,1234"));
@@ -365,6 +391,7 @@
}
@SmallTest
+ @Test
public void testNanpFormatting() {
SpannableStringBuilder number = new SpannableStringBuilder();
number.append("8005551212");
@@ -393,6 +420,7 @@
}
@SmallTest
+ @Test
public void testConvertKeypadLettersToDigits() {
assertEquals("1-800-4664-411",
PhoneNumberUtils.convertKeypadLettersToDigits("1-800-GOOG-411"));
@@ -467,6 +495,7 @@
}
@SmallTest
+ @Test
public void testCheckAndProcessPlusCodeByNumberFormat() {
assertEquals("18475797000",
PhoneNumberUtils.cdmaCheckAndProcessPlusCodeByNumberFormat("+18475797000",
@@ -477,6 +506,7 @@
* Basic checks for the VoiceMail number.
*/
@SmallTest
+ @Test
public void testWithNumberNotEqualToVoiceMail() throws Exception {
assertFalse(PhoneNumberUtils.isVoiceMailNumber("911"));
assertFalse(PhoneNumberUtils.isVoiceMailNumber("tel:911"));
@@ -492,6 +522,7 @@
}
@SmallTest
+ @Test
public void testFormatNumberToE164() {
// Note: ISO 3166-1 only allows upper case country codes.
assertEquals("+16502910000", PhoneNumberUtils.formatNumberToE164("650 2910000", "US"));
@@ -500,6 +531,7 @@
}
@SmallTest
+ @Test
public void testFormatNumber() {
assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "US"));
assertEquals("223-4567", PhoneNumberUtils.formatNumber("2234567", "US"));
@@ -515,6 +547,7 @@
* current country is not Japan.
*/
@SmallTest
+ @Test
public void testFormatJapanInternational() {
assertEquals("+81 90-6657-1180", PhoneNumberUtils.formatNumber("+819066571180", "US"));
}
@@ -524,6 +557,7 @@
* country is Japan.
*/
@SmallTest
+ @Test
public void testFormatJapanNational() {
assertEquals("090-6657-0660", PhoneNumberUtils.formatNumber("09066570660", "JP"));
assertEquals("090-6657-1180", PhoneNumberUtils.formatNumber("+819066571180", "JP"));
@@ -533,6 +567,7 @@
}
@SmallTest
+ @Test
public void testFormatNumber_LeadingStarAndHash() {
// Numbers with a leading '*' or '#' should be left unchanged.
assertEquals("*650 2910000", PhoneNumberUtils.formatNumber("*650 2910000", "US"));
@@ -546,6 +581,7 @@
}
@SmallTest
+ @Test
public void testNormalizeNumber() {
assertEquals("6502910000", PhoneNumberUtils.normalizeNumber("650 2910000"));
assertEquals("1234567", PhoneNumberUtils.normalizeNumber("12,3#4*567"));
@@ -554,6 +590,7 @@
}
@SmallTest
+ @Test
public void testFormatDailabeNumber() {
// Using the phoneNumberE164's country code
assertEquals("(650) 291-0000",
@@ -585,7 +622,8 @@
}
@FlakyTest
- @SmallTest
+ @Test
+ @Ignore
public void testIsEmergencyNumber() {
// There are two parallel sets of tests here: one for the
// regular isEmergencyNumber() method, and the other for
@@ -639,6 +677,7 @@
}
@SmallTest
+ @Test
public void testStripSeparators() {
// Smoke tests which should never fail.
assertEquals("1234567890", PhoneNumberUtils.stripSeparators("1234567890"));
@@ -654,6 +693,7 @@
}
@SmallTest
+ @Test
public void testConvertAndStrip() {
// Smoke tests which should never fail.
assertEquals("1234567890", PhoneNumberUtils.convertAndStrip("1234567890"));
@@ -670,6 +710,7 @@
}
@SmallTest
+ @Test
public void testConvertSipUriToTelUri1() {
// Nominal case, a tel Uri came in, so we expect one out.
Uri source = Uri.fromParts("tel", "+16505551212", null);
@@ -692,7 +733,10 @@
}
@SmallTest
+ @Test
public void testIsInternational() {
+ assertFalse(PhoneNumberUtils.isInternationalNumber("", "US"));
+ assertFalse(PhoneNumberUtils.isInternationalNumber(null, "US"));
assertFalse(PhoneNumberUtils.isInternationalNumber("+16505551212", "US"));
assertTrue(PhoneNumberUtils.isInternationalNumber("+16505551212", "UK"));
assertTrue(PhoneNumberUtils.isInternationalNumber("+16505551212", "JP"));
@@ -703,4 +747,21 @@
assertTrue(PhoneNumberUtils.isInternationalNumber("011-613-966-94916", "US"));
assertFalse(PhoneNumberUtils.isInternationalNumber("011-613-966-94916", "AU"));
}
+
+ @SmallTest
+ @Test
+ public void testIsUriNumber() {
+ assertTrue(PhoneNumberUtils.isUriNumber("foo@google.com"));
+ assertTrue(PhoneNumberUtils.isUriNumber("xyz@zzz.org"));
+ assertFalse(PhoneNumberUtils.isUriNumber("+15103331245"));
+ assertFalse(PhoneNumberUtils.isUriNumber("+659231235"));
+ }
+
+ @SmallTest
+ @Test
+ public void testGetUsernameFromUriNumber() {
+ assertEquals("john", PhoneNumberUtils.getUsernameFromUriNumber("john@myorg.com"));
+ assertEquals("tim_123", PhoneNumberUtils.getUsernameFromUriNumber("tim_123@zzz.org"));
+ assertEquals("5103331245", PhoneNumberUtils.getUsernameFromUriNumber("5103331245"));
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java
index 4a17199..fdda80f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneStateListenerTest.java
@@ -60,7 +60,7 @@
@After
public void tearDown() throws Exception {
- mPhoneStateListenerHandler.quitSafely();
+ mPhoneStateListenerHandler.quit();
super.tearDown();
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
index e68262f..b5ec320 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/PhoneSwitcherTest.java
@@ -388,6 +388,12 @@
// }
// if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
// if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
+
+ for (int i = 0; i < numPhones; i++) {
+ commandsInterfaces[i].dispose();
+ }
+
+ connectivityServiceMock.die();
testHandler.die();
handlerThread.quit();
}
@@ -468,6 +474,11 @@
if (commandsInterfaces[0].isDataAllowed()) fail("data allowed");
if (commandsInterfaces[1].isDataAllowed() == false) fail("data not allowed");
+ for (int i = 0; i < numPhones; i++) {
+ commandsInterfaces[i].dispose();
+ }
+
+ connectivityServiceMock.die();
testHandler.die();
handlerThread.quit();
}
@@ -537,6 +548,11 @@
if (commandsInterfaces[0].isDataAllowed() == false) fail("data not allowed");
if (commandsInterfaces[1].isDataAllowed()) fail("data allowed");
+ for (int i = 0; i < numPhones; i++) {
+ commandsInterfaces[i].dispose();
+ }
+
+ connectivityServiceMock.die();
testHandler.die();
handlerThread.quit();
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/RadioAccessSpecifierTest.java b/tests/telephonytests/src/com/android/internal/telephony/RadioAccessSpecifierTest.java
new file mode 100644
index 0000000..653c357
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/RadioAccessSpecifierTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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 org.junit.Assert.assertEquals;
+
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.telephony.RadioAccessSpecifier;
+import android.telephony.RadioNetworkConstants.GeranBands;
+import android.telephony.RadioNetworkConstants.RadioAccessNetworks;
+
+import org.junit.Test;
+
+/** Unit tests for {@link RadioAccessSpecifier}. */
+
+public class RadioAccessSpecifierTest {
+
+ @Test
+ @SmallTest
+ public void testParcel() {
+ int ranGsm = RadioAccessNetworks.GERAN;
+ int[] gsmBands = {GeranBands.BAND_T380, GeranBands.BAND_T410};
+ int[] gsmChannels = {1, 2, 3, 4};
+ RadioAccessSpecifier ras = new RadioAccessSpecifier(ranGsm, gsmBands, gsmChannels);
+
+ Parcel p = Parcel.obtain();
+ ras.writeToParcel(p, 0);
+ p.setDataPosition(0);
+
+ RadioAccessSpecifier newRas = RadioAccessSpecifier.CREATOR.createFromParcel(p);
+ assertEquals(ras, newRas);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 3be623c..15897d4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -26,6 +26,7 @@
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.nullable;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
@@ -44,10 +45,12 @@
import android.os.HandlerThread;
import android.os.Message;
import android.os.Parcel;
+import android.os.PersistableBundle;
import android.os.Process;
import android.os.UserHandle;
import android.os.WorkSource;
import android.support.test.filters.FlakyTest;
+import android.telephony.CarrierConfigManager;
import android.telephony.CellInfo;
import android.telephony.CellInfoGsm;
import android.telephony.ServiceState;
@@ -70,6 +73,7 @@
import org.mockito.Mock;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
public class ServiceStateTrackerTest extends TelephonyTest {
@@ -85,16 +89,19 @@
private ServiceStateTracker sst;
private ServiceStateTrackerTestHandler mSSTTestHandler;
+ private PersistableBundle mBundle;
private static final int EVENT_REGISTERED_TO_NETWORK = 1;
private static final int EVENT_SUBSCRIPTION_INFO_READY = 2;
- private static final int EVENT_ROAMING_ON = 3;
- private static final int EVENT_ROAMING_OFF = 4;
+ private static final int EVENT_DATA_ROAMING_ON = 3;
+ private static final int EVENT_DATA_ROAMING_OFF = 4;
private static final int EVENT_DATA_CONNECTION_ATTACHED = 5;
private static final int EVENT_DATA_CONNECTION_DETACHED = 6;
private static final int EVENT_DATA_RAT_CHANGED = 7;
private static final int EVENT_PS_RESTRICT_ENABLED = 8;
private static final int EVENT_PS_RESTRICT_DISABLED = 9;
+ private static final int EVENT_VOICE_ROAMING_ON = 10;
+ private static final int EVENT_VOICE_ROAMING_OFF = 11;
private class ServiceStateTrackerTestHandler extends HandlerThread {
@@ -119,14 +126,12 @@
mPhone.mDcTracker = mDct;
replaceInstance(ProxyController.class, "sProxyController", null, mProxyController);
+ mBundle = mContextFixture.getCarrierConfigBundle();
+ mBundle.putStringArray(
+ CarrierConfigManager.KEY_ROAMING_OPERATOR_STRING_ARRAY, new String[]{"123456"});
- mContextFixture.putStringArrayResource(
- com.android.internal.R.array.config_sameNamedOperatorConsideredRoaming,
- new String[]{"123456"});
-
- mContextFixture.putStringArrayResource(
- com.android.internal.R.array.config_operatorConsideredNonRoaming,
- new String[]{"123456"});
+ mBundle.putStringArray(
+ CarrierConfigManager.KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, new String[]{"123456"});
mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_HOME);
mSimulatedCommands.setVoiceRadioTech(ServiceState.RIL_RADIO_TECHNOLOGY_HSPA);
@@ -146,7 +151,7 @@
@After
public void tearDown() throws Exception {
sst = null;
- mSSTTestHandler.quitSafely();
+ mSSTTestHandler.quit();
super.tearDown();
}
@@ -326,7 +331,6 @@
assertFalse(sst.isImsRegistered());
}
- @FlakyTest
@Test
@MediumTest
public void testSignalStrength() {
@@ -360,14 +364,15 @@
sst.mSS.setRilDataRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_LTE);
mSimulatedCommands.notifySignalStrength();
- waitForMs(200);
+ waitForMs(300);
assertEquals(sst.getSignalStrength(), ss);
assertEquals(sst.getSignalStrength().isGsm(), true);
// notify signal strength again, but this time data RAT is not LTE
+ sst.mSS.setRilVoiceRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT);
sst.mSS.setRilDataRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD);
mSimulatedCommands.notifySignalStrength();
- waitForMs(200);
+ waitForMs(300);
assertEquals(sst.getSignalStrength(), ss);
assertEquals(sst.getSignalStrength().isGsm(), false);
}
@@ -439,7 +444,7 @@
@Test
@MediumTest
public void testRegAndUnregForVoiceRoamingOn() throws Exception {
- sst.registerForVoiceRoamingOn(mTestHandler, EVENT_ROAMING_ON, null);
+ sst.registerForVoiceRoamingOn(mTestHandler, EVENT_DATA_ROAMING_ON, null);
// Enable roaming and trigger events to notify handler registered
doReturn(true).when(mPhone).isPhoneTypeGsm();
@@ -447,12 +452,12 @@
mSimulatedCommands.setDataRegState(ServiceState.RIL_REG_STATE_ROAMING);
mSimulatedCommands.notifyNetworkStateChanged();
- waitForMs(100);
+ waitForMs(200);
// verify if registered handler has message posted to it
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong());
- assertEquals(EVENT_ROAMING_ON, messageArgumentCaptor.getValue().what);
+ assertEquals(EVENT_DATA_ROAMING_ON, messageArgumentCaptor.getValue().what);
// Disable roaming
mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_HOME);
@@ -469,7 +474,7 @@
mSimulatedCommands.setDataRegState(ServiceState.RIL_REG_STATE_ROAMING);
mSimulatedCommands.notifyNetworkStateChanged();
- waitForMs(100);
+ waitForMs(200);
// verify that no new message posted to handler
verify(mTestHandler, times(1)).sendMessageAtTime(any(Message.class), anyLong());
@@ -486,7 +491,7 @@
waitForMs(100);
- sst.registerForVoiceRoamingOff(mTestHandler, EVENT_ROAMING_OFF, null);
+ sst.registerForVoiceRoamingOff(mTestHandler, EVENT_DATA_ROAMING_OFF, null);
// Disable roaming
doReturn(true).when(mPhone).isPhoneTypeGsm();
@@ -494,12 +499,12 @@
mSimulatedCommands.setDataRegState(ServiceState.RIL_REG_STATE_HOME);
mSimulatedCommands.notifyNetworkStateChanged();
- waitForMs(100);
+ waitForMs(200);
// verify if registered handler has message posted to it
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong());
- assertEquals(EVENT_ROAMING_OFF, messageArgumentCaptor.getValue().what);
+ assertEquals(EVENT_DATA_ROAMING_OFF, messageArgumentCaptor.getValue().what);
// Enable roaming
mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_ROAMING);
@@ -525,7 +530,7 @@
@Test
@MediumTest
public void testRegAndUnregForDataRoamingOn() throws Exception {
- sst.registerForDataRoamingOn(mTestHandler, EVENT_ROAMING_ON, null);
+ sst.registerForDataRoamingOn(mTestHandler, EVENT_DATA_ROAMING_ON, null);
// Enable roaming and trigger events to notify handler registered
doReturn(true).when(mPhone).isPhoneTypeGsm();
@@ -533,12 +538,12 @@
mSimulatedCommands.setDataRegState(ServiceState.RIL_REG_STATE_ROAMING);
mSimulatedCommands.notifyNetworkStateChanged();
- waitForMs(100);
+ waitForMs(200);
// verify if registered handler has message posted to it
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong());
- assertEquals(EVENT_ROAMING_ON, messageArgumentCaptor.getValue().what);
+ assertEquals(EVENT_DATA_ROAMING_ON, messageArgumentCaptor.getValue().what);
// Disable roaming
mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_HOME);
@@ -555,7 +560,7 @@
mSimulatedCommands.setDataRegState(ServiceState.RIL_REG_STATE_ROAMING);
mSimulatedCommands.notifyNetworkStateChanged();
- waitForMs(100);
+ waitForMs(200);
// verify that no new message posted to handler
verify(mTestHandler, times(1)).sendMessageAtTime(any(Message.class), anyLong());
@@ -572,7 +577,7 @@
waitForMs(100);
- sst.registerForDataRoamingOff(mTestHandler, EVENT_ROAMING_OFF, null);
+ sst.registerForDataRoamingOff(mTestHandler, EVENT_DATA_ROAMING_OFF, null, true);
// Disable roaming
doReturn(true).when(mPhone).isPhoneTypeGsm();
@@ -585,7 +590,7 @@
// verify if registered handler has message posted to it
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
verify(mTestHandler).sendMessageAtTime(messageArgumentCaptor.capture(), anyLong());
- assertEquals(EVENT_ROAMING_OFF, messageArgumentCaptor.getValue().what);
+ assertEquals(EVENT_DATA_ROAMING_OFF, messageArgumentCaptor.getValue().what);
// Enable roaming
mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_ROAMING);
@@ -716,7 +721,7 @@
mSimulatedCommands.setDataRegState(ServiceState.RIL_REG_STATE_UNKNOWN);
mSimulatedCommands.notifyNetworkStateChanged();
- waitForMs(100);
+ waitForMs(200);
// verify if registered handler has message posted to it
ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
@@ -902,7 +907,14 @@
doReturn(true).when(mPhone).isPhoneTypeGsm();
doReturn(IccCardApplicationStatus.AppState.APPSTATE_READY).when(
mUiccCardApplication3gpp).getState();
- spySst.updatePhoneType();
+
+ ArgumentCaptor<Integer> intArgumentCaptor = ArgumentCaptor.forClass(Integer.class);
+ verify(mSimulatedCommandsVerifier).setOnRestrictedStateChanged(any(Handler.class),
+ intArgumentCaptor.capture(), eq(null));
+ // Since spy() creates a copy of sst object we need to call
+ // setOnRestrictedStateChanged() explicitly.
+ mSimulatedCommands.setOnRestrictedStateChanged(spySst,
+ intArgumentCaptor.getValue().intValue(), null);
// Combination of restricted state and expected notification type.
final int CS_ALL[] = {RILConstants.RIL_RESTRICTED_STATE_CS_ALL,
@@ -978,6 +990,40 @@
}
@Test
+ @MediumTest
+ public void testRoamingPhoneTypeSwitch() {
+ // Enable roaming
+ doReturn(true).when(mPhone).isPhoneTypeGsm();
+
+ mSimulatedCommands.setVoiceRegState(ServiceState.RIL_REG_STATE_ROAMING);
+ mSimulatedCommands.setDataRegState(ServiceState.RIL_REG_STATE_ROAMING);
+ mSimulatedCommands.notifyNetworkStateChanged();
+
+ waitForMs(200);
+
+ sst.registerForDataRoamingOff(mTestHandler, EVENT_DATA_ROAMING_OFF, null, true);
+ sst.registerForVoiceRoamingOff(mTestHandler, EVENT_VOICE_ROAMING_OFF, null);
+ sst.registerForDataConnectionDetached(mTestHandler, EVENT_DATA_CONNECTION_DETACHED, null);
+
+ // Call functions which would trigger posting of message on test handler
+ doReturn(false).when(mPhone).isPhoneTypeGsm();
+ sst.updatePhoneType();
+
+ // verify if registered handler has message posted to it
+ ArgumentCaptor<Message> messageArgumentCaptor = ArgumentCaptor.forClass(Message.class);
+ verify(mTestHandler, atLeast(3)).sendMessageAtTime(
+ messageArgumentCaptor.capture(), anyLong());
+ HashSet<Integer> messageSet = new HashSet<>();
+ for (Message m : messageArgumentCaptor.getAllValues()) {
+ messageSet.add(m.what);
+ }
+
+ assertTrue(messageSet.contains(EVENT_DATA_ROAMING_OFF));
+ assertTrue(messageSet.contains(EVENT_VOICE_ROAMING_OFF));
+ assertTrue(messageSet.contains(EVENT_DATA_CONNECTION_DETACHED));
+ }
+
+ @Test
@SmallTest
public void testGetDesiredPowerState() {
sst.setRadioPower(true);
@@ -1010,21 +1056,19 @@
@Test
@SmallTest
public void testIsConcurrentVoiceAndDataAllowed() {
- // Verify all 3 branches in the function isConcurrentVoiceAndDataAllowed
- doReturn(true).when(mPhone).isPhoneTypeGsm();
- sst.mSS.setRilVoiceRadioTechnology(sst.mSS.RIL_RADIO_TECHNOLOGY_HSPA);
- assertEquals(true, sst.isConcurrentVoiceAndDataAllowed());
-
doReturn(false).when(mPhone).isPhoneTypeGsm();
- doReturn(true).when(mPhone).isPhoneTypeCdma();
- assertEquals(false, sst.isConcurrentVoiceAndDataAllowed());
-
- doReturn(false).when(mPhone).isPhoneTypeGsm();
- doReturn(false).when(mPhone).isPhoneTypeCdma();
sst.mSS.setCssIndicator(1);
assertEquals(true, sst.isConcurrentVoiceAndDataAllowed());
sst.mSS.setCssIndicator(0);
assertEquals(false, sst.isConcurrentVoiceAndDataAllowed());
+
+ doReturn(true).when(mPhone).isPhoneTypeGsm();
+ sst.mSS.setRilDataRadioTechnology(sst.mSS.RIL_RADIO_TECHNOLOGY_HSPA);
+ assertEquals(true, sst.isConcurrentVoiceAndDataAllowed());
+ sst.mSS.setRilDataRadioTechnology(sst.mSS.RIL_RADIO_TECHNOLOGY_GPRS);
+ assertEquals(false, sst.isConcurrentVoiceAndDataAllowed());
+ sst.mSS.setCssIndicator(1);
+ assertEquals(true, sst.isConcurrentVoiceAndDataAllowed());
}
@Test
@@ -1051,14 +1095,14 @@
// Mock sending incorrect nitz str from RIL
mSimulatedCommands.triggerNITZupdate("38/06/20,00:00:00+0");
- waitForMs(100);
+ waitForMs(200);
// AlarmManger.setTime is triggered by SystemClock.setCurrentTimeMillis().
// Verify system time is not set to incorrect NITZ time
verify(mAlarmManager, times(0)).setTime(anyLong());
// Mock sending correct nitz str from RIL
mSimulatedCommands.triggerNITZupdate("15/06/20,00:00:00+0");
- waitForMs(100);
+ waitForMs(200);
verify(mAlarmManager, times(1)).setTime(anyLong());
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsNumberUtilsTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsNumberUtilsTest.java
index 43d70b5..05c2cb8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SmsNumberUtilsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SmsNumberUtilsTest.java
@@ -19,6 +19,7 @@
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
+import android.telephony.CarrierConfigManager;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
@@ -122,9 +123,9 @@
((MockContentResolver) mContextFixture.getTestDouble().getContentResolver())
.addProvider(HbpcdLookup.MccIdd.CONTENT_URI.getAuthority(), mHbpcdContentProvider);
- mContextFixture.putStringArrayResource(
- com.android.internal.R.array.config_sms_convert_destination_number_support,
- new String[]{"true"});
+ mContextFixture.getCarrierConfigBundle().
+ putBoolean(CarrierConfigManager.KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL,
+ true);
logd("SmsNumberUtilsTest -Setup!");
}
@@ -243,4 +244,4 @@
assertEquals("01118582345678",
SmsNumberUtils.filterDestAddr(mPhone, "+011-1-858-234-5678"));
}
-}
\ No newline at end of file
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java
index 7c8c15c..cbc56ae 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SmsStorageMonitorTest.java
@@ -67,7 +67,7 @@
@After
public void tearDown() throws Exception {
mSmsStorageMonitor = null;
- mSmsStorageMonitorTestHandler.quitSafely();
+ mSmsStorageMonitorTestHandler.quit();
super.tearDown();
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java b/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java
index fea4303..76fce94 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SmsUsageMonitorShortCodeTest.java
@@ -16,21 +16,24 @@
package com.android.internal.telephony;
-import android.os.Looper;
-import android.support.test.filters.FlakyTest;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_FREE_SHORT_CODE;
import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_NOT_SHORT_CODE;
import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE;
import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_PREMIUM_SHORT_CODE;
import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_STANDARD_SHORT_CODE;
+import static org.junit.Assert.assertEquals;
+
+import android.os.Looper;
+import android.support.test.filters.FlakyTest;
+
+import org.junit.Ignore;
+
/**
* Test cases for SMS short code pattern matching in SmsUsageMonitor.
*/
-public class SmsUsageMonitorShortCodeTest extends AndroidTestCase {
+@Ignore
+public class SmsUsageMonitorShortCodeTest {
private static final class ShortCodeTest {
final String countryIso;
@@ -458,14 +461,13 @@
};
@FlakyTest
- @SmallTest
public void testSmsUsageMonitor() {
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
// http://b/25897652 .
if (Looper.myLooper() == null) {
Looper.prepare();
}
- SmsUsageMonitor monitor = new SmsUsageMonitor(getContext());
+ SmsUsageMonitor monitor = new SmsUsageMonitor(TestApplication.getAppContext());
for (ShortCodeTest test : sShortCodeTests) {
assertEquals("country: " + test.countryIso + " number: " + test.address,
test.category, monitor.checkDestination(test.address, test.countryIso));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
index 4960e72..feea80e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionInfoUpdaterTest.java
@@ -60,8 +60,10 @@
public class SubscriptionInfoUpdaterTest extends TelephonyTest {
- private static final int FAKE_SUB_ID = 1;
- private static final String FAKE_PLMN = "123456";
+ private static final int FAKE_SUB_ID_1 = 0;
+ private static final int FAKE_SUB_ID_2 = 1;
+ private static final String FAKE_MCC_MNC_1 = "123456";
+ private static final String FAKE_MCC_MNC_2 = "456789";
private SubscriptionInfoUpdaterHandlerThread mSubscriptionInfoUpdaterHandlerThread;
private IccRecords mIccRecord;
@@ -114,7 +116,8 @@
doReturn(1).when(mTelephonyManager).getPhoneCount();
doReturn(mUserInfo).when(mIActivityManager).getCurrentUser();
- doReturn(new int[]{FAKE_SUB_ID}).when(mSubscriptionController).getSubId(0);
+ doReturn(new int[]{FAKE_SUB_ID_1}).when(mSubscriptionController).getSubId(0);
+ doReturn(new int[]{FAKE_SUB_ID_1}).when(mSubscriptionManager).getActiveSubscriptionIdList();
mContentProvider = new FakeSubscriptionContentProvider();
((MockContentResolver) mContext.getContentResolver()).addProvider(
SubscriptionManager.CONTENT_URI.getAuthority(),
@@ -128,7 +131,7 @@
@After
public void tearDown() throws Exception {
- mSubscriptionInfoUpdaterHandlerThread.quitSafely();
+ mSubscriptionInfoUpdaterHandlerThread.quit();
super.tearDown();
}
@@ -136,11 +139,11 @@
@SmallTest
public void testSimAbsent() throws Exception {
doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController)
- .getSubInfoUsingSlotIndexWithCheck(eq(0), anyBoolean(), anyString());
+ .getSubInfoUsingSlotIndexWithCheck(eq(FAKE_SUB_ID_1), anyBoolean(), anyString());
Intent mIntent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
IccCardConstants.INTENT_VALUE_ICC_ABSENT);
- mIntent.putExtra(PhoneConstants.PHONE_KEY, 0);
+ mIntent.putExtra(PhoneConstants.PHONE_KEY, FAKE_SUB_ID_1);
mContext.sendBroadcast(mIntent);
@@ -150,7 +153,7 @@
CarrierConfigManager mConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- verify(mConfigManager).updateConfigForPhoneId(eq(0),
+ verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
eq(IccCardConstants.INTENT_VALUE_ICC_ABSENT));
verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged();
}
@@ -161,7 +164,7 @@
Intent mIntent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
- mIntent.putExtra(PhoneConstants.PHONE_KEY, FAKE_SUB_ID);
+ mIntent.putExtra(PhoneConstants.PHONE_KEY, FAKE_SUB_ID_1);
mContext.sendBroadcast(mIntent);
@@ -169,7 +172,7 @@
verify(mSubscriptionContent, times(0)).put(anyString(), any());
CarrierConfigManager mConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- verify(mConfigManager).updateConfigForPhoneId(eq(1),
+ verify(mConfigManager).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
eq(IccCardConstants.INTENT_VALUE_ICC_UNKNOWN));
verify(mSubscriptionController, times(0)).notifySubscriptionInfoChanged();
}
@@ -215,14 +218,14 @@
public void testSimLoaded() throws Exception {
/* mock new sim got loaded and there is no sim loaded before */
doReturn(null).when(mSubscriptionController)
- .getSubInfoUsingSlotIndexWithCheck(eq(0), anyBoolean(), anyString());
+ .getSubInfoUsingSlotIndexWithCheck(eq(FAKE_SUB_ID_1), anyBoolean(), anyString());
doReturn("89012604200000000000").when(mIccRecord).getIccId();
- doReturn(FAKE_PLMN).when(mTelephonyManager).getSimOperatorNumericForPhone(0);
+ doReturn(FAKE_MCC_MNC_1).when(mTelephonyManager).getSimOperatorNumeric(FAKE_SUB_ID_1);
Intent intentInternalSimStateChanged =
new Intent(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
intentInternalSimStateChanged.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
IccCardConstants.INTENT_VALUE_ICC_LOADED);
- intentInternalSimStateChanged.putExtra(PhoneConstants.PHONE_KEY, 0);
+ intentInternalSimStateChanged.putExtra(PhoneConstants.PHONE_KEY, FAKE_SUB_ID_1);
mContext.sendBroadcast(intentInternalSimStateChanged);
waitForMs(100);
@@ -246,14 +249,14 @@
stringArgumentCaptor.getAllValues().get(1)); */
SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext);
- verify(mTelephonyManager).getSimOperatorNumericForPhone(0);
+ verify(mTelephonyManager).getSimOperatorNumeric(FAKE_SUB_ID_1);
verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(
- eq("89012604200000000000"), eq(0));
+ eq("89012604200000000000"), eq(FAKE_SUB_ID_1));
verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged();
- verify(mSubscriptionController, times(1)).setMccMnc(FAKE_PLMN, FAKE_SUB_ID);
+ verify(mSubscriptionController, times(1)).setMccMnc(FAKE_MCC_MNC_1, FAKE_SUB_ID_1);
CarrierConfigManager mConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(0),
+ verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
eq(IccCardConstants.INTENT_VALUE_ICC_LOADED));
// ACTION_USER_UNLOCKED should trigger another SIM_STATE_CHANGED
@@ -282,26 +285,26 @@
public void testSimLoadedEmptyOperatorNumeric() throws Exception {
/* mock new sim got loaded and there is no sim loaded before */
doReturn(null).when(mSubscriptionController)
- .getSubInfoUsingSlotIndexWithCheck(eq(0), anyBoolean(), anyString());
+ .getSubInfoUsingSlotIndexWithCheck(eq(FAKE_SUB_ID_1), anyBoolean(), anyString());
doReturn("89012604200000000000").when(mIccRecord).getIccId();
// operator numeric is empty
- doReturn("").when(mTelephonyManager).getSimOperatorNumericForPhone(0);
+ doReturn("").when(mTelephonyManager).getSimOperatorNumeric(FAKE_SUB_ID_1);
Intent mIntent = new Intent(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
IccCardConstants.INTENT_VALUE_ICC_LOADED);
- mIntent.putExtra(PhoneConstants.PHONE_KEY, 0);
+ mIntent.putExtra(PhoneConstants.PHONE_KEY, FAKE_SUB_ID_1);
mContext.sendBroadcast(mIntent);
waitForMs(100);
SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext);
- verify(mTelephonyManager).getSimOperatorNumericForPhone(0);
+ verify(mTelephonyManager).getSimOperatorNumeric(FAKE_SUB_ID_1);
verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(
- eq("89012604200000000000"), eq(0));
+ eq("89012604200000000000"), eq(FAKE_SUB_ID_1));
verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged();
verify(mSubscriptionController, times(0)).setMccMnc(anyString(), anyInt());
CarrierConfigManager mConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(0),
+ verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
eq(IccCardConstants.INTENT_VALUE_ICC_LOADED));
}
@@ -323,13 +326,13 @@
}).when(mIccFileHandler).loadEFTransparent(anyInt(), any(Message.class));
doReturn(Arrays.asList(mSubInfo)).when(mSubscriptionController)
- .getSubInfoUsingSlotIndexWithCheck(eq(0), anyBoolean(), anyString());
+ .getSubInfoUsingSlotIndexWithCheck(eq(FAKE_SUB_ID_1), anyBoolean(), anyString());
Intent mIntent = new Intent(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
IccCardConstants.INTENT_VALUE_ICC_LOCKED);
mIntent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, "TESTING");
- mIntent.putExtra(PhoneConstants.PHONE_KEY, 0);
+ mIntent.putExtra(PhoneConstants.PHONE_KEY, FAKE_SUB_ID_1);
mContext.sendBroadcast(mIntent);
waitForMs(100);
@@ -339,18 +342,75 @@
eq(SubscriptionManager.INVALID_SIM_SLOT_INDEX));
SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext);
verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(
- eq("98106240020000000000"), eq(0));
+ eq("98106240020000000000"), eq(FAKE_SUB_ID_1));
verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged();
CarrierConfigManager mConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(0),
+ verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
eq(IccCardConstants.INTENT_VALUE_ICC_LOCKED));
}
@Test
@SmallTest
- public void testSimLockWIthIccId() throws Exception {
+ public void testDualSimLoaded() throws Exception {
+ // Mock there is two sim cards
+
+ replaceInstance(SubscriptionInfoUpdater.class, "mIccId", null,
+ new String[]{null, null});
+ replaceInstance(SubscriptionInfoUpdater.class, "PROJECT_SIM_NUM", null, 2);
+ replaceInstance(SubscriptionInfoUpdater.class, "mPhone", null,
+ new Phone[]{mPhone, mPhone});
+ replaceInstance(SubscriptionInfoUpdater.class, "mInsertSimState", null,
+ new int[]{SubscriptionInfoUpdater.SIM_NOT_CHANGE,
+ SubscriptionInfoUpdater.SIM_NOT_CHANGE});
+
+ doReturn(new int[]{FAKE_SUB_ID_1, FAKE_SUB_ID_2}).when(mSubscriptionManager)
+ .getActiveSubscriptionIdList();
+ doReturn(FAKE_SUB_ID_1).when(mSubscriptionController).getPhoneId(eq(FAKE_SUB_ID_1));
+ doReturn(FAKE_SUB_ID_2).when(mSubscriptionController).getPhoneId(eq(FAKE_SUB_ID_2));
+ doReturn(2).when(mTelephonyManager).getSimCount();
+ doReturn(FAKE_MCC_MNC_1).when(mTelephonyManager).getSimOperatorNumeric(eq(FAKE_SUB_ID_1));
+ doReturn(FAKE_MCC_MNC_2).when(mTelephonyManager).getSimOperatorNumeric(eq(FAKE_SUB_ID_2));
+ // Mock there is no sim inserted before
+ doReturn(null).when(mSubscriptionController)
+ .getSubInfoUsingSlotIndexWithCheck(anyInt(), anyBoolean(), anyString());
+ doReturn("89012604200000000000").when(mIccRecord).getIccId();
+
+ // Mock sending a sim loaded for SIM 1
+ Intent mIntent = new Intent(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
+ mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
+ IccCardConstants.INTENT_VALUE_ICC_LOADED);
+ mIntent.putExtra(PhoneConstants.PHONE_KEY, FAKE_SUB_ID_1);
+ mContext.sendBroadcast(mIntent);
+ waitForMs(100);
+
+ SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext);
+ verify(mSubscriptionManager, times(0)).addSubscriptionInfoRecord(anyString(), anyInt());
+ verify(mSubscriptionController, times(0)).notifySubscriptionInfoChanged();
+ verify(mSubscriptionController, times(0)).setMccMnc(anyString(), anyInt());
+
+ // Mock sending a sim loaded for SIM 2
+ doReturn("89012604200000000001").when(mIccRecord).getIccId();
+ mIntent = new Intent(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
+ mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
+ IccCardConstants.INTENT_VALUE_ICC_LOADED);
+ mIntent.putExtra(PhoneConstants.PHONE_KEY, FAKE_SUB_ID_2);
+ mContext.sendBroadcast(mIntent);
+ waitForMs(100);
+
+ verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(eq("89012604200000000000"),
+ eq(FAKE_SUB_ID_1));
+ verify(mSubscriptionManager, times(1)).addSubscriptionInfoRecord(eq("89012604200000000001"),
+ eq(FAKE_SUB_ID_2));
+ verify(mSubscriptionController, times(1)).setMccMnc(eq(FAKE_MCC_MNC_1), eq(FAKE_SUB_ID_1));
+ verify(mSubscriptionController, times(1)).setMccMnc(eq(FAKE_MCC_MNC_2), eq(FAKE_SUB_ID_2));
+ verify(mSubscriptionController, times(1)).notifySubscriptionInfoChanged();
+ }
+
+ @Test
+ @SmallTest
+ public void testSimLockWithIccId() throws Exception {
/* no need for IccId query */
replaceInstance(SubscriptionInfoUpdater.class, "mIccId", null,
@@ -361,7 +421,7 @@
mIntent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
IccCardConstants.INTENT_VALUE_ICC_LOCKED);
mIntent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, "TESTING");
- mIntent.putExtra(PhoneConstants.PHONE_KEY, 0);
+ mIntent.putExtra(PhoneConstants.PHONE_KEY, FAKE_SUB_ID_1);
mContext.sendBroadcast(mIntent);
waitForMs(100);
@@ -369,12 +429,13 @@
verify(mIccFileHandler, times(0)).loadEFTransparent(anyInt(), any(Message.class));
SubscriptionManager mSubscriptionManager = SubscriptionManager.from(mContext);
verify(mSubscriptionManager, times(0)).addSubscriptionInfoRecord(
- anyString(), eq(0));
+ anyString(), eq(FAKE_SUB_ID_1));
verify(mSubscriptionController, times(0)).notifySubscriptionInfoChanged();
CarrierConfigManager mConfigManager = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
/* broadcast is done */
- verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(0),
+ verify(mConfigManager, times(1)).updateConfigForPhoneId(eq(FAKE_SUB_ID_1),
eq(IccCardConstants.INTENT_VALUE_ICC_LOCKED));
}
+
}
\ No newline at end of file
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 994b846..eaaaa64 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -25,7 +25,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
import android.content.IIntentSender;
@@ -86,6 +86,8 @@
public abstract class TelephonyTest {
protected static String TAG;
+ private static final int MAX_INIT_WAIT_MS = 30000; // 30 seconds
+
@Mock
protected GsmCdmaPhone mPhone;
@Mock
@@ -177,7 +179,11 @@
@Mock
protected ImsExternalCallTracker mImsExternalCallTracker;
@Mock
+ protected AppSmsManager mAppSmsManager;
+ @Mock
protected DeviceStateMonitor mDeviceStateMonitor;
+ @Mock
+ protected IntentBroadcaster mIntentBroadcaster;
protected TelephonyManager mTelephonyManager;
protected SubscriptionManager mSubscriptionManager;
@@ -224,11 +230,14 @@
}
protected void waitUntilReady() {
- while (true) {
- synchronized (mLock) {
- if (mReady) {
- break;
- }
+ synchronized (mLock) {
+ try {
+ mLock.wait(MAX_INIT_WAIT_MS);
+ } catch (InterruptedException ie) {
+ }
+
+ if (!mReady) {
+ fail("Telephony tests failed to initialize");
}
}
}
@@ -236,6 +245,7 @@
protected void setReady(boolean ready) {
synchronized (mLock) {
mReady = ready;
+ mLock.notifyAll();
}
}
@@ -292,7 +302,8 @@
replaceInstance(ImsManager.class, "sImsManagerInstances", null, mImsManagerInstances);
replaceInstance(SubscriptionController.class, "sInstance", null, mSubscriptionController);
replaceInstance(ProxyController.class, "sProxyController", null, mProxyController);
- replaceInstance(ActivityManagerNative.class, "gDefault", null, mIActivityManagerSingleton);
+ replaceInstance(ActivityManager.class, "IActivityManagerSingleton", null,
+ mIActivityManagerSingleton);
replaceInstance(CdmaSubscriptionSourceManager.class,
"mCdmaSubscriptionSourceChangedRegistrants", mCdmaSSM, mRegistrantList);
replaceInstance(SimulatedCommandsVerifier.class, "sInstance", null,
@@ -300,6 +311,7 @@
replaceInstance(Singleton.class, "mInstance", mIActivityManagerSingleton,
mIActivityManager);
replaceInstance(ServiceManager.class, "sCache", null, mServiceManagerMockedServices);
+ replaceInstance(IntentBroadcaster.class, "sIntentBroadcaster", null, mIntentBroadcaster);
mSimulatedCommands = new SimulatedCommands();
mContextFixture = new ContextFixture();
@@ -352,6 +364,8 @@
.getIDeviceIdleController();
doReturn(mImsExternalCallTracker).when(mTelephonyComponentFactory)
.makeImsExternalCallTracker(nullable(ImsPhone.class));
+ doReturn(mAppSmsManager).when(mTelephonyComponentFactory)
+ .makeAppSmsManager(nullable(Context.class));
doReturn(mCarrierSignalAgent).when(mTelephonyComponentFactory)
.makeCarrierSignalAgent(nullable(Phone.class));
doReturn(mCarrierActionAgent).when(mTelephonyComponentFactory)
@@ -373,6 +387,7 @@
doReturn(mSST).when(mPhone).getServiceStateTracker();
doReturn(mCarrierSignalAgent).when(mPhone).getCarrierSignalAgent();
doReturn(mCarrierActionAgent).when(mPhone).getCarrierActionAgent();
+ doReturn(mAppSmsManager).when(mPhone).getAppSmsManager();
mPhone.mEriManager = mEriManager;
//mUiccController
@@ -440,6 +455,8 @@
protected void tearDown() throws Exception {
+ mSimulatedCommands.dispose();
+
SharedPreferences sharedPreferences = mContext.getSharedPreferences((String) null, 0);
sharedPreferences.edit().clear().commit();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java b/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java
index 198beab..fab16be 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/VisualVoicemailSmsFilterTest.java
@@ -16,40 +16,156 @@
package com.android.internal.telephony;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import android.content.ComponentName;
import android.content.Context;
+import android.telecom.PhoneAccountHandle;
import android.telephony.TelephonyManager;
import android.telephony.VisualVoicemailSmsFilterSettings;
+import com.android.internal.telephony.VisualVoicemailSmsFilter.PhoneAccountHandleConverter;
+
import junit.framework.TestCase;
import org.mockito.Mockito;
+import java.util.Arrays;
+
+/**
+ * Unit test for {@link VisualVoicemailSmsFilter}
+ */
public class VisualVoicemailSmsFilterTest extends TestCase {
/**
- * b/29123941 iPhone style notification SMS is neither 3GPP nor 3GPP2, but some plain text
- * message. {@link android.telephony.SmsMessage.createFromPdu()} will fail to parse it and
- * return an invalid object, causing {@link NullPointerException} on any operation if not
- * handled.
+ * PDU for the following message:
+ * <p>originating number: 129
+ * <p>message: //VVM:SYNC:ev=NM;id=143;c=6;t=v;s=11111111111;dt=07/03/2017 18:17 -0800;l=4
+ */
+ private static final byte[][] SYNC_PDU = {{
+ (byte) 0x07, (byte) 0x91, (byte) 0x41, (byte) 0x50, (byte) 0x74, (byte) 0x02,
+ (byte) 0x50, (byte) 0xF5, (byte) 0x44, (byte) 0x03, (byte) 0xC9, (byte) 0x21,
+ (byte) 0xF9, (byte) 0x00, (byte) 0x00, (byte) 0x71, (byte) 0x30, (byte) 0x70,
+ (byte) 0x81, (byte) 0x71, (byte) 0x81, (byte) 0x2B, (byte) 0x53, (byte) 0x06,
+ (byte) 0x05, (byte) 0x04, (byte) 0x07, (byte) 0x10, (byte) 0x01, (byte) 0x01,
+ (byte) 0xAF, (byte) 0x97, (byte) 0xD5, (byte) 0xDA, (byte) 0xD4, (byte) 0x4D,
+ (byte) 0xB3, (byte) 0xCE, (byte) 0xA1, (byte) 0xAE, (byte) 0x6C, (byte) 0xEF,
+ (byte) 0x39, (byte) 0x9B, (byte) 0xBB, (byte) 0x34, (byte) 0xB9, (byte) 0x17,
+ (byte) 0xA3, (byte) 0xCD, (byte) 0x76, (byte) 0xE3, (byte) 0x9E, (byte) 0x6D,
+ (byte) 0x47, (byte) 0xEF, (byte) 0xD9, (byte) 0x77, (byte) 0xF3, (byte) 0x5E,
+ (byte) 0x2C, (byte) 0x16, (byte) 0x8B, (byte) 0xC5, (byte) 0x62, (byte) 0xB1,
+ (byte) 0x58, (byte) 0x2C, (byte) 0x16, (byte) 0xDB, (byte) 0x91, (byte) 0xE9,
+ (byte) 0x3D, (byte) 0xD8, (byte) 0xED, (byte) 0x05, (byte) 0x9B, (byte) 0xBD,
+ (byte) 0x64, (byte) 0xB0, (byte) 0xD8, (byte) 0x0D, (byte) 0x14, (byte) 0xC3,
+ (byte) 0xE9, (byte) 0x62, (byte) 0x37, (byte) 0x50, (byte) 0x0B, (byte) 0x86,
+ (byte) 0x83, (byte) 0xC1, (byte) 0x76, (byte) 0xEC, (byte) 0x1E, (byte) 0x0D}};
+
+ private Context mContext;
+ private TelephonyManager mTelephonyManager;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mContext = Mockito.mock(Context.class);
+ mTelephonyManager = Mockito.mock(TelephonyManager.class);
+ when(mContext.getSystemServiceName(TelephonyManager.class))
+ .thenReturn(Context.TELEPHONY_SERVICE);
+ when(mContext.getSystemService(Context.TELEPHONY_SERVICE))
+ .thenReturn(mTelephonyManager);
+
+ VisualVoicemailSmsFilter.setPhoneAccountHandleConverterForTest(
+ new PhoneAccountHandleConverter() {
+ @Override
+ public PhoneAccountHandle fromSubId(int subId) {
+ return new PhoneAccountHandle(
+ new ComponentName("com.android.internal.telephony",
+ "VisualVoicemailSmsFilterTest"), "foo");
+ }
+ });
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ VisualVoicemailSmsFilter.setPhoneAccountHandleConverterForTest(null);
+ super.tearDown();
+ }
+
+
+ /**
+ * Notification SMS targeting over devices do not follow 3GPP or 3GPP2 standards, but instead
+ * use a plain text message. {@link android.telephony.SmsMessage#createFromPdu(byte[], String)}
+ * will fail to parse it and return an invalid object, causing {@link NullPointerException} on
+ * any operation if not handled.
*/
public void testUnsupportedPdu() {
- Context context = Mockito.mock(Context.class);
- TelephonyManager telephonyManager = Mockito.mock(TelephonyManager.class);
- Mockito.when(context.getSystemServiceName(TelephonyManager.class))
- .thenReturn(Context.TELEPHONY_SERVICE);
- Mockito.when(context.getSystemService(Mockito.anyString())).thenReturn(telephonyManager);
- VisualVoicemailSmsFilterSettings settings = new VisualVoicemailSmsFilterSettings.Builder()
- .build();
-
- Mockito.when(telephonyManager
- .getVisualVoicemailSmsFilterSettings(Mockito.anyInt()))
- .thenReturn(settings);
+ setSettings(new VisualVoicemailSmsFilterSettings.Builder().build());
byte[][] pdus = {
("MBOXUPDATE?m=11;server=example.com;"
+ "port=143;name=1234567890@example.com;pw=CphQJKnYS4jEiDO").getBytes()};
- VisualVoicemailSmsFilter.filter(context, pdus, SmsConstants.FORMAT_3GPP2, 0, 0);
+ assertFalse(
+ VisualVoicemailSmsFilter.filter(mContext, pdus, SmsConstants.FORMAT_3GPP, 0, 0));
}
+ public void testOriginatingNumber_unspecified_filtered() {
+ setSettings(new VisualVoicemailSmsFilterSettings.Builder().build());
+ assertTrue(VisualVoicemailSmsFilter
+ .filter(mContext, SYNC_PDU, SmsConstants.FORMAT_3GPP, 0, 0));
+ }
+
+ public void testOriginatingNumber_match_filtered() {
+ setSettings(
+ new VisualVoicemailSmsFilterSettings.Builder().setOriginatingNumbers(
+ Arrays.asList("129")
+ ).build());
+ assertTrue(VisualVoicemailSmsFilter
+ .filter(mContext, SYNC_PDU, SmsConstants.FORMAT_3GPP, 0, 0));
+ }
+
+ public void testOriginatingNumber_mismatch_notFiltered() {
+ setSettings(
+ new VisualVoicemailSmsFilterSettings.Builder().setOriginatingNumbers(
+ Arrays.asList("128")
+ ).build());
+ assertFalse(VisualVoicemailSmsFilter
+ .filter(mContext, SYNC_PDU, SmsConstants.FORMAT_3GPP, 0, 0));
+ }
+
+ public void testDestinationPort_anyMatch_filtered() {
+ setSettings(new VisualVoicemailSmsFilterSettings.Builder()
+ .setDestinationPort(123).build());
+ assertTrue(VisualVoicemailSmsFilter
+ .filter(mContext, SYNC_PDU, SmsConstants.FORMAT_3GPP, 123, 0));
+ }
+
+ public void testDestinationPort_anyData_filtered() {
+ setSettings(new VisualVoicemailSmsFilterSettings.Builder()
+ .setDestinationPort(VisualVoicemailSmsFilterSettings.DESTINATION_PORT_DATA_SMS)
+ .build());
+ assertTrue(VisualVoicemailSmsFilter
+ .filter(mContext, SYNC_PDU, SmsConstants.FORMAT_3GPP, 456, 0));
+ }
+
+ public void testDestinationPort_anyData_textReceived_notFiltered() {
+ setSettings(new VisualVoicemailSmsFilterSettings.Builder()
+ .setDestinationPort(VisualVoicemailSmsFilterSettings.DESTINATION_PORT_DATA_SMS)
+ .build());
+ assertFalse(VisualVoicemailSmsFilter
+ .filter(mContext, SYNC_PDU, SmsConstants.FORMAT_3GPP, -1, 0));
+ }
+
+
+ public void testDestinationPort_mismatch_notFiltered() {
+ setSettings(new VisualVoicemailSmsFilterSettings.Builder()
+ .setDestinationPort(123).build());
+ assertFalse(VisualVoicemailSmsFilter
+ .filter(mContext, SYNC_PDU, SmsConstants.FORMAT_3GPP, 456, 0));
+ }
+
+ private void setSettings(VisualVoicemailSmsFilterSettings settings) {
+ when(mTelephonyManager.getActiveVisualVoicemailSmsFilterSettings(anyInt()))
+ .thenReturn(settings);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java
index 82169d4..5786a70 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaInboundSmsHandlerTest.java
@@ -16,6 +16,19 @@
package com.android.internal.telephony.cdma;
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
@@ -40,6 +53,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -47,18 +61,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
-import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
public class CdmaInboundSmsHandlerTest extends TelephonyTest {
@Mock
private SmsStorageMonitor mSmsStorageMonitor;
@@ -159,7 +161,7 @@
assertFalse(mCdmaInboundSmsHandler.getWakeLock().isHeld());
mCdmaInboundSmsHandler = null;
mContentProvider.shutdown();
- mCdmaInboundSmsHandlerTestHandler.quitSafely();
+ mCdmaInboundSmsHandlerTestHandler.quit();
super.tearDown();
}
@@ -177,6 +179,7 @@
@FlakyTest
@Test
@MediumTest
+ @Ignore
public void testNewSms() {
transitionFromStartupToIdle();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
index 5cd55b6..ab7fd7f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsCbTest.java
@@ -27,6 +27,7 @@
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.telephony.GsmAlphabet;
+import com.android.internal.telephony.cdma.SmsMessageConverter;
import com.android.internal.telephony.cdma.sms.BearerData;
import com.android.internal.telephony.cdma.sms.CdmaSmsAddress;
import com.android.internal.telephony.cdma.sms.SmsEnvelope;
@@ -121,7 +122,7 @@
for (byte b : bearerData) {
msg.bearerData.add(b);
}
- SmsMessage message = SmsMessage.newFromRil(msg);
+ SmsMessage message = SmsMessageConverter.newCdmaSmsMessageFromRil(msg);
return message;
}
@@ -485,7 +486,7 @@
public void testCmasUnsupportedCharSet() throws Exception {
SmsMessage msg = createCmasSmsMessage(SmsEnvelope.SERVICE_CATEGORY_CMAS_EXTREME_THREAT,
12345, BearerData.PRIORITY_EMERGENCY, BearerData.LANGUAGE_ENGLISH,
- UserData.ENCODING_GSM_DCS, EXTREME_ALERT, -1, -1, -1, -1, -1);
+ 0x1F, EXTREME_ALERT, -1, -1, -1, -1, -1);
SmsCbMessage cbMessage = msg.parseBroadcastSms();
assertNull("expected null for unsupported charset", cbMessage);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsDispatcherTest.java
index e3ba4ff..a308762 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/cdma/CdmaSmsDispatcherTest.java
@@ -72,7 +72,7 @@
@After
public void tearDown() throws Exception {
mCdmaSmsDispatcher = null;
- mCdmaSmsDispatcherTestHandler.quitSafely();
+ mCdmaSmsDispatcherTestHandler.quit();
super.tearDown();
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
index 92d8c34..3624ec1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/ApnSettingTest.java
@@ -16,15 +16,29 @@
package com.android.internal.telephony.dataconnection;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_ALL;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_DEFAULT;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_HIPRI;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_IA;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_MMS;
+import static com.android.internal.telephony.PhoneConstants.APN_TYPE_SUPL;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
+import android.telephony.ServiceState;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyTest;
import org.junit.After;
-import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -33,22 +47,9 @@
import java.util.ArrayList;
import java.util.List;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_ALL;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_DEFAULT;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_HIPRI;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_IA;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_MMS;
-import static com.android.internal.telephony.PhoneConstants.APN_TYPE_SUPL;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-import static org.junit.Assert.assertEquals;
-
-
public class ApnSettingTest extends TelephonyTest {
private PersistableBundle mBundle;
- private boolean isRoaming = false;
@Before
public void setUp() throws Exception {
@@ -61,15 +62,15 @@
super.tearDown();
}
- private ApnSetting createApnSetting(String[] apnTypes) {
+ static ApnSetting createApnSetting(String[] apnTypes) {
return createApnSettingInternal(apnTypes, true);
}
- private ApnSetting createDisabledApnSetting(String[] apnTypes) {
+ private static ApnSetting createDisabledApnSetting(String[] apnTypes) {
return createApnSettingInternal(apnTypes, false);
}
- private ApnSetting createApnSettingInternal(String[] apnTypes, boolean carrierEnabled) {
+ private static ApnSetting createApnSettingInternal(String[] apnTypes, boolean carrierEnabled) {
return new ApnSetting(
2163, // id
"44010", // numeric
@@ -229,63 +230,52 @@
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
+ doReturn(false).when(mServiceState).getDataRoaming();
+ doReturn(1).when(mPhone).getSubId();
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_DEFAULT}).
- isMetered(mContext, 1, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT}).isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}).
- isMetered(mContext, 1, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_MMS}).
- isMetered(mContext, 1, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_MMS}).isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_MMS, PhoneConstants.APN_TYPE_SUPL}).
- isMetered(mContext, 1, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_DUN}).
- isMetered(mContext, 1, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_ALL}).
- isMetered(mContext, 1, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
assertFalse(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_SUPL}).
- isMetered(mContext, 1, isRoaming));
+ isMetered(mPhone));
assertFalse(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_CBS}).
- isMetered(mContext, 1, isRoaming));
+ isMetered(mPhone));
- assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT,
- mContext, 1, isRoaming));
- assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS,
- mContext, 1, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL,
- mContext, 1, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS,
- mContext, 1, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DUN,
- mContext, 1, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA,
- mContext, 1, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_IA,
- mContext, 1, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI,
- mContext, 1, isRoaming));
+ assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+ assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DUN, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_IA, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI, mPhone));
// Carrier config settings changes.
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_DEFAULT});
- assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT,
- mContext, 1, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS,
- mContext, 1, isRoaming));
+ assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
}
@Test
@@ -293,50 +283,93 @@
public void testIsRoamingMetered() throws Exception {
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
- isRoaming = true;
+ doReturn(true).when(mServiceState).getDataRoaming();
+ doReturn(1).when(mPhone).getSubId();
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_DEFAULT}).
- isMetered(mContext, 1, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT}).isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}).
- isMetered(mContext, 1, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_MMS}).
- isMetered(mContext, 1, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_MMS}).isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_MMS, PhoneConstants.APN_TYPE_SUPL}).
- isMetered(mContext, 1, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_DUN}).
- isMetered(mContext, 1, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_ALL}).
- isMetered(mContext, 1, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
assertFalse(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_SUPL}).
- isMetered(mContext, 1, isRoaming));
+ isMetered(mPhone));
assertFalse(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_CBS}).
- isMetered(mContext, 1, isRoaming));
+ isMetered(mPhone));
// Carrier config settings changes.
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_FOTA});
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT,
- mContext, 1, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS,
- mContext, 1, isRoaming));
- assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA,
- mContext, 1, isRoaming));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
+ assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, mPhone));
+ }
+
+ @Test
+ @SmallTest
+ public void testIsIwlanMetered() throws Exception {
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
+ doReturn(false).when(mServiceState).getDataRoaming();
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
+ .getRilDataRadioTechnology();
+ doReturn(1).when(mPhone).getSubId();
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT}).isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS})
+ .isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_MMS}).isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_MMS, PhoneConstants.APN_TYPE_SUPL})
+ .isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_DUN})
+ .isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
+
+ assertFalse(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_SUPL})
+ .isMetered(mPhone));
+
+ assertFalse(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_CBS})
+ .isMetered(mPhone));
+
+ // Carrier config settings changes.
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_FOTA});
+
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
+ assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, mPhone));
}
@Test
@@ -345,38 +378,35 @@
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS});
+ doReturn(false).when(mServiceState).getDataRoaming();
+ doReturn(1).when(mPhone).getSubId();
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS}).
- isMetered(mContext, 2, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_SUPL}).
- isMetered(mContext, 2, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_SUPL}).isMetered(mPhone));
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_CBS}).
- isMetered(mContext, 2, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_CBS}).isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS}).
- isMetered(mContext, 2, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_IA}).
- isMetered(mContext, 2, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_ALL}).
- isMetered(mContext, 2, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
assertFalse(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_IMS}).
- isMetered(mContext, 2, isRoaming));
+ isMetered(mPhone));
assertFalse(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_IMS}).
- isMetered(mContext, 2, isRoaming));
-
+ new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
}
@Test
@@ -384,56 +414,91 @@
public void testIsRoamingMeteredAnother() throws Exception {
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS});
- isRoaming = true;
+ doReturn(true).when(mServiceState).getDataRoaming();
+ doReturn(2).when(mPhone).getSubId();
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS}).
- isMetered(mContext, 2, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_SUPL}).
- isMetered(mContext, 2, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_SUPL}).isMetered(mPhone));
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_CBS}).
- isMetered(mContext, 2, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_CBS}).isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS}).
- isMetered(mContext, 2, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_IA}).
- isMetered(mContext, 2, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_ALL}).
- isMetered(mContext, 2, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
assertFalse(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_IMS}).
- isMetered(mContext, 2, isRoaming));
+ isMetered(mPhone));
assertFalse(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_IMS}).
- isMetered(mContext, 2, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
- assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL,
- mContext, 2, isRoaming));
- assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS,
- mContext, 2, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT,
- mContext, 2, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS,
- mContext, 2, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DUN,
- mContext, 2, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA,
- mContext, 2, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_IA,
- mContext, 2, isRoaming));
- assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI,
- mContext, 2, isRoaming));
+ assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL, mPhone));
+ assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DUN, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_IA, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI, mPhone));
+ }
+ @Test
+ @SmallTest
+ public void testIsIwlanMeteredAnother() throws Exception {
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS});
+ doReturn(true).when(mServiceState).getDataRoaming();
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
+ .getRilDataRadioTechnology();
+ doReturn(2).when(mPhone).getSubId();
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS})
+ .isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_SUPL}).isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_CBS}).isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS})
+ .isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_IA})
+ .isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
+
+ assertFalse(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_IMS})
+ .isMetered(mPhone));
+
+ assertFalse(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
+
+ assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_SUPL, mPhone));
+ assertTrue(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_CBS, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DEFAULT, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_MMS, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_DUN, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_FOTA, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_IA, mPhone));
+ assertFalse(ApnSetting.isMeteredApnType(PhoneConstants.APN_TYPE_HIPRI, mPhone));
}
@Test
@@ -442,21 +507,22 @@
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{});
- assertFalse(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_IMS}).
- isMetered(mContext, 3, isRoaming));
+ doReturn(false).when(mServiceState).getDataRoaming();
+ doReturn(3).when(mPhone).getSubId();
assertFalse(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_IMS, PhoneConstants.APN_TYPE_MMS}).
- isMetered(mContext, 3, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
assertFalse(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_FOTA}).
- isMetered(mContext, 3, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_IMS, PhoneConstants.APN_TYPE_MMS})
+ .isMetered(mPhone));
assertFalse(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_ALL}).
- isMetered(mContext, 3, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_FOTA})
+ .isMetered(mPhone));
+
+ assertFalse(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
}
@Test
@@ -464,23 +530,48 @@
public void testIsRoamingMeteredNothingCharged() throws Exception {
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{});
- isRoaming = true;
+ doReturn(true).when(mServiceState).getDataRoaming();
+ doReturn(3).when(mPhone).getSubId();
assertFalse(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_IMS}).
- isMetered(mContext, 3, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
assertFalse(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_IMS, PhoneConstants.APN_TYPE_MMS}).
- isMetered(mContext, 3, isRoaming));
+ isMetered(mPhone));
assertFalse(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_FOTA}).
- isMetered(mContext, 3, isRoaming));
+ isMetered(mPhone));
assertFalse(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_ALL}).
- isMetered(mContext, 3, isRoaming));
+ isMetered(mPhone));
+ }
+
+ @Test
+ @SmallTest
+ public void testIsIwlanMeteredNothingCharged() throws Exception {
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+ new String[]{});
+ doReturn(true).when(mServiceState).getDataRoaming();
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
+ .getRilDataRadioTechnology();
+ doReturn(3).when(mPhone).getSubId();
+
+ assertFalse(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_IMS}).isMetered(mPhone));
+
+ assertFalse(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_IMS, PhoneConstants.APN_TYPE_MMS})
+ .isMetered(mPhone));
+
+ assertFalse(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_FOTA})
+ .isMetered(mPhone));
+
+ assertFalse(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
}
@Test
@@ -489,21 +580,24 @@
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_ALL});
+ doReturn(false).when(mServiceState).getDataRoaming();
+ doReturn(4).when(mPhone).getSubId();
+
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_ALL}).
- isMetered(mContext, 4, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}).
- isMetered(mContext, 4, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS}).
- isMetered(mContext, 4, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_DUN}).
- isMetered(mContext, 4, isRoaming));
+ isMetered(mPhone));
}
@@ -512,23 +606,51 @@
public void testIsRoamingMeteredNothingFree() throws Exception {
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_ALL});
- isRoaming = true;
+
+ doReturn(true).when(mServiceState).getDataRoaming();
+ doReturn(4).when(mPhone).getSubId();
assertTrue(createApnSetting(
- new String[]{PhoneConstants.APN_TYPE_ALL}).
- isMetered(mContext, 4, isRoaming));
+ new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS})
+ .isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS})
+ .isMetered(mPhone));
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_DUN})
+ .isMetered(mPhone));
+ }
+
+ @Test
+ @SmallTest
+ public void testIsIwlanMeteredNothingFree() throws Exception {
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_IWLAN_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_ALL});
+
+ doReturn(false).when(mServiceState).getDataRoaming();
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
+ .getRilDataRadioTechnology();
+ doReturn(4).when(mPhone).getSubId();
+
+ assertTrue(createApnSetting(
+ new String[]{PhoneConstants.APN_TYPE_ALL}).isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}).
- isMetered(mContext, 4, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS}).
- isMetered(mContext, 4, isRoaming));
+ isMetered(mPhone));
assertTrue(createApnSetting(
new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_DUN}).
- isMetered(mContext, 4, isRoaming));
+ isMetered(mPhone));
}
@Test
@@ -627,4 +749,67 @@
}
}
}
-}
+
+ @Test
+ @SmallTest
+ public void testEqualsRoamingProtocol() throws Exception {
+ ApnSetting apn1 = new ApnSetting(
+ 1234,
+ "310260",
+ "",
+ "ims",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ -1,
+ new String[]{"ims"},
+ "IPV6",
+ "",
+ true,
+ 0,
+ 131071,
+ 0,
+ false,
+ 0,
+ 0,
+ 0,
+ 1440,
+ "",
+ "");
+
+ ApnSetting apn2 = new ApnSetting(
+ 1235,
+ "310260",
+ "",
+ "ims",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ -1,
+ new String[]{"ims"},
+ "IPV6",
+ "IPV6",
+ true,
+ 0,
+ 131072,
+ 0,
+ false,
+ 0,
+ 0,
+ 0,
+ 1440,
+ "",
+ "");
+
+ assertTrue(apn1.equals(apn2, false));
+ assertFalse(apn1.equals(apn2, true));
+ }
+}
\ No newline at end of file
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
index 21ba173..76380c7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DataConnectionTest.java
@@ -164,7 +164,7 @@
logd("tearDown");
mDc = null;
mDcc = null;
- mDataConnectionTestHandler.quitSafely();
+ mDataConnectionTestHandler.quit();
super.tearDown();
}
@@ -278,8 +278,8 @@
return (NetworkInfo) f.get(mDc);
}
- private NetworkCapabilities getCopyNetworkCapabilities() throws Exception {
- Method method = DataConnection.class.getDeclaredMethod("getCopyNetworkCapabilities");
+ private NetworkCapabilities getNetworkCapabilities() throws Exception {
+ Method method = DataConnection.class.getDeclaredMethod("getNetworkCapabilities");
method.setAccessible(true);
return (NetworkCapabilities) method.invoke(mDc);
}
@@ -294,8 +294,8 @@
testConnectEvent();
- assertFalse(getCopyNetworkCapabilities().
- hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+ assertFalse(getNetworkCapabilities()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
assertTrue(getNetworkInfo().isMetered());
}
@@ -310,8 +310,19 @@
testConnectEvent();
- assertTrue(getCopyNetworkCapabilities().
- hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+ assertTrue(getNetworkCapabilities()
+ .hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
assertFalse(getNetworkInfo().isMetered());
}
-}
\ No newline at end of file
+
+ @SmallTest
+ public void testIsIpAddress() throws Exception {
+ // IPv4
+ assertTrue(DataConnection.isIpAddress("1.2.3.4"));
+ assertTrue(DataConnection.isIpAddress("127.0.0.1"));
+
+ // IPv6
+ assertTrue(DataConnection.isIpAddress("::1"));
+ assertTrue(DataConnection.isIpAddress("2001:4860:800d::68"));
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
index f2661f6..d209639 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcControllerTest.java
@@ -114,7 +114,7 @@
@After
public void tearDown() throws Exception {
- mDcControllerTestHandler.quitSafely();
+ mDcControllerTestHandler.quit();
super.tearDown();
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcFailCauseTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcFailCauseTest.java
index 2f22420..6ef1e39 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcFailCauseTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcFailCauseTest.java
@@ -16,22 +16,22 @@
package com.android.internal.telephony.dataconnection;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.telephony.TelephonyTest;
-import com.android.internal.telephony.dataconnection.ApnSetting;
-
-import junit.framework.TestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
-import java.util.List;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
public class DcFailCauseTest extends TelephonyTest {
@@ -144,12 +144,38 @@
@Test
@SmallTest
- public void testPermanentFail() throws Exception {
+ public void testPermanentFailDefault() throws Exception {
for (DcFailCauseData data : mFailCauseDataList) {
- assertEquals("cause = " + data.mCause, data.mPermanentFailure,
- DcFailCause.fromInt(data.mCause).isPermanentFail());
+ assertEquals("cause = " + data.mCause, data.mPermanentFailure, DcFailCause.fromInt(
+ data.mCause).isPermanentFailure(mContext, mPhone.getSubId()));
}
- assertFalse(DcFailCause.fromInt(123456).isPermanentFail());
+ assertFalse(DcFailCause.fromInt(123456).isPermanentFailure(mContext, mPhone.getSubId()));
+ }
+
+ @Test
+ @SmallTest
+ public void testPermanentFailConfigured() throws Exception {
+
+ doReturn(2).when(mPhone).getSubId();
+ PersistableBundle mBundle = mContextFixture.getCarrierConfigBundle();
+ mBundle.putStringArray(
+ CarrierConfigManager.KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS,
+ new String[]{"SERVICE_OPTION_NOT_SUBSCRIBED", "TETHERED_CALL_ACTIVE"});
+
+ // Run it twice to make sure the cached carrier config is working as expected.
+ for (int i = 0; i < 2; i++) {
+ for (DcFailCauseData data : mFailCauseDataList) {
+ if (DcFailCause.fromInt(data.mCause).equals(
+ DcFailCause.SERVICE_OPTION_NOT_SUBSCRIBED) ||
+ DcFailCause.fromInt(data.mCause).equals(DcFailCause.TETHERED_CALL_ACTIVE)) {
+ assertTrue("cause = " + data.mCause, DcFailCause.fromInt(data.mCause).
+ isPermanentFailure(mContext, mPhone.getSubId()));
+ } else {
+ assertFalse("cause = " + data.mCause, DcFailCause.fromInt(data.mCause).
+ isPermanentFailure(mContext, mPhone.getSubId()));
+ }
+ }
+ }
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
index c35e498..1ca9acc 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -17,6 +17,7 @@
package com.android.internal.telephony.dataconnection;
import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+import static com.android.internal.telephony.dataconnection.ApnSettingTest.createApnSetting;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -28,7 +29,6 @@
import static org.mockito.Matchers.anyLong;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.nullable;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
@@ -37,7 +37,6 @@
import android.app.AlarmManager;
import android.app.PendingIntent;
-import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
@@ -61,6 +60,7 @@
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
import android.util.LocalLog;
import com.android.internal.telephony.DctConstants;
@@ -68,11 +68,10 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyTest;
-import com.android.internal.telephony.TestApplication;
-import com.android.internal.telephony.dataconnection.DcTracker.DataAllowFailReason;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -96,10 +95,14 @@
private final static List<String> sApnTypes = Arrays.asList(
"default", "mms", "cbs", "fota", "supl", "ia", "emergency", "dun", "hipri", "ims");
-
+ private static final int LTE_BEARER_BITMASK = 1 << (ServiceState.RIL_RADIO_TECHNOLOGY_LTE - 1);
+ private static final int EHRPD_BEARER_BITMASK =
+ 1 << (ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD - 1);
public static final String FAKE_APN1 = "FAKE APN 1";
public static final String FAKE_APN2 = "FAKE APN 2";
public static final String FAKE_APN3 = "FAKE APN 3";
+ public static final String FAKE_APN4 = "FAKE APN 4";
+ public static final String FAKE_APN5 = "FAKE APN 5";
public static final String FAKE_IFNAME = "FAKE IFNAME";
public static final String FAKE_PCSCF_ADDRESS = "22.33.44.55";
public static final String FAKE_GATEWAY = "11.22.33.44";
@@ -114,6 +117,12 @@
NetworkRequest mNetworkRequest;
@Mock
SubscriptionInfo mSubscriptionInfo;
+ @Mock
+ ApnContext mApnContext;
+ @Mock
+ ApnSetting mApnSetting;
+ @Mock
+ DcAsyncChannel mDcac;
private DcTracker mDct;
private DcTrackerTestHandler mDcTrackerTestHandler;
@@ -201,7 +210,7 @@
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
- 0, // bearer
+ ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer
0, // bearer_bitmask
0, // profile_id
0, // modem_cognitive
@@ -230,7 +239,7 @@
"IP", // protocol
"IP", // roaming_protocol
1, // carrier_enabled
- 0, // bearer
+ ServiceState.RIL_RADIO_TECHNOLOGY_LTE, // bearer,
0, // bearer_bitmask
0, // profile_id
0, // modem_cognitive
@@ -271,6 +280,63 @@
"" // mnvo_match_data
});
+ mc.addRow(new Object[]{
+ 2166, // id
+ plmn, // numeric
+ "sp-mode ehrpd", // name
+ FAKE_APN4, // apn
+ "", // proxy
+ "", // port
+ "", // mmsc
+ "", // mmsproxy
+ "", // mmsport
+ "", // user
+ "", // password
+ -1, // authtype
+ "default,supl", // types
+ "IP", // protocol
+ "IP", // roaming_protocol
+ 1, // carrier_enabled
+ ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD, // bearer
+ 0, // bearer_bitmask
+ 0, // profile_id
+ 0, // modem_cognitive
+ 0, // max_conns
+ 0, // wait_time
+ 0, // max_conns_time
+ 0, // mtu
+ "", // mvno_type
+ "" // mnvo_match_data
+ });
+
+ mc.addRow(new Object[]{
+ 2166, // id
+ plmn, // numeric
+ "b-mobile for Nexus", // name
+ FAKE_APN5, // apn
+ "", // proxy
+ "", // port
+ "", // mmsc
+ "", // mmsproxy
+ "", // mmsport
+ "", // user
+ "", // password
+ -1, // authtype
+ "dun", // types
+ "IP", // protocol
+ "IP", // roaming_protocol
+ 1, // carrier_enabled
+ 0, // bearer
+ 0, // bearer_bitmask
+ 0, // profile_id
+ 0, // modem_cognitive
+ 0, // max_conns
+ 0, // wait_time
+ 0, // max_conns_time
+ 0, // mtu
+ "", // mvno_type
+ "" // mnvo_match_data
+ });
return mc;
}
}
@@ -281,15 +347,13 @@
@Before
public void setUp() throws Exception {
- // set the lazy cp to the real content provider in order to use the real settings
- ContentResolver realContentResolver = TestApplication.getAppContext().getContentResolver();
- Settings.Global.getInt(realContentResolver, Settings.Global.MOBILE_DATA, 1);
-
logd("DcTrackerTest +Setup!");
super.setUp(getClass().getSimpleName());
doReturn("fake.action_detached").when(mPhone).getActionDetached();
doReturn("fake.action_attached").when(mPhone).getActionAttached();
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState)
+ .getRilDataRadioTechnology();
doReturn("44010").when(mSimRecords).getOperatorNumeric();
mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
@@ -338,6 +402,8 @@
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mBundle = mContextFixture.getCarrierConfigBundle();
+ mSimulatedCommands.setDataCallResponse(true, createDataCallResponse());
+
mDcTrackerTestHandler = new DcTrackerTestHandler(getClass().getSimpleName());
mDcTrackerTestHandler.start();
waitUntilReady();
@@ -350,7 +416,7 @@
logd("DcTrackerTest -tearDown");
mDct.removeCallbacksAndMessages(null);
mDct = null;
- mDcTrackerTestHandler.quitSafely();
+ mDcTrackerTestHandler.quit();
super.tearDown();
}
@@ -362,21 +428,21 @@
}
private void verifyDataProfile(DataProfile dp, String apn, int profileId,
- int supportedApnTypesBitmap) {
+ int supportedApnTypesBitmap, int type, int bearerBitmask) {
assertEquals(profileId, dp.profileId);
assertEquals(apn, dp.apn);
assertEquals("IP", dp.protocol);
assertEquals(0, dp.authType);
assertEquals("", dp.user);
assertEquals("", dp.password);
- assertEquals(0, dp.type);
+ assertEquals(type, dp.type);
assertEquals(0, dp.maxConnsTime);
assertEquals(0, dp.maxConns);
assertEquals(0, dp.waitTime);
assertTrue(dp.enabled);
assertEquals(supportedApnTypesBitmap, dp.supportedApnTypesBitmap);
assertEquals("IP", dp.roamingProtocol);
- assertEquals(0, dp.bearerBitmap);
+ assertEquals(bearerBitmask, dp.bearerBitmap);
assertEquals(0, dp.mtu);
assertEquals("", dp.mvnoType);
assertEquals("", dp.mvnoMatchData);
@@ -387,12 +453,11 @@
verify(mPhone, times(1)).notifyDataConnection(eq(Phone.REASON_CONNECTED),
eq(PhoneConstants.APN_TYPE_DEFAULT));
- verify(mAlarmManager, times(1)).set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), anyLong(),
+ verify(mAlarmManager, times(1)).set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(),
any(PendingIntent.class));
assertEquals(apnSetting, mDct.getActiveApnString(PhoneConstants.APN_TYPE_DEFAULT));
assertArrayEquals(new String[]{PhoneConstants.APN_TYPE_DEFAULT}, mDct.getActiveApnTypes());
- assertTrue(mDct.getAnyDataEnabled());
assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
assertEquals(DctConstants.State.CONNECTED, mDct.getState(PhoneConstants.APN_TYPE_DEFAULT));
@@ -406,12 +471,12 @@
assertEquals(FAKE_GATEWAY, linkProperties.getRoutes().get(0).getGateway().getHostAddress());
}
- private boolean isDataAllowed(DataAllowFailReason dataAllowFailReasons) {
+ private boolean isDataAllowed(DataConnectionReasons dataConnectionReasons) {
try {
Method method = DcTracker.class.getDeclaredMethod("isDataAllowed",
- DataAllowFailReason.class);
+ DataConnectionReasons.class);
method.setAccessible(true);
- return (boolean) method.invoke(mDct, dataAllowFailReasons);
+ return (boolean) method.invoke(mDct, dataConnectionReasons);
} catch (Exception e) {
fail(e.toString());
return false;
@@ -427,9 +492,9 @@
mSimulatedCommands.setDataCallResponse(true, createDataCallResponse());
- DataAllowFailReason failureReason = new DataAllowFailReason();
- boolean allowed = isDataAllowed(failureReason);
- assertFalse(failureReason.getDataAllowFailReason(), allowed);
+ DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
+ boolean allowed = isDataAllowed(dataConnectionReasons);
+ assertFalse(dataConnectionReasons.toString(), allowed);
logd("Sending EVENT_RECORDS_LOADED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
@@ -465,16 +530,16 @@
mDct.setEnabled(0, true);
waitForMs(200);
- failureReason.clearAllReasons();
- allowed = isDataAllowed(failureReason);
- assertTrue(failureReason.getDataAllowFailReason(), allowed);
+ dataConnectionReasons = new DataConnectionReasons();
+ allowed = isDataAllowed(dataConnectionReasons);
+ assertTrue(dataConnectionReasons.toString(), allowed);
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
// Verify if RIL command was sent properly.
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
- eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), dpCaptor.capture(),
+ eq(mServiceState.getRilDataRadioTechnology()), dpCaptor.capture(),
eq(false), eq(false), any(Message.class));
- verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5);
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, LTE_BEARER_BITMASK);
verifyDataConnected(FAKE_APN1);
}
@@ -492,9 +557,9 @@
// Simulate RIL fails the data call setup
mSimulatedCommands.setDataCallResponse(false, dcResponse);
- DataAllowFailReason failureReason = new DataAllowFailReason();
- boolean allowed = isDataAllowed(failureReason);
- assertFalse(failureReason.getDataAllowFailReason(), allowed);
+ DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
+ boolean allowed = isDataAllowed(dataConnectionReasons);
+ assertFalse(dataConnectionReasons.toString(), allowed);
logd("Sending EVENT_RECORDS_LOADED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
@@ -531,16 +596,16 @@
waitForMs(200);
- failureReason.clearAllReasons();
- allowed = isDataAllowed(failureReason);
- assertTrue(failureReason.getDataAllowFailReason(), allowed);
+ dataConnectionReasons = new DataConnectionReasons();
+ allowed = isDataAllowed(dataConnectionReasons);
+ assertTrue(dataConnectionReasons.toString(), allowed);
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
// Verify if RIL command was sent properly.
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
- eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), dpCaptor.capture(),
+ eq(mServiceState.getRilDataRadioTechnology()), dpCaptor.capture(),
eq(false), eq(false), any(Message.class));
- verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5);
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, LTE_BEARER_BITMASK);
// Make sure we never notify connected because the data call setup is supposed to fail.
verify(mPhone, never()).notifyDataConnection(eq(Phone.REASON_CONNECTED),
@@ -564,9 +629,9 @@
dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
// Verify if RIL command was sent properly.
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
- eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), dpCaptor.capture(),
+ eq(mServiceState.getRilDataRadioTechnology()), dpCaptor.capture(),
eq(false), eq(false), any(Message.class));
- verifyDataProfile(dpCaptor.getValue(), FAKE_APN2, 0, 5);
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN2, 0, 5, 1, LTE_BEARER_BITMASK);
// Verify connected with APN2 setting.
verifyDataConnected(FAKE_APN2);
@@ -574,6 +639,8 @@
@Test
@MediumTest
+ @Ignore
+ @FlakyTest
public void testUserDisableData() throws Exception {
//step 1: setup two DataCalls one for Metered: default, another one for Non-metered: IMS
//set Default and MMS to be metered in the CarrierConfigManager
@@ -597,9 +664,9 @@
waitForMs(200);
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
- eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), dpCaptor.capture(),
+ eq(mServiceState.getRilDataRadioTechnology()), dpCaptor.capture(),
eq(false), eq(false), any(Message.class));
- verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5);
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, LTE_BEARER_BITMASK);
logd("Sending DATA_DISABLED_CMD");
mDct.setDataEnabled(false);
@@ -648,14 +715,14 @@
waitForMs(300);
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
- eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), dpCaptor.capture(),
+ eq(mServiceState.getRilDataRadioTechnology()), dpCaptor.capture(),
eq(false), eq(false), any(Message.class));
- verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5);
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, LTE_BEARER_BITMASK);
//user is in roaming
doReturn(true).when(mServiceState).getDataRoaming();
logd("Sending DISABLE_ROAMING_CMD");
- mDct.setDataRoamingEnabled(false);
+ mDct.setDataRoamingEnabledByUser(false);
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_ROAMING_ON));
waitForMs(200);
@@ -667,12 +734,11 @@
assertEquals(DctConstants.State.CONNECTED, mDct.getState(PhoneConstants.APN_TYPE_IMS));
// reset roaming settings / data enabled settings at end of this test
- mDct.setDataRoamingEnabled(roamingEnabled);
+ mDct.setDataRoamingEnabledByUser(roamingEnabled);
mDct.setDataEnabled(dataEnabled);
waitForMs(200);
}
- @FlakyTest
@Test
@MediumTest
public void testDataCallOnUserDisableRoaming() throws Exception {
@@ -682,16 +748,19 @@
boolean roamingEnabled = mDct.getDataRoamingEnabled();
boolean dataEnabled = mDct.getDataEnabled();
+ doReturn(true).when(mServiceState).getDataRoaming();
//set Default and MMS to be metered in the CarrierConfigManager
mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_ROAMING_APN_TYPES_STRINGS,
new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});
mDct.setEnabled(5, true);
mDct.setEnabled(0, true);
- doReturn(true).when(mServiceState).getDataRoaming();
+
+ logd("Sending DATA_ENABLED_CMD");
+ mDct.setDataEnabled(true);
logd("Sending DISABLE_ROAMING_CMD");
- mDct.setDataRoamingEnabled(false);
+ mDct.setDataRoamingEnabledByUser(false);
logd("Sending EVENT_RECORDS_LOADED");
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
@@ -701,22 +770,21 @@
mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
waitForMs(200);
- logd("Sending DATA_ENABLED_CMD");
- mDct.setDataEnabled(true);
-
waitForMs(200);
- verify(mSimulatedCommandsVerifier, times(1)).setInitialAttachApn(any(DataProfile.class),
- eq(true), nullable(Message.class));
-
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
- eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), dpCaptor.capture(),
+ eq(mServiceState.getRilDataRadioTechnology()), dpCaptor.capture(),
eq(false), eq(false), any(Message.class));
- verifyDataProfile(dpCaptor.getValue(), FAKE_APN3, 2, 64);
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN3, 2, 64, 0, 0);
assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
assertEquals(DctConstants.State.IDLE, mDct.getState(PhoneConstants.APN_TYPE_DEFAULT));
assertEquals(DctConstants.State.CONNECTED, mDct.getState(PhoneConstants.APN_TYPE_IMS));
+
+ // reset roaming settings / data enabled settings at end of this test
+ mDct.setDataRoamingEnabledByUser(roamingEnabled);
+ mDct.setDataEnabled(dataEnabled);
+ waitForMs(200);
}
// Test the default data switch scenario.
@@ -731,9 +799,9 @@
mSimulatedCommands.setDataCallResponse(true, createDataCallResponse());
- DataAllowFailReason failureReason = new DataAllowFailReason();
- boolean allowed = isDataAllowed(failureReason);
- assertFalse(failureReason.getDataAllowFailReason(), allowed);
+ DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
+ boolean allowed = isDataAllowed(dataConnectionReasons);
+ assertFalse(dataConnectionReasons.toString(), allowed);
ArgumentCaptor<Integer> intArgumentCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mUiccController, times(1)).registerForIccChanged(eq(mDct),
@@ -774,9 +842,9 @@
waitForMs(200);
// Data should not be allowed since auto attach flag has been reset.
- failureReason.clearAllReasons();
- allowed = isDataAllowed(failureReason);
- assertFalse(failureReason.getDataAllowFailReason(), allowed);
+ dataConnectionReasons = new DataConnectionReasons();
+ allowed = isDataAllowed(dataConnectionReasons);
+ assertFalse(dataConnectionReasons.toString(), allowed);
}
// Test for API carrierActionSetMeteredApnsEnabled.
@@ -807,9 +875,9 @@
ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
verify(mSimulatedCommandsVerifier, times(2)).setupDataCall(
- eq(ServiceState.RIL_RADIO_TECHNOLOGY_UMTS), dpCaptor.capture(),
+ eq(mServiceState.getRilDataRadioTechnology()), dpCaptor.capture(),
eq(false), eq(false), any(Message.class));
- verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5);
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, LTE_BEARER_BITMASK);
assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
Message msg = mDct.obtainMessage(DctConstants.EVENT_SET_CARRIER_DATA_ENABLED);
@@ -828,4 +896,320 @@
mDct.setDataEnabled(dataEnabled);
waitForMs(200);
}
+
+ private void initApns(String targetApn, String[] canHandleTypes) {
+ doReturn(targetApn).when(mApnContext).getApnType();
+ doReturn(true).when(mApnContext).isConnectable();
+ ApnSetting apnSetting = createApnSetting(canHandleTypes);
+ doReturn(apnSetting).when(mApnContext).getNextApnSetting();
+ doReturn(apnSetting).when(mApnContext).getApnSetting();
+ doReturn(mDcac).when(mApnContext).getDcAc();
+ doReturn(true).when(mApnContext).isEnabled();
+ doReturn(true).when(mApnContext).getDependencyMet();
+ doReturn(true).when(mApnContext).isReady();
+ doReturn(true).when(mApnContext).hasNoRestrictedRequests(eq(true));
+ }
+
+ // Test the emergency APN setup.
+ @Test
+ @SmallTest
+ public void testTrySetupDataEmergencyApn() throws Exception {
+ initApns(PhoneConstants.APN_TYPE_EMERGENCY, new String[]{PhoneConstants.APN_TYPE_ALL});
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+ waitForMs(200);
+
+ verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+ eq(mServiceState.getRilDataRadioTechnology()), any(DataProfile.class),
+ eq(false), eq(false), any(Message.class));
+ }
+
+ // Test the unmetered APN setup when data is disabled.
+ @Test
+ @SmallTest
+ public void testTrySetupDataUnmeteredDataDisabled() throws Exception {
+ initApns(PhoneConstants.APN_TYPE_FOTA, new String[]{PhoneConstants.APN_TYPE_ALL});
+ mDct.setDataEnabled(false);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+ waitForMs(200);
+
+ verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+ eq(mServiceState.getRilDataRadioTechnology()), any(DataProfile.class),
+ eq(false), eq(false), any(Message.class));
+ }
+
+ // Test the metered APN setup when data is disabled.
+ @Test
+ @SmallTest
+ public void testTrySetupMeteredDataDisabled() throws Exception {
+ initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+ mDct.setDataEnabled(false);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+ waitForMs(200);
+
+ verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(
+ anyInt(), any(DataProfile.class), eq(false), eq(false), any(Message.class));
+ }
+
+ // Test the restricted data request when data is disabled.
+ @Test
+ @SmallTest
+ public void testTrySetupRestrictedDataDisabled() throws Exception {
+ initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+ doReturn(false).when(mApnContext).hasNoRestrictedRequests(eq(true));
+
+ mDct.setDataEnabled(false);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+ waitForMs(200);
+
+ verify(mSimulatedCommandsVerifier, times(1)).setupDataCall(
+ anyInt(), any(DataProfile.class), eq(false), eq(false), any(Message.class));
+ }
+
+ // Test the default data when data is not connectable.
+ @Test
+ @SmallTest
+ public void testTrySetupNotConnectable() throws Exception {
+ initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+ doReturn(false).when(mApnContext).isConnectable();
+ mDct.setDataEnabled(true);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+ waitForMs(200);
+
+ verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(
+ anyInt(), any(DataProfile.class), eq(false), eq(false), any(Message.class));
+ }
+
+ // Test the default data on IWLAN.
+ @Test
+ @SmallTest
+ public void testTrySetupDefaultOnIWLAN() throws Exception {
+ initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN).when(mServiceState)
+ .getRilDataRadioTechnology();
+ mDct.setDataEnabled(true);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+ waitForMs(200);
+
+ verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(
+ anyInt(), any(DataProfile.class), eq(false), eq(false), any(Message.class));
+ }
+
+ // Test the default data when the phone is in ECBM.
+ @Test
+ @SmallTest
+ public void testTrySetupDefaultInECBM() throws Exception {
+ initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+ doReturn(true).when(mPhone).isInEcm();
+ mDct.setDataEnabled(true);
+
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, mApnContext));
+ waitForMs(200);
+
+ verify(mSimulatedCommandsVerifier, times(0)).setupDataCall(
+ anyInt(), any(DataProfile.class), eq(false), eq(false), any(Message.class));
+ }
+
+ // Test update waiting apn list when on data rat change
+ @Test
+ @SmallTest
+ public void testUpdateWaitingApnListOnDataRatChange() throws Exception {
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD).when(mServiceState)
+ .getRilDataRadioTechnology();
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+ mDct.setEnabled(0, true);
+ mDct.setDataEnabled(true);
+ initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
+ // Verify if RIL command was sent properly.
+ verify(mSimulatedCommandsVerifier).setupDataCall(
+ eq(mServiceState.getRilDataRadioTechnology()), dpCaptor.capture(),
+ eq(false), eq(false), any(Message.class));
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 5, 2, EHRPD_BEARER_BITMASK);
+ assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
+
+ //data rat change from ehrpd to lte
+ logd("Sending EVENT_DATA_RAT_CHANGED");
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState)
+ .getRilDataRadioTechnology();
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null));
+ waitForMs(200);
+
+ // Verify the disconnected data call due to rat change and retry manger schedule another
+ // data call setup
+ verify(mSimulatedCommandsVerifier, times(1)).deactivateDataCall(anyInt(), anyInt(),
+ any(Message.class));
+ verify(mAlarmManager, times(1)).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP),
+ anyLong(), any(PendingIntent.class));
+
+ // Simulate the timer expires.
+ Intent intent = new Intent("com.android.internal.telephony.data-reconnect.default");
+ intent.putExtra("reconnect_alarm_extra_type", PhoneConstants.APN_TYPE_DEFAULT);
+ intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, 0);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContext.sendBroadcast(intent);
+ waitForMs(200);
+
+ // Verify if RIL command was sent properly.
+ verify(mSimulatedCommandsVerifier).setupDataCall(
+ eq(mServiceState.getRilDataRadioTechnology()), dpCaptor.capture(),
+ eq(false), eq(false), any(Message.class));
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN1, 0, 5, 1, LTE_BEARER_BITMASK);
+ assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
+ }
+
+ // Test for fetchDunApn()
+ @Test
+ @SmallTest
+ public void testFetchDunApn() {
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ String dunApnString = "[ApnSettingV3]HOT mobile PC,pc.hotm,,,,,,,,,440,10,,DUN,,,true,"
+ + "0,,,,,,,,";
+ ApnSetting dunApnExpected = ApnSetting.fromString(dunApnString);
+
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.TETHER_DUN_APN, dunApnString);
+ // should return APN from Setting
+ ApnSetting dunApn = mDct.fetchDunApn();
+ assertTrue(dunApnExpected.equals(dunApn));
+
+ Settings.Global.putString(mContext.getContentResolver(),
+ Settings.Global.TETHER_DUN_APN, null);
+ // should return APN from db
+ dunApn = mDct.fetchDunApn();
+ assertEquals(FAKE_APN5, dunApn.apn);
+ }
+
+ // Test oos
+ @Test
+ @SmallTest
+ public void testDataRatChangeOOS() throws Exception {
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD).when(mServiceState)
+ .getRilDataRadioTechnology();
+ mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
+ new String[]{PhoneConstants.APN_TYPE_DEFAULT});
+ mDct.setEnabled(0, true);
+ mDct.setDataEnabled(true);
+ initApns(PhoneConstants.APN_TYPE_DEFAULT, new String[]{PhoneConstants.APN_TYPE_ALL});
+
+ logd("Sending EVENT_RECORDS_LOADED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_RECORDS_LOADED, null));
+ waitForMs(200);
+
+ logd("Sending EVENT_DATA_CONNECTION_ATTACHED");
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null));
+ waitForMs(200);
+
+ ArgumentCaptor<DataProfile> dpCaptor = ArgumentCaptor.forClass(DataProfile.class);
+ // Verify if RIL command was sent properly.
+ verify(mSimulatedCommandsVerifier).setupDataCall(
+ eq(mServiceState.getRilDataRadioTechnology()), dpCaptor.capture(),
+ eq(false), eq(false), any(Message.class));
+ verifyDataProfile(dpCaptor.getValue(), FAKE_APN4, 0, 5, 2, EHRPD_BEARER_BITMASK);
+ assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
+
+ // Data rat change from ehrpd to unknown due to OOS
+ logd("Sending EVENT_DATA_RAT_CHANGED");
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN).when(mServiceState)
+ .getRilDataRadioTechnology();
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null));
+ waitForMs(200);
+
+ // Verify data connection is on
+ verify(mSimulatedCommandsVerifier, times(0)).deactivateDataCall(anyInt(), anyInt(),
+ any(Message.class));
+
+ // Data rat resume from unknown to ehrpd
+ doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD).when(mServiceState)
+ .getRilDataRadioTechnology();
+ mDct.sendMessage(mDct.obtainMessage(DctConstants.EVENT_DATA_RAT_CHANGED, null));
+ waitForMs(200);
+
+ // Verify the same data connection
+ assertEquals(FAKE_APN4, mDct.getActiveApnString(PhoneConstants.APN_TYPE_DEFAULT));
+ assertEquals(DctConstants.State.CONNECTED, mDct.getOverallState());
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
index e377600..a60b502 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/TelephonyNetworkFactoryTest.java
@@ -98,6 +98,7 @@
}
void die() {
+ connectivityServiceMock.die();
looper.quit();
handlerThread.quit();
}
@@ -139,7 +140,7 @@
TestSetup ts = new TestSetup(numberOfPhones);
- TelephonyNetworkFactory tnf = makeTnf(phoneId, ts);
+ makeTnf(phoneId, ts);
ts.subscriptionControllerMock.setDefaultDataSubId(subId);
ts.subscriptionControllerMock.setSlotSubId(phoneId, subId);
@@ -234,7 +235,7 @@
TestSetup ts = new TestSetup(numberOfPhones);
- TelephonyNetworkFactory tnf = makeTnf(phoneId, ts);
+ makeTnf(phoneId, ts);
ts.subscriptionControllerMock.setDefaultDataSubId(subId);
ts.subscriptionControllerMock.setSlotSubId(phoneId, subId);
@@ -272,7 +273,7 @@
fail("test 5, LiveRequests != 0");
}
- NetworkRequest subSpecificMms = makeSubSpecificMmsRequest(ts, subId);
+ makeSubSpecificMmsRequest(ts, subId);
waitABit();
if (ts.dcTrackerMock.getNumberOfLiveRequests() != 1) {
fail("test 6, LiveRequests != 1");
@@ -285,7 +286,7 @@
fail("test 7, LiveRequests != 0");
}
- NetworkRequest subSpecificDefault = makeSubSpecificDefaultRequest(ts, subId);
+ makeSubSpecificDefaultRequest(ts, subId);
waitABit();
if (ts.dcTrackerMock.getNumberOfLiveRequests() != 0) {
fail("test 8, LiveRequests != 0");
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
index 20cefb9..b117eb1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmCellBroadcastHandlerTest.java
@@ -39,7 +39,6 @@
import android.provider.Settings;
import android.provider.Telephony;
import android.support.test.filters.FlakyTest;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.internal.telephony.SmsStorageMonitor;
import com.android.internal.telephony.TelephonyTest;
@@ -47,12 +46,13 @@
import org.junit.After;
import org.junit.Before;
-import org.junit.Test;
+import org.junit.Ignore;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import java.util.List;
+@Ignore
public class GsmCellBroadcastHandlerTest extends TelephonyTest {
@Mock
private SmsStorageMonitor mSmsStorageMonitor;
@@ -95,12 +95,11 @@
@After
public void tearDown() throws Exception {
mGsmCellBroadcastHandler = null;
- mGsmCellBroadcastHandlerTestHandler.quitSafely();
+ mGsmCellBroadcastHandlerTestHandler.quit();
super.tearDown();
}
@FlakyTest
- @Test @SmallTest
public void testBroadcastSms() {
mContextFixture.putResource(
com.android.internal.R.string.config_defaultCellBroadcastReceiverPkg,
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
index 340ff35..e9a16bf 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmInboundSmsHandlerTest.java
@@ -64,6 +64,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -187,7 +188,7 @@
assertFalse(mGsmInboundSmsHandler.getWakeLock().isHeld());
mGsmInboundSmsHandler = null;
mContentProvider.shutdown();
- mGsmInboundSmsHandlerTestHandler.quitSafely();
+ mGsmInboundSmsHandlerTestHandler.quit();
super.tearDown();
}
@@ -225,6 +226,8 @@
assertEquals("IdleState", getCurrentState().getName());
}
+ @FlakyTest
+ @Ignore
@Test
@MediumTest
public void testNewSms() {
@@ -304,7 +307,7 @@
mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_INJECT_SMS, new AsyncResult(null,
mSmsMessage, null));
- waitForMs(100);
+ waitForMs(200);
verifySmsIntentBroadcasts(0);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
index fc06962..335634d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/gsm/GsmSmsDispatcherTest.java
@@ -16,33 +16,54 @@
package com.android.internal.telephony.gsm;
+import static android.telephony.SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED;
+
+import static com.android.internal.telephony.SmsUsageMonitor.CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE;
+import static com.android.internal.telephony.SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW;
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.location.Country;
import android.location.CountryDetector;
import android.os.HandlerThread;
import android.os.Message;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.provider.Telephony;
import android.support.test.filters.FlakyTest;
+import android.telephony.SmsManager;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Singleton;
+import com.android.internal.telephony.ContextFixture;
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.ImsSMSDispatcher;
+import com.android.internal.telephony.SMSDispatcher;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.TelephonyTestUtils;
+import com.android.internal.telephony.TestApplication;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import java.util.HashMap;
+
public class GsmSmsDispatcherTest extends TelephonyTest {
@Mock
private android.telephony.SmsMessage mSmsMessage;
@@ -55,7 +76,21 @@
@Mock
private CountryDetector mCountryDetector;
@Mock
+ private SMSDispatcher.SmsTracker mSmsTracker;
+ @Mock
private ISub.Stub mISubStub;
+ private Object mLock = new Object();
+ private boolean mReceivedTestIntent = false;
+ private static final String TEST_INTENT = "com.android.internal.telephony.TEST_INTENT";
+ private BroadcastReceiver mTestReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ logd("onReceive");
+ synchronized (mLock) {
+ mReceivedTestIntent = true;
+ }
+ }
+ };
private GsmSMSDispatcher mGsmSmsDispatcher;
private GsmSmsDispatcherTestHandler mGsmSmsDispatcherTestHandler;
@@ -91,7 +126,7 @@
@After
public void tearDown() throws Exception {
mGsmSmsDispatcher = null;
- mGsmSmsDispatcherTestHandler.quitSafely();
+ mGsmSmsDispatcherTestHandler.quit();
super.tearDown();
}
@@ -147,4 +182,57 @@
return systemEmergencyNumbers.split(",")[0];
}
}
+
+ @Test @SmallTest
+ public void testSendTextWithInvalidDestAddr() throws Exception {
+ // unmock ActivityManager to be able to register receiver, create real PendingIntent and
+ // receive TEST_INTENT
+ restoreInstance(Singleton.class, "mInstance", mIActivityManagerSingleton);
+ restoreInstance(ActivityManager.class, "IActivityManagerSingleton", null);
+ Context realContext = TestApplication.getAppContext();
+ realContext.registerReceiver(mTestReceiver, new IntentFilter(TEST_INTENT));
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(realContext, 0,
+ new Intent(TEST_INTENT), 0);
+ // send invalid dest address: +
+ mGsmSmsDispatcher.sendText("+", "222" /*scAddr*/, TAG,
+ pendingIntent, null, null, null, false);
+ waitForMs(500);
+ verify(mSimulatedCommandsVerifier, times(0)).sendSMS(anyString(), anyString(),
+ any(Message.class));
+ synchronized (mLock) {
+ assertEquals(true, mReceivedTestIntent);
+ assertEquals(SmsManager.RESULT_ERROR_NULL_PDU, mTestReceiver.getResultCode());
+ }
+ }
+
+ @Test
+ public void testSendRawPduWithEventStopSending() throws Exception {
+ setupMockPackagePermissionChecks();
+ mContextFixture.removeCallingOrSelfPermission(ContextFixture.PERMISSION_ENABLE_ALL);
+
+ // return a fake value to pass getData()
+ HashMap data = new HashMap<String, String>();
+ data.put("pdu", new byte[1]);
+ when(mSmsTracker.getData()).thenReturn(data);
+
+ // Set values to return to simulate EVENT_STOP_SENDING
+ when(mSmsUsageMonitor.checkDestination(any(), any()))
+ .thenReturn(CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE);
+ when(mSmsUsageMonitor.getPremiumSmsPermission(any()))
+ .thenReturn(PREMIUM_SMS_PERMISSION_NEVER_ALLOW);
+ when(mSmsTracker.getAppPackageName()).thenReturn("");
+
+ // Settings.Global.DEVICE_PROVISIONED to 1
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.DEVICE_PROVISIONED, 1);
+
+ mGsmSmsDispatcher.sendRawPdu(mSmsTracker);
+
+ verify(mSmsUsageMonitor, times(1)).checkDestination(any(), any());
+ verify(mSmsUsageMonitor, times(1)).getPremiumSmsPermission(any());
+ ArgumentCaptor<Integer> argumentCaptor = ArgumentCaptor
+ .forClass(Integer.class);
+ verify(mSmsTracker, times(1)).onFailed(any(), argumentCaptor.capture(), anyInt());
+ assertEquals(RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED, (int) argumentCaptor.getValue());
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
index 28855ff..7b831a0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsServiceControllerTest.java
@@ -16,33 +16,10 @@
package com.android.internal.telephony.ims;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.support.test.runner.AndroidJUnit4;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Pair;
-
-import com.android.ims.internal.IImsServiceFeatureListener;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.Spy;
-
-import java.util.HashSet;
-
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
@@ -51,10 +28,36 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.support.test.filters.FlakyTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Pair;
+
+import com.android.ims.internal.IImsServiceFeatureListener;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+import java.util.HashSet;
+
/**
* Unit tests for ImsServiceController
*/
@RunWith(AndroidJUnit4.class)
+@Ignore
public class ImsServiceControllerTest extends ImsTestBase {
private static final int RETRY_TIMEOUT = 50; // ms
@@ -91,8 +94,8 @@
/**
* Tests that Context.bindService is called with the correct parameters when we call bind.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindService() {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -113,8 +116,8 @@
/**
* Verify that if bind is called multiple times, we only call bindService once.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindFailureWhenBound() {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -130,8 +133,8 @@
* Tests ImsServiceController callbacks are properly called when an ImsService is bound and
* connected.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindServiceAndConnected() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -157,8 +160,8 @@
* Tests ImsServiceController callbacks are properly called when an ImsService is bound and
* connected.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindServiceAndConnectedDisconnected() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -183,8 +186,8 @@
* Tests ImsServiceController callbacks are properly called when an ImsService is bound and
* connected.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindServiceBindUnbind() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -209,8 +212,8 @@
/**
* Ensures that imsServiceFeatureRemoved is called when the binder dies in another process.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindServiceAndBinderDied() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -234,8 +237,8 @@
/**
* Ensures ImsService and ImsResolver are notified when a feature is added.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindServiceAndAddFeature() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -259,8 +262,8 @@
/**
* Ensures ImsService and ImsResolver are notified when a feature is added.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindServiceAndRemoveFeature() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -289,8 +292,8 @@
/**
* Ensures ImsService and ImsResolver are notified when all features are removed.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindServiceAndRemoveAllFeatures() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -321,8 +324,8 @@
/**
* Verifies that nothing is notified of a feature change if the service is not bound.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindUnbindServiceAndAddFeature() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -344,8 +347,8 @@
* Verifies that the ImsServiceController automatically tries to bind again after an untimely
* binder death.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testAutoBindAfterBinderDied() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -364,8 +367,8 @@
/**
* Ensure that bindService has only been called once before automatic rebind occurs.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testNoAutoBindBeforeTimeout() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -382,8 +385,8 @@
/**
* Ensure that calling unbind stops automatic rebind of the ImsService from occuring.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testUnbindCauseAutoBindCancelAfterBinderDied() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
@@ -404,8 +407,8 @@
* Ensure that calling bind causes the automatic rebinding to be cancelled or not cause another
* call to bindService.
*/
+ @FlakyTest
@Test
- @SmallTest
public void testBindCauseAutoBindCancelAfterBinderDied() throws RemoteException {
HashSet<Pair<Integer, Integer>> testFeatures = new HashSet<>();
testFeatures.add(new Pair<>(1, 1));
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/ImsVideoProviderWrapperTest.java b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsVideoProviderWrapperTest.java
new file mode 100644
index 0000000..338e8a4
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/ImsVideoProviderWrapperTest.java
@@ -0,0 +1,174 @@
+/*
+ * 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.ims;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.telecom.VideoProfile;
+
+import com.android.ims.internal.ImsVideoCallProviderWrapper;
+import com.android.ims.internal.VideoPauseTracker;
+
+import junit.framework.TestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for the {@link com.android.ims.internal.VideoPauseTracker} class.
+ */
+@RunWith(AndroidJUnit4.class)
+public class ImsVideoProviderWrapperTest extends TestCase {
+ private ImsVideoCallProviderWrapper mImsVideoCallProviderWrapper;
+ @Mock
+ VideoPauseTracker mVideoPauseTracker;
+
+ @Before
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+ mImsVideoCallProviderWrapper = new ImsVideoCallProviderWrapper(null, mVideoPauseTracker);
+ when(mVideoPauseTracker.shouldPauseVideoFor(anyInt())).thenReturn(true);
+ when(mVideoPauseTracker.shouldResumeVideoFor(anyInt())).thenReturn(true);
+ }
+
+ @SmallTest
+ @Test
+ public void testIsPause() {
+ assertTrue(ImsVideoCallProviderWrapper.isPauseRequest(VideoProfile.STATE_BIDIRECTIONAL,
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED));
+ assertTrue(ImsVideoCallProviderWrapper.isPauseRequest(VideoProfile.STATE_BIDIRECTIONAL,
+ VideoProfile.STATE_PAUSED));
+ assertFalse(ImsVideoCallProviderWrapper.isPauseRequest(VideoProfile.STATE_PAUSED,
+ VideoProfile.STATE_PAUSED));
+ assertFalse(ImsVideoCallProviderWrapper.isPauseRequest(VideoProfile.STATE_AUDIO_ONLY,
+ VideoProfile.STATE_AUDIO_ONLY));
+ }
+
+ @SmallTest
+ @Test
+ public void testIsResume() {
+ assertTrue(ImsVideoCallProviderWrapper.isResumeRequest(
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED,
+ VideoProfile.STATE_BIDIRECTIONAL));
+ assertTrue(ImsVideoCallProviderWrapper.isResumeRequest(VideoProfile.STATE_PAUSED,
+ VideoProfile.STATE_AUDIO_ONLY));
+ assertFalse(ImsVideoCallProviderWrapper.isResumeRequest(
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED,
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED));
+ assertFalse(ImsVideoCallProviderWrapper.isResumeRequest(VideoProfile.STATE_PAUSED,
+ VideoProfile.STATE_AUDIO_ONLY | VideoProfile.STATE_PAUSED));
+ }
+
+ @SmallTest
+ @Test
+ public void testIsTurnOffCameraRequest() {
+ assertTrue(ImsVideoCallProviderWrapper.isTurnOffCameraRequest(
+ VideoProfile.STATE_BIDIRECTIONAL, VideoProfile.STATE_RX_ENABLED));
+ assertTrue(ImsVideoCallProviderWrapper.isTurnOffCameraRequest(
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED,
+ VideoProfile.STATE_RX_ENABLED));
+ assertFalse(ImsVideoCallProviderWrapper.isTurnOffCameraRequest(
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED,
+ VideoProfile.STATE_BIDIRECTIONAL));
+ }
+
+ @SmallTest
+ @Test
+ public void testIsTurnOnCameraRequest() {
+ assertTrue(ImsVideoCallProviderWrapper.isTurnOnCameraRequest(
+ VideoProfile.STATE_RX_ENABLED, VideoProfile.STATE_BIDIRECTIONAL));
+ assertTrue(ImsVideoCallProviderWrapper.isTurnOnCameraRequest(
+ VideoProfile.STATE_RX_ENABLED,
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED));
+ assertFalse(ImsVideoCallProviderWrapper.isTurnOnCameraRequest(
+ VideoProfile.STATE_BIDIRECTIONAL,
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED));
+ }
+
+ /**
+ * Verifies that the to profile is not changed when a request to turn off the camera is sent
+ * using the broken vendor-format request.
+ */
+ @SmallTest
+ @Test
+ public void testNoFilterWhenDisablingCamera() {
+ mImsVideoCallProviderWrapper.setUseVideoPauseWorkaround(true);
+ VideoProfile fromProfile = new VideoProfile(
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED);
+ VideoProfile toProfile = new VideoProfile(VideoProfile.STATE_RX_ENABLED);
+
+ VideoProfile filteredTo = mImsVideoCallProviderWrapper.maybeFilterPauseResume(fromProfile,
+ toProfile, VideoPauseTracker.SOURCE_INCALL);
+ assertEquals(filteredTo.getVideoState(), toProfile.getVideoState());
+ }
+
+ /**
+ * Verifies that the to profile is not changed when a request to turn on the camera is sent
+ * using the broken vendor-format request.
+ */
+ @SmallTest
+ @Test
+ public void testNoFilterWhenEnablingCamera() {
+ mImsVideoCallProviderWrapper.setUseVideoPauseWorkaround(true);
+ VideoProfile fromProfile = new VideoProfile(
+ VideoProfile.STATE_RX_ENABLED | VideoProfile.STATE_PAUSED);
+ VideoProfile toProfile = new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL);
+
+ VideoProfile filteredTo = mImsVideoCallProviderWrapper.maybeFilterPauseResume(fromProfile,
+ toProfile, VideoPauseTracker.SOURCE_INCALL);
+ assertEquals(filteredTo.getVideoState(), toProfile.getVideoState());
+ }
+
+ /**
+ * Verifies normal operation of filtering of pause request.
+ */
+ @SmallTest
+ @Test
+ public void testNoFilteringOnPause() {
+ VideoProfile fromProfile = new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL);
+ VideoProfile toProfile = new VideoProfile(
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED);
+
+ VideoProfile filteredTo = mImsVideoCallProviderWrapper.maybeFilterPauseResume(fromProfile,
+ toProfile, VideoPauseTracker.SOURCE_INCALL);
+ assertEquals(filteredTo.getVideoState(), toProfile.getVideoState());
+ }
+
+ /**
+ * Verifies normal operation of filtering of pause request.
+ */
+ @SmallTest
+ @Test
+ public void testNoFilteringOnResume() {
+ VideoProfile fromProfile = new VideoProfile(
+ VideoProfile.STATE_BIDIRECTIONAL | VideoProfile.STATE_PAUSED);
+ VideoProfile toProfile = new VideoProfile(VideoProfile.STATE_BIDIRECTIONAL);
+
+ VideoProfile filteredTo = mImsVideoCallProviderWrapper.maybeFilterPauseResume(fromProfile,
+ toProfile, VideoPauseTracker.SOURCE_INCALL);
+ assertEquals(filteredTo.getVideoState(), toProfile.getVideoState());
+ }
+}
+
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ims/TestImsServiceControllerAdapter.java b/tests/telephonytests/src/com/android/internal/telephony/ims/TestImsServiceControllerAdapter.java
index 564e284..0e22be1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ims/TestImsServiceControllerAdapter.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ims/TestImsServiceControllerAdapter.java
@@ -52,7 +52,8 @@
}
@Override
- public void removeImsFeature(int slotId, int feature) throws RemoteException {
+ public void removeImsFeature(int slotId, int feature, IImsFeatureStatusCallback c)
+ throws RemoteException {
TestImsServiceControllerAdapter.this.removeImsFeature(slotId, feature);
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
index 923cd05..be8d6f6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneCallTrackerTest.java
@@ -15,18 +15,39 @@
*/
package com.android.internal.telephony.imsphone;
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.isNull;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.support.test.filters.FlakyTest;
+import android.telephony.DisconnectCause;
+import android.telecom.VideoProfile;
import android.telephony.PhoneNumberUtils;
import android.telephony.ims.feature.ImsFeature;
import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.LargeTest;
import com.android.ims.ImsCall;
import com.android.ims.ImsCallProfile;
@@ -38,6 +59,7 @@
import com.android.ims.ImsServiceClass;
import com.android.ims.internal.ImsCallSession;
import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.PhoneConstants;
@@ -46,33 +68,13 @@
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.isNull;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
public class ImsPhoneCallTrackerTest extends TelephonyTest {
private ImsPhoneCallTracker mCTUT;
private ImsCTHandlerThread mImsCTHandlerThread;
@@ -84,6 +86,8 @@
private int mServiceId;
@Mock
private ImsCallSession mImsCallSession;
+ @Mock
+ private SharedPreferences mSharedPreferences;
private Handler mCTHander;
private class ImsCTHandlerThread extends HandlerThread {
@@ -211,7 +215,7 @@
@After
public void tearDown() throws Exception {
mCTUT = null;
- mImsCTHandlerThread.quitSafely();
+ mImsCTHandlerThread.quit();
super.tearDown();
}
@@ -228,6 +232,7 @@
mImsConnectionStateListener.onFeatureCapabilityChanged(ImsServiceClass.MMTEL,
featureEnableArray,
featureDisableArray);
+ waitForHandlerAction(mCTHander, 1000);
assertTrue(mCTUT.isVolteEnabled());
assertFalse(mCTUT.isVideoCallEnabled());
// video call not enabled
@@ -239,6 +244,7 @@
mImsConnectionStateListener.onFeatureCapabilityChanged(ImsServiceClass.MMTEL,
featureEnableArray,
featureDisableArray);
+ waitForHandlerAction(mCTHander, 1000);
assertTrue(mCTUT.isVideoCallEnabled());
verify(mImsPhone, times(1)).notifyForVideoCapabilityChanged(eq(true));
}
@@ -349,6 +355,31 @@
assertEquals(Call.State.HOLDING, mCTUT.mBackgroundCall.getState());
}
+ /**
+ * Ensures that the dial method will perform a shared preferences lookup using the correct
+ * shared preference key to determine the CLIR mode.
+ */
+ @Test
+ @SmallTest
+ public void testDialClirMode() {
+ mCTUT.setSharedPreferenceProxy((Context context) -> {
+ return mSharedPreferences;
+ });
+ ArgumentCaptor<String> mStringCaptor = ArgumentCaptor.forClass(String.class);
+ doReturn(CommandsInterface.CLIR_INVOCATION).when(mSharedPreferences).getInt(
+ mStringCaptor.capture(), anyInt());
+
+ try {
+ mCTUT.dial("+17005554141", VideoProfile.STATE_AUDIO_ONLY, null);
+ } catch (CallStateException cse) {
+ cse.printStackTrace();
+ Assert.fail("unexpected exception thrown" + cse.getMessage());
+ }
+
+ // Ensure that the correct key was queried from the shared prefs.
+ assertEquals("clir_key0", mStringCaptor.getValue());
+ }
+
@FlakyTest
@Test
@SmallTest
@@ -370,6 +401,8 @@
assertEquals(Call.State.ALERTING, mCTUT.mForegroundCall.getState());
}
+ @FlakyTest
+ @Ignore
@Test
@SmallTest
public void testImsMTActiveMODial() {
@@ -476,6 +509,8 @@
nullable(ImsConnectionStateListener.class));
}
+ @FlakyTest
+ @Ignore
@Test
@SmallTest
public void testTTYImsServiceUnavailable() throws ImsException {
@@ -494,4 +529,22 @@
verify(mImsManager, times(2)).open(anyInt(), nullable(PendingIntent.class),
nullable(ImsConnectionStateListener.class));
}
+
+ @Test
+ @SmallTest
+ public void testLowBatteryDisconnectMidCall() {
+ assertEquals(DisconnectCause.LOW_BATTERY, mCTUT.getDisconnectCauseFromReasonInfo(
+ new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_LOW_BATTERY, 0), Call.State.ACTIVE));
+ assertEquals(DisconnectCause.LOW_BATTERY, mCTUT.getDisconnectCauseFromReasonInfo(
+ new ImsReasonInfo(ImsReasonInfo.CODE_LOW_BATTERY, 0), Call.State.ACTIVE));
+ }
+
+ @Test
+ @SmallTest
+ public void testLowBatteryDisconnectDialing() {
+ assertEquals(DisconnectCause.DIAL_LOW_BATTERY, mCTUT.getDisconnectCauseFromReasonInfo(
+ new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_LOW_BATTERY, 0), Call.State.DIALING));
+ assertEquals(DisconnectCause.DIAL_LOW_BATTERY, mCTUT.getDisconnectCauseFromReasonInfo(
+ new ImsReasonInfo(ImsReasonInfo.CODE_LOW_BATTERY, 0), Call.State.DIALING));
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java
index 8a7c53a..c31541e 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneFactoryTest.java
@@ -60,7 +60,7 @@
@After
public void tearDown() throws Exception {
- mImsPhoneFactoryHandler.quitSafely();
+ mImsPhoneFactoryHandler.quit();
super.tearDown();
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
index de0c8ce..3b357d7 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java
@@ -66,6 +66,7 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -141,7 +142,7 @@
@After
public void tearDown() throws Exception {
mImsPhoneUT = null;
- mImsPhoneTestHandler.quitSafely();
+ mImsPhoneTestHandler.quit();
super.tearDown();
}
@@ -450,7 +451,7 @@
@FlakyTest
@Test
- @SmallTest
+ @Ignore
public void testCallForwardingOption() throws Exception {
Message msg = mTestHandler.obtainMessage();
mImsPhoneUT.getCallForwardingOption(CF_REASON_UNCONDITIONAL, msg);
@@ -507,8 +508,9 @@
assertEquals(msg, messageArgumentCaptor.getValue().obj);
}
+ @FlakyTest
@Test
- @SmallTest
+ @Ignore
public void testEcbm() throws Exception {
ImsEcbmStateListener imsEcbmStateListener = mImsPhoneUT.getImsEcbmStateListener();
@@ -577,6 +579,7 @@
@FlakyTest
@Test
@SmallTest
+ @Ignore
public void testProcessDisconnectReason() throws Exception {
// set up CarrierConfig
PersistableBundle bundle = mContextFixture.getCarrierConfigBundle();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/InProgressCallSessionTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/InProgressCallSessionTest.java
index 612cae7..0e04da8 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/InProgressCallSessionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/InProgressCallSessionTest.java
@@ -18,8 +18,8 @@
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.internal.telephony.TelephonyProto;
import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.nano.TelephonyProto;
import org.junit.After;
import org.junit.Before;
@@ -72,6 +72,6 @@
}
assertTrue(mCallSession.isEventsDropped());
- assertEquals(2, mCallSession.events.getFirst().getRilRequestId());
+ assertEquals(2, mCallSession.events.getFirst().rilRequestId);
}
-}
\ No newline at end of file
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/InProgressSmsSessionTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/InProgressSmsSessionTest.java
index 710f003..b2b9ca5 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/InProgressSmsSessionTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/InProgressSmsSessionTest.java
@@ -18,8 +18,8 @@
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.internal.telephony.TelephonyProto;
import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.nano.TelephonyProto;
import org.junit.After;
import org.junit.Before;
@@ -68,7 +68,7 @@
}
assertTrue(mSmsSession.isEventsDropped());
- assertEquals(6, mSmsSession.events.getFirst().getRilRequestId());
+ assertEquals(6, mSmsSession.events.getFirst().rilRequestId);
}
// Test dropped event scenario
@@ -92,4 +92,4 @@
assertEquals(50, mSmsSession.getNumExpectedResponses());
}
-}
\ No newline at end of file
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
index e33a605..bd5785d 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/TelephonyMetricsTest.java
@@ -22,12 +22,12 @@
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_DEACTIVATE_DATA_CALL;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL;
-import static com.android.internal.telephony.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS;
+import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -47,21 +47,21 @@
import com.android.internal.telephony.GsmCdmaConnection;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.SmsResponse;
-import com.android.internal.telephony.TelephonyProto;
-import com.android.internal.telephony.TelephonyProto.ImsConnectionState;
-import com.android.internal.telephony.TelephonyProto.RadioAccessTechnology;
-import com.android.internal.telephony.TelephonyProto.SmsSession;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.CallState;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.ImsCommand;
-import com.android.internal.telephony.TelephonyProto.TelephonyCallSession.Event.RilCall;
-import com.android.internal.telephony.TelephonyProto.TelephonyEvent;
-import com.android.internal.telephony.TelephonyProto.TelephonyLog;
-import com.android.internal.telephony.TelephonyProto.TelephonyServiceState;
-import com.android.internal.telephony.TelephonyProto.TelephonyServiceState.RoamingType;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.UUSInfo;
import com.android.internal.telephony.dataconnection.DataCallResponse;
+import com.android.internal.telephony.nano.TelephonyProto;
+import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
+import com.android.internal.telephony.nano.TelephonyProto.RadioAccessTechnology;
+import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.CallState;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.ImsCommand;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession.Event.RilCall;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyEvent;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyLog;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState;
+import com.android.internal.telephony.nano.TelephonyProto.TelephonyServiceState.RoamingType;
import org.junit.After;
import org.junit.Before;
@@ -146,9 +146,8 @@
assertEquals(1000, log.events.length);
assertEquals(0, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
- assertTrue(log.hasEventsDropped());
- assertTrue(log.getEventsDropped());
- assertEquals(1, log.events[0].getDataStallAction());
+ assertTrue(log.eventsDropped);
+ assertEquals(1, log.events[0].dataStallAction);
}
// Test write data stall event
@@ -161,9 +160,23 @@
assertEquals(1, log.events.length);
assertEquals(0, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
- assertTrue(log.events[0].hasPhoneId());
- assertEquals(mPhone.getPhoneId(), log.events[0].getPhoneId());
- assertEquals(3, log.events[0].getDataStallAction());
+ assertEquals(mPhone.getPhoneId(), log.events[0].phoneId);
+ assertEquals(3, log.events[0].dataStallAction);
+ }
+
+ // Test write modem restart event
+ @Test
+ @SmallTest
+ public void testModemRestartEvent() throws Exception {
+ mMetrics.writeModemRestartEvent(mPhone.getPhoneId(), "Test");
+ TelephonyLog log = buildProto();
+
+ assertEquals(1, log.events.length);
+ assertEquals(0, log.callSessions.length);
+ assertEquals(0, log.smsSessions.length);
+
+ assertEquals(mPhone.getPhoneId(), log.events[0].phoneId);
+ assertEquals("Test", log.events[0].modemRestart.reason);
}
// Test write on IMS call start
@@ -177,16 +190,36 @@
assertEquals(0, log.events.length);
assertEquals(1, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
- assertTrue(log.callSessions[0].hasPhoneId());
- assertEquals(mPhone.getPhoneId(), log.callSessions[0].getPhoneId());
- assertTrue(log.callSessions[0].hasEventsDropped());
- assertFalse(log.callSessions[0].getEventsDropped());
- assertTrue(log.callSessions[0].hasStartTimeMinutes());
+
+ assertEquals(mPhone.getPhoneId(), log.callSessions[0].phoneId);
+
+ assertFalse(log.callSessions[0].eventsDropped);
+
assertEquals(1, log.callSessions[0].events.length);
- assertTrue(log.callSessions[0].events[0].hasCallIndex());
- assertEquals(123, log.callSessions[0].events[0].getCallIndex());
- assertTrue(log.callSessions[0].events[0].hasImsCommand());
- assertEquals(ImsCommand.IMS_CMD_START, log.callSessions[0].events[0].getImsCommand());
+
+ assertEquals(123, log.callSessions[0].events[0].callIndex);
+
+ assertEquals(ImsCommand.IMS_CMD_START, log.callSessions[0].events[0].imsCommand);
+ }
+
+ // Test write on IMS call received
+ @Test
+ @SmallTest
+ public void testWriteOnImsCallReceive() throws Exception {
+ mMetrics.writeOnImsCallReceive(mPhone.getPhoneId(), mImsCallSession);
+ mMetrics.writePhoneState(mPhone.getPhoneId(), PhoneConstants.State.IDLE);
+ TelephonyLog log = buildProto();
+
+ assertEquals(0, log.events.length);
+ assertEquals(1, log.callSessions.length);
+ assertEquals(0, log.smsSessions.length);
+ assertEquals(mPhone.getPhoneId(), log.callSessions[0].phoneId);
+
+ assertFalse(log.callSessions[0].eventsDropped);
+
+ assertEquals(1, log.callSessions[0].events.length);
+
+ assertEquals(123, log.callSessions[0].events[0].callIndex);
}
// Test write ims call state
@@ -202,12 +235,11 @@
assertEquals(1, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
assertEquals(2, log.callSessions[0].events.length);
- assertTrue(log.callSessions[0].hasEventsDropped());
- assertFalse(log.callSessions[0].getEventsDropped());
- assertTrue(log.callSessions[0].events[1].hasCallIndex());
- assertEquals(123, log.callSessions[0].events[1].getCallIndex());
- assertTrue(log.callSessions[0].events[1].hasCallState());
- assertEquals(CallState.CALL_ACTIVE, log.callSessions[0].events[1].getCallState());
+ assertFalse(log.callSessions[0].eventsDropped);
+
+ assertEquals(123, log.callSessions[0].events[1].callIndex);
+
+ assertEquals(CallState.CALL_ACTIVE, log.callSessions[0].events[1].callState);
}
// Test write ims set feature value
@@ -217,6 +249,8 @@
mMetrics.writeOnImsCallStart(mPhone.getPhoneId(), mImsCallSession);
mMetrics.writeImsSetFeatureValue(mPhone.getPhoneId(),
ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 0, 1, 0);
+ mMetrics.writeImsSetFeatureValue(mPhone.getPhoneId(),
+ ImsConfig.FeatureConstants.FEATURE_TYPE_VOICE_OVER_LTE, 0, 1, 0);
mMetrics.writePhoneState(mPhone.getPhoneId(), PhoneConstants.State.IDLE);
TelephonyLog log = buildProto();
@@ -224,10 +258,8 @@
assertEquals(1, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
assertEquals(2, log.callSessions[0].events.length);
- assertTrue(log.callSessions[0].hasEventsDropped());
- assertFalse(log.callSessions[0].getEventsDropped());
- assertTrue(log.callSessions[0].events[1].settings.hasIsEnhanced4GLteModeEnabled());
- assertTrue(log.callSessions[0].events[1].settings.getIsEnhanced4GLteModeEnabled());
+ assertFalse(log.callSessions[0].eventsDropped);
+ assertTrue(log.callSessions[0].events[1].settings.isEnhanced4GLteModeEnabled);
}
// Test write on ims call handover event
@@ -245,24 +277,16 @@
assertEquals(1, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
assertEquals(2, log.callSessions[0].events.length);
- assertTrue(log.callSessions[0].hasEventsDropped());
- assertFalse(log.callSessions[0].getEventsDropped());
- assertTrue(log.callSessions[0].events[1].hasType());
+ assertFalse(log.callSessions[0].eventsDropped);
assertEquals(TelephonyCallSession.Event.Type.IMS_CALL_HANDOVER,
- log.callSessions[0].events[1].getType());
- assertTrue(log.callSessions[0].events[1].hasCallIndex());
- assertEquals(123, log.callSessions[0].events[1].getCallIndex());
- assertTrue(log.callSessions[0].events[1].hasSrcAccessTech());
- assertEquals(5, log.callSessions[0].events[1].getSrcAccessTech());
- assertTrue(log.callSessions[0].events[1].hasTargetAccessTech());
- assertEquals(6, log.callSessions[0].events[1].getTargetAccessTech());
+ log.callSessions[0].events[1].type);
+ assertEquals(123, log.callSessions[0].events[1].callIndex);
+ assertEquals(5, log.callSessions[0].events[1].srcAccessTech);
+ assertEquals(6, log.callSessions[0].events[1].targetAccessTech);
- assertTrue(log.callSessions[0].events[1].reasonInfo.hasExtraMessage());
- assertEquals("extramessage", log.callSessions[0].events[1].reasonInfo.getExtraMessage());
- assertTrue(log.callSessions[0].events[1].reasonInfo.hasExtraCode());
- assertEquals(456, log.callSessions[0].events[1].reasonInfo.getExtraCode());
- assertTrue(log.callSessions[0].events[1].reasonInfo.hasReasonCode());
- assertEquals(123, log.callSessions[0].events[1].reasonInfo.getReasonCode());
+ assertEquals("extramessage", log.callSessions[0].events[1].reasonInfo.extraMessage);
+ assertEquals(456, log.callSessions[0].events[1].reasonInfo.extraCode);
+ assertEquals(123, log.callSessions[0].events[1].reasonInfo.reasonCode);
}
// Test write on ims command
@@ -278,15 +302,15 @@
assertEquals(1, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
assertEquals(2, log.callSessions[0].events.length);
- assertTrue(log.callSessions[0].hasEventsDropped());
- assertFalse(log.callSessions[0].getEventsDropped());
- assertTrue(log.callSessions[0].events[1].hasType());
+
+ assertFalse(log.callSessions[0].eventsDropped);
+
assertEquals(TelephonyCallSession.Event.Type.IMS_COMMAND,
- log.callSessions[0].events[1].getType());
- assertTrue(log.callSessions[0].events[1].hasImsCommand());
- assertEquals(123, log.callSessions[0].events[1].getImsCommand());
- assertTrue(log.callSessions[0].events[1].hasCallIndex());
- assertEquals(123, log.callSessions[0].events[1].getCallIndex());
+ log.callSessions[0].events[1].type);
+
+ assertEquals(123, log.callSessions[0].events[1].imsCommand);
+
+ assertEquals(123, log.callSessions[0].events[1].callIndex);
}
// Test write on ims connection state
@@ -296,6 +320,8 @@
mMetrics.writeOnImsCallStart(mPhone.getPhoneId(), mImsCallSession);
mMetrics.writeOnImsConnectionState(mPhone.getPhoneId(),
ImsConnectionState.State.CONNECTED, mImsReasonInfo);
+ mMetrics.writeOnImsConnectionState(mPhone.getPhoneId(),
+ ImsConnectionState.State.CONNECTED, mImsReasonInfo);
mMetrics.writePhoneState(mPhone.getPhoneId(), PhoneConstants.State.IDLE);
TelephonyLog log = buildProto();
@@ -303,27 +329,18 @@
assertEquals(1, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
assertEquals(2, log.callSessions[0].events.length);
- assertTrue(log.hasEventsDropped());
- assertFalse(log.getEventsDropped());
- assertTrue(log.events[0].hasType());
- assertEquals(TelephonyEvent.Type.IMS_CONNECTION_STATE_CHANGED, log.events[0].getType());
- assertTrue(log.events[0].imsConnectionState.hasState());
+ assertFalse(log.eventsDropped);
+ assertEquals(TelephonyEvent.Type.IMS_CONNECTION_STATE_CHANGED, log.events[0].type);
assertEquals(ImsConnectionState.State.CONNECTED,
- log.events[0].imsConnectionState.getState());
- assertTrue(log.events[0].imsConnectionState.reasonInfo.hasReasonCode());
- assertEquals(123, log.events[0].imsConnectionState.reasonInfo.getReasonCode());
- assertTrue(log.events[0].imsConnectionState.reasonInfo.hasExtraCode());
- assertEquals(456, log.events[0].imsConnectionState.reasonInfo.getExtraCode());
- assertTrue(log.events[0].imsConnectionState.reasonInfo.hasExtraMessage());
- assertEquals("extramessage", log.events[0].imsConnectionState.reasonInfo.getExtraMessage());
- assertTrue(log.callSessions[0].hasEventsDropped());
- assertFalse(log.callSessions[0].getEventsDropped());
- assertTrue(log.callSessions[0].events[1].hasType());
+ log.events[0].imsConnectionState.state);
+ assertEquals(123, log.events[0].imsConnectionState.reasonInfo.reasonCode);
+ assertEquals(456, log.events[0].imsConnectionState.reasonInfo.extraCode);
+ assertEquals("extramessage", log.events[0].imsConnectionState.reasonInfo.extraMessage);
+ assertFalse(log.callSessions[0].eventsDropped);
assertEquals(TelephonyCallSession.Event.Type.IMS_CONNECTION_STATE_CHANGED,
- log.callSessions[0].events[1].getType());
- assertTrue(log.callSessions[0].events[1].imsConnectionState.hasState());
+ log.callSessions[0].events[1].type);
assertEquals(ImsConnectionState.State.CONNECTED,
- log.callSessions[0].events[1].imsConnectionState.getState());
+ log.callSessions[0].events[1].imsConnectionState.state);
}
// Test write on setup data call response
@@ -340,21 +357,15 @@
assertEquals(1, log.events.length);
assertEquals(0, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
- assertTrue(log.hasEventsDropped());
- assertFalse(log.getEventsDropped());
+ assertFalse(log.eventsDropped);
TelephonyEvent.RilSetupDataCallResponse respProto = log.events[0].setupDataCallResponse;
- assertTrue(respProto.hasStatus());
- assertEquals(5, respProto.getStatus());
- assertTrue(respProto.hasSuggestedRetryTimeMillis());
- assertEquals(6, respProto.getSuggestedRetryTimeMillis());
- assertTrue(respProto.call.hasCid());
- assertEquals(7, respProto.call.getCid());
- assertTrue(respProto.call.hasType());
- assertEquals(PDP_TYPE_IPV4V6, respProto.call.getType());
- assertTrue(respProto.call.hasIframe());
- assertEquals(FAKE_IFNAME, respProto.call.getIframe());
+ assertEquals(5, respProto.status);
+ assertEquals(6, respProto.suggestedRetryTimeMillis);
+ assertEquals(7, respProto.call.cid);
+ assertEquals(PDP_TYPE_IPV4V6, respProto.call.type);
+ assertEquals(FAKE_IFNAME, respProto.call.iframe);
}
// Test write on deactivate data call response
@@ -368,13 +379,10 @@
assertEquals(1, log.events.length);
assertEquals(0, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
- assertTrue(log.hasEventsDropped());
- assertFalse(log.getEventsDropped());
+ assertFalse(log.eventsDropped);
- assertTrue(log.events[0].hasType());
- assertEquals(TelephonyEvent.Type.DATA_CALL_DEACTIVATE_RESPONSE, log.events[0].getType());
- assertTrue(log.events[0].hasError());
- assertEquals(4, log.events[0].getError());
+ assertEquals(TelephonyEvent.Type.DATA_CALL_DEACTIVATE_RESPONSE, log.events[0].type);
+ assertEquals(4, log.events[0].error);
}
// Test write RIL send SMS
@@ -396,46 +404,29 @@
assertEquals(0, log.events.length);
assertEquals(0, log.callSessions.length);
assertEquals(1, log.smsSessions.length);
- assertTrue(log.hasEventsDropped());
- assertFalse(log.getEventsDropped());
+ assertFalse(log.eventsDropped);
SmsSession.Event[] events = log.smsSessions[0].events;
assertEquals(4, events.length);
- assertTrue(events[0].hasType());
- assertEquals(SmsSession.Event.Type.SMS_SEND, events[0].getType());
- assertTrue(events[0].hasRilRequestId());
- assertEquals(1, events[0].getRilRequestId());
- assertTrue(events[0].hasTech());
- assertEquals(2, events[0].getTech());
- assertTrue(events[0].hasFormat());
- assertEquals(1, events[0].getFormat());
+ assertEquals(SmsSession.Event.Type.SMS_SEND, events[0].type);
+ assertEquals(1, events[0].rilRequestId);
+ assertEquals(2, events[0].tech);
+ assertEquals(1, events[0].format);
- assertTrue(events[1].hasType());
- assertEquals(SmsSession.Event.Type.SMS_SEND, events[1].getType());
- assertTrue(events[1].hasRilRequestId());
- assertEquals(4, events[1].getRilRequestId());
- assertTrue(events[1].hasTech());
- assertEquals(5, events[1].getTech());
- assertTrue(events[1].hasFormat());
- assertEquals(2, events[1].getFormat());
+ assertEquals(SmsSession.Event.Type.SMS_SEND, events[1].type);
+ assertEquals(4, events[1].rilRequestId);
+ assertEquals(5, events[1].tech);
+ assertEquals(2, events[1].format);
- assertTrue(events[2].hasType());
- assertEquals(SmsSession.Event.Type.SMS_SEND_RESULT, events[2].getType());
- assertTrue(events[2].hasRilRequestId());
- assertEquals(1, events[2].getRilRequestId());
- assertTrue(events[2].hasError());
- assertEquals(0, events[2].getError());
- assertTrue(events[2].hasErrorCode());
- assertEquals(123, events[2].getErrorCode());
+ assertEquals(SmsSession.Event.Type.SMS_SEND_RESULT, events[2].type);
+ assertEquals(1, events[2].rilRequestId);
+ assertEquals(1, events[2].error);
+ assertEquals(123, events[2].errorCode);
- assertTrue(events[3].hasType());
- assertEquals(SmsSession.Event.Type.SMS_SEND_RESULT, events[3].getType());
- assertTrue(events[3].hasRilRequestId());
- assertEquals(4, events[3].getRilRequestId());
- assertTrue(events[3].hasError());
- assertEquals(0, events[3].getError());
- assertTrue(events[3].hasErrorCode());
- assertEquals(456, events[3].getErrorCode());
+ assertEquals(SmsSession.Event.Type.SMS_SEND_RESULT, events[3].type);
+ assertEquals(4, events[3].rilRequestId);
+ assertEquals(1, events[3].error);
+ assertEquals(456, events[3].errorCode);
}
// Test write phone state
@@ -450,18 +441,14 @@
assertEquals(0, log.events.length);
assertEquals(1, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
- assertTrue(log.hasEventsDropped());
- assertFalse(log.getEventsDropped());
+ assertFalse(log.eventsDropped);
- assertTrue(log.callSessions[0].hasPhoneId());
- assertEquals(mPhone.getPhoneId(), log.callSessions[0].getPhoneId());
+ assertEquals(mPhone.getPhoneId(), log.callSessions[0].phoneId);
assertEquals(2, log.callSessions[0].events.length);
- assertTrue(log.callSessions[0].events[1].hasType());
assertEquals(TelephonyCallSession.Event.Type.PHONE_STATE_CHANGED,
- log.callSessions[0].events[1].getType());
- assertTrue(log.callSessions[0].events[1].hasPhoneState());
+ log.callSessions[0].events[1].type);
assertEquals(TelephonyCallSession.Event.PhoneState.STATE_OFFHOOK,
- log.callSessions[0].events[1].getPhoneState());
+ log.callSessions[0].events[1].phoneState);
}
// Test write RIL dial and hangup
@@ -478,29 +465,23 @@
assertEquals(0, log.events.length);
assertEquals(1, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
- assertTrue(log.hasEventsDropped());
- assertFalse(log.getEventsDropped());
+ assertFalse(log.eventsDropped);
TelephonyCallSession.Event[] events = log.callSessions[0].events;
assertEquals(2, events.length);
- assertTrue(events[0].hasType());
- assertEquals(TelephonyCallSession.Event.Type.RIL_REQUEST, events[0].getType());
- assertTrue(events[0].hasRilRequest());
- assertEquals(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL,
- events[0].getRilRequest());
- RilCall[] calls = events[0].calls;
- assertEquals(CallState.CALL_DIALING, calls[0].getState());
+ assertEquals(TelephonyCallSession.Event.Type.RIL_REQUEST, events[0].type);
- assertTrue(events[1].hasType());
- assertEquals(TelephonyCallSession.Event.Type.RIL_REQUEST, events[1].getType());
- assertTrue(events[1].hasRilRequest());
+ assertEquals(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_DIAL,
+ events[0].rilRequest);
+ RilCall[] calls = events[0].calls;
+ assertEquals(CallState.CALL_DIALING, calls[0].state);
+
assertEquals(TelephonyCallSession.Event.RilRequest.RIL_REQUEST_HANGUP,
- events[1].getRilRequest());
+ events[1].rilRequest);
calls = events[1].calls;
- assertTrue(calls[0].hasIndex());
- assertEquals(3, calls[0].getIndex());
- assertEquals(CallState.CALL_DISCONNECTED, calls[0].getState());
+ assertEquals(3, calls[0].index);
+ assertEquals(CallState.CALL_DISCONNECTED, calls[0].state);
}
// Test write RIL setup data call
@@ -515,21 +496,21 @@
assertEquals(1, log.events.length);
assertEquals(0, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
- assertTrue(log.hasEventsDropped());
- assertFalse(log.getEventsDropped());
- assertTrue(log.events[0].hasType());
- assertEquals(TelephonyEvent.Type.DATA_CALL_SETUP, log.events[0].getType());
+ assertFalse(log.eventsDropped);
+
+
+ assertEquals(TelephonyEvent.Type.DATA_CALL_SETUP, log.events[0].type);
TelephonyEvent.RilSetupDataCall setupDataCall = log.events[0].setupDataCall;
- assertTrue(setupDataCall.hasApn());
- assertEquals("apn", setupDataCall.getApn());
- assertTrue(setupDataCall.hasRat());
- assertEquals(14, setupDataCall.getRat());
- assertTrue(setupDataCall.hasDataProfile());
- assertEquals(4, setupDataCall.getDataProfile());
- assertTrue(setupDataCall.hasType());
- assertEquals(PDP_TYPE_IPV4V6, setupDataCall.getType());
+
+ assertEquals("apn", setupDataCall.apn);
+
+ assertEquals(14, setupDataCall.rat);
+
+ assertEquals(4, setupDataCall.dataProfile);
+
+ assertEquals(PDP_TYPE_IPV4V6, setupDataCall.type);
}
// Test write service state changed
@@ -537,39 +518,40 @@
@SmallTest
public void testWriteServiceStateChanged() throws Exception {
mMetrics.writeServiceStateChanged(mPhone.getPhoneId(), mServiceState);
+ mMetrics.writeServiceStateChanged(mPhone.getPhoneId(), mServiceState);
TelephonyLog log = buildProto();
assertEquals(1, log.events.length);
assertEquals(0, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
- assertTrue(log.hasEventsDropped());
- assertFalse(log.getEventsDropped());
+
+ assertFalse(log.eventsDropped);
TelephonyEvent event = log.events[0];
- assertTrue(event.hasType());
- assertEquals(TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED, event.getType());
+
+ assertEquals(TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED, event.type);
TelephonyServiceState state = event.serviceState;
- assertTrue(state.hasVoiceRat());
- assertEquals(RadioAccessTechnology.RAT_LTE, state.getVoiceRat());
- assertTrue(state.hasDataRat());
- assertEquals(RadioAccessTechnology.RAT_LTE, state.getDataRat());
- assertTrue(state.hasVoiceRoamingType());
- assertEquals(RoamingType.ROAMING_TYPE_DOMESTIC, state.getVoiceRoamingType());
- assertTrue(state.hasDataRoamingType());
- assertEquals(RoamingType.ROAMING_TYPE_DOMESTIC, state.getDataRoamingType());
- assertTrue(state.voiceOperator.hasAlphaLong());
- assertEquals("voicelong", state.voiceOperator.getAlphaLong());
- assertTrue(state.voiceOperator.hasAlphaShort());
- assertEquals("voiceshort", state.voiceOperator.getAlphaShort());
- assertTrue(state.voiceOperator.hasNumeric());
- assertEquals("123456", state.voiceOperator.getNumeric());
- assertTrue(state.dataOperator.hasAlphaLong());
- assertEquals("datalong", state.dataOperator.getAlphaLong());
- assertTrue(state.dataOperator.hasAlphaShort());
- assertEquals("datashort", state.dataOperator.getAlphaShort());
- assertTrue(state.dataOperator.hasNumeric());
- assertEquals("123456", state.dataOperator.getNumeric());
+
+ assertEquals(RadioAccessTechnology.RAT_LTE, state.voiceRat);
+
+ assertEquals(RadioAccessTechnology.RAT_LTE, state.dataRat);
+
+ assertEquals(RoamingType.ROAMING_TYPE_DOMESTIC, state.voiceRoamingType);
+
+ assertEquals(RoamingType.ROAMING_TYPE_DOMESTIC, state.dataRoamingType);
+
+ assertEquals("voicelong", state.voiceOperator.alphaLong);
+
+ assertEquals("voiceshort", state.voiceOperator.alphaShort);
+
+ assertEquals("123456", state.voiceOperator.numeric);
+
+ assertEquals("datalong", state.dataOperator.alphaLong);
+
+ assertEquals("datashort", state.dataOperator.alphaShort);
+
+ assertEquals("123456", state.dataOperator.numeric);
}
// Test reset scenario
@@ -583,34 +565,34 @@
assertEquals(1, log.events.length);
assertEquals(0, log.callSessions.length);
assertEquals(0, log.smsSessions.length);
- assertTrue(log.hasEventsDropped());
- assertFalse(log.getEventsDropped());
+
+ assertFalse(log.eventsDropped);
TelephonyEvent event = log.events[0];
- assertTrue(event.hasType());
- assertEquals(TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED, event.getType());
+
+ assertEquals(TelephonyEvent.Type.RIL_SERVICE_STATE_CHANGED, event.type);
TelephonyServiceState state = event.serviceState;
- assertTrue(state.hasVoiceRat());
- assertEquals(RadioAccessTechnology.RAT_LTE, state.getVoiceRat());
- assertTrue(state.hasDataRat());
- assertEquals(RadioAccessTechnology.RAT_LTE, state.getDataRat());
- assertTrue(state.hasVoiceRoamingType());
- assertEquals(RoamingType.ROAMING_TYPE_DOMESTIC, state.getVoiceRoamingType());
- assertTrue(state.hasDataRoamingType());
- assertEquals(RoamingType.ROAMING_TYPE_DOMESTIC, state.getDataRoamingType());
- assertTrue(state.voiceOperator.hasAlphaLong());
- assertEquals("voicelong", state.voiceOperator.getAlphaLong());
- assertTrue(state.voiceOperator.hasAlphaShort());
- assertEquals("voiceshort", state.voiceOperator.getAlphaShort());
- assertTrue(state.voiceOperator.hasNumeric());
- assertEquals("123456", state.voiceOperator.getNumeric());
- assertTrue(state.dataOperator.hasAlphaLong());
- assertEquals("datalong", state.dataOperator.getAlphaLong());
- assertTrue(state.dataOperator.hasAlphaShort());
- assertEquals("datashort", state.dataOperator.getAlphaShort());
- assertTrue(state.dataOperator.hasNumeric());
- assertEquals("123456", state.dataOperator.getNumeric());
+
+ assertEquals(RadioAccessTechnology.RAT_LTE, state.voiceRat);
+
+ assertEquals(RadioAccessTechnology.RAT_LTE, state.dataRat);
+
+ assertEquals(RoamingType.ROAMING_TYPE_DOMESTIC, state.voiceRoamingType);
+
+ assertEquals(RoamingType.ROAMING_TYPE_DOMESTIC, state.dataRoamingType);
+
+ assertEquals("voicelong", state.voiceOperator.alphaLong);
+
+ assertEquals("voiceshort", state.voiceOperator.alphaShort);
+
+ assertEquals("123456", state.voiceOperator.numeric);
+
+ assertEquals("datalong", state.dataOperator.alphaLong);
+
+ assertEquals("datashort", state.dataOperator.alphaShort);
+
+ assertEquals("123456", state.dataOperator.numeric);
}
// Test Proto Encoding/Decoding
@@ -624,4 +606,42 @@
byte[] decodedString = Base64.decode(encodedString, Base64.DEFAULT);
assertArrayEquals(TelephonyProto.TelephonyLog.toByteArray(log), decodedString);
}
+
+ // Test write ims capabilities changed
+ @Test
+ @SmallTest
+ public void testWriteOnImsCapabilities() throws Exception {
+ boolean[] caps1 = new boolean[]{true, false, true, false, true, false};
+ mMetrics.writeOnImsCapabilities(mPhone.getPhoneId(), caps1);
+ boolean[] caps2 = new boolean[]{true, false, true, false, true, false};
+ // The duplicate one should be filtered out.
+ mMetrics.writeOnImsCapabilities(mPhone.getPhoneId(), caps2);
+ boolean[] caps3 = new boolean[]{false, true, false, true, false, true};
+ mMetrics.writeOnImsCapabilities(mPhone.getPhoneId(), caps3);
+ TelephonyLog log = buildProto();
+
+ assertEquals(2, log.events.length);
+ assertEquals(0, log.callSessions.length);
+ assertEquals(0, log.smsSessions.length);
+
+ TelephonyEvent event = log.events[0];
+
+ assertEquals(TelephonyEvent.Type.IMS_CAPABILITIES_CHANGED, event.type);
+ assertEquals(caps1[0], event.imsCapabilities.voiceOverLte);
+ assertEquals(caps1[1], event.imsCapabilities.videoOverLte);
+ assertEquals(caps1[2], event.imsCapabilities.voiceOverWifi);
+ assertEquals(caps1[3], event.imsCapabilities.videoOverWifi);
+ assertEquals(caps1[4], event.imsCapabilities.utOverLte);
+ assertEquals(caps1[5], event.imsCapabilities.utOverWifi);
+
+ event = log.events[1];
+
+ assertEquals(TelephonyEvent.Type.IMS_CAPABILITIES_CHANGED, event.type);
+ assertEquals(caps3[0], event.imsCapabilities.voiceOverLte);
+ assertEquals(caps3[1], event.imsCapabilities.videoOverLte);
+ assertEquals(caps3[2], event.imsCapabilities.voiceOverWifi);
+ assertEquals(caps3[3], event.imsCapabilities.videoOverWifi);
+ assertEquals(caps3[4], event.imsCapabilities.utOverLte);
+ assertEquals(caps3[5], event.imsCapabilities.utOverWifi);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
index acab717..82a3466 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/ConnectivityServiceMock.java
@@ -127,6 +127,9 @@
public void die() {
// clean up threads/handlers
+ if (mHandlerThread != null) {
+ mHandlerThread.quit();
+ }
}
private class InternalHandler extends Handler {
@@ -518,6 +521,10 @@
throw new RuntimeException("not implemented");
}
+ public void startCaptivePortalApp(Network network) {
+ throw new RuntimeException("not implemented");
+ }
+
public int getMultipathPreference(Network network) {
throw new RuntimeException("not implemented");
}
@@ -644,6 +651,11 @@
}
@Override
+ public boolean isAlwaysOnVpnPackageSupported(int userId, String packageName) {
+ throw new RuntimeException("not implemented");
+ }
+
+ @Override
public boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdownEnabled) {
throw new RuntimeException("not implemented");
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
index 11b1a81..504b4e1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/DcTrackerMock.java
@@ -61,10 +61,6 @@
throw new RuntimeException("Not Implemented");
}
@Override
- public boolean isDataPossible(String apnType) {
- throw new RuntimeException("Not Implemented");
- }
- @Override
public LinkProperties getLinkProperties(String apnType) {
throw new RuntimeException("Not Implemented");
}
@@ -89,10 +85,6 @@
throw new RuntimeException("Not Implemented");
}
@Override
- public boolean getAnyDataEnabled() {
- throw new RuntimeException("Not Implemented");
- }
- @Override
public boolean hasMatchedTetherApnSetting() {
throw new RuntimeException("Not Implemented");
}
@@ -105,7 +97,7 @@
throw new RuntimeException("Not Implemented");
}
@Override
- public void setDataRoamingEnabled(boolean enabled) {
+ public void setDataRoamingEnabledByUser(boolean enabled) {
throw new RuntimeException("Not Implemented");
}
@Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/OWNERS b/tests/telephonytests/src/com/android/internal/telephony/mocks/OWNERS
new file mode 100644
index 0000000..909c9bb
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/OWNERS
@@ -0,0 +1,13 @@
+# Re-list all owners appearing in the root OWNERS file for this project
+# This allows adding new owners for specific files using the per-file rule.
+per-file *=amitmahajan@google.com
+per-file *=breadley@google.com
+per-file *=fionaxu@google.com
+per-file *=jackyu@google.com
+per-file *=jsh@google.com
+per-file *=rgreenwalt@google.com
+per-file *=tgunn@google.com
+
+per-file ConnectivityServiceMock.java=ek@google.com
+per-file ConnectivityServiceMock.java=hugobenichi@google.com
+per-file ConnectivityServiceMock.java=lorenzo@google.com
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
index 68b9b11..0d19f47 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/PhoneMock.java
@@ -17,21 +17,21 @@
package com.android.internal.telephony;
import android.content.Context;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
-import android.os.Messenger;
import android.os.Registrant;
import android.os.RegistrantList;
import android.os.ResultReceiver;
import android.os.WorkSource;
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
import android.service.carrier.CarrierIdentifier;
import android.telephony.CellInfo;
import android.telephony.CellLocation;
import android.telephony.DataConnectionRealTimeInfo;
+import android.telephony.NetworkScanRequest;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.VoLteServiceState;
@@ -802,11 +802,7 @@
throw new RuntimeException("not implemented");
}
- public boolean isDataConnectivityPossible() {
- throw new RuntimeException("not implemented");
- }
-
- public boolean isDataConnectivityPossible(String apnType) {
+ public boolean isDataAllowed() {
throw new RuntimeException("not implemented");
}
@@ -1240,6 +1236,14 @@
throw new RuntimeException("not implemented");
}
+ public void startNetworkScan(NetworkScanRequest nsr, Message response) {
+ throw new RuntimeException("not implemented");
+ }
+
+ public void stopNetworkScan(Message response) {
+ throw new RuntimeException("not implemented");
+ }
+
public void getNeighboringCids(Message response) {
throw new RuntimeException("not implemented");
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
index 3a89927..60995a1 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/SubscriptionControllerMock.java
@@ -243,12 +243,8 @@
throw new RuntimeException("not implemented");
}
@Override
- public int[] getSubIdUsingSlotIndex(int slotIndex) {
- return getSubId(slotIndex);
- }
- @Override
- public List<SubscriptionInfo> getSubInfoUsingSlotIndexWithCheck(int slotIndex, boolean needCheck,
- String callingPackage) {
+ public List<SubscriptionInfo> getSubInfoUsingSlotIndexWithCheck(int slotId, boolean needCheck,
+ String callingPackage) {
throw new RuntimeException("not implemented");
}
@Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccCardProxyTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccCardProxyTest.java
new file mode 100644
index 0000000..e4795fa
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccCardProxyTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.uicc;
+
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.support.test.filters.FlakyTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.IccCardConstants.State;
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
+import com.android.internal.telephony.uicc.IccCardStatus.CardState;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mock;
+
+public class IccCardProxyTest extends TelephonyTest {
+ private IccCardProxy mIccCardProxyUT;
+ // private UiccCard mUiccCard;
+ private IccCardProxyHandlerThread mIccCardProxyHandlerThread;
+ private static final int PHONE_ID = 0;
+ private static final int PHONE_COUNT = 1;
+
+ private static final int SCARY_SLEEP_MS = 200;
+ // Must match IccCardProxy.EVENT_ICC_CHANGED
+ private static final int EVENT_ICC_CHANGED = 3;
+
+ @Mock private Handler mMockedHandler;
+ @Mock private IccCardStatus mIccCardStatus;
+ @Mock private UiccCard mUiccCard;
+ @Mock private UiccCardApplication mUiccCardApplication;
+
+ private class IccCardProxyHandlerThread extends HandlerThread {
+
+ private IccCardProxyHandlerThread(String name) {
+ super(name);
+ }
+
+ @Override
+ public void onLooperPrepared() {
+ /* create a new UICC Controller associated with the simulated Commands */
+ mIccCardProxyUT = new IccCardProxy(mContext, mSimulatedCommands, PHONE_ID);
+ setReady(true);
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(this.getClass().getSimpleName());
+ doReturn(PHONE_COUNT).when(mTelephonyManager).getPhoneCount();
+ doReturn(PHONE_COUNT).when(mTelephonyManager).getSimCount();
+ mSimulatedCommands.setIccCardStatus(mIccCardStatus);
+ mIccCardProxyHandlerThread = new IccCardProxyHandlerThread(TAG);
+ mIccCardProxyHandlerThread.start();
+ waitUntilReady();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mIccCardProxyHandlerThread.quitSafely();
+ super.tearDown();
+ }
+
+ @Test
+ @SmallTest
+ public void testInitialCardState() {
+ assertEquals(mIccCardProxyUT.getState(), State.UNKNOWN);
+ }
+
+ @Test
+ @SmallTest
+ public void testPowerOn() {
+ mSimulatedCommands.setRadioPower(true, null);
+ mSimulatedCommands.notifyRadioOn();
+ when(mUiccController.getUiccCard(anyInt())).thenReturn(mUiccCard);
+ mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
+ waitForMs(SCARY_SLEEP_MS);
+ assertEquals(CommandsInterface.RadioState.RADIO_ON, mSimulatedCommands.getRadioState());
+ assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
+ logd("IccCardProxy state = " + mIccCardProxyUT.getState());
+ }
+
+ @Test
+ @SmallTest
+ public void testCardLoaded() {
+ testPowerOn();
+ when(mUiccCard.getCardState()).thenReturn(CardState.CARDSTATE_PRESENT);
+ mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
+ waitForMs(SCARY_SLEEP_MS);
+ assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
+ }
+
+ @Test
+ @SmallTest
+ public void testAppNotLoaded() {
+ testPowerOn();
+ when(mUiccCard.getCardState()).thenReturn(CardState.CARDSTATE_PRESENT);
+ mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
+ when(mUiccCardApplication.getState()).thenReturn(AppState.APPSTATE_UNKNOWN);
+ when(mUiccCard.getApplication(anyInt())).thenReturn(mUiccCardApplication);
+
+ waitForMs(SCARY_SLEEP_MS);
+ assertEquals(mIccCardProxyUT.getState(), State.NOT_READY);
+ }
+
+ @Test
+ @Ignore
+ @FlakyTest
+ @SmallTest
+ public void testAppReady() {
+ testPowerOn();
+ when(mUiccCard.getCardState()).thenReturn(CardState.CARDSTATE_PRESENT);
+ mIccCardProxyUT.sendMessage(mIccCardProxyUT.obtainMessage(EVENT_ICC_CHANGED));
+ when(mUiccCardApplication.getState()).thenReturn(AppState.APPSTATE_READY);
+ when(mUiccCard.getApplication(anyInt())).thenReturn(mUiccCardApplication);
+
+ waitForMs(SCARY_SLEEP_MS);
+ assertEquals(mIccCardProxyUT.getState(), State.READY);
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
index c99bd75..9510619 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/IccPhoneBookInterfaceManagerTest.java
@@ -89,7 +89,7 @@
@After
public void tearDown() throws Exception {
- mIccPhoneBookInterfaceManagerHandler.quitSafely();
+ mIccPhoneBookInterfaceManagerHandler.quit();
super.tearDown();
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardApplicationTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardApplicationTest.java
index 1a5daeb..60f5f6f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardApplicationTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardApplicationTest.java
@@ -110,7 +110,7 @@
@After
public void tearDown() throws Exception {
- mTestHandlerThread.quitSafely();
+ mTestHandlerThread.quit();
super.tearDown();
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
index 9a24a86..a7c3c48 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCardTest.java
@@ -15,26 +15,33 @@
*/
package com.android.internal.telephony.uicc;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Message;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.android.internal.telephony.TelephonyTest;
-import com.android.internal.telephony.cat.CatService;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import static org.mockito.Mockito.*;
+import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.isA;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.telephony.TelephonyTest;
+import com.android.internal.telephony.cat.CatService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
public class UiccCardTest extends TelephonyTest {
private UiccCard mUicccard;
@@ -69,7 +76,7 @@
@Override
public void onLooperPrepared() {
mUicccard = new UiccCard(mContextFixture.getTestDouble(),
- mSimulatedCommands, mIccCardStatus);
+ mSimulatedCommands, mIccCardStatus, 0 /* phoneId */);
/* create a custom handler for the Handler Thread */
mHandler = new Handler(mTestHandlerThread.getLooper()) {
@Override
@@ -134,7 +141,7 @@
@After
public void tearDown() throws Exception {
- mTestHandlerThread.quitSafely();
+ mTestHandlerThread.quit();
super.tearDown();
}
@@ -201,9 +208,9 @@
waitForMs(50);
assertTrue(mUicccard.areCarrierPriviligeRulesLoaded());
- verify(mSimulatedCommandsVerifier, times(1)).iccOpenLogicalChannel(isA(String.class),
+ verify(mSimulatedCommandsVerifier, times(2)).iccOpenLogicalChannel(isA(String.class),
anyInt(), isA(Message.class));
- verify(mSimulatedCommandsVerifier, times(1)).iccTransmitApduLogicalChannel(
+ verify(mSimulatedCommandsVerifier, times(2)).iccTransmitApduLogicalChannel(
eq(mChannelId), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyString(),
isA(Message.class)
);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
new file mode 100644
index 0000000..8bb5d8c
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccCarrierPrivilegeRulesTest.java
@@ -0,0 +1,620 @@
+/*
+ * 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.uicc;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.doAnswer;
+
+import android.content.pm.Signature;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.telephony.TelephonyTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class UiccCarrierPrivilegeRulesTest extends TelephonyTest {
+ private UiccCarrierPrivilegeRules mUiccCarrierPrivilegeRules;
+ public UiccCarrierPrivilegeRulesTest() {
+ super();
+ }
+ private UiccCarrierPrivilegeRulesHandlerThread mTestHandlerThread;
+ private Handler mHandler;
+
+ private static final int EVENT_OPEN_LOGICAL_CHANNEL_DONE = 1;
+ private static final int EVENT_TEST_DONE = 2;
+
+ @Mock
+ private UiccCard mUiccCard;
+
+ private class UiccCarrierPrivilegeRulesHandlerThread extends HandlerThread {
+
+ private UiccCarrierPrivilegeRulesHandlerThread(String name) {
+ super(name);
+ }
+
+ @Override
+ public void onLooperPrepared() {
+ /* create a custom handler for the Handler Thread */
+ mHandler = new Handler(mTestHandlerThread.getLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_OPEN_LOGICAL_CHANNEL_DONE:
+ /* Upon handling this event, new CarrierPrivilegeRule
+ will be created with the looper of HandlerThread */
+ mUiccCarrierPrivilegeRules = new UiccCarrierPrivilegeRules(
+ mUiccCard, mHandler.obtainMessage(EVENT_TEST_DONE));
+ break;
+ case EVENT_TEST_DONE:
+ setReady(true);
+ break;
+ default:
+ logd("Unknown Event " + msg.what);
+ }
+ }
+ };
+ setReady(true);
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp(getClass().getSimpleName());
+ mTestHandlerThread = new UiccCarrierPrivilegeRulesHandlerThread(TAG);
+ mTestHandlerThread.start();
+
+ waitUntilReady();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mTestHandlerThread.quit();
+ super.tearDown();
+ mUiccCarrierPrivilegeRules = null;
+ }
+
+ private void testHelper(String hexString) {
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[2];
+ AsyncResult ar = new AsyncResult(null, new int[]{0}, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ anyInt(), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+ }
+
+ @Test
+ @SmallTest
+ public void testParseRule_Normal() {
+ /**
+ * FF40 45
+ * E2 43
+ * E1 35
+ * C1 14 ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4
+ * CA 1D 636F6D2E676F6F676C652E616E64726F69642E617070732E6D79617070
+ * E3 0A
+ * DB 08 0000000000000001
+ */
+ final String hexString =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001";
+
+ testHelper(hexString);
+
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(2, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0));
+ Signature signature = new Signature("abcd92cbb156b280fa4e1429a6eceeb6e5c1bfe4");
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+ }
+
+ @Test
+ @SmallTest
+ public void testParseRule_With4FD0D1() {
+ /**
+ * FF40 34
+ * E2 32
+ * E1 1E
+ * 4F 06 FF FF FF FF FF FF
+ * C1 14 B6 1B E3 4A D2 C2 0D 7A FE D8 49 3C 31 3A 13 7F 89 FA 27 65
+ * E3 10
+ * D0 01 01
+ * D1 01 01
+ * DB 08 00 00 00 00 00 00 00 01
+ */
+ final String hexString = "FF4034E232E11E4F06FFFFFFFFFFFFC114B61BE34AD2C20D7AFED84"
+ + "93C313A137F89FA2765E310D00101D10101DB080000000000000001";
+
+ testHelper(hexString);
+
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(0, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ }
+
+ @Test
+ @SmallTest
+ public void testParseRule_With4FD0() {
+ /**
+ * FF40 31
+ * E2 2F
+ * E1 1E
+ * 4F 06 FF FF FF FF FF FF
+ * C1 14 B6 1B E3 4A D2 C2 0D 7A FE D8 49 3C 31 3A 13 7F 89 FA 27 65
+ * E3 0D
+ * D0 01 01
+ * DB 08 00 00 00 00 00 00 00 01
+ */
+ final String hexString = "FF4031E22FE11E4F06FFFFFFFFFFFFC114B61BE34AD2C20D7AFED8493C313A"
+ + "137F89FA2765E30DD00101DB080000000000000001";
+
+ testHelper(hexString);
+
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(0, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ }
+
+ @Test
+ @SmallTest
+ public void testParseRule_TwoMessages() {
+ /**
+ * FF40 68
+ * E2 39
+ * E1 2B
+ * 4F 06 FFFFFFFFFFFF
+ * C1 02 B61B
+ * CA 1D 636F6D2E676F6F676C652E616E64726F69642E617070732E6D79617070
+ * E3 0A
+ * D0 01 01
+ * D1 01 01
+ * DB 02 0001
+ * E2 2B
+ * E1 23
+ * C1 02 ABCD
+ * CA 1D 636F6D2E676F6F676C652E616E64726F69642E617070732E6D79617070
+ * E3 04
+ * DB 02 0001
+ */
+ final String hexString =
+ "FF4068E239E12B4F06FFFFFFFFFFFFC102B61BCA1D636F6D2E676F6F676C652E616E64726F69642"
+ + "E617070732E6D79617070E30AD00101D10101DB020001E22BE123C102ABCDCA1D636F"
+ + "6D2E676F6F676C652E616E64726F69642E617070732E6D79617070E304DB020001";
+
+ testHelper(hexString);
+
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(4, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0));
+ Signature signature1 = new Signature("b61b");
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature1,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(1));
+ Signature signature2 = new Signature("abcd");
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature2,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+ }
+
+ @Test
+ @SmallTest
+ public void testParseRule_InvalidRulesWith4F00() {
+ /**
+ * FF40 24
+ * E2 22
+ * E1 18
+ * 4F 00
+ * C1 14 75C073AFD219AEB221948E828F066E778ADFDF23
+ * E3 06
+ * D0 01 01
+ * D1 01 01
+ */
+ final String hexString = "FF4024E222E1184F00C11475C073AFD219AEB221948E828F066E778ADFDF23"
+ + "E306D00101D10101";
+
+ testHelper(hexString);
+
+ assertTrue(!mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(0, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ }
+
+ @Test
+ @SmallTest
+ public void testParseRule_InvalidRulesWithoutDB() {
+ /**
+ * FF40 2A
+ * E2 28
+ * E1 1E
+ * 4F 06 FF FF FF FF FF FF
+ * C1 14 B6 1B E3 4A D2 C2 0D 7A FE D8 49 3C 31 3A 13 7F 89 FA 27 65
+ * E3 06
+ * D0 01 01
+ * D1 01 01
+ */
+ final String hexString = "FF402AE228E11E4F06FFFFFFFFFFFFC114B61BE34AD2C20D7AFED8493C313A"
+ + "137F89FA2765E306D00101D10101";
+
+ testHelper(hexString);
+
+ assertTrue(!mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(0, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ }
+
+ private static final String ARAM = "A00000015141434C00";
+ private static final String ARAD = "A00000015144414300";
+ private static final String PKCS15_AID = "A000000063504B43532D3135";
+
+ @Test
+ @SmallTest
+ public void testAID_OnlyARAM() {
+ final String hexString =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001";
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String aid = (String) invocation.getArguments()[0];
+ Message message = (Message) invocation.getArguments()[2];
+ if (aid.equals(ARAM)) {
+ AsyncResult ar = new AsyncResult(null, new int[]{0}, null);
+ message.obj = ar;
+ message.arg2 = 1;
+ message.sendToTarget();
+ } else {
+ AsyncResult ar = new AsyncResult(null, null, null);
+ message.obj = ar;
+ message.sendToTarget();
+ }
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ anyInt(), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(1, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0));
+ Signature signature = new Signature("abcd92cbb156b280fa4e1429a6eceeb6e5c1bfe4");
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+ }
+
+ @Test
+ @SmallTest
+ public void testAID_OnlyARAD() {
+ final String hexString =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001";
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String aid = (String) invocation.getArguments()[0];
+ Message message = (Message) invocation.getArguments()[2];
+ if (aid.equals(ARAD)) {
+ AsyncResult ar = new AsyncResult(null, new int[]{0}, null);
+ message.obj = ar;
+ message.arg2 = 0;
+ message.sendToTarget();
+ } else {
+ AsyncResult ar = new AsyncResult(null, null, null);
+ message.obj = ar;
+ message.arg2 = 1;
+ message.sendToTarget();
+ }
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ anyInt(), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(1, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0));
+ Signature signature = new Signature("abcd92cbb156b280fa4e1429a6eceeb6e5c1bfe4");
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+ }
+
+ @Test
+ @SmallTest
+ public void testAID_BothARAMandARAD() {
+ final String hexString =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001";
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String aid = (String) invocation.getArguments()[0];
+ Message message = (Message) invocation.getArguments()[2];
+ AsyncResult ar = new AsyncResult(null, new int[]{0}, null);
+ message.obj = ar;
+ if (aid.equals(ARAD)) {
+ message.arg2 = 0;
+ } else {
+ message.arg2 = 1;
+ }
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00, IccUtils.hexStringToBytes(hexString));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ anyInt(), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+
+ Signature signature = new Signature("abcd92cbb156b280fa4e1429a6eceeb6e5c1bfe4");
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(2, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0));
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(1));
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(1)));
+ }
+
+ @Test
+ @SmallTest
+ public void testAID_NeitherARAMorARAD() {
+ final String hexString =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30ADB080000000000000001";
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String aid = (String) invocation.getArguments()[0];
+ Message message = (Message) invocation.getArguments()[2];
+ AsyncResult ar = new AsyncResult(null, null, null);
+ if (aid.equals(ARAM)) {
+ message.arg2 = 1;
+ } else if (aid.equals(ARAD)) {
+ message.arg2 = 0;
+ } else {
+ // PKCS15
+ ar = new AsyncResult(null, null, new Throwable());
+ }
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+
+ assertTrue(!mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ }
+
+ private static final int P2 = 0x40;
+ private static final int P2_EXTENDED_DATA = 0x60;
+ @Test
+ @SmallTest
+ public void testAID_RetransmitLogicalChannel() {
+ final String hexString1 =
+ "FF4045E243E135C114ABCD92CBB156B280FA4E1429A6ECEEB6E5C1BFE4CA1D636F6D2E676F6F676"
+ + "C652E616E64726F69642E617070732E6D79617070E30A";
+
+ final String hexString2 =
+ "DB080000000000000001";
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ String aid = (String) invocation.getArguments()[0];
+ Message message = (Message) invocation.getArguments()[2];
+ if (aid.equals(ARAD)) {
+ AsyncResult ar = new AsyncResult(null, new int[]{0}, null);
+ message.obj = ar;
+ message.arg2 = 0;
+ message.sendToTarget();
+ } else {
+ AsyncResult ar = new AsyncResult(null, null, null);
+ message.obj = ar;
+ message.arg2 = 1;
+ message.sendToTarget();
+ }
+ return null;
+ }
+ }).when(mUiccCard).iccOpenLogicalChannel(anyString(), anyInt(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00,
+ IccUtils.hexStringToBytes(hexString1));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ eq(P2), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[7];
+ IccIoResult iir = new IccIoResult(0x90, 0x00,
+ IccUtils.hexStringToBytes(hexString2));
+ AsyncResult ar = new AsyncResult(null, iir, null);
+ message.obj = ar;
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccTransmitApduLogicalChannel(anyInt(), anyInt(), anyInt(), anyInt(),
+ eq(P2_EXTENDED_DATA), anyInt(), anyString(), any(Message.class));
+
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Message message = (Message) invocation.getArguments()[1];
+ message.sendToTarget();
+ return null;
+ }
+ }).when(mUiccCard).iccCloseLogicalChannel(anyInt(), any(Message.class));
+
+
+ Message mCardOpenLogicalChannel = mHandler.obtainMessage(EVENT_OPEN_LOGICAL_CHANNEL_DONE);
+ setReady(false);
+ mCardOpenLogicalChannel.sendToTarget();
+ waitUntilReady();
+
+ assertTrue(mUiccCarrierPrivilegeRules.hasCarrierPrivilegeRules());
+ assertEquals(1, mUiccCarrierPrivilegeRules.getPackageNames().size());
+ assertEquals("com.google.android.apps.myapp",
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0));
+ Signature signature = new Signature("abcd92cbb156b280fa4e1429a6eceeb6e5c1bfe4");
+ assertEquals(0, mUiccCarrierPrivilegeRules.getCarrierPrivilegeStatus(signature,
+ mUiccCarrierPrivilegeRules.getPackageNames().get(0)));
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
index 12c2690..e62700a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccControllerTest.java
@@ -96,7 +96,7 @@
@After
public void tearDown() throws Exception {
- mUiccControllerHandlerThread.quitSafely();
+ mUiccControllerHandlerThread.quit();
super.tearDown();
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java
index fb48619..2f44b0a 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java
@@ -16,6 +16,16 @@
package com.android.internal.telephony.uicc;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
@@ -35,15 +45,6 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyObject;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
public class UiccStateChangedLauncherTest extends TelephonyTest {
private static final String TAG = UiccStateChangedLauncherTest.class.getName();
@@ -101,7 +102,7 @@
// The first broadcast should be sent after initialization.
UiccCard[] cards = new UiccCard[CARD_COUNT];
cards[0] = new UiccCard(mContext, mSimulatedCommands,
- makeCardStatus(CardState.CARDSTATE_PRESENT));
+ makeCardStatus(CardState.CARDSTATE_PRESENT), 0 /* phoneId */);
when(UiccController.getInstance().getUiccCards()).thenReturn(cards);
uiccLauncher.handleMessage(msg);