diff options
44 files changed, 3800 insertions, 229 deletions
@@ -341,6 +341,7 @@ LOCAL_SRC_FILES += \ telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \ telephony/java/com/android/internal/telephony/ISms.aidl \ telephony/java/com/android/internal/telephony/IWapPushManager.aidl \ + telephony/java/com/android/internal/telephony/ISub.aidl \ wifi/java/android/net/wifi/IWifiManager.aidl \ wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \ wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \ diff --git a/CleanSpec.mk b/CleanSpec.mk index 5b027b3..5d92792 100644 --- a/CleanSpec.mk +++ b/CleanSpec.mk @@ -193,6 +193,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/app) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/android/app/wearable) $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates/src/core/java/android/tv/ITv*) +$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework-base_intermediates) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 3fe0fb8..2a5e9fd 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -6547,6 +6547,53 @@ public final class Settings { public static boolean putFloat(ContentResolver cr, String name, float value) { return putString(cr, name, Float.toString(value)); } + + + /** + * Subscription to be used for voice call on a multi sim device. The supported values + * are 0 = SUB1, 1 = SUB2 and etc. + * @hide + */ + public static final String MULTI_SIM_VOICE_CALL_SUBSCRIPTION = "multi_sim_voice_call"; + + /** + * Used to provide option to user to select subscription during dial. + * The supported values are 0 = disable or 1 = enable prompt. + * @hide + */ + public static final String MULTI_SIM_VOICE_PROMPT = "multi_sim_voice_prompt"; + + /** + * Subscription to be used for data call on a multi sim device. The supported values + * are 0 = SUB1, 1 = SUB2 and etc. + * @hide + */ + public static final String MULTI_SIM_DATA_CALL_SUBSCRIPTION = "multi_sim_data_call"; + + /** + * Subscription to be used for SMS on a multi sim device. The supported values + * are 0 = SUB1, 1 = SUB2 and etc. + * @hide + */ + public static final String MULTI_SIM_SMS_SUBSCRIPTION = "multi_sim_sms"; + + /** + * Used to provide option to user to select subscription during send SMS. + * The value 1 - enable, 0 - disable + * @hide + */ + public static final String MULTI_SIM_SMS_PROMPT = "multi_sim_sms_prompt"; + + + + /** User preferred subscriptions setting. + * This holds the details of the user selected subscription from the card and + * the activation status. Each settings string have the coma separated values + * iccId,appType,appId,activationStatus,3gppIndex,3gpp2Index + * @hide + */ + public static final String[] MULTI_SIM_USER_PREFERRED_SUBS = {"user_preferred_sub1", + "user_preferred_sub2","user_preferred_sub3"}; } /** diff --git a/core/res/res/drawable-hdpi/sim_dark_blue.9.png b/core/res/res/drawable-hdpi/sim_dark_blue.9.png Binary files differnew file mode 100755 index 0000000..b991535 --- /dev/null +++ b/core/res/res/drawable-hdpi/sim_dark_blue.9.png diff --git a/core/res/res/drawable-hdpi/sim_dark_green.9.png b/core/res/res/drawable-hdpi/sim_dark_green.9.png Binary files differnew file mode 100755 index 0000000..c8de61d --- /dev/null +++ b/core/res/res/drawable-hdpi/sim_dark_green.9.png diff --git a/core/res/res/drawable-hdpi/sim_dark_orange.9.png b/core/res/res/drawable-hdpi/sim_dark_orange.9.png Binary files differnew file mode 100755 index 0000000..10347e8 --- /dev/null +++ b/core/res/res/drawable-hdpi/sim_dark_orange.9.png diff --git a/core/res/res/drawable-hdpi/sim_dark_purple.9.png b/core/res/res/drawable-hdpi/sim_dark_purple.9.png Binary files differnew file mode 100755 index 0000000..ac4ee01 --- /dev/null +++ b/core/res/res/drawable-hdpi/sim_dark_purple.9.png diff --git a/core/res/res/drawable-hdpi/sim_light_blue.9.png b/core/res/res/drawable-hdpi/sim_light_blue.9.png Binary files differnew file mode 100755 index 0000000..b2c5581 --- /dev/null +++ b/core/res/res/drawable-hdpi/sim_light_blue.9.png diff --git a/core/res/res/drawable-hdpi/sim_light_green.9.png b/core/res/res/drawable-hdpi/sim_light_green.9.png Binary files differnew file mode 100755 index 0000000..4d29c81 --- /dev/null +++ b/core/res/res/drawable-hdpi/sim_light_green.9.png diff --git a/core/res/res/drawable-hdpi/sim_light_orange.9.png b/core/res/res/drawable-hdpi/sim_light_orange.9.png Binary files differnew file mode 100755 index 0000000..68c6c2f --- /dev/null +++ b/core/res/res/drawable-hdpi/sim_light_orange.9.png diff --git a/core/res/res/drawable-hdpi/sim_light_purple.9.png b/core/res/res/drawable-hdpi/sim_light_purple.9.png Binary files differnew file mode 100755 index 0000000..4deb8dc --- /dev/null +++ b/core/res/res/drawable-hdpi/sim_light_purple.9.png diff --git a/core/res/res/drawable-mdpi/sim_dark_blue.9.png b/core/res/res/drawable-mdpi/sim_dark_blue.9.png Binary files differnew file mode 100755 index 0000000..d646a7f --- /dev/null +++ b/core/res/res/drawable-mdpi/sim_dark_blue.9.png diff --git a/core/res/res/drawable-mdpi/sim_dark_green.9.png b/core/res/res/drawable-mdpi/sim_dark_green.9.png Binary files differnew file mode 100755 index 0000000..ee4ea0d --- /dev/null +++ b/core/res/res/drawable-mdpi/sim_dark_green.9.png diff --git a/core/res/res/drawable-mdpi/sim_dark_orange.9.png b/core/res/res/drawable-mdpi/sim_dark_orange.9.png Binary files differnew file mode 100755 index 0000000..b394999 --- /dev/null +++ b/core/res/res/drawable-mdpi/sim_dark_orange.9.png diff --git a/core/res/res/drawable-mdpi/sim_dark_purple.9.png b/core/res/res/drawable-mdpi/sim_dark_purple.9.png Binary files differnew file mode 100755 index 0000000..459b5d6 --- /dev/null +++ b/core/res/res/drawable-mdpi/sim_dark_purple.9.png diff --git a/core/res/res/drawable-mdpi/sim_light_blue.9.png b/core/res/res/drawable-mdpi/sim_light_blue.9.png Binary files differnew file mode 100755 index 0000000..396ad70 --- /dev/null +++ b/core/res/res/drawable-mdpi/sim_light_blue.9.png diff --git a/core/res/res/drawable-mdpi/sim_light_green.9.png b/core/res/res/drawable-mdpi/sim_light_green.9.png Binary files differnew file mode 100755 index 0000000..a063174 --- /dev/null +++ b/core/res/res/drawable-mdpi/sim_light_green.9.png diff --git a/core/res/res/drawable-mdpi/sim_light_orange.9.png b/core/res/res/drawable-mdpi/sim_light_orange.9.png Binary files differnew file mode 100755 index 0000000..95ea88e --- /dev/null +++ b/core/res/res/drawable-mdpi/sim_light_orange.9.png diff --git a/core/res/res/drawable-mdpi/sim_light_purple.9.png b/core/res/res/drawable-mdpi/sim_light_purple.9.png Binary files differnew file mode 100755 index 0000000..b1bd35f --- /dev/null +++ b/core/res/res/drawable-mdpi/sim_light_purple.9.png diff --git a/core/res/res/layout/subscription_item_layout.xml b/core/res/res/layout/subscription_item_layout.xml new file mode 100755 index 0000000..9f8f2b3 --- /dev/null +++ b/core/res/res/layout/subscription_item_layout.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** +** Copyright (C) 2014 MediaTek Inc. +** +** 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. +*/ +--> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:gravity="center_vertical" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" > + <RelativeLayout + android:layout_width="48dip" + android:layout_height="32dip" + android:id="@+id/sub_color" + android:layout_marginEnd="6dip" + android:layout_centerVertical="true"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/sub_short_number" + android:layout_marginBottom="2dip" + android:layout_marginEnd="4dip" + android:layout_alignParentEnd="true" + android:layout_alignParentBottom="true" + android:textSize="12sp" + android:singleLine="true" + android:textColor="@android:color/white" + android:includeFontPadding="false"/> + </RelativeLayout> + <RelativeLayout + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_centerVertical="true"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/sub_name" + android:singleLine="true" + android:ellipsize="none" + android:requiresFadingEdge="horizontal" + android:scrollHorizontally="true" + android:textAppearance="?android:attr/textAppearanceMedium"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:id="@+id/sub_number" + android:layout_below="@+id/sub_name" + android:layout_alignStart="@+id/sub_name" + android:singleLine="true" + android:ellipsize="none" + android:requiresFadingEdge="horizontal" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:attr/textColorSecondary"/> + </RelativeLayout> +</LinearLayout> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 830c64c..a4f78bd 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1574,4 +1574,28 @@ <item>users</item> </string-array> + <!-- default telephony hardware configuration for this platform. + --> + <!-- this string array should be overridden by the device to present a list + telephony hardware resource. this is used by the telephony device controller + (TDC) to offer the basic capabilities of the hardware to the telephony + framework + --> + <!-- an array of "[hardware type],[hardware-uuid],[state],[[hardware-type specific]]" + with, [[hardware-type specific]] in: + - "[[ril-model],[rat],[max-active-voice],[max-active-data],[max-active-standby]]" + for 'modem' hardware + - "[[associated-modem-uuid]]" + for 'sim' hardware. + refer to HardwareConfig in com.android.internal.telephony for specific details/values + those elements can carry. + --> + <string-array translatable="false" name="config_telephonyHardware"> + <!-- modem --> + <item>"0,modem,0,0,0,1,1,1"</item> + <!-- sim --> + <item>"1,sim,0,modem"</item> + </string-array> + + </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 8fad07a..d69f60a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -999,6 +999,7 @@ <java-symbol type="array" name="config_sameNamedOperatorConsideredRoaming" /> <java-symbol type="array" name="config_callBarringMMI" /> <java-symbol type="array" name="config_globalActionsList" /> + <java-symbol type="array" name="config_telephonyHardware" /> <java-symbol type="drawable" name="default_wallpaper" /> <java-symbol type="drawable" name="indicator_input_error" /> @@ -1122,6 +1123,15 @@ <java-symbol type="drawable" name="ic_corp_badge" /> <java-symbol type="drawable" name="ic_corp_icon_badge" /> + <java-symbol type="drawable" name="sim_light_blue" /> + <java-symbol type="drawable" name="sim_light_green" /> + <java-symbol type="drawable" name="sim_light_orange" /> + <java-symbol type="drawable" name="sim_light_purple" /> + <java-symbol type="drawable" name="sim_dark_blue" /> + <java-symbol type="drawable" name="sim_dark_green" /> + <java-symbol type="drawable" name="sim_dark_orange" /> + <java-symbol type="drawable" name="sim_dark_purple" /> + <java-symbol type="layout" name="action_bar_home" /> <java-symbol type="layout" name="action_bar_title_item" /> <java-symbol type="layout" name="action_menu_item_layout" /> diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 362061e..d26f3fc 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -61,6 +61,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.telephony.DataConnectionRealTimeInfo; import android.telephony.PhoneStateListener; +import android.telephony.SubscriptionManager; import android.util.Log; import android.util.Slog; import android.util.SparseBooleanArray; @@ -237,7 +238,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub mThread = new Thread(mConnector, NETD_TAG); mDaemonHandler = new Handler(FgThread.get().getLooper()); - mPhoneStateListener = new PhoneStateListener(mDaemonHandler.getLooper()) { + mPhoneStateListener = new PhoneStateListener( + SubscriptionManager.DEFAULT_SUB_ID, // FIXME: What Subscription should be used?? + mDaemonHandler.getLooper()) { public void onDataConnectionRealTimeInfoChanged( DataConnectionRealTimeInfo dcRtInfo) { notifyInterfaceClassActivity(ConnectivityManager.TYPE_MOBILE, diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index cfaf016..9d92421 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -33,10 +33,13 @@ import android.os.RemoteException; import android.os.UserHandle; import android.telephony.CellLocation; import android.telephony.DataConnectionRealTimeInfo; +import android.telephony.TelephonyManager; +import android.telephony.SubscriptionManager; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.CellInfo; +import android.telephony.VoLteServiceState; import android.telephony.TelephonyManager; import android.telephony.DisconnectCause; import android.telephony.PreciseCallState; @@ -65,8 +68,9 @@ import com.android.server.am.BatteryStatsService; */ class TelephonyRegistry extends ITelephonyRegistry.Stub { private static final String TAG = "TelephonyRegistry"; - private static final boolean DBG = false; - private static final boolean DBG_LOC = false; + private static final boolean DBG = false; // STOPSHIP if true + private static final boolean DBG_LOC = false; // STOPSHIP if true + private static final boolean VDBG = false; // STOPSHIP if true private static class Record { String pkgForDebug; @@ -79,6 +83,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { int events; + long subId; + + boolean isLegacyApp; + @Override public String toString() { return "{pkgForDebug=" + pkgForDebug + " callerUid=" + callerUid + @@ -94,41 +102,47 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private final IBatteryStats mBatteryStats; - private int mCallState = TelephonyManager.CALL_STATE_IDLE; + private int mNumPhones; - private String mCallIncomingNumber = ""; + private int[] mCallState; - private ServiceState mServiceState = new ServiceState(); + private String[] mCallIncomingNumber; - private SignalStrength mSignalStrength = new SignalStrength(); + private ServiceState[] mServiceState; - private boolean mMessageWaiting = false; + private SignalStrength[] mSignalStrength; - private boolean mCallForwarding = false; + private boolean[] mMessageWaiting; - private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; + private boolean[] mCallForwarding; - private int mDataConnectionState = TelephonyManager.DATA_UNKNOWN; + private int[] mDataActivity; - private boolean mDataConnectionPossible = false; + private int[] mDataConnectionState; - private String mDataConnectionReason = ""; + private boolean[] mDataConnectionPossible; - private String mDataConnectionApn = ""; + private String[] mDataConnectionReason; + + private String[] mDataConnectionApn; private ArrayList<String> mConnectedApns; - private LinkProperties mDataConnectionLinkProperties; + private LinkProperties[] mDataConnectionLinkProperties; - private NetworkCapabilities mDataConnectionNetworkCapabilities; + private NetworkCapabilities[] mDataConnectionNetworkCapabilities; - private Bundle mCellLocation = new Bundle(); + private Bundle[] mCellLocation; - private int mDataConnectionNetworkType; + private int[] mDataConnectionNetworkType; private int mOtaspMode = ServiceStateTracker.OTASP_UNKNOWN; - private List<CellInfo> mCellInfo = null; + private ArrayList<List<CellInfo>> mCellInfo = null; + + private VoLteServiceState mVoLteServiceState = new VoLteServiceState(); + + private long mDefaultSubId; private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo(); @@ -148,21 +162,40 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { PhoneStateListener.LISTEN_CALL_STATE | PhoneStateListener.LISTEN_DATA_ACTIVITY | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE | - PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR; + PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR | + PhoneStateListener.LISTEN_VOLTE_STATE;; static final int PRECISE_PHONE_STATE_PERMISSION_MASK = PhoneStateListener.LISTEN_PRECISE_CALL_STATE | PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE; private static final int MSG_USER_SWITCHED = 1; + private static final int MSG_UPDATE_DEFAULT_SUB = 2; private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_USER_SWITCHED: { - if (DBG) Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1); - TelephonyRegistry.this.notifyCellLocation(mCellLocation); + Slog.d(TAG, "MSG_USER_SWITCHED userId=" + msg.arg1); + int numPhones = TelephonyManager.getDefault().getPhoneCount(); + for (int sub = 0; sub < numPhones; sub++) { + TelephonyRegistry.this.notifyCellLocationUsingSubId(sub, mCellLocation[sub]); + } + break; + } + case MSG_UPDATE_DEFAULT_SUB: { + Slog.d(TAG, "MSG_UPDATE_DEFAULT_SUB subid=" + mDefaultSubId); + // Default subscription id changed, update the changed default subscription + // id in all the legacy application listener records. + synchronized (mRecords) { + for (Record r : mRecords) { + // FIXME: Be sure we're using isLegacyApp correctly! + if (r.isLegacyApp == true) { + r.subId = mDefaultSubId; + } + } + } break; } } @@ -173,9 +206,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); + Slog.d(TAG, "mBroadcastReceiver: action=" + action); if (Intent.ACTION_USER_SWITCHED.equals(action)) { mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0), 0)); + } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) { + mDefaultSubId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY, + SubscriptionManager.getDefaultSubId()); + mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0)); } } }; @@ -190,13 +228,55 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyRegistry(Context context) { CellLocation location = CellLocation.getEmpty(); + mContext = context; + mBatteryStats = BatteryStatsService.getService(); + mConnectedApns = new ArrayList<String>(); + + // Initialize default subscription to be used for single standby. + mDefaultSubId = SubscriptionManager.getDefaultSubId(); + + int numPhones = TelephonyManager.getDefault().getPhoneCount(); + if (DBG) Slog.d(TAG, "TelephonyRegistor: ctor numPhones=" + numPhones); + mNumPhones = numPhones; + mCallState = new int[numPhones]; + mDataActivity = new int[numPhones]; + mDataConnectionState = new int[numPhones]; + mDataConnectionNetworkType = new int[numPhones]; + mCallIncomingNumber = new String[numPhones]; + mServiceState = new ServiceState[numPhones]; + mSignalStrength = new SignalStrength[numPhones]; + mMessageWaiting = new boolean[numPhones]; + mDataConnectionPossible = new boolean[numPhones]; + mDataConnectionReason = new String[numPhones]; + mDataConnectionApn = new String[numPhones]; + mCallForwarding = new boolean[numPhones]; + mCellLocation = new Bundle[numPhones]; + mDataConnectionLinkProperties = new LinkProperties[numPhones]; + mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones]; + mCellInfo = new ArrayList<List<CellInfo>>(); + for (int i = 0; i < numPhones; i++) { + mCallState[i] = TelephonyManager.CALL_STATE_IDLE; + mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; + mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN; + mCallIncomingNumber[i] = ""; + mServiceState[i] = new ServiceState(); + mSignalStrength[i] = new SignalStrength(); + mMessageWaiting[i] = false; + mCallForwarding[i] = false; + mDataConnectionPossible[i] = false; + mDataConnectionReason[i] = ""; + mDataConnectionApn[i] = ""; + mCellLocation[i] = new Bundle(); + mCellInfo.add(i, null); + } + // Note that location can be null for non-phone builds like // like the generic one. if (location != null) { - location.fillInNotifierBundle(mCellLocation); + for (int i = 0; i < numPhones; i++) { + location.fillInNotifierBundle(mCellLocation[i]); + } } - mContext = context; - mBatteryStats = BatteryStatsService.getService(); mConnectedApns = new ArrayList<String>(); } @@ -205,16 +285,31 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED); + Slog.d(TAG, "systemRunning register for intents"); mContext.registerReceiver(mBroadcastReceiver, filter); } @Override public void listen(String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow) { + listen(pkgForDebug, callback, events, notifyNow, mDefaultSubId, true); + } + + @Override + public void listenUsingSubId(long subId, String pkgForDebug, IPhoneStateListener callback, + int events, boolean notifyNow) { + listen(pkgForDebug, callback, events, notifyNow, subId, false); + } + + private void listen(String pkgForDebug, IPhoneStateListener callback, int events, + boolean notifyNow, long subId, boolean isLegacyApp) { int callerUid = UserHandle.getCallingUserId(); int myUid = UserHandle.myUserId(); - if (DBG) { + if (VDBG) { Slog.d(TAG, "listen: E pkg=" + pkgForDebug + " events=0x" + Integer.toHexString(events) + + " notifyNow=" + notifyNow + " subId=" + subId + + " isLegacyApp=" + isLegacyApp + " myUid=" + myUid + " callerUid=" + callerUid); } @@ -239,22 +334,37 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { r.callback = callback; r.pkgForDebug = pkgForDebug; r.callerUid = callerUid; + r.subId = subId; + r.isLegacyApp = isLegacyApp; + // Legacy applications pass invalid subId(-1), based on + // the received subId value update the isLegacyApp field + if ((r.subId <= 0) || (r.subId == SubscriptionManager.INVALID_SUB_ID)) { + r.subId = mDefaultSubId; + r.isLegacyApp = true; // FIXME: is this needed ?? + } + if (r.subId == SubscriptionManager.DEFAULT_SUB_ID) { + r.subId = mDefaultSubId; + if (DBG) Slog.i(TAG, "listen: DEFAULT_SUB_ID"); + } mRecords.add(r); if (DBG) Slog.i(TAG, "listen: add new record=" + r); } + int phoneId = SubscriptionManager.getPhoneId(subId); int send = events & (events ^ r.events); r.events = events; - if (notifyNow) { + if (notifyNow && validatePhoneId(phoneId)) { if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { try { - r.callback.onServiceStateChanged(new ServiceState(mServiceState)); + r.callback.onServiceStateChanged( + new ServiceState(mServiceState[phoneId])); } catch (RemoteException ex) { remove(r.binder); } } if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { try { - int gsmSignalStrength = mSignalStrength.getGsmSignalStrength(); + int gsmSignalStrength = mSignalStrength[phoneId] + .getGsmSignalStrength(); r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 : gsmSignalStrength)); } catch (RemoteException ex) { @@ -263,51 +373,56 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { try { - r.callback.onMessageWaitingIndicatorChanged(mMessageWaiting); + r.callback.onMessageWaitingIndicatorChanged( + mMessageWaiting[phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) { try { - r.callback.onCallForwardingIndicatorChanged(mCallForwarding); + r.callback.onCallForwardingIndicatorChanged( + mCallForwarding[phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { try { - if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation=" + mCellLocation); - r.callback.onCellLocationChanged(new Bundle(mCellLocation)); + if (DBG_LOC) Slog.d(TAG, "listen: mCellLocation = " + + mCellLocation[phoneId]); + r.callback.onCellLocationChanged( + new Bundle(mCellLocation[phoneId])); } catch (RemoteException ex) { remove(r.binder); } } if ((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) { try { - r.callback.onCallStateChanged(mCallState, mCallIncomingNumber); + r.callback.onCallStateChanged(mCallState[phoneId], + mCallIncomingNumber[phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { try { - r.callback.onDataConnectionStateChanged(mDataConnectionState, - mDataConnectionNetworkType); + r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId], + mDataConnectionNetworkType[phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if ((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) { try { - r.callback.onDataActivity(mDataActivity); + r.callback.onDataActivity(mDataActivity[phoneId]); } catch (RemoteException ex) { remove(r.binder); } } if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { try { - r.callback.onSignalStrengthsChanged(mSignalStrength); + r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); } catch (RemoteException ex) { remove(r.binder); } @@ -321,8 +436,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) { try { - if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo=" + mCellInfo); - r.callback.onCellInfoChanged(mCellInfo); + if (DBG_LOC) Slog.d(TAG, "listen: mCellInfo[" + phoneId + "] = " + + mCellInfo.get(phoneId)); + r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); } catch (RemoteException ex) { remove(r.binder); } @@ -373,10 +489,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } synchronized (mRecords) { - mCallState = state; - mCallIncomingNumber = incomingNumber; for (Record r : mRecords) { - if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) { + if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) && + (r.isLegacyApp == true)) { + // FIXME: why does isLegacyApp need to be true? try { r.callback.onCallStateChanged(state, incomingNumber); } catch (RemoteException ex) { @@ -386,82 +502,148 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } handleRemoveListLocked(); } - broadcastCallStateChanged(state, incomingNumber); + broadcastCallStateChanged(state, incomingNumber, mDefaultSubId); + } + + public void notifyCallStateUsingSubId(long subId, int state, String incomingNumber) { + if (!checkNotifyPermission("notifyCallState()")) { + return; + } + if (VDBG) { + Slog.d(TAG, "notifyCallStateUsingSubId: subId=" + subId + + " state=" + state + " incomingNumber=" + incomingNumber); + } + synchronized (mRecords) { + int phoneId = SubscriptionManager.getPhoneId(subId); + if (validatePhoneId(phoneId)) { + mCallState[phoneId] = state; + mCallIncomingNumber[phoneId] = incomingNumber; + for (Record r : mRecords) { + if (((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) && + (r.subId == subId) && (r.isLegacyApp == false)) { + // FIXME: why isLegacyApp false? + try { + r.callback.onCallStateChanged(state, incomingNumber); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + broadcastCallStateChanged(state, incomingNumber, subId); } - public void notifyServiceState(ServiceState state) { + public void notifyServiceState(ServiceState state) { + notifyServiceStateUsingSubId(mDefaultSubId, state); + } + + public void notifyServiceStateUsingSubId(long subId, ServiceState state) { if (!checkNotifyPermission("notifyServiceState()")){ return; } - long ident = Binder.clearCallingIdentity(); - try { - mBatteryStats.notePhoneState(state.getState()); - } catch (RemoteException re) { - // Can't do much - } finally { - Binder.restoreCallingIdentity(ident); + if (subId == SubscriptionManager.DEFAULT_SUB_ID) { + subId = mDefaultSubId; + Slog.d(TAG, "notifyServiceStateUsingSubId: using mDefaultSubId=" + mDefaultSubId); + } + if (VDBG) { + Slog.d(TAG, "notifyServiceStateUsingSubId: subId=" + subId + + " state=" + state); } synchronized (mRecords) { - mServiceState = state; - for (Record r : mRecords) { - if ((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { - try { - r.callback.onServiceStateChanged(new ServiceState(state)); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); + int phoneId = SubscriptionManager.getPhoneId(subId); + if (validatePhoneId(phoneId)) { + mServiceState[phoneId] = state; + for (Record r : mRecords) { + // FIXME: use DEFAULT_SUB_ID instead?? + if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) && + (r.subId == subId)) { + try { + r.callback.onServiceStateChanged(new ServiceState(state)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } } } + } else { + Slog.d(TAG, "notifyServiceStateUsingSubId: INVALID phoneId=" + phoneId); } handleRemoveListLocked(); } - broadcastServiceStateChanged(state); + broadcastServiceStateChanged(state, subId); } public void notifySignalStrength(SignalStrength signalStrength) { + notifySignalStrengthUsingSubId(mDefaultSubId, signalStrength); + } + + public void notifySignalStrengthUsingSubId(long subId, SignalStrength signalStrength) { if (!checkNotifyPermission("notifySignalStrength()")) { return; } + if (VDBG) { + Slog.d(TAG, "notifySignalStrengthUsingSubId: subId=" + subId + + " signalStrength=" + signalStrength); + } synchronized (mRecords) { - mSignalStrength = signalStrength; - for (Record r : mRecords) { - if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { - try { - r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength)); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); + int phoneId = SubscriptionManager.getPhoneId(subId); + if (validatePhoneId(phoneId)) { + mSignalStrength[phoneId] = signalStrength; + for (Record r : mRecords) { + if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) && + (r.subId == subId)){ + try { + r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } } - } - if ((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { - try { - int gsmSignalStrength = signalStrength.getGsmSignalStrength(); - r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 - : gsmSignalStrength)); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); + if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) && + (r.subId == subId)) { + try { + int gsmSignalStrength = signalStrength.getGsmSignalStrength(); + r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 + : gsmSignalStrength)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } } } } handleRemoveListLocked(); } - broadcastSignalStrengthChanged(signalStrength); + broadcastSignalStrengthChanged(signalStrength, subId); } public void notifyCellInfo(List<CellInfo> cellInfo) { + notifyCellInfoUsingSubId(mDefaultSubId, cellInfo); + } + + public void notifyCellInfoUsingSubId(long subId, List<CellInfo> cellInfo) { if (!checkNotifyPermission("notifyCellInfo()")) { return; } + if (VDBG) { + Slog.d(TAG, "notifyCellInfoUsingSubId: subId=" + subId + + " cellInfo=" + cellInfo); + } synchronized (mRecords) { - mCellInfo = cellInfo; - for (Record r : mRecords) { - if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) { - try { - if (DBG_LOC) { - Slog.d(TAG, "notifyCellInfo: mCellInfo=" + mCellInfo + " r=" + r); + int phoneId = SubscriptionManager.getPhoneId(subId); + if (validatePhoneId(phoneId)) { + mCellInfo.set(phoneId, cellInfo); + for (Record r : mRecords) { + if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) + && r.subId == subId) { + try { + if (DBG_LOC) { + Slog.d(TAG, "notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r); + } + r.callback.onCellInfoChanged(cellInfo); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); } - r.callback.onCellInfoChanged(cellInfo); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); } } } @@ -495,17 +677,29 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } public void notifyMessageWaitingChanged(boolean mwi) { + notifyMessageWaitingChangedUsingSubId(mDefaultSubId, mwi); + } + + public void notifyMessageWaitingChangedUsingSubId(long subId, boolean mwi) { if (!checkNotifyPermission("notifyMessageWaitingChanged()")) { return; } + if (VDBG) { + Slog.d(TAG, "notifyMessageWaitingChangedUsingSubId: subId=" + subId + + " mwi=" + mwi); + } synchronized (mRecords) { - mMessageWaiting = mwi; - for (Record r : mRecords) { - if ((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { - try { - r.callback.onMessageWaitingIndicatorChanged(mwi); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); + int phoneId = SubscriptionManager.getPhoneId(subId); + if (validatePhoneId(phoneId)) { + mMessageWaiting[phoneId] = mwi; + for (Record r : mRecords) { + if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) && + (r.subId == subId)) { + try { + r.callback.onMessageWaitingIndicatorChanged(mwi); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } } } } @@ -514,17 +708,29 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } public void notifyCallForwardingChanged(boolean cfi) { + notifyCallForwardingChangedUsingSubId(mDefaultSubId, cfi); + } + + public void notifyCallForwardingChangedUsingSubId(long subId, boolean cfi) { if (!checkNotifyPermission("notifyCallForwardingChanged()")) { return; } + if (VDBG) { + Slog.d(TAG, "notifyCallForwardingChangedUsingSubId: subId=" + subId + + " cfi=" + cfi); + } synchronized (mRecords) { - mCallForwarding = cfi; - for (Record r : mRecords) { - if ((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) { - try { - r.callback.onCallForwardingIndicatorChanged(cfi); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); + int phoneId = SubscriptionManager.getPhoneId(subId); + if (validatePhoneId(phoneId)) { + mCallForwarding[phoneId] = cfi; + for (Record r : mRecords) { + if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) && + (r.subId == subId)) { + try { + r.callback.onCallForwardingIndicatorChanged(cfi); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } } } } @@ -533,11 +739,16 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } public void notifyDataActivity(int state) { + notifyDataActivityUsingSubId(mDefaultSubId, state); + } + + public void notifyDataActivityUsingSubId(long subId, int state) { if (!checkNotifyPermission("notifyDataActivity()" )) { return; } synchronized (mRecords) { - mDataActivity = state; + int phoneId = SubscriptionManager.getPhoneId(subId); + mDataActivity[phoneId] = state; for (Record r : mRecords) { if ((r.events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) { try { @@ -554,29 +765,40 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { public void notifyDataConnection(int state, boolean isDataConnectivityPossible, String reason, String apn, String apnType, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int networkType, boolean roaming) { + notifyDataConnectionUsingSubId(mDefaultSubId, state, isDataConnectivityPossible, + reason, apn, apnType, linkProperties, + networkCapabilities, networkType, roaming); + } + + public void notifyDataConnectionUsingSubId(long subId, int state, + boolean isDataConnectivityPossible, String reason, String apn, String apnType, + LinkProperties linkProperties, NetworkCapabilities networkCapabilities, + int networkType, boolean roaming) { if (!checkNotifyPermission("notifyDataConnection()" )) { return; } - if (DBG) { - Slog.i(TAG, "notifyDataConnection: state=" + state + " isDataConnectivityPossible=" - + isDataConnectivityPossible + " reason='" + reason + if (VDBG) { + Slog.i(TAG, "notifyDataConnectionUsingSubId: subId=" + subId + + " state=" + state + " isDataConnectivityPossible=" + isDataConnectivityPossible + + " reason='" + reason + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType + " mRecords.size()=" + mRecords.size() + " mRecords=" + mRecords); } synchronized (mRecords) { + int phoneId = SubscriptionManager.getPhoneId(subId); boolean modified = false; if (state == TelephonyManager.DATA_CONNECTED) { if (!mConnectedApns.contains(apnType)) { mConnectedApns.add(apnType); - if (mDataConnectionState != state) { - mDataConnectionState = state; + if (mDataConnectionState[phoneId] != state) { + mDataConnectionState[phoneId] = state; modified = true; } } } else { if (mConnectedApns.remove(apnType)) { if (mConnectedApns.isEmpty()) { - mDataConnectionState = state; + mDataConnectionState[phoneId] = state; modified = true; } else { // leave mDataConnectionState as is and @@ -584,25 +806,28 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } } - mDataConnectionPossible = isDataConnectivityPossible; - mDataConnectionReason = reason; - mDataConnectionLinkProperties = linkProperties; - mDataConnectionNetworkCapabilities = networkCapabilities; - if (mDataConnectionNetworkType != networkType) { - mDataConnectionNetworkType = networkType; + mDataConnectionPossible[phoneId] = isDataConnectivityPossible; + mDataConnectionReason[phoneId] = reason; + mDataConnectionLinkProperties[phoneId] = linkProperties; + mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities; + if (mDataConnectionNetworkType[phoneId] != networkType) { + mDataConnectionNetworkType[phoneId] = networkType; // need to tell registered listeners about the new network type modified = true; } if (modified) { if (DBG) { - Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState - + ", " + mDataConnectionNetworkType + ")"); + Slog.d(TAG, "onDataConnectionStateChanged(" + mDataConnectionState[phoneId] + + ", " + mDataConnectionNetworkType[phoneId] + ")"); } for (Record r : mRecords) { - if ((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { + if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) && + (r.subId == subId)) { try { - r.callback.onDataConnectionStateChanged(mDataConnectionState, - mDataConnectionNetworkType); + Slog.d(TAG,"Notify data connection state changed on sub: " + + subId); + r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId], + mDataConnectionNetworkType[phoneId]); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -624,15 +849,24 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { handleRemoveListLocked(); } broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn, - apnType, linkProperties, networkCapabilities, roaming); + apnType, linkProperties, networkCapabilities, roaming, subId); broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason, linkProperties, ""); } public void notifyDataConnectionFailed(String reason, String apnType) { + notifyDataConnectionFailedUsingSubId(mDefaultSubId, reason, apnType); + } + + public void notifyDataConnectionFailedUsingSubId(long subId, + String reason, String apnType) { if (!checkNotifyPermission("notifyDataConnectionFailed()")) { return; } + if (VDBG) { + Slog.d(TAG, "notifyDataConnectionFailedUsingSubId: subId=" + subId + + " reason=" + reason + " apnType=" + apnType); + } synchronized (mRecords) { mPreciseDataConnectionState = new PreciseDataConnectionState( TelephonyManager.DATA_UNKNOWN,TelephonyManager.NETWORK_TYPE_UNKNOWN, @@ -648,29 +882,42 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } handleRemoveListLocked(); } - broadcastDataConnectionFailed(reason, apnType); + broadcastDataConnectionFailed(reason, apnType, subId); broadcastPreciseDataConnectionStateChanged(TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, "", reason, null, ""); } public void notifyCellLocation(Bundle cellLocation) { + notifyCellLocationUsingSubId(mDefaultSubId, cellLocation); + } + + public void notifyCellLocationUsingSubId(long subId, Bundle cellLocation) { + Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId + + " cellLocation=" + cellLocation); if (!checkNotifyPermission("notifyCellLocation()")) { return; } + if (VDBG) { + Slog.d(TAG, "notifyCellLocationUsingSubId: subId=" + subId + + " cellLocation=" + cellLocation); + } synchronized (mRecords) { - mCellLocation = cellLocation; - for (Record r : mRecords) { - if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { - try { - if (DBG_LOC) { - Slog.d(TAG, "notifyCellLocation: mCellLocation=" + mCellLocation - + " r=" + r); + int phoneId = SubscriptionManager.getPhoneId(subId); + if (validatePhoneId(phoneId)) { + mCellLocation[phoneId] = cellLocation; + for (Record r : mRecords) { + if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) + && r.subId == subId) { + try { + if (DBG_LOC) { + Slog.d(TAG, "notifyCellLocation: cellLocation=" + cellLocation + + " r=" + r); + } + r.callback.onCellLocationChanged(new Bundle(cellLocation)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); } - r.callback.onCellLocationChanged(new Bundle(cellLocation)); - } catch (RemoteException ex) { - mRemoveList.add(r.binder); } - } } handleRemoveListLocked(); @@ -771,6 +1018,26 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyManager.NETWORK_TYPE_UNKNOWN, apnType, apn, reason, null, failCause); } + public void notifyVoLteServiceStateChanged(VoLteServiceState lteState) { + if (!checkNotifyPermission("notifyVoLteServiceStateChanged()")) { + return; + } + synchronized (mRecords) { + mVoLteServiceState = lteState; + for (Record r : mRecords) { + if ((r.events & PhoneStateListener.LISTEN_VOLTE_STATE) != 0) { + try { + r.callback.onVoLteServiceStateChanged( + new VoLteServiceState(mVoLteServiceState)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + handleRemoveListLocked(); + } + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) @@ -810,15 +1077,26 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { // the legacy intent broadcasting // - private void broadcastServiceStateChanged(ServiceState state) { + private void broadcastServiceStateChanged(ServiceState state, long subId) { + long ident = Binder.clearCallingIdentity(); + try { + mBatteryStats.notePhoneState(state.getState()); + } catch (RemoteException re) { + // Can't do much + } finally { + Binder.restoreCallingIdentity(ident); + } + Intent intent = new Intent(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED); Bundle data = new Bundle(); state.fillInNotifierBundle(data); intent.putExtras(data); + // Pass the subscription along with the intent. + intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } - private void broadcastSignalStrengthChanged(SignalStrength signalStrength) { + private void broadcastSignalStrengthChanged(SignalStrength signalStrength, long subId) { long ident = Binder.clearCallingIdentity(); try { mBatteryStats.notePhoneSignalStrength(signalStrength); @@ -833,10 +1111,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { Bundle data = new Bundle(); signalStrength.fillInNotifierBundle(data); intent.putExtras(data); + intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } - private void broadcastCallStateChanged(int state, String incomingNumber) { + private void broadcastCallStateChanged(int state, String incomingNumber, long subId) { long ident = Binder.clearCallingIdentity(); try { if (state == TelephonyManager.CALL_STATE_IDLE) { @@ -856,6 +1135,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (!TextUtils.isEmpty(incomingNumber)) { intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber); } + intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); mContext.sendBroadcastAsUser(intent, UserHandle.ALL, android.Manifest.permission.READ_PHONE_STATE); } @@ -863,7 +1143,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible, String reason, String apn, String apnType, LinkProperties linkProperties, - NetworkCapabilities networkCapabilities, boolean roaming) { + NetworkCapabilities networkCapabilities, boolean roaming, long subId) { // Note: not reporting to the battery stats service here, because the // status bar takes care of that after taking into account all of the // required info. @@ -890,13 +1170,16 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { intent.putExtra(PhoneConstants.DATA_APN_KEY, apn); intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType); + intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } - private void broadcastDataConnectionFailed(String reason, String apnType) { + private void broadcastDataConnectionFailed(String reason, String apnType, + long subId) { Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason); intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType); + intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } @@ -989,4 +1272,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } return valid; } + + private boolean validatePhoneId(int phoneId) { + boolean valid = (phoneId >= 0) && (phoneId < mNumPhones); + if (VDBG) Slog.d(TAG, "validatePhoneId: " + valid); + return valid; + } } diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index ed7f6b8..b935d2a 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -36,6 +36,7 @@ import android.text.TextUtils; import android.telephony.Rlog; import android.util.SparseIntArray; +import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_IDP_STRING; import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY; @@ -166,7 +167,9 @@ public class PhoneNumberUtils // TODO: We don't check for SecurityException here (requires // CALL_PRIVILEGED permission). if (scheme.equals("voicemail")) { - return TelephonyManager.getDefault().getCompleteVoiceMailNumber(); + long subId = intent.getLongExtra(SUBSCRIPTION_KEY, + SubscriptionManager.getDefaultVoiceSubId()); + return TelephonyManager.getDefault().getCompleteVoiceMailNumber(subId); } if (context == null) { @@ -1144,7 +1147,7 @@ public class PhoneNumberUtils * @return A locally acceptable formatting of the input, or the raw input if * formatting rules aren't known for the number * - * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead + * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead */ public static String formatNumber(String source) { SpannableStringBuilder text = new SpannableStringBuilder(source); @@ -1162,7 +1165,7 @@ public class PhoneNumberUtils * @return The phone number formatted with the given formatting type. * * @hide - * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead + * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead */ public static String formatNumber(String source, int defaultFormattingType) { SpannableStringBuilder text = new SpannableStringBuilder(source); @@ -1177,7 +1180,7 @@ public class PhoneNumberUtils * @return The formatting type for the given locale, or FORMAT_UNKNOWN if the formatting * rules are not known for the given locale * - * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead + * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead */ public static int getFormatTypeForLocale(Locale locale) { String country = locale.getCountry(); @@ -1193,7 +1196,7 @@ public class PhoneNumberUtils * @param defaultFormattingType The default formatting rules to apply if the number does * not begin with +[country_code] * - * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead + * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead */ public static void formatNumber(Editable text, int defaultFormattingType) { int formatType = defaultFormattingType; @@ -1241,7 +1244,7 @@ public class PhoneNumberUtils * * @param text the number to be formatted, will be modified with the formatting * - * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead + * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead */ public static void formatNanpNumber(Editable text) { int length = text.length(); @@ -1356,7 +1359,7 @@ public class PhoneNumberUtils * @param text the number to be formatted, will be modified with * the formatting * - * @deprecated Use {@link #formatNumber(String phoneNumber, String defaultCountryIso)} instead + * @deprecated Use link #formatNumber(String phoneNumber, String defaultCountryIso) instead */ public static void formatJapaneseNumber(Editable text) { JapanesePhoneNumberFormatter.format(text); @@ -1560,9 +1563,23 @@ public class PhoneNumberUtils * listed in the RIL / SIM, otherwise return false. */ public static boolean isEmergencyNumber(String number) { + return isEmergencyNumber(getDefaultVoiceSubId(), number); + } + + /** + * Checks a given number against the list of + * emergency numbers provided by the RIL and SIM card. + * + * @param subId the subscription id of the SIM. + * @param number the number to look up. + * @return true if the number is in the list of emergency numbers + * listed in the RIL / SIM, otherwise return false. + * @hide + */ + public static boolean isEmergencyNumber(long subId, String number) { // Return true only if the specified number *exactly* matches // one of the emergency numbers listed by the RIL / SIM. - return isEmergencyNumberInternal(number, true /* useExactMatch */); + return isEmergencyNumberInternal(subId, number, true /* useExactMatch */); } /** @@ -1586,9 +1603,33 @@ public class PhoneNumberUtils * @hide */ public static boolean isPotentialEmergencyNumber(String number) { + return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number); + } + + /** + * Checks if given number might *potentially* result in + * a call to an emergency service on the current network. + * + * Specifically, this method will return true if the specified number + * is an emergency number according to the list managed by the RIL or + * SIM, *or* if the specified number simply starts with the same + * digits as any of the emergency numbers listed in the RIL / SIM. + * + * This method is intended for internal use by the phone app when + * deciding whether to allow ACTION_CALL intents from 3rd party apps + * (where we're required to *not* allow emergency calls to be placed.) + * + * @param subId the subscription id of the SIM. + * @param number the number to look up. + * @return true if the number is in the list of emergency numbers + * listed in the RIL / SIM, *or* if the number starts with the + * same digits as any of those emergency numbers. + * @hide + */ + public static boolean isPotentialEmergencyNumber(long subId, String number) { // Check against the emergency numbers listed by the RIL / SIM, // and *don't* require an exact match. - return isEmergencyNumberInternal(number, false /* useExactMatch */); + return isEmergencyNumberInternal(subId, number, false /* useExactMatch */); } /** @@ -1611,7 +1652,32 @@ public class PhoneNumberUtils * listed in the RIL / sim, otherwise return false. */ private static boolean isEmergencyNumberInternal(String number, boolean useExactMatch) { - return isEmergencyNumberInternal(number, null, useExactMatch); + return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, useExactMatch); + } + + /** + * Helper function for isEmergencyNumber(String) and + * isPotentialEmergencyNumber(String). + * + * @param subId the subscription id of the SIM. + * @param number the number to look up. + * + * @param useExactMatch if true, consider a number to be an emergency + * number only if it *exactly* matches a number listed in + * the RIL / SIM. If false, a number is considered to be an + * emergency number if it simply starts with the same digits + * as any of the emergency numbers listed in the RIL / SIM. + * (Setting useExactMatch to false allows you to identify + * number that could *potentially* result in emergency calls + * since many networks will actually ignore trailing digits + * after a valid emergency number.) + * + * @return true if the number is in the list of emergency numbers + * listed in the RIL / sim, otherwise return false. + */ + private static boolean isEmergencyNumberInternal(long subId, String number, + boolean useExactMatch) { + return isEmergencyNumberInternal(subId, number, null, useExactMatch); } /** @@ -1625,7 +1691,21 @@ public class PhoneNumberUtils * @hide */ public static boolean isEmergencyNumber(String number, String defaultCountryIso) { - return isEmergencyNumberInternal(number, + return isEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso); + } + + /** + * Checks if a given number is an emergency number for a specific country. + * + * @param subId the subscription id of the SIM. + * @param number the number to look up. + * @param defaultCountryIso the specific country which the number should be checked against + * @return if the number is an emergency number for the specific country, then return true, + * otherwise false + * @hide + */ + public static boolean isEmergencyNumber(long subId, String number, String defaultCountryIso) { + return isEmergencyNumberInternal(subId, number, defaultCountryIso, true /* useExactMatch */); } @@ -1652,7 +1732,33 @@ public class PhoneNumberUtils * @hide */ public static boolean isPotentialEmergencyNumber(String number, String defaultCountryIso) { - return isEmergencyNumberInternal(number, + return isPotentialEmergencyNumber(getDefaultVoiceSubId(), number, defaultCountryIso); + } + + /** + * Checks if a given number might *potentially* result in a call to an + * emergency service, for a specific country. + * + * Specifically, this method will return true if the specified number + * is an emergency number in the specified country, *or* if the number + * simply starts with the same digits as any emergency number for that + * country. + * + * This method is intended for internal use by the phone app when + * deciding whether to allow ACTION_CALL intents from 3rd party apps + * (where we're required to *not* allow emergency calls to be placed.) + * + * @param subId the subscription id of the SIM. + * @param number the number to look up. + * @param defaultCountryIso the specific country which the number should be checked against + * @return true if the number is an emergency number for the specific + * country, *or* if the number starts with the same digits as + * any of those emergency numbers. + * @hide + */ + public static boolean isPotentialEmergencyNumber(long subId, String number, + String defaultCountryIso) { + return isEmergencyNumberInternal(subId, number, defaultCountryIso, false /* useExactMatch */); } @@ -1674,6 +1780,29 @@ public class PhoneNumberUtils private static boolean isEmergencyNumberInternal(String number, String defaultCountryIso, boolean useExactMatch) { + return isEmergencyNumberInternal(getDefaultVoiceSubId(), number, defaultCountryIso, + useExactMatch); + } + + /** + * Helper function for isEmergencyNumber(String, String) and + * isPotentialEmergencyNumber(String, String). + * + * @param subId the subscription id of the SIM. + * @param number the number to look up. + * @param defaultCountryIso the specific country which the number should be checked against + * @param useExactMatch if true, consider a number to be an emergency + * number only if it *exactly* matches a number listed in + * the RIL / SIM. If false, a number is considered to be an + * emergency number if it simply starts with the same digits + * as any of the emergency numbers listed in the RIL / SIM. + * + * @return true if the number is an emergency number for the specified country. + * @hide + */ + private static boolean isEmergencyNumberInternal(long subId, String number, + String defaultCountryIso, + boolean useExactMatch) { // If the number passed in is null, just return false: if (number == null) return false; @@ -1692,9 +1821,14 @@ public class PhoneNumberUtils // to the list. number = extractNetworkPortionAlt(number); + String numbers = ""; + int slotId = SubscriptionManager.getSlotId(subId); // retrieve the list of emergency numbers // check read-write ecclist property first - String numbers = SystemProperties.get("ril.ecclist"); + String ecclist = (slotId == 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); + + numbers = SystemProperties.get(ecclist); + if (TextUtils.isEmpty(numbers)) { // then read-only ecclist property since old RIL only uses this numbers = SystemProperties.get("ro.ril.ecclist"); @@ -1742,15 +1876,29 @@ public class PhoneNumberUtils /** * Checks if a given number is an emergency number for the country that the user is in. - * @param context the specific context which the number should be checked against - * @param number the number to look up. * + * @param number the number to look up. + * @param context the specific context which the number should be checked against * @return true if the specified number is an emergency number for the country the user * is currently in. */ public static boolean isLocalEmergencyNumber(Context context, String number) { - return isLocalEmergencyNumberInternal(context, - number, + return isLocalEmergencyNumber(context, getDefaultVoiceSubId(), number); + } + + /** + * Checks if a given number is an emergency number for the country that the user is in. + * + * @param subId the subscription id of the SIM. + * @param number the number to look up. + * @param context the specific context which the number should be checked against + * @return true if the specified number is an emergency number for the country the user + * is currently in. + * @hide + */ + public static boolean isLocalEmergencyNumber(Context context, long subId, String number) { + return isLocalEmergencyNumberInternal(subId, number, + context, true /* useExactMatch */); } @@ -1767,9 +1915,9 @@ public class PhoneNumberUtils * This method is intended for internal use by the phone app when * deciding whether to allow ACTION_CALL intents from 3rd party apps * (where we're required to *not* allow emergency calls to be placed.) - * @param context the specific context which the number should be checked against - * @param number the number to look up. * + * @param number the number to look up. + * @param context the specific context which the number should be checked against * @return true if the specified number is an emergency number for a local country, based on the * CountryDetector. * @@ -1777,16 +1925,44 @@ public class PhoneNumberUtils * @hide */ public static boolean isPotentialLocalEmergencyNumber(Context context, String number) { - return isLocalEmergencyNumberInternal(context, - number, + return isPotentialLocalEmergencyNumber(context, getDefaultVoiceSubId(), number); + } + + /** + * Checks if a given number might *potentially* result in a call to an + * emergency service, for the country that the user is in. The current + * country is determined using the CountryDetector. + * + * Specifically, this method will return true if the specified number + * is an emergency number in the current country, *or* if the number + * simply starts with the same digits as any emergency number for the + * current country. + * + * This method is intended for internal use by the phone app when + * deciding whether to allow ACTION_CALL intents from 3rd party apps + * (where we're required to *not* allow emergency calls to be placed.) + * + * @param subId the subscription id of the SIM. + * @param number the number to look up. + * @param context the specific context which the number should be checked against + * @return true if the specified number is an emergency number for a local country, based on the + * CountryDetector. + * + * @hide + */ + public static boolean isPotentialLocalEmergencyNumber(Context context, long subId, + String number) { + return isLocalEmergencyNumberInternal(subId, number, + context, false /* useExactMatch */); } /** * Helper function for isLocalEmergencyNumber() and * isPotentialLocalEmergencyNumber(). - * @param context the specific context which the number should be checked against + * * @param number the number to look up. + * @param context the specific context which the number should be checked against * @param useExactMatch if true, consider a number to be an emergency * number only if it *exactly* matches a number listed in * the RIL / SIM. If false, a number is considered to be an @@ -1797,9 +1973,34 @@ public class PhoneNumberUtils * local country, based on the CountryDetector. * * @see android.location.CountryDetector + * @hide */ - private static boolean isLocalEmergencyNumberInternal(Context context, - String number, + private static boolean isLocalEmergencyNumberInternal(String number, + Context context, + boolean useExactMatch) { + return isLocalEmergencyNumberInternal(getDefaultVoiceSubId(), number, context, + useExactMatch); + } + + /** + * Helper function for isLocalEmergencyNumber() and + * isPotentialLocalEmergencyNumber(). + * + * @param subId the subscription id of the SIM. + * @param number the number to look up. + * @param context the specific context which the number should be checked against + * @param useExactMatch if true, consider a number to be an emergency + * number only if it *exactly* matches a number listed in + * the RIL / SIM. If false, a number is considered to be an + * emergency number if it simply starts with the same digits + * as any of the emergency numbers listed in the RIL / SIM. + * + * @return true if the specified number is an emergency number for a + * local country, based on the CountryDetector. + * @hide + */ + private static boolean isLocalEmergencyNumberInternal(long subId, String number, + Context context, boolean useExactMatch) { String countryIso; CountryDetector detector = (CountryDetector) context.getSystemService( @@ -1812,7 +2013,7 @@ public class PhoneNumberUtils Rlog.w(LOG_TAG, "No CountryDetector; falling back to countryIso based on locale: " + countryIso); } - return isEmergencyNumberInternal(number, countryIso, useExactMatch); + return isEmergencyNumberInternal(subId, number, countryIso, useExactMatch); } /** @@ -1826,10 +2027,26 @@ public class PhoneNumberUtils * to read the VM number. */ public static boolean isVoiceMailNumber(String number) { + return isVoiceMailNumber(SubscriptionManager.getDefaultSubId(), number); + } + + /** + * isVoiceMailNumber: checks a given number against the voicemail + * number provided by the RIL and SIM card. The caller must have + * the READ_PHONE_STATE credential. + * + * @param subId the subscription id of the SIM. + * @param number the number to look up. + * @return true if the number is in the list of voicemail. False + * otherwise, including if the caller does not have the permission + * to read the VM number. + * @hide + */ + public static boolean isVoiceMailNumber(long subId, String number) { String vmNumber; try { - vmNumber = TelephonyManager.getDefault().getVoiceMailNumber(); + vmNumber = TelephonyManager.getDefault().getVoiceMailNumber(subId); } catch (SecurityException ex) { return false; } @@ -2561,5 +2778,11 @@ public class PhoneNumberUtils return true; } + /** + * Returns Default voice subscription Id. + */ + private static long getDefaultVoiceSubId() { + return SubscriptionManager.getDefaultVoiceSubId(); + } //==== End of utility methods used only in compareStrictly() ===== } diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 59ec6f5..c8c3063 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -20,11 +20,13 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.telephony.ServiceState; -import android.telephony.SignalStrength; import android.telephony.CellLocation; import android.telephony.CellInfo; +import android.telephony.VoLteServiceState; import android.telephony.Rlog; +import android.telephony.ServiceState; +import android.telephony.SignalStrength; +import android.telephony.SubscriptionManager; import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; @@ -48,6 +50,7 @@ import java.util.List; * appropriate LISTEN_ flags. */ public class PhoneStateListener { + private static final String TAG = "PhoneStateListener"; /** * Stop listening for updates. @@ -200,18 +203,42 @@ public class PhoneStateListener { */ public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO = 0x00002000; + /** + * Listen for changes to LTE network state + * + * @see #onLteNetworkStateChanged + * @hide + */ + public static final int LISTEN_VOLTE_STATE = 0x00004000; + + /* + * Subscription used to listen to the phone state changes + * @hide + */ + /** @hide */ + protected long mSubId = 0; + private final Handler mHandler; public PhoneStateListener() { - this(Looper.myLooper()); + this(SubscriptionManager.DEFAULT_SUB_ID, Looper.myLooper()); + } + + /** + * @hide + */ + public PhoneStateListener(long subId) { + this(subId, Looper.myLooper()); } /** @hide */ - public PhoneStateListener(Looper looper) { + public PhoneStateListener(long subId, Looper looper) { + Rlog.d(TAG, "ctor: subId=" + subId + " looper=" + looper); + mSubId = subId; mHandler = new Handler(looper) { public void handleMessage(Message msg) { - //Rlog.d("TelephonyRegistry", "what=0x" + Integer.toHexString(msg.what) - // + " msg=" + msg); + Rlog.d(TAG, "mSubId=" + mSubId + " what=0x" + Integer.toHexString(msg.what) + + " msg=" + msg); switch (msg.what) { case LISTEN_SERVICE_STATE: PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj); @@ -258,6 +285,9 @@ public class PhoneStateListener { PhoneStateListener.this.onDataConnectionRealTimeInfoChanged( (DataConnectionRealTimeInfo)msg.obj); break; + case LISTEN_VOLTE_STATE: + PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj); + break; } } }; @@ -417,6 +447,15 @@ public class PhoneStateListener { } /** + * Callback invoked when the service state of LTE network + * related to the VoLTE service has changed. + * @param stateInfo is the current LTE network information + * @hide + */ + public void onVoLteServiceStateChanged(VoLteServiceState stateInfo) { + } + + /** * The callback methods need to be called on the handler thread where * this object was created. If the binder did that for us it'd be nice. */ @@ -484,5 +523,9 @@ public class PhoneStateListener { Message.obtain(mHandler, LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0, dcRtInfo).sendToTarget(); } + + public void onVoLteServiceStateChanged(VoLteServiceState lteState) { + Message.obtain(mHandler, LISTEN_VOLTE_STATE, 0, 0, lteState).sendToTarget(); + } }; } diff --git a/telephony/java/android/telephony/SubInfoRecord.aidl b/telephony/java/android/telephony/SubInfoRecord.aidl new file mode 100755 index 0000000..a2de676 --- /dev/null +++ b/telephony/java/android/telephony/SubInfoRecord.aidl @@ -0,0 +1,19 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* 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; + +parcelable SubInfoRecord; diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java new file mode 100644 index 0000000..670def7 --- /dev/null +++ b/telephony/java/android/telephony/SubInfoRecord.java @@ -0,0 +1,108 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* 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; + +/** + * A parcelable holder class of byte[] for ISms aidl implementation + * @hide + */ + +public class SubInfoRecord implements Parcelable { + + public long mSubId; + public String mIccId; + public int mSlotId; + public String mDisplayName; + public int mNameSource; + public int mColor; + public String mNumber; + public int mDispalyNumberFormat; + public int mDataRoaming; + public int[] mSimIconRes; + + public SubInfoRecord() { + this.mSubId = -1; + this.mIccId = ""; + this.mSlotId = -1; + this.mDisplayName = ""; + this.mNameSource = 0; + this.mColor = 0; + this.mNumber = ""; + this.mDispalyNumberFormat = 0; + this.mDataRoaming = 0; + this.mSimIconRes = new int[2]; + } + + + public SubInfoRecord(long subId, String iccId, int slotId, String displayname, int nameSource, + int mColor, String mNumber, int displayFormat, int roaming, int[] iconRes) { + this.mSubId = subId; + this.mIccId = iccId; + this.mSlotId = slotId; + this.mDisplayName = displayname; + this.mNameSource = nameSource; + this.mColor = mColor; + this.mNumber = mNumber; + this.mDispalyNumberFormat = displayFormat; + this.mDataRoaming = roaming; + this.mSimIconRes = iconRes; + } + + public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() { + public SubInfoRecord createFromParcel(Parcel source) { + long mSubId = source.readLong(); + String mIccId = source.readString(); + int mSlotId = source.readInt(); + String mDisplayName = source.readString(); + int mNameSource = source.readInt(); + int mColor = source.readInt(); + String mNumber = source.readString(); + int mDispalyNumberFormat = source.readInt(); + int mDataRoaming = source.readInt(); + int[] iconRes = new int[2]; + source.readIntArray(iconRes); + + return new SubInfoRecord(mSubId, mIccId, mSlotId, mDisplayName, mNameSource, mColor, mNumber, + mDispalyNumberFormat, mDataRoaming, iconRes); + } + + public SubInfoRecord[] newArray(int size) { + return new SubInfoRecord[size]; + } + }; + + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mSubId); + dest.writeString(mIccId); + dest.writeInt(mSlotId); + dest.writeString(mDisplayName); + dest.writeInt(mNameSource); + dest.writeInt(mColor); + dest.writeString(mNumber); + dest.writeInt(mDispalyNumberFormat); + dest.writeInt(mDataRoaming); + dest.writeIntArray(mSimIconRes); + } + + public int describeContents() { + return 0; + } + +} diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java new file mode 100644 index 0000000..859a890 --- /dev/null +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -0,0 +1,708 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* 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 static android.Manifest.permission.READ_PHONE_STATE; + +import android.app.ActivityManagerNative; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.os.UserHandle; +import android.net.Uri; +import android.provider.BaseColumns; +import android.telephony.Rlog; +import android.os.ServiceManager; +import android.os.RemoteException; + +import com.android.internal.telephony.ISub; +import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.TelephonyIntents; + +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; + +/** + *@hide + */ +public class SubscriptionManager implements BaseColumns { + private static final String LOG_TAG = "SUB"; + private static final boolean DBG = true; + private static final boolean VDBG = false; + + // An invalid subscription identifier + public static final long INVALID_SUB_ID = Long.MAX_VALUE; + + // The default subscription identifier + public static final long DEFAULT_SUB_ID = Long.MAX_VALUE - 1; + + public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo"); + + public static final int DEFAULT_INT_VALUE = -100; + + public static final String DEFAULT_STRING_VALUE = "N/A"; + + public static final int EXTRA_VALUE_NEW_SIM = 1; + public static final int EXTRA_VALUE_REMOVE_SIM = 2; + public static final int EXTRA_VALUE_REPOSITION_SIM = 3; + public static final int EXTRA_VALUE_NOCHANGE = 4; + + public static final String INTENT_KEY_DETECT_STATUS = "simDetectStatus"; + public static final String INTENT_KEY_SIM_COUNT = "simCount"; + public static final String INTENT_KEY_NEW_SIM_SLOT = "newSIMSlot"; + public static final String INTENT_KEY_NEW_SIM_STATUS = "newSIMStatus"; + + /** + * The ICC ID of a SIM. + * <P>Type: TEXT (String)</P> + */ + public static final String ICC_ID = "icc_id"; + + /** + * <P>Type: INTEGER (int)</P> + */ + public static final String SIM_ID = "sim_id"; + + public static final int SIM_NOT_INSERTED = -1; + + /** + * The display name of a SIM. + * <P>Type: TEXT (String)</P> + */ + public static final String DISPLAY_NAME = "display_name"; + + public static final int DEFAULT_NAME_RES = com.android.internal.R.string.unknownName; + + /** + * The display name source of a SIM. + * <P>Type: INT (int)</P> + */ + public static final String NAME_SOURCE = "name_source"; + + public static final int DEFAULT_SOURCE = 0; + + public static final int SIM_SOURCE = 1; + + public static final int USER_INPUT = 2; + + /** + * The color of a SIM. + * <P>Type: INTEGER (int)</P> + */ + public static final String COLOR = "color"; + + public static final int COLOR_1 = 0; + + public static final int COLOR_2 = 1; + + public static final int COLOR_3 = 2; + + public static final int COLOR_4 = 3; + + public static final int COLOR_DEFAULT = COLOR_1; + + /** + * The phone number of a SIM. + * <P>Type: TEXT (String)</P> + */ + public static final String NUMBER = "number"; + + /** + * The number display format of a SIM. + * <P>Type: INTEGER (int)</P> + */ + public static final String DISPLAY_NUMBER_FORMAT = "display_number_format"; + + public static final int DISPALY_NUMBER_NONE = 0; + + public static final int DISPLAY_NUMBER_FIRST = 1; + + public static final int DISPLAY_NUMBER_LAST = 2; + + public static final int DISLPAY_NUMBER_DEFAULT = DISPLAY_NUMBER_FIRST; + + /** + * Permission for data roaming of a SIM. + * <P>Type: INTEGER (int)</P> + */ + public static final String DATA_ROAMING = "data_roaming"; + + public static final int DATA_ROAMING_ENABLE = 1; + + public static final int DATA_ROAMING_DISABLE = 0; + + public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE; + + private static final int RES_TYPE_BACKGROUND_DARK = 0; + + private static final int RES_TYPE_BACKGROUND_LIGHT = 1; + + private static final int[] sSimBackgroundDarkRes = setSimResource(RES_TYPE_BACKGROUND_DARK); + + private static final int[] sSimBackgroundLightRes = setSimResource(RES_TYPE_BACKGROUND_LIGHT); + + private static HashMap<Integer, Long> mSimInfo = new HashMap<Integer, Long>(); + + public SubscriptionManager() { + if (DBG) logd("SubscriptionManager created"); + } + + /** + * Get the SubInfoRecord according to an index + * @param context Context provided by caller + * @param subId The unique SubInfoRecord index in database + * @return SubInfoRecord, maybe null + */ + public static SubInfoRecord getSubInfoUsingSubId(Context context, long subId) { + if (VDBG) logd("[getSubInfoUsingSubIdx]+ subId:" + subId); + if (subId <= 0) { + if (VDBG) logd("[getSubInfoUsingSubIdx]- subId <= 0"); + return null; + } + + SubInfoRecord subInfo = null; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + subInfo = iSub.getSubInfoUsingSubId(subId); + } + } catch (RemoteException ex) { + // ignore it + } + + return subInfo; + + } + + /** + * Get the SubInfoRecord according to an IccId + * @param context Context provided by caller + * @param iccId the IccId of SIM card + * @return SubInfoRecord, maybe null + */ + public static List<SubInfoRecord> getSubInfoUsingIccId(Context context, String iccId) { + if (VDBG) logd("[getSubInfoUsingIccId]+ iccId=" + iccId); + if (iccId == null) { + logd("[getSubInfoUsingIccId]- null iccid"); + return null; + } + + List<SubInfoRecord> result = null; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.getSubInfoUsingIccId(iccId); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + } + + /** + * Get the SubInfoRecord according to slotId + * @param context Context provided by caller + * @param slotId the slot which the SIM is inserted + * @return SubInfoRecord, maybe null + */ + public static List<SubInfoRecord> getSubInfoUsingSlotId(Context context, int slotId) { + if (VDBG) logd("[getSubInfoUsingSlotId]- slotId=" + slotId); + if (slotId < 0) { + logd("[getSubInfoUsingSlotId]- return null, slotId < 0"); + return null; + } + + List<SubInfoRecord> result = null; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.getSubInfoUsingSlotId(slotId); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + } + + /** + * Get all the SubInfoRecord(s) in subinfo database + * @param context Context provided by caller + * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before + */ + public static List<SubInfoRecord> getAllSubInfoList(Context context) { + if (VDBG) logd("[getAllSubInfoList]+"); + + List<SubInfoRecord> result = null; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.getAllSubInfoList(); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + } + + /** + * Get the SubInfoRecord(s) of the currently inserted SIM(s) + * @param context Context provided by caller + * @return Array list of currently inserted SubInfoRecord(s) + */ + public static List<SubInfoRecord> getActivatedSubInfoList(Context context) { + if (VDBG) logd("[getActivatedSubInfoList]+"); + + List<SubInfoRecord> result = null; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.getActivatedSubInfoList(); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + } + + /** + * Get the SUB count of all SUB(s) in subinfo database + * @param context Context provided by caller + * @return all SIM count in database, include what was inserted before + */ + public static int getAllSubInfoCount(Context context) { + if (VDBG) logd("[getAllSubInfoCount]+"); + + int result = 0; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.getAllSubInfoCount(); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + } + + /** + * Add a new SubInfoRecord to subinfo database if needed + * @param context Context provided by caller + * @param iccId the IccId of the SIM card + * @param slotId the slot which the SIM is inserted + * @return the URL of the newly created row or the updated row + */ + public static Uri addSubInfoRecord(Context context, String iccId, int slotId) { + if (VDBG) logd("[addSubInfoRecord]+ iccId:" + iccId + " slotId:" + slotId); + if (iccId == null) { + logd("[addSubInfoRecord]- null iccId"); + } + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + // FIXME: This returns 1 on success, 0 on error should should we return it? + iSub.addSubInfoRecord(iccId, slotId); + } + } catch (RemoteException ex) { + // ignore it + } + + // FIXME: Always returns null? + return null; + + } + + /** + * Set SIM color by simInfo index + * @param context Context provided by caller + * @param color the color of the SIM + * @param subId the unique SubInfoRecord index in database + * @return the number of records updated + */ + public static int setColor(Context context, int color, long subId) { + if (VDBG) logd("[setColor]+ color:" + color + " subId:" + subId); + int size = sSimBackgroundDarkRes.length; + if (subId <= 0 || color < 0 || color >= size) { + logd("[setColor]- fail"); + return -1; + } + + int result = 0; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.setColor(color, subId); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + + } + + /** + * Set display name by simInfo index + * @param context Context provided by caller + * @param displayName the display name of SIM card + * @param subId the unique SubInfoRecord index in database + * @return the number of records updated + */ + public static int setDisplayName(Context context, String displayName, long subId) { + return setDisplayName(context, displayName, subId, -1); + } + + /** + * Set display name by simInfo index with name source + * @param context Context provided by caller + * @param displayName the display name of SIM card + * @param subId the unique SubInfoRecord index in database + * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT + * @return the number of records updated + */ + public static int setDisplayName(Context context, String displayName, long subId, long nameSource) { + if (VDBG) logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId + " nameSource:" + nameSource); + if (subId <= 0) { + logd("[setDisplayName]- fail"); + return -1; + } + + int result = 0; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.setDisplayNameUsingSrc(displayName, subId, nameSource); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + + } + + /** + * Set phone number by subId + * @param context Context provided by caller + * @param number the phone number of the SIM + * @param subId the unique SubInfoRecord index in database + * @return the number of records updated + */ + public static int setDispalyNumber(Context context, String number, long subId) { + if (VDBG) logd("[setDispalyNumber]+ number:" + number + " subId:" + subId); + if (number == null || subId <= 0) { + logd("[setDispalyNumber]- fail"); + return -1; + } + + int result = 0; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.setDispalyNumber(number, subId); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + + } + + /** + * Set number display format. 0: none, 1: the first four digits, 2: the last four digits + * @param context Context provided by caller + * @param format the display format of phone number + * @param subId the unique SubInfoRecord index in database + * @return the number of records updated + */ + public static int setDisplayNumberFormat(Context context, int format, long subId) { + if (VDBG) logd("[setDisplayNumberFormat]+ format:" + format + " subId:" + subId); + if (format < 0 || subId <= 0) { + logd("[setDisplayNumberFormat]- fail, return -1"); + return -1; + } + + int result = 0; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.setDisplayNumberFormat(format, subId); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + + } + + /** + * Set data roaming by simInfo index + * @param context Context provided by caller + * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming + * @param subId the unique SubInfoRecord index in database + * @return the number of records updated + */ + public static int setDataRoaming(Context context, int roaming, long subId) { + if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId); + if (roaming < 0 || subId <= 0) { + logd("[setDataRoaming]- fail"); + return -1; + } + + int result = 0; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.setDataRoaming(roaming, subId); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + } + + public static int getSlotId(long subId) { + if (VDBG) logd("[getSlotId]+ subId:" + subId); + + int result = 0; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.getSlotId(subId); + } + } catch (RemoteException ex) { + // ignore it + } + + return result; + + } + + public static long[] getSubId(int slotId) { + if (VDBG) logd("[getSubId]+ slotId:" + slotId); + + long[] subId = null; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + subId = iSub.getSubId(slotId); + } + } catch (RemoteException ex) { + // ignore it + } + + return subId; + } + + public static int getPhoneId(long subId) { + if (VDBG) logd("[getPhoneId]+ subId=" + subId); + + int result = 0; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + result = iSub.getPhoneId(subId); + } + } catch (RemoteException ex) { + // ignore it + } + + if (VDBG) logd("[getPhoneId]- phonId=" + result); + return result; + + } + + private static int[] setSimResource(int type) { + int[] simResource = null; + + switch (type) { + case RES_TYPE_BACKGROUND_DARK: + simResource = new int[] { + com.android.internal.R.drawable.sim_dark_blue, + com.android.internal.R.drawable.sim_dark_orange, + com.android.internal.R.drawable.sim_dark_green, + com.android.internal.R.drawable.sim_dark_purple + }; + break; + case RES_TYPE_BACKGROUND_LIGHT: + simResource = new int[] { + com.android.internal.R.drawable.sim_light_blue, + com.android.internal.R.drawable.sim_light_orange, + com.android.internal.R.drawable.sim_light_green, + com.android.internal.R.drawable.sim_light_purple + }; + break; + } + + return simResource; + } + + private static void logd(String msg) { + Rlog.d(LOG_TAG, "[SubManager] " + msg); + } + + public static long normalizeSubId(long subId) { + long retVal = (subId == DEFAULT_SUB_ID) ? getDefaultSubId() : subId; + Rlog.d(LOG_TAG, "[SubManager] normalizeSubId subId=" + retVal); + return retVal; + } + + public static boolean validSubId(long subId) { + return (subId != DEFAULT_SUB_ID) && (subId != -1); + } + + /** + * @return the "system" defaultSubId on a voice capable device this + * will be getDefaultVoiceSubId() and on a data only device it will be + * getDefaultDataSubId(). + */ + public static long getDefaultSubId() { + long subId = 1; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + subId = iSub.getDefaultSubId(); + } + } catch (RemoteException ex) { + // ignore it + } + + if (VDBG) logd("getDefaultSubId=" + subId); + return subId; + } + + public static long getDefaultVoiceSubId() { + long subId = 1; + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + subId = iSub.getDefaultVoiceSubId(); + } + } catch (RemoteException ex) { + // ignore it + } + + if (VDBG) logd("getDefaultSubId, sub id = " + subId); + return subId; + } + + public static void setDefaultVoiceSubId(long subId) { + if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId); + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + iSub.setDefaultVoiceSubId(subId); + } + } catch (RemoteException ex) { + // ignore it + } + } + + public static long getPreferredSmsSubId() { + // FIXME add framework support to get the preferred sub + return getDefaultSubId(); + } + + public static long getPreferredDataSubId() { + // FIXME add framework support to get the preferred sub + return getDefaultSubId(); + } + + public static long getDefaultDataSubId() { + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + return iSub.getDefaultDataSubId(); + } else { + return -1; + } + } catch (RemoteException ex) { + return -1; + } + } + + public static void setDefaultDataSubId(long subId) { + if (VDBG) logd("setDataSubscription sub id = " + subId); + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + iSub.setDefaultDataSubId(subId); + } + } catch (RemoteException ex) { + // ignore it + } + } + + public static void clearSubInfo() + { + if (VDBG) logd("[clearSubInfo]+"); + + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + iSub.clearSubInfo(); + } + } catch (RemoteException ex) { + // ignore it + } + + return; + } + + public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) { + long [] subId = SubscriptionManager.getSubId(phoneId); + if ((subId != null) && (subId.length >= 1)) { + if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId); + intent.putExtra(PhoneConstants.SLOT_KEY, phoneId); //FIXME: RENAME TO PHONE_ID_KEY ?? + intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId[0]); + } else { + logd("putPhoneIdAndSubIdExtra: no valid subs"); + } + } +} + diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 3f65bca..aaee99f 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -86,6 +86,22 @@ public class TelephonyManager { private final Context mContext; + private static String multiSimConfig = + SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG); + + /** Enum indicating multisim variants + * DSDS - Dual SIM Dual Standby + * DSDA - Dual SIM Dual Active + * TSTS - Triple SIM Triple Standby + **/ + /** @hide */ + public enum MultiSimVariants { + DSDS, + DSDA, + TSTS, + UNKNOWN + }; + /** @hide */ public TelephonyManager(Context context) { Context appContext = context.getApplicationContext(); @@ -114,11 +130,61 @@ public class TelephonyManager { return sInstance; } + + /** + * Returns the multi SIM variant + * Returns DSDS for Dual SIM Dual Standby + * Returns DSDA for Dual SIM Dual Active + * Returns TSTS for Triple SIM Triple Standby + * Returns UNKNOWN for others + */ + /** {@hide} */ + public MultiSimVariants getMultiSimConfiguration() { + String mSimConfig = + SystemProperties.get(TelephonyProperties.PROPERTY_MULTI_SIM_CONFIG); + if (mSimConfig.equals("dsds")) { + return MultiSimVariants.DSDS; + } else if (mSimConfig.equals("dsda")) { + return MultiSimVariants.DSDA; + } else if (mSimConfig.equals("tsts")) { + return MultiSimVariants.TSTS; + } else { + return MultiSimVariants.UNKNOWN; + } + } + + + /** + * Returns the number of phones available. + * Returns 1 for Single standby mode (Single SIM functionality) + * Returns 2 for Dual standby mode.(Dual SIM functionality) + */ + /** {@hide} */ + public int getPhoneCount() { + int phoneCount = 1; + switch (getMultiSimConfiguration()) { + case DSDS: + case DSDA: + phoneCount = PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM; + break; + case TSTS: + phoneCount = PhoneConstants.MAX_PHONE_COUNT_TRI_SIM; + break; + } + return phoneCount; + } + /** {@hide} */ public static TelephonyManager from(Context context) { return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); } + /** {@hide} */ + public boolean isMultiSimEnabled() { + return (multiSimConfig.equals("dsds") || multiSimConfig.equals("dsda") || + multiSimConfig.equals("tsts")); + } + // // Broadcast Intent actions // @@ -529,8 +595,23 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceId() { + return getDeviceId(getDefaultSim()); + } + + /** + * Returns the unique device ID of a subscription, for example, the IMEI for + * GSM and the MEID for CDMA phones. Return null if device ID is not available. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * + * @param slotId of which deviceID is returned + */ + /** {@hide} */ + public String getDeviceId(int slotId) { + long[] subId = SubscriptionManager.getSubId(slotId); try { - return getSubscriberInfo().getDeviceId(); + return getSubscriberInfo().getDeviceIdUsingSubId(subId[0]); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -578,8 +659,23 @@ public class TelephonyManager { * @hide */ public void enableLocationUpdates() { + enableLocationUpdates(getDefaultSubscription()); + } + + /** + * Enables location update notifications for a subscription. + * {@link PhoneStateListener#onCellLocationChanged + * PhoneStateListener.onCellLocationChanged} will be called on location updates. + * + * <p>Requires Permission: {@link android.Manifest.permission#CONTROL_LOCATION_UPDATES + * CONTROL_LOCATION_UPDATES} + * + * @param subId for which the location updates are enabled + */ + /** @hide */ + public void enableLocationUpdates(long subId) { try { - getITelephony().enableLocationUpdates(); + getITelephony().enableLocationUpdatesUsingSubId(subId); } catch (RemoteException ex) { } catch (NullPointerException ex) { } @@ -595,8 +691,13 @@ public class TelephonyManager { * @hide */ public void disableLocationUpdates() { + disableLocationUpdates(getDefaultSubscription()); + } + + /** @hide */ + public void disableLocationUpdates(long subId) { try { - getITelephony().disableLocationUpdates(); + getITelephony().disableLocationUpdatesUsingSubId(subId); } catch (RemoteException ex) { } catch (NullPointerException ex) { } @@ -644,22 +745,37 @@ public class TelephonyManager { * {@hide} */ public int getCurrentPhoneType() { + return getCurrentPhoneType(getDefaultSubscription()); + } + + /** + * Returns a constant indicating the device phone type for a subscription. + * + * @see #PHONE_TYPE_NONE + * @see #PHONE_TYPE_GSM + * @see #PHONE_TYPE_CDMA + * + * @param subId for which phone type is returned + */ + /** {@hide} */ + public int getCurrentPhoneType(long subId) { + try{ ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getActivePhoneType(); + return telephony.getActivePhoneTypeUsingSubId(subId); } else { // This can happen when the ITelephony interface is not up yet. - return getPhoneTypeFromProperty(); + return getPhoneTypeFromProperty(subId); } } catch (RemoteException ex) { // This shouldn't happen in the normal case, as a backup we // read from the system property. - return getPhoneTypeFromProperty(); + return getPhoneTypeFromProperty(subId); } catch (NullPointerException ex) { // This shouldn't happen in the normal case, as a backup we // read from the system property. - return getPhoneTypeFromProperty(); + return getPhoneTypeFromProperty(subId); } } @@ -680,20 +796,35 @@ public class TelephonyManager { } private int getPhoneTypeFromProperty() { - int type = - SystemProperties.getInt(TelephonyProperties.CURRENT_ACTIVE_PHONE, - getPhoneTypeFromNetworkType()); - return type; + return getPhoneTypeFromProperty(getDefaultSubscription()); + } + + /** {@hide} */ + private int getPhoneTypeFromProperty(long subId) { + String type = + getTelephonyProperty + (TelephonyProperties.CURRENT_ACTIVE_PHONE, subId, null); + if (type != null) { + return (Integer.parseInt(type)); + } else { + return getPhoneTypeFromNetworkType(subId); + } } private int getPhoneTypeFromNetworkType() { + return getPhoneTypeFromNetworkType(getDefaultSubscription()); + } + + /** {@hide} */ + private int getPhoneTypeFromNetworkType(long subId) { // When the system property CURRENT_ACTIVE_PHONE, has not been set, // use the system property for default network type. // This is a fail safe, and can only happen at first boot. - int mode = SystemProperties.getInt("ro.telephony.default_network", -1); - if (mode == -1) - return PHONE_TYPE_NONE; - return getPhoneType(mode); + String mode = getTelephonyProperty("ro.telephony.default_network", subId, null); + if (mode != null) { + return TelephonyManager.getPhoneType(Integer.parseInt(mode)); + } + return TelephonyManager.PHONE_TYPE_NONE; } /** @@ -828,7 +959,23 @@ public class TelephonyManager { * on a CDMA network). */ public String getNetworkOperatorName() { - return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ALPHA); + return getNetworkOperatorName(getDefaultSubscription()); + } + + /** + * Returns the alphabetic name of current registered operator + * for a particular subscription. + * <p> + * Availability: Only when user is registered to a network. Result may be + * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if + * on a CDMA network). + * @param subId + */ + /** {@hide} */ + public String getNetworkOperatorName(long subId) { + + return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, + subId, ""); } /** @@ -839,17 +986,48 @@ public class TelephonyManager { * on a CDMA network). */ public String getNetworkOperator() { - return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC); + return getNetworkOperator(getDefaultSubscription()); } /** + * Returns the numeric name (MCC+MNC) of current registered operator + * for a particular subscription. + * <p> + * Availability: Only when user is registered to a network. Result may be + * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if + * on a CDMA network). + * + * @param subId + */ + /** {@hide} */ + public String getNetworkOperator(long subId) { + + return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, + subId, ""); + } + + /** * Returns true if the device is considered roaming on the current * network, for GSM purposes. * <p> * Availability: Only when user registered to a network. */ public boolean isNetworkRoaming() { - return "true".equals(SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING)); + return isNetworkRoaming(getDefaultSubscription()); + } + + /** + * Returns true if the device is considered roaming on the current + * network for a subscription. + * <p> + * Availability: Only when user registered to a network. + * + * @param subId + */ + /** {@hide} */ + public boolean isNetworkRoaming(long subId) { + return "true".equals(getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, + subId, null)); } /** @@ -861,7 +1039,23 @@ public class TelephonyManager { * on a CDMA network). */ public String getNetworkCountryIso() { - return SystemProperties.get(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY); + return getNetworkCountryIso(getDefaultSubscription()); + } + + /** + * Returns the ISO country code equivalent of the current registered + * operator's MCC (Mobile Country Code) of a subscription. + * <p> + * Availability: Only when user is registered to a network. Result may be + * unreliable on CDMA networks (use {@link #getPhoneType()} to determine if + * on a CDMA network). + * + * @param subId for which Network CountryIso is returned + */ + /** {@hide} */ + public String getNetworkCountryIso(long subId) { + return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, + subId, ""); } /** Network type is unknown */ @@ -908,6 +1102,49 @@ public class TelephonyManager { /** * Returns a constant indicating the radio technology (network type) + * currently in use on the device for a subscription. + * @return the network type + * + * @param subId for which network type is returned + * + * @see #NETWORK_TYPE_UNKNOWN + * @see #NETWORK_TYPE_GPRS + * @see #NETWORK_TYPE_EDGE + * @see #NETWORK_TYPE_UMTS + * @see #NETWORK_TYPE_HSDPA + * @see #NETWORK_TYPE_HSUPA + * @see #NETWORK_TYPE_HSPA + * @see #NETWORK_TYPE_CDMA + * @see #NETWORK_TYPE_EVDO_0 + * @see #NETWORK_TYPE_EVDO_A + * @see #NETWORK_TYPE_EVDO_B + * @see #NETWORK_TYPE_1xRTT + * @see #NETWORK_TYPE_IDEN + * @see #NETWORK_TYPE_LTE + * @see #NETWORK_TYPE_EHRPD + * @see #NETWORK_TYPE_HSPAP + */ + /** {@hide} */ + public int getNetworkType(long subId) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getNetworkTypeUsingSubId(subId); + } else { + // This can happen when the ITelephony interface is not up yet. + return NETWORK_TYPE_UNKNOWN; + } + } catch(RemoteException ex) { + // This shouldn't happen in the normal case + return NETWORK_TYPE_UNKNOWN; + } catch (NullPointerException ex) { + // This could happen before phone restarts due to crashing + return NETWORK_TYPE_UNKNOWN; + } + } + + /** + * Returns a constant indicating the radio technology (network type) * currently in use on the device for data transmission. * @return the network type * @@ -931,10 +1168,22 @@ public class TelephonyManager { * @hide */ public int getDataNetworkType() { + return getDataNetworkType(getDefaultSubscription()); + } + + /** + * Returns a constant indicating the radio technology (network type) + * currently in use on the device for data transmission for a subscription + * @return the network type + * + * @param subId for which network type is returned + */ + /** {@hide} */ + public int getDataNetworkType(long subId) { try{ ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getDataNetworkType(); + return telephony.getDataNetworkTypeUsingSubId(subId); } else { // This can happen when the ITelephony interface is not up yet. return NETWORK_TYPE_UNKNOWN; @@ -954,10 +1203,19 @@ public class TelephonyManager { * @hide */ public int getVoiceNetworkType() { + return getVoiceNetworkType(getDefaultSubscription()); + } + + /** + * Returns the NETWORK_TYPE_xxxx for voice for a subId + * + */ + /** {@hide} */ + public int getVoiceNetworkType(long subId) { try{ ITelephony telephony = getITelephony(); if (telephony != null) { - return telephony.getVoiceNetworkType(); + return telephony.getVoiceNetworkTypeUsingSubId(subId); } else { // This can happen when the ITelephony interface is not up yet. return NETWORK_TYPE_UNKNOWN; @@ -1023,6 +1281,13 @@ public class TelephonyManager { return getNetworkTypeName(getNetworkType()); } + /** + * Returns a string representation of the radio technology (network type) + * currently in use on the device. + * @param subId for which network type is returned + * @return the name of the radio technology + * + */ /** {@hide} */ public static String getNetworkTypeName(int type) { switch (type) { @@ -1093,8 +1358,20 @@ public class TelephonyManager { * @return true if a ICC card is present */ public boolean hasIccCard() { + return hasIccCard(getDefaultSim()); + } + + /** + * @return true if a ICC card is present for a subscription + * + * @param slotId for which icc card presence is checked + */ + /** {@hide} */ + // FIXME Input argument slotId should be of type int + public boolean hasIccCard(long slotId) { + try { - return getITelephony().hasIccCard(); + return getITelephony().hasIccCardUsingSlotId(slotId); } catch (RemoteException ex) { // Assume no ICC card if remote exception which shouldn't happen return false; @@ -1117,7 +1394,30 @@ public class TelephonyManager { * @see #SIM_STATE_CARD_IO_ERROR */ public int getSimState() { - String prop = SystemProperties.get(TelephonyProperties.PROPERTY_SIM_STATE); + return getSimState(getDefaultSim()); + } + + /** + * Returns a constant indicating the state of the + * device SIM card in a slot. + * + * @param slotId + * + * @see #SIM_STATE_UNKNOWN + * @see #SIM_STATE_ABSENT + * @see #SIM_STATE_PIN_REQUIRED + * @see #SIM_STATE_PUK_REQUIRED + * @see #SIM_STATE_NETWORK_LOCKED + * @see #SIM_STATE_READY + */ + /** {@hide} */ + // FIXME the argument to pass is subId ?? + public int getSimState(int slotId) { + long[] subId = SubscriptionManager.getSubId(slotId); + // FIXME Do not use a property to determine SIM_STATE, call + // appropriate method on some object. + String prop = + getTelephonyProperty(TelephonyProperties.PROPERTY_SIM_STATE, subId[0], ""); if ("ABSENT".equals(prop)) { return SIM_STATE_ABSENT; } @@ -1150,7 +1450,27 @@ public class TelephonyManager { * @see #getSimState */ public String getSimOperator() { - return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC); + long subId = getDefaultSubscription(); + Rlog.d(TAG, "getSimOperator(): default subId=" + subId); + return getSimOperator(subId); + } + + /** + * Returns the MCC+MNC (mobile country code + mobile network code) of the + * provider of the SIM for a particular subscription. 5 or 6 decimal digits. + * <p> + * Availability: SIM state must be {@link #SIM_STATE_READY} + * + * @see #getSimState + * + * @param subId for which SimOperator is returned + */ + /** {@hide} */ + public String getSimOperator(long subId) { + String operator = getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, + subId, ""); + Rlog.d(TAG, "getSimOperator: subId=" + subId + " operator=" + operator); + return operator; } /** @@ -1161,14 +1481,40 @@ public class TelephonyManager { * @see #getSimState */ public String getSimOperatorName() { - return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA); + return getSimOperatorName(getDefaultSubscription()); + } + + /** + * Returns the Service Provider Name (SPN). + * <p> + * Availability: SIM state must be {@link #SIM_STATE_READY} + * + * @see #getSimState + * + * @param subId for which SimOperatorName is returned + */ + /** {@hide} */ + public String getSimOperatorName(long subId) { + return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, + subId, ""); } /** * Returns the ISO country code equivalent for the SIM provider's country code. */ public String getSimCountryIso() { - return SystemProperties.get(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY); + return getSimCountryIso(getDefaultSubscription()); + } + + /** + * Returns the ISO country code equivalent for the SIM provider's country code. + * + * @param subId for which SimCountryIso is returned + */ + /** {@hide} */ + public String getSimCountryIso(long subId) { + return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY, + subId, ""); } /** @@ -1179,8 +1525,21 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getSimSerialNumber() { + return getSimSerialNumber(getDefaultSubscription()); + } + + /** + * Returns the serial number for the given subscription, if applicable. Return null if it is + * unavailable. + * <p> + * @param subId for which Sim Serial number is returned + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + */ + /** {@hide} */ + public String getSimSerialNumber(long subId) { try { - return getSubscriberInfo().getIccSerialNumber(); + return getSubscriberInfo().getIccSerialNumberUsingSubId(subId); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1200,8 +1559,23 @@ public class TelephonyManager { * @hide */ public int getLteOnCdmaMode() { + return getLteOnCdmaMode(getDefaultSubscription()); + } + + /** + * Return if the current radio is LTE on CDMA for Subscription. This + * is a tri-state return value as for a period of time + * the mode may be unknown. + * + * @param subId for which radio is LTE on CDMA is returned + * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE} + * or {@link PhoneConstants#LTE_ON_CDMA_TRUE} + * + */ + /** {@hide} */ + public int getLteOnCdmaMode(long subId) { try { - return getITelephony().getLteOnCdmaMode(); + return getITelephony().getLteOnCdmaModeUsingSubId(subId); } catch (RemoteException ex) { // Assume no ICC card if remote exception which shouldn't happen return PhoneConstants.LTE_ON_CDMA_UNKNOWN; @@ -1225,8 +1599,23 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getSubscriberId() { + return getSubscriberId(getDefaultSubscription()); + } + + /** + * Returns the unique subscriber ID, for example, the IMSI for a GSM phone + * for a subscription. + * Return null if it is unavailable. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * + * @param subId whose subscriber id is returned + */ + /** {@hide} */ + public String getSubscriberId(long subId) { try { - return getSubscriberInfo().getSubscriberId(); + return getSubscriberInfo().getSubscriberIdUsingSubId(subId); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1254,6 +1643,27 @@ public class TelephonyManager { } /** + * Returns the Group Identifier Level1 for a GSM phone for a particular subscription. + * Return null if it is unavailable. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * + * @param subscription whose subscriber id is returned + */ + /** {@hide} */ + public String getGroupIdLevel1(long subId) { + try { + return getSubscriberInfo().getGroupIdLevel1UsingSubId(subId); + } catch (RemoteException ex) { + return null; + } catch (NullPointerException ex) { + // This could happen before phone restarts due to crashing + return null; + } + } + + /** * Returns the phone number string for line 1, for example, the MSISDN * for a GSM phone. Return null if it is unavailable. * <p> @@ -1261,8 +1671,22 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getLine1Number() { + return getLine1Number(getDefaultSubscription()); + } + + /** + * Returns the phone number string for line 1, for example, the MSISDN + * for a GSM phone for a particular subscription. Return null if it is unavailable. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * + * @param subId whose phone number for line 1 is returned + */ + /** {@hide} */ + public String getLine1Number(long subId) { try { - return getSubscriberInfo().getLine1Number(); + return getSubscriberInfo().getLine1NumberUsingSubId(subId); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1281,8 +1705,23 @@ public class TelephonyManager { * nobody seems to call this. */ public String getLine1AlphaTag() { + return getLine1AlphaTag(getDefaultSubscription()); + } + + /** + * Returns the alphabetic identifier associated with the line 1 number + * for a subscription. + * Return null if it is unavailable. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * @param subId whose alphabetic identifier associated with line 1 is returned + * nobody seems to call this. + */ + /** {@hide} */ + public String getLine1AlphaTag(long subId) { try { - return getSubscriberInfo().getLine1AlphaTag(); + return getSubscriberInfo().getLine1AlphaTagUsingSubId(subId); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1301,8 +1740,22 @@ public class TelephonyManager { * @hide */ public String getMsisdn() { + return getMsisdn(getDefaultSubscription()); + } + + /** + * Returns the MSISDN string. + * for a GSM phone. Return null if it is unavailable. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * + * @param subId for which msisdn is returned + */ + /** {@hide} */ + public String getMsisdn(long subId) { try { - return getSubscriberInfo().getMsisdn(); + return getSubscriberInfo().getMsisdnUsingSubId(subId); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1318,8 +1771,21 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getVoiceMailNumber() { + return getVoiceMailNumber(getDefaultSubscription()); + } + + /** + * Returns the voice mail number for a subscription. + * Return null if it is unavailable. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * @param subId whose voice mail number is returned + */ + /** {@hide} */ + public String getVoiceMailNumber(long subId) { try { - return getSubscriberInfo().getVoiceMailNumber(); + return getSubscriberInfo().getVoiceMailNumberUsingSubId(subId); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1337,8 +1803,21 @@ public class TelephonyManager { * @hide */ public String getCompleteVoiceMailNumber() { + return getCompleteVoiceMailNumber(getDefaultSubscription()); + } + + /** + * Returns the complete voice mail number. Return null if it is unavailable. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#CALL_PRIVILEGED CALL_PRIVILEGED} + * + * @param subId + */ + /** {@hide} */ + public String getCompleteVoiceMailNumber(long subId) { try { - return getSubscriberInfo().getCompleteVoiceMailNumber(); + return getSubscriberInfo().getCompleteVoiceMailNumberUsingSubId(subId); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1355,8 +1834,20 @@ public class TelephonyManager { * @hide */ public int getVoiceMessageCount() { + return getVoiceMessageCount(getDefaultSubscription()); + } + + /** + * Returns the voice mail count for a subscription. Return 0 if unavailable. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * @param subId whose voice message count is returned + */ + /** {@hide} */ + public int getVoiceMessageCount(long subId) { try { - return getITelephony().getVoiceMessageCount(); + return getITelephony().getVoiceMessageCountUsingSubId(subId); } catch (RemoteException ex) { return 0; } catch (NullPointerException ex) { @@ -1373,8 +1864,22 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getVoiceMailAlphaTag() { + return getVoiceMailAlphaTag(getDefaultSubscription()); + } + + /** + * Retrieves the alphabetic identifier associated with the voice + * mail number for a subscription. + * <p> + * Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * @param subId whose alphabetic identifier associated with the + * voice mail number is returned + */ + /** {@hide} */ + public String getVoiceMailAlphaTag(long subId) { try { - return getSubscriberInfo().getVoiceMailAlphaTag(); + return getSubscriberInfo().getVoiceMailAlphaTagUsingSubId(subId); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -1437,7 +1942,6 @@ public class TelephonyManager { return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo")); } - /** Device call state: No activity. */ public static final int CALL_STATE_IDLE = 0; /** Device call state: Ringing. A new call arrived and is @@ -1453,8 +1957,19 @@ public class TelephonyManager { * Returns a constant indicating the call state (cellular) on the device. */ public int getCallState() { + return getCallState(getDefaultSubscription()); + } + + /** + * Returns a constant indicating the call state (cellular) on the device + * for a subscription. + * + * @param subId whose call state is returned + */ + /** {@hide} */ + public int getCallState(long subId) { try { - return getITelephony().getCallState(); + return getITelephony().getCallStateUsingSubId(subId); } catch (RemoteException ex) { // the phone process is restarting. return CALL_STATE_IDLE; @@ -1575,8 +2090,8 @@ public class TelephonyManager { public void listen(PhoneStateListener listener, int events) { String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>"; try { - Boolean notifyNow = true; - sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow); + Boolean notifyNow = (getITelephony() != null); + sRegistry.listenUsingSubId(listener.mSubId, pkgForDebug, listener.callback, events, notifyNow); } catch (RemoteException ex) { // system process dead } catch (NullPointerException ex) { @@ -1590,8 +2105,16 @@ public class TelephonyManager { * @hide */ public int getCdmaEriIconIndex() { + return getCdmaEriIconIndex(getDefaultSubscription()); + } + + /** + * Returns the CDMA ERI icon index to display for a subscription + */ + /** {@hide} */ + public int getCdmaEriIconIndex(long subId) { try { - return getITelephony().getCdmaEriIconIndex(); + return getITelephony().getCdmaEriIconIndexUsingSubId(subId); } catch (RemoteException ex) { // the phone process is restarting. return -1; @@ -1608,8 +2131,18 @@ public class TelephonyManager { * @hide */ public int getCdmaEriIconMode() { + return getCdmaEriIconMode(getDefaultSubscription()); + } + + /** + * Returns the CDMA ERI icon mode for a subscription. + * 0 - ON + * 1 - FLASHING + */ + /** {@hide} */ + public int getCdmaEriIconMode(long subId) { try { - return getITelephony().getCdmaEriIconMode(); + return getITelephony().getCdmaEriIconModeUsingSubId(subId); } catch (RemoteException ex) { // the phone process is restarting. return -1; @@ -1624,8 +2157,17 @@ public class TelephonyManager { * @hide */ public String getCdmaEriText() { + return getCdmaEriText(getDefaultSubscription()); + } + + /** + * Returns the CDMA ERI text, of a subscription + * + */ + /** {@hide} */ + public String getCdmaEriText(long subId) { try { - return getITelephony().getCdmaEriText(); + return getITelephony().getCdmaEriTextUsingSubId(subId); } catch (RemoteException ex) { // the phone process is restarting. return null; @@ -1924,6 +2466,286 @@ public class TelephonyManager { } /** + * Returns Default subscription. + */ + private static long getDefaultSubscription() { + return SubscriptionManager.getDefaultSubId(); + } + + /** {@hide} */ + public int getDefaultSim() { + //TODO Need to get it from Telephony Devcontroller + return 0; + } + + /** + * Sets the telephony property with the value specified. + * + * @hide + */ + public static void setTelephonyProperty(String property, long subId, String value) { + String propVal = ""; + String p[] = null; + String prop = SystemProperties.get(property); + int phoneId = SubscriptionManager.getPhoneId(subId); + + if (value == null) { + value = ""; + } + + if (prop != null) { + p = prop.split(","); + } + + if (phoneId < 0) return; + + for (int i = 0; i < phoneId; i++) { + String str = ""; + if ((p != null) && (i < p.length)) { + str = p[i]; + } + propVal = propVal + str + ","; + } + + propVal = propVal + value; + if (p != null) { + for (int i = phoneId + 1; i < p.length; i++) { + propVal = propVal + "," + p[i]; + } + } + + // TODO: workaround for QC + if (property.length() > SystemProperties.PROP_NAME_MAX || propVal.length() > SystemProperties.PROP_VALUE_MAX) { + Rlog.d(TAG, "setTelephonyProperty length too long:" + property + ", " + propVal); + return; + } + + Rlog.d(TAG, "setTelephonyProperty property=" + property + " propVal=" + propVal); + SystemProperties.set(property, propVal); + } + + /** + * Convenience function for retrieving a value from the secure settings + * value list as an integer. Note that internally setting values are + * always stored as strings; this function converts the string to an + * integer for you. + * <p> + * This version does not take a default value. If the setting has not + * been set, or the string value is not a number, + * it throws {@link SettingNotFoundException}. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to retrieve. + * @param index The index of the list + * + * @throws SettingNotFoundException Thrown if a setting by the given + * name can't be found or the setting value is not an integer. + * + * @return The value at the given index of settings. + * @hide + */ + public static int getIntAtIndex(android.content.ContentResolver cr, + String name, int index) + throws android.provider.Settings.SettingNotFoundException { + String v = android.provider.Settings.Global.getString(cr, name); + if (v != null) { + String valArray[] = v.split(","); + if ((index >= 0) && (index < valArray.length) && (valArray[index] != null)) { + try { + return Integer.parseInt(valArray[index]); + } catch (NumberFormatException e) { + //Log.e(TAG, "Exception while parsing Integer: ", e); + } + } + } + throw new android.provider.Settings.SettingNotFoundException(name); + } + + /** + * Convenience function for updating settings value as coma separated + * integer values. This will either create a new entry in the table if the + * given name does not exist, or modify the value of the existing row + * with that name. Note that internally setting values are always + * stored as strings, so this function converts the given value to a + * string before storing it. + * + * @param cr The ContentResolver to access. + * @param name The name of the setting to modify. + * @param index The index of the list + * @param value The new value for the setting to be added to the list. + * @return true if the value was set, false on database errors + * @hide + */ + public static boolean putIntAtIndex(android.content.ContentResolver cr, + String name, int index, int value) { + String data = ""; + String valArray[] = null; + String v = android.provider.Settings.Global.getString(cr, name); + + if (v != null) { + valArray = v.split(","); + } + + // Copy the elements from valArray till index + for (int i = 0; i < index; i++) { + String str = ""; + if ((valArray != null) && (i < valArray.length)) { + str = valArray[i]; + } + data = data + str + ","; + } + + data = data + value; + + // Copy the remaining elements from valArray if any. + if (valArray != null) { + for (int i = index+1; i < valArray.length; i++) { + data = data + "," + valArray[i]; + } + } + return android.provider.Settings.Global.putString(cr, name, data); + } + + /** + * Gets the telephony property. + * + * @hide + */ + public static String getTelephonyProperty(String property, long subId, String defaultVal) { + String propVal = null; + int phoneId = SubscriptionManager.getPhoneId(subId); + String prop = SystemProperties.get(property); + if ((prop != null) && (prop.length() > 0)) { + String values[] = prop.split(","); + if ((phoneId >= 0) && (phoneId < values.length) && (values[phoneId] != null)) { + propVal = values[phoneId]; + } + } + return propVal == null ? defaultVal : propVal; + } + + /** @hide */ + public int getSimCount() { + if(isMultiSimEnabled()) { + //TODO Need to get it from Telephony Devcontroller + return 2; + } else { + return 1; + } + } + + /** + * Returns the IMS Service Table (IST) that was loaded from the ISIM. + * @return IMS Service Table or null if not present or not loaded + * @hide + */ + public String getIsimIst() { + try { + return getSubscriberInfo().getIsimIst(); + } catch (RemoteException ex) { + return null; + } catch (NullPointerException ex) { + // This could happen before phone restarts due to crashing + return null; + } + } + + /** + * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM. + * @return an array of PCSCF strings with one PCSCF per string, or null if + * not present or not loaded + * @hide + */ + public String[] getIsimPcscf() { + try { + return getSubscriberInfo().getIsimPcscf(); + } catch (RemoteException ex) { + return null; + } catch (NullPointerException ex) { + // This could happen before phone restarts due to crashing + return null; + } + } + + /** + * Returns the response of ISIM Authetification through RIL. + * Returns null if the Authentification hasn't been successed or isn't present iphonesubinfo. + * @return the response of ISIM Authetification, or null if not available + * @hide + * @deprecated + * @see getIccSimChallengeResponse with appType=PhoneConstants.APPTYPE_ISIM + */ + public String getIsimChallengeResponse(String nonce){ + try { + return getSubscriberInfo().getIsimChallengeResponse(nonce); + } catch (RemoteException ex) { + return null; + } catch (NullPointerException ex) { + // This could happen before phone restarts due to crashing + return null; + } + } + + /** + * Returns the response of SIM Authentication through RIL. + * Returns null if the Authentication hasn't been successful + * @param subId subscription ID to be queried + * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx) + * @param data authentication challenge data + * @return the response of SIM Authentication, or null if not available + * @hide + */ + public String getIccSimChallengeResponse(long subId, int appType, String data) { + try { + return getSubscriberInfo().getIccSimChallengeResponse(subId, appType, data); + } catch (RemoteException ex) { + return null; + } catch (NullPointerException ex) { + // This could happen before phone starts + return null; + } + } + + /** + * Returns the response of SIM Authentication through RIL for the default subscription. + * Returns null if the Authentication hasn't been successful + * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx) + * @param data authentication challenge data + * @return the response of SIM Authentication, or null if not available + * @hide + */ + public String getIccSimChallengeResponse(int appType, String data) { + return getIccSimChallengeResponse(getDefaultSubscription(), appType, data); + } + + /** + * Get P-CSCF address from PCO after data connection is established or modified. + * + * @return array of P-CSCF address + * @hide + */ + public String[] getPcscfAddress() { + try { + return getITelephony().getPcscfAddress(); + } catch (RemoteException e) { + return new String[0]; + } + } + + /** + * Set IMS registration state + * + * @param Registration state + * @hide + */ + public void setImsRegistrationState(boolean registered) { + try { + getITelephony().setImsRegistrationState(registered); + } catch (RemoteException e) { + } + } + + /** * Get the preferred network type. * Used for device configuration by some CDMA operators. * diff --git a/telephony/java/android/telephony/VoLteServiceState.aidl b/telephony/java/android/telephony/VoLteServiceState.aidl new file mode 100644 index 0000000..59dd04f --- /dev/null +++ b/telephony/java/android/telephony/VoLteServiceState.aidl @@ -0,0 +1,21 @@ +/* +** +** 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 android.telephony; + +parcelable VoLteServiceState; + diff --git a/telephony/java/android/telephony/VoLteServiceState.java b/telephony/java/android/telephony/VoLteServiceState.java new file mode 100644 index 0000000..afef601 --- /dev/null +++ b/telephony/java/android/telephony/VoLteServiceState.java @@ -0,0 +1,229 @@ +/* + * 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 android.telephony; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.Rlog; + +/** + * Contains LTE network state related information. + * + * @hide + */ +public final class VoLteServiceState implements Parcelable { + + private static final String LOG_TAG = "VoLteServiceState"; + private static final boolean DBG = false; + + //Use int max, as -1 is a valid value in signal strength + public static final int INVALID = 0x7FFFFFFF; + + public static final int NOT_SUPPORTED = 0; + public static final int SUPPORTED = 1; + + // Single Radio Voice Call Continuity(SRVCC) progress state + public static final int HANDOVER_STARTED = 0; + public static final int HANDOVER_COMPLETED = 1; + public static final int HANDOVER_FAILED = 2; + public static final int HANDOVER_CANCELED = 3; + + private int mSrvccState; + + /** + * Create a new VoLteServiceState from a intent notifier Bundle + * + * This method is used by PhoneStateIntentReceiver and maybe by + * external applications. + * + * @param m Bundle from intent notifier + * @return newly created VoLteServiceState + * + * @hide + */ + public static VoLteServiceState newFromBundle(Bundle m) { + VoLteServiceState ret; + ret = new VoLteServiceState(); + ret.setFromNotifierBundle(m); + return ret; + } + + /** + * Empty constructor + * + * @hide + */ + public VoLteServiceState() { + initialize(); + } + + /** + * Constructor + * + * @hide + */ + public VoLteServiceState(int srvccState) { + initialize(); + + mSrvccState = srvccState; + } + + /** + * Copy constructors + * + * @param s Source VoLteServiceState + * + * @hide + */ + public VoLteServiceState(VoLteServiceState s) { + copyFrom(s); + } + + /** + * Initialize values to defaults. + * + * @hide + */ + private void initialize() { + mSrvccState = INVALID; + } + + /** + * @hide + */ + protected void copyFrom(VoLteServiceState s) { + mSrvccState = s.mSrvccState; + } + + /** + * Construct a VoLteServiceState object from the given parcel. + * + * @hide + */ + public VoLteServiceState(Parcel in) { + if (DBG) log("Size of VoLteServiceState parcel:" + in.dataSize()); + + mSrvccState = in.readInt(); + } + + /** + * {@link Parcelable#writeToParcel} + */ + public void writeToParcel(Parcel out, int flags) { + out.writeInt(mSrvccState); + } + + /** + * {@link Parcelable#describeContents} + */ + public int describeContents() { + return 0; + } + + /** + * {@link Parcelable.Creator} + * + * @hide + */ + public static final Parcelable.Creator<VoLteServiceState> CREATOR = new Parcelable.Creator() { + public VoLteServiceState createFromParcel(Parcel in) { + return new VoLteServiceState(in); + } + + public VoLteServiceState[] newArray(int size) { + return new VoLteServiceState[size]; + } + }; + + /** + * Validate the individual fields as per the range + * specified in ril.h + * Set to invalid any field that is not in the valid range + * + * @return + * Valid values for all fields + * @hide + */ + public void validateInput() { + } + + public int hashCode() { + int primeNum = 31; + return ((mSrvccState * primeNum)); + } + + /** + * @return true if the LTE network states are the same + */ + @Override + public boolean equals (Object o) { + VoLteServiceState s; + + try { + s = (VoLteServiceState) o; + } catch (ClassCastException ex) { + return false; + } + + if (o == null) { + return false; + } + + return (mSrvccState == s.mSrvccState); + } + + /** + * @return string representation. + */ + @Override + public String toString() { + return ("VoLteServiceState:" + + " " + mSrvccState); + } + + /** + * Set VoLteServiceState based on intent notifier map + * + * @param m intent notifier map + * @hide + */ + private void setFromNotifierBundle(Bundle m) { + mSrvccState = m.getInt("mSrvccState"); + } + + /** + * Set intent notifier Bundle based on VoLteServiceState + * + * @param m intent notifier Bundle + * @hide + */ + public void fillInNotifierBundle(Bundle m) { + m.putInt("mSrvccState", mSrvccState); + } + + public int getSrvccState() { + return mSrvccState; + } + + /** + * log + */ + private static void log(String s) { + Rlog.w(LOG_TAG, s); + } +} diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index f8dd7cf..745c9d0 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -37,6 +37,9 @@ import com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder; import com.android.i18n.phonenumbers.NumberParseException; import com.android.i18n.phonenumbers.PhoneNumberUtil; import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; +import android.telephony.SubscriptionManager; + +import android.telephony.TelephonyManager; import java.util.Locale; @@ -233,6 +236,7 @@ public class CallerInfo { info.contactExists = true; } cursor.close(); + cursor = null; } info.needUpdate = false; @@ -269,6 +273,23 @@ public class CallerInfo { public static CallerInfo getCallerInfo(Context context, String number) { if (VDBG) Rlog.v(TAG, "getCallerInfo() based on number..."); + long subId = SubscriptionManager.getDefaultSubId(); + return getCallerInfo(context, number, subId); + } + + /** + * getCallerInfo given a phone number and subscription, look up in the call-log database + * for the matching caller id info. + * @param context the context used to get the ContentResolver + * @param number the phone number used to lookup caller id + * @param subId the subscription for checking for if voice mail number or not + * @return the CallerInfo which contains the caller id for the given + * number. The returned CallerInfo is null if no number is supplied. If + * a matching number is not found, then a generic caller info is returned, + * with all relevant fields empty or null. + */ + public static CallerInfo getCallerInfo(Context context, String number, long subId) { + if (TextUtils.isEmpty(number)) { return null; } @@ -278,7 +299,7 @@ public class CallerInfo { // shortcut and skip the query. if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) { return new CallerInfo().markAsEmergency(context); - } else if (PhoneNumberUtils.isVoiceMailNumber(number)) { + } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) { return new CallerInfo().markAsVoiceMail(); } @@ -400,10 +421,17 @@ public class CallerInfo { // TODO: As in the emergency number handling, we end up writing a // string in the phone number field. /* package */ CallerInfo markAsVoiceMail() { + + long subId = SubscriptionManager.getDefaultSubId(); + return markAsVoiceMail(subId); + + } + + /* package */ CallerInfo markAsVoiceMail(long subId) { mIsVoiceMail = true; try { - String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag(); + String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag(subId); phoneNumber = voiceMailLabel; } catch (SecurityException se) { diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index 34fed5e..fe403d9 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -24,12 +24,15 @@ import android.net.Uri; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.SystemProperties; import android.provider.ContactsContract.CommonDataKinds.SipAddress; import android.provider.ContactsContract.Data; import android.provider.ContactsContract.PhoneLookup; import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import android.telephony.Rlog; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; /** * Helper class to make it easier to run asynchronous caller-id lookup queries. @@ -75,6 +78,8 @@ public class CallerInfoAsyncQuery { public Object cookie; public int event; public String number; + + public long subId; } @@ -207,11 +212,17 @@ public class CallerInfoAsyncQuery { // However, if there is any code that calls this method, we should // check the parameters to make sure they're viable. if (DBG) Rlog.d(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request."); + if (cursor != null) { + cursor.close(); + } return; } if (cw.event == EVENT_END_OF_QUEUE) { release(); + if (cursor != null) { + cursor.close(); + } return; } @@ -232,7 +243,7 @@ public class CallerInfoAsyncQuery { // comments at the top of CallerInfo class). mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext); } else if (cw.event == EVENT_VOICEMAIL_NUMBER) { - mCallerInfo = new CallerInfo().markAsVoiceMail(); + mCallerInfo = new CallerInfo().markAsVoiceMail(cw.subId); } else { mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor); if (DBG) Rlog.d(LOG_TAG, "==> Got mCallerInfo: " + mCallerInfo); @@ -289,6 +300,10 @@ public class CallerInfoAsyncQuery { " for token: " + token + mCallerInfo); cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo); } + + if (cursor != null) { + cursor.close(); + } } } @@ -334,6 +349,25 @@ public class CallerInfoAsyncQuery { */ public static CallerInfoAsyncQuery startQuery(int token, Context context, String number, OnQueryCompleteListener listener, Object cookie) { + + long subId = SubscriptionManager.getDefaultSubId(); + return startQuery(token, context, number, listener, cookie, subId); + } + + /** + * Factory method to start the query based on a number with specific subscription. + * + * Note: if the number contains an "@" character we treat it + * as a SIP address, and look it up directly in the Data table + * rather than using the PhoneLookup table. + * TODO: But eventually we should expose two separate methods, one for + * numbers and one for SIP addresses, and then have + * PhoneUtils.startGetCallerInfo() decide which one to call based on + * the phone type of the incoming connection. + */ + public static CallerInfoAsyncQuery startQuery(int token, Context context, String number, + OnQueryCompleteListener listener, Object cookie, long subId) { + if (DBG) { Rlog.d(LOG_TAG, "##### CallerInfoAsyncQuery startQuery()... #####"); Rlog.d(LOG_TAG, "- number: " + /*number*/ "xxxxxxx"); @@ -397,11 +431,12 @@ public class CallerInfoAsyncQuery { cw.listener = listener; cw.cookie = cookie; cw.number = number; + cw.subId = subId; // check to see if these are recognized numbers, and use shortcuts if we can. if (PhoneNumberUtils.isLocalEmergencyNumber(context, number)) { cw.event = EVENT_EMERGENCY_NUMBER; - } else if (PhoneNumberUtils.isVoiceMailNumber(number)) { + } else if (PhoneNumberUtils.isVoiceMailNumber(subId, number)) { cw.event = EVENT_VOICEMAIL_NUMBER; } else { cw.event = EVENT_NEW_QUERY; diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl index 3f36645..a95336e 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -23,6 +23,7 @@ import android.telephony.CellInfo; import android.telephony.DataConnectionRealTimeInfo; import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; +import android.telephony.VoLteServiceState; oneway interface IPhoneStateListener { void onServiceStateChanged(in ServiceState serviceState); @@ -41,5 +42,6 @@ oneway interface IPhoneStateListener { void onPreciseCallStateChanged(in PreciseCallState callState); void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState); void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo); + void onVoLteServiceStateChanged(in VoLteServiceState lteState); } diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl index 03940dc..4734965 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl @@ -28,6 +28,13 @@ interface IPhoneSubInfo { String getDeviceId(); /** + * Retrieves the unique device ID of a subId for the device, e.g., IMEI + * for GSM phones. + */ + String getDeviceIdUsingSubId(long subId); + + + /** * Retrieves the software version number for the device, e.g., IMEI/SV * for GSM phones. */ @@ -39,46 +46,94 @@ interface IPhoneSubInfo { String getSubscriberId(); /** + * Retrieves the unique subscriber ID of a given subId, e.g., IMSI for GSM phones. + */ + String getSubscriberIdUsingSubId(long subId); + + /** * Retrieves the Group Identifier Level1 for GSM phones. */ String getGroupIdLevel1(); /** + * Retrieves the Group Identifier Level1 for GSM phones of a subId. + */ + String getGroupIdLevel1UsingSubId(long subId); + + /** * Retrieves the serial number of the ICC, if applicable. */ String getIccSerialNumber(); /** + * Retrieves the serial number of a given subId. + */ + String getIccSerialNumberUsingSubId(long subId); + + /** * Retrieves the phone number string for line 1. */ String getLine1Number(); /** + * Retrieves the phone number string for line 1 of a subcription. + */ + String getLine1NumberUsingSubId(long subId); + + + /** * Retrieves the alpha identifier for line 1. */ String getLine1AlphaTag(); /** + * Retrieves the alpha identifier for line 1 of a subId. + */ + String getLine1AlphaTagUsingSubId(long subId); + + + /** * Retrieves MSISDN Number. */ String getMsisdn(); /** + * Retrieves the Msisdn of a subId. + */ + String getMsisdnUsingSubId(long subId); + + /** * Retrieves the voice mail number. */ String getVoiceMailNumber(); /** + * Retrieves the voice mail number of a given subId. + */ + String getVoiceMailNumberUsingSubId(long subId); + + /** * Retrieves the complete voice mail number. */ String getCompleteVoiceMailNumber(); /** + * Retrieves the complete voice mail number for particular subId + */ + String getCompleteVoiceMailNumberUsingSubId(long subId); + + /** * Retrieves the alpha identifier associated with the voice mail number. */ String getVoiceMailAlphaTag(); /** + * Retrieves the alpha identifier associated with the voice mail number + * of a subId. + */ + String getVoiceMailAlphaTagUsingSubId(long subId); + + /** * Returns the IMS private user identity (IMPI) that was loaded from the ISIM. * @return the IMPI, or null if not present or not loaded */ @@ -96,4 +151,38 @@ interface IPhoneSubInfo { * not present or not loaded */ String[] getIsimImpu(); + + /** + * Returns the IMS Service Table (IST) that was loaded from the ISIM. + * @return IMS Service Table or null if not present or not loaded + */ + String getIsimIst(); + + /** + * Returns the IMS Proxy Call Session Control Function(PCSCF) that were loaded from the ISIM. + * @return an array of PCSCF strings with one PCSCF per string, or null if + * not present or not loaded + */ + String[] getIsimPcscf(); + + /** + * TODO: Deprecate and remove this interface. Superceded by getIccsimChallengeResponse. + * Returns the response of ISIM Authetification through RIL. + * @return the response of ISIM Authetification, or null if + * the Authentification hasn't been successed or isn't present iphonesubinfo. + */ + String getIsimChallengeResponse(String nonce); + + /** + * Returns the response of the SIM application on the UICC to authentication + * challenge/response algorithm. The data string and challenge response are + * Base64 encoded Strings. + * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102. + * + * @param subId subscription ID to be queried + * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx) + * @param data authentication challenge data + * @return challenge response + */ + String getIccSimChallengeResponse(long subId, int appType, String data); } diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl index 6fc64ae..9e975e9 100644 --- a/telephony/java/com/android/internal/telephony/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -42,6 +42,13 @@ interface ISms { List<SmsRawData> getAllMessagesFromIccEf(String callingPkg); /** + * Retrieves all messages currently stored on ICC. + * @param subId the subId id. + * @return list of SmsRawData of all sms on ICC + */ + List<SmsRawData> getAllMessagesFromIccEfUsingSubId(in long subId, String callingPkg); + + /** * Update the specified message on the ICC. * * @param messageIndex record index of message to update @@ -56,6 +63,21 @@ interface ISms { in byte[] pdu); /** + * Update the specified message on the ICC. + * + * @param messageIndex record index of message to update + * @param newStatus new message status (STATUS_ON_ICC_READ, + * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, + * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) + * @param pdu the raw PDU to store + * @param subId the subId id. + * @return success or not + * + */ + boolean updateMessageOnIccEfUsingSubId(in long subId, String callingPkg, + int messageIndex, int newStatus, in byte[] pdu); + + /** * Copy a raw SMS PDU to the ICC. * * @param pdu the raw PDU to store @@ -67,6 +89,19 @@ interface ISms { boolean copyMessageToIccEf(String callingPkg, int status, in byte[] pdu, in byte[] smsc); /** + * Copy a raw SMS PDU to the ICC. + * + * @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) + * @param subId the subId id. + * @return success or not + * + */ + boolean copyMessageToIccEfUsingSubId(in long subId, String callingPkg, int status, + in byte[] pdu, in byte[] smsc); + + /** * Send a data SMS. * * @param smsc the SMSC to send the message through, or NULL for the @@ -93,6 +128,34 @@ interface ISms { in byte[] data, in PendingIntent sentIntent, in PendingIntent deliveryIntent); /** + * Send a data SMS. + * + * @param smsc the SMSC to send the message through, or NULL for the + * default SMSC + * @param data the body of the message to send + * @param sentIntent if not NULL this <code>PendingIntent</code> is + * broadcast when the message is sucessfully sent, or failed. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors:<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 applicaitons, + * which cause smaller number of SMS to be sent in checking period. + * @param deliveryIntent if not NULL this <code>PendingIntent</code> is + * broadcast when the message is delivered to the recipient. The + * raw pdu of the status report is in the extended data ("pdu"). + * @param subId the subId id. + */ + void sendDataUsingSubId(long subId, String callingPkg, in String destAddr, + in String scAddr, in int destPort, in byte[] data, in PendingIntent sentIntent, + in PendingIntent deliveryIntent); + + /** * Send an SMS. * * @param smsc the SMSC to send the message through, or NULL for the @@ -119,6 +182,34 @@ interface ISms { in PendingIntent sentIntent, in PendingIntent deliveryIntent); /** + * Send an SMS. + * + * @param smsc the SMSC to send the message through, or NULL for the + * default SMSC + * @param text the body of the message to send + * @param sentIntent if not NULL this <code>PendingIntent</code> is + * broadcast when the message is sucessfully sent, or failed. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors:<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"). + * @param subId the subId on which the SMS has to be sent. + */ + void sendTextUsingSubId(in long subId, String callingPkg, in String destAddr, + in String scAddr, in String text, in PendingIntent sentIntent, + in PendingIntent deliveryIntent); + + /** * Inject an SMS PDU into the android platform. * * @param pdu is the byte array of pdu to be injected into android application framework @@ -158,6 +249,34 @@ interface ISms { in List<PendingIntent> deliveryIntents); /** + * Send a multi-part text based SMS. + * + * @param destinationAddress the address to send the message to + * @param scAddress is the service center address or null to use + * the current default SMSC + * @param parts an <code>ArrayList</code> of strings that, in order, + * comprise the original message + * @param sentIntents if not null, an <code>ArrayList</code> of + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be <code>Activity.RESULT_OK<code> for success, + * or one of these errors: + * <code>RESULT_ERROR_GENERIC_FAILURE</code> + * <code>RESULT_ERROR_RADIO_OFF</code> + * <code>RESULT_ERROR_NULL_PDU</code>. + * @param deliveryIntents if not null, an <code>ArrayList</code> of + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). + * @param subId the subId on which the SMS has to be sent. + */ + void sendMultipartTextUsingSubId(in long subId, String callingPkg, + in String destinationAddress, in String scAddress, + in List<String> parts, in List<PendingIntent> sentIntents, + in List<PendingIntent> deliveryIntents); + + /** * Enable reception of cell broadcast (SMS-CB) messages with the given * message identifier. Note that if two different clients enable the same * message identifier, they must both disable it for the device to stop @@ -172,6 +291,21 @@ interface ISms { boolean enableCellBroadcast(int messageIdentifier); /** + * Enable reception of cell broadcast (SMS-CB) messages with the given + * message identifier. Note that if two different clients enable the same + * message identifier, they must both disable it for the device to stop + * receiving those messages. + * + * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) or + * C.R1001-G (3GPP2) + * @param subId for which the broadcast has to be enabled + * @return true if successful, false otherwise + * + * @see #disableCellBroadcast(int) + */ + boolean enableCellBroadcastUsingSubId(in long subId, int messageIdentifier); + + /** * Disable reception of cell broadcast (SMS-CB) messages with the given * message identifier. Note that if two different clients enable the same * message identifier, they must both disable it for the device to stop @@ -185,6 +319,21 @@ interface ISms { */ boolean disableCellBroadcast(int messageIdentifier); + /** + * Disable reception of cell broadcast (SMS-CB) messages with the given + * message identifier. Note that if two different clients enable the same + * message identifier, they must both disable it for the device to stop + * receiving those messages. + * + * @param messageIdentifier Message identifier as specified in TS 23.041 (3GPP) or + * C.R1001-G (3GPP2) + * @param subId for which the broadcast has to be disabled + * @return true if successful, false otherwise + * + * @see #enableCellBroadcast(int) + */ + boolean disableCellBroadcastUsingSubId(in long subId, int messageIdentifier); + /* * Enable reception of cell broadcast (SMS-CB) messages with the given * message identifier range. Note that if two different clients enable @@ -201,6 +350,23 @@ interface ISms { */ boolean enableCellBroadcastRange(int startMessageId, int endMessageId); + /* + * Enable reception of cell broadcast (SMS-CB) messages with the given + * message identifier range. Note that if two different clients enable + * a message identifier range, they must both disable it for the device + * to stop receiving those messages. + * + * @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 subId for which the broadcast has to be enabled + * @return true if successful, false otherwise + * + * @see #disableCellBroadcastRange(int, int) + */ + boolean enableCellBroadcastRangeUsingSubId(long subId, int startMessageId, int endMessageId); + /** * Disable reception of cell broadcast (SMS-CB) messages with the given * message identifier range. Note that if two different clients enable @@ -218,18 +384,52 @@ interface ISms { boolean disableCellBroadcastRange(int startMessageId, int endMessageId); /** + * Disable reception of cell broadcast (SMS-CB) messages with the given + * message identifier range. Note that if two different clients enable + * a message identifier range, they must both disable it for the device + * to stop receiving those messages. + * + * @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 subId for which the broadcast has to be disabled + * @return true if successful, false otherwise + * + * @see #enableCellBroadcastRange(int, int, int) + */ + boolean disableCellBroadcastRangeUsingSubId(long subId, int startMessageId, + int endMessageId); + + /** * Returns the premium SMS send permission for the specified package. * Requires system permission. */ int getPremiumSmsPermission(String packageName); /** + * Returns the premium SMS send permission for the specified package. + * Requires system permission. + */ + int getPremiumSmsPermissionUsingSubId(long subId, String packageName); + + /** * Set the SMS send permission for the specified package. * Requires system permission. */ void setPremiumSmsPermission(String packageName, int permission); /** + * Set the SMS send permission for the specified package. + * Requires system permission. + */ + /** + * Set the SMS send permission for the specified package. + * Requires system permission. + */ + void setPremiumSmsPermissionUsingSubId(long subId, String packageName, int permission); + + /** * SMS over IMS is supported if IMS is registered and SMS is supported * on IMS. * @@ -240,6 +440,23 @@ interface ISms { boolean isImsSmsSupported(); /** + * SMS over IMS is supported if IMS is registered and SMS is supported + * on IMS. + * @param subId for subId which isImsSmsSupported is queried + * @return true if SMS over IMS is supported, false otherwise + * + * @see #getImsSmsFormat() + */ + boolean isImsSmsSupportedUsingSubId(long subId); + + /* + * get user prefered SMS subId + * @return subId id + */ + long getPreferredSmsSubscription(); + + + /** * Gets SMS format supported on IMS. SMS over IMS format is * either 3GPP or 3GPP2. * @@ -250,4 +467,25 @@ interface ISms { * @see #isImsSmsSupported() */ String getImsSmsFormat(); + + /** + * Gets SMS format supported on IMS. SMS over IMS format is + * either 3GPP or 3GPP2. + * @param subId for subId which getImsSmsFormat is queried + * @return android.telephony.SmsMessage.FORMAT_3GPP, + * android.telephony.SmsMessage.FORMAT_3GPP2 + * or android.telephony.SmsMessage.FORMAT_UNKNOWN + * + * @see #isImsSmsSupported() + */ + String getImsSmsFormatUsingSubId(long subId); + + + + + /* + * Get SMS prompt property, enabled or not + * @return true if enabled, false otherwise + */ + boolean isSMSPromptEnabled(); } diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl new file mode 100755 index 0000000..6021ccf --- /dev/null +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -0,0 +1,153 @@ +/* +* Copyright (C) 2011-2014 MediaTek Inc. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package com.android.internal.telephony; + +import android.app.PendingIntent; +import android.telephony.SubInfoRecord; + +interface ISub { + /** + * Get the SubInfoRecord according to an index + * @param context Context provided by caller + * @param subId The unique SubInfoRecord index in database + * @return SubInfoRecord, maybe null + */ + SubInfoRecord getSubInfoUsingSubId(long subId); + + /** + * Get the SubInfoRecord according to an IccId + * @param context Context provided by caller + * @param iccId the IccId of SIM card + * @return SubInfoRecord, maybe null + */ + List<SubInfoRecord> getSubInfoUsingIccId(String iccId); + + /** + * Get the SubInfoRecord according to slotId + * @param context Context provided by caller + * @param slotId the slot which the SIM is inserted + * @return SubInfoRecord, maybe null + */ + List<SubInfoRecord> getSubInfoUsingSlotId(int slotId); + + /** + * Get all the SubInfoRecord(s) in subinfo database + * @param context Context provided by caller + * @return Array list of all SubInfoRecords in database, include thsoe that were inserted before + */ + List<SubInfoRecord> getAllSubInfoList(); + + /** + * Get the SubInfoRecord(s) of the currently inserted SIM(s) + * @param context Context provided by caller + * @return Array list of currently inserted SubInfoRecord(s) + */ + List<SubInfoRecord> getActivatedSubInfoList(); + + /** + * Get the SUB count of all SUB(s) in subinfo database + * @param context Context provided by caller + * @return all SIM count in database, include what was inserted before + */ + int getAllSubInfoCount(); + + /** + * Add a new SubInfoRecord to subinfo database if needed + * @param context Context provided by caller + * @param iccId the IccId of the SIM card + * @param slotId the slot which the SIM is inserted + * @return the URL of the newly created row or the updated row + */ + int addSubInfoRecord(String iccId, int slotId); + + /** + * Set SIM color by simInfo index + * @param context Context provided by caller + * @param color the color of the SIM + * @param subId the unique SubInfoRecord index in database + * @return the number of records updated + */ + int setColor(int color, long subId); + + /** + * Set display name by simInfo index + * @param context Context provided by caller + * @param displayName the display name of SIM card + * @param subId the unique SubInfoRecord index in database + * @return the number of records updated + */ + int setDisplayName(String displayName, long subId); + + /** + * Set display name by simInfo index with name source + * @param context Context provided by caller + * @param displayName the display name of SIM card + * @param subId the unique SubInfoRecord index in database + * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT + * @return the number of records updated + */ + int setDisplayNameUsingSrc(String displayName, long subId, long nameSource); + + /** + * Set phone number by subId + * @param context Context provided by caller + * @param number the phone number of the SIM + * @param subId the unique SubInfoRecord index in database + * @return the number of records updated + */ + int setDispalyNumber(String number, long subId); + + /** + * Set number display format. 0: none, 1: the first four digits, 2: the last four digits + * @param context Context provided by caller + * @param format the display format of phone number + * @param subId the unique SubInfoRecord index in database + * @return the number of records updated + */ + int setDisplayNumberFormat(int format, long subId); + + /** + * Set data roaming by simInfo index + * @param context Context provided by caller + * @param roaming 0:Don't allow data when roaming, 1:Allow data when roaming + * @param subId the unique SubInfoRecord index in database + * @return the number of records updated + */ + int setDataRoaming(int roaming, long subId); + + int getSlotId(long subId); + + long[] getSubId(int slotId); + + long getDefaultSubId(); + + int clearSubInfo(); + + int getPhoneId(long subId); + + /** + * Get the default data subscription + * @return Id of the data subscription + */ + long getDefaultDataSubId(); + + void setDefaultDataSubId(long subId); + + long getDefaultVoiceSubId(); + + void setDefaultVoiceSubId(long subId); +} diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index acaa8de..407da87 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -16,14 +16,11 @@ package com.android.internal.telephony; -import android.content.ComponentName; import android.os.Bundle; -import android.telephony.CellInfo; -import android.telephony.NeighboringCellInfo; - import java.util.List; +import android.telephony.NeighboringCellInfo; +import android.telephony.CellInfo; -import java.util.List; /** * Interface used to interact with the phone. Mostly this is used by the @@ -56,6 +53,13 @@ interface ITelephony { boolean endCall(); /** + * End call on particular subId or go to the Home screen + * @param subId user preferred subId. + * @return whether it hung up + */ + boolean endCallUsingSubId(long subId); + + /** * Answer the currently-ringing call. * * If there's already a current active call, that call will be @@ -92,6 +96,23 @@ interface ITelephony { boolean isOffhook(); /** + * Check if a particular subId has an active or holding call + * + * @param subId user preferred subId. + * @return true if the phone state is OFFHOOK. + */ + boolean isOffhookUsingSubId(long subId); + + /** + * Check if an incoming phone call is ringing or call waiting + * on a particular subId. + * + * @param subId user preferred subId. + * @return true if the phone state is RINGING. + */ + boolean isRingingUsingSubId(long subId); + + /** * Check if an incoming phone call is ringing or call waiting. * @return true if the phone state is RINGING. */ @@ -104,12 +125,27 @@ interface ITelephony { boolean isIdle(); /** + * Check if the phone is idle on a particular subId. + * + * @param subId user preferred subId. + * @return true if the phone state is IDLE. + */ + boolean isIdleUsingSubId(long subId); + + /** * Check to see if the radio is on or not. * @return returns true if the radio is on. */ boolean isRadioOn(); /** + * Check to see if the radio is on or not on particular subId. + * @param subId user preferred subId. + * @return returns true if the radio is on. + */ + boolean isRadioOnUsingSubId(long subId); + + /** * Check if the SIM pin lock is enabled. * @return true if the SIM pin lock is enabled. */ @@ -128,6 +164,15 @@ interface ITelephony { boolean supplyPin(String pin); /** + * Supply a pin to unlock the SIM for particular subId. + * Blocks until a result is determined. + * @param pin The pin to check. + * @param subId user preferred subId. + * @return whether the operation was a success. + */ + boolean supplyPinUsingSubId(long subId, String pin); + + /** * Supply puk to unlock the SIM and set SIM pin to new pin. * Blocks until a result is determined. * @param puk The puk to check. @@ -137,6 +182,16 @@ interface ITelephony { boolean supplyPuk(String puk, String pin); /** + * Supply puk to unlock the SIM and set SIM pin to new pin. + * Blocks until a result is determined. + * @param puk The puk to check. + * pin The new pin to be set in SIM + * @param subId user preferred subId. + * @return whether the operation was a success. + */ + boolean supplyPukUsingSubId(long subId, String puk, String pin); + + /** * Supply a pin to unlock the SIM. Blocks until a result is determined. * Returns a specific success/error code. * @param pin The pin to check. @@ -146,6 +201,15 @@ interface ITelephony { int[] supplyPinReportResult(String pin); /** + * Supply a pin to unlock the SIM. Blocks until a result is determined. + * Returns a specific success/error code. + * @param pin The pin to check. + * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code + * retValue[1] = number of attempts remaining if known otherwise -1 + */ + int[] supplyPinReportResultUsingSubId(long subId, String pin); + + /** * Supply puk to unlock the SIM and set SIM pin to new pin. * Blocks until a result is determined. * Returns a specific success/error code @@ -157,6 +221,17 @@ interface ITelephony { int[] supplyPukReportResult(String puk, String pin); /** + * Supply puk to unlock the SIM and set SIM pin to new pin. + * Blocks until a result is determined. + * Returns a specific success/error code + * @param puk The puk to check + * pin The pin to check. + * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code + * retValue[1] = number of attempts remaining if known otherwise -1 + */ + int[] supplyPukReportResultUsingSubId(long subId, String puk, String pin); + + /** * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated * without SEND (so <code>dial</code> is not appropriate). * @@ -166,16 +241,38 @@ interface ITelephony { boolean handlePinMmi(String dialString); /** + * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated + * without SEND (so <code>dial</code> is not appropriate) for + * a particular subId. + * @param dialString the MMI command to be executed. + * @param subId user preferred subId. + * @return true if MMI command is executed. + */ + boolean handlePinMmiUsingSubId(long subId, String dialString); + + /** * Toggles the radio on or off. */ void toggleRadioOnOff(); /** + * Toggles the radio on or off on particular subId. + * @param subId user preferred subId. + */ + void toggleRadioOnOffUsingSubId(long subId); + + /** * Set the radio to on or off */ boolean setRadio(boolean turnOn); /** + * Set the radio to on or off on particular subId. + * @param subId user preferred subId. + */ + boolean setRadioUsingSubId(long subId, boolean turnOn); + + /** * Set the radio to on or off unconditionally */ boolean setRadioPower(boolean turnOn); @@ -186,16 +283,35 @@ interface ITelephony { void updateServiceLocation(); /** + * Request to update location information for a subscrition in service state + * @param subId user preferred subId. + */ + void updateServiceLocationUsingSubId(long subId); + + /** * Enable location update notifications. */ void enableLocationUpdates(); /** + * Enable location update notifications. + * @param subId user preferred subId. + */ + void enableLocationUpdatesUsingSubId(long subId); + + /** * Disable location update notifications. */ void disableLocationUpdates(); /** + * Disable location update notifications. + * @param subId user preferred subId. + */ + void disableLocationUpdatesUsingSubId(long subId); + + + /** * Enable a specific APN type. */ int enableApnType(String type); @@ -206,6 +322,16 @@ interface ITelephony { int disableApnType(String type); /** + * Enable a specific APN type with subscription. + */ + int enableApnTypeUsingSub(long subId, String type); + + /** + * Disable a specific APN type with subscription. + */ + int disableApnTypeUsingSub(long subId, String type); + + /** * Allow mobile data connections. */ boolean enableDataConnectivity(); @@ -228,6 +354,12 @@ interface ITelephony { List<NeighboringCellInfo> getNeighboringCellInfo(String callingPkg); int getCallState(); + + /** + * Returns the call state for a subId. + */ + int getCallStateUsingSubId(long subId); + int getDataActivity(); int getDataState(); @@ -239,11 +371,25 @@ interface ITelephony { int getActivePhoneType(); /** + * Returns the current active phone type as integer for particular subId. + * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE + * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE + * @param subId user preferred subId. + */ + int getActivePhoneTypeUsingSubId(long subId); + + /** * Returns the CDMA ERI icon index to display */ int getCdmaEriIconIndex(); /** + * Returns the CDMA ERI icon index to display on particular subId. + * @param subId user preferred subId. + */ + int getCdmaEriIconIndexUsingSubId(long subId); + + /** * Returns the CDMA ERI icon mode, * 0 - ON * 1 - FLASHING @@ -251,11 +397,25 @@ interface ITelephony { int getCdmaEriIconMode(); /** + * Returns the CDMA ERI icon mode on particular subId, + * 0 - ON + * 1 - FLASHING + * @param subId user preferred subId. + */ + int getCdmaEriIconModeUsingSubId(long subId); + + /** * Returns the CDMA ERI text, */ String getCdmaEriText(); /** + * Returns the CDMA ERI text for particular subId, + * @param subId user preferred subId. + */ + String getCdmaEriTextUsingSubId(long subId); + + /** * Returns true if OTA service provisioning needs to run. * Only relevant on some technologies, others will always * return false. @@ -268,26 +428,61 @@ interface ITelephony { int getVoiceMessageCount(); /** + * Returns the unread count of voicemails for a subId. + * @param subId user preferred subId. + * Returns the unread count of voicemails + */ + int getVoiceMessageCountUsingSubId(long subId); + + /** * Returns the network type for data transmission */ int getNetworkType(); /** + * Returns the network type of a subId. + * @param subId user preferred subId. + * Returns the network type + */ + int getNetworkTypeUsingSubId(long subId); + + /** * Returns the network type for data transmission */ int getDataNetworkType(); /** + * Returns the data network type of a subId + * @param subId user preferred subId. + * Returns the network type + */ + int getDataNetworkTypeUsingSubId(long subId); + + /** * Returns the network type for voice */ int getVoiceNetworkType(); /** + * Returns the voice network type of a subId + * @param subId user preferred subId. + * Returns the network type + */ + int getVoiceNetworkTypeUsingSubId(long subId); + + /** * Return true if an ICC card is present */ boolean hasIccCard(); /** + * Return true if an ICC card is present for a subId. + * @param slotId user preferred slotId. + * Return true if an ICC card is present + */ + boolean hasIccCardUsingSlotId(long slotId); + + /** * Return if the current radio is LTE on CDMA. This * is a tri-state return value as for a period of time * the mode may be unknown. @@ -298,6 +493,16 @@ interface ITelephony { int getLteOnCdmaMode(); /** + * Return if the current radio is LTE on CDMA. This + * is a tri-state return value as for a period of time + * the mode may be unknown. + * + * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE} + * or {@link PHone#LTE_ON_CDMA_TRUE} + */ + int getLteOnCdmaModeUsingSubId(long subId); + + /** * Returns the all observed cell information of the device. */ List<CellInfo> getAllCellInfo(); @@ -308,6 +513,12 @@ interface ITelephony { void setCellInfoListRate(int rateInMillis); /** + * get default sim + * @return sim id + */ + int getDefaultSim(); + + /** * Opens a logical channel to the ICC card. * * Input parameters equivalent to TS 27.007 AT+CCHO command. @@ -428,4 +639,16 @@ interface ITelephony { * @return true on enabled */ boolean getDataEnabled(); + + /** + * Get P-CSCF address from PCO after data connection is established or modified. + */ + String[] getPcscfAddress(); + + /** + * Set IMS registration state + */ + void setImsRegistrationState(boolean registered); + } + diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index b104c11..fd2d1c7 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -24,22 +24,36 @@ import android.telephony.CellInfo; import android.telephony.DataConnectionRealTimeInfo; import android.telephony.ServiceState; import android.telephony.SignalStrength; +import android.telephony.CellInfo; +import android.telephony.VoLteServiceState; import com.android.internal.telephony.IPhoneStateListener; interface ITelephonyRegistry { void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow); - + void listenUsingSubId(in long subId, String pkg, IPhoneStateListener callback, int events, + boolean notifyNow); void notifyCallState(int state, String incomingNumber); + void notifyCallStateUsingSubId(in long subId, int state, String incomingNumber); void notifyServiceState(in ServiceState state); + void notifyServiceStateUsingSubId(in long subId, in ServiceState state); void notifySignalStrength(in SignalStrength signalStrength); + void notifySignalStrengthUsingSubId(in long subId, in SignalStrength signalStrength); void notifyMessageWaitingChanged(boolean mwi); + void notifyMessageWaitingChangedUsingSubId(in long subId, boolean mwi); void notifyCallForwardingChanged(boolean cfi); + void notifyCallForwardingChangedUsingSubId(in long subId, boolean cfi); void notifyDataActivity(int state); + void notifyDataActivityUsingSubId(in long subId, int state); void notifyDataConnection(int state, boolean isDataConnectivityPossible, String reason, String apn, String apnType, in LinkProperties linkProperties, in NetworkCapabilities networkCapabilities, int networkType, boolean roaming); + void notifyDataConnectionUsingSubId(long subId, int state, boolean isDataConnectivityPossible, + String reason, String apn, String apnType, in LinkProperties linkProperties, + in NetworkCapabilities networkCapabilities, int networkType, boolean roaming); void notifyDataConnectionFailed(String reason, String apnType); + void notifyDataConnectionFailedUsingSubId(long subId, String reason, String apnType); void notifyCellLocation(in Bundle cellLocation); + void notifyCellLocationUsingSubId(in long subId, in Bundle cellLocation); void notifyOtaspChanged(in int otaspMode); void notifyCellInfo(in List<CellInfo> cellInfo); void notifyPreciseCallState(int ringingCallState, int foregroundCallState, @@ -47,5 +61,7 @@ interface ITelephonyRegistry { void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause); void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn, String failCause); + void notifyCellInfoUsingSubId(in long subId, in List<CellInfo> cellInfo); void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo); + void notifyVoLteServiceStateChanged(in VoLteServiceState lteState); } diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index 08f4379..aecf955 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -58,6 +58,7 @@ public class PhoneConstants { public static final int PHONE_TYPE_CDMA = RILConstants.CDMA_PHONE; public static final int PHONE_TYPE_SIP = RILConstants.SIP_PHONE; public static final int PHONE_TYPE_THIRD_PARTY = RILConstants.THIRD_PARTY_PHONE; + public static final int PHONE_TYPE_IMS = RILConstants.IMS_PHONE; // Modes for LTE_ON_CDMA public static final int LTE_ON_CDMA_UNKNOWN = RILConstants.LTE_ON_CDMA_UNKNOWN; @@ -133,4 +134,55 @@ public class PhoneConstants { /** APN type for IA Initial Attach APN */ public static final String APN_TYPE_IA = "ia"; + // FIXME: This looks to be used as default phoneId, rename + // or use SubscriptionManager.DEFAULT_SUB_ID + public static final int DEFAULT_SUBSCRIPTION = 0; + + // FIXME: This looks to be used as invalid phoneId, rename + // or use SubscriptionManager.INVALID_SUB_ID + public static final int INVALID_SUBSCRIPTION = -1; + + public static final int RIL_CARD_MAX_APPS = 8; + + public static final int DEFAULT_CARD_INDEX = 0; + + public static final int MAX_PHONE_COUNT_SINGLE_SIM = 1; + + public static final int MAX_PHONE_COUNT_DUAL_SIM = 2; + + public static final int MAX_PHONE_COUNT_TRI_SIM = 3; + + public static final String SUBSCRIPTION_KEY = "subscription"; + + public static final String SLOT_KEY = "slot"; + + public static final String SUB_SETTING = "subSettings"; + + public static final int SUB1 = 0; + public static final int SUB2 = 1; + public static final int SUB3 = 2; + + public static final int EVENT_SUBSCRIPTION_ACTIVATED = 500; + public static final int EVENT_SUBSCRIPTION_DEACTIVATED = 501; + + // TODO: Remove these constants and use an int instead. + public static final int SIM_ID_1 = 0; + public static final int SIM_ID_2 = 1; + public static final int SIM_ID_3 = 2; + public static final int SIM_ID_4 = 3; + + // ICC SIM Application Types + // TODO: Replace the IccCardApplicationStatus.AppType enums with these constants + public static final int APPTYPE_UNKNOWN = 0; + public static final int APPTYPE_SIM = 1; + public static final int APPTYPE_USIM = 2; + public static final int APPTYPE_RUIM = 3; + public static final int APPTYPE_CSIM = 4; + public static final int APPTYPE_ISIM = 5; + + public enum CardUnavailableReason { + REASON_CARD_REMOVED, + REASON_RADIO_UNAVAILABLE, + REASON_SIM_REFRESH_RESET + }; } diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 815211c..0271d0a 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -57,6 +57,7 @@ public interface RILConstants { retries needed */ int MISSING_RESOURCE = 16; /* no logical channel available */ int NO_SUCH_ELEMENT = 17; /* application not found on SIM */ + int SUBSCRIPTION_NOT_SUPPORTED = 26; /* Subscription not supported */ /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */ int NETWORK_MODE_WCDMA_PREF = 0; /* GSM/WCDMA (WCDMA preferred) */ @@ -85,6 +86,7 @@ public interface RILConstants { int CDMA_PHONE = 2; int SIP_PHONE = 3; int THIRD_PARTY_PHONE = 4; + int IMS_PHONE = 5; int LTE_ON_CDMA_UNKNOWN = -1; int LTE_ON_CDMA_FALSE = 0; @@ -282,6 +284,11 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_NV_WRITE_CDMA_PRL = 120; int RIL_REQUEST_NV_RESET_CONFIG = 121; int RIL_REQUEST_SET_RADIO_MODE = 122; + int RIL_REQUEST_DATA_IDLE = 123; + int RIL_REQUEST_SET_UICC_SUBSCRIPTION = 124; + int RIL_REQUEST_ALLOW_DATA = 125; + int RIL_REQUEST_GET_HARDWARE_CONFIG = 126; + int RIL_REQUEST_ICC_SIM_AUTHENTICATION = 127; int RIL_UNSOL_RESPONSE_BASE = 1000; int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000; @@ -322,4 +329,7 @@ cat include/telephony/ril.h | \ int RIL_UNSOL_VOICE_RADIO_TECH_CHANGED = 1035; int RIL_UNSOL_CELL_INFO_LIST = 1036; int RIL_UNSOL_RESPONSE_IMS_NETWORK_STATE_CHANGED = 1037; + int RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED = 1038; + int RIL_UNSOL_SRVCC_STATE_NOTIFY = 1039; + int RIL_UNSOL_HARDWARE_CONFIG_CHANGED = 1040; } diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index 9ad2d42..5954947 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import android.content.Intent; + /** * The intents that the telephony services broadcast. * @@ -48,7 +50,7 @@ public class TelephonyIntents { * * <p class="note"> * Requires the READ_PHONE_STATE permission. - * + * * <p class="note">This is a protected intent that can only be sent * by the system. */ @@ -69,7 +71,7 @@ public class TelephonyIntents { * * <p class="note"> * Requires no permission. - * + * * <p class="note">This is a protected intent that can only be sent * by the system. */ @@ -88,7 +90,7 @@ public class TelephonyIntents { * * <p class="note"> * Requires no permission. - * + * * <p class="note">This is a protected intent that can only be sent * by the system. */ @@ -114,7 +116,7 @@ public class TelephonyIntents { * * <p class="note"> * Requires the READ_PHONE_STATE permission. - * + * * <p class="note">This is a protected intent that can only be sent * by the system. */ @@ -136,7 +138,7 @@ public class TelephonyIntents { * * <p class="note"> * Requires the READ_PHONE_STATE permission. - * + * * <p class="note">This is a protected intent that can only be sent * by the system. */ @@ -176,7 +178,7 @@ public class TelephonyIntents { * * <p class="note"> * Requires the READ_PHONE_STATE permission. - * + * * <p class="note">This is a protected intent that can only be sent * by the system. */ @@ -207,7 +209,7 @@ public class TelephonyIntents { * * <p class="note"> * Requires the READ_PHONE_STATE permission. - * + * * <p class="note">This is a protected intent that can only be sent * by the system. */ @@ -225,7 +227,7 @@ public class TelephonyIntents { * * <p class="note"> * Requires the READ_PHONE_STATE permission. - * + * * <p class="note">This is a protected intent that can only be sent * by the system. */ @@ -243,7 +245,7 @@ public class TelephonyIntents { * * <p class="note"> * Requires the READ_PHONE_STATE permission. - * + * * <p class="note">This is a protected intent that can only be sent * by the system. */ @@ -315,4 +317,85 @@ public class TelephonyIntents { public static final String EXTRA_PLMN = "plmn"; public static final String EXTRA_SHOW_SPN = "showSpn"; public static final String EXTRA_SPN = "spn"; + + /** + * <p>Broadcast Action: It indicates one column of a siminfo record has been changed + * The intent will have the following extra values:</p> + * <ul> + * <li><em>columnName</em> - The siminfo column that is updated.</li> + * <li><em>stringContent</em> - The string value of the updated column.</li> + * <li><em>intContent</em> - The int value of the updated column.</li> + * </ul> + * <p class="note">This is a protected intent that can only be sent + * by the system. + */ + public static final String ACTION_SIMINFO_CONTENT_CHANGE + = "android.intent.action.ACTION_SIMINFO_CONTENT_CHANGE"; + + /** + * <p>Broadcast Action: It indicates one column of a subinfo record has been changed + * The intent will have the following extra values:</p> + * <ul> + * <li><em>columnName</em> - The siminfo column that is updated.</li> + * <li><em>stringContent</em> - The string value of the updated column.</li> + * <li><em>intContent</em> - The int value of the updated column.</li> + * </ul> + * <p class="note">This is a protected intent that can only be sent + * by the system. + */ + public static final String ACTION_SUBINFO_CONTENT_CHANGE + = "android.intent.action.ACTION_SUBINFO_CONTENT_CHANGE"; + + /** + * <p>Broadcast Action: It indicates siminfo update is completed when SIM inserted state change + * The intent will have the following extra values:</p> + * <p class="note">This is a protected intent that can only be sent + * by the system. + */ + public static final String ACTION_SIMINFO_UPDATED + = "android.intent.action.ACTION_SIMINFO_UPDATED"; + + /** + * <p>Broadcast Action: It indicates subinfo record update is completed + * when SIM inserted state change + * The intent will have the following extra values:</p> + * <p class="note">This is a protected intent that can only be sent + * by the system. + */ + public static final String ACTION_SUBINFO_RECORD_UPDATED + = "android.intent.action.ACTION_SUBINFO_RECORD_UPDATED"; + + public static final String EXTRA_COLUMN_NAME = "columnName"; + public static final String EXTRA_INT_CONTENT = "intContent"; + public static final String EXTRA_STRING_CONTENT = "stringContent"; + + /** + * Broadcast Action: The default subscription has changed. This has the following + * extra values:</p> + * <ul> + * <li><em>subscription</em> - A int, the current default subscription.</li> + * </ul> + */ + public static final String ACTION_DEFAULT_SUBSCRIPTION_CHANGED + = "android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED"; + + /** + * Broadcast Action: The default data subscription has changed. This has the following + * extra values:</p> + * <ul> + * <li><em>subscription</em> - A int, the current data default subscription.</li> + * </ul> + */ + public static final String ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED + = "android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED"; + + /** + * Broadcast Action: The default voice subscription has changed. This has the following + * extra values:</p> + * <ul> + * <li><em>subscription</em> - A int, the current voice default subscription.</li> + * </ul> + */ + public static final String ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED + = "android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED"; } diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index f95e081..5ec4247 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -187,4 +187,26 @@ public interface TelephonyProperties * Ignore RIL_UNSOL_NITZ_TIME_RECEIVED completely, used for debugging/testing. */ static final String PROPERTY_IGNORE_NITZ = "telephony.test.ignore.nitz"; + + /** + * Property to set multi sim feature. + * Type: String(dsds, dsda) + */ + static final String PROPERTY_MULTI_SIM_CONFIG = "persist.radio.multisim.config"; + + /** + * Property to store default subscription. + */ + static final String PROPERTY_DEFAULT_SUBSCRIPTION = "persist.radio.default.sub"; + + /** + * Property to enable MMS Mode. + * Type: string ( default = silent, enable to = prompt ) + */ + static final String PROPERTY_MMS_TRANSACTION = "mms.transaction"; + + /** + * Set to the sim count. + */ + static final String PROPERTY_SIM_COUNT = "ro.telephony.sim.count"; } |