Merge "Modify theme to DialerSettingsLight"
diff --git a/Android.bp b/Android.bp
index 76e910f..a06d5ef 100644
--- a/Android.bp
+++ b/Android.bp
@@ -22,7 +22,6 @@
"telephony-common",
"voip-common",
"ims-common",
- "org.apache.http.legacy",
"libprotobuf-java-lite",
"unsupportedappusage",
],
@@ -32,10 +31,10 @@
"androidx.preference_preference",
"androidx.recyclerview_recyclerview",
"androidx.legacy_legacy-preference-v14",
- "guava",
- "volley",
"android-support-annotations",
"com.android.phone.common-lib",
+ "guava",
+ "PlatformProperties",
],
srcs: [
@@ -79,4 +78,4 @@
proto: {
type: "lite",
},
-}
\ No newline at end of file
+}
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 59c1775..a7c2073 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -32,10 +32,8 @@
<protected-broadcast android:name="android.intent.action.EMERGENCY_CALL_STATE_CHANGED" />
<protected-broadcast android:name="android.intent.action.SIG_STR" />
<protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
- <protected-broadcast android:name="android.intent.action.DATA_CONNECTION_FAILED" />
<protected-broadcast android:name="android.intent.action.DATA_STALL_DETECTED" />
<protected-broadcast android:name="android.intent.action.SIM_STATE_CHANGED" />
- <protected-broadcast android:name="android.intent.action.NETWORK_SET_TIME" />
<protected-broadcast android:name="com.android.internal.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS" />
<protected-broadcast android:name="android.intent.action.ACTION_MDN_STATE_CHANGED" />
<protected-broadcast android:name="android.provider.Telephony.SPN_STRINGS_UPDATED" />
@@ -77,7 +75,7 @@
<protected-broadcast android:name= "com.android.imsconnection.DISCONNECTED" />
<protected-broadcast android:name= "com.android.intent.action.IMS_FEATURE_CHANGED" />
<protected-broadcast android:name= "com.android.intent.action.IMS_CONFIG_CHANGED" />
- <protected-broadcast android:name= "com.android.ims.REGISTRATION_ERROR" />
+ <protected-broadcast android:name= "android.telephony.ims.action.WFC_IMS_REGISTRATION_ERROR" />
<protected-broadcast android:name= "com.android.phone.vvm.omtp.sms.REQUEST_SENT" />
<protected-broadcast android:name= "com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT" />
<protected-broadcast android:name= "com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED" />
@@ -95,6 +93,9 @@
<!-- For Vendor Debugging in Telephony -->
<protected-broadcast android:name="android.telephony.action.ANOMALY_REPORTED" />
+ <protected-broadcast android:name= "android.intent.action.SUBSCRIPTION_INFO_RECORD_ADDED" />
+ <protected-broadcast android:name= "android.intent.action.ACTION_MANAGED_ROAMING_IND" />
+
<!-- Allows granting runtime permissions to telephony related components. -->
<uses-permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS" />
@@ -130,8 +131,8 @@
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.SEND_RESPOND_VIA_MESSAGE" />
- <uses-permission android:name="android.permission.SET_TIME" />
<uses-permission android:name="android.permission.SET_TIME_ZONE" />
+ <uses-permission android:name="android.permission.SUGGEST_TELEPHONY_TIME_AND_ZONE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
@@ -210,6 +211,7 @@
ACTION_SIM_SLOT_STATUS_CHANGED broadcast to start activities
from the background. -->
<uses-permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND" />
+ <uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
<application android:name="PhoneApp"
android:persistent="true"
@@ -243,6 +245,15 @@
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="tel" />
</intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL_EMERGENCY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL_EMERGENCY" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:scheme="tel" />
+ </intent-filter>
</activity>
<activity android:name="ADNList" />
@@ -299,6 +310,15 @@
</intent-filter>
</activity>
+ <activity android:name="CdmaCallForwardOptions"
+ android:label="@string/labelCF"
+ android:configChanges="orientation|screenSize|keyboardHidden"
+ android:theme="@style/DialerSettingsLight">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
<activity android:name="GsmUmtsCallBarringOptions"
android:label="@string/labelCallBarring"
android:configChanges="orientation|screenSize|keyboardHidden"
@@ -500,7 +520,7 @@
<receiver android:name="com.android.services.telephony.sip.SipIncomingCallReceiver">
<intent-filter>
- <action android:name="com.android.phone.SIP_INCOMING_CALL" />
+ <action android:name="android.net.sip.action.SIP_INCOMING_CALL" />
</intent-filter>
</receiver>
@@ -531,6 +551,12 @@
android:uiOptions="splitActionBarWhenNarrow">
</activity>
+ <service android:name="com.android.services.telephony.sip.components.TelephonySipService">
+ <intent-filter>
+ <action android:name="android.net.sip.action.START_SIP" />
+ </intent-filter>
+ </service>
+
<!-- End SIP -->
<activity android:name="MMIDialogActivity"
@@ -623,5 +649,33 @@
<action android:name="android.telephony.data.DataService" />
</intent-filter>
</service>
+
+ <provider
+ android:name="ServiceStateProvider"
+ android:authorities="service-state"
+ android:exported="true"
+ android:multiprocess="false"
+ android:singleUser="true"
+ android:writePermission="android.permission.MODIFY_PHONE_STATE"/>
+
+ <activity
+ android:name=".settings.RadioInfo"
+ android:label="@string/phone_info_label"
+ android:theme="@style/Theme.AppCompat.DayNight">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEVELOPMENT_PREFERENCE" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".settings.BandMode"
+ android:label="@string/band_mode_title"
+ android:theme="@style/Theme.AppCompat.DayNight">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE_LAUNCH" />
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 22845e0..3aa8121 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -50,3 +50,6 @@
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/com.android.services.telephony.common_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/telephony-common.jar)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/ims-common.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/apex/com.android.telephony/javalib/telephony-common.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/apex/com.android.telephony/javalib/ims-common.jar)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/apex/com.android.telephony.apex)
\ No newline at end of file
diff --git a/OWNERS b/OWNERS
index 5be6fe5..3059d4d 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,14 +1,15 @@
amitmahajan@google.com
breadley@google.com
fionaxu@google.com
-hallliu@google.com
jackyu@google.com
+hallliu@google.com
rgreenwalt@google.com
tgunn@google.com
-refuhoo@google.com
-mpq@google.com
jminjie@google.com
shuoq@google.com
-paulye@google.com
+refuhoo@google.com
nazaninb@google.com
-sarahchin@google.com
\ No newline at end of file
+sarahchin@google.com
+dbright@google.com
+xiaotonj@google.com
+
diff --git a/apex/Android.bp b/apex/Android.bp
index f9e4b67..a7137d9 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -4,7 +4,7 @@
// optional. if unspecified, a default one is auto-generated
androidManifest: "AndroidManifest.xml",
- java_libs: ["telephony-common", "ims-common"],
+ //java_libs: ["telephony-common", "ims-common", "voip-common"],
//apps: ["TeleService", "StkLib", "ONSLib"],
key: "com.android.telephony.key",
@@ -14,7 +14,7 @@
apex {
name: "com.android.telephony",
manifest: "apex_manifest.json",
- apps: ["StkLib"],
+ //apps: ["StkLib"],
defaults:["com.android.telephony-defaults"],
}
diff --git a/res/drawable/preference_background.xml b/res/drawable/preference_background.xml
index 19ca432..1ec90fb 100644
--- a/res/drawable/preference_background.xml
+++ b/res/drawable/preference_background.xml
@@ -21,7 +21,7 @@
android:insetBottom="0dip">
<shape android:shape="rectangle">
- <solid android:color="@*android:color/background_material_light" />
+ <solid android:color="@color/background_material_light" />
</shape>
</inset>
diff --git a/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml b/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
deleted file mode 100644
index 905dc55..0000000
--- a/res/drawable/progress_indeterminate_horizontal_material_trimmed.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 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.
--->
-
-<!-- Variant of progress_indeterminate_horizontal_material in frameworks/base/core/res, which
- draws the whole height of the progress bar instead having blank space above and below the
- bar. -->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/vector_drawable_progress_indeterminate_horizontal_trimmed" >
- <target
- android:name="rect2_grp"
- android:animation="@*android:anim/progress_indeterminate_horizontal_rect2" />
- <target
- android:name="rect1_grp"
- android:animation="@*android:anim/progress_indeterminate_horizontal_rect1" />
-</animated-vector>
\ No newline at end of file
diff --git a/res/layout/choose_network_progress_header.xml b/res/layout/choose_network_progress_header.xml
deleted file mode 100644
index 671c297..0000000
--- a/res/layout/choose_network_progress_header.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 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.
--->
-
-<FrameLayout
- android:layout_width="match_parent"
- android:layout_height="3dp"
- xmlns:android="http://schemas.android.com/apk/res/android">
- <View
- android:id="@+id/progress_bar_background"
- style="@style/TrimmedHorizontalProgressBar"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?android:attr/colorSecondary" />
- <ProgressBar
- android:id="@+id/progress_bar_animation"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/TrimmedHorizontalProgressBar"
- android:indeterminate="true" />
-</FrameLayout>
\ No newline at end of file
diff --git a/res/layout/emergency_dialer.xml b/res/layout/emergency_dialer.xml
index d14a679..ab32c62 100644
--- a/res/layout/emergency_dialer.xml
+++ b/res/layout/emergency_dialer.xml
@@ -58,8 +58,6 @@
android:accessibilityPaneTitle="@string/pane_title_emergency_dialpad"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingLeft="36dp"
- android:paddingRight="36dp"
android:paddingBottom="@dimen/dialpad_bottom_padding"
android:visibility="visible">
<LinearLayout
@@ -73,6 +71,7 @@
android:id="@+id/emergency_action_group"
android:layout_height="64dp"
android:layout_width="match_parent"
+ android:layout_marginHorizontal="36dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp">
@@ -155,8 +154,14 @@
</FrameLayout>
</com.android.phone.EmergencyActionGroup>
-
+ <Space
+ android:id="@+id/emergency_info_dialpad_spacer"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
<include layout="@layout/dialpad_view_unthemed"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
android:theme="?attr/dialpadTheme" />
</LinearLayout>
diff --git a/res/layout/pref_dialog_editpin.xml b/res/layout/pref_dialog_editpin.xml
deleted file mode 100644
index 94cdadf..0000000
--- a/res/layout/pref_dialog_editpin.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<!-- Layout used as the dialog's content View for EditTextPreference. -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@*android:id/edittext_container"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:padding="?android:attr/dialogPreferredPadding">
-
- <TextView android:id="@android:id/message"
- style="?android:attr/textAppearanceSmall"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="?android:attr/textColorSecondary" />
-
-</LinearLayout>
diff --git a/res/values-af/config.xml b/res/values-af/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-af/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-am/config.xml b/res/values-am/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-am/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ar/config.xml b/res/values-ar/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ar/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-as/config.xml b/res/values-as/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-as/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-az/config.xml b/res/values-az/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-az/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-b+sr+Latn/config.xml b/res/values-b+sr+Latn/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-b+sr+Latn/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-be/config.xml b/res/values-be/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-be/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-bg/config.xml b/res/values-bg/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-bg/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-bn/config.xml b/res/values-bn/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-bn/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-bs/config.xml b/res/values-bs/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-bs/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ca/config.xml b/res/values-ca/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ca/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-cs/config.xml b/res/values-cs/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-cs/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-da/config.xml b/res/values-da/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-da/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-de/config.xml b/res/values-de/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-de/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-el/config.xml b/res/values-el/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-el/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-en-rAU/config.xml b/res/values-en-rAU/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-en-rAU/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-en-rCA/config.xml b/res/values-en-rCA/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-en-rCA/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-en-rGB/config.xml b/res/values-en-rGB/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-en-rGB/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-en-rIN/config.xml b/res/values-en-rIN/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-en-rIN/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-en-rXC/config.xml b/res/values-en-rXC/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-en-rXC/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-es-rUS/config.xml b/res/values-es-rUS/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-es-rUS/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-es/config.xml b/res/values-es/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-es/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-et/config.xml b/res/values-et/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-et/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-eu/config.xml b/res/values-eu/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-eu/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-fa/config.xml b/res/values-fa/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-fa/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-fi/config.xml b/res/values-fi/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-fi/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-fr-rCA/config.xml b/res/values-fr-rCA/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-fr-rCA/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-fr/config.xml b/res/values-fr/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-fr/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-gl/config.xml b/res/values-gl/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-gl/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-gu/config.xml b/res/values-gu/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-gu/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-h500dp/dimens.xml b/res/values-h500dp/dimens.xml
index 2c7c797..d74f0a1 100644
--- a/res/values-h500dp/dimens.xml
+++ b/res/values-h500dp/dimens.xml
@@ -16,5 +16,5 @@
-->
<resources>
- <dimen name="dialpad_bottom_padding">36dp</dimen>
+ <dimen name="dialpad_bottom_padding">16dp</dimen>
</resources>
\ No newline at end of file
diff --git a/res/values-hi/config.xml b/res/values-hi/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-hi/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-hr/config.xml b/res/values-hr/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-hr/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-hu/config.xml b/res/values-hu/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-hu/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-hy/config.xml b/res/values-hy/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-hy/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-in/config.xml b/res/values-in/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-in/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-is/config.xml b/res/values-is/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-is/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-it/config.xml b/res/values-it/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-it/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-iw/config.xml b/res/values-iw/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-iw/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ja/config.xml b/res/values-ja/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ja/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ka/config.xml b/res/values-ka/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ka/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-kk/config.xml b/res/values-kk/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-kk/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-km/config.xml b/res/values-km/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-km/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-kn/config.xml b/res/values-kn/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-kn/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ko/config.xml b/res/values-ko/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ko/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ky/config.xml b/res/values-ky/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ky/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-lo/config.xml b/res/values-lo/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-lo/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-lt/config.xml b/res/values-lt/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-lt/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-lv/config.xml b/res/values-lv/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-lv/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-mk/config.xml b/res/values-mk/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-mk/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ml/config.xml b/res/values-ml/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ml/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-mn/config.xml b/res/values-mn/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-mn/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-mr/config.xml b/res/values-mr/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-mr/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ms/config.xml b/res/values-ms/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ms/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-my/config.xml b/res/values-my/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-my/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-nb/config.xml b/res/values-nb/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-nb/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ne/config.xml b/res/values-ne/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ne/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index fa5c8a1..f7d831b 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -27,31 +27,31 @@
<item name="android:dialogTheme">@style/DialerAlertDialogTheme</item>
</style>
- <style name="EmergencyInfoNameTextAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <style name="EmergencyInfoNameTextAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">@dimen/emergency_info_name_text_size</item>
</style>
- <style name="EmergencyInfoHintTextAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <style name="EmergencyInfoHintTextAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textColor">@color/white_70_percent</item>
<item name="android:textSize">@dimen/emergency_info_hint_text_size</item>
</style>
- <style name="EmergencyInfoTapHintTextAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <style name="EmergencyInfoTapHintTextAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">@dimen/emergency_info_tap_hint_text_size</item>
</style>
- <style name="ShortcutViewHintTextAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <style name="ShortcutViewHintTextAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textColor">@android:color/white</item>
</style>
- <style name="PhoneNumberTextAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <style name="PhoneNumberTextAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">@dimen/emergency_shortcut_number_text_size</item>
</style>
@@ -62,8 +62,8 @@
<item name="android:textSize">@dimen/emergency_shortcut_type_text_size</item>
</style>
- <style name="PhoneNumberTapHintAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <style name="PhoneNumberTapHintAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">@dimen/emergency_shortcut_tap_hint_text_size</item>
</style>
diff --git a/res/values-nl/config.xml b/res/values-nl/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-nl/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-or/config.xml b/res/values-or/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-or/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-pa/config.xml b/res/values-pa/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-pa/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-pl/config.xml b/res/values-pl/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-pl/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-pt-rPT/config.xml b/res/values-pt-rPT/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-pt-rPT/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-pt/config.xml b/res/values-pt/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-pt/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ro/config.xml b/res/values-ro/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ro/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ru/config.xml b/res/values-ru/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ru/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-si/config.xml b/res/values-si/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-si/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sk/config.xml b/res/values-sk/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sk/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sl/config.xml b/res/values-sl/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sl/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sq/config.xml b/res/values-sq/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sq/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sr/config.xml b/res/values-sr/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sr/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sv/config.xml b/res/values-sv/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sv/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-sw/config.xml b/res/values-sw/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-sw/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ta/config.xml b/res/values-ta/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ta/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-te/config.xml b/res/values-te/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-te/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-th/config.xml b/res/values-th/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-th/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-tl/config.xml b/res/values-tl/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-tl/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-tr/config.xml b/res/values-tr/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-tr/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-uk/config.xml b/res/values-uk/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-uk/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-ur/config.xml b/res/values-ur/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-ur/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-uz/config.xml b/res/values-uz/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-uz/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-vi/config.xml b/res/values-vi/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-vi/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-zh-rCN/config.xml b/res/values-zh-rCN/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-zh-rCN/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-zh-rHK/config.xml b/res/values-zh-rHK/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-zh-rHK/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-zh-rTW/config.xml b/res/values-zh-rTW/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-zh-rTW/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values-zu/config.xml b/res/values-zu/config.xml
deleted file mode 100644
index 509a3c8..0000000
--- a/res/values-zu/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
-
-<!-- NOTE: Many variables that used to be in this file have been migrated to
- CarrierConfigManager.java. Please consider whether new variables belong
- there before adding to this file. Variables here should be more closely
- related to devices than to networks. -->
-
-<!-- Phone app resources that may need to be customized
- for different hardware or product builds. -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
-</resources>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 8d84baf..fca8acf 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -15,21 +15,6 @@
-->
<resources>
- <!-- Base attributes available to CheckBoxPreference. Copied from frameworks/base/core/res. -->
- <declare-styleable name="CheckBoxPreference">
- <!-- The summary for the Preference in a PreferenceActivity screen when the
- CheckBoxPreference is checked. If separate on/off summaries are not
- needed, the summary attribute can be used instead. -->
- <attr name="android:summaryOn" />
- <!-- The summary for the Preference in a PreferenceActivity screen when the
- CheckBoxPreference is unchecked. If separate on/off summaries are not
- needed, the summary attribute can be used instead. -->
- <attr name="android:summaryOff" />
- <!-- The state (true for on, or false for off) that causes dependents to be disabled. By default,
- dependents will be disabled when this is unchecked, so the value of this preference is false. -->
- <attr name="android:disableDependentsState" />
- </declare-styleable>
-
<declare-styleable name="EditPhoneNumberPreference">
<!-- The enable button text. -->
<attr name="enableButtonText" format="string" />
diff --git a/res/values/config.xml b/res/values/config.xml
index 8bc1919..d4e4c79 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -209,7 +209,7 @@
<!-- The package to handle visual voicemail if the default dialer or the package
CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING does not handle it -->
- <string name="system_visual_voicemail_client"></string>
+ <string name="system_visual_voicemail_client" translatable="false"/>
<!-- Flag to enable VVM3 visual voicemail. VVM3 is used by Verizon Wireless. -->
<bool name="vvm3_enabled">false</bool>
@@ -235,6 +235,12 @@
<!-- Flag indicating whether the device supports RTT (real-time text) -->
<bool name="config_support_rtt">false</bool>
+ <!-- String indicating the package name of the device ImsService implementation for MMTEL. -->
+ <string name="config_ims_mmtel_package" translatable="false"/>
+
+ <!-- String indicating the package name of the device ImsService implementation for RCS. -->
+ <string name="config_ims_rcs_package" translatable="false"/>
+
<!-- The package name for the platform number verification supplier app. -->
<string name="platform_number_verification_package" translatable="false"></string>
@@ -251,6 +257,14 @@
audio stream which the remote party will be able to hear. -->
<bool name="config_support_telephony_audio_device">false</bool>
+ <string-array translatable="false" name="config_volte_provision_error_on_publish_response">
+ <item>403 not authorized for presence</item>
+ </string-array>
+
+ <string-array translatable="false" name="config_rcs_provision_error_on_publish_response">
+ <item>404 not found</item>
+ </string-array>
+
<!-- The country list that shortcut view can be enabled. -->
<string-array name="config_countries_to_enable_shortcut_view" translatable="false">
</string-array>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b97ef10..b74b2ff 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -273,6 +273,15 @@
<string name="sum_cfnrc_disabled">Off</string>
<!-- Error message displayed after failing to disable forwarding calls when the phone is unreachable -->
<string name="disable_cfnrc_forbidden">Your carrier doesn\'t support disabling call forwarding when your phone is unreachable.</string>
+ <string name="registration_cf_forbidden">Your carrier doesn\'t support call forwarding.</string>
+
+ <!-- Cdma Call waiting settings screen, setting option name -->
+ <string name="cdma_call_waiting">Turn on call waiting?</string>
+ <string name="enable_cdma_call_waiting_setting">During a call, you\'ll be notified about incoming calls</string>
+ <string name="enable_cdma_cw">Turn on</string>
+ <string name="disable_cdma_cw">Cancel</string>
+ <string name="cdma_call_waiting_in_ims_on">CDMA Call Waiting under IMS On</string>
+ <string name="cdma_call_waiting_in_ims_off">CDMA Call Waiting under IMS Off</string>
<!-- Title of the progress dialog displayed while updating Call settings -->
<string name="updating_title">Call settings</string>
@@ -438,6 +447,17 @@
<item>LTE/TDSCDMA/GSM/WCDMA</item>
<item>TDSCDMA/CDMA/EVDO/GSM/WCDMA </item>
<item>LTE/TDSCDMA/CDMA/EVDO/GSM/WCDMA</item>
+ <item>NR only</item>
+ <item>NR/LTE</item>
+ <item>NR/LTE/CDMA/EvDo</item>
+ <item>NR/LTE/GSM/WCDMA</item>
+ <item>NR/LTE/CDMA/EvDo/GSM/WCDMA</item>
+ <item>NR/LTE/WCDMA</item>
+ <item>NR/LTE/TDSCDMA</item>
+ <item>NR/LTE/TDSCDMA/GSM</item>
+ <item>NR/LTE/TDSCDMA/WCDMA</item>
+ <item>NR/LTE/TDSCDMA/GSM/WCDMA</item>
+ <item>NR/LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA</item>
</string-array>
<!-- The preferred network modes RIL constants, in order of the modes above,
e.g. the choice "GSM/WCDMA preferred" has the corresponding value "0" -->
@@ -465,6 +485,17 @@
<item>"20"</item>
<item>"21"</item>
<item>"22"</item>
+ <item>"23"</item>
+ <item>"24"</item>
+ <item>"25"</item>
+ <item>"26"</item>
+ <item>"27"</item>
+ <item>"28"</item>
+ <item>"29"</item>
+ <item>"30"</item>
+ <item>"31"</item>
+ <item>"32"</item>
+ <item>"33"</item>
</string-array>
<!-- The following strings are summaries for preferred network modes in Mobile network settings,
@@ -493,6 +524,8 @@
<string name="preferred_network_mode_lte_gsm_wcdma_summary">Preferred network mode: GSM/WCDMA/LTE</string>
<!-- CDMA+LTE/EVDO -->
<string name="preferred_network_mode_lte_cdma_evdo_summary">Preferred network mode: CDMA+LTE/EVDO</string>
+ <!-- LTE/CDMA/EvDo/GSM/WCDMA [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_lte_cdma_evdo_gsm_wcdma_summary">Preferred network mode: LTE/CDMA/EvDo/GSM/WCDMA</string>
<!-- Global -->
<string name="preferred_network_mode_global_summary">Preferred network mode: Global</string>
<!-- LTE / WCDMA -->
@@ -521,6 +554,28 @@
<string name="preferred_network_mode_tdscdma_cdma_evdo_gsm_wcdma_summary">Preferred network mode: TDSCDMA/CDMA/EvDo/GSM/WCDMA</string>
<!-- LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA -->
<string name="preferred_network_mode_lte_tdscdma_cdma_evdo_gsm_wcdma_summary">Preferred network mode: LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA</string>
+ <!-- NR only [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_only_summary">Preferred network mode: NR only</string>
+ <!-- NR / LTE [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_lte_summary">Preferred network mode: NR / LTE</string>
+ <!-- NR/LTE/CDMA/EvDo [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_lte_cdma_evdo_summary">Preferred network mode: NR/LTE/CDMA/EvDo</string>
+ <!-- NR/LTE/GSM/WCDMA [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_lte_gsm_wcdma_summary">Preferred network mode: NR/LTE/GSM/WCDMA</string>
+ <!-- NR/LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_lte_cdma_evdo_gsm_wcdma_summary">Preferred network mode: NR/LTE/CDMA/EvDo/GSM/WCDMA</string>
+ <!-- NR/LTE/WCDMA [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_lte_wcdma_summary">Preferred network mode: NR/LTE/WCDMA</string>
+ <!-- NR/LTE/TDSCDMA [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_lte_tdscdma_summary">Preferred network mode: NR/LTE/TDSCDMA</string>
+ <!-- NR/LTE/TDSCDMA/GSM [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_lte_tdscdma_gsm_summary">Preferred network mode: NR/LTE/TDSCDMA/GSM</string>
+ <!-- NR/LTE/TDSCDMA/WCDMA [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_lte_tdscdma_wcdma_summary">Preferred network mode: NR/LTE/TDSCDMA/WCDMA</string>
+ <!-- NR/LTE/TDSCDMA/GSM/WCDMA [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_lte_tdscdma_gsm_wcdma_summary">Preferred network mode: NR/LTE/TDSCDMA/GSM/WCDMA</string>
+ <!-- NR/LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA [CHAR LIMIT=NONE] -->
+ <string name="preferred_network_mode_nr_lte_tdscdma_cdma_evdo_gsm_wcdma_summary">Preferred network mode: NR/LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA</string>
<!-- Mobile network settings screen, name for call settings category -->
<string name="call_category">Calling</string>
@@ -757,6 +812,10 @@
<string name="multi_category_enable">Multi-category enabled</string>
<string name="multi_category_disable">Multi-category disabled</string>
+ <string name="network_recommended">\u0020(recommended)</string>
+ <string name="network_5G" translatable="false">5G</string>
+ <string name="network_lte_pure" translatable="false">LTE</string>
+ <string name="network_4G_pure" translatable="false">4G</string>
<string name="network_lte">LTE (recommended)</string>
<string name="network_4G">4G (recommended)</string>
<string name="network_3G" translatable="false">3G</string>
@@ -1397,6 +1456,17 @@
<string name="alert_dialog_no">No</string>
<!-- ECM: ECM exit dialog choice -->
<string name="alert_dialog_dismiss">Dismiss</string>
+ <!-- ECM: Notification body wihout data restriction hint -->
+ <string name="phone_in_ecm_call_notification_text_without_data_restriction_hint">The phone is in emergency callback mode</string>
+ <!-- ECM: Displays the time when ECM will end without data restriction hint, Example: "Until 10:45 AM" -->
+ <string name="phone_in_ecm_notification_complete_time_without_data_restriction_hint">Until <xliff:g id="completeTime">%s</xliff:g></string>
+ <!-- ECM: Dialog box message without data restriction hint for exiting from the notifications screen -->
+ <plurals name="alert_dialog_exit_ecm_without_data_restriction_hint">
+ <!-- number of minutes is one -->
+ <item quantity="one">The phone will be in emergency callback mode for <xliff:g id="count">%s</xliff:g> minute.\nDo you want to exit now?</item>
+ <!-- number of minutes is not equal to one -->
+ <item quantity="other">The phone will be in emergency callback mode for <xliff:g id="count">%s</xliff:g> minutes.\nDo you want to exit now?</item>
+ </plurals>
<!-- For incoming calls, this is a string we can get from a CDMA network instead of
the actual phone number, to indicate there's no number present. DO NOT TRANSLATE. -->
@@ -1793,8 +1863,6 @@
<string name="messageCallBarring">Enter password</string>
<!-- Call barring settings screen, section heading -->
<string name="call_barring_settings">Call barring settings</string>
- <!-- Call barring settings screen, deactivate all call barring settings -->
- <string name="call_barring_deactivate_all_no_password">Deactivate all call barring settings?</string>
<!-- In-call screen: error message shown when the user attempts to place a call, but the network
does not have enough resources (e.g. it is busy) and the call cannot be placed. -->
<string name="callFailed_NetworkBusy">Network is busy. Please try your call again later.</string>
@@ -2094,5 +2162,4 @@
<string name="carrier_provisioning">Carrier Provisioning Info</string>
<!-- Trigger Carrier Provisioning [CHAR LIMIT=NONE] -->
<string name="trigger_carrier_provisioning">Trigger Carrier Provisioning</string>
-
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index e95142b..e8a0bed 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -211,12 +211,6 @@
<item name="android:textColor">?android:attr/textColorPrimaryInverseDisableOnly</item>
</style>
- <style name="TrimmedHorizontalProgressBar" parent="android:Widget.Material.ProgressBar.Horizontal">
- <item name="android:indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material_trimmed</item>
- <item name="android:minHeight">3dip</item>
- <item name="android:maxHeight">3dip</item>
- </style>
-
<style name="Empty" parent="@android:style/Theme.Material.Light">
<item name="android:forceDarkAllowed">true</item>
<item name="android:windowIsTranslucent">true</item>
@@ -227,33 +221,6 @@
<item name="android:backgroundDimEnabled">true</item>
</style>
- <style name="InCallAnimationStyle" parent="@*android:style/Animation.Holo.Activity">
- <!-- Suppress task-to-task animation happening during the transition from
- OutgoingCallBroadcaster (and SipOptionHandler) to InCallScreen.
- The transition unexpectedly happens during the transition (inside the phone task),
- because InCallScreen is using android:launchMode="singleInstance".
-
- - taskOpenEnterAnimation/taskOpenExitAnimation is used for the first time
- InCallScreen instance is created.
-
- - taskToFrontEnterAnimation/taskToFrontExitAnimation is used when InCallScreen
- is already available.
- (Note that InCallScreen won't be destroyed once it is created)
-
- TODO: try removing the flag instead -->
- <item name="*android:taskOpenEnterAnimation">@*android:anim/activity_open_enter</item>
- <item name="*android:taskOpenExitAnimation">@*android:anim/activity_open_exit</item>
- <item name="*android:taskToFrontEnterAnimation">@*android:anim/activity_open_enter</item>
- <item name="*android:taskToFrontExitAnimation">@*android:anim/activity_open_exit</item>
- </style>
-
- <style name="OutgoingAnimationStyle" parent="@*android:style/Animation.Holo.Activity">
- <!-- Suppress task-to-task transition animation happening from
- DialtactsActivity to OutgoingCallBroadcaster. -->
- <item name="*android:taskOpenEnterAnimation">@*android:anim/activity_open_enter</item>
- <item name="*android:taskOpenExitAnimation">@*android:anim/activity_open_exit</item>
- </style>
-
<!-- Style for the call settings action bar. Should be kept in sync with Dialer. -->
<style name="DialtactsActionBarStyle" parent="@style/TelephonyActionBarStyle">
<!-- Shift the title text to the right -->
@@ -284,7 +251,7 @@
<item name="android:src">@drawable/overflow_menu</item>
</style>
- <style name="EmergencyDialerTheme" parent="@*android:style/Theme.DeviceDefault.Settings.Dark.NoActionBar">
+ <style name="EmergencyDialerTheme" parent="@android:style/Theme.Material.NoActionBar">
<item name="android:forceDarkAllowed">true</item>
<item name="android:colorPrimaryDark">?android:attr/colorPrimary</item>
<item name="android:colorBackgroundCacheHint">@null</item>
@@ -293,7 +260,7 @@
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:homeAsUpIndicator">@drawable/ic_back_arrow</item>
<item name="emergencyButtonBackgroundColor">#3cffffff</item>
- <item name="dialpadTheme">@style/Dialpad_DarkTransparent</item>
+ <item name="dialpadTheme">@style/Dialpad_DarkTransparent.Emergency</item>
</style>
<style name="EmergencyDialerThemeDark" parent="@style/EmergencyDialerTheme">
@@ -301,7 +268,15 @@
<item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
<item name="emergencyButtonBackgroundColor">#19414549</item>
<item name="android:colorControlHighlight">#40000000</item>
- <item name="dialpadTheme">@style/Dialpad_LightTransparent</item>
+ <item name="dialpadTheme">@style/Dialpad_LightTransparent.Emergency</item>
+ </style>
+
+ <style name="Dialpad_LightTransparent.Emergency">
+ <item name="dialpad_delete_padding">16dp</item>
+ </style>
+
+ <style name="Dialpad_DarkTransparent.Emergency">
+ <item name="dialpad_delete_padding">16dp</item>
</style>
<style name="EmergencyDialerAlertDialogTheme"
@@ -318,13 +293,6 @@
<item name="android:actionOverflowButtonStyle">@style/DialtactsActionBarOverflow</item>
</style>
- <style name="OutgoingCallBroadcasterTheme" parent="@android:style/Theme.Holo.NoActionBar">
- <item name="android:forceDarkAllowed">true</item>
- <item name="android:windowBackground">@android:color/black</item>
-
- <item name="*android:windowAnimationStyle">@style/OutgoingAnimationStyle</item>
- </style>
-
<style name="DialtactsDigitsTextAppearance">
<item name="android:maxLines">1</item>
<item name="android:textSize">@dimen/dialpad_digits_text_size</item>
@@ -343,48 +311,47 @@
<item name="android:backgroundDimEnabled">false</item>
</style>
- <style name="CallSettingsWithoutDividerTheme" parent="SettingsLight">
- <item name="android:forceDarkAllowed">true</item>
+ <style name="CallSettingsWithoutDividerTheme" parent="DialerSettingsLight">
<item name="android:listDivider">@null</item>
</style>
- <style name="EmergencyInfoNameTextAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">@*android:color/primary_text_default_material_dark</item>
+ <style name="EmergencyInfoNameTextAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
+ <item name="android:textColor">@color/primary_text_default_material_dark</item>
<item name="android:textSize">@dimen/emergency_info_name_text_size</item>
</style>
- <style name="EmergencyInfoHintTextAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">@*android:color/secondary_text_default_material_dark</item>
+ <style name="EmergencyInfoHintTextAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
+ <item name="android:textColor">@color/secondary_text_default_material_dark</item>
<item name="android:textSize">@dimen/emergency_info_hint_text_size</item>
</style>
- <style name="EmergencyInfoTapHintTextAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <style name="EmergencyInfoTapHintTextAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">@dimen/emergency_info_tap_hint_text_size</item>
</style>
- <style name="ShortcutViewHintTextAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">@*android:color/secondary_text_default_material_dark</item>
+ <style name="ShortcutViewHintTextAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
+ <item name="android:textColor">@color/secondary_text_default_material_dark</item>
</style>
- <style name="PhoneNumberTextAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
- <item name="android:textColor">@*android:color/primary_text_default_material_light</item>
+ <style name="PhoneNumberTextAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
+ <item name="android:textColor">@color/primary_text_default_material_light</item>
<item name="android:textSize">@dimen/emergency_shortcut_number_text_size</item>
</style>
<style name="PhoneNumberTypeAppearance">
<item name="android:fontFamily">roboto</item>
- <item name="android:textColor">@*android:color/secondary_text_default_material_light</item>
+ <item name="android:textColor">@color/secondary_text_default_material_light</item>
<item name="android:textSize">@dimen/emergency_shortcut_type_text_size</item>
</style>
- <style name="PhoneNumberTapHintAppearance">
- <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+ <style name="PhoneNumberTapHintAppearance"
+ parent="@android:style/TextAppearance.Material.Subhead">
<item name="android:textColor">@android:color/white</item>
<item name="android:textSize">@dimen/emergency_shortcut_tap_hint_text_size</item>
</style>
diff --git a/res/values/styles_preference.xml b/res/values/styles_preference.xml
index fef4f72..eace2e7 100644
--- a/res/values/styles_preference.xml
+++ b/res/values/styles_preference.xml
@@ -19,22 +19,22 @@
<!-- Things unrelated to preference framework UI customization should go to other styles files -->
<resources>
<!-- Preferences -->
- <style name="SettingsPreference" parent="@*android:style/Preference.DeviceDefault">
+ <style name="SettingsPreference" parent="@style/Preference.Material">
<item name="android:singleLineTitle">false</item>
<item name="android:iconSpaceReserved">true</item>
</style>
- <style name="SettingsSwitchPreference" parent="@*android:style/Preference.DeviceDefault.SwitchPreference">
+ <style name="SettingsSwitchPreference" parent="@style/Preference.SwitchPreference.Material">
<item name="android:iconSpaceReserved">true</item>
<item name="android:singleLineTitle">false</item>
</style>
- <style name="SettingsDialogPreference" parent="@*android:style/Preference.DeviceDefault.DialogPreference">
+ <style name="SettingsDialogPreference" parent="@style/Preference.DialogPreference.Material">
<item name="android:singleLineTitle">false</item>
<item name="android:iconSpaceReserved">true</item>
</style>
- <style name="SettingsPreferenceScreen" parent="@*android:style/Preference.DeviceDefault.PreferenceScreen">
+ <style name="SettingsPreferenceScreen" parent="@style/Preference.PreferenceScreen.Material">
<item name="android:singleLineTitle">false</item>
<item name="android:iconSpaceReserved">true</item>
</style>
diff --git a/res/xml/cdma_call_privacy.xml b/res/xml/cdma_call_privacy.xml
index 1aeeefe..a16a504 100644
--- a/res/xml/cdma_call_privacy.xml
+++ b/res/xml/cdma_call_privacy.xml
@@ -7,4 +7,14 @@
android:title="@string/voice_privacy"
android:persistent="false"
android:summary="@string/voice_privacy_summary"/>
+
+ <PreferenceScreen
+ android:key="call_forwarding_key"
+ android:title="@string/labelCF"
+ android:persistent="false" />
+
+ <com.android.phone.CdmaCallWaitingPreference
+ android:key="call_waiting_key"
+ android:title="@string/labelCW"
+ android:persistent="false" />
</PreferenceScreen>
diff --git a/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java b/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
index 3212c00..2dbd707 100644
--- a/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
+++ b/sip/src/com/android/services/telephony/sip/SipIncomingCallReceiver.java
@@ -84,7 +84,7 @@
}
private boolean isRunningInSystemUser() {
- return UserHandle.myUserId() == UserHandle.USER_SYSTEM;
+ return UserHandle.myUserId() == UserHandle.SYSTEM.getIdentifier();
}
private static void log(String msg) {
diff --git a/sip/src/com/android/services/telephony/sip/SipSettings.java b/sip/src/com/android/services/telephony/sip/SipSettings.java
index ded16df..813ba51 100644
--- a/sip/src/com/android/services/telephony/sip/SipSettings.java
+++ b/sip/src/com/android/services/telephony/sip/SipSettings.java
@@ -42,6 +42,7 @@
import com.android.phone.R;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
@@ -238,9 +239,9 @@
}
private void processActiveProfilesFromSipService() {
- SipProfile[] activeList = {};
+ List<SipProfile> activeList = new ArrayList<>();
try {
- activeList = mSipManager.getListOfProfiles();
+ activeList = mSipManager.getProfiles();
} catch (SipException e) {
log("SipManager could not retrieve SIP profiles: " + e);
}
diff --git a/sip/src/com/android/services/telephony/sip/SipUtil.java b/sip/src/com/android/services/telephony/sip/SipUtil.java
index ff38754..828174e 100644
--- a/sip/src/com/android/services/telephony/sip/SipUtil.java
+++ b/sip/src/com/android/services/telephony/sip/SipUtil.java
@@ -29,12 +29,11 @@
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import com.android.phone.PhoneGlobals;
-import com.android.phone.R;
-import com.android.server.sip.SipService;
import java.io.IOException;
import java.util.ArrayList;
@@ -46,6 +45,7 @@
"com.android.services.telephony.sip.incoming_call_intent";
static final String EXTRA_PHONE_ACCOUNT =
"com.android.services.telephony.sip.phone_account";
+ static final String PHONE_PACKAGE = "com.android.phone";
private SipUtil() {
}
@@ -53,9 +53,9 @@
public static boolean isVoipSupported(Context context) {
return SipManager.isVoipSupported(context) &&
context.getResources().getBoolean(
- com.android.internal.R.bool.config_built_in_sip_phone) &&
- context.getResources().getBoolean(
- com.android.internal.R.bool.config_voice_capable);
+ com.android.internal.R.bool.config_built_in_sip_phone)
+ && ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE))
+ .isVoiceCapable();
}
static PendingIntent createIncomingCallPendingIntent(
@@ -190,7 +190,10 @@
// Migrate SIP database from DE->CE storage if the device has just upgraded.
possiblyMigrateSipDb(phoneGlobalsContext);
// Wait until boot complete to start SIP so that it has access to CE storage.
- SipService.start(phoneGlobalsContext);
+ Intent startSipIntent = new Intent();
+ startSipIntent.setAction(SipManager.ACTION_START_SIP);
+ startSipIntent.setPackage(PHONE_PACKAGE);
+ phoneGlobalsContext.startService(startSipIntent);
}
/**
diff --git a/sip/src/com/android/services/telephony/sip/components/TelephonySipService.java b/sip/src/com/android/services/telephony/sip/components/TelephonySipService.java
new file mode 100644
index 0000000..5b863b1
--- /dev/null
+++ b/sip/src/com/android/services/telephony/sip/components/TelephonySipService.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.services.telephony.sip.components;
+
+import android.app.Service;
+import android.content.Intent;
+import android.net.sip.SipManager;
+import android.os.IBinder;
+
+import com.android.server.sip.SipService;
+
+/**
+ * This class represents telephony SIP service which handle start SIP service requests from
+ * Telephony.
+ */
+public class TelephonySipService extends Service {
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if ((intent != null)
+ && SipManager.ACTION_START_SIP.equals(intent.getAction())) {
+ SipService.start(this);
+ }
+ return START_STICKY;
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/src/com/android/phone/CallBarringDeselectAllPreference.java b/src/com/android/phone/CallBarringDeselectAllPreference.java
index e9310f8..7191937 100644
--- a/src/com/android/phone/CallBarringDeselectAllPreference.java
+++ b/src/com/android/phone/CallBarringDeselectAllPreference.java
@@ -19,12 +19,9 @@
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.View;
import android.widget.EditText;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.phone.settings.fdn.EditPinPreference;
/**
@@ -34,9 +31,6 @@
private static final String LOG_TAG = "CallBarringDeselectAllPreference";
private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
- private boolean mShowPassword;
- private Phone mPhone;
-
/**
* CallBarringDeselectAllPreference constructor.
*
@@ -49,28 +43,10 @@
@Override
protected void showDialog(Bundle state) {
- // Finds out if the password field should be shown or not.
- ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
- mShowPassword = !(imsPhone != null && imsPhone.isUtEnabled());
-
- // Selects dialog message depending on if the password field is shown or not.
- setDialogMessage(getContext().getString(mShowPassword
- ? R.string.messageCallBarring : R.string.call_barring_deactivate_all_no_password));
-
- if (DBG) {
- Log.d(LOG_TAG, "showDialog: mShowPassword: " + mShowPassword);
- }
-
+ setDialogMessage(getContext().getString(R.string.messageCallBarring));
super.showDialog(state);
}
- void init(Phone phone) {
- if (DBG) {
- Log.d(LOG_TAG, "init: phoneId = " + phone.getPhoneId());
- }
- mPhone = phone;
- }
-
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
@@ -78,20 +54,7 @@
final EditText editText = (EditText) view.findViewById(android.R.id.edit);
if (editText != null) {
// Hide the input-text-line if the password is not shown.
- editText.setVisibility(mShowPassword ? View.VISIBLE : View.GONE);
+ editText.setVisibility(View.VISIBLE);
}
}
-
- @Override
- protected boolean needInputMethod() {
- // Input method should only be displayed if the password-field is shown.
- return mShowPassword;
- }
-
- /**
- * Returns whether the password field is shown.
- */
- boolean isPasswordShown() {
- return mShowPassword;
- }
}
diff --git a/src/com/android/phone/CallBarringEditPreference.java b/src/com/android/phone/CallBarringEditPreference.java
index edff1e3..5d83de1 100644
--- a/src/com/android/phone/CallBarringEditPreference.java
+++ b/src/com/android/phone/CallBarringEditPreference.java
@@ -35,10 +35,10 @@
import android.widget.TextView;
import android.widget.Toast;
+import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
-import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.phone.settings.fdn.EditPinPreference;
import java.lang.ref.WeakReference;
@@ -57,10 +57,7 @@
private CharSequence mDisableText;
private CharSequence mSummaryOn;
private CharSequence mSummaryOff;
- private CharSequence mDialogMessageEnabled;
- private CharSequence mDialogMessageDisabled;
private int mButtonClicked;
- private boolean mShowPassword;
private final MyHandler mHandler = new MyHandler(this);
private Phone mPhone;
private TimeConsumingPreferenceListener mTcpListener;
@@ -77,9 +74,9 @@
super(context, attrs);
// Get the summary settings, use CheckBoxPreference as the standard.
TypedArray typedArray = context.obtainStyledAttributes(attrs,
- android.R.styleable.CheckBoxPreference, 0, 0);
- mSummaryOn = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOn);
- mSummaryOff = typedArray.getString(android.R.styleable.CheckBoxPreference_summaryOff);
+ R.styleable.CheckBoxPreference, 0, 0);
+ mSummaryOn = typedArray.getString(R.styleable.CheckBoxPreference_summaryOn);
+ mSummaryOff = typedArray.getString(R.styleable.CheckBoxPreference_summaryOff);
mDisableText = context.getText(R.string.disable);
mEnableText = context.getText(R.string.enable);
typedArray.recycle();
@@ -90,10 +87,6 @@
typedArray = context.obtainStyledAttributes(attrs,
R.styleable.CallBarringEditPreference, 0, R.style.EditPhoneNumberPreference);
mFacility = typedArray.getString(R.styleable.CallBarringEditPreference_facility);
- mDialogMessageEnabled = typedArray.getString(
- R.styleable.CallBarringEditPreference_dialogMessageEnabledNoPwd);
- mDialogMessageDisabled = typedArray.getString(
- R.styleable.CallBarringEditPreference_dialogMessageDisabledNoPwd);
typedArray.recycle();
}
@@ -116,7 +109,7 @@
if (!skipReading) {
// Query call barring status
mPhone.getCallBarring(mFacility, "", mHandler.obtainMessage(
- MyHandler.MESSAGE_GET_CALL_BARRING), 0);
+ MyHandler.MESSAGE_GET_CALL_BARRING), CommandsInterface.SERVICE_CLASS_VOICE);
if (mTcpListener != null) {
mTcpListener.onStarted(this, true);
}
@@ -130,29 +123,8 @@
}
@Override
- protected boolean needInputMethod() {
- // Input method should only be displayed if the password-field is shown.
- return mShowPassword;
- }
-
- void setInputMethodNeeded(boolean needed) {
- mShowPassword = needed;
- }
-
- @Override
protected void showDialog(Bundle state) {
- setShowPassword();
- if (mShowPassword) {
- setDialogMessage(getContext().getString(R.string.messageCallBarring));
- } else {
- setDialogMessage(mIsActivated ? mDialogMessageEnabled : mDialogMessageDisabled);
- }
-
- if (DBG) {
- Log.d(LOG_TAG, "showDialog: mShowPassword: " + mShowPassword
- + ", mIsActivated: " + mIsActivated);
- }
-
+ setDialogMessage(getContext().getString(R.string.messageCallBarring));
super.showDialog(state);
}
@@ -204,8 +176,7 @@
editText.setTransformationMethod(PasswordTransformationMethod.getInstance());
editText.setKeyListener(DigitsKeyListener.getInstance());
- // Hide the input-text-line if the password is not shown.
- editText.setVisibility(mShowPassword ? View.VISIBLE : View.GONE);
+ editText.setVisibility(View.VISIBLE);
}
}
@@ -217,17 +188,14 @@
+ positiveResult);
}
if (mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
- String password = null;
- if (mShowPassword) {
- password = getEditText().getText().toString();
+ String password = getEditText().getText().toString();
- // Check if the password is valid.
- if (password == null || password.length() != PW_LENGTH) {
- Toast.makeText(getContext(),
- getContext().getString(R.string.call_barring_right_pwd_number),
- Toast.LENGTH_SHORT).show();
- return;
- }
+ // Check if the password is valid.
+ if (password == null || password.length() != PW_LENGTH) {
+ Toast.makeText(getContext(),
+ getContext().getString(R.string.call_barring_right_pwd_number),
+ Toast.LENGTH_SHORT).show();
+ return;
}
if (DBG) {
@@ -235,7 +203,8 @@
}
// Send set call barring message to RIL layer.
mPhone.setCallBarring(mFacility, !mIsActivated, password,
- mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING), 0);
+ mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_BARRING),
+ CommandsInterface.SERVICE_CLASS_VOICE);
if (mTcpListener != null) {
mTcpListener.onStarted(this, false);
}
@@ -254,11 +223,6 @@
notifyDependencyChange(shouldDisableDependents());
}
- private void setShowPassword() {
- ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
- mShowPassword = !(imsPhone != null && imsPhone.isUtEnabled());
- }
-
@Override
public boolean shouldDisableDependents() {
return mIsActivated;
@@ -310,16 +274,6 @@
pref.mTcpListener.onFinished(pref, false);
} else {
pref.mTcpListener.onFinished(pref, true);
- ImsPhone imsPhone = pref.mPhone != null
- ? (ImsPhone) pref.mPhone.getImsPhone() : null;
- if (!pref.mShowPassword && (imsPhone == null || !imsPhone.isUtEnabled())) {
- // Re-enable password when rejected from NW and modem would perform CSFB
- pref.mShowPassword = true;
- if (DBG) {
- Log.d(LOG_TAG,
- "handleGetCallBarringResponse: mShowPassword changed for CSFB");
- }
- }
}
// Unsuccessful query for call barring.
@@ -374,7 +328,7 @@
"",
obtainMessage(MESSAGE_GET_CALL_BARRING, 0, MESSAGE_SET_CALL_BARRING,
ar.exception),
- 0);
+ CommandsInterface.SERVICE_CLASS_VOICE);
}
}
}
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 3f57cae..9faffa1 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -396,11 +396,7 @@
} else {
if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
prefSet.removePreference(fdnButton);
-
- if (!carrierConfig.getBoolean(
- CarrierConfigManager.KEY_VOICE_PRIVACY_DISABLE_UI_BOOL)) {
- addPreferencesFromResource(R.xml.cdma_call_privacy);
- }
+ addPreferencesFromResource(R.xml.cdma_call_privacy);
} else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
if (mPhone.getIccCard() == null || !mPhone.getIccCard().getIccFdnAvailable()) {
prefSet.removePreference(fdnButton);
diff --git a/src/com/android/phone/CallForwardEditPreference.java b/src/com/android/phone/CallForwardEditPreference.java
index 76f17b1..8e0b685 100644
--- a/src/com/android/phone/CallForwardEditPreference.java
+++ b/src/com/android/phone/CallForwardEditPreference.java
@@ -122,7 +122,27 @@
Log.d(LOG_TAG, "mButtonClicked=" + mButtonClicked + ", positiveResult=" + positiveResult);
// Ignore this event if the user clicked the cancel button, or if the dialog is dismissed
// without any button being pressed (back button press or click event outside the dialog).
- if (this.mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
+ if (isUnknownStatus() && this.mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
+ int action = (mButtonClicked == DialogInterface.BUTTON_POSITIVE) ?
+ CommandsInterface.CF_ACTION_REGISTRATION :
+ CommandsInterface.CF_ACTION_DISABLE;
+ final String number = (action == CommandsInterface.CF_ACTION_DISABLE) ?
+ "" : getPhoneNumber();
+
+ Log.d(LOG_TAG, "reason=" + reason + ", action=" + action + ", number=" + number);
+
+ // Display no forwarding number while we're waiting for confirmation.
+ setSummaryOff("");
+
+ mPhone.setCallForwardingOption(action,
+ reason,
+ number,
+ mServiceClass,
+ 0,
+ mHandler.obtainMessage(MyHandler.MESSAGE_SET_CF,
+ action,
+ MyHandler.MESSAGE_SET_CF));
+ } else if (this.mButtonClicked != DialogInterface.BUTTON_NEGATIVE) {
int action = (isToggled() || (mButtonClicked == DialogInterface.BUTTON_POSITIVE)) ?
CommandsInterface.CF_ACTION_REGISTRATION :
CommandsInterface.CF_ACTION_DISABLE;
@@ -159,6 +179,7 @@
mPhone.setCallForwardingOption(action,
reason,
number,
+ mServiceClass,
time,
mHandler.obtainMessage(MyHandler.MESSAGE_SET_CF,
action,
@@ -193,6 +214,7 @@
Log.i(LOG_TAG, "handleGetCFResponse: Overridding CF number");
}
+ setUnknownStatus(callForwardInfo.status == CommandsInterface.SS_STATUS_UNKNOWN);
setToggled(callForwardInfo.status == 1);
boolean displayVoicemailNumber = false;
if (TextUtils.isEmpty(callForwardInfo.number)) {
@@ -216,7 +238,7 @@
*/
void startCallForwardOptionsQuery() {
if (!mCallForwardByUssd) {
- mPhone.getCallForwardingOption(reason,
+ mPhone.getCallForwardingOption(reason, mServiceClass,
mHandler.obtainMessage(MyHandler.MESSAGE_GET_CF,
// unused in this case
CommandsInterface.CF_ACTION_DISABLE,
@@ -342,6 +364,7 @@
AsyncResult ar = (AsyncResult) msg.obj;
callForwardInfo = null;
+ boolean summaryOff = false;
if (ar.exception != null) {
Log.d(LOG_TAG, "handleGetCFResponse: ar.exception=" + ar.exception);
if (ar.exception instanceof CommandException) {
@@ -359,9 +382,8 @@
mTcpListener.onError(CallForwardEditPreference.this, RESPONSE_ERROR);
}
CallForwardInfo cfInfoArray[] = (CallForwardInfo[]) ar.result;
- if (cfInfoArray.length == 0) {
+ if (cfInfoArray == null || cfInfoArray.length == 0) {
Log.d(LOG_TAG, "handleGetCFResponse: cfInfoArray.length==0");
- setEnabled(false);
mTcpListener.onError(CallForwardEditPreference.this, RESPONSE_ERROR);
} else {
for (int i = 0, length = cfInfoArray.length; i < length; i++) {
@@ -372,10 +394,16 @@
CallForwardInfo info = cfInfoArray[i];
handleCallForwardResult(info);
+ summaryOff = (info.status == CommandsInterface.SS_STATUS_UNKNOWN);
+
+ if (ar.userObj instanceof Throwable) {
+ Log.d(LOG_TAG, "Skipped duplicated error dialog");
+ continue;
+ }
+
// Show an alert if we got a success response but
// with unexpected values.
- // Currently only handle the fail-to-disable case
- // since we haven't observed fail-to-enable.
+ // Handle the fail-to-disable case.
if (msg.arg2 == MESSAGE_SET_CF &&
msg.arg1 == CommandsInterface.CF_ACTION_DISABLE &&
info.status == 1) {
@@ -399,7 +427,21 @@
}
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setNeutralButton(R.string.close_dialog, null);
- builder.setTitle(getContext().getText(R.string.error_updating_title));
+ builder.setTitle(getContext()
+ .getText(R.string.error_updating_title));
+ builder.setMessage(s);
+ builder.setCancelable(true);
+ builder.create().show();
+ } else if (msg.arg2 == MESSAGE_SET_CF &&
+ msg.arg1 == CommandsInterface.CF_ACTION_REGISTRATION &&
+ info.status == 0) {
+ // Handle the fail-to-enable case.
+ CharSequence s = getContext()
+ .getText(R.string.registration_cf_forbidden);
+ AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+ builder.setNeutralButton(R.string.close_dialog, null);
+ builder.setTitle(getContext()
+ .getText(R.string.error_updating_title));
builder.setMessage(s);
builder.setCancelable(true);
builder.create().show();
@@ -412,7 +454,15 @@
// Now whether or not we got a new number, reset our enabled
// summary text since it may have been replaced by an empty
// placeholder.
- updateSummaryText();
+ // for CDMA, doesn't display summary.
+ if (summaryOff) {
+ setSummaryOff("");
+ } else {
+ // Now whether or not we got a new number, reset our enabled
+ // summary text since it may have been replaced by an empty
+ // placeholder.
+ updateSummaryText();
+ }
}
private void handleSetCFResponse(Message msg) {
@@ -421,9 +471,19 @@
Log.d(LOG_TAG, "handleSetCFResponse: ar.exception=" + ar.exception);
// setEnabled(false);
}
+
+ if (ar.result != null) {
+ int arr = (int)ar.result;
+ if (arr == CommandsInterface.SS_STATUS_UNKNOWN) {
+ Log.d(LOG_TAG, "handleSetCFResponse: no need to re get in CDMA");
+ mTcpListener.onFinished(CallForwardEditPreference.this, false);
+ return;
+ }
+ }
+
Log.d(LOG_TAG, "handleSetCFResponse: re get");
if (!mCallForwardByUssd) {
- mPhone.getCallForwardingOption(reason,
+ mPhone.getCallForwardingOption(reason, mServiceClass,
obtainMessage(MESSAGE_GET_CF, msg.arg1, MESSAGE_SET_CF, ar.exception));
} else {
mHandler.sendMessage(mHandler.obtainMessage(mHandler.MESSAGE_GET_CF_USSD,
diff --git a/src/com/android/phone/CallNotifier.java b/src/com/android/phone/CallNotifier.java
index dab04f0..23a9649 100644
--- a/src/com/android/phone/CallNotifier.java
+++ b/src/com/android/phone/CallNotifier.java
@@ -21,6 +21,7 @@
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.media.AudioManager;
+import android.media.AudioSystem;
import android.media.ToneGenerator;
import android.os.AsyncResult;
import android.os.Handler;
@@ -392,10 +393,10 @@
try {
int stream;
if (mBluetoothHeadset != null) {
- stream = isBluetoothAudioOn() ? AudioManager.STREAM_BLUETOOTH_SCO :
- AudioManager.STREAM_VOICE_CALL;
+ stream = isBluetoothAudioOn() ? AudioSystem.STREAM_BLUETOOTH_SCO :
+ AudioSystem.STREAM_VOICE_CALL;
} else {
- stream = AudioManager.STREAM_VOICE_CALL;
+ stream = AudioSystem.STREAM_VOICE_CALL;
}
toneGenerator = new ToneGenerator(stream, toneVolume);
// if (DBG) log("- created toneGenerator: " + toneGenerator);
@@ -558,7 +559,8 @@
public void updatePhoneStateListeners(boolean isRefresh, int updateType, int subIdToUpdate) {
List<SubscriptionInfo> subInfos = SubscriptionController.getInstance()
- .getActiveSubscriptionInfoList(mApplication.getOpPackageName());
+ .getActiveSubscriptionInfoList(mApplication.getOpPackageName(),
+ null);
// Sort sub id list based on slot id, so that CFI/MWI notifications will be updated for
// slot 0 first then slot 1. This is needed to ensure that when CFI or MWI is enabled for
@@ -615,7 +617,7 @@
for (int i = 0; i < subInfos.size(); i++) {
int subId = subInfos.get(i).getSubscriptionId();
if (!mPhoneStateListeners.containsKey(subId)) {
- CallNotifierPhoneStateListener listener = new CallNotifierPhoneStateListener();
+ CallNotifierPhoneStateListener listener = new CallNotifierPhoneStateListener(subId);
mTelephonyManager.createForSubscriptionId(subId).listen(listener,
PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
| PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR);
@@ -767,8 +769,11 @@
};
private class CallNotifierPhoneStateListener extends PhoneStateListener {
- public CallNotifierPhoneStateListener() {
+ private final int mSubId;
+
+ CallNotifierPhoneStateListener(int subId) {
super();
+ this.mSubId = subId;
}
@Override
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index d451ccf..a816c89 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -57,13 +57,8 @@
import com.android.internal.telephony.SubscriptionInfoUpdater;
import com.android.internal.telephony.TelephonyPermissions;
import com.android.internal.telephony.util.ArrayUtils;
-import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
@@ -80,7 +75,6 @@
/**
* CarrierConfigLoader binds to privileged carrier apps to fetch carrier config overlays.
*/
-
public class CarrierConfigLoader extends ICarrierConfigLoader.Stub {
private static final String LOG_TAG = "CarrierConfigLoader";
@@ -101,6 +95,8 @@
private PersistableBundle[] mOverrideConfigs;
// Service connection for binding to config app.
private CarrierServiceConnection[] mServiceConnection;
+ // Whether we are bound to a service for each phone
+ private boolean[] mServiceBound;
// Whether we have sent config change bcast for each phone id.
private boolean[] mHasSentConfigChange;
// SubscriptionInfoUpdater
@@ -149,10 +145,8 @@
private static final int BIND_TIMEOUT_MILLIS = 30000;
- // Tags used for saving and restoring XML documents.
- private static final String TAG_DOCUMENT = "carrier_config";
- private static final String TAG_VERSION = "package_version";
- private static final String TAG_BUNDLE = "bundle_data";
+ // Keys used for saving and restoring config bundle from file.
+ private static final String KEY_VERSION = "__carrier_config_package_version__";
private static final String OVERRIDE_PACKAGE_ADDITION = "-override";
@@ -273,7 +267,7 @@
final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
// If new service connection has been created, unbind.
if (mServiceConnection[phoneId] != conn || conn.service == null) {
- mContext.unbindService(conn);
+ unbindIfBound(mContext, conn, phoneId);
break;
}
final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
@@ -282,7 +276,7 @@
new ResultReceiver(this) {
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
- mContext.unbindService(conn);
+ unbindIfBound(mContext, conn, phoneId);
// If new service connection has been created, this is stale.
if (mServiceConnection[phoneId] != conn) {
loge("Received response for stale request.");
@@ -316,7 +310,7 @@
} catch (RemoteException e) {
loge("Failed to get carrier config from default app: " +
mPlatformCarrierConfigPackage + " err: " + e.toString());
- mContext.unbindService(conn);
+ unbindIfBound(mContext, conn, phoneId);
break; // So we don't set a timeout.
}
sendMessageDelayed(
@@ -336,7 +330,7 @@
if (mServiceConnection[phoneId] != null) {
// If a ResponseReceiver callback is in the queue when this happens, we will
// unbind twice and throw an exception.
- mContext.unbindService(mServiceConnection[phoneId]);
+ unbindIfBound(mContext, mServiceConnection[phoneId], phoneId);
broadcastConfigChangedIntent(phoneId);
}
notifySubscriptionInfoUpdater(phoneId);
@@ -402,7 +396,7 @@
final CarrierServiceConnection conn = (CarrierServiceConnection) msg.obj;
// If new service connection has been created, unbind.
if (mServiceConnection[phoneId] != conn || conn.service == null) {
- mContext.unbindService(conn);
+ unbindIfBound(mContext, conn, phoneId);
break;
}
final CarrierIdentifier carrierId = getCarrierIdentifierForPhoneId(phoneId);
@@ -411,7 +405,7 @@
new ResultReceiver(this) {
@Override
public void onReceiveResult(int resultCode, Bundle resultData) {
- mContext.unbindService(conn);
+ unbindIfBound(mContext, conn, phoneId);
// If new service connection has been created, this is stale.
if (mServiceConnection[phoneId] != conn) {
loge("Received response for stale request.");
@@ -446,7 +440,7 @@
+ " carrierid: " + carrierId.toString());
} catch (RemoteException e) {
loge("Failed to get carrier config: " + e.toString());
- mContext.unbindService(conn);
+ unbindIfBound(mContext, conn, phoneId);
break; // So we don't set a timeout.
}
sendMessageDelayed(
@@ -466,7 +460,7 @@
if (mServiceConnection[phoneId] != null) {
// If a ResponseReceiver callback is in the queue when this happens, we will
// unbind twice and throw an exception.
- mContext.unbindService(mServiceConnection[phoneId]);
+ unbindIfBound(mContext, mServiceConnection[phoneId], phoneId);
broadcastConfigChangedIntent(phoneId);
}
notifySubscriptionInfoUpdater(phoneId);
@@ -545,6 +539,7 @@
mPersistentOverrideConfigs = new PersistableBundle[numPhones];
mOverrideConfigs = new PersistableBundle[numPhones];
mServiceConnection = new CarrierServiceConnection[numPhones];
+ mServiceBound = new boolean[numPhones];
mHasSentConfigChange = new boolean[numPhones];
// Make this service available through ServiceManager.
ServiceManager.addService(Context.CARRIER_CONFIG_SERVICE, this);
@@ -601,6 +596,10 @@
configToSend = mConfigFromDefaultApp[phoneId];
}
+ if (configToSend == null) {
+ configToSend = new PersistableBundle();
+ }
+
// mOverrideConfigs is for testing. And it will override current configs.
PersistableBundle config = mOverrideConfigs[phoneId];
if (config != null) {
@@ -620,7 +619,6 @@
private void broadcastConfigChangedIntent(int phoneId, boolean addSubIdExtra) {
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
- Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND |
Intent.FLAG_RECEIVER_FOREGROUND);
if (addSubIdExtra) {
int simApplicationState = TelephonyManager.SIM_STATE_UNKNOWN;
@@ -652,8 +650,13 @@
carrierService.setPackage(pkgName);
mServiceConnection[phoneId] = new CarrierServiceConnection(phoneId, eventId);
try {
- return mContext.bindService(carrierService, mServiceConnection[phoneId],
- Context.BIND_AUTO_CREATE);
+ if (mContext.bindService(carrierService, mServiceConnection[phoneId],
+ Context.BIND_AUTO_CREATE)) {
+ mServiceBound[phoneId] = true;
+ return true;
+ } else {
+ return false;
+ }
} catch (SecurityException ex) {
return false;
}
@@ -793,27 +796,14 @@
outFile = new FileOutputStream(
new File(mContext.getFilesDir(),
getFilenameForConfig(packageName, extraString, iccid, cid)));
- FastXmlSerializer out = new FastXmlSerializer();
- out.setOutput(outFile, "utf-8");
- out.startDocument("utf-8", true);
- out.startTag(null, TAG_DOCUMENT);
- out.startTag(null, TAG_VERSION);
- out.text(version);
- out.endTag(null, TAG_VERSION);
- out.startTag(null, TAG_BUNDLE);
- config.saveToXml(out);
- out.endTag(null, TAG_BUNDLE);
- out.endTag(null, TAG_DOCUMENT);
- out.endDocument();
- out.flush();
+ config.putString(KEY_VERSION, version);
+ config.writeToStream(outFile);
+ outFile.flush();
outFile.close();
}
catch (IOException e) {
loge(e.toString());
}
- catch (XmlPullParserException e) {
- loge(e.toString());
- }
}
/**
@@ -858,24 +848,16 @@
file = new File(mContext.getFilesDir(),
getFilenameForConfig(packageName, extraString, iccid, cid));
inFile = new FileInputStream(file);
- XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
- parser.setInput(inFile, "utf-8");
- int event;
- while (((event = parser.next()) != XmlPullParser.END_DOCUMENT)) {
+ restoredBundle = PersistableBundle.readFromStream(inFile);
+ String savedVersion = restoredBundle.getString(KEY_VERSION);
+ restoredBundle.remove(KEY_VERSION);
- if (event == XmlPullParser.START_TAG && TAG_VERSION.equals(parser.getName())) {
- String savedVersion = parser.nextText();
- if (!version.equals(savedVersion)) {
- loge("Saved version mismatch: " + version + " vs " + savedVersion);
- break;
- }
- }
-
- if (event == XmlPullParser.START_TAG && TAG_BUNDLE.equals(parser.getName())) {
- restoredBundle = PersistableBundle.restoreFromXml(parser);
- }
+ if (!version.equals(savedVersion)) {
+ loge("Saved version mismatch: " + version + " vs " + savedVersion);
+ restoredBundle = null;
}
+
inFile.close();
}
catch (FileNotFoundException e) {
@@ -883,9 +865,6 @@
// an override file during boot and should not be treated as an error.
if (file != null) log("File not found: " + file.getPath());
}
- catch (XmlPullParserException e) {
- loge(e.toString());
- }
catch (IOException e) {
loge(e.toString());
}
@@ -967,8 +946,14 @@
@Override
public @NonNull PersistableBundle getConfigForSubId(int subId, String callingPackage) {
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mContext, subId, callingPackage, "getCarrierConfig")) {
+ return getConfigForSubIdWithFeature(subId, callingPackage, null);
+ }
+
+ @Override
+ public @NonNull PersistableBundle getConfigForSubIdWithFeature(int subId, String callingPackage,
+ String callingFeatureId) {
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mContext, subId, callingPackage,
+ callingFeatureId, "getCarrierConfig")) {
return new PersistableBundle();
}
@@ -1080,6 +1065,7 @@
case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR:
case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED:
case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN:
+ case IccCardConstants.INTENT_VALUE_ICC_NOT_READY:
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CLEAR_CONFIG, phoneId, -1));
break;
case IccCardConstants.INTENT_VALUE_ICC_LOADED:
@@ -1091,6 +1077,9 @@
@Override
public String getDefaultCarrierServicePackageName() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+ "getDefaultCarrierServicePackageName");
return mPlatformCarrierConfigPackage;
}
@@ -1149,6 +1138,14 @@
}
}
+ private void unbindIfBound(Context context, CarrierServiceConnection conn,
+ int phoneId) {
+ if (mServiceBound[phoneId]) {
+ mServiceBound[phoneId] = false;
+ context.unbindService(conn);
+ }
+ }
+
private class CarrierServiceConnection implements ServiceConnection {
int phoneId;
int eventId;
@@ -1168,6 +1165,19 @@
@Override
public void onServiceDisconnected(ComponentName name) {
+ log("Disconnected from config app: " + name.flattenToString());
+ this.service = null;
+ }
+
+ @Override
+ public void onBindingDied(ComponentName name) {
+ log("Binding died from config app: " + name.flattenToString());
+ this.service = null;
+ }
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ log("Null binding from config app: " + name.flattenToString());
this.service = null;
}
}
diff --git a/src/com/android/phone/CdmaCallForwardOptions.java b/src/com/android/phone/CdmaCallForwardOptions.java
new file mode 100644
index 0000000..a8d2e93
--- /dev/null
+++ b/src/com/android/phone/CdmaCallForwardOptions.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import android.app.ActionBar;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.preference.Preference;
+import android.preference.PreferenceScreen;
+import android.telephony.CarrierConfigManager;
+import android.util.Log;
+import android.view.MenuItem;
+
+import com.android.internal.telephony.CallForwardInfo;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Phone;
+
+import java.util.ArrayList;
+
+public class CdmaCallForwardOptions extends TimeConsumingPreferenceActivity {
+ private static final String LOG_TAG = "CdmaCallForwardOptions";
+
+ private static final String NUM_PROJECTION[] = {
+ android.provider.ContactsContract.CommonDataKinds.Phone.NUMBER
+ };
+
+ private static final String BUTTON_CFU_KEY = "button_cfu_key";
+ private static final String BUTTON_CFB_KEY = "button_cfb_key";
+ private static final String BUTTON_CFNRY_KEY = "button_cfnry_key";
+ private static final String BUTTON_CFNRC_KEY = "button_cfnrc_key";
+
+ private static final String KEY_TOGGLE = "toggle";
+ private static final String KEY_STATUS = "status";
+ private static final String KEY_NUMBER = "number";
+ private static final String KEY_ENABLE = "enable";
+
+ private CallForwardEditPreference mButtonCFU;
+ private CallForwardEditPreference mButtonCFB;
+ private CallForwardEditPreference mButtonCFNRy;
+ private CallForwardEditPreference mButtonCFNRc;
+
+ private final ArrayList<CallForwardEditPreference> mPreferences =
+ new ArrayList<CallForwardEditPreference> ();
+ private int mInitIndex= 0;
+
+ private boolean mFirstResume;
+ private Bundle mIcicle;
+ private Phone mPhone;
+ private SubscriptionInfoHelper mSubscriptionInfoHelper;
+ private boolean mReplaceInvalidCFNumbers;
+ private boolean mCallForwardByUssd;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ addPreferencesFromResource(R.xml.callforward_options);
+
+ mSubscriptionInfoHelper = new SubscriptionInfoHelper(this, getIntent());
+ mSubscriptionInfoHelper.setActionBarTitle(
+ getActionBar(), getResources(), R.string.call_forwarding_settings_with_label);
+ mPhone = mSubscriptionInfoHelper.getPhone();
+
+ PersistableBundle b = null;
+ boolean supportCFNRc = true;
+ if (mSubscriptionInfoHelper.hasSubId()) {
+ b = PhoneGlobals.getInstance().getCarrierConfigForSubId(
+ mSubscriptionInfoHelper.getSubId());
+ } else {
+ b = PhoneGlobals.getInstance().getCarrierConfig();
+ }
+ if (b != null) {
+ mReplaceInvalidCFNumbers = b.getBoolean(
+ CarrierConfigManager.KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL);
+ mCallForwardByUssd = b.getBoolean(
+ CarrierConfigManager.KEY_USE_CALL_FORWARDING_USSD_BOOL);
+ supportCFNRc = b.getBoolean(
+ CarrierConfigManager.KEY_CALL_FORWARDING_WHEN_UNREACHABLE_SUPPORTED_BOOL);
+ }
+
+ PreferenceScreen prefSet = getPreferenceScreen();
+ mButtonCFU = (CallForwardEditPreference) prefSet.findPreference(BUTTON_CFU_KEY);
+ mButtonCFB = (CallForwardEditPreference) prefSet.findPreference(BUTTON_CFB_KEY);
+ mButtonCFNRy = (CallForwardEditPreference) prefSet.findPreference(BUTTON_CFNRY_KEY);
+ mButtonCFNRc = (CallForwardEditPreference) prefSet.findPreference(BUTTON_CFNRC_KEY);
+
+ mButtonCFU.setParentActivity(this, mButtonCFU.reason);
+ mButtonCFB.setParentActivity(this, mButtonCFB.reason);
+ mButtonCFNRy.setParentActivity(this, mButtonCFNRy.reason);
+ mButtonCFNRc.setParentActivity(this, mButtonCFNRc.reason);
+
+ mPreferences.add(mButtonCFU);
+ mPreferences.add(mButtonCFB);
+ mPreferences.add(mButtonCFNRy);
+
+ if (supportCFNRc) {
+ mPreferences.add(mButtonCFNRc);
+ } else {
+ // When CFNRc is not supported, mButtonCFNRc is grayed out from the menu.
+ // Default state for the preferences in this PreferenceScreen is disabled.
+ // Only preferences listed in the ArrayList mPreferences will be enabled.
+ // By not adding mButtonCFNRc to mPreferences it will be kept disabled.
+ Log.d(LOG_TAG, "onCreate: CFNRc is not supported, grey out the item.");
+ }
+
+ if (mCallForwardByUssd) {
+ //the call forwarding ussd command's behavior is similar to the call forwarding when
+ //unanswered,so only display the call forwarding when unanswered item.
+ prefSet.removePreference(mButtonCFU);
+ prefSet.removePreference(mButtonCFB);
+ prefSet.removePreference(mButtonCFNRc);
+ mPreferences.remove(mButtonCFU);
+ mPreferences.remove(mButtonCFB);
+ mPreferences.remove(mButtonCFNRc);
+ mButtonCFNRy.setDependency(null);
+ }
+
+ // we wait to do the initialization until onResume so that the
+ // TimeConsumingPreferenceActivity dialog can display as it
+ // relies on onResume / onPause to maintain its foreground state.
+
+ mFirstResume = true;
+ mIcicle = icicle;
+
+ ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ // android.R.id.home will be triggered in onOptionsItemSelected()
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ if (mFirstResume) {
+ if (mIcicle == null) {
+ Log.d(LOG_TAG, "start to init ");
+ CallForwardEditPreference pref = mPreferences.get(mInitIndex);
+ pref.init(this, mPhone, mReplaceInvalidCFNumbers, mCallForwardByUssd);
+ pref.startCallForwardOptionsQuery();
+
+ } else {
+ mInitIndex = mPreferences.size();
+
+ for (CallForwardEditPreference pref : mPreferences) {
+ Bundle bundle = mIcicle.getParcelable(pref.getKey());
+ pref.setToggled(bundle.getBoolean(KEY_TOGGLE));
+ pref.setEnabled(bundle.getBoolean(KEY_ENABLE));
+ CallForwardInfo cf = new CallForwardInfo();
+ cf.number = bundle.getString(KEY_NUMBER);
+ cf.status = bundle.getInt(KEY_STATUS);
+ pref.init(this, mPhone, mReplaceInvalidCFNumbers, mCallForwardByUssd);
+ pref.restoreCallForwardInfo(cf);
+ }
+ }
+ mFirstResume = false;
+ mIcicle = null;
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ for (CallForwardEditPreference pref : mPreferences) {
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(KEY_TOGGLE, pref.isToggled());
+ bundle.putBoolean(KEY_ENABLE, pref.isEnabled());
+ if (pref.callForwardInfo != null) {
+ bundle.putString(KEY_NUMBER, pref.callForwardInfo.number);
+ bundle.putInt(KEY_STATUS, pref.callForwardInfo.status);
+ }
+ outState.putParcelable(pref.getKey(), bundle);
+ }
+ }
+
+ @Override
+ public void onFinished(Preference preference, boolean reading) {
+ if (mInitIndex < mPreferences.size()-1 && !isFinishing()) {
+ mInitIndex++;
+ CallForwardEditPreference pref = mPreferences.get(mInitIndex);
+ pref.init(this, mPhone, mReplaceInvalidCFNumbers, mCallForwardByUssd);
+ pref.startCallForwardOptionsQuery();
+ }
+
+ super.onFinished(preference, reading);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ Log.d(LOG_TAG, "onActivityResult: done");
+ if (resultCode != RESULT_OK) {
+ Log.d(LOG_TAG, "onActivityResult: contact picker result not OK.");
+ return;
+ }
+ Cursor cursor = null;
+ try {
+ cursor = getContentResolver().query(data.getData(),
+ NUM_PROJECTION, null, null, null);
+ if ((cursor == null) || (!cursor.moveToFirst())) {
+ Log.d(LOG_TAG, "onActivityResult: bad contact data, no results found.");
+ return;
+ }
+
+ switch (requestCode) {
+ case CommandsInterface.CF_REASON_UNCONDITIONAL:
+ mButtonCFU.onPickActivityResult(cursor.getString(0));
+ break;
+ case CommandsInterface.CF_REASON_BUSY:
+ mButtonCFB.onPickActivityResult(cursor.getString(0));
+ break;
+ case CommandsInterface.CF_REASON_NO_REPLY:
+ mButtonCFNRy.onPickActivityResult(cursor.getString(0));
+ break;
+ case CommandsInterface.CF_REASON_NOT_REACHABLE:
+ mButtonCFNRc.onPickActivityResult(cursor.getString(0));
+ break;
+ default:
+ // TODO: may need exception here.
+ }
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final int itemId = item.getItemId();
+ if (itemId == android.R.id.home) { // See ActionBar#setDisplayHomeAsUpEnabled()
+ CallFeaturesSetting.goUpToTopLevelSetting(this, mSubscriptionInfoHelper);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/src/com/android/phone/CdmaCallOptions.java b/src/com/android/phone/CdmaCallOptions.java
index acfa496..8f4fa67 100644
--- a/src/com/android/phone/CdmaCallOptions.java
+++ b/src/com/android/phone/CdmaCallOptions.java
@@ -27,11 +27,13 @@
import com.android.internal.telephony.PhoneConstants;
-public class CdmaCallOptions extends PreferenceActivity {
+public class CdmaCallOptions extends TimeConsumingPreferenceActivity {
private static final String LOG_TAG = "CdmaCallOptions";
private final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
private static final String BUTTON_VP_KEY = "button_voice_privacy_key";
+ private static final String CALL_FORWARDING_KEY = "call_forwarding_key";
+ private static final String CALL_WAITING_KEY = "call_waiting_key";
private SwitchPreference mButtonVoicePrivacy;
@Override
@@ -55,8 +57,15 @@
if (subInfoHelper.getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_CDMA
|| carrierConfig.getBoolean(CarrierConfigManager.KEY_VOICE_PRIVACY_DISABLE_UI_BOOL)) {
// disable the entire screen
- getPreferenceScreen().setEnabled(false);
+ mButtonVoicePrivacy.setEnabled(false);
}
+
+ Preference callForwardingPref = getPreferenceScreen().findPreference(CALL_FORWARDING_KEY);
+ callForwardingPref.setIntent(subInfoHelper.getIntent(CdmaCallForwardOptions.class));
+
+ CdmaCallWaitingPreference callWaitingPref = (CdmaCallWaitingPreference)getPreferenceScreen()
+ .findPreference(CALL_WAITING_KEY);
+ callWaitingPref.init(this, subInfoHelper.getPhone());
}
@Override
@@ -76,5 +85,4 @@
}
return false;
}
-
}
diff --git a/src/com/android/phone/CdmaCallWaitingPreference.java b/src/com/android/phone/CdmaCallWaitingPreference.java
new file mode 100644
index 0000000..4cda7ba
--- /dev/null
+++ b/src/com/android/phone/CdmaCallWaitingPreference.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Phone;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.TypedArray;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.util.AttributeSet;
+import android.util.Log;
+
+public class CdmaCallWaitingPreference extends Preference {
+ private static final String LOG_TAG = "CdmaCallWaitingPreference";
+ private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
+
+ private int mButtonClicked;
+ private Context mContext;
+ private Phone mPhone;
+ private SubscriptionInfoHelper mSubscriptionInfoHelper;
+ private TimeConsumingPreferenceListener mTcpListener;
+ private MyHandler mHandler = new MyHandler();
+
+ public CdmaCallWaitingPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mContext = context;
+ }
+
+ public CdmaCallWaitingPreference(Context context, AttributeSet attrs) {
+ this(context, attrs, com.android.internal.R.attr.preferenceStyle);
+ }
+
+ public CdmaCallWaitingPreference(Context context) {
+ this(context, null);
+ }
+
+ public void init(TimeConsumingPreferenceListener listener, Phone phone) {
+ mPhone = phone;
+ mTcpListener = listener;
+ Log.d(LOG_TAG, "phone id= " + mPhone.getPhoneId());
+ mPhone.getCallWaiting(mHandler.obtainMessage(MyHandler.MESSAGE_GET_CALL_WAITING,
+ MyHandler.MESSAGE_GET_CALL_WAITING, MyHandler.MESSAGE_GET_CALL_WAITING));
+ if (mTcpListener != null) {
+ mTcpListener.onStarted(this, true);
+ }
+ }
+
+ @Override
+ public void onClick() {
+ super.onClick();
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+ builder.setTitle(mContext.getText(R.string.cdma_call_waiting));
+ builder.setMessage(mContext.getText(R.string.enable_cdma_call_waiting_setting));
+ builder.setPositiveButton(R.string.enable_cdma_cw, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ mPhone.setCallWaiting(true,
+ mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_WAITING));
+ if (mTcpListener != null) {
+ mTcpListener.onStarted(CdmaCallWaitingPreference.this, false);
+ }
+ }
+ });
+ builder.setNegativeButton(R.string.disable_cdma_cw, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int whichButton) {
+ mPhone.setCallWaiting(false,
+ mHandler.obtainMessage(MyHandler.MESSAGE_SET_CALL_WAITING));
+ if (mTcpListener != null) {
+ mTcpListener.onStarted(CdmaCallWaitingPreference.this, false);
+ }
+ }
+ });
+ builder.create().show();
+ }
+
+ private class MyHandler extends Handler {
+ static final int MESSAGE_GET_CALL_WAITING = 0;
+ static final int MESSAGE_SET_CALL_WAITING = 1;
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_GET_CALL_WAITING:
+ handleGetCallWaitingResponse(msg);
+ break;
+ case MESSAGE_SET_CALL_WAITING:
+ handleSetCallWaitingResponse(msg);
+ break;
+ }
+ }
+
+ private void handleGetCallWaitingResponse(Message msg) {
+ AsyncResult ar = (AsyncResult) msg.obj;
+
+ if (mTcpListener != null) {
+ if (msg.arg2 == MESSAGE_SET_CALL_WAITING) {
+ mTcpListener.onFinished(CdmaCallWaitingPreference.this, false);
+ } else {
+ mTcpListener.onFinished(CdmaCallWaitingPreference.this, true);
+ }
+ }
+
+ if (ar.exception instanceof CommandException) {
+ if (DBG) {
+ Log.d(LOG_TAG, "handleGetCallWaitingResponse: CommandException=" +
+ ar.exception);
+ }
+ if (mTcpListener != null) {
+ mTcpListener.onException(CdmaCallWaitingPreference.this,
+ (CommandException)ar.exception);
+ }
+ } else if (ar.userObj instanceof Throwable || ar.exception != null) {
+ if (DBG) {
+ Log.d(LOG_TAG, "handleGetCallWaitingResponse: Exception" + ar.exception);
+ }
+ if (mTcpListener != null) {
+ mTcpListener.onError(CdmaCallWaitingPreference.this,
+ TimeConsumingPreferenceActivity.RESPONSE_ERROR);
+ }
+ } else {
+ if (DBG) {
+ Log.d(LOG_TAG, "handleGetCallWaitingResponse: CW state successfully queried.");
+ }
+ int[] cwArray = (int[])ar.result;
+ if (cwArray == null) {
+ if (mTcpListener != null) {
+ mTcpListener.onError(CdmaCallWaitingPreference.this,
+ TimeConsumingPreferenceActivity.RESPONSE_ERROR);
+ }
+ return;
+ }
+
+ try {
+ if (cwArray[0] == CommandsInterface.SS_STATUS_UNKNOWN) {
+ setSummary("");
+ } else if(cwArray[0] == 1) {
+ setSummary(mContext.getString(R.string.cdma_call_waiting_in_ims_on));
+ } else if(cwArray[0] == 0) {
+ setSummary(mContext.getString(R.string.cdma_call_waiting_in_ims_off));
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ setSummary("");
+ Log.e(LOG_TAG, "handleGetCallWaitingResponse: improper result: err ="
+ + e.getMessage());
+ }
+ }
+ }
+
+ private void handleSetCallWaitingResponse(Message msg) {
+ AsyncResult ar = (AsyncResult) msg.obj;
+
+ if (ar.exception != null) {
+ if (DBG) {
+ Log.d(LOG_TAG, "handleSetCallWaitingResponse: ar.exception=" + ar.exception);
+ }
+ }
+
+ if (ar.result != null) {
+ int arr = (int)ar.result;
+ if (arr == CommandsInterface.SS_STATUS_UNKNOWN) {
+ Log.d(LOG_TAG, "handleSetCallWaitingResponse: no need to re get in CDMA");
+ mTcpListener.onFinished(CdmaCallWaitingPreference.this, false);
+ return;
+ }
+ }
+
+ if (DBG) Log.d(LOG_TAG, "handleSetCallWaitingResponse: re get");
+ mPhone.getCallWaiting(obtainMessage(MESSAGE_GET_CALL_WAITING,
+ MESSAGE_SET_CALL_WAITING, MESSAGE_SET_CALL_WAITING, ar.exception));
+ }
+ }
+}
diff --git a/src/com/android/phone/CellInfoUtil.java b/src/com/android/phone/CellInfoUtil.java
index 8272029..f6d741f 100644
--- a/src/com/android/phone/CellInfoUtil.java
+++ b/src/com/android/phone/CellInfoUtil.java
@@ -33,6 +33,7 @@
import com.android.internal.telephony.OperatorInfo;
+import java.util.Collections;
import java.util.List;
/**
@@ -149,7 +150,8 @@
mcc,
mnc,
operatorInfo.getOperatorAlphaLong(),
- operatorInfo.getOperatorAlphaShort());
+ operatorInfo.getOperatorAlphaShort(),
+ Collections.emptyList());
CellInfoGsm ci = new CellInfoGsm();
ci.setCellIdentity(cig);
diff --git a/src/com/android/phone/EditPhoneNumberPreference.java b/src/com/android/phone/EditPhoneNumberPreference.java
index 35af20d..505c284 100644
--- a/src/com/android/phone/EditPhoneNumberPreference.java
+++ b/src/com/android/phone/EditPhoneNumberPreference.java
@@ -16,6 +16,9 @@
package com.android.phone;
+import static android.view.View.LAYOUT_DIRECTION_LOCALE;
+import static android.view.View.TEXT_DIRECTION_LOCALE;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
@@ -37,6 +40,8 @@
import android.widget.ImageButton;
import android.widget.TextView;
+import com.android.internal.telephony.CommandsInterface;
+
public class EditPhoneNumberPreference extends EditTextPreference {
//allowed modes for this preference.
@@ -90,6 +95,7 @@
private String mPhoneNumber;
private boolean mChecked;
+ private boolean mIsUnknownStatus;
/**
* Interface for the dialog closed listener, related to
@@ -136,9 +142,9 @@
a.recycle();
//get the summary settings, use CheckBoxPreference as the standard.
- a = context.obtainStyledAttributes(attrs, R.styleable.CheckBoxPreference, 0, 0);
- mSummaryOn = a.getString(R.styleable.CheckBoxPreference_summaryOn);
- mSummaryOff = a.getString(R.styleable.CheckBoxPreference_summaryOff);
+ a = context.obtainStyledAttributes(attrs, android.R.styleable.CheckBoxPreference, 0, 0);
+ mSummaryOn = a.getString(android.R.styleable.CheckBoxPreference_summaryOn);
+ mSummaryOff = a.getString(android.R.styleable.CheckBoxPreference_summaryOff);
a.recycle();
}
@@ -209,7 +215,9 @@
}
}
editText.setText(BidiFormatter.getInstance().unicodeWrap(
- mPhoneNumber, TextDirectionHeuristics.LTR));
+ mPhoneNumber, TextDirectionHeuristics.LOCALE));
+ editText.setTextDirection(TEXT_DIRECTION_LOCALE);
+ editText.setLayoutDirection(LAYOUT_DIRECTION_LOCALE);
editText.setMovementMethod(ArrowKeyMovementMethod.getInstance());
editText.setKeyListener(DialerKeyListener.getInstance());
editText.setOnFocusChangeListener(mDialogFocusChangeListener);
@@ -254,7 +262,13 @@
// displayed, since there is no need to hide the edittext
// field anymore.
if (mConfirmationMode == CM_ACTIVATION) {
- if (mChecked) {
+ if (mIsUnknownStatus) {
+ builder.setPositiveButton(mEnableText, this);
+ builder.setNeutralButton(mDisableText, this);
+ if (mPrefId == CommandsInterface.CF_REASON_ALL) {
+ builder.setPositiveButton(null, null);
+ }
+ } else if (mChecked) {
builder.setPositiveButton(mChangeNumberText, this);
builder.setNeutralButton(mDisableText, this);
} else {
@@ -310,7 +324,8 @@
@Override
public void onClick(DialogInterface dialog, int which) {
// The neutral button (button3) is always the toggle.
- if ((mConfirmationMode == CM_ACTIVATION) && (which == DialogInterface.BUTTON_NEUTRAL)) {
+ if ((mConfirmationMode == CM_ACTIVATION) && (which == DialogInterface.BUTTON_NEUTRAL)
+ && !mIsUnknownStatus) {
//flip the toggle if we are in the correct mode.
setToggled(!isToggled());
}
@@ -499,4 +514,12 @@
public void showPhoneNumberDialog() {
showDialog(null);
}
+
+ public void setUnknownStatus(boolean isUnknown) {
+ mIsUnknownStatus = isUnknown;
+ }
+
+ public boolean isUnknownStatus() {
+ return mIsUnknownStatus;
+ }
}
diff --git a/src/com/android/phone/EmergencyActionGroup.java b/src/com/android/phone/EmergencyActionGroup.java
index 53ec1eb..4961a69 100644
--- a/src/com/android/phone/EmergencyActionGroup.java
+++ b/src/com/android/phone/EmergencyActionGroup.java
@@ -159,7 +159,7 @@
if (v.getId() == R.id.action1 || v.getId() == R.id.action2 || v.getId() == R.id.action3) {
AccessibilityManager accessibilityMgr =
- (AccessibilityManager) mContext.getSystemService(
+ (AccessibilityManager) getContext().getSystemService(
Context.ACCESSIBILITY_SERVICE);
if (accessibilityMgr.isTouchExplorationEnabled()) {
getContext().startActivity(intent);
diff --git a/src/com/android/phone/EmergencyCallbackModeExitDialog.java b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
index dcfa024..1210627 100644
--- a/src/com/android/phone/EmergencyCallbackModeExitDialog.java
+++ b/src/com/android/phone/EmergencyCallbackModeExitDialog.java
@@ -35,6 +35,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.telephony.TelephonyManager;
import android.util.Log;
import com.android.internal.telephony.Phone;
@@ -300,8 +301,14 @@
return String.format(getResources().getQuantityText(
R.plurals.alert_dialog_not_avaialble_in_ecm, minutes).toString(), time);
case EXIT_ECM_DIALOG:
- return String.format(getResources().getQuantityText(R.plurals.alert_dialog_exit_ecm,
- minutes).toString(), time);
+ boolean shouldRestrictData = mPhone.getImsPhone() != null
+ && mPhone.getImsPhone().isInImsEcm();
+ return String.format(getResources().getQuantityText(
+ // During IMS ECM, data restriction hint should be removed.
+ shouldRestrictData
+ ? R.plurals.alert_dialog_exit_ecm_without_data_restriction_hint
+ : R.plurals.alert_dialog_exit_ecm,
+ minutes).toString(), time);
}
return null;
}
@@ -324,7 +331,8 @@
// Received exit Emergency Callback Mode notification close all dialogs
if (intent.getAction().equals(
TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
- if (intent.getBooleanExtra("phoneinECMState", false) == false) {
+ // Cancel if the sticky broadcast extra for whether or not we are in ECM is false.
+ if (!intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) {
if (mAlertDialog != null)
mAlertDialog.dismiss();
if (mProgressDialog != null)
diff --git a/src/com/android/phone/EmergencyCallbackModeService.java b/src/com/android/phone/EmergencyCallbackModeService.java
index a07f7aa..6b247bd 100644
--- a/src/com/android/phone/EmergencyCallbackModeService.java
+++ b/src/com/android/phone/EmergencyCallbackModeService.java
@@ -30,13 +30,14 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
-import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.sysprop.TelephonyProperties;
+import android.telephony.TelephonyManager;
import android.util.Log;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.util.NotificationChannelController;
import java.text.SimpleDateFormat;
@@ -50,7 +51,7 @@
public class EmergencyCallbackModeService extends Service {
// Default Emergency Callback Mode timeout value
- private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
+ private static final long DEFAULT_ECM_EXIT_TIMER_VALUE = 300000L;
private static final String LOG_TAG = "EmergencyCallbackModeService";
private NotificationManager mNotificationManager = null;
@@ -106,7 +107,8 @@
mPhone.unregisterForEcmTimerReset(mHandler);
// Cancel the notification and timer
- mNotificationManager.cancel(R.string.phone_in_ecm_notification_title);
+ mNotificationManager.cancelAsUser(null, R.string.phone_in_ecm_notification_title,
+ UserHandle.ALL);
mTimer.cancel();
}
}
@@ -120,7 +122,7 @@
// Stop the service when phone exits Emergency Callback Mode
if (intent.getAction().equals(
TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
- if (intent.getBooleanExtra("phoneinECMState", false) == false) {
+ if (!intent.getBooleanExtra(TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) {
stopSelf();
}
}
@@ -139,8 +141,7 @@
*/
private void startTimerNotification() {
// Get Emergency Callback Mode timeout value
- long ecmTimeout = SystemProperties.getLong(
- TelephonyProperties.PROPERTY_ECM_EXIT_TIMER, DEFAULT_ECM_EXIT_TIMER_VALUE);
+ long ecmTimeout = TelephonyProperties.ecm_exit_timer().orElse(DEFAULT_ECM_EXIT_TIMER_VALUE);
// Show the notification
showNotification(ecmTimeout);
@@ -196,7 +197,11 @@
// Format notification string
String text = null;
if(mInEmergencyCall) {
- text = getText(R.string.phone_in_ecm_call_notification_text).toString();
+ text = getText(
+ // During IMS ECM, data restriction hint should be removed.
+ (imsPhone != null && imsPhone.isInImsEcm())
+ ? R.string.phone_in_ecm_call_notification_text_without_data_restriction_hint
+ : R.string.phone_in_ecm_call_notification_text).toString();
} else {
// Calculate the time in ms when the notification will be finished.
long finishedCountMs = millisUntilFinished + System.currentTimeMillis();
@@ -207,14 +212,19 @@
String completeTime = SimpleDateFormat.getTimeInstance(SimpleDateFormat.SHORT).format(
finishedCountMs);
- text = getResources().getString(R.string.phone_in_ecm_notification_complete_time,
+ text = getResources().getString(
+ // During IMS ECM, data restriction hint should be removed.
+ (imsPhone != null && imsPhone.isInImsEcm())
+ ? R.string.phone_in_ecm_notification_complete_time_without_data_restriction_hint
+ : R.string.phone_in_ecm_notification_complete_time,
completeTime);
}
builder.setContentText(text);
builder.setChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
// Show notification
- mNotificationManager.notify(R.string.phone_in_ecm_notification_title, builder.build());
+ mNotificationManager.notifyAsUser(null, R.string.phone_in_ecm_notification_title,
+ builder.build(), UserHandle.ALL);
}
/**
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 7531aca..334442f 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -45,7 +45,7 @@
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -720,8 +720,12 @@
isEmergencyNumber = true;
phoneToMakeCall = mShortcutViewConfig.getPhoneInfo();
} else {
- isEmergencyNumber = getSystemService(TelephonyManager.class)
- .isEmergencyNumber(mLastNumber);
+ try {
+ isEmergencyNumber = getSystemService(TelephonyManager.class)
+ .isEmergencyNumber(mLastNumber);
+ } catch (IllegalStateException ise) {
+ isEmergencyNumber = false;
+ }
}
if (isEmergencyNumber) {
diff --git a/src/com/android/phone/EmergencyInfoGroup.java b/src/com/android/phone/EmergencyInfoGroup.java
index f5aca7f..a62edfd 100644
--- a/src/com/android/phone/EmergencyInfoGroup.java
+++ b/src/com/android/phone/EmergencyInfoGroup.java
@@ -209,7 +209,7 @@
public void onClick(View view) {
if (view.getId() == R.id.emergency_info_view) {
AccessibilityManager accessibilityMgr =
- (AccessibilityManager) mContext.getSystemService(
+ (AccessibilityManager) getContext().getSystemService(
Context.ACCESSIBILITY_SERVICE);
if (accessibilityMgr.isTouchExplorationEnabled()) {
if (mOnConfirmClickListener != null) {
diff --git a/src/com/android/phone/EmergencyShortcutButton.java b/src/com/android/phone/EmergencyShortcutButton.java
index d147ce4..bfa956c 100644
--- a/src/com/android/phone/EmergencyShortcutButton.java
+++ b/src/com/android/phone/EmergencyShortcutButton.java
@@ -184,7 +184,7 @@
public void onClick(View view) {
if (view.getId() == R.id.emergency_call_number_info_view) {
AccessibilityManager accessibilityMgr =
- (AccessibilityManager) mContext.getSystemService(
+ (AccessibilityManager) getContext().getSystemService(
Context.ACCESSIBILITY_SERVICE);
if (accessibilityMgr.isTouchExplorationEnabled()) {
// TalkBack itself includes a prompt to confirm click action implicitly,
diff --git a/src/com/android/phone/GsmUmtsCallBarringOptions.java b/src/com/android/phone/GsmUmtsCallBarringOptions.java
index 3c9cd84..30e9b5c 100644
--- a/src/com/android/phone/GsmUmtsCallBarringOptions.java
+++ b/src/com/android/phone/GsmUmtsCallBarringOptions.java
@@ -37,7 +37,6 @@
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.GsmCdmaPhone;
import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.phone.settings.fdn.EditPinPreference;
import java.util.ArrayList;
@@ -75,7 +74,6 @@
private static final String DIALOG_PW_ENTRY_KEY = "dialog_pw_enter_key";
private static final String KEY_STATUS = "toggle";
private static final String PREFERENCE_ENABLED_KEY = "PREFERENCE_ENABLED";
- private static final String PREFERENCE_SHOW_PASSWORD_KEY = "PREFERENCE_SHOW_PASSWORD";
private static final String SAVED_BEFORE_LOAD_COMPLETED_KEY = "PROGRESS_SHOWING";
private CallBarringEditPreference mButtonBAOC;
@@ -141,16 +139,13 @@
return;
}
- String password = null;
- if (mButtonDisableAll.isPasswordShown()) {
- password = mButtonDisableAll.getText();
- // Validate the length of password first, before submitting it to the
- // RIL for CB disable.
- if (!validatePassword(password)) {
- mButtonDisableAll.setText("");
- displayMessage(R.string.call_barring_right_pwd_number);
- return;
- }
+ String password = mButtonDisableAll.getText();
+ // Validate the length of password first, before submitting it to the
+ // RIL for CB disable.
+ if (!validatePassword(password)) {
+ mButtonDisableAll.setText("");
+ displayMessage(R.string.call_barring_right_pwd_number);
+ return;
}
// Submit the disable all request
@@ -417,34 +412,18 @@
mPreferences.add(mButtonBAIC);
mPreferences.add(mButtonBAICr);
- // Find out if password is currently used.
- boolean usePassword = true;
- boolean useDisableaAll = true;
-
- ImsPhone imsPhone = mPhone != null ? (ImsPhone) mPhone.getImsPhone() : null;
- if (imsPhone != null && imsPhone.isUtEnabled()) {
- usePassword = false;
- useDisableaAll = false;
- }
-
// Find out if the sim card is ready.
boolean isSimReady = TelephonyManager.from(this).getSimState(
SubscriptionManager.getSlotIndex(mPhone.getSubId()))
== TelephonyManager.SIM_STATE_READY;
- // Deactivate all option is unavailable when sim card is not ready or Ut is enabled.
- if (isSimReady && useDisableaAll) {
+ // Deactivate all option and Change password option are unavailable
+ // when sim card is not ready.
+ if (isSimReady) {
mButtonDisableAll.setEnabled(true);
- mButtonDisableAll.init(mPhone);
- } else {
- mButtonDisableAll.setEnabled(false);
- }
-
- // Change password option is unavailable when sim card is not ready or when the password is
- // not used.
- if (isSimReady && usePassword) {
mButtonChangePW.setEnabled(true);
} else {
+ mButtonDisableAll.setEnabled(false);
mButtonChangePW.setEnabled(false);
mButtonChangePW.setSummary(R.string.call_barring_change_pwd_description_disabled);
}
@@ -472,8 +451,6 @@
pref.handleCallBarringResult(bundle.getBoolean(KEY_STATUS));
pref.init(this, true, mPhone);
pref.setEnabled(bundle.getBoolean(PREFERENCE_ENABLED_KEY, pref.isEnabled()));
- pref.setInputMethodNeeded(bundle.getBoolean(PREFERENCE_SHOW_PASSWORD_KEY,
- pref.needInputMethod()));
}
}
mPwChangeState = mIcicle.getInt(PW_CHANGE_STATE_KEY);
@@ -513,7 +490,6 @@
Bundle bundle = new Bundle();
bundle.putBoolean(KEY_STATUS, pref.mIsActivated);
bundle.putBoolean(PREFERENCE_ENABLED_KEY, pref.isEnabled());
- bundle.putBoolean(PREFERENCE_SHOW_PASSWORD_KEY, pref.needInputMethod());
outState.putParcelable(pref.getKey(), bundle);
}
outState.putInt(PW_CHANGE_STATE_KEY, mPwChangeState);
diff --git a/src/com/android/phone/IccPanel.java b/src/com/android/phone/IccPanel.java
index be182233..73dd8bc 100644
--- a/src/com/android/phone/IccPanel.java
+++ b/src/com/android/phone/IccPanel.java
@@ -74,13 +74,13 @@
@Override
protected void onStart() {
super.onStart();
- mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);
+ mStatusBarManager.setDisabledForSimNetworkLock(true);
}
@Override
public void onStop() {
super.onStop();
- mStatusBarManager.disable(StatusBarManager.DISABLE_NONE);
+ mStatusBarManager.setDisabledForSimNetworkLock(false);
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index 06d2367..3ea8df2 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -22,17 +22,24 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
+import android.telephony.SubscriptionManager;
import android.telephony.ims.ImsException;
+import android.telephony.ims.RegistrationManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRcsController;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.telephony.ims.aidl.IRcsUceControllerCallback;
import android.telephony.ims.feature.RcsFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
-import com.android.ims.RcsFeatureManager;
+import com.android.ims.ImsManager;
+import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.services.telephony.rcs.RcsFeatureController;
+import com.android.services.telephony.rcs.TelephonyRcsService;
+import com.android.services.telephony.rcs.UserCapabilityExchangeImpl;
import java.util.List;
@@ -46,6 +53,7 @@
private static ImsRcsController sInstance;
private PhoneGlobals mApp;
+ private TelephonyRcsService mRcsService;
/**
* Initialize the singleton ImsRcsController instance.
@@ -70,6 +78,86 @@
}
/**
+ * Register a {@link RegistrationManager.RegistrationCallback} to receive IMS network
+ * registration state.
+ */
+ @Override
+ public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
+ enforceReadPrivilegedPermission("registerImsRegistrationCallback");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ getRcsFeatureController(subId).registerImsRegistrationCallback(subId, callback);
+ } catch (ImsException e) {
+ Log.e(TAG, "registerImsRegistrationCallback: sudId=" + subId + ", " + e.getMessage());
+ throw new ServiceSpecificException(e.getCode());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Removes an existing {@link RegistrationManager.RegistrationCallback}.
+ */
+ @Override
+ public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
+ enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ getRcsFeatureController(subId).unregisterImsRegistrationCallback(subId, callback);
+ } catch (ServiceSpecificException e) {
+ Log.e(TAG, "unregisterImsRegistrationCallback: error=" + e.errorCode);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Get the IMS service registration state for the RcsFeature associated with this sub id.
+ */
+ @Override
+ public void getImsRcsRegistrationState(int subId, IIntegerConsumer consumer) {
+ enforceReadPrivilegedPermission("getImsRcsRegistrationState");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ getRcsFeatureController(subId).getRegistrationState(regState -> {
+ try {
+ consumer.accept((regState == null)
+ ? RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED : regState);
+ } catch (RemoteException e) {
+ Log.w(TAG, "getImsRcsRegistrationState: callback is not available.");
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Gets the Transport Type associated with the current IMS RCS registration.
+ */
+ @Override
+ public void getImsRcsRegistrationTransportType(int subId, IIntegerConsumer consumer) {
+ enforceReadPrivilegedPermission("getImsRcsRegistrationTransportType");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ getRcsFeatureController(subId).getRegistrationTech(regTech -> {
+ // Convert registration tech from ImsRegistrationImplBase -> RegistrationManager
+ int regTechConverted = (regTech == null)
+ ? ImsRegistrationImplBase.REGISTRATION_TECH_NONE : regTech;
+ regTechConverted = RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(
+ regTechConverted);
+ try {
+ consumer.accept(regTechConverted);
+ } catch (RemoteException e) {
+ Log.w(TAG, "getImsRcsRegistrationTransportType: callback is not available.");
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
* Register a capability callback which will provide RCS availability updates for the
* subscription specified.
*
@@ -77,13 +165,12 @@
* @param callback The ImsCapabilityCallback to be registered.
*/
@Override
- public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)
- throws RemoteException {
+ public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
enforceReadPrivilegedPermission("registerRcsAvailabilityCallback");
final long token = Binder.clearCallingIdentity();
try {
- getRcsFeatureManager(subId).registerRcsAvailabilityCallback(callback);
- } catch (com.android.ims.ImsException e) {
+ getRcsFeatureController(subId).registerRcsAvailabilityCallback(subId, callback);
+ } catch (ImsException e) {
Log.e(TAG, "registerRcsAvailabilityCallback: sudId=" + subId + ", " + e.getMessage());
throw new ServiceSpecificException(e.getCode());
} finally {
@@ -102,9 +189,7 @@
enforceReadPrivilegedPermission("unregisterRcsAvailabilityCallback");
final long token = Binder.clearCallingIdentity();
try {
- getRcsFeatureManager(subId).unregisterRcsAvailabilityCallback(callback);
- } catch (com.android.ims.ImsException e) {
- Log.e(TAG, "unregisterRcsAvailabilityCallback: sudId=" + subId + "," + e.getMessage());
+ getRcsFeatureController(subId).unregisterRcsAvailabilityCallback(subId, callback);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -125,8 +210,8 @@
enforceReadPrivilegedPermission("isCapable");
final long token = Binder.clearCallingIdentity();
try {
- return getRcsFeatureManager(subId).isCapable(capability, radioTech);
- } catch (com.android.ims.ImsException e) {
+ return getRcsFeatureController(subId).isCapable(capability, radioTech);
+ } catch (ImsException e) {
Log.e(TAG, "isCapable: sudId=" + subId
+ ", capability=" + capability + ", " + e.getMessage());
return false;
@@ -149,8 +234,8 @@
enforceReadPrivilegedPermission("isAvailable");
final long token = Binder.clearCallingIdentity();
try {
- return getRcsFeatureManager(subId).isAvailable(capability);
- } catch (com.android.ims.ImsException e) {
+ return getRcsFeatureController(subId).isAvailable(capability);
+ } catch (ImsException e) {
Log.e(TAG, "isAvailable: sudId=" + subId
+ ", capability=" + capability + ", " + e.getMessage());
return false;
@@ -163,23 +248,49 @@
public void requestCapabilities(int subId, List<Uri> contactNumbers,
IRcsUceControllerCallback c) {
enforceReadPrivilegedPermission("requestCapabilities");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
+ UserCapabilityExchangeImpl.class);
+ if (uce == null) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "This subscription does not support UCE.");
+ }
+ uce.requestCapabilities(contactNumbers, c);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
public int getUcePublishState(int subId) {
enforceReadPrivilegedPermission("getUcePublishState");
- return -1;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
+ UserCapabilityExchangeImpl.class);
+ if (uce == null) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "This subscription does not support UCE.");
+ }
+ return uce.getUcePublishState();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
@Override
public boolean isUceSettingEnabled(int subId) {
enforceReadPrivilegedPermission("isUceSettingEnabled");
- return false;
+ return SubscriptionManager.getBooleanSubscriptionProperty(subId,
+ SubscriptionManager.IMS_RCS_UCE_ENABLED, false /*defaultValue*/, mApp);
}
@Override
public void setUceSettingEnabled(int subId, boolean isEnabled) {
enforceModifyPermission();
+ SubscriptionManager.setSubscriptionProperty(subId, SubscriptionManager.IMS_RCS_UCE_ENABLED,
+ (isEnabled ? "1" : "0"));
}
/**
@@ -202,13 +313,17 @@
}
/**
- * Retrieve RcsFeatureManager instance.
+ * Retrieve ImsPhone instance.
*
* @param subId the subscription ID
- * @return The RcsFeatureManager instance
- * @throws SecurityException if getting Phone or RcsFeatureManager instance failed.
+ * @return The ImsPhone instance
+ * @throws ServiceSpecificException if getting ImsPhone instance failed.
*/
- private RcsFeatureManager getRcsFeatureManager(int subId) {
+ private ImsPhone getImsPhone(int subId) {
+ if (!ImsManager.isImsSupportedOnDevice(mApp)) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "IMS is not available on device.");
+ }
Phone phone = PhoneGlobals.getPhone(subId);
if (phone == null) {
throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
@@ -216,14 +331,43 @@
}
ImsPhone imsPhone = (ImsPhone) phone.getImsPhone();
if (imsPhone == null) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
"Cannot find ImsPhone instance: " + subId);
}
- RcsFeatureManager rcsFeatureManager = imsPhone.getRcsManager();
- if (rcsFeatureManager == null) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_SERVICE_UNAVAILABLE,
- "Cannot find RcsFeatureManager instance: " + subId);
+ return imsPhone;
+ }
+
+ /**
+ * Retrieve RcsFeatureManager instance.
+ *
+ * @param subId the subscription ID
+ * @return The RcsFeatureManager instance
+ * @throws ServiceSpecificException if getting RcsFeatureManager instance failed.
+ */
+ private RcsFeatureController getRcsFeatureController(int subId) {
+ if (!ImsManager.isImsSupportedOnDevice(mApp)) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "IMS is not available on device.");
}
- return rcsFeatureManager;
+ if (mRcsService == null) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "IMS is not available on device.");
+ }
+ Phone phone = PhoneGlobals.getPhone(subId);
+ if (phone == null) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_INVALID_SUBSCRIPTION,
+ "Invalid subscription Id: " + subId);
+ }
+ int slotId = phone.getPhoneId();
+ RcsFeatureController c = mRcsService.getFeatureController(slotId);
+ if (c == null) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "The requested operation is not supported for subId " + subId);
+ }
+ return c;
+ }
+
+ void setRcsService(TelephonyRcsService rcsService) {
+ mRcsService = rcsService;
}
}
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index fe55335..fccceec 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -470,7 +470,7 @@
private Intent getShowVoicemailIntentForDefaultDialer(UserHandle userHandle) {
String dialerPackage = mContext.getSystemService(TelecomManager.class)
- .getDefaultDialerPackage(userHandle.getIdentifier());
+ .getDefaultDialerPackage(userHandle);
return new Intent(TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION)
.setPackage(dialerPackage);
}
diff --git a/src/com/android/phone/NumberVerificationManager.java b/src/com/android/phone/NumberVerificationManager.java
index 9ec16f8..2298d40 100644
--- a/src/com/android/phone/NumberVerificationManager.java
+++ b/src/com/android/phone/NumberVerificationManager.java
@@ -135,7 +135,7 @@
}
// make sure at least one phone is registered for voice
- if (phone.getServiceState().getVoiceRegState() == ServiceState.STATE_IN_SERVICE) {
+ if (phone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) {
isAnyPhoneVoiceRegistered = true;
}
// make sure at least one phone has room for an incoming call.
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 5d4d9b3..6f657b4 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -26,6 +26,7 @@
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.content.res.XmlResourceParser;
import android.media.AudioManager;
import android.net.ConnectivityManager;
@@ -66,9 +67,11 @@
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.dataconnection.DataConnectionReasons;
import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
+import com.android.internal.telephony.ims.ImsResolver;
import com.android.internal.util.IndentingPrintWriter;
import com.android.phone.settings.SettingsConstants;
import com.android.phone.vvm.CarrierVvmPackageInstalledReceiver;
+import com.android.services.telephony.rcs.TelephonyRcsService;
import com.android.services.telephony.sip.SipAccountRegistry;
import com.android.services.telephony.sip.SipUtil;
@@ -146,6 +149,8 @@
CallNotifier notifier;
CallerInfoCache callerInfoCache;
NotificationMgr notificationMgr;
+ ImsResolver mImsResolver;
+ TelephonyRcsService mTelephonyRcsService;
public PhoneInterfaceManager phoneMgr;
public ImsRcsController imsRcsController;
CarrierConfigLoader configLoader;
@@ -300,8 +305,8 @@
// Cache the "voice capable" flag.
// This flag currently comes from a resource (which is
// overrideable on a per-product basis):
- sVoiceCapable =
- getResources().getBoolean(com.android.internal.R.bool.config_voice_capable);
+ sVoiceCapable = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE))
+ .isVoiceCapable();
// ...but this might eventually become a PackageManager "system
// feature" instead, in which case we'd do something like:
// sVoiceCapable =
@@ -317,6 +322,19 @@
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
+ // Only bring up ImsResolver if the device supports having an IMS stack.
+ if (getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY_IMS)) {
+ // Get the package name of the default IMS implementation.
+ String defaultImsMmtelPackage = getResources().getString(
+ R.string.config_ims_mmtel_package);
+ String defaultImsRcsPackage = getResources().getString(
+ R.string.config_ims_rcs_package);
+ mImsResolver = new ImsResolver(this, defaultImsMmtelPackage,
+ defaultImsRcsPackage, PhoneFactory.getPhones().length);
+ mImsResolver.initialize();
+ }
+
// Start TelephonyDebugService After the default phone is created.
Intent intent = new Intent(this, TelephonyDebugService.class);
startService(intent);
@@ -356,6 +374,13 @@
imsRcsController = ImsRcsController.init(this);
+ if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS)) {
+ mTelephonyRcsService = new TelephonyRcsService(this,
+ PhoneFactory.getPhones().length);
+ mTelephonyRcsService.initialize();
+ imsRcsController.setRcsService(mTelephonyRcsService);
+ }
+
configLoader = CarrierConfigLoader.init(this);
// Create the CallNotifier singleton, which handles
@@ -387,7 +412,7 @@
IntentFilter sipIntentFilter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
sipIntentFilter.addAction(SipManager.ACTION_SIP_SERVICE_UP);
sipIntentFilter.addAction(SipManager.ACTION_SIP_CALL_OPTION_CHANGED);
- sipIntentFilter.addAction(SipManager.ACTION_SIP_REMOVE_PHONE);
+ sipIntentFilter.addAction(SipManager.ACTION_SIP_REMOVE_PROFILE);
registerReceiver(mSipReceiver, sipIntentFilter);
mCarrierVvmPackageInstalledReceiver.register(this);
@@ -438,6 +463,10 @@
return PhoneFactory.getPhone(SubscriptionManager.getPhoneId(subId));
}
+ public ImsResolver getImsResolver() {
+ return mImsResolver;
+ }
+
/* package */ CallManager getCallManager() {
return mCM;
}
@@ -447,7 +476,7 @@
}
public PersistableBundle getCarrierConfigForSubId(int subId) {
- return configLoader.getConfigForSubId(subId, getOpPackageName());
+ return configLoader.getConfigForSubIdWithFeature(subId, getOpPackageName(), null);
}
private void registerSettingsObserver() {
@@ -642,7 +671,8 @@
if (TelephonyCapabilities.supportsEcm(phoneInEcm)) {
Log.d(LOG_TAG, "Emergency Callback Mode arrived in PhoneApp.");
// Start Emergency Callback Mode service
- if (intent.getBooleanExtra("phoneinECMState", false)) {
+ if (intent.getBooleanExtra(
+ TelephonyManager.EXTRA_PHONE_IN_ECM_STATE, false)) {
context.startService(new Intent(context,
EmergencyCallbackModeService.class));
} else {
@@ -688,7 +718,7 @@
} else if (action.equals(SipManager.ACTION_SIP_SERVICE_UP)
|| action.equals(SipManager.ACTION_SIP_CALL_OPTION_CHANGED)) {
sipAccountRegistry.setup(context);
- } else if (action.equals(SipManager.ACTION_SIP_REMOVE_PHONE)) {
+ } else if (action.equals(SipManager.ACTION_SIP_REMOVE_PROFILE)) {
if (DBG) {
Log.d(LOG_TAG, "SIP_REMOVE_PHONE "
+ intent.getStringExtra(SipManager.EXTRA_LOCAL_URI));
@@ -877,6 +907,20 @@
pw.increaseIndent();
mDataRoamingNotifLog.dump(fd, pw, args);
pw.decreaseIndent();
+ pw.println("ImsResolver:");
+ pw.increaseIndent();
+ try {
+ if (mImsResolver != null) mImsResolver.dump(fd, pw, args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ pw.decreaseIndent();
+ pw.println("RcsService:");
+ try {
+ if (mTelephonyRcsService != null) mTelephonyRcsService.dump(fd, pw, args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
pw.decreaseIndent();
pw.println("------- End PhoneGlobals -------");
}
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index 296525d..05f7872 100755
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -22,6 +22,7 @@
import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
import android.Manifest.permission;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.PendingIntent;
@@ -34,7 +35,6 @@
import android.content.pm.ComponentInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.net.NetworkStats;
import android.net.Uri;
import android.os.AsyncResult;
import android.os.Binder;
@@ -45,14 +45,15 @@
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.os.ParcelFileDescriptor;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.ShellCallback;
-import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.WorkSource;
@@ -60,17 +61,20 @@
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Telephony;
+import android.sysprop.TelephonyProperties;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.Annotation.ApnType;
+import android.telephony.CallForwardingInfo;
import android.telephony.CarrierConfigManager;
import android.telephony.CarrierRestrictionRules;
import android.telephony.CellIdentity;
+import android.telephony.CellIdentityCdma;
+import android.telephony.CellIdentityGsm;
import android.telephony.CellInfo;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoWcdma;
-import android.telephony.CellLocation;
import android.telephony.ClientRequestStats;
import android.telephony.ICellInfoCallback;
import android.telephony.IccOpenLogicalChannelResponse;
@@ -82,7 +86,6 @@
import android.telephony.PhoneNumberRange;
import android.telephony.RadioAccessFamily;
import android.telephony.RadioAccessSpecifier;
-import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
@@ -94,10 +97,8 @@
import android.telephony.UiccSlotInfo;
import android.telephony.UssdResponse;
import android.telephony.VisualVoicemailSmsFilterSettings;
-import android.telephony.cdma.CdmaCellLocation;
import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
-import android.telephony.gsm.GsmCellLocation;
import android.telephony.ims.ImsException;
import android.telephony.ims.ProvisioningManager;
import android.telephony.ims.RegistrationManager;
@@ -110,30 +111,32 @@
import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.feature.RcsFeature;
import android.telephony.ims.stub.ImsConfigImplBase;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
-import android.util.Slog;
import com.android.ims.ImsManager;
import com.android.ims.internal.IImsServiceFeatureCallback;
+import com.android.internal.telephony.CallForwardInfo;
import com.android.internal.telephony.CallManager;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.CarrierInfoManager;
import com.android.internal.telephony.CarrierResolver;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.CommandException;
+import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.DefaultPhoneNotifier;
import com.android.internal.telephony.HalVersion;
+import com.android.internal.telephony.IBooleanConsumer;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.INumberVerificationCallback;
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.LocaleTracker;
-import com.android.internal.telephony.MccTable;
import com.android.internal.telephony.NetworkScanRequestTracker;
import com.android.internal.telephony.OperatorInfo;
import com.android.internal.telephony.Phone;
@@ -158,6 +161,7 @@
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
import com.android.internal.telephony.uicc.IccIoResult;
+import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.telephony.uicc.SIMRecords;
import com.android.internal.telephony.uicc.UiccCard;
@@ -165,6 +169,7 @@
import com.android.internal.telephony.uicc.UiccController;
import com.android.internal.telephony.uicc.UiccProfile;
import com.android.internal.telephony.uicc.UiccSlot;
+import com.android.internal.telephony.util.LocaleUtils;
import com.android.internal.telephony.util.VoicemailNotificationSettingsUtil;
import com.android.internal.util.HexDump;
import com.android.phone.settings.PickSmsSubscriptionActivity;
@@ -172,6 +177,7 @@
import com.android.phone.vvm.RemoteVvmTaskManager;
import com.android.phone.vvm.VisualVoicemailSettingsUtil;
import com.android.phone.vvm.VisualVoicemailSmsFilterConfig;
+import com.android.telephony.Rlog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -184,6 +190,7 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.function.Consumer;
/**
* Implementation of the ITelephony interface.
@@ -265,6 +272,20 @@
private static final int EVENT_SET_FORBIDDEN_PLMNS_DONE = 73;
private static final int CMD_ERASE_MODEM_CONFIG = 74;
private static final int EVENT_ERASE_MODEM_CONFIG_DONE = 75;
+ private static final int CMD_CHANGE_ICC_LOCK_PASSWORD = 76;
+ private static final int EVENT_CHANGE_ICC_LOCK_PASSWORD_DONE = 77;
+ private static final int CMD_SET_ICC_LOCK_ENABLED = 78;
+ private static final int EVENT_SET_ICC_LOCK_ENABLED_DONE = 79;
+ private static final int CMD_SET_SYSTEM_SELECTION_CHANNELS = 80;
+ private static final int EVENT_SET_SYSTEM_SELECTION_CHANNELS_DONE = 81;
+ private static final int CMD_GET_CALL_FORWARDING = 83;
+ private static final int EVENT_GET_CALL_FORWARDING_DONE = 84;
+ private static final int CMD_SET_CALL_FORWARDING = 85;
+ private static final int EVENT_SET_CALL_FORWARDING_DONE = 86;
+ private static final int CMD_GET_CALL_WAITING = 87;
+ private static final int EVENT_GET_CALL_WAITING_DONE = 88;
+ private static final int CMD_SET_CALL_WAITING = 89;
+ private static final int EVENT_SET_CALL_WAITING_DONE = 90;
// Parameters of select command.
private static final int SELECT_COMMAND = 0xA4;
@@ -272,15 +293,12 @@
private static final int SELECT_P2 = 0;
private static final int SELECT_P3 = 0x10;
- private static final String DEFAULT_NETWORK_MODE_PROPERTY_NAME = "ro.telephony.default_network";
- private static final String DEFAULT_DATA_ROAMING_PROPERTY_NAME = "ro.com.android.dataroaming";
- private static final String DEFAULT_MOBILE_DATA_PROPERTY_NAME = "ro.com.android.mobiledata";
-
/** The singleton instance. */
private static PhoneInterfaceManager sInstance;
private PhoneGlobals mApp;
private CallManager mCM;
+ private ImsResolver mImsResolver;
private UserManager mUserManager;
private AppOpsManager mAppOps;
private MainThreadHandler mMainThreadHandler;
@@ -802,6 +820,148 @@
getPhoneFromRequest(request).getAvailableNetworks(onCompleted);
break;
+ case CMD_GET_CALL_FORWARDING:
+ request = (MainThreadRequest) msg.obj;
+ onCompleted = obtainMessage(EVENT_GET_CALL_FORWARDING_DONE, request);
+ int callForwardingReason = (Integer) request.argument;
+ getPhoneFromRequest(request).getCallForwardingOption(
+ callForwardingReason, onCompleted);
+ break;
+
+ case EVENT_GET_CALL_FORWARDING_DONE:
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ CallForwardingInfo callForwardingInfo = null;
+ if (ar.exception == null && ar.result != null) {
+ CallForwardInfo[] callForwardInfos = (CallForwardInfo[]) ar.result;
+ for (CallForwardInfo callForwardInfo : callForwardInfos) {
+ // Service Class is a bit mask per 3gpp 27.007. Search for
+ // any service for voice call.
+ if ((callForwardInfo.serviceClass
+ & CommandsInterface.SERVICE_CLASS_VOICE) > 0) {
+ callForwardingInfo = new CallForwardingInfo(
+ callForwardInfo.serviceClass, callForwardInfo.reason,
+ callForwardInfo.number,
+ callForwardInfo.timeSeconds);
+ break;
+ }
+ }
+ // Didn't find a call forward info for voice call.
+ if (callForwardingInfo == null) {
+ callForwardingInfo = new CallForwardingInfo(
+ CallForwardingInfo.STATUS_UNKNOWN_ERROR,
+ 0 /* reason */, null /* number */, 0 /* timeout */);
+ }
+ } else {
+ if (ar.result == null) {
+ loge("EVENT_GET_CALL_FORWARDING_DONE: Empty response");
+ }
+ if (ar.exception != null) {
+ loge("EVENT_GET_CALL_FORWARDING_DONE: Exception: " + ar.exception);
+ }
+ int errorCode = CallForwardingInfo.STATUS_UNKNOWN_ERROR;
+ if (ar.exception instanceof CommandException) {
+ CommandException.Error error =
+ ((CommandException) (ar.exception)).getCommandError();
+ if (error == CommandException.Error.FDN_CHECK_FAILURE) {
+ errorCode = CallForwardingInfo.STATUS_FDN_CHECK_FAILURE;
+ } else if (error == CommandException.Error.REQUEST_NOT_SUPPORTED) {
+ errorCode = CallForwardingInfo.STATUS_NOT_SUPPORTED;
+ }
+ }
+ callForwardingInfo = new CallForwardingInfo(
+ errorCode, 0 /* reason */, null /* number */, 0 /* timeout */);
+ }
+ request.result = callForwardingInfo;
+ notifyRequester(request);
+ break;
+
+ case CMD_SET_CALL_FORWARDING:
+ request = (MainThreadRequest) msg.obj;
+ onCompleted = obtainMessage(EVENT_SET_CALL_FORWARDING_DONE, request);
+ CallForwardingInfo callForwardingInfoToSet =
+ (CallForwardingInfo) request.argument;
+ getPhoneFromRequest(request).setCallForwardingOption(
+ callForwardingInfoToSet.getStatus(),
+ callForwardingInfoToSet.getReason(),
+ callForwardingInfoToSet.getNumber(),
+ callForwardingInfoToSet.getTimeoutSeconds(), onCompleted);
+ break;
+
+ case EVENT_SET_CALL_FORWARDING_DONE:
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ if (ar.exception == null) {
+ request.result = true;
+ } else {
+ request.result = false;
+ loge("setCallForwarding exception: " + ar.exception);
+ }
+ notifyRequester(request);
+ break;
+
+ case CMD_GET_CALL_WAITING:
+ request = (MainThreadRequest) msg.obj;
+ onCompleted = obtainMessage(EVENT_GET_CALL_WAITING_DONE, request);
+ getPhoneFromRequest(request).getCallWaiting(onCompleted);
+ break;
+
+ case EVENT_GET_CALL_WAITING_DONE:
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ int callForwardingStatus = TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR;
+ if (ar.exception == null && ar.result != null) {
+ int[] callForwardResults = (int[]) ar.result;
+ // Service Class is a bit mask per 3gpp 27.007.
+ // Search for any service for voice call.
+ if (callForwardResults.length > 1
+ && ((callForwardResults[1]
+ & CommandsInterface.SERVICE_CLASS_VOICE) > 0)) {
+ callForwardingStatus = callForwardResults[0] == 0
+ ? TelephonyManager.CALL_WAITING_STATUS_INACTIVE
+ : TelephonyManager.CALL_WAITING_STATUS_ACTIVE;
+ } else {
+ callForwardingStatus = TelephonyManager.CALL_WAITING_STATUS_INACTIVE;
+ }
+ } else {
+ if (ar.result == null) {
+ loge("EVENT_GET_CALL_WAITING_DONE: Empty response");
+ }
+ if (ar.exception != null) {
+ loge("EVENT_GET_CALL_WAITING_DONE: Exception: " + ar.exception);
+ }
+ if (ar.exception instanceof CommandException) {
+ CommandException.Error error =
+ ((CommandException) (ar.exception)).getCommandError();
+ if (error == CommandException.Error.REQUEST_NOT_SUPPORTED) {
+ callForwardingStatus =
+ TelephonyManager.CALL_WAITING_STATUS_NOT_SUPPORTED;
+ }
+ }
+ }
+ request.result = callForwardingStatus;
+ notifyRequester(request);
+ break;
+
+ case CMD_SET_CALL_WAITING:
+ request = (MainThreadRequest) msg.obj;
+ onCompleted = obtainMessage(EVENT_SET_CALL_WAITING_DONE, request);
+ boolean isEnable = (Boolean) request.argument;
+ getPhoneFromRequest(request).setCallWaiting(isEnable, onCompleted);
+ break;
+
+ case EVENT_SET_CALL_WAITING_DONE:
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ if (ar.exception == null) {
+ request.result = true;
+ } else {
+ request.result = false;
+ loge("setCallWaiting exception: " + ar.exception);
+ }
+ notifyRequester(request);
+ break;
+
case EVENT_PERFORM_NETWORK_SCAN_DONE:
ar = (AsyncResult) msg.obj;
request = (MainThreadRequest) ar.userObj;
@@ -861,14 +1021,47 @@
onCompleted = obtainMessage(EVENT_GET_MODEM_ACTIVITY_INFO_DONE, request);
if (defaultPhone != null) {
defaultPhone.getModemActivityInfo(onCompleted, request.workSource);
+ } else {
+ ResultReceiver result = (ResultReceiver) request.argument;
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY,
+ new ModemActivityInfo(0, 0, 0, new int[0], 0));
+ result.send(0, bundle);
}
break;
case EVENT_GET_MODEM_ACTIVITY_INFO_DONE:
ar = (AsyncResult) msg.obj;
request = (MainThreadRequest) ar.userObj;
+ ResultReceiver result = (ResultReceiver) request.argument;
+
+ ModemActivityInfo ret = new ModemActivityInfo(0, 0, 0, new int[0], 0);
if (ar.exception == null && ar.result != null) {
- request.result = ar.result;
+ // Update the last modem activity info and the result of the request.
+ ModemActivityInfo info = (ModemActivityInfo) ar.result;
+ if (isModemActivityInfoValid(info)) {
+ int[] mergedTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
+ int[] txTimeMs = info.getTransmitTimeMillis();
+ int[] lastModemTxTimeMs = mLastModemActivityInfo
+ .getTransmitTimeMillis();
+ for (int i = 0; i < mergedTxTimeMs.length; i++) {
+ mergedTxTimeMs[i] = txTimeMs[i] + lastModemTxTimeMs[i];
+ }
+ mLastModemActivityInfo.setTimestamp(info.getTimestamp());
+ mLastModemActivityInfo.setSleepTimeMillis(info.getSleepTimeMillis()
+ + mLastModemActivityInfo.getSleepTimeMillis());
+ mLastModemActivityInfo.setIdleTimeMillis(info.getIdleTimeMillis()
+ + mLastModemActivityInfo.getIdleTimeMillis());
+ mLastModemActivityInfo.setTransmitTimeMillis(mergedTxTimeMs);
+ mLastModemActivityInfo.setReceiveTimeMillis(
+ info.getReceiveTimeMillis()
+ + mLastModemActivityInfo.getReceiveTimeMillis());
+ }
+ ret = new ModemActivityInfo(mLastModemActivityInfo.getTimestamp(),
+ mLastModemActivityInfo.getSleepTimeMillis(),
+ mLastModemActivityInfo.getIdleTimeMillis(),
+ mLastModemActivityInfo.getTransmitTimeMillis(),
+ mLastModemActivityInfo.getReceiveTimeMillis());
} else {
if (ar.result == null) {
loge("queryModemActivityInfo: Empty response");
@@ -879,10 +1072,9 @@
loge("queryModemActivityInfo: Unknown exception");
}
}
- // Result cannot be null. Return ModemActivityInfo with all fields set to 0.
- if (request.result == null) {
- request.result = new ModemActivityInfo(0, 0, 0, null, 0, 0);
- }
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY, ret);
+ result.send(0, bundle);
notifyRequester(request);
break;
@@ -1105,7 +1297,7 @@
request = (MainThreadRequest) msg.obj;
WorkSource ws = (WorkSource) request.argument;
Phone phone = getPhoneFromRequest(request);
- phone.getCellLocation(ws, obtainMessage(EVENT_GET_CELL_LOCATION_DONE, request));
+ phone.getCellIdentity(ws, obtainMessage(EVENT_GET_CELL_LOCATION_DONE, request));
break;
case EVENT_GET_CELL_LOCATION_DONE:
ar = (AsyncResult) msg.obj;
@@ -1115,7 +1307,7 @@
} else {
phone = getPhoneFromRequest(request);
request.result = (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA)
- ? new CdmaCellLocation() : new GsmCellLocation();
+ ? new CellIdentityCdma() : new CellIdentityGsm();
}
synchronized (request) {
@@ -1180,6 +1372,23 @@
}
notifyRequester(request);
break;
+ case CMD_SET_SYSTEM_SELECTION_CHANNELS: {
+ request = (MainThreadRequest) msg.obj;
+ onCompleted = obtainMessage(EVENT_SET_SYSTEM_SELECTION_CHANNELS_DONE, request);
+ Pair<List<RadioAccessSpecifier>, Consumer<Boolean>> args =
+ (Pair<List<RadioAccessSpecifier>, Consumer<Boolean>>) request.argument;
+ request.phone.setSystemSelectionChannels(args.first, onCompleted);
+ break;
+ }
+ case EVENT_SET_SYSTEM_SELECTION_CHANNELS_DONE: {
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ Pair<List<RadioAccessSpecifier>, Consumer<Boolean>> args =
+ (Pair<List<RadioAccessSpecifier>, Consumer<Boolean>>) request.argument;
+ args.second.accept(ar.exception == null);
+ notifyRequester(request);
+ break;
+ }
case EVENT_SET_FORBIDDEN_PLMNS_DONE:
ar = (AsyncResult) msg.obj;
request = (MainThreadRequest) ar.userObj;
@@ -1232,6 +1441,43 @@
case EVENT_ERASE_MODEM_CONFIG_DONE:
handleNullReturnEvent(msg, "eraseModemConfig");
break;
+
+ case CMD_CHANGE_ICC_LOCK_PASSWORD:
+ request = (MainThreadRequest) msg.obj;
+ onCompleted = obtainMessage(EVENT_CHANGE_ICC_LOCK_PASSWORD_DONE, request);
+ Pair<String, String> changed = (Pair<String, String>) request.argument;
+ getPhoneFromRequest(request).getIccCard().changeIccLockPassword(
+ changed.first, changed.second, onCompleted);
+ break;
+ case EVENT_CHANGE_ICC_LOCK_PASSWORD_DONE:
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ if (ar.exception == null) {
+ request.result = TelephonyManager.CHANGE_ICC_LOCK_SUCCESS;
+ } else {
+ request.result = msg.arg1;
+ }
+ notifyRequester(request);
+ break;
+
+ case CMD_SET_ICC_LOCK_ENABLED:
+ request = (MainThreadRequest) msg.obj;
+ onCompleted = obtainMessage(EVENT_SET_ICC_LOCK_ENABLED_DONE, request);
+ Pair<Boolean, String> enabled = (Pair<Boolean, String>) request.argument;
+ getPhoneFromRequest(request).getIccCard().setIccLockEnabled(
+ enabled.first, enabled.second, onCompleted);
+ break;
+ case EVENT_SET_ICC_LOCK_ENABLED_DONE:
+ ar = (AsyncResult) msg.obj;
+ request = (MainThreadRequest) ar.userObj;
+ if (ar.exception == null) {
+ request.result = TelephonyManager.CHANGE_ICC_LOCK_SUCCESS;
+ } else {
+ request.result = msg.arg1;
+ }
+ notifyRequester(request);
+ break;
+
default:
Log.w(LOG_TAG, "MainThreadHandler: unexpected message code: " + msg.what);
break;
@@ -1393,6 +1639,7 @@
private PhoneInterfaceManager(PhoneGlobals app) {
mApp = app;
mCM = PhoneGlobals.getInstance().mCM;
+ mImsResolver = PhoneGlobals.getInstance().getImsResolver();
mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE);
mMainThreadHandler = new MainThreadHandler();
@@ -1454,6 +1701,16 @@
}
}
+ private boolean isImsAvailableOnDevice() {
+ PackageManager pm = getDefaultPhone().getContext().getPackageManager();
+ if (pm == null) {
+ // For some reason package manger is not available.. This will fail internally anyway,
+ // so do not throw error and allow.
+ return true;
+ }
+ return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS, 0);
+ }
+
public void dial(String number) {
dialForSubscriber(getPreferredVoiceSubscription(), number);
}
@@ -1530,29 +1787,16 @@
}
}
- public boolean supplyPin(String pin) {
- return supplyPinForSubscriber(getDefaultSubscription(), pin);
- }
-
public boolean supplyPinForSubscriber(int subId, String pin) {
int [] resultArray = supplyPinReportResultForSubscriber(subId, pin);
return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
}
- public boolean supplyPuk(String puk, String pin) {
- return supplyPukForSubscriber(getDefaultSubscription(), puk, pin);
- }
-
public boolean supplyPukForSubscriber(int subId, String puk, String pin) {
int [] resultArray = supplyPukReportResultForSubscriber(subId, puk, pin);
return (resultArray[0] == PhoneConstants.PIN_RESULT_SUCCESS) ? true : false;
}
- /** {@hide} */
- public int[] supplyPinReportResult(String pin) {
- return supplyPinReportResultForSubscriber(getDefaultSubscription(), pin);
- }
-
public int[] supplyPinReportResultForSubscriber(int subId, String pin) {
enforceModifyPermission();
@@ -1566,11 +1810,6 @@
}
}
- /** {@hide} */
- public int[] supplyPukReportResult(String puk, String pin) {
- return supplyPukReportResultForSubscriber(getDefaultSubscription(), puk, pin);
- }
-
public int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin) {
enforceModifyPermission();
@@ -1703,15 +1942,29 @@
}
}
+ @Deprecated
@Override
public boolean isRadioOn(String callingPackage) {
- return isRadioOnForSubscriber(getDefaultSubscription(), callingPackage);
+ return isRadioOnWithFeature(callingPackage, null);
}
@Override
+ public boolean isRadioOnWithFeature(String callingPackage, String callingFeatureId) {
+ return isRadioOnForSubscriberWithFeature(getDefaultSubscription(), callingPackage,
+ callingFeatureId);
+ }
+
+ @Deprecated
+ @Override
public boolean isRadioOnForSubscriber(int subId, String callingPackage) {
+ return isRadioOnForSubscriberWithFeature(subId, callingPackage, null);
+ }
+
+ @Override
+ public boolean isRadioOnForSubscriberWithFeature(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "isRadioOnForSubscriber")) {
+ mApp, subId, callingPackage, callingFeatureId, "isRadioOnForSubscriber")) {
return false;
}
@@ -1998,7 +2251,7 @@
}
@Override
- public Bundle getCellLocation(String callingPackage) {
+ public CellIdentity getCellLocation(String callingPackage, String callingFeatureId) {
mApp.getSystemService(AppOpsManager.class)
.checkPackage(Binder.getCallingUid(), callingPackage);
@@ -2006,6 +2259,7 @@
LocationAccessPolicy.checkLocationPermission(mApp,
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setCallingPid(Binder.getCallingPid())
.setCallingUid(Binder.getCallingUid())
.setMethod("getCellLocation")
@@ -2015,33 +2269,23 @@
case DENIED_HARD:
throw new SecurityException("Not allowed to access cell location");
case DENIED_SOFT:
- return new Bundle();
+ return (getDefaultPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_CDMA)
+ ? new CellIdentityCdma() : new CellIdentityGsm();
}
WorkSource workSource = getWorkSource(Binder.getCallingUid());
final long identity = Binder.clearCallingIdentity();
try {
if (DBG_LOC) log("getCellLocation: is active user");
- Bundle data = new Bundle();
int subId = mSubscriptionController.getDefaultDataSubId();
- CellLocation cl = (CellLocation) sendRequest(CMD_GET_CELL_LOCATION, workSource, subId);
- cl.fillInNotifierBundle(data);
- return data;
+ return (CellIdentity) sendRequest(CMD_GET_CELL_LOCATION, workSource, subId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
- public String getNetworkCountryIsoForPhone(int phoneId, String callingPackage) {
- if (!TextUtils.isEmpty(callingPackage)) {
- final int subId = mSubscriptionController.getSubIdUsingPhoneId(phoneId);
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getNetworkCountryIsoForPhone")) {
- return "";
- }
- }
-
+ public String getNetworkCountryIsoForPhone(int phoneId) {
// Reporting the correct network country is ambiguous when IWLAN could conflict with
// registered cell info, so return a NULL country instead.
final long identity = Binder.clearCallingIdentity();
@@ -2054,7 +2298,8 @@
// Todo: fix this when we can get the actual cellular network info when the device
// is on IWLAN.
if (TelephonyManager.NETWORK_TYPE_IWLAN
- == getVoiceNetworkTypeForSubscriber(subId, mApp.getPackageName())) {
+ == getVoiceNetworkTypeForSubscriber(subId, mApp.getPackageName(),
+ null)) {
return "";
}
Phone phone = PhoneFactory.getPhone(phoneId);
@@ -2141,7 +2386,8 @@
@Override
@SuppressWarnings("unchecked")
- public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage) {
+ public List<NeighboringCellInfo> getNeighboringCellInfo(String callingPackage,
+ String callingFeatureId) {
final int targetSdk = getTargetSdk(callingPackage);
if (targetSdk >= android.os.Build.VERSION_CODES.Q) {
throw new SecurityException(
@@ -2155,7 +2401,7 @@
if (DBG_LOC) log("getNeighboringCellInfo: is active user");
- List<CellInfo> info = getAllCellInfo(callingPackage);
+ List<CellInfo> info = getAllCellInfo(callingPackage, callingFeatureId);
if (info == null) return null;
List<NeighboringCellInfo> neighbors = new ArrayList<NeighboringCellInfo>();
@@ -2179,7 +2425,7 @@
}
@Override
- public List<CellInfo> getAllCellInfo(String callingPackage) {
+ public List<CellInfo> getAllCellInfo(String callingPackage, String callingFeatureId) {
mApp.getSystemService(AppOpsManager.class)
.checkPackage(Binder.getCallingUid(), callingPackage);
@@ -2187,6 +2433,7 @@
LocationAccessPolicy.checkLocationPermission(mApp,
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setCallingPid(Binder.getCallingPid())
.setCallingUid(Binder.getCallingUid())
.setMethod("getAllCellInfo")
@@ -2222,20 +2469,21 @@
}
@Override
- public void requestCellInfoUpdate(int subId, ICellInfoCallback cb, String callingPackage) {
- requestCellInfoUpdateInternal(
- subId, cb, callingPackage, getWorkSource(Binder.getCallingUid()));
+ public void requestCellInfoUpdate(int subId, ICellInfoCallback cb, String callingPackage,
+ String callingFeatureId) {
+ requestCellInfoUpdateInternal(subId, cb, callingPackage, callingFeatureId,
+ getWorkSource(Binder.getCallingUid()));
}
@Override
- public void requestCellInfoUpdateWithWorkSource(
- int subId, ICellInfoCallback cb, String callingPackage, WorkSource workSource) {
+ public void requestCellInfoUpdateWithWorkSource(int subId, ICellInfoCallback cb,
+ String callingPackage, String callingFeatureId, WorkSource workSource) {
enforceModifyPermission();
- requestCellInfoUpdateInternal(subId, cb, callingPackage, workSource);
+ requestCellInfoUpdateInternal(subId, cb, callingPackage, callingFeatureId, workSource);
}
- private void requestCellInfoUpdateInternal(
- int subId, ICellInfoCallback cb, String callingPackage, WorkSource workSource) {
+ private void requestCellInfoUpdateInternal(int subId, ICellInfoCallback cb,
+ String callingPackage, String callingFeatureId, WorkSource workSource) {
mApp.getSystemService(AppOpsManager.class)
.checkPackage(Binder.getCallingUid(), callingPackage);
@@ -2243,6 +2491,7 @@
LocationAccessPolicy.checkLocationPermission(mApp,
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setCallingPid(Binder.getCallingPid())
.setCallingUid(Binder.getCallingUid())
.setMethod("requestCellInfoUpdate")
@@ -2281,14 +2530,14 @@
}
@Override
- public String getImeiForSlot(int slotIndex, String callingPackage) {
+ public String getImeiForSlot(int slotIndex, String callingPackage, String callingFeatureId) {
Phone phone = PhoneFactory.getPhone(slotIndex);
if (phone == null) {
return null;
}
int subId = phone.getSubId();
if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mApp, subId,
- callingPackage, "getImeiForSlot")) {
+ callingPackage, callingFeatureId, "getImeiForSlot")) {
return null;
}
@@ -2312,7 +2561,7 @@
}
@Override
- public String getMeidForSlot(int slotIndex, String callingPackage) {
+ public String getMeidForSlot(int slotIndex, String callingPackage, String callingFeatureId) {
Phone phone = PhoneFactory.getPhone(slotIndex);
if (phone == null) {
return null;
@@ -2320,7 +2569,7 @@
int subId = phone.getSubId();
if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mApp, subId,
- callingPackage, "getMeidForSlot")) {
+ callingPackage, callingFeatureId, "getMeidForSlot")) {
return null;
}
@@ -2344,14 +2593,16 @@
}
@Override
- public String getDeviceSoftwareVersionForSlot(int slotIndex, String callingPackage) {
+ public String getDeviceSoftwareVersionForSlot(int slotIndex, String callingPackage,
+ String callingFeatureId) {
Phone phone = PhoneFactory.getPhone(slotIndex);
if (phone == null) {
return null;
}
int subId = phone.getSubId();
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getDeviceSoftwareVersionForSlot")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "getDeviceSoftwareVersionForSlot")) {
return null;
}
@@ -2438,6 +2689,17 @@
mApp.enforceCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE, null);
}
+ /**
+ * Make sure the caller is system.
+ *
+ * @throws SecurityException if the caller is not system.
+ */
+ private void enforceSystemCaller() {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Caller must be system");
+ }
+ }
+
private void enforceActiveEmergencySessionPermission() {
mApp.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
@@ -2500,14 +2762,17 @@
* Returns the CDMA ERI icon index to display
*/
@Override
- public int getCdmaEriIconIndex(String callingPackage) {
- return getCdmaEriIconIndexForSubscriber(getDefaultSubscription(), callingPackage);
+ public int getCdmaEriIconIndex(String callingPackage, String callingFeatureId) {
+ return getCdmaEriIconIndexForSubscriber(getDefaultSubscription(), callingPackage,
+ callingFeatureId);
}
@Override
- public int getCdmaEriIconIndexForSubscriber(int subId, String callingPackage) {
+ public int getCdmaEriIconIndexForSubscriber(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getCdmaEriIconIndexForSubscriber")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "getCdmaEriIconIndexForSubscriber")) {
return -1;
}
@@ -2530,14 +2795,17 @@
* 1 - FLASHING
*/
@Override
- public int getCdmaEriIconMode(String callingPackage) {
- return getCdmaEriIconModeForSubscriber(getDefaultSubscription(), callingPackage);
+ public int getCdmaEriIconMode(String callingPackage, String callingFeatureId) {
+ return getCdmaEriIconModeForSubscriber(getDefaultSubscription(), callingPackage,
+ callingFeatureId);
}
@Override
- public int getCdmaEriIconModeForSubscriber(int subId, String callingPackage) {
+ public int getCdmaEriIconModeForSubscriber(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getCdmaEriIconModeForSubscriber")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "getCdmaEriIconModeForSubscriber")) {
return -1;
}
@@ -2558,14 +2826,17 @@
* Returns the CDMA ERI text,
*/
@Override
- public String getCdmaEriText(String callingPackage) {
- return getCdmaEriTextForSubscriber(getDefaultSubscription(), callingPackage);
+ public String getCdmaEriText(String callingPackage, String callingFeatureId) {
+ return getCdmaEriTextForSubscriber(getDefaultSubscription(), callingPackage,
+ callingFeatureId);
}
@Override
- public String getCdmaEriTextForSubscriber(int subId, String callingPackage) {
+ public String getCdmaEriTextForSubscriber(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getCdmaEriIconTextForSubscriber")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "getCdmaEriIconTextForSubscriber")) {
return null;
}
@@ -2666,7 +2937,8 @@
*/
@Override
public boolean setVoiceMailNumber(int subId, String alphaTag, String number) {
- TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(subId, "setVoiceMailNumber");
+ TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+ mApp, subId, "setVoiceMailNumber");
final long identity = Binder.clearCallingIdentity();
try {
@@ -2700,10 +2972,12 @@
}
@Override
- public String getVisualVoicemailPackageName(String callingPackage, int subId) {
+ public String getVisualVoicemailPackageName(String callingPackage, String callingFeatureId,
+ int subId) {
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getVisualVoicemailPackageName")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "getVisualVoicemailPackageName")) {
return null;
}
@@ -2770,14 +3044,15 @@
}
@Override
- public void sendVisualVoicemailSmsForSubscriber(String callingPackage, int subId,
- String number, int port, String text, PendingIntent sentIntent) {
+ public void sendVisualVoicemailSmsForSubscriber(String callingPackage,
+ String callingAttributionTag, int subId, String number, int port, String text,
+ PendingIntent sentIntent) {
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
enforceVisualVoicemailPackage(callingPackage, subId);
enforceSendSmsPermission();
SmsController smsController = PhoneFactory.getSmsController();
- smsController.sendVisualVoicemailSmsForSubscriber(callingPackage, subId, number, port, text,
- sentIntent);
+ smsController.sendVisualVoicemailSmsForSubscriber(callingPackage, callingAttributionTag,
+ subId, number, port, text, sentIntent);
}
/**
@@ -2866,9 +3141,11 @@
* Returns the unread count of voicemails for a subId
*/
@Override
- public int getVoiceMessageCountForSubscriber(int subId, String callingPackage) {
+ public int getVoiceMessageCountForSubscriber(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getVoiceMessageCountForSubscriber")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "getVoiceMessageCountForSubscriber")) {
return 0;
}
final long identity = Binder.clearCallingIdentity();
@@ -2911,7 +3188,7 @@
TelecomManager tm = defaultPhone.getContext().getSystemService(TelecomManager.class);
String defaultDialer = tm.getDefaultDialerPackage();
if (!TextUtils.equals(callingPackage, defaultDialer)) {
- TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+ TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mApp,
getDefaultSubscription(), "sendDialerSpecialCode");
}
@@ -2925,11 +3202,18 @@
@Override
public int getNetworkSelectionMode(int subId) {
- if (!isActiveSubscription(subId)) {
- return TelephonyManager.NETWORK_SELECTION_MODE_UNKNOWN;
+ TelephonyPermissions
+ .enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getNetworkSelectionMode");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (!isActiveSubscription(subId)) {
+ return TelephonyManager.NETWORK_SELECTION_MODE_UNKNOWN;
+ }
+ return (int) sendRequest(CMD_GET_NETWORK_SELECTION_MODE, null /* argument */, subId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
-
- return (int) sendRequest(CMD_GET_NETWORK_SELECTION_MODE, null /* argument */, subId);
}
@Override
@@ -2948,10 +3232,17 @@
return false;
}
+ /**
+ * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+ * @param subId The subscription to use to check the configuration.
+ * @param c The callback that will be used to send the result.
+ */
@Override
public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback c)
throws RemoteException {
- enforceReadPrivilegedPermission("registerImsRegistrationCallback");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "registerImsRegistrationCallback");
+
if (!ImsManager.isImsSupportedOnDevice(mApp)) {
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
"IMS not available on device.");
@@ -2968,9 +3259,15 @@
}
}
+ /**
+ * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+ * @param subId The subscription to use to check the configuration.
+ * @param c The callback that will be used to send the result.
+ */
@Override
public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback c) {
- enforceReadPrivilegedPermission("unregisterImsRegistrationCallback");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "unregisterImsRegistrationCallback");
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
@@ -3026,7 +3323,8 @@
*/
@Override
public void getImsMmTelRegistrationTransportType(int subId, IIntegerConsumer consumer) {
- enforceReadPrivilegedPermission("getImsMmTelRegistrationTransportType");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getImsMmTelRegistrationTransportType");
if (!ImsManager.isImsSupportedOnDevice(mApp)) {
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
"IMS not available on device.");
@@ -3057,10 +3355,16 @@
}
}
+ /**
+ * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+ * @param subId The subscription to use to check the configuration.
+ * @param c The callback that will be used to send the result.
+ */
@Override
public void registerMmTelCapabilityCallback(int subId, IImsCapabilityCallback c)
throws RemoteException {
- enforceReadPrivilegedPermission("registerMmTelCapabilityCallback");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "registerMmTelCapabilityCallback");
if (!ImsManager.isImsSupportedOnDevice(mApp)) {
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
"IMS not available on device.");
@@ -3077,9 +3381,15 @@
}
}
+ /**
+ * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+ * @param subId The subscription to use to check the configuration.
+ * @param c The callback that will be used to send the result.
+ */
@Override
public void unregisterMmTelCapabilityCallback(int subId, IImsCapabilityCallback c) {
- enforceReadPrivilegedPermission("unregisterMmTelCapabilityCallback");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "unregisterMmTelCapabilityCallback");
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
throw new IllegalArgumentException("Invalid Subscription ID: " + subId);
}
@@ -3169,9 +3479,15 @@
}
}
+ /**
+ * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+ * @param subId The subscription to use to check the configuration.
+ */
@Override
public boolean isAdvancedCallingSettingEnabled(int subId) {
- enforceReadPrivilegedPermission("enforceReadPrivilegedPermission");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isAdvancedCallingSettingEnabled");
+
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
final long token = Binder.clearCallingIdentity();
try {
@@ -3200,9 +3516,14 @@
}
}
+ /**
+ * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+ * @param subId The subscription to use to check the configuration.
+ */
@Override
public boolean isVtSettingEnabled(int subId) {
- enforceReadPrivilegedPermission("isVtSettingEnabled");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isVtSettingEnabled");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3229,9 +3550,14 @@
}
}
+ /**
+ * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+ * @param subId The subscription to use to check the configuration.
+ */
@Override
public boolean isVoWiFiSettingEnabled(int subId) {
- enforceReadPrivilegedPermission("isVoWiFiSettingEnabled");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isVoWiFiSettingEnabled");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3259,9 +3585,14 @@
}
}
+ /**
+ * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+ * @param subId The subscription to use to check the configuration.
+ */
@Override
public boolean isVoWiFiRoamingSettingEnabled(int subId) {
- enforceReadPrivilegedPermission("isVoWiFiRoamingSettingEnabled");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isVoWiFiRoamingSettingEnabled");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3306,9 +3637,14 @@
}
}
+ /**
+ * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+ * @param subId The subscription to use to check the configuration.
+ */
@Override
public int getVoWiFiModeSetting(int subId) {
- enforceReadPrivilegedPermission("getVoWiFiModeSetting");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getVoWiFiModeSetting");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3383,9 +3719,14 @@
}
}
+ /**
+ * Requires carrier privileges or READ_PRECISE_PHONE_STATE permission.
+ * @param subId The subscription to use to check the configuration.
+ */
@Override
public boolean isTtyOverVolteEnabled(int subId) {
- enforceReadPrivilegedPermission("isTtyOverVolteEnabled");
+ TelephonyPermissions.enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "isTtyOverVolteEnabled");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
@@ -3403,6 +3744,10 @@
enforceReadPrivilegedPermission("registerImsProvisioningChangedCallback");
final long identity = Binder.clearCallingIdentity();
try {
+ if (!isImsAvailableOnDevice()) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "IMS not available on device.");
+ }
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
ImsManager.getInstance(mApp, getSlotIndexOrException(subId))
.addProvisioningCallbackForSubscription(callback, subId);
@@ -3434,6 +3779,91 @@
}
}
+
+ private void checkModifyPhoneStatePermission(int subId, String message) {
+ TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
+ message);
+ }
+
+ private boolean isImsProvisioningRequired(int subId, int capability,
+ boolean isMmtelCapability) {
+ Phone phone = getPhone(subId);
+ if (phone == null) {
+ loge("phone instance null for subid " + subId);
+ return false;
+ }
+ if (isMmtelCapability) {
+ if (!doesImsCapabilityRequireProvisioning(phone.getContext(), subId, capability)) {
+ return false;
+ }
+ } else {
+ if (!doesRcsCapabilityRequireProvisioning(phone.getContext(), subId, capability)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void setRcsProvisioningStatusForCapability(int subId, int capability,
+ boolean isProvisioned) {
+ checkModifyPhoneStatePermission(subId, "setRcsProvisioningStatusForCapability");
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
+ if (!isImsProvisioningRequired(subId, capability, false)) {
+ return;
+ }
+
+ // this capability requires provisioning, route to the correct API.
+ ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
+ switch (capability) {
+ case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE:
+ case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE:
+ ims.setEabProvisioned(isProvisioned);
+ break;
+ default: {
+ throw new IllegalArgumentException("Tried to set provisioning for "
+ + "rcs capability '" + capability + "', which does not require "
+ + "provisioning.");
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+
+ }
+
+
+ @Override
+ public boolean getRcsProvisioningStatusForCapability(int subId, int capability) {
+ enforceReadPrivilegedPermission("getRcsProvisioningStatusForCapability");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ // TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
+ if (!isImsProvisioningRequired(subId, capability, false)) {
+ return true;
+ }
+
+ ImsManager ims = ImsManager.getInstance(mApp, getSlotIndex(subId));
+ switch (capability) {
+ case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE:
+ case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE:
+ return ims.isEabProvisionedOnDevice();
+
+ default: {
+ throw new IllegalArgumentException("Tried to get rcs provisioning for "
+ + "capability '" + capability + "', which does not require "
+ + "provisioning.");
+ }
+ }
+
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
@Override
public void setImsProvisioningStatusForCapability(int subId, int capability, int tech,
boolean isProvisioned) {
@@ -3441,18 +3871,11 @@
&& tech != ImsRegistrationImplBase.REGISTRATION_TECH_LTE) {
throw new IllegalArgumentException("Registration technology '" + tech + "' is invalid");
}
- TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp, subId,
- "setProvisioningStatusForCapability");
+ checkModifyPhoneStatePermission(subId, "setImsProvisioningStatusForCapability");
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
- Phone phone = getPhone(subId);
- if (phone == null) {
- loge("setImsProvisioningStatusForCapability: phone instance null for subid "
- + subId);
- return;
- }
- if (!doesImsCapabilityRequireProvisioning(phone.getContext(), subId, capability)) {
+ if (!isImsProvisioningRequired(subId, capability, true)) {
return;
}
@@ -3490,8 +3913,9 @@
break;
}
default: {
- throw new IllegalArgumentException("Tried to set provisioning for capability '"
- + capability + "', which does not require provisioning.");
+ throw new IllegalArgumentException("Tried to set provisioning for "
+ + "MmTel capability '" + capability + "', which does not require "
+ + "provisioning. ");
}
}
@@ -3510,16 +3934,7 @@
final long identity = Binder.clearCallingIdentity();
try {
// TODO: Refactor to remove ImsManager dependence and query through ImsPhone directly.
- Phone phone = getPhone(subId);
- if (phone == null) {
- loge("getImsProvisioningStatusForCapability: phone instance null for subid "
- + subId);
- // We will fail with "true" as the provisioning status because this is the default
- // if we do not require provisioning.
- return true;
- }
-
- if (!doesImsCapabilityRequireProvisioning(phone.getContext(), subId, capability)) {
+ if (!isImsProvisioningRequired(subId, capability, true)) {
return true;
}
@@ -3545,8 +3960,9 @@
return isMmTelCapabilityProvisionedInCache(subId, capability, tech);
}
default: {
- throw new IllegalArgumentException("Tried to get provisioning for capability '"
- + capability + "', which does not require provisioning.");
+ throw new IllegalArgumentException(
+ "Tried to get provisioning for MmTel capability '" + capability
+ + "', which does not require provisioning.");
}
}
@@ -3655,6 +4071,29 @@
return false;
}
+ private boolean doesRcsCapabilityRequireProvisioning(Context context, int subId,
+ int capability) {
+ CarrierConfigManager configManager = new CarrierConfigManager(context);
+ PersistableBundle c = configManager.getConfigForSubId(subId);
+
+ boolean requireRcsProvisioning = c.getBoolean(
+ CarrierConfigManager.KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL, false);
+
+ // First check to make sure that the capability requires provisioning.
+ switch (capability) {
+ case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE:
+ // intentional fallthrough
+ case RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE: {
+ if (requireRcsProvisioning) {
+ // OPTION or PRESENCE requires provisioning
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+ }
+
@Override
public int getImsProvisioningInt(int subId, int key) {
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -3778,13 +4217,15 @@
* Returns the data network type for a subId; does not throw SecurityException.
*/
@Override
- public int getNetworkTypeForSubscriber(int subId, String callingPackage) {
+ public int getNetworkTypeForSubscriber(int subId, String callingPackage,
+ String callingFeatureId) {
final int targetSdk = getTargetSdk(callingPackage);
if (targetSdk > android.os.Build.VERSION_CODES.Q) {
- return getDataNetworkTypeForSubscriber(subId, callingPackage);
+ return getDataNetworkTypeForSubscriber(subId, callingPackage, callingFeatureId);
} else if (targetSdk == android.os.Build.VERSION_CODES.Q
&& !TelephonyPermissions.checkCallingOrSelfReadPhoneStateNoThrow(
- mApp, subId, callingPackage, "getNetworkTypeForSubscriber")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "getNetworkTypeForSubscriber")) {
return TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
@@ -3805,17 +4246,20 @@
* Returns the data network type
*/
@Override
- public int getDataNetworkType(String callingPackage) {
- return getDataNetworkTypeForSubscriber(getDefaultSubscription(), callingPackage);
+ public int getDataNetworkType(String callingPackage, String callingFeatureId) {
+ return getDataNetworkTypeForSubscriber(getDefaultSubscription(), callingPackage,
+ callingFeatureId);
}
/**
* Returns the data network type for a subId
*/
@Override
- public int getDataNetworkTypeForSubscriber(int subId, String callingPackage) {
+ public int getDataNetworkTypeForSubscriber(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getDataNetworkTypeForSubscriber")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "getDataNetworkTypeForSubscriber")) {
return TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
@@ -3836,9 +4280,11 @@
* Returns the Voice network type for a subId
*/
@Override
- public int getVoiceNetworkTypeForSubscriber(int subId, String callingPackage) {
+ public int getVoiceNetworkTypeForSubscriber(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getDataNetworkTypeForSubscriber")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "getDataNetworkTypeForSubscriber")) {
return TelephonyManager.NETWORK_TYPE_UNKNOWN;
}
@@ -3892,14 +4338,17 @@
* or {@link Phone#LTE_ON_CDMA_TRUE}
*/
@Override
- public int getLteOnCdmaMode(String callingPackage) {
- return getLteOnCdmaModeForSubscriber(getDefaultSubscription(), callingPackage);
+ public int getLteOnCdmaMode(String callingPackage, String callingFeatureId) {
+ return getLteOnCdmaModeForSubscriber(getDefaultSubscription(), callingPackage,
+ callingFeatureId);
}
@Override
- public int getLteOnCdmaModeForSubscriber(int subId, String callingPackage) {
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getLteOnCdmaModeForSubscriber")) {
+ public int getLteOnCdmaModeForSubscriber(int subId, String callingPackage,
+ String callingFeatureId) {
+ try {
+ enforceReadPrivilegedPermission("getLteOnCdmaModeForSubscriber");
+ } catch (SecurityException e) {
return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
}
@@ -4223,9 +4672,10 @@
* Get the forbidden PLMN List from the given app type (ex APPTYPE_USIM)
* on a particular subscription
*/
- public String[] getForbiddenPlmns(int subId, int appType, String callingPackage) {
+ public String[] getForbiddenPlmns(int subId, int appType, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getForbiddenPlmns")) {
+ mApp, subId, callingPackage, callingFeatureId, "getForbiddenPlmns")) {
return null;
}
@@ -4257,12 +4707,13 @@
* @param appType the uicc app type, must be USIM or SIM.
* @param fplmns the Forbiden plmns list that needed to be written to the SIM.
* @param callingPackage the op Package name.
+ * @param callingFeatureId the feature in the package.
* @return number of fplmns that is successfully written to the SIM.
*/
- public int setForbiddenPlmns(
- int subId, int appType, List<String> fplmns, String callingPackage) {
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "setForbiddenPlmns")) {
+ public int setForbiddenPlmns(int subId, int appType, List<String> fplmns, String callingPackage,
+ String callingFeatureId) {
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, subId, callingPackage,
+ callingFeatureId, "setForbiddenPlmns")) {
if (DBG) logv("no permissions for setForbiddenplmns");
throw new IllegalStateException("No Permissions for setForbiddenPlmns");
}
@@ -4438,10 +4889,11 @@
return false;
}
- public String[] getPcscfAddress(String apnType, String callingPackage) {
+ public String[] getPcscfAddress(String apnType, String callingPackage,
+ String callingFeatureId) {
final Phone defaultPhone = getDefaultPhone();
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, defaultPhone.getSubId(), callingPackage, "getPcscfAddress")) {
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, defaultPhone.getSubId(),
+ callingPackage, callingFeatureId, "getPcscfAddress")) {
return new String[0];
}
@@ -4454,6 +4906,27 @@
}
/**
+ * Toggle IMS disable and enable for the framework to reset it. See {@link #enableIms(int)} and
+ * {@link #disableIms(int)}.
+ * @param slotIndex device slot.
+ */
+ public void resetIms(int slotIndex) {
+ enforceModifyPermission();
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (mImsResolver == null) {
+ // may happen if the does not support IMS.
+ return;
+ }
+ mImsResolver.disableIms(slotIndex);
+ mImsResolver.enableIms(slotIndex);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
* Enables IMS for the framework. This will trigger IMS registration and ImsFeature capability
* status updates, if not already enabled.
*/
@@ -4462,12 +4935,11 @@
final long identity = Binder.clearCallingIdentity();
try {
- ImsResolver resolver = PhoneFactory.getImsResolver();
- if (resolver == null) {
+ if (mImsResolver == null) {
// may happen if the device does not support IMS.
return;
}
- resolver.enableIms(slotId);
+ mImsResolver.enableIms(slotId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4482,12 +4954,11 @@
final long identity = Binder.clearCallingIdentity();
try {
- ImsResolver resolver = PhoneFactory.getImsResolver();
- if (resolver == null) {
+ if (mImsResolver == null) {
// may happen if the device does not support IMS.
return;
}
- resolver.disableIms(slotId);
+ mImsResolver.disableIms(slotId);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4504,12 +4975,11 @@
final long identity = Binder.clearCallingIdentity();
try {
- ImsResolver resolver = PhoneFactory.getImsResolver();
- if (resolver == null) {
+ if (mImsResolver == null) {
// may happen if the device does not support IMS.
return null;
}
- return resolver.getMmTelFeatureAndListen(slotId, callback);
+ return mImsResolver.getMmTelFeatureAndListen(slotId, callback);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4526,12 +4996,11 @@
final long identity = Binder.clearCallingIdentity();
try {
- ImsResolver resolver = PhoneFactory.getImsResolver();
- if (resolver == null) {
+ if (mImsResolver == null) {
// may happen if the device does not support IMS.
return null;
}
- return resolver.getRcsFeatureAndListen(slotId, callback);
+ return mImsResolver.getRcsFeatureAndListen(slotId, callback);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4546,12 +5015,11 @@
final long identity = Binder.clearCallingIdentity();
try {
- ImsResolver resolver = PhoneFactory.getImsResolver();
- if (resolver == null) {
+ if (mImsResolver == null) {
// may happen if the device does not support IMS.
return null;
}
- return resolver.getImsRegistration(slotId, feature);
+ return mImsResolver.getImsRegistration(slotId, feature);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4566,12 +5034,11 @@
final long identity = Binder.clearCallingIdentity();
try {
- ImsResolver resolver = PhoneFactory.getImsResolver();
- if (resolver == null) {
+ if (mImsResolver == null) {
// may happen if the device does not support IMS.
return null;
}
- return resolver.getImsConfig(slotId, feature);
+ return mImsResolver.getImsConfig(slotId, feature);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4580,58 +5047,65 @@
/**
* Sets the ImsService Package Name that Telephony will bind to.
*
- * @param slotId the slot ID that the ImsService should bind for.
- * @param isCarrierImsService true if the ImsService is the carrier override, false if the
+ * @param slotIndex the slot ID that the ImsService should bind for.
+ * @param isCarrierService true if the ImsService is the carrier override, false if the
* ImsService is the device default ImsService.
- * @param packageName The package name of the application that contains the ImsService to bind
- * to.
+ * @param featureTypes An integer array of feature types associated with a packageName.
+ * @param packageName The name of the package that the current configuration will be replaced
+ * with.
* @return true if setting the ImsService to bind to succeeded, false if it did not.
- * @hide
*/
- public boolean setImsService(int slotId, boolean isCarrierImsService, String packageName) {
- int[] subIds = SubscriptionManager.getSubId(slotId);
+ public boolean setBoundImsServiceOverride(int slotIndex, boolean isCarrierService,
+ int[] featureTypes, String packageName) {
+ int[] subIds = SubscriptionManager.getSubId(slotIndex);
+ TelephonyPermissions.enforceShellOnly(Binder.getCallingUid(), "setBoundImsServiceOverride");
TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
(subIds != null ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID),
- "setImsService");
+ "setBoundImsServiceOverride");
final long identity = Binder.clearCallingIdentity();
try {
- ImsResolver resolver = PhoneFactory.getImsResolver();
- if (resolver == null) {
+ if (mImsResolver == null) {
// may happen if the device does not support IMS.
return false;
}
- return resolver.overrideImsServiceConfiguration(slotId, isCarrierImsService,
- packageName);
+ Map<Integer, String> featureConfig = new HashMap<>();
+ for (int featureType : featureTypes) {
+ featureConfig.put(featureType, packageName);
+ }
+ return mImsResolver.overrideImsServiceConfiguration(slotIndex, isCarrierService,
+ featureConfig);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
/**
- * Return the ImsService configuration.
+ * Return the package name of the currently bound ImsService.
*
* @param slotId The slot that the ImsService is associated with.
* @param isCarrierImsService true, if the ImsService is a carrier override, false if it is
* the device default.
+ * @param featureType The feature associated with the queried configuration.
* @return the package name of the ImsService configuration.
*/
- public String getImsService(int slotId, boolean isCarrierImsService) {
+ public String getBoundImsServicePackage(int slotId, boolean isCarrierImsService,
+ @ImsFeature.FeatureType int featureType) {
int[] subIds = SubscriptionManager.getSubId(slotId);
- TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(mApp,
- (subIds != null ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID),
- "getImsService");
+ TelephonyPermissions
+ .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+ mApp, (subIds != null ? subIds[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID),
+ "getBoundImsServicePackage");
final long identity = Binder.clearCallingIdentity();
try {
- ImsResolver resolver = PhoneFactory.getImsResolver();
- if (resolver == null) {
+ if (mImsResolver == null) {
// may happen if the device does not support IMS.
return "";
}
// TODO: change API to query RCS separately.
- return resolver.getImsServiceConfiguration(slotId, isCarrierImsService,
- ImsFeature.FEATURE_MMTEL);
+ return mImsResolver.getImsServiceConfiguration(slotId, isCarrierImsService,
+ featureType);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -4691,12 +5165,11 @@
TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
mApp, subId, "setNetworkSelectionModeAutomatic");
- if (!isActiveSubscription(subId)) {
- return;
- }
-
final long identity = Binder.clearCallingIdentity();
try {
+ if (!isActiveSubscription(subId)) {
+ return;
+ }
if (DBG) log("setNetworkSelectionModeAutomatic: subId " + subId);
sendRequest(CMD_SET_NETWORK_SELECTION_MODE_AUTOMATIC, null, subId);
} finally {
@@ -4743,13 +5216,15 @@
* Scans for available networks.
*/
@Override
- public CellNetworkScanResult getCellNetworkScanResults(int subId, String callingPackage) {
+ public CellNetworkScanResult getCellNetworkScanResults(int subId, String callingPackage,
+ String callingFeatureId) {
TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
mApp, subId, "getCellNetworkScanResults");
LocationAccessPolicy.LocationPermissionResult locationResult =
LocationAccessPolicy.checkLocationPermission(mApp,
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setCallingPid(Binder.getCallingPid())
.setCallingUid(Binder.getCallingUid())
.setMethod("getCellNetworkScanResults")
@@ -4773,6 +5248,75 @@
}
/**
+ * Get the call forwarding info, given the call forwarding reason.
+ */
+ @Override
+ public CallForwardingInfo getCallForwarding(int subId, int callForwardingReason) {
+ enforceReadPrivilegedPermission("getCallForwarding");
+ long identity = Binder.clearCallingIdentity();
+ try {
+ if (DBG) {
+ log("getCallForwarding: subId " + subId
+ + " callForwardingReason" + callForwardingReason);
+ }
+ return (CallForwardingInfo) sendRequest(
+ CMD_GET_CALL_FORWARDING, callForwardingReason, subId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Sets the voice call forwarding info including status (enable/disable), call forwarding
+ * reason, the number to forward, and the timeout before the forwarding is attempted.
+ */
+ @Override
+ public boolean setCallForwarding(int subId, CallForwardingInfo callForwardingInfo) {
+ enforceModifyPermission();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ if (DBG) {
+ log("setCallForwarding: subId " + subId
+ + " callForwardingInfo" + callForwardingInfo);
+ }
+ return (Boolean) sendRequest(CMD_SET_CALL_FORWARDING, callForwardingInfo, subId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Get the call forwarding info, given the call forwarding reason.
+ */
+ @Override
+ public int getCallWaitingStatus(int subId) {
+ enforceReadPrivilegedPermission("getCallForwarding");
+ long identity = Binder.clearCallingIdentity();
+ try {
+ if (DBG) log("getCallWaitingStatus: subId " + subId);
+ return (Integer) sendRequest(CMD_GET_CALL_WAITING, null, subId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Sets the voice call forwarding info including status (enable/disable), call forwarding
+ * reason, the number to forward, and the timeout before the forwarding is attempted.
+ */
+ @Override
+ public boolean setCallWaitingStatus(int subId, boolean isEnable) {
+ enforceModifyPermission();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ if (DBG) log("setCallWaitingStatus: subId " + subId + " isEnable: " + isEnable);
+ return (Boolean) sendRequest(CMD_SET_CALL_WAITING, isEnable, subId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
* Starts a new network scan and returns the id of this scan.
*
* @param subId id of the subscription
@@ -4783,13 +5327,14 @@
*/
@Override
public int requestNetworkScan(int subId, NetworkScanRequest request, Messenger messenger,
- IBinder binder, String callingPackage) {
+ IBinder binder, String callingPackage, String callingFeatureId) {
TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
mApp, subId, "requestNetworkScan");
LocationAccessPolicy.LocationPermissionResult locationResult =
LocationAccessPolicy.checkLocationPermission(mApp,
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setCallingPid(Binder.getCallingPid())
.setCallingUid(Binder.getCallingUid())
.setMethod("requestNetworkScan")
@@ -4870,10 +5415,10 @@
* @return the preferred network type, defined in RILConstants.java.
*/
@Override
- public int getCalculatedPreferredNetworkType(String callingPackage) {
+ public int getCalculatedPreferredNetworkType(String callingPackage, String callingFeatureId) {
final Phone defaultPhone = getDefaultPhone();
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, defaultPhone.getSubId(),
- callingPackage, "getCalculatedPreferredNetworkType")) {
+ callingPackage, callingFeatureId, "getCalculatedPreferredNetworkType")) {
return RILConstants.PREFERRED_NETWORK_MODE;
}
@@ -4924,21 +5469,81 @@
final long identity = Binder.clearCallingIdentity();
try {
- if (DBG) log("setPreferredNetworkType: subId " + subId + " type " + networkType);
- Boolean success = (Boolean) sendRequest(
- CMD_SET_PREFERRED_NETWORK_TYPE, networkType, subId);
- if (DBG) log("setPreferredNetworkType: " + (success ? "ok" : "fail"));
- if (success) {
- Settings.Global.putInt(mApp.getContentResolver(),
- Settings.Global.PREFERRED_NETWORK_MODE + subId, networkType);
- }
- return success;
+ Settings.Global.putInt(mApp.getContentResolver(),
+ Settings.Global.PREFERRED_NETWORK_MODE + subId, networkType);
+ return setPreferredNetworkTypesInternal(subId);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
/**
+ * Get the allowed network types that store in the telephony provider.
+ *
+ * @param subId the id of the subscription.
+ * @return allowedNetworkTypes the allowed network types.
+ */
+ @Override
+ public long getAllowedNetworkTypes(int subId) {
+ TelephonyPermissions
+ .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
+ mApp, subId, "getAllowedNetworkTypes");
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return SubscriptionManager.getLongSubscriptionProperty(
+ subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, -1, mApp);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Set the allowed network types.
+ *
+ * @param subId the id of the subscription.
+ * @param allowedNetworkTypes the allowed network types.
+ * @return true on success; false on any failure.
+ */
+ @Override
+ public boolean setAllowedNetworkTypes(int subId, long allowedNetworkTypes) {
+ TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+ mApp, subId, "setAllowedNetworkTypes");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ SubscriptionManager.setSubscriptionProperty(subId,
+ SubscriptionManager.ALLOWED_NETWORK_TYPES,
+ String.valueOf(allowedNetworkTypes));
+ return setPreferredNetworkTypesInternal(subId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ private boolean setPreferredNetworkTypesInternal(int subId) {
+ long networkTypeBitMask = RadioAccessFamily.getRafFromNetworkType(
+ Settings.Global.getInt(mApp.getContentResolver(),
+ Settings.Global.PREFERRED_NETWORK_MODE + subId,
+ RILConstants.PREFERRED_NETWORK_MODE));
+ long allowedNetworkTypes = SubscriptionManager.getLongSubscriptionProperty(
+ subId, SubscriptionManager.ALLOWED_NETWORK_TYPES, -1, mApp);
+ int networkMode = RadioAccessFamily.getNetworkTypeFromRaf(
+ (int) (networkTypeBitMask & allowedNetworkTypes));
+
+ if (DBG) {
+ log("setPreferredNetworkTypesInternal: subId " + subId
+ + " networkTypes " + networkTypeBitMask
+ + " allowedNetworkTypes " + allowedNetworkTypes
+ + " networkMode " + networkMode);
+ }
+
+ Boolean success = (Boolean) sendRequest(
+ CMD_SET_PREFERRED_NETWORK_TYPE, networkMode, subId);
+ if (DBG) log("setPreferredNetworkTypesInternal: " + (success ? "ok" : "fail"));
+ return success;
+ }
+
+ /**
* Check whether DUN APN is required for tethering with subId.
*
* @param subId the id of the subscription to require tethering.
@@ -4989,6 +5594,34 @@
}
/**
+ * Enable or disable always reporting signal strength changes from radio.
+ *
+ * @param isEnable {@code true} for enabling; {@code false} for disabling.
+ */
+ @Override
+ public void setAlwaysReportSignalStrength(int subId, boolean isEnable) {
+ enforceModifyPermission();
+ enforceSystemCaller();
+
+ final long identity = Binder.clearCallingIdentity();
+ final Phone phone = getPhone(subId);
+ try {
+ if (phone != null) {
+ if (DBG) {
+ log("setAlwaysReportSignalStrength: subId=" + subId
+ + " isEnable=" + isEnable);
+ }
+ phone.setAlwaysReportSignalStrength(isEnable);
+ } else {
+ loge("setAlwaysReportSignalStrength: no phone found for subId="
+ + subId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
* Get the user enabled state of Mobile Data.
*
* TODO: remove and use isUserDataEnabled.
@@ -5042,24 +5675,15 @@
}
/**
- * Get whether mobile data is enabled.
+ * Checks if the device is capable of mobile data by considering whether whether the
+ * user has enabled mobile data, whether the carrier has enabled mobile data, and
+ * whether the network policy allows data connections.
*
- * Comparable to {@link #isUserDataEnabled(int)}, this considers all factors deciding
- * whether mobile data is actually enabled.
- *
- * Accepts either ACCESS_NETWORK_STATE, MODIFY_PHONE_STATE or carrier privileges.
- *
- * @return {@code true} if data is enabled else {@code false}
+ * @return {@code true} if the overall data connection is capable; {@code false} if not.
*/
@Override
public boolean isDataEnabled(int subId) {
- try {
- mApp.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_NETWORK_STATE,
- null);
- } catch (Exception e) {
- TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
- mApp, subId, "isDataEnabled");
- }
+ enforceReadPrivilegedPermission("isDataEnabled");
final long identity = Binder.clearCallingIdentity();
try {
@@ -5079,14 +5703,13 @@
}
}
- private int getCarrierPrivilegeStatusFromCarrierConfigRules(int privilegeFromSim,
+ private int getCarrierPrivilegeStatusFromCarrierConfigRules(int privilegeFromSim, int uid,
Phone phone) {
//load access rules from carrier configs, and check those as well: b/139133814
SubscriptionController subController = SubscriptionController.getInstance();
if (privilegeFromSim == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
|| subController == null) return privilegeFromSim;
- int uid = Binder.getCallingUid();
PackageManager pkgMgr = phone.getContext().getPackageManager();
String[] packages = pkgMgr.getPackagesForUid(uid);
@@ -5140,11 +5763,12 @@
return getCarrierPrivilegeStatusFromCarrierConfigRules(
card.getCarrierPrivilegeStatusForCurrentTransaction(
- phone.getContext().getPackageManager()), phone);
+ phone.getContext().getPackageManager()), Binder.getCallingUid(), phone);
}
@Override
public int getCarrierPrivilegeStatusForUid(int subId, int uid) {
+ enforceReadPrivilegedPermission("getCarrierPrivilegeStatusForUid");
final Phone phone = getPhone(subId);
if (phone == null) {
loge("getCarrierPrivilegeStatusForUid: Invalid subId");
@@ -5157,8 +5781,8 @@
return TelephonyManager.CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED;
}
return getCarrierPrivilegeStatusFromCarrierConfigRules(
- profile.getCarrierPrivilegeStatusForUid(
- phone.getContext().getPackageManager(), uid), phone);
+ profile.getCarrierPrivilegeStatusForUid(
+ phone.getContext().getPackageManager(), uid), uid, phone);
}
@Override
@@ -5230,7 +5854,7 @@
PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
| PackageManager.GET_SIGNING_CERTIFICATES,
- UserHandle.USER_SYSTEM);
+ UserHandle.SYSTEM.getIdentifier());
}
for (int p = packages.size() - 1; p >= 0; p--) {
PackageInfo pkgInfo = packages.get(p);
@@ -5280,7 +5904,7 @@
@Override
public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag,
String number) {
- TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+ TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mApp,
subId, "setLine1NumberForDisplayForSubscriber");
final long identity = Binder.clearCallingIdentity();
@@ -5293,7 +5917,7 @@
final String subscriberId = phone.getSubscriberId();
if (DBG_MERGE) {
- Slog.d(LOG_TAG, "Setting line number for ICC=" + iccId + ", subscriberId="
+ Rlog.d(LOG_TAG, "Setting line number for ICC=" + iccId + ", subscriberId="
+ subscriberId + " to " + number);
}
@@ -5330,10 +5954,11 @@
}
@Override
- public String getLine1NumberForDisplay(int subId, String callingPackage) {
+ public String getLine1NumberForDisplay(int subId, String callingPackage,
+ String callingFeatureId) {
// This is open to apps with WRITE_SMS.
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneNumber(
- mApp, subId, callingPackage, "getLine1NumberForDisplay")) {
+ mApp, subId, callingPackage, callingFeatureId, "getLine1NumberForDisplay")) {
if (DBG_MERGE) log("getLine1NumberForDisplay returning null due to permission");
return null;
}
@@ -5357,9 +5982,10 @@
}
@Override
- public String getLine1AlphaTagForDisplay(int subId, String callingPackage) {
+ public String getLine1AlphaTagForDisplay(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getLine1AlphaTagForDisplay")) {
+ mApp, subId, callingPackage, callingFeatureId, "getLine1AlphaTagForDisplay")) {
return null;
}
@@ -5377,12 +6003,13 @@
}
@Override
- public String[] getMergedSubscriberIds(int subId, String callingPackage) {
+ public String[] getMergedSubscriberIds(int subId, String callingPackage,
+ String callingFeatureId) {
// This API isn't public, so no need to provide a valid subscription ID - we're not worried
// about carrier-privileged callers not having access.
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
mApp, SubscriptionManager.INVALID_SUBSCRIPTION_ID, callingPackage,
- "getMergedSubscriberIds")) {
+ callingFeatureId, "getMergedSubscriberIds")) {
return null;
}
@@ -5416,7 +6043,7 @@
final String numberKey = PREF_CARRIERS_NUMBER_PREFIX + iccId;
mergeNumber = (String) prefs.get(numberKey);
if (DBG_MERGE) {
- Slog.d(LOG_TAG, "Found line number " + mergeNumber
+ Rlog.d(LOG_TAG, "Found line number " + mergeNumber
+ " for active subscriber " + subscriberId);
}
if (!TextUtils.isEmpty(mergeNumber)) {
@@ -5450,7 +6077,7 @@
final String[] resultArray = result.toArray(new String[result.size()]);
Arrays.sort(resultArray);
if (DBG_MERGE) {
- Slog.d(LOG_TAG,
+ Rlog.d(LOG_TAG,
"Found subscribers " + Arrays.toString(resultArray) + " after merge");
}
return resultArray;
@@ -5487,7 +6114,8 @@
// Get all subscriberIds from the group.
final List<String> mergedSubscriberIds = new ArrayList<>();
final List<SubscriptionInfo> groupInfos = SubscriptionController.getInstance()
- .getSubscriptionsInGroup(groupUuid, mApp.getOpPackageName());
+ .getSubscriptionsInGroup(groupUuid, mApp.getOpPackageName(),
+ null);
for (SubscriptionInfo subInfo : groupInfos) {
subscriberId = telephonyManager.getSubscriberId(subInfo.getSubscriptionId());
if (subscriberId != null) {
@@ -5504,7 +6132,7 @@
@Override
public boolean setOperatorBrandOverride(int subId, String brand) {
- TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+ TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mApp,
subId, "setOperatorBrandOverride");
final long identity = Binder.clearCallingIdentity();
@@ -5520,7 +6148,8 @@
public boolean setRoamingOverride(int subId, List<String> gsmRoamingList,
List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
List<String> cdmaNonRoamingList) {
- TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(subId, "setRoamingOverride");
+ TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(
+ mApp, subId, "setRoamingOverride");
final long identity = Binder.clearCallingIdentity();
try {
@@ -5611,10 +6240,10 @@
}
@Override
- public boolean isVideoCallingEnabled(String callingPackage) {
+ public boolean isVideoCallingEnabled(String callingPackage, String callingFeatureId) {
final Phone defaultPhone = getDefaultPhone();
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, defaultPhone.getSubId(), callingPackage, "isVideoCallingEnabled")) {
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, defaultPhone.getSubId(),
+ callingPackage, callingFeatureId, "isVideoCallingEnabled")) {
return false;
}
@@ -5635,9 +6264,11 @@
}
@Override
- public boolean canChangeDtmfToneLength(int subId, String callingPackage) {
+ public boolean canChangeDtmfToneLength(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "isVideoCallingEnabled")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "isVideoCallingEnabled")) {
return false;
}
@@ -5653,9 +6284,9 @@
}
@Override
- public boolean isWorldPhone(int subId, String callingPackage) {
+ public boolean isWorldPhone(int subId, String callingPackage, String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "isVideoCallingEnabled")) {
+ mApp, subId, callingPackage, callingFeatureId, "isVideoCallingEnabled")) {
return false;
}
@@ -5719,12 +6350,23 @@
public boolean isRttEnabled(int subscriptionId) {
final long identity = Binder.clearCallingIdentity();
try {
- return isRttSupported(subscriptionId);
+ boolean isRttSupported = isRttSupported(subscriptionId);
+ boolean isUserRttSettingOn = Settings.Secure.getInt(
+ mApp.getContentResolver(), Settings.Secure.RTT_CALLING_MODE, 0) != 0;
+ boolean shouldIgnoreUserRttSetting = mApp.getCarrierConfigForSubId(subscriptionId)
+ .getBoolean(CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL);
+ return isRttSupported && (isUserRttSettingOn || shouldIgnoreUserRttSetting);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ @Deprecated
+ @Override
+ public String getDeviceId(String callingPackage) {
+ return getDeviceIdWithFeature(callingPackage, null);
+ }
+
/**
* Returns the unique device ID of phone, for example, the IMEI for
* GSM and the MEID for CDMA phones. Return null if device ID is not available.
@@ -5733,14 +6375,14 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
@Override
- public String getDeviceId(String callingPackage) {
+ public String getDeviceIdWithFeature(String callingPackage, String callingFeatureId) {
final Phone phone = PhoneFactory.getPhone(0);
if (phone == null) {
return null;
}
int subId = phone.getSubId();
if (!TelephonyPermissions.checkCallingOrSelfReadDeviceIdentifiers(mApp, subId,
- callingPackage, "getDeviceId")) {
+ callingPackage, callingFeatureId, "getDeviceId")) {
return null;
}
@@ -5779,9 +6421,9 @@
@Override
public int getSubIdForPhoneAccountHandle(
- PhoneAccountHandle phoneAccountHandle, String callingPackage) {
+ PhoneAccountHandle phoneAccountHandle, String callingPackage, String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, getDefaultSubscription(),
- callingPackage, "getSubIdForPhoneAccountHandle")) {
+ callingPackage, callingFeatureId, "getSubIdForPhoneAccountHandle")) {
throw new SecurityException("Requires READ_PHONE_STATE permission.");
}
final long identity = Binder.clearCallingIdentity();
@@ -5915,7 +6557,7 @@
final long identity = Binder.clearCallingIdentity();
try {
final SubscriptionInfo info = mSubscriptionController.getActiveSubscriptionInfo(subId,
- phone.getContext().getOpPackageName());
+ phone.getContext().getOpPackageName(), null);
if (info == null) {
log("getSimLocaleForSubscriber, inactive subId: " + subId);
return null;
@@ -5939,7 +6581,7 @@
// exact locale (e.g. fr_FR = French/France). So, if the locale returned from
// the SIM and carrier preferences does not include a country we add the country
// determined from the SIM MCC to provide an exact locale.
- final Locale mccLocale = MccTable.getLocaleFromMcc(mApp, mcc, simLanguage);
+ final Locale mccLocale = LocaleUtils.getLocaleFromMcc(mApp, mcc, simLanguage);
if (mccLocale != null) {
if (DBG) log("No locale from SIM, using mcc locale:" + mccLocale);
return mccLocale.toLanguageTag();
@@ -5953,18 +6595,20 @@
}
private List<SubscriptionInfo> getAllSubscriptionInfoList() {
- return mSubscriptionController.getAllSubInfoList(mApp.getOpPackageName());
+ return mSubscriptionController.getAllSubInfoList(mApp.getOpPackageName(),
+ null);
}
/**
* NOTE: this method assumes permission checks are done and caller identity has been cleared.
*/
private List<SubscriptionInfo> getActiveSubscriptionInfoListPrivileged() {
- return mSubscriptionController.getActiveSubscriptionInfoList(mApp.getOpPackageName());
+ return mSubscriptionController.getActiveSubscriptionInfoList(mApp.getOpPackageName(),
+ null);
}
private final ModemActivityInfo mLastModemActivityInfo =
- new ModemActivityInfo(0, 0, 0, new int[0], 0, 0);
+ new ModemActivityInfo(0, 0, 0, new int[0], 0);
/**
* Responds to the ResultReceiver with the {@link android.telephony.ModemActivityInfo} object
@@ -5981,38 +6625,7 @@
final long identity = Binder.clearCallingIdentity();
try {
- ModemActivityInfo ret = null;
- synchronized (mLastModemActivityInfo) {
- ModemActivityInfo info = (ModemActivityInfo) sendRequest(
- CMD_GET_MODEM_ACTIVITY_INFO,
- null, workSource);
- if (isModemActivityInfoValid(info)) {
- int[] mergedTxTimeMs = new int[ModemActivityInfo.TX_POWER_LEVELS];
- for (int i = 0; i < mergedTxTimeMs.length; i++) {
- mergedTxTimeMs[i] = info.getTxTimeMillis()[i]
- + mLastModemActivityInfo.getTxTimeMillis()[i];
- }
- mLastModemActivityInfo.setTimestamp(info.getTimestamp());
- mLastModemActivityInfo.setSleepTimeMillis(info.getSleepTimeMillis()
- + mLastModemActivityInfo.getSleepTimeMillis());
- mLastModemActivityInfo.setIdleTimeMillis(
- info.getIdleTimeMillis() + mLastModemActivityInfo.getIdleTimeMillis());
- mLastModemActivityInfo.setTxTimeMillis(mergedTxTimeMs);
- mLastModemActivityInfo.setRxTimeMillis(
- info.getRxTimeMillis() + mLastModemActivityInfo.getRxTimeMillis());
- mLastModemActivityInfo.setEnergyUsed(
- info.getEnergyUsed() + mLastModemActivityInfo.getEnergyUsed());
- }
- ret = new ModemActivityInfo(mLastModemActivityInfo.getTimestamp(),
- mLastModemActivityInfo.getSleepTimeMillis(),
- mLastModemActivityInfo.getIdleTimeMillis(),
- mLastModemActivityInfo.getTxTimeMillis(),
- mLastModemActivityInfo.getRxTimeMillis(),
- mLastModemActivityInfo.getEnergyUsed());
- }
- Bundle bundle = new Bundle();
- bundle.putParcelable(TelephonyManager.MODEM_ACTIVITY_RESULT_KEY, ret);
- result.send(0, bundle);
+ sendRequestAsync(CMD_GET_MODEM_ACTIVITY_INFO, result, null, workSource);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -6027,13 +6640,14 @@
int activityDurationMs =
(int) (info.getTimestamp() - mLastModemActivityInfo.getTimestamp());
int totalTxTimeMs = 0;
- for (int i = 0; i < info.getTxTimeMillis().length; i++) {
- totalTxTimeMs += info.getTxTimeMillis()[i];
+ int[] txTimeMs = info.getTransmitTimeMillis();
+ for (int i = 0; i < info.getTransmitPowerInfo().size(); i++) {
+ totalTxTimeMs += txTimeMs[i];
}
return (info.isValid()
&& (info.getSleepTimeMillis() <= activityDurationMs)
&& (info.getIdleTimeMillis() <= activityDurationMs)
- && (info.getRxTimeMillis() <= activityDurationMs)
+ && (info.getReceiveTimeMillis() <= activityDurationMs)
&& (totalTxTimeMs <= activityDurationMs));
}
@@ -6042,9 +6656,10 @@
* Returns the service state information on specified subscription.
*/
@Override
- public ServiceState getServiceStateForSubscriber(int subId, String callingPackage) {
+ public ServiceState getServiceStateForSubscriber(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getServiceStateForSubscriber")) {
+ mApp, subId, callingPackage, callingFeatureId, "getServiceStateForSubscriber")) {
return null;
}
@@ -6052,6 +6667,7 @@
LocationAccessPolicy.checkLocationPermission(mApp,
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setCallingPid(Binder.getCallingPid())
.setCallingUid(Binder.getCallingUid())
.setMethod("getServiceStateForSubscriber")
@@ -6063,6 +6679,7 @@
LocationAccessPolicy.checkLocationPermission(mApp,
new LocationAccessPolicy.LocationPermissionQuery.Builder()
.setCallingPackage(callingPackage)
+ .setCallingFeatureId(callingFeatureId)
.setCallingPid(Binder.getCallingPid())
.setCallingUid(Binder.getCallingUid())
.setMethod("getServiceStateForSubscriber")
@@ -6087,8 +6704,8 @@
// Scrub out the location info in ServiceState depending on what level of access
// the caller has.
if (hasFinePermission) return ss;
- if (hasCoarsePermission) return ss.sanitizeLocationInfo(false);
- return ss.sanitizeLocationInfo(true);
+ if (hasCoarsePermission) return ss.createLocationInfoSanitizedCopy(false);
+ return ss.createLocationInfoSanitizedCopy(true);
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -6539,33 +7156,6 @@
}
/**
- * Get aggregated video call data usage since boot.
- *
- * @param perUidStats True if requesting data usage per uid, otherwise overall usage.
- * @return Snapshot of video call data usage
- * {@hide}
- */
- @Override
- public NetworkStats getVtDataUsage(int subId, boolean perUidStats) {
- mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_NETWORK_USAGE_HISTORY,
- null);
-
- final long identity = Binder.clearCallingIdentity();
- try {
- // NetworkStatsService keeps tracking the active network interface and identity. It
- // records the delta with the corresponding network identity.
- // We just return the total video call data usage snapshot since boot.
- Phone phone = getPhone(subId);
- if (phone != null) {
- return phone.getVtDataUsage(perUidStats);
- }
- return null;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
- /**
* Policy control of data connection. Usually used when data limit is passed.
* @param enabled True if enabling the data, otherwise disabling.
* @param subId Subscription index
@@ -6592,9 +7182,10 @@
* @hide
*/
@Override
- public List<ClientRequestStats> getClientRequestStats(String callingPackage, int subId) {
+ public List<ClientRequestStats> getClientRequestStats(String callingPackage,
+ String callingFeatureId, int subId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getClientRequestStats")) {
+ mApp, subId, callingPackage, callingFeatureId, "getClientRequestStats")) {
return null;
}
Phone phone = getPhone(subId);
@@ -6705,14 +7296,15 @@
* Get the current modem radio state for the given slot.
* @param slotIndex slot index.
* @param callingPackage the name of the package making the call.
+ * @param callingFeatureId The feature in the package.
* @return the current radio power state from the modem
*/
@Override
- public int getRadioPowerState(int slotIndex, String callingPackage) {
+ public int getRadioPowerState(int slotIndex, String callingPackage, String callingFeatureId) {
Phone phone = PhoneFactory.getPhone(slotIndex);
if (phone != null) {
- if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, phone.getSubId(), callingPackage, "getRadioPowerState")) {
+ if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp, phone.getSubId(),
+ callingPackage, callingFeatureId, "getRadioPowerState")) {
return TelephonyManager.RADIO_POWER_UNAVAILABLE;
}
@@ -6786,7 +7378,8 @@
@Override
public boolean isManualNetworkSelectionAllowed(int subId) {
- TelephonyPermissions.enforeceCallingOrSelfReadPhoneStatePermissionOrCarrierPrivilege(
+ TelephonyPermissions
+ .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
mApp, subId, "isManualNetworkSelectionAllowed");
boolean isAllowed = true;
@@ -6942,23 +7535,6 @@
}
}
- @Override
- public void setRadioIndicationUpdateMode(int subId, int filters, int mode) {
- enforceModifyPermission();
- final Phone phone = getPhone(subId);
- if (phone == null) {
- loge("setRadioIndicationUpdateMode fails with invalid subId: " + subId);
- return;
- }
-
- final long identity = Binder.clearCallingIdentity();
- try {
- phone.setRadioIndicationUpdateMode(filters, mode);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
-
/**
* A test API to reload the UICC profile.
*
@@ -6994,8 +7570,7 @@
* Returns false if the mobile data is disabled by default, otherwise return true.
*/
private boolean getDefaultDataEnabled() {
- return "true".equalsIgnoreCase(
- SystemProperties.get(DEFAULT_MOBILE_DATA_PROPERTY_NAME, "true"));
+ return TelephonyProperties.mobile_data().orElse(true);
}
/**
@@ -7006,8 +7581,7 @@
private boolean getDefaultDataRoamingEnabled(int subId) {
final CarrierConfigManager configMgr = (CarrierConfigManager)
mApp.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- boolean isDataRoamingEnabled = "true".equalsIgnoreCase(
- SystemProperties.get(DEFAULT_DATA_ROAMING_PROPERTY_NAME, "false"));
+ boolean isDataRoamingEnabled = TelephonyProperties.data_roaming().orElse(true);
isDataRoamingEnabled |= configMgr.getConfigForSubId(subId).getBoolean(
CarrierConfigManager.KEY_CARRIER_DEFAULT_DATA_ROAMING_ENABLED_BOOL);
return isDataRoamingEnabled;
@@ -7018,11 +7592,12 @@
* not set, return {@link Phone#PREFERRED_NT_MODE}.
*/
private int getDefaultNetworkType(int subId) {
- return Integer.parseInt(
- TelephonyManager.getTelephonyProperty(
- mSubscriptionController.getPhoneId(subId),
- DEFAULT_NETWORK_MODE_PROPERTY_NAME,
- String.valueOf(Phone.PREFERRED_NT_MODE)));
+ List<Integer> list = TelephonyProperties.default_network();
+ int phoneId = mSubscriptionController.getPhoneId(subId);
+ if (phoneId >= 0 && phoneId < list.size() && list.get(phoneId) != null) {
+ return list.get(phoneId);
+ }
+ return Phone.PREFERRED_NT_MODE;
}
@Override
@@ -7062,9 +7637,11 @@
}
@Override
- public int getNumberOfModemsWithSimultaneousDataConnections(int subId, String callingPackage) {
+ public int getNumberOfModemsWithSimultaneousDataConnections(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "getNumberOfModemsWithSimultaneousDataConnections")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "getNumberOfModemsWithSimultaneousDataConnections")) {
return -1;
}
@@ -7078,7 +7655,8 @@
@Override
public int getCdmaRoamingMode(int subId) {
- TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+ TelephonyPermissions
+ .enforeceCallingOrSelfReadPrivilegedPhoneStatePermissionOrCarrierPrivilege(
mApp, subId, "getCdmaRoamingMode");
final long identity = Binder.clearCallingIdentity();
@@ -7117,9 +7695,10 @@
@Override
public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList(
- String callingPackage) {
+ String callingPackage, String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, getDefaultSubscription(), callingPackage, "getEmergencyNumberList")) {
+ mApp, getDefaultSubscription(), callingPackage, callingFeatureId,
+ "getEmergencyNumberList")) {
throw new SecurityException("Requires READ_PHONE_STATE permission.");
}
final long identity = Binder.clearCallingIdentity();
@@ -7245,7 +7824,7 @@
}
@Override
- public void updateTestOtaEmergencyNumberDbFilePath(String otaFilePath) {
+ public void updateOtaEmergencyNumberDbFilePath(ParcelFileDescriptor otaParcelFileDescriptor) {
enforceActiveEmergencySessionPermission();
final long identity = Binder.clearCallingIdentity();
@@ -7253,7 +7832,24 @@
for (Phone phone: PhoneFactory.getPhones()) {
EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker();
if (tracker != null) {
- tracker.updateTestOtaEmergencyNumberDbFilePath(otaFilePath);
+ tracker.updateOtaEmergencyNumberDbFilePath(otaParcelFileDescriptor);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
+ public void resetOtaEmergencyNumberDbFilePath() {
+ enforceActiveEmergencySessionPermission();
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ for (Phone phone: PhoneFactory.getPhones()) {
+ EmergencyNumberTracker tracker = phone.getEmergencyNumberTracker();
+ if (tracker != null) {
+ tracker.resetOtaEmergencyNumberDbFilePath();
}
}
} finally {
@@ -7305,12 +7901,14 @@
* Whether a modem stack is enabled or not.
*/
@Override
- public boolean isModemEnabledForSlot(int slotIndex, String callingPackage) {
+ public boolean isModemEnabledForSlot(int slotIndex, String callingPackage,
+ String callingFeatureId) {
Phone phone = PhoneFactory.getPhone(slotIndex);
if (phone == null) return false;
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, phone.getSubId(), callingPackage, "isModemEnabledForSlot")) {
+ mApp, phone.getSubId(), callingPackage, callingFeatureId,
+ "isModemEnabledForSlot")) {
throw new SecurityException("Requires READ_PHONE_STATE permission.");
}
@@ -7342,9 +7940,10 @@
@Override
@TelephonyManager.IsMultiSimSupportedResult
- public int isMultiSimSupported(String callingPackage) {
+ public int isMultiSimSupported(String callingPackage, String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(mApp,
- getDefaultPhone().getSubId(), callingPackage, "isMultiSimSupported")) {
+ getDefaultPhone().getSubId(), callingPackage, callingFeatureId,
+ "isMultiSimSupported")) {
return TelephonyManager.MULTISIM_NOT_SUPPORTED_BY_HARDWARE;
}
@@ -7445,9 +8044,11 @@
* Return value defaults to true.
*/
@Override
- public boolean doesSwitchMultiSimConfigTriggerReboot(int subId, String callingPackage) {
+ public boolean doesSwitchMultiSimConfigTriggerReboot(int subId, String callingPackage,
+ String callingFeatureId) {
if (!TelephonyPermissions.checkCallingOrSelfReadPhoneState(
- mApp, subId, callingPackage, "doesSwitchMultiSimConfigTriggerReboot")) {
+ mApp, subId, callingPackage, callingFeatureId,
+ "doesSwitchMultiSimConfigTriggerReboot")) {
return false;
}
final long identity = Binder.clearCallingIdentity();
@@ -7498,6 +8099,15 @@
}
/**
+ * Get the current calling package name.
+ * @return the current calling package name
+ */
+ @Override
+ public String getCurrentPackageName() {
+ return mApp.getPackageManager().getPackagesForUid(Binder.getCallingUid())[0];
+ }
+
+ /**
* Return whether data is enabled for certain APN type. This will tell if framework will accept
* corresponding network requests on a subId.
*
@@ -7505,7 +8115,7 @@
* 1) user data is turned on, or
* 2) APN is un-metered for this subscription, or
* 3) APN type is whitelisted. E.g. MMS is whitelisted if
- * {@link SubscriptionManager#setAlwaysAllowMmsData} is turned on.
+ * {@link TelephonyManager#setAlwaysAllowMmsData} is turned on.
*
* @return whether data is allowed for a apn type.
*
@@ -7546,10 +8156,59 @@
}
@Override
- public void enqueueSmsPickResult(String callingPackage, IIntegerConsumer pendingSubIdResult) {
+ public void setSystemSelectionChannels(List<RadioAccessSpecifier> specifiers,
+ int subscriptionId, IBooleanConsumer resultCallback) {
+ enforceModifyPermission();
+ long token = Binder.clearCallingIdentity();
+ try {
+ Phone phone = getPhone(subscriptionId);
+ if (phone == null) {
+ try {
+ if (resultCallback != null) {
+ resultCallback.accept(false);
+ }
+ } catch (RemoteException e) {
+ // ignore
+ }
+ return;
+ }
+ Pair<List<RadioAccessSpecifier>, Consumer<Boolean>> argument =
+ Pair.create(specifiers, (x) -> {
+ try {
+ if (resultCallback != null) {
+ resultCallback.accept(x);
+ }
+ } catch (RemoteException e) {
+ // ignore
+ }
+ });
+ sendRequestAsync(CMD_SET_SYSTEM_SELECTION_CHANNELS, argument, phone, null);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public boolean isMvnoMatched(int subId, int mvnoType, @NonNull String mvnoMatchData) {
+ IccRecords iccRecords = UiccController.getInstance().getIccRecords(
+ SubscriptionManager.getPhoneId(subId), UiccController.APP_FAM_3GPP);
+ if (iccRecords == null) {
+ Log.d(LOG_TAG, "isMvnoMatched# IccRecords is null");
+ return false;
+ }
+ return ApnSettingUtils.mvnoMatches(iccRecords, mvnoType, mvnoMatchData);
+ }
+
+ @Override
+ public void enqueueSmsPickResult(String callingPackage, String callingAttributionTag,
+ IIntegerConsumer pendingSubIdResult) {
+ if (callingPackage == null) {
+ callingPackage = getCurrentPackageName();
+ }
SmsPermissions permissions = new SmsPermissions(getDefaultPhone(), mApp,
(AppOpsManager) mApp.getSystemService(Context.APP_OPS_SERVICE));
- if (!permissions.checkCallingCanSendSms(callingPackage, "Sending message")) {
+ if (!permissions.checkCallingCanSendSms(callingPackage, callingAttributionTag,
+ "Sending message")) {
throw new SecurityException("Requires SEND_SMS permission to perform this operation");
}
PickSmsSubscriptionActivity.addPendingResult(pendingSubIdResult);
@@ -7618,6 +8277,22 @@
}
}
+ @Override
+ public boolean setAlwaysAllowMmsData(int subId, boolean alwaysAllow) {
+ enforceModifyPermission();
+
+ // Now that all security checks passes, perform the operation as ourselves.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Phone phone = getPhone(subId);
+ if (phone == null) return false;
+
+ return phone.getDataEnabledSettings().setAlwaysAllowMmsData(alwaysAllow);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
/**
* Updates whether conference event pacakge handling is enabled.
* @param isCepEnabled {@code true} if CEP handling is enabled (default), or {@code false}
@@ -7645,4 +8320,106 @@
Binder.restoreCallingIdentity(identity);
}
}
+
+ /**
+ * Notify that an RCS autoconfiguration XML file has been received for provisioning.
+ *
+ * @param config The XML file to be read. ASCII/UTF8 encoded text if not compressed.
+ * @param isCompressed The XML file is compressed in gzip format and must be decompressed
+ * before being read.
+ */
+ @Override
+ public void notifyRcsAutoConfigurationReceived(int subId, @NonNull byte[] config, boolean
+ isCompressed) {
+ TelephonyPermissions.enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
+ mApp, subId, "notifyRcsAutoConfigurationReceived");
+ try {
+ IImsConfig configBinder = getImsConfig(getSlotIndex(subId), ImsFeature.FEATURE_RCS);
+ if (configBinder == null) {
+ Rlog.e(LOG_TAG, "null result for getImsConfig");
+ } else {
+ configBinder.notifyRcsAutoConfigurationReceived(config, isCompressed);
+ }
+ } catch (RemoteException e) {
+ Rlog.e(LOG_TAG, "fail to getImsConfig " + e.getMessage());
+ }
+ }
+
+ @Override
+ public boolean isIccLockEnabled(int subId) {
+ enforceReadPrivilegedPermission("isIccLockEnabled");
+
+ // Now that all security checks passes, perform the operation as ourselves.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Phone phone = getPhone(subId);
+ if (phone != null && phone.getIccCard() != null) {
+ return phone.getIccCard().getIccLockEnabled();
+ } else {
+ return false;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Set the ICC pin lock enabled or disabled..
+ *
+ * @return Integer.MAX_VALUE if enable/disable IccLock successfully. If failed it will return
+ * 0 or a positive integer as the attempts remaining value.
+ *
+ */
+ @Override
+ public int setIccLockEnabled(int subId, boolean enabled, String password) {
+ enforceModifyPermission();
+
+ Phone phone = getPhone(subId);
+ if (phone == null) {
+ return 0;
+ }
+ // Now that all security checks passes, perform the operation as ourselves.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ int attemptsRemaining = (int) sendRequest(CMD_SET_ICC_LOCK_ENABLED,
+ new Pair<Boolean, String>(enabled, password), phone, null);
+ return attemptsRemaining;
+
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "setIccLockEnabled. Exception e =" + e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return 0;
+ }
+
+ /**
+ * Change the ICC password used in ICC pin lock.
+ *
+ * @return Integer.MAX_VALUE if enable/disable IccLock successfully. If failed it will return
+ * 0 or a positive integer as the attempts remaining value.
+ *
+ */
+ @Override
+ public int changeIccLockPassword(int subId, String oldPassword, String newPassword) {
+ enforceModifyPermission();
+
+ Phone phone = getPhone(subId);
+ if (phone == null) {
+ return 0;
+ }
+ // Now that all security checks passes, perform the operation as ourselves.
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ int attemptsRemaining = (int) sendRequest(CMD_CHANGE_ICC_LOCK_PASSWORD,
+ new Pair<String, String>(oldPassword, newPassword), phone, null);
+ return attemptsRemaining;
+
+ } catch (Exception e) {
+ Log.e(LOG_TAG, "changeIccLockPassword. Exception e =" + e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ return 0;
+ }
}
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index 9835ba1..20a818e 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -31,7 +31,7 @@
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.text.TextUtils;
import android.util.Log;
@@ -701,7 +701,7 @@
* {@code false} otherwise.
*/
public static boolean isPhoneAccountActive(SubscriptionManager sm, PhoneAccountHandle handle) {
- return sm.getActiveSubscriptionInfoForIccIndex(handle.getId()) != null;
+ return sm.getActiveSubscriptionInfoForIcc(handle.getId()) != null;
}
private static ComponentName getPstnConnectionServiceName() {
diff --git a/src/com/android/phone/ServiceStateProvider.java b/src/com/android/phone/ServiceStateProvider.java
new file mode 100644
index 0000000..a7d27d5
--- /dev/null
+++ b/src/com/android/phone/ServiceStateProvider.java
@@ -0,0 +1,566 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import static android.provider.Telephony.ServiceStateTable;
+import static android.provider.Telephony.ServiceStateTable.CONTENT_URI;
+import static android.provider.Telephony.ServiceStateTable.IS_MANUAL_NETWORK_SELECTION;
+import static android.provider.Telephony.ServiceStateTable.VOICE_REG_STATE;
+import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
+import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionIdAndField;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.net.Uri;
+import android.os.Parcel;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The class to provide base facility to access ServiceState related content,
+ * which is stored in a SQLite database.
+ */
+public class ServiceStateProvider extends ContentProvider {
+ private static final String TAG = "ServiceStateProvider";
+
+ public static final String AUTHORITY = ServiceStateTable.AUTHORITY;
+ public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+ /**
+ * The current service state.
+ *
+ * This is the entire {@link ServiceState} object in byte array.
+ *
+ * @hide
+ */
+ public static final String SERVICE_STATE = "service_state";
+
+ /**
+ * An integer value indicating the current data service state.
+ * <p>
+ * Valid values: {@link ServiceState#STATE_IN_SERVICE},
+ * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
+ * {@link ServiceState#STATE_POWER_OFF}.
+ * <p>
+ * This is the same as {@link ServiceState#getDataRegState()}.
+ * @hide
+ */
+ public static final String DATA_REG_STATE = "data_reg_state";
+
+ /**
+ * An integer value indicating the current voice roaming type.
+ * <p>
+ * This is the same as {@link ServiceState#getVoiceRoamingType()}.
+ * @hide
+ */
+ public static final String VOICE_ROAMING_TYPE = "voice_roaming_type";
+
+ /**
+ * An integer value indicating the current data roaming type.
+ * <p>
+ * This is the same as {@link ServiceState#getDataRoamingType()}.
+ * @hide
+ */
+ public static final String DATA_ROAMING_TYPE = "data_roaming_type";
+
+ /**
+ * The current registered voice network operator name in long alphanumeric format.
+ * <p>
+ * This is the same as {@link ServiceState#getOperatorAlphaLong()}.
+ * @hide
+ */
+ public static final String VOICE_OPERATOR_ALPHA_LONG = "voice_operator_alpha_long";
+
+ /**
+ * The current registered operator name in short alphanumeric format.
+ * <p>
+ * In GSM/UMTS, short format can be up to 8 characters long. The current registered voice
+ * network operator name in long alphanumeric format.
+ * <p>
+ * This is the same as {@link ServiceState#getOperatorAlphaShort()}.
+ * @hide
+ */
+ public static final String VOICE_OPERATOR_ALPHA_SHORT = "voice_operator_alpha_short";
+
+ /**
+ * The current registered operator numeric id.
+ * <p>
+ * In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
+ * network code.
+ * <p>
+ * This is the same as {@link ServiceState#getOperatorNumeric()}.
+ */
+ public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
+
+ /**
+ * The current registered data network operator name in long alphanumeric format.
+ * <p>
+ * This is the same as {@link ServiceState#getOperatorAlphaLong()}.
+ * @hide
+ */
+ public static final String DATA_OPERATOR_ALPHA_LONG = "data_operator_alpha_long";
+
+ /**
+ * The current registered data network operator name in short alphanumeric format.
+ * <p>
+ * This is the same as {@link ServiceState#getOperatorAlphaShort()}.
+ * @hide
+ */
+ public static final String DATA_OPERATOR_ALPHA_SHORT = "data_operator_alpha_short";
+
+ /**
+ * The current registered data network operator numeric id.
+ * <p>
+ * This is the same as {@link ServiceState#getOperatorNumeric()}.
+ * @hide
+ */
+ public static final String DATA_OPERATOR_NUMERIC = "data_operator_numeric";
+
+ /**
+ * This is the same as {@link ServiceState#getRilVoiceRadioTechnology()}.
+ * @hide
+ */
+ public static final String RIL_VOICE_RADIO_TECHNOLOGY = "ril_voice_radio_technology";
+
+ /**
+ * This is the same as {@link ServiceState#getRilDataRadioTechnology()}.
+ * @hide
+ */
+ public static final String RIL_DATA_RADIO_TECHNOLOGY = "ril_data_radio_technology";
+
+ /**
+ * This is the same as {@link ServiceState#getCssIndicator()}.
+ * @hide
+ */
+ public static final String CSS_INDICATOR = "css_indicator";
+
+ /**
+ * This is the same as {@link ServiceState#getCdmaNetworkId()}.
+ * @hide
+ */
+ public static final String NETWORK_ID = "network_id";
+
+ /**
+ * This is the same as {@link ServiceState#getCdmaSystemId()}.
+ * @hide
+ */
+ public static final String SYSTEM_ID = "system_id";
+
+ /**
+ * This is the same as {@link ServiceState#getCdmaRoamingIndicator()}.
+ * @hide
+ */
+ public static final String CDMA_ROAMING_INDICATOR = "cdma_roaming_indicator";
+
+ /**
+ * This is the same as {@link ServiceState#getCdmaDefaultRoamingIndicator()}.
+ * @hide
+ */
+ public static final String CDMA_DEFAULT_ROAMING_INDICATOR =
+ "cdma_default_roaming_indicator";
+
+ /**
+ * This is the same as {@link ServiceState#getCdmaEriIconIndex()}.
+ * @hide
+ */
+ public static final String CDMA_ERI_ICON_INDEX = "cdma_eri_icon_index";
+
+ /**
+ * This is the same as {@link ServiceState#getCdmaEriIconMode()}.
+ * @hide
+ */
+ public static final String CDMA_ERI_ICON_MODE = "cdma_eri_icon_mode";
+
+ /**
+ * This is the same as {@link ServiceState#isEmergencyOnly()}.
+ * @hide
+ */
+ public static final String IS_EMERGENCY_ONLY = "is_emergency_only";
+
+ /**
+ * This is the same as {@link ServiceState#getDataRoamingFromRegistration()}.
+ * @hide
+ */
+ public static final String IS_DATA_ROAMING_FROM_REGISTRATION =
+ "is_data_roaming_from_registration";
+
+ /**
+ * This is the same as {@link ServiceState#isUsingCarrierAggregation()}.
+ * @hide
+ */
+ public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
+
+ /**
+ * The current registered raw data network operator name in long alphanumeric format.
+ * <p>
+ * This is the same as {@link ServiceState#getOperatorAlphaLongRaw()}.
+ * @hide
+ */
+ public static final String OPERATOR_ALPHA_LONG_RAW = "operator_alpha_long_raw";
+
+ /**
+ * The current registered raw data network operator name in short alphanumeric format.
+ * <p>
+ * This is the same as {@link ServiceState#getOperatorAlphaShortRaw()}.
+ * @hide
+ */
+ public static final String OPERATOR_ALPHA_SHORT_RAW = "operator_alpha_short_raw";
+
+ private final HashMap<Integer, ServiceState> mServiceStates = new HashMap<>();
+ private static final String[] sColumns = {
+ VOICE_REG_STATE,
+ DATA_REG_STATE,
+ VOICE_ROAMING_TYPE,
+ DATA_ROAMING_TYPE,
+ VOICE_OPERATOR_ALPHA_LONG,
+ VOICE_OPERATOR_ALPHA_SHORT,
+ VOICE_OPERATOR_NUMERIC,
+ DATA_OPERATOR_ALPHA_LONG,
+ DATA_OPERATOR_ALPHA_SHORT,
+ DATA_OPERATOR_NUMERIC,
+ IS_MANUAL_NETWORK_SELECTION,
+ RIL_VOICE_RADIO_TECHNOLOGY,
+ RIL_DATA_RADIO_TECHNOLOGY,
+ CSS_INDICATOR,
+ NETWORK_ID,
+ SYSTEM_ID,
+ CDMA_ROAMING_INDICATOR,
+ CDMA_DEFAULT_ROAMING_INDICATOR,
+ CDMA_ERI_ICON_INDEX,
+ CDMA_ERI_ICON_MODE,
+ IS_EMERGENCY_ONLY,
+ IS_USING_CARRIER_AGGREGATION,
+ OPERATOR_ALPHA_LONG_RAW,
+ OPERATOR_ALPHA_SHORT_RAW,
+ };
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ /**
+ * Returns the {@link ServiceState} information on specified subscription.
+ *
+ * @param subId whose subscriber id is returned
+ * @return the {@link ServiceState} information on specified subscription.
+ */
+ @VisibleForTesting
+ public ServiceState getServiceState(int subId) {
+ return mServiceStates.get(subId);
+ }
+
+ /**
+ * Returns the system's default subscription id.
+ *
+ * @return the "system" default subscription id.
+ */
+ @VisibleForTesting
+ public int getDefaultSubId() {
+ return SubscriptionManager.getDefaultSubscriptionId();
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ if (isPathPrefixMatch(uri, CONTENT_URI)) {
+ // Parse the subId
+ int subId = 0;
+ try {
+ subId = Integer.parseInt(uri.getLastPathSegment());
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "insert: no subId provided in uri");
+ throw e;
+ }
+ Log.d(TAG, "subId=" + subId);
+
+ // handle DEFAULT_SUBSCRIPTION_ID
+ if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+ subId = getDefaultSubId();
+ }
+
+ final Parcel p = Parcel.obtain();
+ final byte[] rawBytes = values.getAsByteArray(SERVICE_STATE);
+ p.unmarshall(rawBytes, 0, rawBytes.length);
+ p.setDataPosition(0);
+
+ // create the new service state
+ final ServiceState newSS = ServiceState.CREATOR.createFromParcel(p);
+
+ // notify listeners
+ // if ss is null (e.g. first service state update) we will notify for all fields
+ ServiceState ss = getServiceState(subId);
+ notifyChangeForSubIdAndField(getContext(), ss, newSS, subId);
+ notifyChangeForSubId(getContext(), ss, newSS, subId);
+
+ // store the new service state
+ mServiceStates.put(subId, newSS);
+ return uri;
+ }
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ throw new RuntimeException("Not supported");
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ throw new RuntimeException("Not supported");
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ throw new RuntimeException("Not supported");
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ if (!isPathPrefixMatch(uri, CONTENT_URI)) {
+ throw new IllegalArgumentException("Invalid URI: " + uri);
+ } else {
+ // Parse the subId
+ int subId = 0;
+ try {
+ subId = Integer.parseInt(uri.getLastPathSegment());
+ } catch (NumberFormatException e) {
+ Log.d(TAG, "query: no subId provided in uri, using default.");
+ subId = getDefaultSubId();
+ }
+ Log.d(TAG, "subId=" + subId);
+
+ // handle DEFAULT_SUBSCRIPTION_ID
+ if (subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
+ subId = getDefaultSubId();
+ }
+
+ // Get the service state
+ ServiceState ss = getServiceState(subId);
+ if (ss == null) {
+ Log.d(TAG, "returning null");
+ return null;
+ }
+
+ // Build the result
+ final int voice_reg_state = ss.getState();
+ final int data_reg_state = ss.getDataRegistrationState();
+ final int voice_roaming_type = ss.getVoiceRoamingType();
+ final int data_roaming_type = ss.getDataRoamingType();
+ final String voice_operator_alpha_long = ss.getOperatorAlphaLong();
+ final String voice_operator_alpha_short = ss.getOperatorAlphaShort();
+ final String voice_operator_numeric = ss.getOperatorNumeric();
+ final String data_operator_alpha_long = ss.getOperatorAlphaLong();
+ final String data_operator_alpha_short = ss.getOperatorAlphaShort();
+ final String data_operator_numeric = ss.getOperatorNumeric();
+ final int is_manual_network_selection = (ss.getIsManualSelection()) ? 1 : 0;
+ final int ril_voice_radio_technology = ss.getRilVoiceRadioTechnology();
+ final int ril_data_radio_technology = ss.getRilDataRadioTechnology();
+ final int css_indicator = ss.getCssIndicator();
+ final int network_id = ss.getCdmaNetworkId();
+ final int system_id = ss.getCdmaSystemId();
+ final int cdma_roaming_indicator = ss.getCdmaRoamingIndicator();
+ final int cdma_default_roaming_indicator = ss.getCdmaDefaultRoamingIndicator();
+ final int cdma_eri_icon_index = ss.getCdmaEriIconIndex();
+ final int cdma_eri_icon_mode = ss.getCdmaEriIconMode();
+ final int is_emergency_only = (ss.isEmergencyOnly()) ? 1 : 0;
+ final int is_using_carrier_aggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0;
+ final String operator_alpha_long_raw = ss.getOperatorAlphaLongRaw();
+ final String operator_alpha_short_raw = ss.getOperatorAlphaShortRaw();
+
+ return buildSingleRowResult(projection, sColumns, new Object[] {
+ voice_reg_state,
+ data_reg_state,
+ voice_roaming_type,
+ data_roaming_type,
+ voice_operator_alpha_long,
+ voice_operator_alpha_short,
+ voice_operator_numeric,
+ data_operator_alpha_long,
+ data_operator_alpha_short,
+ data_operator_numeric,
+ is_manual_network_selection,
+ ril_voice_radio_technology,
+ ril_data_radio_technology,
+ css_indicator,
+ network_id,
+ system_id,
+ cdma_roaming_indicator,
+ cdma_default_roaming_indicator,
+ cdma_eri_icon_index,
+ cdma_eri_icon_mode,
+ is_emergency_only,
+ is_using_carrier_aggregation,
+ operator_alpha_long_raw,
+ operator_alpha_short_raw,
+ });
+ }
+ }
+
+ private static Cursor buildSingleRowResult(String[] projection, String[] availableColumns,
+ Object[] data) {
+ if (projection == null) {
+ projection = availableColumns;
+ }
+ final MatrixCursor c = new MatrixCursor(projection, 1);
+ final RowBuilder row = c.newRow();
+ for (int i = 0; i < c.getColumnCount(); i++) {
+ final String columnName = c.getColumnName(i);
+ boolean found = false;
+ for (int j = 0; j < availableColumns.length; j++) {
+ if (availableColumns[j].equals(columnName)) {
+ row.add(data[j]);
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ throw new IllegalArgumentException("Invalid column " + projection[i]);
+ }
+ }
+ return c;
+ }
+
+ /**
+ * Notify interested apps that certain fields of the ServiceState have changed.
+ *
+ * Apps which want to wake when specific fields change can use
+ * JobScheduler's TriggerContentUri. This replaces the waking functionality of the implicit
+ * broadcast of ACTION_SERVICE_STATE_CHANGED for apps targeting version O.
+ *
+ * We will only notify for certain fields. This is an intentional change from the behavior of
+ * the broadcast. Listeners will be notified when the voice or data registration state or
+ * roaming type changes.
+ */
+ @VisibleForTesting
+ public static void notifyChangeForSubIdAndField(Context context, ServiceState oldSS,
+ ServiceState newSS, int subId) {
+ final boolean firstUpdate = (oldSS == null) ? true : false;
+
+ // for every field, if the field has changed values, notify via the provider
+ if (firstUpdate || voiceRegStateChanged(oldSS, newSS)) {
+ context.getContentResolver().notifyChange(
+ getUriForSubscriptionIdAndField(subId, VOICE_REG_STATE),
+ /* observer= */ null, /* syncToNetwork= */ false);
+ }
+ if (firstUpdate || dataRegStateChanged(oldSS, newSS)) {
+ context.getContentResolver().notifyChange(
+ getUriForSubscriptionIdAndField(subId, DATA_REG_STATE), null, false);
+ }
+ if (firstUpdate || voiceRoamingTypeChanged(oldSS, newSS)) {
+ context.getContentResolver().notifyChange(
+ getUriForSubscriptionIdAndField(subId, VOICE_ROAMING_TYPE), null, false);
+ }
+ if (firstUpdate || dataRoamingTypeChanged(oldSS, newSS)) {
+ context.getContentResolver().notifyChange(
+ getUriForSubscriptionIdAndField(subId, DATA_ROAMING_TYPE), null, false);
+ }
+ }
+
+ private static boolean voiceRegStateChanged(ServiceState oldSS, ServiceState newSS) {
+ return oldSS.getState() != newSS.getState();
+ }
+
+ private static boolean dataRegStateChanged(ServiceState oldSS, ServiceState newSS) {
+ return oldSS.getDataRegistrationState() != newSS.getDataRegistrationState();
+ }
+
+ private static boolean voiceRoamingTypeChanged(ServiceState oldSS, ServiceState newSS) {
+ return oldSS.getVoiceRoamingType() != newSS.getVoiceRoamingType();
+ }
+
+ private static boolean dataRoamingTypeChanged(ServiceState oldSS, ServiceState newSS) {
+ return oldSS.getDataRoamingType() != newSS.getDataRoamingType();
+ }
+
+ /**
+ * Notify interested apps that the ServiceState has changed.
+ *
+ * Apps which want to wake when any field in the ServiceState has changed can use
+ * JobScheduler's TriggerContentUri. This replaces the waking functionality of the implicit
+ * broadcast of ACTION_SERVICE_STATE_CHANGED for apps targeting version O.
+ *
+ * We will only notify for certain fields. This is an intentional change from the behavior of
+ * the broadcast. Listeners will only be notified when the voice/data registration state or
+ * roaming type changes.
+ */
+ @VisibleForTesting
+ public static void notifyChangeForSubId(Context context, ServiceState oldSS, ServiceState newSS,
+ int subId) {
+ // if the voice or data registration or roaming state field has changed values, notify via
+ // the provider.
+ // If oldSS is null and newSS is not (e.g. first update of service state) this will also
+ // notify
+ if (oldSS == null || voiceRegStateChanged(oldSS, newSS) || dataRegStateChanged(oldSS, newSS)
+ || voiceRoamingTypeChanged(oldSS, newSS) || dataRoamingTypeChanged(oldSS, newSS)) {
+ context.getContentResolver().notifyChange(getUriForSubscriptionId(subId), null, false);
+ }
+ }
+
+ /**
+ * Test if this is a path prefix match against the given Uri. Verifies that
+ * scheme, authority, and atomic path segments match.
+ *
+ * Copied from frameworks/base/core/java/android/net/Uri.java
+ */
+ private boolean isPathPrefixMatch(Uri uriA, Uri uriB) {
+ if (!Objects.equals(uriA.getScheme(), uriB.getScheme())) return false;
+ if (!Objects.equals(uriA.getAuthority(), uriB.getAuthority())) return false;
+
+ List<String> segA = uriA.getPathSegments();
+ List<String> segB = uriB.getPathSegments();
+
+ final int size = segB.size();
+ if (segA.size() < size) return false;
+
+ for (int i = 0; i < size; i++) {
+ if (!Objects.equals(segA.get(i), segB.get(i))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance.
+ *
+ * @param state the ServiceState to convert into ContentValues
+ * @return the convertedContentValues instance
+ * @hide
+ */
+ public static ContentValues getContentValuesForServiceState(ServiceState state) {
+ ContentValues values = new ContentValues();
+ final Parcel p = Parcel.obtain();
+ state.writeToParcel(p, 0);
+ // Turn the parcel to byte array. Safe to do this because the content values were never
+ // written into a persistent storage. ServiceStateProvider keeps values in the memory.
+ values.put(SERVICE_STATE, p.marshall());
+ return values;
+ }
+}
diff --git a/src/com/android/phone/TelephonyShellCommand.java b/src/com/android/phone/TelephonyShellCommand.java
index 0806fd1..53b3356 100644
--- a/src/com/android/phone/TelephonyShellCommand.java
+++ b/src/com/android/phone/TelephonyShellCommand.java
@@ -26,6 +26,7 @@
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.feature.ImsFeature;
import android.util.Log;
import com.android.internal.telephony.ITelephony;
@@ -35,6 +36,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.TreeSet;
@@ -180,13 +182,15 @@
private void onHelpIms() {
PrintWriter pw = getOutPrintWriter();
pw.println("IMS Commands:");
- pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d) PACKAGE_NAME");
+ pw.println(" ims set-ims-service [-s SLOT_ID] (-c | -d | -f) PACKAGE_NAME");
pw.println(" Sets the ImsService defined in PACKAGE_NAME to to be the bound");
pw.println(" ImsService. Options are:");
pw.println(" -s: the slot ID that the ImsService should be bound for. If no option");
pw.println(" is specified, it will choose the default voice SIM slot.");
pw.println(" -c: Override the ImsService defined in the carrier configuration.");
pw.println(" -d: Override the ImsService defined in the device overlay.");
+ pw.println(" -f: Set the feature that this override if for, if no option is");
+ pw.println(" specified, the new package name will be used for all features.");
pw.println(" ims get-ims-service [-s SLOT_ID] [-c | -d]");
pw.println(" Gets the package name of the currently defined ImsService.");
pw.println(" Options are:");
@@ -194,6 +198,8 @@
pw.println(" is specified, it will choose the default voice SIM slot.");
pw.println(" -c: The ImsService defined as the carrier configured ImsService.");
pw.println(" -c: The ImsService defined as the device default ImsService.");
+ pw.println(" -f: The feature type that the query will be requested for. If none is");
+ pw.println(" specified, the returned package name will correspond to MMTEL.");
pw.println(" ims enable [-s SLOT_ID]");
pw.println(" enables IMS for the SIM slot specified, or for the default voice SIM slot");
pw.println(" if none is specified.");
@@ -444,6 +450,7 @@
PrintWriter errPw = getErrPrintWriter();
int slotId = getDefaultSlot();
Boolean isCarrierService = null;
+ List<Integer> featuresList = new ArrayList<>();
String opt;
while ((opt = getNextOption()) != null) {
@@ -465,6 +472,26 @@
isCarrierService = false;
break;
}
+ case "-f": {
+ String featureString = getNextArgRequired();
+ String[] features = featureString.split(",");
+ for (int i = 0; i < features.length; i++) {
+ try {
+ Integer result = Integer.parseInt(features[i]);
+ if (result < ImsFeature.FEATURE_EMERGENCY_MMTEL
+ || result >= ImsFeature.FEATURE_MAX) {
+ errPw.println("ims set-ims-service -f " + result
+ + " is an invalid feature.");
+ return -1;
+ }
+ featuresList.add(result);
+ } catch (NumberFormatException e) {
+ errPw.println("ims set-ims-service -f tried to parse " + features[i]
+ + " as an integer.");
+ return -1;
+ }
+ }
+ }
}
}
// Mandatory param, either -c or -d
@@ -479,16 +506,24 @@
if (packageName == null) {
packageName = "";
}
- boolean result = mInterface.setImsService(slotId, isCarrierService, packageName);
+ int[] featureArray = new int[featuresList.size()];
+ for (int i = 0; i < featuresList.size(); i++) {
+ featureArray[i] = featuresList.get(i);
+ }
+ boolean result = mInterface.setBoundImsServiceOverride(slotId, isCarrierService,
+ featureArray, packageName);
if (VDBG) {
Log.v(LOG_TAG, "ims set-ims-service -s " + slotId + " "
- + (isCarrierService ? "-c " : "-d ") + packageName + ", result=" + result);
+ + (isCarrierService ? "-c " : "-d ")
+ + "-f " + featuresList + " "
+ + packageName + ", result=" + result);
}
getOutPrintWriter().println(result);
} catch (RemoteException e) {
Log.w(LOG_TAG, "ims set-ims-service -s " + slotId + " "
- + (isCarrierService ? "-c " : "-d ") + packageName + ", error"
- + e.getMessage());
+ + (isCarrierService ? "-c " : "-d ")
+ + "-f " + featuresList + " "
+ + packageName + ", error" + e.getMessage());
errPw.println("Exception: " + e.getMessage());
return -1;
}
@@ -500,6 +535,7 @@
PrintWriter errPw = getErrPrintWriter();
int slotId = getDefaultSlot();
Boolean isCarrierService = null;
+ Integer featureType = ImsFeature.FEATURE_MMTEL;
String opt;
while ((opt = getNextOption()) != null) {
@@ -521,23 +557,38 @@
isCarrierService = false;
break;
}
+ case "-f": {
+ try {
+ featureType = Integer.parseInt(getNextArg());
+ } catch (NumberFormatException e) {
+ errPw.println("ims get-ims-service -f requires valid integer as feature.");
+ return -1;
+ }
+ if (featureType < ImsFeature.FEATURE_EMERGENCY_MMTEL
+ || featureType >= ImsFeature.FEATURE_MAX) {
+ errPw.println("ims get-ims-service -f invalid feature.");
+ return -1;
+ }
+ }
}
}
// Mandatory param, either -c or -d
if (isCarrierService == null) {
- errPw.println("ims set-ims-service requires either \"-c\" or \"-d\" to be set.");
+ errPw.println("ims get-ims-service requires either \"-c\" or \"-d\" to be set.");
return -1;
}
String result;
try {
- result = mInterface.getImsService(slotId, isCarrierService);
+ result = mInterface.getBoundImsServicePackage(slotId, isCarrierService, featureType);
} catch (RemoteException e) {
return -1;
}
if (VDBG) {
Log.v(LOG_TAG, "ims get-ims-service -s " + slotId + " "
- + (isCarrierService ? "-c " : "-d ") + ", returned: " + result);
+ + (isCarrierService ? "-c " : "-d ")
+ + (featureType != null ? ("-f " + featureType) : "") + " , returned: "
+ + result);
}
getOutPrintWriter().println(result);
return 0;
diff --git a/src/com/android/phone/TimeConsumingPreferenceActivity.java b/src/com/android/phone/TimeConsumingPreferenceActivity.java
index 8c5ae6d..3b5fe21 100644
--- a/src/com/android/phone/TimeConsumingPreferenceActivity.java
+++ b/src/com/android/phone/TimeConsumingPreferenceActivity.java
@@ -187,6 +187,11 @@
@Override
public void onError(Preference preference, int error) {
if (DBG) dumpState();
+ if (!preference.isEnabled()) {
+ Log.i(LOG_TAG, "onError, skipped duplicated error popup");
+ return;
+ }
+
Log.i(LOG_TAG, "onError, preference=" + preference.getKey() + ", error=" + error);
if (mIsForeground) {
diff --git a/src/com/android/phone/settings/AccessibilitySettingsFragment.java b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
index c9aa630..e31de64 100644
--- a/src/com/android/phone/settings/AccessibilitySettingsFragment.java
+++ b/src/com/android/phone/settings/AccessibilitySettingsFragment.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.media.AudioManager;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
@@ -64,12 +65,9 @@
// support multi sim configuration.
TelephonyManager telephonyManager =
(TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
- final boolean isVolteTtySupported = getVolteTtySupported();
- final boolean isVolteCurrentlyEnabled =
- ImsManager.isVolteEnabledByPlatform(mContext);
- pref.setEnabled((isVolteTtySupported && isVolteCurrentlyEnabled &&
- !isVideoCallOrConferenceInProgress()) ||
- (telephonyManager.getCallState() == TelephonyManager.CALL_STATE_IDLE));
+ final boolean isVolteTtySupported = isVolteTtySupportedInAnySlot();
+ pref.setEnabled((isVolteTtySupported && !isVideoCallOrConferenceInProgress())
+ || (telephonyManager.getCallState() == TelephonyManager.CALL_STATE_IDLE));
}
}
};
@@ -166,17 +164,55 @@
int rttMode = mButtonRtt.isChecked() ? 1 : 0;
Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.RTT_CALLING_MODE,
rttMode);
+ // Update RTT config with IMS Manager if the always-on carrier config isn't set to true.
+ CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService(
+ Context.CARRIER_CONFIG_SERVICE);
+ for (int subId : SubscriptionController.getInstance().getActiveSubIdList(true)) {
+ if (!configManager.getConfigForSubId(subId).getBoolean(
+ CarrierConfigManager.KEY_IGNORE_RTT_MODE_SETTING_BOOL, false)) {
+ int phoneId = SubscriptionController.getInstance().getPhoneId(subId);
+ ImsManager imsManager = ImsManager.getInstance(getContext(), phoneId);
+ imsManager.setRttEnabled(mButtonRtt.isChecked());
+ }
+ }
return true;
}
return false;
}
- private boolean getVolteTtySupported() {
+ private boolean isVolteTtySupportedInAnySlot() {
+ final Phone[] phones = PhoneFactory.getPhones();
+ if (phones == null) {
+ if (DBG) Log.d(LOG_TAG, "isVolteTtySupportedInAnySlot: No phones found.");
+ return false;
+ }
+
CarrierConfigManager configManager =
(CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- return configManager.getConfig().getBoolean(
- CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL);
+ for (Phone phone : phones) {
+ // Check if this phone supports VoLTE.
+ ImsManager imsManager = ImsManager.getInstance(mContext, phone.getPhoneId());
+ boolean volteEnabled = false;
+ if (imsManager != null) {
+ volteEnabled = imsManager.isVolteEnabledByPlatform();
+ }
+
+ // Check if this phone suports VoLTE TTY.
+ boolean volteTtySupported = false;
+ PersistableBundle carrierConfig = configManager.getConfigForSubId(phone.getSubId());
+ if (carrierConfig != null) {
+ volteTtySupported = carrierConfig.getBoolean(
+ CarrierConfigManager.KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL);
+ }
+
+ if (volteEnabled && volteTtySupported) {
+ // VoLTE TTY is supported on this phone that also suports VoLTE.
+ return true;
+ }
+ }
+ // VoLTE TTY was not supported on any phone that also supports VoLTE.
+ return false;
}
private boolean isVideoCallOrConferenceInProgress() {
diff --git a/src/com/android/phone/settings/CallForwardInfoUtil.java b/src/com/android/phone/settings/CallForwardInfoUtil.java
index 1983fab..b963df8 100644
--- a/src/com/android/phone/settings/CallForwardInfoUtil.java
+++ b/src/com/android/phone/settings/CallForwardInfoUtil.java
@@ -82,6 +82,7 @@
phone.setCallForwardingOption(commandInterfaceCfAction,
info.reason,
info.number,
+ info.serviceClass,
info.timeSeconds,
message);
}
@@ -93,10 +94,12 @@
*/
public static CallForwardInfo getCallForwardInfo(CallForwardInfo[] infos, int reason) {
CallForwardInfo info = null;
- for (int i = 0 ; i < infos.length; i++) {
- if (isServiceClassVoice(infos[i])) {
- info = infos[i];
- break;
+ if (infos != null) {
+ for (int i = 0 ; i < infos.length; i++) {
+ if (isServiceClassVoice(infos[i])) {
+ info = infos[i];
+ break;
+ }
}
}
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index ce5b839..31b7a9e 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -111,28 +111,40 @@
private static final boolean IS_USER_BUILD = "user".equals(Build.TYPE);
private static final String[] PREFERRED_NETWORK_LABELS = {
- "WCDMA preferred",
+ "GSM/WCDMA preferred",
"GSM only",
"WCDMA only",
- "GSM auto (PRL)",
- "CDMA auto (PRL)",
+ "GSM/WCDMA auto (PRL)",
+ "CDMA/EvDo auto (PRL)",
"CDMA only",
"EvDo only",
- "Global auto (PRL)",
- "LTE/CDMA auto (PRL)",
- "LTE/UMTS auto (PRL)",
- "LTE/CDMA/UMTS auto (PRL)",
+ "CDMA/EvDo/GSM/WCDMA (PRL)",
+ "CDMA + LTE/EvDo (PRL)",
+ "GSM/WCDMA/LTE (PRL)",
+ "LTE/CDMA/EvDo/GSM/WCDMA (PRL)",
"LTE only",
"LTE/WCDMA",
- "TD-SCDMA only",
- "TD-SCDMA/WCDMA",
- "LTE/TD-SCDMA",
- "TD-SCDMA/GSM",
- "TD-SCDMA/UMTS",
- "LTE/TD-SCDMA/WCDMA",
- "LTE/TD-SCDMA/UMTS",
- "TD-SCDMA/CDMA/UMTS",
- "Global/TD-SCDMA",
+ "TDSCDMA only",
+ "TDSCDMA/WCDMA",
+ "LTE/TDSCDMA",
+ "TDSCDMA/GSM",
+ "LTE/TDSCDMA/GSM",
+ "TDSCDMA/GSM/WCDMA",
+ "LTE/TDSCDMA/WCDMA",
+ "LTE/TDSCDMA/GSM/WCDMA",
+ "TDSCDMA/CDMA/EvDo/GSM/WCDMA ",
+ "LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA",
+ "NR only",
+ "NR/LTE",
+ "NR/LTE/CDMA/EvDo",
+ "NR/LTE/GSM/WCDMA",
+ "NR/LTE/CDMA/EvDo/GSM/WCDMA",
+ "NR/LTE/WCDMA",
+ "NR/LTE/TDSCDMA",
+ "NR/LTE/TDSCDMA/GSM",
+ "NR/LTE/TDSCDMA/WCDMA",
+ "NR/LTE/TDSCDMA/GSM/WCDMA",
+ "NR/LTE/TDSCDMA/CDMA/EvDo/GSM/WCDMA",
"Unknown"
};
@@ -1437,8 +1449,18 @@
OnCheckedChangeListener mRadioPowerOnChangeListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- log("toggle radio power: currently " + (isRadioOn() ? "on" : "off"));
- mPhone.setRadioPower(isChecked);
+ // TODO: b/145681511. Within current design, radio power on all of the phones need
+ // to be controlled at the same time.
+ Phone[] phones = PhoneFactory.getPhones();
+ if (phones == null) {
+ return;
+ }
+ log("toggle radio power: phone*" + phones.length + " " + (isRadioOn() ? "on" : "off"));
+ for (int phoneIndex = 0; phoneIndex < phones.length; phoneIndex++) {
+ if (phones[phoneIndex] != null) {
+ phones[phoneIndex].setRadioPower(isChecked);
+ }
+ }
}
};
@@ -1706,7 +1728,7 @@
mQueuedWork.execute(new Runnable() {
public void run() {
mTelephonyManager.setOpportunisticNetworkState(state);
- mCbrsDataSwitch.setChecked(getCbrsDataState());
+ mHandler.post(() -> mCbrsDataSwitch.setChecked(getCbrsDataState()));
}
});
}
diff --git a/src/com/android/phone/settings/SuppServicesUiUtil.java b/src/com/android/phone/settings/SuppServicesUiUtil.java
index 4e9841f..4f1a79f 100644
--- a/src/com/android/phone/settings/SuppServicesUiUtil.java
+++ b/src/com/android/phone/settings/SuppServicesUiUtil.java
@@ -84,7 +84,7 @@
.create();
}
- private static String makeMessage(Context context, String preferenceKey, Phone phone) {
+ public static String makeMessage(Context context, String preferenceKey, Phone phone) {
String message = "";
int simSlot = (phone.getPhoneId() == 0) ? 1 : 2;
String suppServiceName = getSuppServiceName(context, preferenceKey);
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
index e18dc93..66b1af9 100644
--- a/src/com/android/phone/settings/VoicemailSettingsActivity.java
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -43,6 +43,7 @@
import android.widget.Toast;
import com.android.internal.telephony.CallForwardInfo;
+import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.util.NotificationChannelController;
@@ -733,6 +734,7 @@
for (int i = 0; i < mForwardingReadResults.length; i++) {
mPhone.getCallForwardingOption(
VoicemailProviderSettings.FORWARDING_SETTINGS_REASONS[i],
+ CommandsInterface.SERVICE_CLASS_VOICE,
mGetOptionComplete.obtainMessage(EVENT_FORWARDING_GET_COMPLETED, i, 0));
}
showDialogIfForeground(VoicemailDialogUtil.VM_FWD_READING_DIALOG);
diff --git a/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java b/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java
index 92baa97..8b17cfb 100644
--- a/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java
+++ b/src/com/android/phone/settings/fdn/DeleteFdnContactScreen.java
@@ -64,7 +64,8 @@
resolveIntent();
- authenticatePin2();
+ // Starts PIN2 authentication only for the first time.
+ if (icicle == null) authenticatePin2();
getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.delete_fdn_contact_screen);
diff --git a/src/com/android/phone/settings/fdn/EditFdnContactScreen.java b/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
index 0eda140..140cc74 100644
--- a/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
+++ b/src/com/android/phone/settings/fdn/EditFdnContactScreen.java
@@ -443,7 +443,7 @@
}
if (v == mNameField) {
- mNumberField.requestFocus();
+ mButton.requestFocus();
} else if (v == mNumberField) {
mButton.requestFocus();
} else if (v == mButton) {
diff --git a/src/com/android/phone/settings/fdn/EditPinPreference.java b/src/com/android/phone/settings/fdn/EditPinPreference.java
index 9596f39..a9d1948 100644
--- a/src/com/android/phone/settings/fdn/EditPinPreference.java
+++ b/src/com/android/phone/settings/fdn/EditPinPreference.java
@@ -23,8 +23,6 @@
import android.util.AttributeSet;
import android.view.View;
-import com.android.phone.R;
-
/**
* Class similar to the com.android.settings.EditPinPreference
* class, with a couple of modifications, including a different layout
@@ -62,27 +60,12 @@
super(context, attrs, defStyle);
}
- /**
- * Overridden to setup the correct dialog layout, as well as setting up
- * other properties for the pin / puk entry field.
- */
- @Override
- protected View onCreateDialogView() {
- // set the dialog layout
- setDialogLayoutResource(R.layout.pref_dialog_editpin);
-
- View dialog = super.onCreateDialogView();
-
- getEditText().setInputType(InputType.TYPE_CLASS_NUMBER |
- InputType.TYPE_NUMBER_VARIATION_PASSWORD);
-
- return dialog;
- }
-
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
+ getEditText().setInputType(InputType.TYPE_CLASS_NUMBER
+ | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
// If the layout does not contain an edittext, hide the buttons.
shouldHideButtons = (view.findViewById(android.R.id.edit) == null);
}
diff --git a/src/com/android/services/telephony/CdmaConference.java b/src/com/android/services/telephony/CdmaConference.java
old mode 100755
new mode 100644
index 693fd16..7458195
--- a/src/com/android/services/telephony/CdmaConference.java
+++ b/src/com/android/services/telephony/CdmaConference.java
@@ -17,6 +17,7 @@
package com.android.services.telephony;
import android.content.Context;
+import android.net.Uri;
import android.os.PersistableBundle;
import android.telecom.Connection;
import android.telecom.PhoneAccountHandle;
@@ -73,6 +74,22 @@
}
@Override
+ public void onAddConferenceParticipants(List<Uri> participants) {
+ Log.e(this, new Exception(), "Adding Conference Participants not supported " +
+ " for CDMA conference call.");
+ }
+
+ @Override
+ public void onAnswer(int videoState) {
+ Log.e(this, new Exception(), "Answer not supported for CDMA conference call.");
+ }
+
+ @Override
+ public void onReject() {
+ Log.e(this, new Exception(), "Reject not supported for CDMA conference call.");
+ }
+
+ @Override
public void onHold() {
Log.e(this, new Exception(), "Hold not supported for CDMA conference call.");
}
diff --git a/src/com/android/services/telephony/ConferenceParticipantConnection.java b/src/com/android/services/telephony/ConferenceParticipantConnection.java
index ed92e7f..b7ecd48 100644
--- a/src/com/android/services/telephony/ConferenceParticipantConnection.java
+++ b/src/com/android/services/telephony/ConferenceParticipantConnection.java
@@ -19,13 +19,13 @@
import android.net.Uri;
import android.telecom.Connection;
import android.telecom.DisconnectCause;
-import android.telephony.Rlog;
import android.telephony.SubscriptionInfo;
import android.text.TextUtils;
import com.android.ims.internal.ConferenceParticipant;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
+import com.android.telephony.Rlog;
/**
* Represents a participant in a conference call.
@@ -215,7 +215,7 @@
sb.append(" connectTime:");
sb.append(getConnectTimeMillis());
sb.append(" connectElapsedTime:");
- sb.append(getConnectElapsedTimeMillis());
+ sb.append(getConnectionStartElapsedRealtimeMillis());
sb.append("]");
return sb.toString();
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index 9e32f00..0da5dfc 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -847,17 +847,17 @@
case android.telephony.DisconnectCause.UNOBTAINABLE_NUMBER:
return ToneGenerator.TONE_SUP_ERROR;
+ case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY:
+ // Do not play any tones if disconnected because of a successful merge.
+ return ToneGenerator.TONE_UNKNOWN;
+
case android.telephony.DisconnectCause.ERROR_UNSPECIFIED:
case android.telephony.DisconnectCause.LOCAL:
case android.telephony.DisconnectCause.NORMAL:
case android.telephony.DisconnectCause.NORMAL_UNSPECIFIED:
case android.telephony.DisconnectCause.VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED:
- return ToneGenerator.TONE_PROP_PROMPT;
-
- case android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY:
- // Do not play any tones if disconnected because of a successful merge.
default:
- return ToneGenerator.TONE_UNKNOWN;
+ return ToneGenerator.TONE_PROP_PROMPT;
}
}
}
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 4c3f9c9..c11a1ca 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -30,7 +30,6 @@
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
import android.util.Pair;
import com.android.ims.internal.ConferenceParticipant;
@@ -42,6 +41,7 @@
import com.android.phone.PhoneGlobals;
import com.android.phone.PhoneUtils;
import com.android.phone.R;
+import com.android.telephony.Rlog;
import java.util.ArrayList;
import java.util.Arrays;
@@ -199,6 +199,18 @@
TelephonyConnection telephonyConnection = (TelephonyConnection) c;
handleConferenceParticipantsUpdate(telephonyConnection, participants);
}
+
+ /**
+ * Handles request to play a ringback tone.
+ *
+ * @param c The connection.
+ * @param ringback Whether the ringback tone is to be played.
+ */
+ @Override
+ public void onRingbackRequested(android.telecom.Connection c, boolean ringback) {
+ Log.d(this, "onRingbackRequested ringback %s", ringback ? "Y" : "N");
+ setRingbackRequested(ringback);
+ }
};
/**
@@ -224,6 +236,11 @@
private TelecomAccountRegistry mTelecomAccountRegistry;
/**
+ * The participant with which Adhoc Conference call is getting formed.
+ */
+ private List<Uri> mParticipants;
+
+ /**
* The known conference participant connections. The HashMap is keyed by a Pair containing
* the handle and endpoint Uris.
* Access to the hashmap is protected by the {@link #mUpdateSyncRoot}.
@@ -296,10 +313,10 @@
long connectTime = conferenceHost.getOriginalConnection().getConnectTime();
long connectElapsedTime = conferenceHost.getOriginalConnection().getConnectTimeReal();
setConnectionTime(connectTime);
- setConnectionStartElapsedRealTime(connectElapsedTime);
+ setConnectionStartElapsedRealtimeMillis(connectElapsedTime);
// Set the connectTime in the connection as well.
conferenceHost.setConnectTimeMillis(connectTime);
- conferenceHost.setConnectionStartElapsedRealTime(connectElapsedTime);
+ conferenceHost.setConnectionStartElapsedRealtimeMillis(connectElapsedTime);
mTelephonyConnectionService = telephonyConnectionService;
setConferenceHost(conferenceHost);
@@ -357,6 +374,10 @@
Connection.CAPABILITY_CAN_PAUSE_VIDEO,
mConferenceHost.getVideoPauseSupported() && isVideoCapable());
+ conferenceCapabilities = changeBitmask(conferenceCapabilities,
+ Connection.CAPABILITY_ADD_PARTICIPANT,
+ (capabilities & Connection.CAPABILITY_ADD_PARTICIPANT) != 0);
+
return conferenceCapabilities;
}
@@ -383,6 +404,10 @@
conferenceProperties = changeBitmask(conferenceProperties,
Connection.PROPERTY_REMOTELY_HOSTED, !isConferenceHost());
+ conferenceProperties = changeBitmask(conferenceProperties,
+ Connection.PROPERTY_IS_ADHOC_CONFERENCE,
+ (properties & Connection.PROPERTY_IS_ADHOC_CONFERENCE) != 0);
+
return conferenceProperties;
}
@@ -422,6 +447,26 @@
return VideoProfile.STATE_AUDIO_ONLY;
}
+ public Connection getConferenceHost() {
+ return mConferenceHost;
+ }
+
+ /**
+ * @return The address's to which this Connection is currently communicating.
+ */
+ public final List<Uri> getParticipants() {
+ return mParticipants;
+ }
+
+ /**
+ * Sets the value of the {@link #getParticipants()}.
+ *
+ * @param address The new address's.
+ */
+ public final void setParticipants(List<Uri> address) {
+ mParticipants = address;
+ }
+
/**
* Invoked when the Conference and all its {@link Connection}s should be disconnected.
* <p>
@@ -481,6 +526,41 @@
}
/**
+ * Supports adding participants to an existing conference call
+ *
+ * @param participants that are pulled to existing conference call
+ */
+ @Override
+ public void onAddConferenceParticipants(List<Uri> participants) {
+ if (mConferenceHost == null) {
+ return;
+ }
+ mConferenceHost.performAddConferenceParticipants(participants);
+ }
+
+ /**
+ * Invoked when the conference is answered.
+ */
+ @Override
+ public void onAnswer(int videoState) {
+ if (mConferenceHost == null) {
+ return;
+ }
+ mConferenceHost.performAnswer(videoState);
+ }
+
+ /**
+ * Invoked when the conference is rejected.
+ */
+ @Override
+ public void onReject() {
+ if (mConferenceHost == null) {
+ return;
+ }
+ mConferenceHost.performReject(android.telecom.Call.REJECT_REASON_DECLINED);
+ }
+
+ /**
* Invoked when the conference should be put on hold.
*/
@Override
@@ -678,7 +758,8 @@
setAddress(mConferenceHost.getAddress(), mConferenceHost.getAddressPresentation());
setCallerDisplayName(mConferenceHost.getCallerDisplayName(),
mConferenceHost.getCallerDisplayNamePresentation());
- setConnectionStartElapsedRealTime(mConferenceHost.getConnectElapsedTimeMillis());
+ setConnectionStartElapsedRealtimeMillis(
+ mConferenceHost.getConnectionStartElapsedRealtimeMillis());
setConnectionTime(mConferenceHost.getConnectTimeMillis());
}
@@ -838,7 +919,8 @@
+ "newParticipantcount=%d", oldParticipantCount, newParticipantCount);
// If the single party call emulation fature flag is enabled, we can potentially treat
// the conference as a single party call when there is just one participant.
- if (mFeatureFlagProxy.isUsingSinglePartyCallEmulation()) {
+ if (mFeatureFlagProxy.isUsingSinglePartyCallEmulation() &&
+ !mConferenceHost.isAdhocConferenceCall()) {
if (oldParticipantCount != 1 && newParticipantCount == 1) {
// If number of participants goes to 1, emulate a single party call.
startEmulatingSinglePartyCall();
@@ -895,7 +977,8 @@
Log.d(this,
"stopEmulatingSinglePartyCall: restored lone participant connect time");
loneParticipant.setConnectTimeMillis(getConnectionTime());
- loneParticipant.setConnectionStartElapsedRealTime(getConnectionStartElapsedRealTime());
+ loneParticipant.setConnectionStartElapsedRealtimeMillis(
+ getConnectionStartElapsedRealtimeMillis());
}
// Tell Telecom its a conference again.
@@ -935,7 +1018,8 @@
setAddress(entry.getAddress(), entry.getAddressPresentation());
setCallerDisplayName(entry.getCallerDisplayName(),
entry.getCallerDisplayNamePresentation());
- setConnectionStartElapsedRealTime(entry.getConnectElapsedTimeMillis());
+ setConnectionStartElapsedRealtimeMillis(
+ entry.getConnectionStartElapsedRealtimeMillis());
setConnectionTime(entry.getConnectTimeMillis());
mLoneParticipantIdentity = new Pair<>(entry.getUserEntity(), entry.getEndpoint());
@@ -979,10 +1063,11 @@
!isConferenceHost() /* isRemotelyHosted */);
if (participant.getConnectTime() == 0) {
connection.setConnectTimeMillis(parent.getConnectTimeMillis());
- connection.setConnectionStartElapsedRealTime(parent.getConnectElapsedTimeMillis());
+ connection.setConnectionStartElapsedRealtimeMillis(
+ parent.getConnectionStartElapsedRealtimeMillis());
} else {
connection.setConnectTimeMillis(participant.getConnectTime());
- connection.setConnectionStartElapsedRealTime(participant.getConnectElapsedTime());
+ connection.setConnectionStartElapsedRealtimeMillis(participant.getConnectElapsedTime());
}
// Indicate whether this is an MT or MO call to Telecom; the participant has the cached
// data from the time of merge.
@@ -1148,7 +1233,8 @@
c.updateState();
// Copy the connect time from the conferenceHost
c.setConnectTimeMillis(mConferenceHost.getConnectTimeMillis());
- c.setConnectionStartElapsedRealTime(mConferenceHost.getConnectElapsedTimeMillis());
+ c.setConnectionStartElapsedRealtimeMillis(
+ mConferenceHost.getConnectionStartElapsedRealtimeMillis());
mTelephonyConnectionService.addExistingConnection(phoneAccountHandle, c);
mTelephonyConnectionService.addConnectionToConferenceController(c);
} // CDMA case not applicable for SRVCC
@@ -1173,11 +1259,13 @@
switch (state) {
case Connection.STATE_INITIALIZING:
case Connection.STATE_NEW:
- case Connection.STATE_RINGING:
// No-op -- not applicable.
break;
+ case Connection.STATE_RINGING:
+ setConferenceOnRinging();
+ break;
case Connection.STATE_DIALING:
- setDialing();
+ setConferenceOnDialing();
break;
case Connection.STATE_DISCONNECTED:
DisconnectCause disconnectCause;
@@ -1198,10 +1286,10 @@
destroyTelephonyConference();
break;
case Connection.STATE_ACTIVE:
- setActive();
+ setConferenceOnActive();
break;
case Connection.STATE_HOLDING:
- setOnHold();
+ setConferenceOnHold();
break;
}
}
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 1e10055..8789ba8 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -22,7 +22,7 @@
import android.telecom.ConnectionService;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccountHandle;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
@@ -52,8 +52,19 @@
Log.v(ImsConferenceController.class, "onDestroyed: %s", conference);
}
+ if (conference instanceof ImsConference) {
+ // Ims Conference call ended, so UE may now have the ability to initiate
+ // an Adhoc Conference call. Hence, try enabling adhoc conference capability
+ mTelecomAccountRegistry.refreshAdhocConference(true);
+ }
mImsConferences.remove(conference);
}
+
+ @Override
+ public void onStateChanged(Conference conference, int oldState, int newState) {
+ Log.v(this, "onStateChanged: Conference = " + conference);
+ recalculateConferenceable();
+ }
};
private final TelephonyConnection.TelephonyConnectionListener mTelephonyConnectionListener =
@@ -101,10 +112,11 @@
private final ArrayList<TelephonyConnection> mTelephonyConnections = new ArrayList<>();
/**
- * List of known {@link ImsConference}s. Realistically there will only ever be a single
- * concurrent IMS conference.
+ * List of known {@link ImsConference}s. There can be upto maximum two Ims conference calls.
+ * One conference call can be a host conference call and another conference call formed as a
+ * result of accepting incoming conference call.
*/
- private final ArrayList<ImsConference> mImsConferences = new ArrayList<>(1);
+ private final ArrayList<ImsConference> mImsConferences = new ArrayList<>(2);
private TelecomAccountRegistry mTelecomAccountRegistry;
@@ -122,6 +134,17 @@
mFeatureFlagProxy = featureFlagProxy;
}
+ void addConference(ImsConference conference) {
+ if (mImsConferences.contains(conference)) {
+ // Adding a duplicate realistically shouldn't happen.
+ Log.w(this, "addConference - conference already tracked; conference=%s", conference);
+ return;
+ }
+ mImsConferences.add(conference);
+ conference.addTelephonyConferenceListener(mConferenceListener);
+ recalculateConferenceable();
+ }
+
/**
* Adds a new connection to the IMS conference controller.
*
@@ -250,6 +273,11 @@
continue;
}
+ // Since UE cannot host two conference calls, remove the ability to initiate
+ // another conference call as there already exists a conference call, which
+ // is hosted on this device.
+ mTelecomAccountRegistry.refreshAdhocConference(false);
+
switch (conference.getState()) {
case Connection.STATE_ACTIVE:
//fall through
@@ -360,6 +388,10 @@
Log.v(this, "Start new ImsConference - connection: %s", connection);
}
+ if (connection.isAdhocConferenceCall()) {
+ Log.w(this, "start new ImsConference - control should never come here");
+ return;
+ }
// Make a clone of the connection which will become the Ims conference host connection.
// This is necessary since the Connection Service does not support removing a connection
// from Telecom. Instead we create a new instance and remove the old one from telecom.
diff --git a/src/com/android/services/telephony/MmiCodeUtil.java b/src/com/android/services/telephony/MmiCodeUtil.java
new file mode 100644
index 0000000..d208ec3
--- /dev/null
+++ b/src/com/android/services/telephony/MmiCodeUtil.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public final class MmiCodeUtil {
+ //***** Constants
+
+ // Supp Service codes from TS 22.030 Annex B
+
+ //Called line presentation
+ static final String SC_CLIP = "30";
+ static final String SC_CLIR = "31";
+
+ // Call Forwarding
+ static final String SC_CFU = "21";
+ static final String SC_CFB = "67";
+ static final String SC_CFNRy = "61";
+ static final String SC_CFNR = "62";
+
+ static final String SC_CF_All = "002";
+ static final String SC_CF_All_Conditional = "004";
+
+ // Call Waiting
+ static final String SC_WAIT = "43";
+
+ // Call Barring
+ static final String SC_BAOC = "33";
+ static final String SC_BAOIC = "331";
+ static final String SC_BAOICxH = "332";
+ static final String SC_BAIC = "35";
+ static final String SC_BAICr = "351";
+
+ static final String SC_BA_ALL = "330";
+ static final String SC_BA_MO = "333";
+ static final String SC_BA_MT = "353";
+
+ // Supp Service Password registration
+ static final String SC_PWD = "03";
+
+ // PIN/PIN2/PUK/PUK2
+ static final String SC_PIN = "04";
+ static final String SC_PIN2 = "042";
+ static final String SC_PUK = "05";
+ static final String SC_PUK2 = "052";
+
+ // See TS 22.030 6.5.2 "Structure of the MMI"
+
+ static Pattern sPatternSuppService = Pattern.compile(
+ "((\\*|#|\\*#|\\*\\*|##)(\\d{2,3})(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*))?)?)?)?#)(.*)");
+/* 1 2 3 4 5 6 7 8 9 10 11 12
+
+ 1 = Full string up to and including #
+ 2 = action (activation/interrogation/registration/erasure)
+ 3 = service code
+ 5 = SIA
+ 7 = SIB
+ 9 = SIC
+ 10 = dialing number
+*/
+
+ static final int MATCH_GROUP_SERVICE_CODE = 3;
+
+ public static final String BUTTON_CLIR_KEY = "button_clir_key";
+ public static final String BUTTON_CW_KEY = "button_cw_key";
+ public static final String CALL_FORWARDING_KEY = "call_forwarding_key";
+ public static final String CALL_BARRING_KEY = "call_barring_key";
+
+ //***** Public Class methods
+ public static String getMmiServiceCode(String dialString) {
+ Matcher m;
+ String ret = null;
+
+ m = sPatternSuppService.matcher(dialString);
+
+ if (m.matches()) {
+ ret = makeEmptyNull(m.group(MATCH_GROUP_SERVICE_CODE));
+ }
+
+ return ret;
+ }
+
+ private static String makeEmptyNull(String s) {
+ if (s != null && s.length() == 0) return null;
+
+ return s;
+ }
+
+ static boolean isServiceCodeCallForwarding(String sc) {
+ return sc != null &&
+ (sc.equals(SC_CFU)
+ || sc.equals(SC_CFB) || sc.equals(SC_CFNRy)
+ || sc.equals(SC_CFNR) || sc.equals(SC_CF_All)
+ || sc.equals(SC_CF_All_Conditional));
+ }
+
+ static boolean isServiceCodeCallBarring(String sc) {
+ return sc != null &&
+ (sc.equals(SC_BAOC)
+ || sc.equals(SC_BAOIC) || sc.equals(SC_BAOICxH)
+ || sc.equals(SC_BAIC) || sc.equals(SC_BAICr)
+ || sc.equals(SC_BA_ALL) || sc.equals(SC_BA_MO)
+ || sc.equals(SC_BA_MT));
+ }
+
+ static boolean isPinPukCommand(String sc) {
+ return sc != null && (sc.equals(SC_PIN) || sc.equals(SC_PIN2)
+ || sc.equals(SC_PUK) || sc.equals(SC_PUK2));
+ }
+
+ public static String getSuppServiceKey(String dialString) {
+ String sc = getMmiServiceCode(dialString);
+ if (sc != null && sc.equals(SC_CLIP)) {
+ return "";
+ } else if (sc != null && sc.equals(SC_CLIR)) {
+ return BUTTON_CLIR_KEY;
+ } else if (isServiceCodeCallForwarding(sc)) {
+ return CALL_FORWARDING_KEY;
+ } else if (isServiceCodeCallBarring(sc)) {
+ return CALL_BARRING_KEY;
+ } else if (sc != null && sc.equals(SC_PWD)) {
+ return "";
+ } else if (sc != null && sc.equals(SC_WAIT)) {
+ return BUTTON_CW_KEY;
+ } else if (isPinPukCommand(sc)) {
+ return "";
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index 2dfeaed..d2dfab5 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -25,7 +25,7 @@
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
-import android.telephony.Rlog;
+import com.android.telephony.Rlog;
import android.text.TextUtils;
import com.android.internal.telephony.Call;
@@ -288,7 +288,11 @@
}
} else {
TelecomManager tm = mPhone.getContext().getSystemService(TelecomManager.class);
- tm.addNewIncomingCall(handle, extras);
+ if (connection.isMultiparty()) {
+ tm.addNewIncomingConference(handle, extras);
+ } else {
+ tm.addNewIncomingCall(handle, extras);
+ }
}
}
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/RadioOnHelper.java
index 981dc96..25ac220 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/RadioOnHelper.java
@@ -77,7 +77,8 @@
* RadioOnHelper's handler (thus ensuring that the rest of the sequence is entirely
* serialized, and runs on the main looper.)
*/
- public void triggerRadioOnAndListen(RadioOnStateListener.Callback callback) {
+ public void triggerRadioOnAndListen(RadioOnStateListener.Callback callback,
+ boolean forEmergencyCall, Phone phoneForEmergencyCall) {
setupListeners();
mCallback = callback;
mInProgressListeners.clear();
@@ -89,16 +90,17 @@
}
mInProgressListeners.add(mListeners.get(i));
- mListeners.get(i).waitForRadioOn(phone, this);
+ mListeners.get(i).waitForRadioOn(phone, this, forEmergencyCall,
+ forEmergencyCall && phone == phoneForEmergencyCall);
}
- powerOnRadio();
+ powerOnRadio(forEmergencyCall, phoneForEmergencyCall);
}
/**
* Attempt to power on the radio (i.e. take the device out of airplane mode). We'll eventually
* get an onServiceStateChanged() callback when the radio successfully comes up.
*/
- private void powerOnRadio() {
+ private void powerOnRadio(boolean forEmergencyCall, Phone phoneForEmergencyCall) {
// If airplane mode is on, we turn it off the same way that the Settings activity turns it
// off.
@@ -110,6 +112,11 @@
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0);
+ for (Phone phone : PhoneFactory.getPhones()) {
+ Log.d(this, "powerOnRadio, enabling Radio");
+ phone.setRadioPower(true, forEmergencyCall, phone == phoneForEmergencyCall, false);
+ }
+
// Post the broadcast intend for change in airplane mode
// TODO: We really should not be in charge of sending this broadcast.
// If changing the setting is sufficient to trigger all of the rest of the logic,
diff --git a/src/com/android/services/telephony/RadioOnStateListener.java b/src/com/android/services/telephony/RadioOnStateListener.java
index 52bd9cf..93e1e3c 100644
--- a/src/com/android/services/telephony/RadioOnStateListener.java
+++ b/src/com/android/services/telephony/RadioOnStateListener.java
@@ -56,6 +56,9 @@
@VisibleForTesting
public static final int MSG_SERVICE_STATE_CHANGED = 2;
private static final int MSG_RETRY_TIMEOUT = 3;
+ @VisibleForTesting
+ public static final int MSG_RADIO_ON = 4;
+ public static final int MSG_RADIO_OFF_OR_NOT_AVAILABLE = 5;
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
@@ -67,7 +70,10 @@
Phone phone = (Phone) args.arg1;
RadioOnStateListener.Callback callback =
(RadioOnStateListener.Callback) args.arg2;
- startSequenceInternal(phone, callback);
+ boolean forEmergencyCall = (boolean) args.arg3;
+ boolean isSelectedPhoneForEmergencyCall = (boolean) args.arg4;
+ startSequenceInternal(phone, callback, forEmergencyCall,
+ isSelectedPhoneForEmergencyCall);
} finally {
args.recycle();
}
@@ -75,6 +81,12 @@
case MSG_SERVICE_STATE_CHANGED:
onServiceStateChanged((ServiceState) ((AsyncResult) msg.obj).result);
break;
+ case MSG_RADIO_ON:
+ onRadioOn();
+ break;
+ case MSG_RADIO_OFF_OR_NOT_AVAILABLE:
+ registerForRadioOn();
+ break;
case MSG_RETRY_TIMEOUT:
onRetryTimeout();
break;
@@ -88,6 +100,10 @@
private Callback mCallback; // The callback to notify upon completion.
private Phone mPhone; // The phone that will attempt to place the call.
+ private boolean mForEmergencyCall; // Whether radio is being turned on for emergency call.
+ // Whether this phone is selected to place emergency call. Can be true only if
+ // mForEmergencyCall is true.
+ private boolean mSelectedPhoneForEmergencyCall;
private int mNumRetriesSoFar;
/**
@@ -104,7 +120,8 @@
* RadioOnStateListener's handler (thus ensuring that the rest of the sequence is entirely
* serialized, and runs only on the handler thread.)
*/
- public void waitForRadioOn(Phone phone, Callback callback) {
+ public void waitForRadioOn(Phone phone, Callback callback,
+ boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) {
Log.d(this, "waitForRadioOn: Phone " + phone.getPhoneId());
if (mPhone != null) {
@@ -115,6 +132,8 @@
SomeArgs args = SomeArgs.obtain();
args.arg1 = phone;
args.arg2 = callback;
+ args.arg3 = forEmergencyCall;
+ args.arg4 = isSelectedPhoneForEmergencyCall;
mHandler.obtainMessage(MSG_START_SEQUENCE, args).sendToTarget();
}
@@ -123,7 +142,8 @@
*
* @see #waitForRadioOn
*/
- private void startSequenceInternal(Phone phone, Callback callback) {
+ private void startSequenceInternal(Phone phone, Callback callback,
+ boolean forEmergencyCall, boolean isSelectedPhoneForEmergencyCall) {
Log.d(this, "startSequenceInternal: Phone " + phone.getPhoneId());
// First of all, clean up any state left over from a prior RadioOn call sequence. This
@@ -133,8 +153,13 @@
mPhone = phone;
mCallback = callback;
+ mForEmergencyCall = forEmergencyCall;
+ mSelectedPhoneForEmergencyCall = isSelectedPhoneForEmergencyCall;
registerForServiceStateChanged();
+ // Register for RADIO_OFF to handle cases where emergency call is dialed before
+ // we receive UNSOL_RESPONSE_RADIO_STATE_CHANGED with RADIO_OFF.
+ registerForRadioOff();
// Next step: when the SERVICE_STATE_CHANGED event comes in, we'll retry the call; see
// onServiceStateChanged(). But also, just in case, start a timer to make sure we'll retry
// the call even if the SERVICE_STATE_CHANGED event never comes in for some reason.
@@ -147,6 +172,7 @@
* call with {@link Callback#isOkToCall}
*/
private void onServiceStateChanged(ServiceState state) {
+ if (mPhone == null) return;
Log.d(this, "onServiceStateChanged(), new state = %s, Phone = %s", state,
mPhone.getPhoneId());
@@ -169,6 +195,18 @@
}
}
+ private void onRadioOn() {
+ if (mPhone == null) return;
+ ServiceState state = mPhone.getServiceState();
+ Log.d(this, "onRadioOn, state = %s, Phone = %s", state,
+ mPhone.getPhoneId());
+ if (isOkToCall(state.getState())) {
+ onComplete(true);
+ cleanup();
+ } else {
+ Log.d(this, "onRadioOn: not ready to call yet, keep waiting.");
+ }
+ }
/**
* Callback to see if it is okay to call yet, given the current conditions.
*/
@@ -180,6 +218,7 @@
* Handles the retry timer expiring.
*/
private void onRetryTimeout() {
+ if (mPhone == null) return;
int serviceState = mPhone.getServiceState().getState();
Log.d(this, "onRetryTimeout(): phone state = %s, service state = %d, retries = %d.",
mPhone.getState(), serviceState, mNumRetriesSoFar);
@@ -208,7 +247,8 @@
cleanup();
} else {
Log.d(this, "Trying (again) to turn on the radio.");
- mPhone.setRadioPower(true);
+ mPhone.setRadioPower(true, mForEmergencyCall, mSelectedPhoneForEmergencyCall,
+ false);
startRetryTimer();
}
}
@@ -239,6 +279,8 @@
onComplete(false);
unregisterForServiceStateChanged();
+ unregisterForRadioOff();
+ unregisterForRadioOn();
cancelRetryTimer();
// Used for unregisterForServiceStateChanged() so we null it out here instead.
@@ -271,6 +313,31 @@
mHandler.removeMessages(MSG_SERVICE_STATE_CHANGED); // Clean up any pending messages too
}
+ private void registerForRadioOff() {
+ mPhone.mCi.registerForOffOrNotAvailable(mHandler, MSG_RADIO_OFF_OR_NOT_AVAILABLE, null);
+ }
+
+ private void unregisterForRadioOff() {
+ // This method is safe to call even if we haven't set mPhone yet.
+ if (mPhone != null) {
+ mPhone.mCi.unregisterForOffOrNotAvailable(mHandler); // Safe even if unnecessary
+ }
+ mHandler.removeMessages(MSG_RADIO_OFF_OR_NOT_AVAILABLE); // Clean up any pending messages
+ }
+
+ private void registerForRadioOn() {
+ unregisterForRadioOff();
+ mPhone.mCi.registerForOn(mHandler, MSG_RADIO_ON, null);
+ }
+
+ private void unregisterForRadioOn() {
+ // This method is safe to call even if we haven't set mPhone yet.
+ if (mPhone != null) {
+ mPhone.mCi.unregisterForOn(mHandler); // Safe even if unnecessary
+ }
+ mHandler.removeMessages(MSG_RADIO_ON); // Clean up any pending messages too
+ }
+
private void onComplete(boolean isRadioReady) {
if (mCallback != null) {
Callback tempCallback = mCallback;
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index 5a1e6a6..1013927 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -41,7 +41,6 @@
import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
-import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -49,6 +48,8 @@
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsException;
import android.telephony.ims.ImsMmTelManager;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.text.TextUtils;
@@ -60,6 +61,7 @@
import com.android.phone.PhoneGlobals;
import com.android.phone.PhoneUtils;
import com.android.phone.R;
+import com.android.telephony.Rlog;
import java.util.Arrays;
import java.util.LinkedList;
@@ -86,9 +88,11 @@
private final PstnPhoneCapabilitiesNotifier mPhoneCapabilitiesNotifier;
private boolean mIsEmergency;
private boolean mIsRttCapable;
+ private boolean mIsAdhocConfCapable;
private boolean mIsEmergencyPreferred;
private MmTelFeature.MmTelCapabilities mMmTelCapabilities;
private ImsMmTelManager.CapabilityCallback mMmtelCapabilityCallback;
+ private RegistrationManager.RegistrationCallback mImsRegistrationCallback;
private ImsMmTelManager mMmTelManager;
private final boolean mIsDummy;
private boolean mIsVideoCapable;
@@ -106,6 +110,7 @@
mPhone = phone;
mIsEmergency = isEmergency;
mIsDummy = isDummy;
+ mIsAdhocConfCapable = mPhone.isImsRegistered();
mAccount = registerPstnPhoneAccount(isEmergency, isDummy);
Log.i(this, "Registered phoneAccount: %s with handle: %s",
mAccount, mAccount.getAccountHandle());
@@ -138,15 +143,38 @@
updateRttCapability();
}
};
-
registerMmTelCapabilityCallback();
+
+ mImsRegistrationCallback = new RegistrationManager.RegistrationCallback() {
+ @Override
+ public void onRegistered(int imsRadioTech) {
+ updateAdhocConfCapability(true);
+ }
+
+ @Override
+ public void onRegistering(int imsRadioTech) {
+ updateAdhocConfCapability(false);
+ }
+
+ @Override
+ public void onUnregistered(ImsReasonInfo imsReasonInfo) {
+ updateAdhocConfCapability(false);
+ }
+ };
+ registerImsRegistrationCallback();
}
void teardown() {
mIncomingCallNotifier.teardown();
mPhoneCapabilitiesNotifier.teardown();
- if (mMmTelManager != null && mMmtelCapabilityCallback != null) {
- mMmTelManager.unregisterMmTelCapabilityCallback(mMmtelCapabilityCallback);
+ if (mMmTelManager != null) {
+ if (mMmtelCapabilityCallback != null) {
+ mMmTelManager.unregisterMmTelCapabilityCallback(mMmtelCapabilityCallback);
+ }
+
+ if (mImsRegistrationCallback != null) {
+ mMmTelManager.unregisterImsRegistrationCallback(mImsRegistrationCallback);
+ }
}
}
@@ -171,6 +199,25 @@
}
}
+ private void registerImsRegistrationCallback() {
+ if (mMmTelManager == null || mImsRegistrationCallback == null) {
+ return;
+ }
+
+ try {
+ mMmTelManager.registerImsRegistrationCallback(mContext.getMainExecutor(),
+ mImsRegistrationCallback);
+ } catch (ImsException e) {
+ Log.w(this, "registerImsRegistrationCallback: registration failed, no ImsService"
+ + " available. Exception: " + e.getMessage());
+ return;
+ } catch (IllegalArgumentException e) {
+ Log.w(this, "registerImsRegistrationCallback: registration failed, invalid"
+ + " subscription, Exception" + e.getMessage());
+ return;
+ }
+ }
+
/**
* Trigger re-registration of this account.
*/
@@ -226,6 +273,7 @@
// slotId from the subId or the phoneId in all instances.
SubscriptionInfo record =
mSubscriptionManager.getActiveSubscriptionInfo(subId);
+ TelephonyManager tm = mTelephonyManager.createForSubscriptionId(subId);
if (isEmergency) {
label = mContext.getResources().getString(R.string.sim_label_emergency_calls);
@@ -234,7 +282,7 @@
} else if (mTelephonyManager.getPhoneCount() == 1) {
// For single-SIM devices, we show the label and description as whatever the name of
// the network is.
- description = label = mTelephonyManager.getNetworkOperatorName();
+ description = label = tm.getNetworkOperatorName();
} else {
CharSequence subDisplayName = null;
@@ -321,6 +369,12 @@
extras.putAll(getPhoneAccountExtras());
}
+ if (mIsAdhocConfCapable && isCarrierAdhocConferenceCallSupported()) {
+ capabilities |= PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING;
+ } else {
+ capabilities &= ~PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING;
+ }
+
final boolean isHandoverFromSupported = mContext.getResources().getBoolean(
R.bool.config_support_handover_from);
if (isHandoverFromSupported && !isEmergency) {
@@ -511,6 +565,19 @@
}
/**
+ * Determines from carrier config whether adhoc conference calling is supported.
+ *
+ * @return {@code true} if adhoc conference calling is supported, {@code false} otherwise.
+ */
+ private boolean isCarrierAdhocConferenceCallSupported() {
+ PersistableBundle b =
+ PhoneGlobals.getInstance().getCarrierConfigForSubId(mPhone.getSubId());
+ return b != null &&
+ b.getBoolean(CarrierConfigManager.KEY_SUPPORT_ADHOC_CONFERENCE_CALLS_BOOL);
+ }
+
+
+ /**
* Determines from carrier config whether merging calls is supported.
*
* @return {@code true} if merging calls is supported, {@code false} otherwise.
@@ -664,6 +731,26 @@
}
}
+ public void updateAdhocConfCapability(boolean isAdhocConfCapable) {
+ synchronized (mAccountsLock) {
+ if (!mAccounts.contains(this)) {
+ // Account has already been torn down, don't try to register it again.
+ // This handles the case where teardown has already happened, and we got a Ims
+ // registartion update that lost the race for the mAccountsLock. In such a
+ // scenario by the time we get here, the original phone account could have been
+ // torn down.
+ return;
+ }
+
+ if (isAdhocConfCapable != mIsAdhocConfCapable) {
+ Log.i(this, "updateAdhocConfCapability - changed, new value: "
+ + isAdhocConfCapable);
+ mIsAdhocConfCapable = isAdhocConfCapable;
+ mAccount = registerPstnPhoneAccount(mIsEmergency, mIsDummy);
+ }
+ }
+ }
+
public void updateRttCapability() {
boolean isRttEnabled = isRttCurrentlySupported();
if (isRttEnabled != mIsRttCapable) {
@@ -1048,6 +1135,21 @@
return null;
}
+ public void refreshAdhocConference(boolean isEnableAdhocConf) {
+ synchronized (mAccountsLock) {
+ Log.v(this, "refreshAdhocConference isEnable = " + isEnableAdhocConf);
+ for (AccountEntry entry : mAccounts) {
+ boolean hasAdhocConfCapability = entry.mAccount.hasCapabilities(
+ PhoneAccount.CAPABILITY_ADHOC_CONFERENCE_CALLING);
+ if (!isEnableAdhocConf && hasAdhocConfCapability) {
+ entry.updateAdhocConfCapability(isEnableAdhocConf);
+ } else if (isEnableAdhocConf && !hasAdhocConfCapability) {
+ entry.updateAdhocConfCapability(entry.mPhone.isImsRegistered());
+ }
+ }
+ }
+ }
+
/**
* Returns whethere a the subscription associated with a {@link PhoneAccountHandle} is using a
* sim call manager.
@@ -1214,30 +1316,6 @@
// Clean up any PhoneAccounts that are no longer relevant
cleanupPhoneAccounts();
-
- // At some point, the phone account ID was switched from the subId to the iccId.
- // If there is a default account, check if this is the case, and upgrade the default account
- // from using the subId to iccId if so.
- PhoneAccountHandle defaultPhoneAccount =
- mTelecomManager.getUserSelectedOutgoingPhoneAccount();
- ComponentName telephonyComponentName =
- new ComponentName(mContext, TelephonyConnectionService.class);
-
- if (defaultPhoneAccount != null &&
- telephonyComponentName.equals(defaultPhoneAccount.getComponentName()) &&
- !hasAccountEntryForPhoneAccount(defaultPhoneAccount)) {
-
- String phoneAccountId = defaultPhoneAccount.getId();
- if (!TextUtils.isEmpty(phoneAccountId) && TextUtils.isDigitsOnly(phoneAccountId)) {
- PhoneAccountHandle upgradedPhoneAccount =
- PhoneUtils.makePstnPhoneAccountHandle(
- PhoneGlobals.getPhone(Integer.parseInt(phoneAccountId)));
-
- if (hasAccountEntryForPhoneAccount(upgradedPhoneAccount)) {
- mTelecomManager.setUserSelectedOutgoingPhoneAccount(upgradedPhoneAccount);
- }
- }
- }
}
private void tearDownAccounts() {
diff --git a/src/com/android/services/telephony/TelephonyConference.java b/src/com/android/services/telephony/TelephonyConference.java
index afbe89d..7e4693f 100644
--- a/src/com/android/services/telephony/TelephonyConference.java
+++ b/src/com/android/services/telephony/TelephonyConference.java
@@ -16,6 +16,7 @@
package com.android.services.telephony;
+import android.net.Uri;
import android.telecom.Connection;
import android.telecom.PhoneAccountHandle;
@@ -93,6 +94,22 @@
}
@Override
+ public void onAnswer(int videoState) {
+ Log.e(this, new Exception(), "Answer not supported for GSM conference call.");
+ }
+
+ @Override
+ public void onReject() {
+ Log.e(this, new Exception(), "Reject not supported for GSM conference call.");
+ }
+
+ @Override
+ public void onAddConferenceParticipants(List<Uri> participants) {
+ Log.e(this, new Exception(), "Adding Conference Participants not supported " +
+ " for GSM conference call.");
+ }
+
+ @Override
public void onMerge(Connection connection) {
try {
Phone phone = ((TelephonyConnection) connection).getPhone();
diff --git a/src/com/android/services/telephony/TelephonyConferenceBase.java b/src/com/android/services/telephony/TelephonyConferenceBase.java
index 5e7ecf6..1c81fb9 100644
--- a/src/com/android/services/telephony/TelephonyConferenceBase.java
+++ b/src/com/android/services/telephony/TelephonyConferenceBase.java
@@ -48,6 +48,14 @@
public void onConferenceMembershipChanged(Connection connection) {}
/**
+ * Listener called when there conference call state changes.
+ * @param conference The conference.
+ * @param oldState previous state of conference call.
+ * @param newState new state of conference call.
+ */
+ public void onStateChanged(Conference conference, int oldState, int newState) {}
+
+ /**
* Listener called when a conference is destroyed.
* @param conference The conference.
*/
@@ -129,6 +137,54 @@
}
/**
+ * Sets state to be on hold.
+ */
+ public final void setConferenceOnHold() {
+ int oldState = getState();
+ if (oldState == Connection.STATE_HOLDING) {
+ return;
+ }
+ setOnHold();
+ notifyStateChanged(oldState, getState());
+ }
+
+ /**
+ * Sets state to be dialing.
+ */
+ public final void setConferenceOnDialing() {
+ int oldState = getState();
+ if (oldState == Connection.STATE_DIALING) {
+ return;
+ }
+ setDialing();
+ notifyStateChanged(oldState, getState());
+ }
+
+ /**
+ * Sets state to be ringing.
+ */
+ public final void setConferenceOnRinging() {
+ int oldState = getState();
+ if (oldState == Connection.STATE_RINGING) {
+ return;
+ }
+ setRinging();
+ notifyStateChanged(oldState, getState());
+ }
+
+ /**
+ * Sets state to be active.
+ */
+ public final void setConferenceOnActive() {
+ int oldState = getState();
+ if (oldState == Connection.STATE_ACTIVE) {
+ return;
+ }
+ setActive();
+ notifyStateChanged(oldState, getState());
+ }
+
+ /**
* Updates RIL voice radio technology used for current conference after its creation.
*/
public void updateCallRadioTechAfterCreation() {
@@ -188,4 +244,12 @@
listener.onDestroyed(this);
}
}
+
+ private void notifyStateChanged(int oldState, int newState) {
+ if (oldState != newState) {
+ for (TelephonyConferenceListener listener : mListeners) {
+ listener.onStateChanged(this, oldState, newState);
+ }
+ }
+ }
}
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
old mode 100644
new mode 100755
index fb865b4..004a699
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -37,12 +37,11 @@
import android.telecom.StatusHints;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
-import android.telephony.Annotation.RilRadioTechnology;
import android.telephony.CarrierConfigManager;
import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
-import android.telephony.Rlog;
import android.telephony.ServiceState;
+import android.telephony.ServiceState.RilRadioTechnology;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsCallProfile;
@@ -51,6 +50,7 @@
import android.util.Pair;
import com.android.ims.ImsCall;
+import com.android.ims.ImsException;
import com.android.ims.internal.ConferenceParticipant;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
@@ -63,12 +63,14 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.imsphone.ImsPhone;
+import com.android.internal.telephony.imsphone.ImsPhoneCall;
import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
import com.android.internal.telephony.imsphone.ImsPhoneConnection;
import com.android.phone.ImsUtil;
import com.android.phone.PhoneGlobals;
import com.android.phone.PhoneUtils;
import com.android.phone.R;
+import com.android.telephony.Rlog;
import java.util.ArrayList;
import java.util.Arrays;
@@ -113,6 +115,13 @@
private static final int MSG_SET_CALL_RADIO_TECH = 18;
private static final int MSG_ON_CONNECTION_EVENT = 19;
private static final int MSG_REDIAL_CONNECTION_CHANGED = 20;
+ private static final int MSG_REJECT = 21;
+
+ private static final String JAPAN_COUNTRY_CODE_WITH_PLUS_SIGN = "+81";
+ private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
+
+ private List<Uri> mParticipants;
+ private boolean mIsAdhocConferenceCall;
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@Override
@@ -163,7 +172,9 @@
"not foreground connection, skipping");
return;
}
- setRingbackRequested((Boolean) ((AsyncResult) msg.obj).result);
+ boolean ringback = (Boolean) ((AsyncResult) msg.obj).result;
+ setRingbackRequested(ringback);
+ notifyRingbackRequested(ringback);
break;
case MSG_DISCONNECT:
updateState();
@@ -268,6 +279,10 @@
int cause = (int) msg.obj;
hangup(cause);
break;
+ case MSG_REJECT:
+ int rejectReason = (int) msg.obj;
+ reject(rejectReason);
+ break;
case MSG_SET_CALL_RADIO_TECH:
int vrat = (int) msg.obj;
@@ -463,6 +478,7 @@
public void onVideoProviderChanged(android.telecom.Connection c,
Connection.VideoProvider videoProvider) {}
public void onVideoStateChanged(android.telecom.Connection c, int videoState) {}
+ public void onRingbackRequested(Connection c, boolean ringback) {}
}
private final PostDialListener mPostDialListener = new PostDialListener() {
@@ -859,6 +875,11 @@
}
@Override
+ public void onAddConferenceParticipants(List<Uri> participants) {
+ performAddConferenceParticipants(participants);
+ }
+
+ @Override
public void onAbort() {
Log.v(this, "onAbort");
mHandler.obtainMessage(MSG_HANGUP, android.telephony.DisconnectCause.LOCAL).sendToTarget();
@@ -876,14 +897,7 @@
@Override
public void onAnswer(int videoState) {
- Log.v(this, "onAnswer");
- if (isValidRingingCall() && getPhone() != null) {
- try {
- getPhone().acceptCall(videoState);
- } catch (CallStateException e) {
- Log.e(this, e, "Failed to accept call.");
- }
- }
+ performAnswer(videoState);
}
@Override
@@ -927,15 +941,76 @@
@Override
public void onReject() {
- Log.v(this, "onReject");
+ performReject(android.telecom.Call.REJECT_REASON_DECLINED);
+ }
+
+ @Override
+ public void onReject(@android.telecom.Call.RejectReason int rejectReason) {
+ performReject(rejectReason);
+ }
+
+ public void performReject(int rejectReason) {
+ Log.v(this, "performReject");
if (isValidRingingCall()) {
- mHandler.obtainMessage(MSG_HANGUP, android.telephony.DisconnectCause.INCOMING_REJECTED)
+ mHandler.obtainMessage(MSG_REJECT, rejectReason)
.sendToTarget();
}
super.onReject();
}
@Override
+ public void onTransfer(Uri number, boolean isConfirmationRequired) {
+ Log.v(this, "onTransfer");
+ if (mOriginalConnection != null) {
+ if (number == null) {
+ Log.w(this, "call transfer uri is null");
+ return;
+ }
+ String scheme = number.getScheme();
+ String transferNumber = "";
+ String uriString = number.getSchemeSpecificPart();
+ if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
+ if (!PhoneAccount.SCHEME_TEL.equals(scheme)) {
+ Log.w(this, "onTransfer, number scheme is not of type tel instead: "
+ + scheme);
+ return;
+ }
+ if (PhoneNumberUtils.isUriNumber(uriString)) {
+ Log.w(this, "Invalid transfer address. Not a legal PSTN number.");
+ return;
+ }
+ transferNumber = PhoneNumberUtils.convertAndStrip(uriString);
+ if (TextUtils.isEmpty(transferNumber)) {
+ Log.w(this, "Empty transfer number obtained from uri");
+ return;
+ }
+ } else {
+ Log.w(this, "Cannot transfer to voicemail uri");
+ return;
+ }
+
+ try {
+ mOriginalConnection.transfer(transferNumber, isConfirmationRequired);
+ } catch (CallStateException e) {
+ Log.e(this, e, "Failed to transfer call.");
+ }
+ }
+ }
+
+ @Override
+ public void onTransfer(Connection otherConnection) {
+ Log.v(this, "onConsultativeTransfer");
+ if (mOriginalConnection != null && (otherConnection instanceof TelephonyConnection)) {
+ try {
+ mOriginalConnection.consultativeTransfer(
+ ((TelephonyConnection) otherConnection).getOriginalConnection());
+ } catch (CallStateException e) {
+ Log.e(this, e, "Failed to transfer call.");
+ }
+ }
+ }
+
+ @Override
public void onPostDialContinue(boolean proceed) {
Log.v(this, "onPostDialContinue, proceed: " + proceed);
if (mOriginalConnection != null) {
@@ -1001,6 +1076,17 @@
originalConnection.sendRttModifyResponse(textStream);
}
+ public void performAnswer(int videoState) {
+ Log.v(this, "performAnswer");
+ if (isValidRingingCall() && getPhone() != null) {
+ try {
+ getPhone().acceptCall(videoState);
+ } catch (CallStateException e) {
+ Log.e(this, e, "Failed to accept call.");
+ }
+ }
+ }
+
public void performHold() {
Log.v(this, "performHold");
// TODO: Can dialing calls be put on hold as well since they take up the
@@ -1096,6 +1182,29 @@
}
}
+ private String[] getAddConferenceParticipants(List<Uri> participants) {
+ String[] addConfParticipants = new String[participants.size()];
+ int i = 0;
+ for (Uri participant : participants) {
+ addConfParticipants[i] = participant.getSchemeSpecificPart();
+ i++;
+ }
+ return addConfParticipants;
+ }
+
+ public void performAddConferenceParticipants(List<Uri> participants) {
+ Log.v(this, "performAddConferenceParticipants");
+ if (mOriginalConnection.getCall() instanceof ImsPhoneCall) {
+ ImsPhoneCall imsPhoneCall = (ImsPhoneCall)mOriginalConnection.getCall();
+ try {
+ imsPhoneCall.getImsCall().inviteParticipants(
+ getAddConferenceParticipants(participants));
+ } catch(ImsException e) {
+ Log.e(this, e, "failed to add conference participants");
+ }
+ }
+ }
+
/**
* Builds connection capabilities common to all TelephonyConnections. Namely, apply IMS-based
* capabilities.
@@ -1130,6 +1239,12 @@
newCapabilities = changeBitmask(newCapabilities, CAPABILITY_SUPPORT_DEFLECT,
isImsConnection() && canDeflectImsCalls());
+ newCapabilities = applyAddParticipantCapabilities(newCapabilities);
+ newCapabilities = changeBitmask(newCapabilities, CAPABILITY_TRANSFER_CONSULTATIVE,
+ isImsConnection() && canConsultativeTransfer());
+ newCapabilities = changeBitmask(newCapabilities, CAPABILITY_TRANSFER,
+ isImsConnection() && canTransferToNumber());
+
if (getConnectionCapabilities() != newCapabilities) {
setConnectionCapabilities(newCapabilities);
notifyConnectionCapabilitiesChanged(newCapabilities);
@@ -1162,11 +1277,13 @@
isExternalConnection());
newProperties = changeBitmask(newProperties, PROPERTY_HAS_CDMA_VOICE_PRIVACY,
mIsCdmaVoicePrivacyEnabled);
- newProperties = changeBitmask(newProperties, PROPERTY_ASSISTED_DIALING_USED,
+ newProperties = changeBitmask(newProperties, PROPERTY_ASSISTED_DIALING,
mIsUsingAssistedDialing);
newProperties = changeBitmask(newProperties, PROPERTY_IS_RTT, isRtt());
newProperties = changeBitmask(newProperties, PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL,
isNetworkIdentifiedEmergencyCall());
+ newProperties = changeBitmask(newProperties, PROPERTY_IS_ADHOC_CONFERENCE,
+ isAdhocConferenceCall());
if (getConnectionProperties() != newProperties) {
setTelephonyConnectionProperties(newProperties);
@@ -1186,6 +1303,9 @@
if (isShowingOriginalDialString()
&& mOriginalConnection.getOrigDialString() != null) {
address = getAddressFromNumber(mOriginalConnection.getOrigDialString());
+ } else if (isNeededToFormatIncomingNumberForJp()) {
+ address = getAddressFromNumber(
+ formatIncomingNumberForJp(mOriginalConnection.getAddress()));
} else {
address = getAddressFromNumber(mOriginalConnection.getAddress());
}
@@ -1255,6 +1375,7 @@
setTelephonyVideoState(mOriginalConnection.getVideoState());
setOriginalConnectionCapabilities(mOriginalConnection.getConnectionCapabilities());
setIsNetworkIdentifiedEmergencyCall(mOriginalConnection.isNetworkIdentifiedEmergencyCall());
+ setIsAdhocConferenceCall(mOriginalConnection.isAdhocConference());
setAudioModeIsVoip(mOriginalConnection.getAudioModeIsVoip());
setTelephonyVideoProvider(mOriginalConnection.getVideoProvider());
setAudioQuality(mOriginalConnection.getAudioQuality());
@@ -1511,6 +1632,39 @@
return true;
}
+ /**
+ * @return The address's to which this Connection is currently communicating.
+ */
+ public final @Nullable List<Uri> getParticipants() {
+ return mParticipants;
+ }
+
+ /**
+ * Sets the value of the {@link #getParticipants()} property.
+ *
+ * @param address The participant address's.
+ */
+ public final void setParticipants(@Nullable List<Uri> address) {
+ mParticipants = address;
+ }
+
+ /**
+ * @return true if connection is adhocConference call else false.
+ */
+ public final boolean isAdhocConferenceCall() {
+ return mIsAdhocConferenceCall;
+ }
+
+ /**
+ * Sets the value of the {@link #isAdhocConferenceCall()} property.
+ *
+ * @param isAdhocConferenceCall represents if the call is adhoc conference call or not.
+ */
+ public void setIsAdhocConferenceCall(boolean isAdhocConferenceCall) {
+ mIsAdhocConferenceCall = isAdhocConferenceCall;
+ updateConnectionProperties();
+ }
+
private boolean canHoldImsCalls() {
PersistableBundle b = getCarrierConfig();
// Return true if the CarrierConfig is unavailable
@@ -1520,6 +1674,75 @@
|| !VideoProfile.isVideo(getVideoState()));
}
+ private boolean isConferenceHosted() {
+ boolean isHosted = false;
+ if (getTelephonyConnectionService() != null) {
+ for (Conference current : getTelephonyConnectionService().getAllConferences()) {
+ if (current instanceof ImsConference) {
+ ImsConference other = (ImsConference) current;
+ if (getState() == current.getState()) {
+ continue;
+ }
+ if (other.isConferenceHost()) {
+ isHosted = true;
+ break;
+ }
+ }
+ }
+ }
+ return isHosted;
+ }
+
+ private boolean isAddParticipantCapable() {
+ // not add participant capable for non ims phones
+ if (getPhone() == null || getPhone().getPhoneType() != PhoneConstants.PHONE_TYPE_IMS) {
+ return false;
+ }
+
+ if (!getCarrierConfig()
+ .getBoolean(CarrierConfigManager.KEY_SUPPORT_ADD_CONFERENCE_PARTICIPANTS_BOOL)) {
+ return false;
+ }
+
+ boolean isCapable = !mTreatAsEmergencyCall && (mConnectionState == Call.State.ACTIVE ||
+ mConnectionState == Call.State.HOLDING);
+
+ // add participant capable if current connection is a host connection or
+ // if conference is not hosted on the device
+ isCapable = isCapable && ((mOriginalConnection != null &&
+ mOriginalConnection.isConferenceHost()) ||
+ !isConferenceHosted());
+
+ /**
+ * For individual IMS calls, if the extra for remote conference support is
+ * - indicated, then consider the same for add participant capability
+ * - not indicated, then the add participant capability is same as before.
+ */
+ if (isCapable && (mOriginalConnection != null) && !mIsMultiParty) {
+ isCapable = mOriginalConnectionExtras.getBoolean(
+ ImsCallProfile.EXTRA_CONFERENCE_AVAIL, isCapable);
+ }
+ return isCapable;
+ }
+
+ /**
+ * Applies the add participant capabilities to the {@code CallCapabilities} bit-mask.
+ *
+ * @param callCapabilities The {@code CallCapabilities} bit-mask.
+ * @return The capabilities with the add participant capabilities applied.
+ */
+ private int applyAddParticipantCapabilities(int callCapabilities) {
+ int currentCapabilities = callCapabilities;
+ if (isAddParticipantCapable()) {
+ currentCapabilities = changeBitmask(currentCapabilities,
+ Connection.CAPABILITY_ADD_PARTICIPANT, true);
+ } else {
+ currentCapabilities = changeBitmask(currentCapabilities,
+ Connection.CAPABILITY_ADD_PARTICIPANT, false);
+ }
+ return currentCapabilities;
+ }
+
@VisibleForTesting
public PersistableBundle getCarrierConfig() {
Phone phone = getPhone();
@@ -1540,6 +1763,50 @@
return false;
}
+ private boolean isCallTransferSupported() {
+ PersistableBundle b = getCarrierConfig();
+ // Return false if the CarrierConfig is unavailable
+ if (b != null) {
+ return b.getBoolean(CarrierConfigManager.KEY_CARRIER_ALLOW_TRANSFER_IMS_CALL_BOOL);
+ }
+ return false;
+ }
+
+ private boolean canTransfer(TelephonyConnection c) {
+ com.android.internal.telephony.Connection connection = c.getOriginalConnection();
+ return (connection != null && !connection.isMultiparty()
+ && (c.getState() == STATE_ACTIVE || c.getState() == STATE_HOLDING));
+ }
+
+ private boolean canTransferToNumber() {
+ if (!isCallTransferSupported()) {
+ return false;
+ }
+ return canTransfer(this);
+ }
+
+ private boolean canConsultativeTransfer() {
+ if (!isCallTransferSupported()) {
+ return false;
+ }
+ if (!canTransfer(this)) {
+ return false;
+ }
+ boolean canConsultativeTransfer = false;
+ if (getTelephonyConnectionService() != null) {
+ for (Connection current : getTelephonyConnectionService().getAllConnections()) {
+ if (current != this && current instanceof TelephonyConnection) {
+ TelephonyConnection other = (TelephonyConnection) current;
+ if (canTransfer(other)) {
+ canConsultativeTransfer = true;
+ break;
+ }
+ }
+ }
+ }
+ return canConsultativeTransfer;
+ }
+
/**
* Determines if the device will respect the value of the
* {@link CarrierConfigManager#KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} configuration option.
@@ -1628,6 +1895,46 @@
}
}
+ protected void reject(@android.telecom.Call.RejectReason int rejectReason) {
+ if (mOriginalConnection != null) {
+ mHangupDisconnectCause = android.telephony.DisconnectCause.INCOMING_REJECTED;
+ try {
+ // Hanging up a ringing call requires that we invoke call.hangup() as opposed to
+ // connection.hangup(). Without this change, the party originating the call
+ // will not get sent to voicemail if the user opts to reject the call.
+ if (isValidRingingCall()) {
+ Call call = getCall();
+ if (call != null) {
+ call.hangup(rejectReason);
+ } else {
+ Log.w(this, "Attempting to hangup a connection without backing call.");
+ }
+ } else {
+ // We still prefer to call connection.hangup() for non-ringing calls
+ // in order to support hanging-up specific calls within a conference call.
+ // If we invoked call.hangup() while in a conference, we would end up
+ // hanging up the entire conference call instead of the specific connection.
+ mOriginalConnection.hangup();
+ }
+ } catch (CallStateException e) {
+ Log.e(this, e, "Call to Connection.hangup failed with exception");
+ }
+ } else {
+ if (getState() == STATE_DISCONNECTED) {
+ Log.i(this, "hangup called on an already disconnected call!");
+ close();
+ } else {
+ // There are a few cases where mOriginalConnection has not been set yet. For
+ // example, when the radio has to be turned on to make an emergency call,
+ // mOriginalConnection could not be set for many seconds.
+ setTelephonyConnectionDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+ android.telephony.DisconnectCause.LOCAL,
+ "Local Disconnect before connection established."));
+ close();
+ }
+ }
+ }
+
com.android.internal.telephony.Connection getOriginalConnection() {
return mOriginalConnection;
}
@@ -1742,6 +2049,12 @@
// Ensure extras are propagated to Telecom.
putTelephonyExtras(mOriginalConnectionExtras);
+ // If extras contain Conference support information,
+ // then ensure capabilities are updated.
+ if (mOriginalConnectionExtras.containsKey(
+ ImsCallProfile.EXTRA_CONFERENCE_AVAIL)) {
+ updateConnectionCapabilities();
+ }
} else {
Log.d(this, "Extras update not required");
}
@@ -2530,6 +2843,8 @@
}
sb.append(" confSupported:");
sb.append(mIsConferenceSupported ? "Y" : "N");
+ sb.append(" isAdhocConf:");
+ sb.append(isAdhocConferenceCall() ? "Y" : "N");
sb.append("]");
return sb.toString();
}
@@ -2654,8 +2969,13 @@
* <p>
* Note: This should be used instead of {@link #setVideoState(int)} to ensure listeners are
* notified.
+ * @param videoState The new video state. Valid values:
+ * {@link VideoProfile#STATE_AUDIO_ONLY},
+ * {@link VideoProfile#STATE_BIDIRECTIONAL},
+ * {@link VideoProfile#STATE_TX_ENABLED},
+ * {@link VideoProfile#STATE_RX_ENABLED}.
*/
- public void setTelephonyVideoState(@VideoProfile.VideoState int videoState) {
+ public void setTelephonyVideoState(int videoState) {
setVideoState(videoState);
notifyVideoStateChanged(videoState);
}
@@ -2846,15 +3166,29 @@
/**
* Notifies {@link TelephonyConnectionListener}s of a change to the video state of a connection.
- * @param videoState The new video state.
+ * @param videoState The new video state. Valid values:
+ * {@link VideoProfile#STATE_AUDIO_ONLY},
+ * {@link VideoProfile#STATE_BIDIRECTIONAL},
+ * {@link VideoProfile#STATE_TX_ENABLED},
+ * {@link VideoProfile#STATE_RX_ENABLED}.
*/
- private void notifyVideoStateChanged(@VideoProfile.VideoState int videoState) {
+ private void notifyVideoStateChanged(int videoState) {
for (TelephonyConnectionListener listener : mTelephonyListeners) {
listener.onVideoStateChanged(this, videoState);
}
}
/**
+ * Notifies {@link TelephonyConnectionListener}s of a whether to play Ringback Tone or not.
+ * @param ringback Whether the ringback tone is to be played
+ */
+ private void notifyRingbackRequested(boolean ringback) {
+ for (TelephonyConnectionListener listener : mTelephonyListeners) {
+ listener.onRingbackRequested(this, ringback);
+ }
+ }
+
+ /**
* Notifies {@link TelephonyConnectionListener}s of changes to the video provider for a
* connection.
* @param videoProvider The new video provider.
@@ -2875,4 +3209,29 @@
listener.onStatusHintsChanged(this, statusHints);
}
}
+
+ /**
+ * Whether the incoming call number should be formatted to national number for Japan.
+ * @return {@code true} should be convert to the national format, {@code false} otherwise.
+ */
+ private boolean isNeededToFormatIncomingNumberForJp() {
+ if (mOriginalConnection.isIncoming()
+ && !TextUtils.isEmpty(mOriginalConnection.getAddress())
+ && mOriginalConnection.getAddress().startsWith(JAPAN_COUNTRY_CODE_WITH_PLUS_SIGN)) {
+ PersistableBundle b = getCarrierConfig();
+ return b != null && b.getBoolean(
+ CarrierConfigManager.KEY_FORMAT_INCOMING_NUMBER_TO_NATIONAL_FOR_JP_BOOL);
+ }
+ return false;
+ }
+
+ /**
+ * Format the incoming call number to national number for Japan.
+ * @param number
+ * @return the formatted phone number (e.g, "+819012345678" -> "09012345678")
+ */
+ private String formatIncomingNumberForJp(String number) {
+ return PhoneNumberUtils.stripSeparators(
+ PhoneNumberUtils.formatNumber(number, JAPAN_ISO_COUNTRY_CODE));
+ }
}
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 40b941e..665bf22 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -17,10 +17,13 @@
package com.android.services.telephony;
import android.annotation.NonNull;
+import android.app.AlertDialog;
+import android.app.Dialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
@@ -46,6 +49,7 @@
import android.telephony.emergency.EmergencyNumber;
import android.text.TextUtils;
import android.util.Pair;
+import android.view.WindowManager;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Call;
@@ -65,12 +69,14 @@
import com.android.phone.MMIDialogActivity;
import com.android.phone.PhoneUtils;
import com.android.phone.R;
+import com.android.phone.settings.SuppServicesUiUtil;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -246,12 +252,20 @@
@Override
public boolean isCurrentEmergencyNumber(String number) {
- return mTelephonyManager.isEmergencyNumber(number);
+ try {
+ return mTelephonyManager.isEmergencyNumber(number);
+ } catch (IllegalStateException ise) {
+ return false;
+ }
}
@Override
public Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList() {
- return mTelephonyManager.getEmergencyNumberList();
+ try {
+ return mTelephonyManager.getEmergencyNumberList();
+ } catch (IllegalStateException ise) {
+ return new HashMap<>();
+ }
}
}
@@ -421,6 +435,14 @@
}
/**
+ * Overrides radioOnHelper for testing.
+ */
+ @VisibleForTesting
+ public void setRadioOnHelper(RadioOnHelper radioOnHelper) {
+ mRadioOnHelper = radioOnHelper;
+ }
+
+ /**
* Overrides PhoneSwitcher dependencies for testing.
*/
@VisibleForTesting
@@ -516,6 +538,136 @@
return super.onUnbind(intent);
}
+ private Conference placeOutgoingConference(ConnectionRequest request,
+ Connection resultConnection, Phone phone) {
+ if (resultConnection instanceof TelephonyConnection) {
+ return placeOutgoingConference((TelephonyConnection) resultConnection, phone, request);
+ }
+ return null;
+ }
+
+ private Conference placeOutgoingConference(TelephonyConnection conferenceHostConnection,
+ Phone phone, ConnectionRequest request) {
+ updatePhoneAccount(conferenceHostConnection, phone);
+ com.android.internal.telephony.Connection originalConnection = null;
+ try {
+ originalConnection = phone.startConference(
+ getParticipantsToDial(request.getParticipants()),
+ new ImsPhone.ImsDialArgs.Builder()
+ .setVideoState(request.getVideoState())
+ .setRttTextStream(conferenceHostConnection.getRttTextStream())
+ .build());
+ } catch (CallStateException e) {
+ Log.e(this, e, "placeOutgoingConference, phone.startConference exception: " + e);
+ handleCallStateException(e, conferenceHostConnection, phone);
+ return null;
+ }
+
+ if (originalConnection == null) {
+ Log.d(this, "placeOutgoingConference, phone.startConference returned null");
+ conferenceHostConnection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+ android.telephony.DisconnectCause.OUTGOING_FAILURE,
+ "conferenceHostConnection is null",
+ phone.getPhoneId()));
+ conferenceHostConnection.clearOriginalConnection();
+ conferenceHostConnection.destroy();
+ } else {
+ conferenceHostConnection.setOriginalConnection(originalConnection);
+ }
+
+ return prepareConference(conferenceHostConnection, request.getAccountHandle());
+ }
+
+ Conference prepareConference(Connection conn, PhoneAccountHandle phoneAccountHandle) {
+ if (!(conn instanceof TelephonyConnection)) {
+ Log.w(this, "prepareConference returning NULL conference");
+ return null;
+ }
+
+ TelephonyConnection connection = (TelephonyConnection)conn;
+ ImsConference conference = new ImsConference(TelecomAccountRegistry.getInstance(this),
+ mTelephonyConnectionServiceProxy, connection,
+ phoneAccountHandle, () -> true);
+ mImsConferenceController.addConference(conference);
+ conference.setVideoState(connection,
+ connection.getVideoState());
+ conference.setVideoProvider(connection,
+ connection.getVideoProvider());
+ conference.setStatusHints(connection.getStatusHints());
+ conference.setAddress(connection.getAddress(),
+ connection.getAddressPresentation());
+ conference.setCallerDisplayName(connection.getCallerDisplayName(),
+ connection.getCallerDisplayNamePresentation());
+ conference.setParticipants(connection.getParticipants());
+ return conference;
+ }
+
+ @Override
+ public @Nullable Conference onCreateIncomingConference(
+ @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull final ConnectionRequest request) {
+ Log.i(this, "onCreateIncomingConference, request: " + request);
+ Connection connection = onCreateIncomingConnection(connectionManagerPhoneAccount, request);
+ Log.d(this, "onCreateIncomingConference, connection: %s", connection);
+ if (connection == null) {
+ Log.i(this, "onCreateIncomingConference, implementation returned null connection.");
+ return Conference.createFailedConference(
+ new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONNECTION"),
+ request.getAccountHandle());
+ }
+
+ final Phone phone = getPhoneForAccount(request.getAccountHandle(),
+ false /* isEmergencyCall*/, null /* not an emergency call */);
+ if (phone == null) {
+ Log.d(this, "onCreateIncomingConference, phone is null");
+ return Conference.createFailedConference(
+ DisconnectCauseUtil.toTelecomDisconnectCause(
+ android.telephony.DisconnectCause.OUT_OF_SERVICE,
+ "Phone is null"),
+ request.getAccountHandle());
+ }
+
+ return prepareConference(connection, request.getAccountHandle());
+ }
+
+ @Override
+ public @Nullable Conference onCreateOutgoingConference(
+ @Nullable PhoneAccountHandle connectionManagerPhoneAccount,
+ @NonNull final ConnectionRequest request) {
+ Log.i(this, "onCreateOutgoingConference, request: " + request);
+ Connection connection = onCreateOutgoingConnection(connectionManagerPhoneAccount, request);
+ Log.d(this, "onCreateOutgoingConference, connection: %s", connection);
+ if (connection == null) {
+ Log.i(this, "onCreateOutgoingConference, implementation returned null connection.");
+ return Conference.createFailedConference(
+ new DisconnectCause(DisconnectCause.ERROR, "IMPL_RETURNED_NULL_CONNECTION"),
+ request.getAccountHandle());
+ }
+
+ final Phone phone = getPhoneForAccount(request.getAccountHandle(),
+ false /* isEmergencyCall*/, null /* not an emergency call */);
+ if (phone == null) {
+ Log.d(this, "onCreateOutgoingConference, phone is null");
+ return Conference.createFailedConference(
+ DisconnectCauseUtil.toTelecomDisconnectCause(
+ android.telephony.DisconnectCause.OUT_OF_SERVICE,
+ "Phone is null"),
+ request.getAccountHandle());
+ }
+
+ return placeOutgoingConference(request, connection, phone);
+ }
+
+ private String[] getParticipantsToDial(List<Uri> participants) {
+ String[] participantsToDial = new String[participants.size()];
+ int i = 0;
+ for (Uri participant : participants) {
+ participantsToDial[i] = participant.getSchemeSpecificPart();
+ i++;
+ }
+ return participantsToDial;
+ }
+
@Override
public Connection onCreateOutgoingConnection(
PhoneAccountHandle connectionManagerPhoneAccount,
@@ -523,7 +675,9 @@
Log.i(this, "onCreateOutgoingConnection, request: " + request);
Uri handle = request.getAddress();
- if (handle == null) {
+ boolean isAdhocConference = request.isAdhocConferenceCall();
+
+ if (!isAdhocConference && handle == null) {
Log.d(this, "onCreateOutgoingConnection, handle is null");
return Connection.createFailedConnection(
mDisconnectCauseFactory.toTelecomDisconnectCause(
@@ -626,19 +780,21 @@
}
final String numberToDial = number;
-
final boolean isAirplaneModeOn = mDeviceState.isAirplaneModeOn(this);
boolean needToTurnOnRadio = (isEmergencyNumber && (!isRadioOn() || isAirplaneModeOn))
|| isRadioPowerDownOnBluetooth();
+ // Get the right phone object from the account data passed in.
+ final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
+ /* Note: when not an emergency, handle can be null for unknown callers */
+ handle == null ? null : handle.getSchemeSpecificPart());
+
if (needToTurnOnRadio) {
final Uri resultHandle = handle;
- // By default, Connection based on the default Phone, since we need to return to Telecom
- // now.
- final int originalPhoneType = mPhoneFactoryProxy.getDefaultPhone().getPhoneType();
+ final int originalPhoneType = phone.getPhoneType();
final Connection resultConnection = getTelephonyConnection(request, numberToDial,
- isEmergencyNumber, resultHandle, PhoneFactory.getDefaultPhone());
+ isEmergencyNumber, resultHandle, phone);
if (mRadioOnHelper == null) {
mRadioOnHelper = new RadioOnHelper(this);
}
@@ -646,7 +802,7 @@
@Override
public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
handleOnComplete(isRadioReady, isEmergencyNumber, resultConnection, request,
- numberToDial, resultHandle, originalPhoneType);
+ numberToDial, resultHandle, originalPhoneType, phone);
}
@Override
@@ -662,7 +818,7 @@
// been powered on and isn't in the UNAVAILABLE state, even if it is
// reporting the OUT_OF_SERVICE state.
return (phone.getState() == PhoneConstants.State.OFFHOOK)
- || phone.getServiceState().getState() != ServiceState.STATE_POWER_OFF;
+ || phone.getServiceStateTracker().isRadioOn();
} else {
// Wait until we are in service and ready to make calls. This can happen
// when we power down the radio on bluetooth to save power on watches or if
@@ -675,7 +831,7 @@
|| serviceState == ServiceState.STATE_IN_SERVICE;
}
}
- });
+ }, isEmergencyNumber && !isTestEmergencyNumber, phone);
// Return the still unconnected GsmConnection and wait for the Radios to boot before
// connecting it to the underlying Phone.
return resultConnection;
@@ -691,14 +847,18 @@
"Add call restricted due to ongoing video call"));
}
- // Get the right phone object from the account data passed in.
- final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
- /* Note: when not an emergency, handle can be null for unknown callers */
- handle == null ? null : handle.getSchemeSpecificPart());
if (!isEmergencyNumber) {
final Connection resultConnection = getTelephonyConnection(request, numberToDial,
false, handle, phone);
- return placeOutgoingConnection(request, resultConnection, phone);
+ if (isAdhocConference) {
+ if (resultConnection instanceof TelephonyConnection) {
+ TelephonyConnection conn = (TelephonyConnection)resultConnection;
+ conn.setParticipants(request.getParticipants());
+ }
+ return resultConnection;
+ } else {
+ return placeOutgoingConnection(request, resultConnection, phone);
+ }
} else {
final Connection resultConnection = getTelephonyConnection(request, numberToDial,
true, handle, phone);
@@ -763,18 +923,21 @@
*/
private void handleOnComplete(boolean isRadioReady, boolean isEmergencyNumber,
Connection originalConnection, ConnectionRequest request, String numberToDial,
- Uri handle, int originalPhoneType) {
+ Uri handle, int originalPhoneType, Phone phone) {
// Make sure the Call has not already been canceled by the user.
if (originalConnection.getState() == Connection.STATE_DISCONNECTED) {
Log.i(this, "Call disconnected before the outgoing call was placed. Skipping call "
+ "placement.");
+ if (isEmergencyNumber) {
+ // If call is already canceled by the user, notify modem to exit emergency call
+ // mode by sending radio on with forEmergencyCall=false.
+ for (Phone curPhone : mPhoneFactoryProxy.getPhones()) {
+ curPhone.setRadioPower(true, false, false, true);
+ }
+ }
return;
}
- // Get the right phone object since the radio has been turned on successfully.
if (isRadioReady) {
- final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber,
- /* Note: when not an emergency, handle can be null for unknown callers */
- handle == null ? null : handle.getSchemeSpecificPart());
if (!isEmergencyNumber) {
adjustAndPlaceOutgoingConnection(phone, originalConnection, request, numberToDial,
handle, originalPhoneType, false);
@@ -816,7 +979,8 @@
// TODO: Switch out the underlying connection instead of creating a new
// one and causing UI Jank.
boolean noActiveSimCard = SubscriptionController.getInstance()
- .getActiveSubInfoCount(phone.getContext().getOpPackageName()) == 0;
+ .getActiveSubInfoCount(phone.getContext().getOpPackageName(),
+ null) == 0;
// If there's no active sim card and the device is in emergency mode, use E account.
addExistingConnection(mPhoneUtilsProxy.makePstnPhoneAccountHandleWithPrefix(
phone, "", isEmergencyNumber && noActiveSimCard), repConnection);
@@ -895,7 +1059,7 @@
int dataNetType = phone.getServiceState().getDataNetworkType();
if (dataNetType == TelephonyManager.NETWORK_TYPE_LTE ||
dataNetType == TelephonyManager.NETWORK_TYPE_LTE_CA) {
- state = phone.getServiceState().getDataRegState();
+ state = phone.getServiceState().getDataRegistrationState();
}
}
@@ -981,7 +1145,7 @@
final TelephonyConnection connection =
createConnectionFor(phone, null, true /* isOutgoing */, request.getAccountHandle(),
- request.getTelecomCallId());
+ request.getTelecomCallId(), request.isAdhocConferenceCall());
if (connection == null) {
return Connection.createFailedConnection(
mDisconnectCauseFactory.toTelecomDisconnectCause(
@@ -994,6 +1158,8 @@
connection.setTelephonyVideoState(request.getVideoState());
connection.setRttTextStream(request.getRttTextStream());
connection.setTtyEnabled(isTtyModeEnabled);
+ connection.setIsAdhocConferenceCall(request.isAdhocConferenceCall());
+ connection.setParticipants(request.getParticipants());
return connection;
}
@@ -1025,11 +1191,26 @@
Call call = phone.getRingingCall();
if (!call.getState().isRinging()) {
Log.i(this, "onCreateIncomingConnection, no ringing call");
- return Connection.createFailedConnection(
+ Connection connection = Connection.createFailedConnection(
mDisconnectCauseFactory.toTelecomDisconnectCause(
android.telephony.DisconnectCause.INCOMING_MISSED,
"Found no ringing call",
phone.getPhoneId()));
+ Bundle extras = request.getExtras();
+
+ long time = extras.getLong(TelecomManager.EXTRA_CALL_CREATED_EPOCH_TIME_MILLIS);
+ if (time != 0) {
+ Log.i(this, "onCreateIncomingConnection. Set connect time info.");
+ connection.setConnectTimeMillis(time);
+ }
+
+ Uri address = extras.getParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS);
+ if (address != null) {
+ Log.i(this, "onCreateIncomingConnection. Set caller id info.");
+ connection.setAddress(address, TelecomManager.PRESENTATION_ALLOWED);
+ }
+
+ return connection;
}
com.android.internal.telephony.Connection originalConnection =
@@ -1042,7 +1223,8 @@
TelephonyConnection connection =
createConnectionFor(phone, originalConnection, false /* isOutgoing */,
- request.getAccountHandle(), request.getTelecomCallId());
+ request.getAccountHandle(), request.getTelecomCallId(),
+ request.isAdhocConferenceCall());
handleIncomingRtt(request, originalConnection);
if (connection == null) {
return Connection.createCanceledConnection();
@@ -1154,6 +1336,29 @@
connection.close();
}
+ /**
+ * Called by the {@link ConnectionService} when a newly created {@link Conference} has been
+ * added to the {@link ConnectionService} and sent to Telecom. Here it is safe to send
+ * connection events.
+ *
+ * @param conference the {@link Conference}.
+ */
+ @Override
+ public void onCreateConferenceComplete(Conference conference) {
+ if (conference instanceof ImsConference) {
+ ImsConference imsConference = (ImsConference)conference;
+ TelephonyConnection telephonyConnection =
+ (TelephonyConnection)(imsConference.getConferenceHost());
+ maybeSendInternationalCallEvent(telephonyConnection);
+ }
+ }
+
+ public void onCreateIncomingConferenceFailed(PhoneAccountHandle connectionManagerPhoneAccount,
+ ConnectionRequest request) {
+ Log.i(this, "onCreateIncomingConferenceFailed, request: " + request);
+ onCreateIncomingConnectionFailed(connectionManagerPhoneAccount, request);
+ }
+
@Override
public void triggerConferenceRecalculate() {
if (mTelephonyConferenceController.shouldRecalculate()) {
@@ -1450,6 +1655,12 @@
TelephonyConnection connection, Phone phone, int videoState, Bundle extras) {
String number = connection.getAddress().getSchemeSpecificPart();
+ if (showDataDialog(phone, number)) {
+ connection.setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+ android.telephony.DisconnectCause.DIALED_MMI, "UT is not available"));
+ return;
+ }
+
com.android.internal.telephony.Connection originalConnection = null;
try {
if (phone != null) {
@@ -1470,6 +1681,12 @@
.OUTGOING_EMERGENCY_CALL_PLACED);
}
}
+ for (Conference c : getAllConferences()) {
+ if (c.getState() != Connection.STATE_DISCONNECTED
+ && c instanceof Conference) {
+ ((Conference) c).onDisconnect();
+ }
+ }
} else if (!isVideoCallHoldAllowed(phone)) {
// If we do not support holding ongoing video call for an outgoing
// emergency call, disconnect the ongoing video call.
@@ -1495,34 +1712,7 @@
}
} catch (CallStateException e) {
Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
- int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE;
- switch (e.getError()) {
- case CallStateException.ERROR_OUT_OF_SERVICE:
- cause = android.telephony.DisconnectCause.OUT_OF_SERVICE;
- break;
- case CallStateException.ERROR_POWER_OFF:
- cause = android.telephony.DisconnectCause.POWER_OFF;
- break;
- case CallStateException.ERROR_ALREADY_DIALING:
- cause = android.telephony.DisconnectCause.ALREADY_DIALING;
- break;
- case CallStateException.ERROR_CALL_RINGING:
- cause = android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING;
- break;
- case CallStateException.ERROR_CALLING_DISABLED:
- cause = android.telephony.DisconnectCause.CALLING_DISABLED;
- break;
- case CallStateException.ERROR_TOO_MANY_CALLS:
- cause = android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS;
- break;
- case CallStateException.ERROR_OTASP_PROVISIONING_IN_PROCESS:
- cause = android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS;
- break;
- }
- connection.setTelephonyConnectionDisconnected(
- mDisconnectCauseFactory.toTelecomDisconnectCause(cause, e.getMessage(),
- phone.getPhoneId()));
- connection.close();
+ handleCallStateException(e, connection, phone);
return;
}
@@ -1538,7 +1728,7 @@
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
if (SubscriptionManager.isValidSubscriptionId(subId)) {
- intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
+ SubscriptionManager.putSubscriptionIdExtra(intent, subId);
}
startActivity(intent);
}
@@ -1561,7 +1751,7 @@
return true;
}
return cfgManager.getConfigForSubId(phone.getSubId()).getBoolean(
- CarrierConfigManager.KEY_ALLOW_HOLDING_VIDEO_CALL_BOOL, true);
+ CarrierConfigManager.KEY_ALLOW_HOLD_VIDEO_CALL_BOOL, true);
}
private boolean shouldHoldForEmergencyCall(Phone phone) {
@@ -1576,12 +1766,55 @@
CarrierConfigManager.KEY_ALLOW_HOLD_CALL_DURING_EMERGENCY_BOOL, true);
}
+ private void handleCallStateException(CallStateException e, TelephonyConnection connection,
+ Phone phone) {
+ int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE;
+ switch (e.getError()) {
+ case CallStateException.ERROR_OUT_OF_SERVICE:
+ cause = android.telephony.DisconnectCause.OUT_OF_SERVICE;
+ break;
+ case CallStateException.ERROR_POWER_OFF:
+ cause = android.telephony.DisconnectCause.POWER_OFF;
+ break;
+ case CallStateException.ERROR_ALREADY_DIALING:
+ cause = android.telephony.DisconnectCause.ALREADY_DIALING;
+ break;
+ case CallStateException.ERROR_CALL_RINGING:
+ cause = android.telephony.DisconnectCause.CANT_CALL_WHILE_RINGING;
+ break;
+ case CallStateException.ERROR_CALLING_DISABLED:
+ cause = android.telephony.DisconnectCause.CALLING_DISABLED;
+ break;
+ case CallStateException.ERROR_TOO_MANY_CALLS:
+ cause = android.telephony.DisconnectCause.TOO_MANY_ONGOING_CALLS;
+ break;
+ case CallStateException.ERROR_OTASP_PROVISIONING_IN_PROCESS:
+ cause = android.telephony.DisconnectCause.OTASP_PROVISIONING_IN_PROCESS;
+ break;
+ }
+ connection.setTelephonyConnectionDisconnected(
+ DisconnectCauseUtil.toTelecomDisconnectCause(cause, e.getMessage(),
+ phone.getPhoneId()));
+ connection.close();
+ }
+
private TelephonyConnection createConnectionFor(
Phone phone,
com.android.internal.telephony.Connection originalConnection,
boolean isOutgoing,
PhoneAccountHandle phoneAccountHandle,
String telecomCallId) {
+ return createConnectionFor(phone, originalConnection, isOutgoing, phoneAccountHandle,
+ telecomCallId, false);
+ }
+
+ private TelephonyConnection createConnectionFor(
+ Phone phone,
+ com.android.internal.telephony.Connection originalConnection,
+ boolean isOutgoing,
+ PhoneAccountHandle phoneAccountHandle,
+ String telecomCallId,
+ boolean isAdhocConference) {
TelephonyConnection returnConnection = null;
int phoneType = phone.getPhoneType();
if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
@@ -1592,8 +1825,10 @@
allowsMute, isOutgoing, telecomCallId);
}
if (returnConnection != null) {
- // Listen to Telephony specific callbacks from the connection
- returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
+ if (!isAdhocConference) {
+ // Listen to Telephony specific callbacks from the connection
+ returnConnection.addTelephonyConnectionListener(mTelephonyConnectionListener);
+ }
returnConnection.setVideoPauseSupported(
TelecomAccountRegistry.getInstance(this).isVideoPauseSupported(
phoneAccountHandle));
@@ -2133,6 +2368,78 @@
}
}
+ private boolean showDataDialog(Phone phone, String number) {
+ boolean ret = false;
+ final Context context = getApplicationContext();
+ String suppKey = MmiCodeUtil.getSuppServiceKey(number);
+ if (suppKey != null) {
+ boolean clirOverUtPrecautions = false;
+ boolean cfOverUtPrecautions = false;
+ boolean cbOverUtPrecautions = false;
+ boolean cwOverUtPrecautions = false;
+
+ CarrierConfigManager cfgManager = (CarrierConfigManager)
+ phone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (cfgManager != null) {
+ clirOverUtPrecautions = cfgManager.getConfigForSubId(phone.getSubId())
+ .getBoolean(CarrierConfigManager.KEY_CALLER_ID_OVER_UT_WARNING_BOOL);
+ cfOverUtPrecautions = cfgManager.getConfigForSubId(phone.getSubId())
+ .getBoolean(CarrierConfigManager.KEY_CALL_FORWARDING_OVER_UT_WARNING_BOOL);
+ cbOverUtPrecautions = cfgManager.getConfigForSubId(phone.getSubId())
+ .getBoolean(CarrierConfigManager.KEY_CALL_BARRING_OVER_UT_WARNING_BOOL);
+ cwOverUtPrecautions = cfgManager.getConfigForSubId(phone.getSubId())
+ .getBoolean(CarrierConfigManager.KEY_CALL_WAITING_OVER_UT_WARNING_BOOL);
+ }
+
+ boolean isSsOverUtPrecautions = SuppServicesUiUtil
+ .isSsOverUtPrecautions(context, phone);
+ if (isSsOverUtPrecautions) {
+ boolean showDialog = false;
+ if (suppKey == MmiCodeUtil.BUTTON_CLIR_KEY && clirOverUtPrecautions) {
+ showDialog = true;
+ } else if (suppKey == MmiCodeUtil.CALL_FORWARDING_KEY && cfOverUtPrecautions) {
+ showDialog = true;
+ } else if (suppKey == MmiCodeUtil.CALL_BARRING_KEY && cbOverUtPrecautions) {
+ showDialog = true;
+ } else if (suppKey == MmiCodeUtil.BUTTON_CW_KEY && cwOverUtPrecautions) {
+ showDialog = true;
+ }
+
+ if (showDialog) {
+ Log.d(this, "Creating UT Data enable dialog");
+ String message = SuppServicesUiUtil.makeMessage(context, suppKey, phone);
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ DialogInterface.OnClickListener networkSettingsClickListener =
+ new Dialog.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ ComponentName mobileNetworkSettingsComponent
+ = new ComponentName(
+ context.getString(
+ R.string.mobile_network_settings_package),
+ context.getString(
+ R.string.mobile_network_settings_class));
+ intent.setComponent(mobileNetworkSettingsComponent);
+ context.startActivity(intent);
+ }
+ };
+ Dialog dialog = builder.setMessage(message)
+ .setNeutralButton(context.getResources().getString(
+ R.string.settings_label),
+ networkSettingsClickListener)
+ .setPositiveButton(context.getResources().getString(
+ R.string.supp_service_over_ut_precautions_dialog_dismiss), null)
+ .create();
+ dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ dialog.show();
+ ret = true;
+ }
+ }
+ }
+ return ret;
+ }
+
/**
* Adds a {@link Conference} to the telephony ConnectionService and registers a listener for
* changes to the conference. Should be used instead of {@link #addConference(Conference)}.
diff --git a/src/com/android/services/telephony/rcs/RcsFeatureController.java b/src/com/android/services/telephony/rcs/RcsFeatureController.java
new file mode 100644
index 0000000..5094c57
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/RcsFeatureController.java
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony.rcs;
+
+import android.annotation.AnyThread;
+import android.content.Context;
+import android.net.Uri;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsRcsManager;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.ims.FeatureConnector;
+import com.android.ims.IFeatureConnector;
+import com.android.ims.RcsFeatureManager;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.imsphone.ImsRegistrationCallbackHelper;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Contains the RCS feature implementations that are associated with this slot's RcsFeature.
+ */
+@AnyThread
+public class RcsFeatureController {
+ private static final String LOG_TAG = "RcsFeatureController";
+
+ /**
+ * Interface used by RCS features that need to listen for when the associated service has been
+ * connected.
+ */
+ public interface Feature {
+ /**
+ * The RcsFeature has been connected to the framework and is ready.
+ */
+ void onRcsConnected(RcsFeatureManager manager);
+
+ /**
+ * The framework has lost the binding to the RcsFeature or it is in the process of changing.
+ */
+ void onRcsDisconnected();
+
+ /**
+ * The subscription associated with the slot this controller is bound to has changed or its
+ * carrier configuration has changed.
+ */
+ void onAssociatedSubscriptionUpdated(int subId);
+
+ /**
+ * Called when the feature should be destroyed.
+ */
+ void onDestroy();
+ }
+
+ /**
+ * Used to inject FeatureConnector instances for testing.
+ */
+ @VisibleForTesting
+ public interface FeatureConnectorFactory<T extends IFeatureConnector> {
+ /**
+ * @return a {@link FeatureConnector} associated for the given {@link IFeatureConnector}
+ * and slot id.
+ */
+ FeatureConnector<T> create(Context context, int slotId,
+ FeatureConnector.Listener<T> listener, Executor executor, String tag);
+ }
+
+ /**
+ * Used to inject ImsRegistrationCallbackHelper instances for testing.
+ */
+ @VisibleForTesting
+ public interface RegistrationHelperFactory {
+ /**
+ * @return an {@link ImsRegistrationCallbackHelper}, which helps manage IMS registration
+ * state.
+ */
+ ImsRegistrationCallbackHelper create(
+ ImsRegistrationCallbackHelper.ImsRegistrationUpdate cb, Executor executor);
+ }
+
+ private FeatureConnectorFactory<RcsFeatureManager> mFeatureFactory = FeatureConnector::new;
+ private RegistrationHelperFactory mRegistrationHelperFactory =
+ ImsRegistrationCallbackHelper::new;
+
+ private final Map<Class<?>, Feature> mFeatures = new ArrayMap<>();
+ private final Context mContext;
+ private final ImsRegistrationCallbackHelper mImsRcsRegistrationHelper;
+ private final int mSlotId;
+ private final Object mLock = new Object();
+ private FeatureConnector<RcsFeatureManager> mFeatureConnector;
+ private RcsFeatureManager mFeatureManager;
+
+ private FeatureConnector.Listener<RcsFeatureManager> mFeatureConnectorListener =
+ new FeatureConnector.Listener<RcsFeatureManager>() {
+ @Override
+ public RcsFeatureManager getFeatureManager() {
+ return new RcsFeatureManager(mContext, mSlotId);
+ }
+
+ @Override
+ public void connectionReady(RcsFeatureManager manager)
+ throws com.android.ims.ImsException {
+ if (manager == null) {
+ logw("connectionReady returned null RcsFeatureManager");
+ return;
+ }
+ try {
+ // May throw ImsException if for some reason the connection to the
+ // ImsService is gone.
+ setupConnectionToService(manager);
+ } catch (ImsException e) {
+ // Use deprecated Exception for compatibility.
+ throw new com.android.ims.ImsException(e.getMessage(),
+ ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
+ }
+ updateConnectionStatus(manager);
+ }
+
+ @Override
+ public void connectionUnavailable() {
+ // Call before disabling connection to manager.
+ removeConnectionToService();
+ updateConnectionStatus(null /*manager*/);
+ }
+ };
+
+ private ImsRegistrationCallbackHelper.ImsRegistrationUpdate mRcsRegistrationUpdate = new
+ ImsRegistrationCallbackHelper.ImsRegistrationUpdate() {
+ @Override
+ public void handleImsRegistered(int imsRadioTech) {
+ }
+
+ @Override
+ public void handleImsRegistering(int imsRadioTech) {
+ }
+
+ @Override
+ public void handleImsUnregistered(ImsReasonInfo imsReasonInfo) {
+ }
+
+ @Override
+ public void handleImsSubscriberAssociatedUriChanged(Uri[] uris) {
+ }
+ };
+
+ public RcsFeatureController(Context context, int slotId) {
+ mContext = context;
+ mSlotId = slotId;
+ mImsRcsRegistrationHelper = mRegistrationHelperFactory.create(mRcsRegistrationUpdate,
+ mContext.getMainExecutor());
+ }
+
+ /**
+ * Should only be used to inject registration helpers for testing.
+ */
+ @VisibleForTesting
+ public RcsFeatureController(Context context, int slotId, RegistrationHelperFactory f) {
+ mContext = context;
+ mSlotId = slotId;
+ mRegistrationHelperFactory = f;
+ mImsRcsRegistrationHelper = mRegistrationHelperFactory.create(mRcsRegistrationUpdate,
+ mContext.getMainExecutor());
+ }
+
+ /**
+ * This method should be called after constructing an instance of this class to start the
+ * connection process to the associated RcsFeature.
+ */
+ public void connect() {
+ synchronized (mLock) {
+ if (mFeatureConnector != null) return;
+ mFeatureConnector = mFeatureFactory.create(mContext, mSlotId, mFeatureConnectorListener,
+ mContext.getMainExecutor(), LOG_TAG);
+ mFeatureConnector.connect();
+ }
+ }
+
+ /**
+ * Adds a {@link Feature} to be tracked by this FeatureController.
+ */
+ public <T extends Feature> void addFeature(T connector, Class<T> clazz) {
+ synchronized (mLock) {
+ mFeatures.put(clazz, connector);
+ }
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager != null) {
+ connector.onRcsConnected(manager);
+ } else {
+ connector.onRcsDisconnected();
+ }
+ }
+
+ /**
+ * @return The RCS feature implementation tracked by this controller.
+ */
+ @SuppressWarnings("unchecked")
+ public <T> T getFeature(Class<T> clazz) {
+ synchronized (mLock) {
+ return (T) mFeatures.get(clazz);
+ }
+ }
+
+ /**
+ * Removes the feature associated with this class.
+ */
+ public <T> void removeFeature(Class<T> clazz) {
+ synchronized (mLock) {
+ RcsFeatureController.Feature feature = mFeatures.remove(clazz);
+ feature.onDestroy();
+ }
+ }
+
+ /**
+ * @return true if this controller has features it is actively tracking.
+ */
+ public boolean hasActiveFeatures() {
+ synchronized (mLock) {
+ return mFeatures.size() > 0;
+ }
+ }
+
+ /**
+ * Update the subscription associated with this controller.
+ */
+ public void updateAssociatedSubscription(int newSubId) {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager != null) {
+ try {
+ manager.updateCapabilities();
+ } catch (ImsException e) {
+ Log.w(LOG_TAG, "associatedSubscriptionChanged failed:" + e);
+ }
+ }
+ synchronized (mLock) {
+ for (Feature c : mFeatures.values()) {
+ c.onAssociatedSubscriptionUpdated(newSubId);
+ }
+ }
+ }
+
+ /**
+ * Call before this controller is destroyed to tear down associated features.
+ */
+ public void destroy() {
+ synchronized (mLock) {
+ Log.i(LOG_TAG, "destroy: slotId=" + mSlotId);
+ if (mFeatureConnector != null) {
+ mFeatureConnector.disconnect();
+ }
+ for (Feature c : mFeatures.values()) {
+ c.onRcsDisconnected();
+ c.onDestroy();
+ }
+ mFeatures.clear();
+ }
+ }
+
+ @VisibleForTesting
+ public void setFeatureConnectorFactory(FeatureConnectorFactory factory) {
+ mFeatureFactory = factory;
+ }
+
+ /**
+ * Add a {@link RegistrationManager.RegistrationCallback} callback that gets called when IMS
+ * registration has changed for a specific subscription.
+ */
+ public void registerImsRegistrationCallback(int subId, IImsRegistrationCallback callback)
+ throws ImsException {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager == null) {
+ throw new ImsException("Service is not available",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ manager.registerImsRegistrationCallback(subId, callback);
+ }
+
+ /**
+ * Removes a previously registered {@link RegistrationManager.RegistrationCallback} callback
+ * that is associated with a specific subscription.
+ */
+ public void unregisterImsRegistrationCallback(int subId, IImsRegistrationCallback callback) {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager != null) {
+ manager.unregisterImsRegistrationCallback(subId, callback);
+ }
+ }
+
+ /**
+ * Register an {@link ImsRcsManager.AvailabilityCallback} with the associated RcsFeature,
+ * which will provide availability updates.
+ */
+ public void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback)
+ throws ImsException {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager == null) {
+ throw new ImsException("Service is not available",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ manager.registerRcsAvailabilityCallback(subId, callback);
+ }
+
+ /**
+ * Remove a registered {@link ImsRcsManager.AvailabilityCallback} from the RcsFeature.
+ */
+ public void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback callback) {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager != null) {
+ manager.unregisterRcsAvailabilityCallback(subId, callback);
+ }
+ }
+
+ /**
+ * Query for the specific capability.
+ */
+ public boolean isCapable(int capability, int radioTech)
+ throws android.telephony.ims.ImsException {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager == null) {
+ throw new ImsException("Service is not available",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ return manager.isCapable(capability, radioTech);
+ }
+
+ /**
+ * Query the availability of an IMS RCS capability.
+ */
+ public boolean isAvailable(int capability) throws android.telephony.ims.ImsException {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager == null) {
+ throw new ImsException("Service is not available",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ return manager.isAvailable(capability);
+ }
+
+ /**
+ * Get the IMS RCS registration technology for this Phone.
+ */
+ public void getRegistrationTech(Consumer<Integer> callback) {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager != null) {
+ manager.getImsRegistrationTech(callback);
+ }
+ callback.accept(ImsRegistrationImplBase.REGISTRATION_TECH_NONE);
+ }
+
+ /**
+ * Retrieve the current RCS registration state.
+ */
+ public void getRegistrationState(Consumer<Integer> callback) {
+ callback.accept(mImsRcsRegistrationHelper.getImsRegistrationState());
+ }
+
+ private void setupConnectionToService(RcsFeatureManager manager) throws ImsException {
+ // Open persistent listener connection, sends RcsFeature#onFeatureReady.
+ manager.openConnection();
+ manager.updateCapabilities();
+ manager.registerImsRegistrationCallback(mImsRcsRegistrationHelper.getCallbackBinder());
+ }
+
+ private void removeConnectionToService() {
+ RcsFeatureManager manager = getFeatureManager();
+ if (manager != null) {
+ manager.unregisterImsRegistrationCallback(
+ mImsRcsRegistrationHelper.getCallbackBinder());
+ // Remove persistent listener connection.
+ manager.releaseConnection();
+ }
+ mImsRcsRegistrationHelper.reset();
+ }
+
+ private void updateConnectionStatus(RcsFeatureManager manager) {
+ synchronized (mLock) {
+ mFeatureManager = manager;
+ if (mFeatureManager != null) {
+ for (Feature c : mFeatures.values()) {
+ c.onRcsConnected(manager);
+ }
+ } else {
+ for (Feature c : mFeatures.values()) {
+ c.onRcsDisconnected();
+ }
+ }
+ }
+ }
+
+ private RcsFeatureManager getFeatureManager() {
+ synchronized (mLock) {
+ return mFeatureManager;
+ }
+ }
+
+ /**
+ * Dump this controller's instance information for usage in dumpsys.
+ */
+ public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
+ IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
+ pw.print("slotId=");
+ pw.println(mSlotId);
+ pw.print("RegistrationState=");
+ pw.println(mImsRcsRegistrationHelper.getImsRegistrationState());
+ pw.print("connected=");
+ synchronized (mLock) {
+ pw.println(mFeatureManager != null);
+ }
+ }
+
+ private void logw(String log) {
+ Log.w(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private StringBuilder getLogPrefix() {
+ StringBuilder sb = new StringBuilder("[");
+ sb.append(mSlotId);
+ sb.append("] ");
+ return sb;
+ }
+}
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
new file mode 100644
index 0000000..c85e9a9
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony.rcs;
+
+import android.annotation.AnyThread;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncResult;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.PhoneConfigurationManager;
+import com.android.internal.util.IndentingPrintWriter;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Singleton service setup to manage RCS related services that the platform provides such as User
+ * Capability Exchange.
+ */
+@AnyThread
+public class TelephonyRcsService {
+
+ private static final String LOG_TAG = "TelephonyRcsService";
+
+ /**
+ * Used to inject RcsFeatureController and UserCapabilityExchangeImpl instances for testing.
+ */
+ @VisibleForTesting
+ public interface FeatureFactory {
+ /**
+ * @return an {@link RcsFeatureController} assoicated with the slot specified.
+ */
+ RcsFeatureController createController(Context context, int slotId);
+
+ /**
+ * @return an instance of {@link UserCapabilityExchangeImpl} associated with the slot
+ * specified.
+ */
+ UserCapabilityExchangeImpl createUserCapabilityExchange(Context context, int slotId,
+ int subId);
+ }
+
+ private FeatureFactory mFeatureFactory = new FeatureFactory() {
+ @Override
+ public RcsFeatureController createController(Context context, int slotId) {
+ return new RcsFeatureController(context, slotId);
+ }
+
+ @Override
+ public UserCapabilityExchangeImpl createUserCapabilityExchange(Context context, int slotId,
+ int subId) {
+ return new UserCapabilityExchangeImpl(context, slotId, subId);
+ }
+ };
+
+ // Notifies this service that there has been a change in available slots.
+ private static final int HANDLER_MSIM_CONFIGURATION_CHANGE = 1;
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+ private int mNumSlots;
+
+ // Maps slot ID -> RcsFeatureController.
+ private SparseArray<RcsFeatureController> mFeatureControllers;
+
+ private BroadcastReceiver mCarrierConfigChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent == null) {
+ return;
+ }
+ if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(intent.getAction())) {
+ Bundle bundle = intent.getExtras();
+ if (bundle == null) {
+ return;
+ }
+ int slotId = bundle.getInt(CarrierConfigManager.EXTRA_SLOT_INDEX,
+ SubscriptionManager.INVALID_PHONE_INDEX);
+ int subId = bundle.getInt(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ updateFeatureControllerSubscription(slotId, subId);
+ }
+ }
+ };
+
+ private Handler mHandler = new Handler(Looper.getMainLooper(), (msg) -> {
+ switch (msg.what) {
+ case HANDLER_MSIM_CONFIGURATION_CHANGE: {
+ AsyncResult result = (AsyncResult) msg.obj;
+ Integer numSlots = (Integer) result.result;
+ if (numSlots == null) {
+ Log.w(LOG_TAG, "msim config change with null num slots.");
+ break;
+ }
+ updateFeatureControllerSize(numSlots);
+ break;
+ }
+ default:
+ return false;
+ }
+ return true;
+ });
+
+ public TelephonyRcsService(Context context, int numSlots) {
+ mContext = context;
+ mNumSlots = numSlots;
+ mFeatureControllers = new SparseArray<>(numSlots);
+ }
+
+ /**
+ * @return the {@link RcsFeatureController} associated with the given slot.
+ */
+ public RcsFeatureController getFeatureController(int slotId) {
+ synchronized (mLock) {
+ return mFeatureControllers.get(slotId);
+ }
+ }
+
+ /**
+ * Called after instance creation to initialize internal structures as well as register for
+ * system callbacks.
+ */
+ public void initialize() {
+ updateFeatureControllerSize(mNumSlots);
+
+ PhoneConfigurationManager.registerForMultiSimConfigChange(mHandler,
+ HANDLER_MSIM_CONFIGURATION_CHANGE, null);
+ mContext.registerReceiver(mCarrierConfigChangedReceiver, new IntentFilter(
+ CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED));
+ }
+
+ @VisibleForTesting
+ public void setFeatureFactory(FeatureFactory f) {
+ mFeatureFactory = f;
+ }
+
+ /**
+ * Update the number of {@link RcsFeatureController}s that are created based on the number of
+ * active slots on the device.
+ */
+ @VisibleForTesting
+ public void updateFeatureControllerSize(int newNumSlots) {
+ synchronized (mLock) {
+ int oldNumSlots = mFeatureControllers.size();
+ if (oldNumSlots == newNumSlots) {
+ return;
+ }
+ Log.i(LOG_TAG, "updateFeatureControllers: oldSlots=" + oldNumSlots + ", newNumSlots="
+ + newNumSlots);
+ mNumSlots = newNumSlots;
+ if (oldNumSlots < newNumSlots) {
+ for (int i = oldNumSlots; i < newNumSlots; i++) {
+ RcsFeatureController c = constructFeatureController(i);
+ // Do not add feature controllers for inactive subscriptions
+ if (c.hasActiveFeatures()) {
+ mFeatureControllers.put(i, c);
+ }
+ }
+ } else {
+ for (int i = (oldNumSlots - 1); i > (newNumSlots - 1); i--) {
+ RcsFeatureController c = mFeatureControllers.get(i);
+ if (c != null) {
+ mFeatureControllers.remove(i);
+ c.destroy();
+ }
+ }
+ }
+ }
+ }
+
+ private void updateFeatureControllerSubscription(int slotId, int newSubId) {
+ synchronized (mLock) {
+ RcsFeatureController f = mFeatureControllers.get(slotId);
+ Log.i(LOG_TAG, "updateFeatureControllerSubscription: slotId=" + slotId + " newSubId="
+ + newSubId + ", existing feature=" + (f != null));
+ if (SubscriptionManager.isValidSubscriptionId(newSubId)) {
+ if (f == null) {
+ // A controller doesn't exist for this slot yet.
+ f = mFeatureFactory.createController(mContext, slotId);
+ updateSupportedFeatures(f, slotId, newSubId);
+ if (f.hasActiveFeatures()) mFeatureControllers.put(slotId, f);
+ } else {
+ updateSupportedFeatures(f, slotId, newSubId);
+ // Do not keep an empty container around.
+ if (!f.hasActiveFeatures()) {
+ f.destroy();
+ mFeatureControllers.remove(slotId);
+ }
+ }
+ }
+ if (f != null) f.updateAssociatedSubscription(newSubId);
+ }
+ }
+
+ private RcsFeatureController constructFeatureController(int slotId) {
+ RcsFeatureController c = mFeatureFactory.createController(mContext, slotId);
+ int subId = getSubscriptionFromSlot(slotId);
+ updateSupportedFeatures(c, slotId, subId);
+ return c;
+ }
+
+ private void updateSupportedFeatures(RcsFeatureController c, int slotId, int subId) {
+ if (doesSubscriptionSupportPresence(subId)) {
+ if (c.getFeature(UserCapabilityExchangeImpl.class) == null) {
+ c.addFeature(mFeatureFactory.createUserCapabilityExchange(mContext, slotId, subId),
+ UserCapabilityExchangeImpl.class);
+ }
+ } else {
+ if (c.getFeature(UserCapabilityExchangeImpl.class) != null) {
+ c.removeFeature(UserCapabilityExchangeImpl.class);
+ }
+ }
+ // Only start the connection procedure if we have active features.
+ if (c.hasActiveFeatures()) c.connect();
+ }
+
+ private boolean doesSubscriptionSupportPresence(int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) return false;
+ CarrierConfigManager carrierConfigManager =
+ mContext.getSystemService(CarrierConfigManager.class);
+ if (carrierConfigManager == null) return false;
+ boolean supportsUce = carrierConfigManager.getConfigForSubId(subId).getBoolean(
+ CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL);
+ supportsUce |= carrierConfigManager.getConfigForSubId(subId).getBoolean(
+ CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL);
+ return supportsUce;
+ }
+
+
+ private int getSubscriptionFromSlot(int slotId) {
+ SubscriptionManager manager = mContext.getSystemService(SubscriptionManager.class);
+ if (manager == null) {
+ Log.w(LOG_TAG, "Couldn't find SubscriptionManager for slotId=" + slotId);
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+ int[] subIds = manager.getSubscriptionIds(slotId);
+ if (subIds != null && subIds.length > 0) {
+ return subIds[0];
+ }
+ return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ }
+
+ /**
+ * Dump this instance into a readable format for dumpsys usage.
+ */
+ public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
+ IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " ");
+ pw.println("RcsFeatureControllers:");
+ pw.increaseIndent();
+ synchronized (mLock) {
+ for (int i = 0; i < mNumSlots; i++) {
+ RcsFeatureController f = mFeatureControllers.get(i);
+ pw.increaseIndent();
+ f.dump(fd, printWriter, args);
+ pw.decreaseIndent();
+ }
+ }
+ pw.decreaseIndent();
+ }
+}
diff --git a/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
new file mode 100644
index 0000000..ac8f9bf
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony.rcs;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.ims.RcsContactUceCapability;
+import android.telephony.ims.RcsUceAdapter;
+import android.telephony.ims.aidl.IRcsUceControllerCallback;
+import android.util.Log;
+
+import com.android.ims.RcsFeatureManager;
+import com.android.ims.ResultCode;
+import com.android.phone.R;
+import com.android.service.ims.presence.ContactCapabilityResponse;
+import com.android.service.ims.presence.PresenceBase;
+import com.android.service.ims.presence.PresencePublication;
+import com.android.service.ims.presence.PresencePublisher;
+import com.android.service.ims.presence.PresenceSubscriber;
+import com.android.service.ims.presence.SubscribePublisher;
+
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/**
+ * Implements User Capability Exchange using Presence.
+ */
+public class UserCapabilityExchangeImpl implements RcsFeatureController.Feature, SubscribePublisher,
+ PresencePublisher {
+
+ private static final String LOG_TAG = "RcsUceImpl";
+
+ private int mSlotId;
+ private int mSubId;
+
+ private final PresencePublication mPresencePublication;
+ private final PresenceSubscriber mPresenceSubscriber;
+
+ private final ConcurrentHashMap<Integer, IRcsUceControllerCallback> mPendingCapabilityRequests =
+ new ConcurrentHashMap<>();
+
+ UserCapabilityExchangeImpl(Context context, int slotId, int subId) {
+ mSlotId = slotId;
+ mSubId = subId;
+ logi("created");
+
+ String[] volteError = context.getResources().getStringArray(
+ R.array.config_volte_provision_error_on_publish_response);
+ String[] rcsError = context.getResources().getStringArray(
+ R.array.config_rcs_provision_error_on_publish_response);
+
+ // Initialize PresencePublication
+ mPresencePublication = new PresencePublication(null /*PresencePublisher*/, context,
+ volteError, rcsError);
+ // Initialize PresenceSubscriber
+ mPresenceSubscriber = new PresenceSubscriber(null /*SubscribePublisher*/, context,
+ volteError, rcsError);
+
+ onAssociatedSubscriptionUpdated(mSubId);
+ }
+
+
+ // Runs on main thread.
+ @Override
+ public void onRcsConnected(RcsFeatureManager rcsFeatureManager) {
+ logi("onRcsConnected");
+ mPresencePublication.updatePresencePublisher(this);
+ mPresenceSubscriber.updatePresenceSubscriber(this);
+ }
+
+ // Runs on main thread.
+ @Override
+ public void onRcsDisconnected() {
+ logi("onRcsDisconnected");
+ mPresencePublication.removePresencePublisher();
+ mPresenceSubscriber.removePresenceSubscriber();
+ }
+
+ // Runs on main thread.
+ @Override
+ public void onAssociatedSubscriptionUpdated(int subId) {
+ mPresencePublication.handleAssociatedSubscriptionChanged(subId);
+ mPresenceSubscriber.handleAssociatedSubscriptionChanged(subId);
+ }
+
+ /**
+ * Should be called before destroying this instance.
+ * This instance is not usable after this method is called.
+ */
+ // Called on main thread.
+ public void onDestroy() {
+ onRcsDisconnected();
+ }
+
+ /**
+ * @return the UCE Publish state.
+ */
+ // May happen on a Binder thread, PresencePublication locks to get result.
+ public int getUcePublishState() {
+ int publishState = mPresencePublication.getPublishState();
+ return toUcePublishState(publishState);
+ }
+
+ /**
+ * Perform a capabilities request and call {@link IRcsUceControllerCallback} with the result.
+ */
+ // May happen on a Binder thread, PresenceSubscriber locks when requesting Capabilities.
+ public void requestCapabilities(List<Uri> contactNumbers, IRcsUceControllerCallback c) {
+ List<String> numbers = contactNumbers.stream()
+ .map(UserCapabilityExchangeImpl::getNumberFromUri).collect(Collectors.toList());
+ int taskId = mPresenceSubscriber.requestCapability(numbers,
+ new ContactCapabilityResponse() {
+ @Override
+ public void onSuccess(int reqId) {
+ logi("onSuccess called for reqId:" + reqId);
+ }
+
+ @Override
+ public void onError(int reqId, int resultCode) {
+ IRcsUceControllerCallback c = mPendingCapabilityRequests.remove(reqId);
+ try {
+ if (c != null) {
+ c.onError(toUceError(resultCode));
+ } else {
+ logw("onError called for unknown reqId:" + reqId);
+ }
+ } catch (RemoteException e) {
+ logi("Calling back to dead service");
+ }
+ }
+
+ @Override
+ public void onFinish(int reqId) {
+ logi("onFinish called for reqId:" + reqId);
+ }
+
+ @Override
+ public void onTimeout(int reqId) {
+ IRcsUceControllerCallback c = mPendingCapabilityRequests.remove(reqId);
+ try {
+ if (c != null) {
+ c.onError(RcsUceAdapter.ERROR_REQUEST_TIMEOUT);
+ } else {
+ logw("onTimeout called for unknown reqId:" + reqId);
+ }
+ } catch (RemoteException e) {
+ logi("Calling back to dead service");
+ }
+ }
+
+ @Override
+ public void onCapabilitiesUpdated(int reqId,
+ List<RcsContactUceCapability> contactCapabilities,
+ boolean updateLastTimestamp) {
+ IRcsUceControllerCallback c = mPendingCapabilityRequests.remove(reqId);
+ try {
+ if (c != null) {
+ c.onCapabilitiesReceived(contactCapabilities);
+ } else {
+ logw("onCapabilitiesUpdated, unknown reqId:" + reqId);
+ }
+ } catch (RemoteException e) {
+ logw("onCapabilitiesUpdated on dead service");
+ }
+ }
+ });
+ if (taskId < 0) {
+ try {
+ c.onError(toUceError(taskId));
+ return;
+ } catch (RemoteException e) {
+ logi("Calling back to dead service");
+ }
+ }
+ mPendingCapabilityRequests.put(taskId, c);
+ }
+
+ @Override
+ public int getPublisherState() {
+ return 0;
+ }
+
+ @Override
+ public int requestPublication(RcsContactUceCapability capabilities, String contactUri,
+ int taskId) {
+ return 0;
+ }
+
+ @Override
+ public int requestCapability(String[] formatedContacts, int taskId) {
+ return 0;
+ }
+
+ @Override
+ public int requestAvailability(String formattedContact, int taskId) {
+ return 0;
+ }
+
+ @Override
+ public int getStackStatusForCapabilityRequest() {
+ return 0;
+ }
+
+ @Override
+ public void updatePublisherState(int publishState) {
+
+ }
+
+ private static String getNumberFromUri(Uri uri) {
+ String number = uri.getSchemeSpecificPart();
+ String[] numberParts = number.split("[@;:]");
+
+ if (numberParts.length == 0) {
+ return null;
+ }
+ return numberParts[0];
+ }
+
+ private static int toUcePublishState(int publishState) {
+ switch (publishState) {
+ case PresenceBase.PUBLISH_STATE_200_OK:
+ return RcsUceAdapter.PUBLISH_STATE_OK;
+ case PresenceBase.PUBLISH_STATE_NOT_PUBLISHED:
+ return RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED;
+ case PresenceBase.PUBLISH_STATE_VOLTE_PROVISION_ERROR:
+ return RcsUceAdapter.PUBLISH_STATE_VOLTE_PROVISION_ERROR;
+ case PresenceBase.PUBLISH_STATE_RCS_PROVISION_ERROR:
+ return RcsUceAdapter.PUBLISH_STATE_RCS_PROVISION_ERROR;
+ case PresenceBase.PUBLISH_STATE_REQUEST_TIMEOUT:
+ return RcsUceAdapter.PUBLISH_STATE_REQUEST_TIMEOUT;
+ case PresenceBase.PUBLISH_STATE_OTHER_ERROR:
+ return RcsUceAdapter.PUBLISH_STATE_OTHER_ERROR;
+ default:
+ return RcsUceAdapter.PUBLISH_STATE_OTHER_ERROR;
+ }
+ }
+
+ private static int toUceError(int resultCode) {
+ switch (resultCode) {
+ case ResultCode.SUBSCRIBE_NOT_REGISTERED:
+ return RcsUceAdapter.ERROR_NOT_REGISTERED;
+ case ResultCode.SUBSCRIBE_REQUEST_TIMEOUT:
+ return RcsUceAdapter.ERROR_REQUEST_TIMEOUT;
+ case ResultCode.SUBSCRIBE_FORBIDDEN:
+ return RcsUceAdapter.ERROR_FORBIDDEN;
+ case ResultCode.SUBSCRIBE_NOT_FOUND:
+ return RcsUceAdapter.ERROR_NOT_FOUND;
+ case ResultCode.SUBSCRIBE_TOO_LARGE:
+ return RcsUceAdapter.ERROR_REQUEST_TOO_LARGE;
+ case ResultCode.SUBSCRIBE_INSUFFICIENT_MEMORY:
+ return RcsUceAdapter.ERROR_INSUFFICIENT_MEMORY;
+ case ResultCode.SUBSCRIBE_LOST_NETWORK:
+ return RcsUceAdapter.ERROR_LOST_NETWORK;
+ case ResultCode.SUBSCRIBE_ALREADY_IN_QUEUE:
+ return RcsUceAdapter.ERROR_ALREADY_IN_QUEUE;
+ default:
+ return RcsUceAdapter.ERROR_GENERIC_FAILURE;
+ }
+ }
+
+ private void logi(String log) {
+ Log.i(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private void logw(String log) {
+ Log.w(LOG_TAG, getLogPrefix().append(log).toString());
+ }
+
+ private StringBuilder getLogPrefix() {
+ StringBuilder builder = new StringBuilder("[");
+ builder.append(mSlotId);
+ builder.append("->");
+ builder.append(mSubId);
+ builder.append("] ");
+ return builder;
+ }
+}
diff --git a/testapps/Android.mk b/testapps/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/testapps/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/testapps/EmbmsServiceTestApp/Android.bp b/testapps/EmbmsServiceTestApp/Android.bp
new file mode 100644
index 0000000..e4a54cb
--- /dev/null
+++ b/testapps/EmbmsServiceTestApp/Android.bp
@@ -0,0 +1,11 @@
+// Build the Sample Embms Services
+android_app {
+ name: "EmbmsTestService",
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+ privileged: true,
+ // Uncomment the following line to build the EmbmsTestService
+ // into the userdebug build:
+ // LOCAL_MODULE_TAGS := debug
+}
diff --git a/testapps/EmbmsServiceTestApp/Android.mk b/testapps/EmbmsServiceTestApp/Android.mk
deleted file mode 100644
index 29b8112..0000000
--- a/testapps/EmbmsServiceTestApp/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# Build the Sample Embms Services
-include $(CLEAR_VARS)
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := EmbmsTestService
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-# Uncomment the following line to build the EmbmsTestService into the userdebug build.
-# LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/EmbmsTestDownloadApp/Android.bp b/testapps/EmbmsTestDownloadApp/Android.bp
new file mode 100644
index 0000000..63f4e83
--- /dev/null
+++ b/testapps/EmbmsTestDownloadApp/Android.bp
@@ -0,0 +1,12 @@
+src_dirs = ["src"]
+res_dirs = ["res"]
+android_test {
+ name: "EmbmsTestDownloadApp",
+ static_libs: [
+ "androidx.recyclerview_recyclerview",
+ "androidx.legacy_legacy-support-v4",
+ ],
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/testapps/EmbmsTestDownloadApp/Android.mk b/testapps/EmbmsTestDownloadApp/Android.mk
deleted file mode 100644
index bd53d79..0000000
--- a/testapps/EmbmsTestDownloadApp/Android.mk
+++ /dev/null
@@ -1,22 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# Build the Sample Embms Download frontend
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- androidx.recyclerview_recyclerview \
- androidx.legacy_legacy-support-v4
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := EmbmsTestDownloadApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/EmbmsTestStreamingApp/Android.bp b/testapps/EmbmsTestStreamingApp/Android.bp
new file mode 100644
index 0000000..814c5ca
--- /dev/null
+++ b/testapps/EmbmsTestStreamingApp/Android.bp
@@ -0,0 +1,7 @@
+android_test {
+ name: "EmbmsTestStreamingApp",
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+ //LOCAL_MODULE_TAGS := debug
+}
diff --git a/testapps/EmbmsTestStreamingApp/Android.mk b/testapps/EmbmsTestStreamingApp/Android.mk
deleted file mode 100644
index f574990..0000000
--- a/testapps/EmbmsTestStreamingApp/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# Build the Sample Embms Streaming frontend
-include $(CLEAR_VARS)
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := EmbmsTestStreamingApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-#LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/ImsTestService/Android.bp b/testapps/ImsTestService/Android.bp
new file mode 100644
index 0000000..a0b4edb
--- /dev/null
+++ b/testapps/ImsTestService/Android.bp
@@ -0,0 +1,13 @@
+android_app {
+ name: "ImsTestApp",
+ static_libs: [
+ "androidx.legacy_legacy-support-v4",
+ "androidx.appcompat_appcompat",
+ "androidx.recyclerview_recyclerview",
+ "androidx.cardview_cardview",
+ ],
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+ privileged: true,
+}
diff --git a/testapps/ImsTestService/Android.mk b/testapps/ImsTestService/Android.mk
deleted file mode 100644
index 2869c86..0000000
--- a/testapps/ImsTestService/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_ANDROID_LIBRARIES := \
- androidx.legacy_legacy-support-v4 \
- androidx.appcompat_appcompat \
- androidx.recyclerview_recyclerview \
- androidx.cardview_cardview
-
-LOCAL_USE_AAPT2 := true
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := ImsTestApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/SmsManagerTestApp/Android.bp b/testapps/SmsManagerTestApp/Android.bp
new file mode 100644
index 0000000..5333eab
--- /dev/null
+++ b/testapps/SmsManagerTestApp/Android.bp
@@ -0,0 +1,5 @@
+android_app {
+ name: "SmsManagerTestApp",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/testapps/SmsManagerTestApp/Android.mk b/testapps/SmsManagerTestApp/Android.mk
deleted file mode 100644
index 307366b..0000000
--- a/testapps/SmsManagerTestApp/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := SmsManagerTestApp
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/TelephonyManagerTestApp/Android.bp b/testapps/TelephonyManagerTestApp/Android.bp
new file mode 100644
index 0000000..8a37c99
--- /dev/null
+++ b/testapps/TelephonyManagerTestApp/Android.bp
@@ -0,0 +1,7 @@
+android_test {
+ name: "TelephonyManagerTestApp",
+ srcs: ["src/**/*.java"],
+ javacflags: ["-parameters"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/testapps/TelephonyManagerTestApp/Android.mk b/testapps/TelephonyManagerTestApp/Android.mk
deleted file mode 100644
index 290b261..0000000
--- a/testapps/TelephonyManagerTestApp/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_JAVACFLAGS := -parameters
-
-LOCAL_PACKAGE_NAME := TelephonyManagerTestApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_PACKAGE)
diff --git a/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java b/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java
index 097c90a..ccb5639 100644
--- a/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java
+++ b/testapps/TelephonyManagerTestApp/src/com/android/phone/testapps/telephonymanagertestapp/ParameterParser.java
@@ -19,12 +19,19 @@
import android.content.Context;
import android.telephony.NumberVerificationCallback;
import android.telephony.PhoneNumberRange;
+import android.telephony.RadioAccessSpecifier;
+import android.text.TextUtils;
import android.widget.Toast;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.stream.Collectors;
class ParameterParser {
private static ParameterParser sInstance;
@@ -42,6 +49,9 @@
put(PhoneNumberRange.class, ParameterParser::parsePhoneNumberRange);
put(Executor.class, s -> parseExecutor(s));
put(NumberVerificationCallback.class, s -> parseNumberVerificationCallback(s));
+ put(Consumer.class, s -> parseConsumer(s));
+ put(List.class, s -> parseList(s));
+ put(RadioAccessSpecifier.class, s -> parseRadioAccessSpecifier(s));
}};
private ParameterParser(Context context) {
@@ -49,6 +59,7 @@
}
Object executeParser(Class type, String input) {
+ if ("null".equals(input)) return null;
return mParsers.getOrDefault(type, s -> null).apply(input);
}
@@ -64,6 +75,57 @@
return mContext.getMainExecutor();
}
+ private Consumer parseConsumer(String input) {
+ return o -> Toast.makeText(mContext, "Consumer: " + String.valueOf(o), Toast.LENGTH_SHORT)
+ .show();
+ }
+
+ /**
+ * input format: (ran)/(band1)+(band2)+.../(chan1)+(chan2)+...
+ * @return
+ */
+ private RadioAccessSpecifier parseRadioAccessSpecifier(String input) {
+ String[] parts = input.split("/");
+ int ran = Integer.parseInt(parts[0]);
+ String[] bandStrings = parts[1].split("\\+");
+ int[] bands = new int[bandStrings.length];
+ String[] chanStrings = parts[2].split("\\+");
+ int[] chans = new int[chanStrings.length];
+
+ for (int i = 0; i < bands.length; i++) {
+ bands[i] = Integer.parseInt(bandStrings[i]);
+ }
+
+ for (int i = 0; i < chans.length; i++) {
+ chans[i] = Integer.parseInt(chanStrings[i]);
+ }
+ return new RadioAccessSpecifier(ran, bands, chans);
+ }
+
+ private List parseList(String input) {
+ if (TextUtils.isEmpty(input)) {
+ return Collections.emptyList();
+ }
+ String[] components = input.split(" ");
+ String className = components[0];
+ Class c;
+ try {
+ c = mContext.getClassLoader().loadClass(className);
+ } catch (ClassNotFoundException e) {
+ Toast.makeText(mContext, "Invalid class " + className,
+ Toast.LENGTH_SHORT).show();
+ return null;
+ }
+ if (!mParsers.containsKey(c)) {
+ Toast.makeText(mContext, "Cannot parse " + className,
+ Toast.LENGTH_SHORT).show();
+ return null;
+ }
+ return Arrays.stream(components).skip(1)
+ .map(mParsers.get(c))
+ .collect(Collectors.toList());
+ }
+
private NumberVerificationCallback parseNumberVerificationCallback(String input) {
return new NumberVerificationCallback() {
@Override
diff --git a/testapps/TelephonyRegistryTestApp/Android.bp b/testapps/TelephonyRegistryTestApp/Android.bp
new file mode 100644
index 0000000..fec5286
--- /dev/null
+++ b/testapps/TelephonyRegistryTestApp/Android.bp
@@ -0,0 +1,7 @@
+android_test {
+ name: "TelephonyRegistryTestApp",
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+ //LOCAL_MODULE_TAGS := debug
+}
diff --git a/testapps/TelephonyRegistryTestApp/Android.mk b/testapps/TelephonyRegistryTestApp/Android.mk
deleted file mode 100644
index 8c0d286..0000000
--- a/testapps/TelephonyRegistryTestApp/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-src_dirs := src
-res_dirs := res
-
-LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
-LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
-LOCAL_PACKAGE_NAME := TelephonyRegistryTestApp
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-#LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_PACKAGE)
diff --git a/tests/Android.bp b/tests/Android.bp
index 22b40b5..7ed234e 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -25,6 +25,7 @@
"telephony-common",
"android.test.base",
"ims-common",
+ "android.test.mock",
],
platform_apis: true,
certificate: "platform",
diff --git a/tests/src/com/android/TelephonyTestBase.java b/tests/src/com/android/TelephonyTestBase.java
index 01267d8..86c5402 100644
--- a/tests/src/com/android/TelephonyTestBase.java
+++ b/tests/src/com/android/TelephonyTestBase.java
@@ -16,6 +16,8 @@
package com.android;
+import static org.mockito.Mockito.spy;
+
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
@@ -34,7 +36,7 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mContext = new TestContext();
+ mContext = spy(new TestContext());
// Set up the looper if it does not exist on the test thread.
if (Looper.myLooper() == null) {
Looper.prepare();
diff --git a/tests/src/com/android/TestContext.java b/tests/src/com/android/TestContext.java
index 776ec6a..c190be9 100644
--- a/tests/src/com/android/TestContext.java
+++ b/tests/src/com/android/TestContext.java
@@ -34,6 +34,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.Executor;
+
public class TestContext extends MockContext {
@Mock CarrierConfigManager mMockCarrierConfigManager;
@@ -49,6 +51,12 @@
}
@Override
+ public Executor getMainExecutor() {
+ // Just run on current thread
+ return Runnable::run;
+ }
+
+ @Override
public Context getApplicationContext() {
return this;
}
diff --git a/tests/src/com/android/phone/NumberVerificationManagerTest.java b/tests/src/com/android/phone/NumberVerificationManagerTest.java
index d476ba5..f7914ab 100644
--- a/tests/src/com/android/phone/NumberVerificationManagerTest.java
+++ b/tests/src/com/android/phone/NumberVerificationManagerTest.java
@@ -57,7 +57,7 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
ServiceState ss = mock(ServiceState.class);
- when(ss.getVoiceRegState()).thenReturn(ServiceState.STATE_IN_SERVICE);
+ when(ss.getState()).thenReturn(ServiceState.STATE_IN_SERVICE);
when(mPhone1.getServiceState()).thenReturn(ss);
when(mPhone1.getForegroundCall()).thenReturn(mForegroundCall);
when(mPhone1.getRingingCall()).thenReturn(mRingingCall);
@@ -107,7 +107,7 @@
@Test
public void testNoPhoneInServiceFailure() throws Exception {
ServiceState ss = mock(ServiceState.class);
- when(ss.getVoiceRegState()).thenReturn(ServiceState.STATE_POWER_OFF);
+ when(ss.getState()).thenReturn(ServiceState.STATE_POWER_OFF);
when(mPhone1.getServiceState()).thenReturn(ss);
when(mPhone2.getServiceState()).thenReturn(ss);
NumberVerificationManager manager =
@@ -138,7 +138,7 @@
@Test
public void testVerificationWorksWithOnePhoneInService() throws Exception {
ServiceState ss = mock(ServiceState.class);
- when(ss.getVoiceRegState()).thenReturn(ServiceState.STATE_POWER_OFF);
+ when(ss.getState()).thenReturn(ServiceState.STATE_POWER_OFF);
when(mPhone1.getServiceState()).thenReturn(ss);
NumberVerificationManager manager =
new NumberVerificationManager(() -> new Phone[]{mPhone1, mPhone2});
diff --git a/tests/src/com/android/phone/PhoneGlobalsTest.java b/tests/src/com/android/phone/PhoneGlobalsTest.java
new file mode 100644
index 0000000..d45a890
--- /dev/null
+++ b/tests/src/com/android/phone/PhoneGlobalsTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+
+@RunWith(AndroidJUnit4.class)
+public class PhoneGlobalsTest extends TelephonyTestBase {
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testGetImsResources() throws Exception {
+ // Do not use test context here, we are testing that overlaying for different locales works
+ // correctly
+ Context realContext = InstrumentationRegistry.getTargetContext();
+ String defaultImsMmtelPackage = getResourcesForLocale(realContext, Locale.US).getString(
+ R.string.config_ims_mmtel_package);
+ String defaultImsMmtelPackageUk = getResourcesForLocale(realContext, Locale.UK).getString(
+ R.string.config_ims_mmtel_package);
+ assertEquals("locales changed IMS package configuration!", defaultImsMmtelPackage,
+ defaultImsMmtelPackageUk);
+ }
+
+ private Resources getResourcesForLocale(Context context, Locale locale) {
+ Configuration config = new Configuration();
+ config.setToDefaults();
+ config.setLocale(locale);
+ Context localeContext = context.createConfigurationContext(config);
+ return localeContext.getResources();
+ }
+}
diff --git a/tests/src/com/android/phone/ServiceStateProviderTest.java b/tests/src/com/android/phone/ServiceStateProviderTest.java
new file mode 100644
index 0000000..574c0c9
--- /dev/null
+++ b/tests/src/com/android/phone/ServiceStateProviderTest.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.phone;
+
+import static android.provider.Telephony.ServiceStateTable;
+import static android.provider.Telephony.ServiceStateTable.getUriForSubscriptionId;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.net.Uri;
+import android.telephony.ServiceState;
+import android.telephony.SubscriptionManager;
+import android.test.mock.MockContentResolver;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for simple queries of ServiceStateProvider.
+ *
+ * Build, install and run the tests by running the commands below:
+ * runtest --path <dir or file>
+ * runtest --path <dir or file> --test-method <testMethodName>
+ * e.g.)
+ * runtest --path tests/src/com/android/phone/ServiceStateProviderTest.java \
+ * --test-method testGetServiceState
+ */
+public class ServiceStateProviderTest {
+ private static final String TAG = "ServiceStateProviderTest";
+
+ private Context mContext;
+ private MockContentResolver mContentResolver;
+ private ServiceState mTestServiceState;
+ private ServiceState mTestServiceStateForSubId1;
+
+ private final String[] mTestProjection =
+ {
+ ServiceStateTable.VOICE_REG_STATE,
+ ServiceStateTable.DATA_REG_STATE,
+ ServiceStateTable.VOICE_OPERATOR_ALPHA_LONG,
+ ServiceStateTable.VOICE_OPERATOR_ALPHA_SHORT,
+ ServiceStateTable.VOICE_OPERATOR_NUMERIC,
+ ServiceStateTable.DATA_OPERATOR_ALPHA_LONG,
+ ServiceStateTable.DATA_OPERATOR_ALPHA_SHORT,
+ ServiceStateTable.DATA_OPERATOR_NUMERIC,
+ ServiceStateTable.IS_MANUAL_NETWORK_SELECTION,
+ ServiceStateTable.RIL_VOICE_RADIO_TECHNOLOGY,
+ ServiceStateTable.RIL_DATA_RADIO_TECHNOLOGY,
+ ServiceStateTable.CSS_INDICATOR,
+ ServiceStateTable.NETWORK_ID,
+ ServiceStateTable.SYSTEM_ID,
+ ServiceStateTable.CDMA_ROAMING_INDICATOR,
+ ServiceStateTable.CDMA_DEFAULT_ROAMING_INDICATOR,
+ ServiceStateTable.CDMA_ERI_ICON_INDEX,
+ ServiceStateTable.CDMA_ERI_ICON_MODE,
+ ServiceStateTable.IS_EMERGENCY_ONLY,
+ ServiceStateTable.IS_USING_CARRIER_AGGREGATION,
+ ServiceStateTable.OPERATOR_ALPHA_LONG_RAW,
+ ServiceStateTable.OPERATOR_ALPHA_SHORT_RAW,
+ };
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = mock(Context.class);
+ mContentResolver = new MockContentResolver() {
+ @Override
+ public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+ throw new RuntimeException("notifyChange!");
+ }
+ };
+ doReturn(mContentResolver).when(mContext).getContentResolver();
+
+ mTestServiceState = new ServiceState();
+ mTestServiceState.setStateOutOfService();
+ mTestServiceStateForSubId1 = new ServiceState();
+ mTestServiceStateForSubId1.setStateOff();
+
+ // Mock out the actual phone state
+ ServiceStateProvider provider = new ServiceStateProvider() {
+ @Override
+ public ServiceState getServiceState(int subId) {
+ if (subId == 1) {
+ return mTestServiceStateForSubId1;
+ } else {
+ return mTestServiceState;
+ }
+ }
+
+ @Override
+ public int getDefaultSubId() {
+ return 0;
+ }
+ };
+ ProviderInfo providerInfo = new ProviderInfo();
+ providerInfo.authority = "service-state";
+ provider.attachInfoForTesting(mContext, providerInfo);
+ mContentResolver.addProvider("service-state", provider);
+ }
+
+ @Test
+ @SmallTest
+ public void testQueryServiceStateWithNoSubId() {
+ // Verify that when calling query with no subId in the uri the default ServiceState is
+ // returned.
+ // In this case the subId is set to 0 and the expected service state is
+ // mTestServiceState.
+ verifyServiceStateForSubId(ServiceStateTable.CONTENT_URI, mTestServiceState);
+ }
+
+ @Test
+ @SmallTest
+ public void testGetServiceStateWithDefaultSubId() {
+ // Verify that when calling with the DEFAULT_SUBSCRIPTION_ID the correct ServiceState is
+ // returned
+ // In this case the subId is set to 0 and the expected service state is
+ // mTestServiceState.
+ verifyServiceStateForSubId(
+ getUriForSubscriptionId(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID),
+ mTestServiceState);
+ }
+
+ /**
+ * Test querying the service state for a given subId
+ */
+ @Test
+ @SmallTest
+ public void testGetServiceStateForSubId() {
+ // Verify that when calling with a specific subId the correct ServiceState is returned
+ // In this case the subId is set to 1 and the expected service state is
+ // mTestServiceStateForSubId1
+ verifyServiceStateForSubId(getUriForSubscriptionId(1), mTestServiceStateForSubId1);
+ }
+
+ private void verifyServiceStateForSubId(Uri uri, ServiceState ss) {
+ Cursor cursor = mContentResolver.query(uri, mTestProjection, "",
+ null, null);
+ assertNotNull(cursor);
+ cursor.moveToFirst();
+
+ final int voiceRegState = ss.getState();
+ final int dataRegState = ss.getDataRegistrationState();
+ final String voiceOperatorAlphaLong = ss.getOperatorAlphaLong();
+ final String voiceOperatorAlphaShort = ss.getOperatorAlphaShort();
+ final String voiceOperatorNumeric = ss.getOperatorNumeric();
+ final String dataOperatorAlphaLong = ss.getOperatorAlphaLong();
+ final String dataOperatorAlphaShort = ss.getOperatorAlphaShort();
+ final String dataOperatorNumeric = ss.getOperatorNumeric();
+ final int isManualNetworkSelection = (ss.getIsManualSelection()) ? 1 : 0;
+ final int rilVoiceRadioTechnology = ss.getRilVoiceRadioTechnology();
+ final int rilDataRadioTechnology = ss.getRilDataRadioTechnology();
+ final int cssIndicator = ss.getCssIndicator();
+ final int networkId = ss.getCdmaNetworkId();
+ final int systemId = ss.getCdmaSystemId();
+ final int cdmaRoamingIndicator = ss.getCdmaRoamingIndicator();
+ final int cdmaDefaultRoamingIndicator = ss.getCdmaDefaultRoamingIndicator();
+ final int cdmaEriIconIndex = ss.getCdmaEriIconIndex();
+ final int cdmaEriIconMode = ss.getCdmaEriIconMode();
+ final int isEmergencyOnly = (ss.isEmergencyOnly()) ? 1 : 0;
+ final int isUsingCarrierAggregation = (ss.isUsingCarrierAggregation()) ? 1 : 0;
+ final String operatorAlphaLongRaw = ss.getOperatorAlphaLongRaw();
+ final String operatorAlphaShortRaw = ss.getOperatorAlphaShortRaw();
+
+ assertEquals(voiceRegState, cursor.getInt(0));
+ assertEquals(dataRegState, cursor.getInt(1));
+ assertEquals(voiceOperatorAlphaLong, cursor.getString(2));
+ assertEquals(voiceOperatorAlphaShort, cursor.getString(3));
+ assertEquals(voiceOperatorNumeric, cursor.getString(4));
+ assertEquals(dataOperatorAlphaLong, cursor.getString(5));
+ assertEquals(dataOperatorAlphaShort, cursor.getString(6));
+ assertEquals(dataOperatorNumeric, cursor.getString(7));
+ assertEquals(isManualNetworkSelection, cursor.getInt(8));
+ assertEquals(rilVoiceRadioTechnology, cursor.getInt(9));
+ assertEquals(rilDataRadioTechnology, cursor.getInt(10));
+ assertEquals(cssIndicator, cursor.getInt(11));
+ assertEquals(networkId, cursor.getInt(12));
+ assertEquals(systemId, cursor.getInt(13));
+ assertEquals(cdmaRoamingIndicator, cursor.getInt(14));
+ assertEquals(cdmaDefaultRoamingIndicator, cursor.getInt(15));
+ assertEquals(cdmaEriIconIndex, cursor.getInt(16));
+ assertEquals(cdmaEriIconMode, cursor.getInt(17));
+ assertEquals(isEmergencyOnly, cursor.getInt(18));
+ assertEquals(isUsingCarrierAggregation, cursor.getInt(19));
+ assertEquals(operatorAlphaLongRaw, cursor.getString(20));
+ assertEquals(operatorAlphaShortRaw, cursor.getString(21));
+ }
+
+ /**
+ * Test that we don't notify for certain field changes. (e.g. we don't notify when the NetworkId
+ * or SystemId change) This is an intentional behavior change from the broadcast.
+ */
+ @Test
+ @SmallTest
+ public void testNoNotify() {
+ int subId = 0;
+
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+ oldSS.setCdmaSystemAndNetworkId(1, 1);
+
+ ServiceState newSS = new ServiceState();
+ newSS.setStateOutOfService();
+ newSS.setCdmaSystemAndNetworkId(0, 0);
+
+ // Test that notifyChange is not called for these fields
+ boolean notifyChangeWasCalled = false;
+ try {
+ ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, newSS, subId);
+ } catch (RuntimeException e) {
+ final String message = e.getMessage();
+ if (message != null && message.equals("notifyChange!")) {
+ notifyChangeWasCalled = true;
+ }
+ }
+ assertFalse(notifyChangeWasCalled);
+ }
+
+ @Test
+ @SmallTest
+ public void testNotifyChanged() {
+ int subId = 0;
+
+ ServiceState oldSS = new ServiceState();
+ oldSS.setStateOutOfService();
+ oldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
+
+ ServiceState copyOfOldSS = new ServiceState();
+ copyOfOldSS.setStateOutOfService();
+ copyOfOldSS.setVoiceRegState(ServiceState.STATE_OUT_OF_SERVICE);
+
+ ServiceState newSS = new ServiceState();
+ newSS.setStateOutOfService();
+ newSS.setVoiceRegState(ServiceState.STATE_POWER_OFF);
+
+ // Test that notifyChange is not called with no change in notifyChangeForSubIdAndField
+ boolean notifyChangeWasCalled = false;
+ try {
+ ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, copyOfOldSS, subId);
+ } catch (RuntimeException e) {
+ final String message = e.getMessage();
+ if (message != null && message.equals("notifyChange!")) {
+ notifyChangeWasCalled = true;
+ }
+ }
+ assertFalse(notifyChangeWasCalled);
+
+ // Test that notifyChange is not called with no change in notifyChangeForSubId
+ notifyChangeWasCalled = false;
+ try {
+ ServiceStateProvider.notifyChangeForSubId(mContext, oldSS, copyOfOldSS, subId);
+ } catch (RuntimeException e) {
+ final String message = e.getMessage();
+ if (message != null && message.equals("notifyChange!")) {
+ notifyChangeWasCalled = true;
+ }
+ }
+ assertFalse(notifyChangeWasCalled);
+
+ // Test that notifyChange is called by notifyChangeForSubIdAndField when the voice_reg_state
+ // changes
+ notifyChangeWasCalled = false;
+ try {
+ ServiceStateProvider.notifyChangeForSubIdAndField(mContext, oldSS, newSS, subId);
+ } catch (RuntimeException e) {
+ final String message = e.getMessage();
+ if (message != null && message.equals("notifyChange!")) {
+ notifyChangeWasCalled = true;
+ }
+ }
+ assertTrue(notifyChangeWasCalled);
+
+ // Test that notifyChange is called by notifyChangeForSubId when the voice_reg_state changes
+ notifyChangeWasCalled = false;
+ try {
+ ServiceStateProvider.notifyChangeForSubId(mContext, oldSS, newSS, subId);
+ } catch (RuntimeException e) {
+ final String message = e.getMessage();
+ if (message != null && message.equals("notifyChange!")) {
+ notifyChangeWasCalled = true;
+ }
+ }
+ assertTrue(notifyChangeWasCalled);
+ }
+}
diff --git a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
index 8b46bf0..25df848 100644
--- a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
+++ b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
@@ -34,6 +34,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.TelephonyTestBase;
+import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
@@ -55,6 +56,7 @@
@Mock Phone mMockPhone;
@Mock RadioOnStateListener.Callback mCallback;
+ @Mock CommandsInterface mMockCi;
RadioOnStateListener mListener;
@Override
@@ -67,9 +69,9 @@
@Override
@After
public void tearDown() throws Exception {
+ mListener.getHandler().removeCallbacksAndMessages(null);
// Wait for the queue to clear...
waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS /*ms timeout*/);
- mListener.getHandler().removeCallbacksAndMessages(null);
mListener = null;
super.tearDown();
}
@@ -80,13 +82,17 @@
@Test
@SmallTest
public void testRegisterForCallback() {
- mListener.waitForRadioOn(mMockPhone, mCallback);
+ mMockPhone.mCi = mMockCi;
+ mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
verify(mMockPhone).unregisterForServiceStateChanged(any(Handler.class));
verify(mMockPhone).registerForServiceStateChanged(any(Handler.class),
eq(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED), isNull());
+
+ verify(mMockCi).registerForOffOrNotAvailable(any(Handler.class),
+ eq(RadioOnStateListener.MSG_RADIO_OFF_OR_NOT_AVAILABLE), isNull());
}
/**
@@ -99,9 +105,11 @@
public void testPhoneChangeState_OkToCallTrue() {
ServiceState state = new ServiceState();
state.setState(ServiceState.STATE_IN_SERVICE);
+ when(mMockPhone.getServiceState()).thenReturn(state);
when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(true);
- mListener.waitForRadioOn(mMockPhone, mCallback);
+ mMockPhone.mCi = mMockCi;
+ mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
@@ -124,7 +132,8 @@
when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
when(mMockPhone.getServiceState()).thenReturn(state);
- mListener.waitForRadioOn(mMockPhone, mCallback);
+ mMockPhone.mCi = mMockCi;
+ mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
@@ -152,10 +161,33 @@
mListener.setMaxNumRetries(2);
// Wait for the timer to expire and check state manually in onRetryTimeout
- mListener.waitForRadioOn(mMockPhone, mCallback);
+ mMockPhone.mCi = mMockCi;
+ mListener.waitForRadioOn(mMockPhone, mCallback, false, false);
waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, TIMEOUT_MS /*delay*/);
verify(mCallback).onComplete(eq(mListener), eq(false));
- verify(mMockPhone, times(2)).setRadioPower(eq(true));
+ verify(mMockPhone, times(2)).setRadioPower(eq(true),
+ eq(false), eq(false), eq(false));
+ }
+
+ @Test
+ @SmallTest
+ public void testTimeout_RetryFailure_ForEmergency() {
+ ServiceState state = new ServiceState();
+ state.setState(ServiceState.STATE_POWER_OFF);
+ when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
+ when(mMockPhone.getServiceState()).thenReturn(state);
+ when(mCallback.isOkToCall(eq(mMockPhone), anyInt())).thenReturn(false);
+ mListener.setTimeBetweenRetriesMillis(0/*ms*/);
+ mListener.setMaxNumRetries(2);
+
+ // Wait for the timer to expire and check state manually in onRetryTimeout
+ mMockPhone.mCi = mMockCi;
+ mListener.waitForRadioOn(mMockPhone, mCallback, true, true);
+ waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, TIMEOUT_MS /*delay*/);
+
+ verify(mCallback).onComplete(eq(mListener), eq(false));
+ verify(mMockPhone, times(2)).setRadioPower(eq(true),
+ eq(true), eq(true), eq(false));
}
}
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
index 6e11e51..2060e6f 100644
--- a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -16,7 +16,10 @@
package com.android.services.telephony;
+import static com.android.internal.telephony.RILConstants.GSM_PHONE;
+
import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
@@ -26,6 +29,7 @@
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -58,6 +62,7 @@
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneSwitcher;
+import com.android.internal.telephony.ServiceStateTracker;
import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.gsm.SuppServiceNotification;
@@ -93,6 +98,7 @@
private static final PhoneAccountHandle PHONE_ACCOUNT_HANDLE_2 = new PhoneAccountHandle(
TEST_COMPONENT_NAME, TEST_ACCOUNT_ID2);
private static final Uri TEST_ADDRESS = Uri.parse("tel:+16505551212");
+ private android.telecom.Connection mConnection;
@Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
@Mock TelephonyConnectionService.SubscriptionManagerProxy mSubscriptionManagerProxy;
@@ -106,6 +112,8 @@
@Mock Handler mMockHandler;
@Mock EmergencyNumberTracker mEmergencyNumberTracker;
@Mock PhoneSwitcher mPhoneSwitcher;
+ @Mock RadioOnHelper mRadioOnHelper;
+ @Mock ServiceStateTracker mSST;
private static class TestTelephonyConnectionService extends TelephonyConnectionService {
@@ -135,6 +143,8 @@
doReturn(false).when(mDeviceState).shouldCheckSimStateBeforeOutgoingCall(any());
mTestConnectionService.setPhoneSwitcherProxy(mPhoneSwitcherProxy);
doReturn(mPhoneSwitcher).when(mPhoneSwitcherProxy).getPhoneSwitcher();
+ when(mPhoneNumberUtilsProxy.convertToEmergencyNumber(any(), anyString()))
+ .thenAnswer(invocation -> invocation.getArgument(1));
mTestConnectionService.setPhoneNumberUtilsProxy(mPhoneNumberUtilsProxy);
mTestConnectionService.setPhoneUtilsProxy(mPhoneUtilsProxy);
HandlerThread mockHandlerThread = mock(HandlerThread.class);
@@ -143,6 +153,7 @@
doReturn(mMockHandler).when(mHandlerFactory).createHandler(any());
mTestConnectionService.setHandlerFactory(mHandlerFactory);
mTestConnectionService.setDeviceState(mDeviceState);
+ mTestConnectionService.setRadioOnHelper(mRadioOnHelper);
doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
.toTelecomDisconnectCause(anyInt(), any());
doReturn(new DisconnectCause(DisconnectCause.UNKNOWN)).when(mDisconnectCauseFactory)
@@ -941,6 +952,64 @@
}
/**
+ * Test that the TelephonyConnectionService successfully turns radio on before placing the
+ * emergency call.
+ */
+ @Test
+ @SmallTest
+ public void testCreateOutgoingEmerge_exitingApm_disconnected() {
+ when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+ Phone testPhone = setupConnectionServiceInApm();
+
+ ArgumentCaptor<RadioOnStateListener.Callback> callback =
+ ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+ verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+ eq(testPhone));
+
+ assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+ when(mSST.isRadioOn()).thenReturn(true);
+ assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+
+ mConnection.setDisconnected(null);
+ callback.getValue().onComplete(null, true);
+ for (Phone phone : mPhoneFactoryProxy.getPhones()) {
+ verify(phone).setRadioPower(true, false, false, true);
+ }
+ }
+
+ /**
+ * Test that the TelephonyConnectionService successfully turns radio on before placing the
+ * emergency call.
+ */
+ @Test
+ @SmallTest
+ public void testCreateOutgoingEmergencyConnection_exitingApm_placeCall() {
+ when(mDeviceState.isAirplaneModeOn(any())).thenReturn(true);
+ Phone testPhone = setupConnectionServiceInApm();
+
+ ArgumentCaptor<RadioOnStateListener.Callback> callback =
+ ArgumentCaptor.forClass(RadioOnStateListener.Callback.class);
+ verify(mRadioOnHelper).triggerRadioOnAndListen(callback.capture(), eq(true),
+ eq(testPhone));
+
+ assertFalse(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+ when(mSST.isRadioOn()).thenReturn(true);
+ assertTrue(callback.getValue().isOkToCall(testPhone, ServiceState.STATE_OUT_OF_SERVICE));
+
+ callback.getValue().onComplete(null, true);
+ Runnable delayDialRunnable = verifyRunnablePosted();
+
+ try {
+ doAnswer(invocation -> null).when(mContext).startActivity(any());
+ delayDialRunnable.run();
+ verify(testPhone).dial(anyString(), any());
+ } catch (CallStateException e) {
+ // This shouldn't happen
+ fail();
+ }
+ }
+
+ /**
* Test that the TelephonyConnectionService does not perform a DDS switch when the carrier
* supports control-plane fallback.
*/
@@ -1115,9 +1184,49 @@
doReturn(emergencyNumbers).when(mTelephonyManagerProxy).getCurrentEmergencyNumberList();
doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
- android.telecom.Connection testConnection = mTestConnectionService
- .onCreateOutgoingConnection(PHONE_ACCOUNT_HANDLE_1, connectionRequest);
- assertNotNull("test connection was not set up correctly.", testConnection);
+ mConnection = mTestConnectionService.onCreateOutgoingConnection(
+ PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+ assertNotNull("test connection was not set up correctly.", mConnection);
+
+ return testPhone0;
+ }
+
+
+ /**
+ * Set up a mock MSIM device with TEST_ADDRESS set as an emergency number in airplane mode.
+ * @return the Phone associated with slot 0.
+ */
+ private Phone setupConnectionServiceInApm() {
+ ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
+ .setAccountHandle(PHONE_ACCOUNT_HANDLE_1)
+ .setAddress(TEST_ADDRESS)
+ .build();
+ Phone testPhone0 = makeTestPhone(0 /*phoneId*/, ServiceState.STATE_POWER_OFF,
+ false /*isEmergencyOnly*/);
+ Phone testPhone1 = makeTestPhone(1 /*phoneId*/, ServiceState.STATE_POWER_OFF,
+ false /*isEmergencyOnly*/);
+ doReturn(GSM_PHONE).when(testPhone0).getPhoneType();
+ doReturn(GSM_PHONE).when(testPhone1).getPhoneType();
+ List<Phone> phones = new ArrayList<>(2);
+ doReturn(false).when(testPhone0).isRadioOn();
+ doReturn(false).when(testPhone1).isRadioOn();
+ phones.add(testPhone0);
+ phones.add(testPhone1);
+ setPhones(phones);
+ setupHandleToPhoneMap(PHONE_ACCOUNT_HANDLE_1, testPhone0);
+ setupDeviceConfig(testPhone0, testPhone1, 0);
+ doReturn(true).when(mTelephonyManagerProxy).isCurrentEmergencyNumber(
+ TEST_ADDRESS.getSchemeSpecificPart());
+ HashMap<Integer, List<EmergencyNumber>> emergencyNumbers = new HashMap<>(1);
+ List<EmergencyNumber> numbers = new ArrayList<>();
+ numbers.add(setupEmergencyNumber(TEST_ADDRESS));
+ emergencyNumbers.put(0 /*subId*/, numbers);
+ doReturn(emergencyNumbers).when(mTelephonyManagerProxy).getCurrentEmergencyNumberList();
+ doReturn(2).when(mTelephonyManagerProxy).getPhoneCount();
+
+ mConnection = mTestConnectionService.onCreateOutgoingConnection(
+ PHONE_ACCOUNT_HANDLE_1, connectionRequest);
+ assertNotNull("test connection was not set up correctly.", mConnection);
return testPhone0;
}
@@ -1163,6 +1272,7 @@
when(phone.getPhoneId()).thenReturn(phoneId);
when(phone.getDefaultPhone()).thenReturn(phone);
when(phone.getEmergencyNumberTracker()).thenReturn(mEmergencyNumberTracker);
+ when(phone.getServiceStateTracker()).thenReturn(mSST);
when(mEmergencyNumberTracker.getEmergencyNumber(anyString())).thenReturn(null);
return phone;
}
@@ -1193,6 +1303,7 @@
private void setPhones(List<Phone> phones) {
when(mPhoneFactoryProxy.getPhones()).thenReturn(phones.toArray(new Phone[phones.size()]));
+ when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phones.get(0));
}
private void setPhonesDialConnection(Phone phone, Connection c) {
diff --git a/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
new file mode 100644
index 0000000..fbb270d
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/RcsFeatureControllerTest.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony.rcs;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.telephony.AccessNetworkConstants;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.RegistrationManager;
+import android.telephony.ims.aidl.IImsCapabilityCallback;
+import android.telephony.ims.aidl.IImsRegistrationCallback;
+import android.telephony.ims.feature.RcsFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+import com.android.ims.FeatureConnector;
+import com.android.ims.RcsFeatureManager;
+import com.android.internal.telephony.imsphone.ImsRegistrationCallbackHelper;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsFeatureControllerTest extends TelephonyTestBase {
+
+ private static final ImsReasonInfo REASON_DISCONNECTED = new ImsReasonInfo(
+ ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN, 0, "test");
+
+ @Mock RcsFeatureManager mFeatureManager;
+ @Mock RcsFeatureController.FeatureConnectorFactory<RcsFeatureManager> mFeatureFactory;
+ @Mock ImsRegistrationCallbackHelper.ImsRegistrationUpdate mRegistrationCallback;
+ @Mock FeatureConnector<RcsFeatureManager> mFeatureConnector;
+ @Mock RcsFeatureController.Feature mMockFeature;
+ @Captor ArgumentCaptor<FeatureConnector.Listener<RcsFeatureManager>> mConnectorListener;
+
+ private RcsFeatureController.RegistrationHelperFactory mRegistrationFactory =
+ new RcsFeatureController.RegistrationHelperFactory() {
+ @Override
+ public ImsRegistrationCallbackHelper create(
+ ImsRegistrationCallbackHelper.ImsRegistrationUpdate cb, Executor executor) {
+ // Run on current thread for testing.
+ return new ImsRegistrationCallbackHelper(mRegistrationCallback, Runnable::run);
+ }
+ };
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testRcsFeatureManagerConnectDisconnect() throws Exception {
+ RcsFeatureController controller = createFeatureController();
+ controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+ verify(mMockFeature).onRcsDisconnected();
+ // Connect the RcsFeatureManager
+ mConnectorListener.getValue().connectionReady(mFeatureManager);
+
+ verify(mFeatureManager).updateCapabilities();
+ verify(mFeatureManager).registerImsRegistrationCallback(any());
+ verify(mMockFeature).onRcsConnected(mFeatureManager);
+
+ // Disconnect
+ mConnectorListener.getValue().connectionUnavailable();
+
+ verify(mFeatureManager).unregisterImsRegistrationCallback(any());
+ verify(mMockFeature, times(2)).onRcsDisconnected();
+ }
+
+ @Test
+ public void testFeatureManagerConnectedAddRemoveFeature() throws Exception {
+ RcsFeatureController controller = createFeatureController();
+ // Connect the RcsFeatureManager
+ mConnectorListener.getValue().connectionReady(mFeatureManager);
+ controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+
+ verify(mMockFeature).onRcsConnected(mFeatureManager);
+ assertEquals(mMockFeature, controller.getFeature(RcsFeatureController.Feature.class));
+
+ controller.removeFeature(RcsFeatureController.Feature.class);
+ verify(mMockFeature).onDestroy();
+ assertNull(controller.getFeature(RcsFeatureController.Feature.class));
+ }
+
+ @Test
+ public void testFeatureManagerConnectedRegister() throws Exception {
+ RcsFeatureController controller = createFeatureController();
+ IImsRegistrationCallback regCb = mock(IImsRegistrationCallback.class);
+ IImsCapabilityCallback capCb = mock(IImsCapabilityCallback.class);
+ // Connect the RcsFeatureManager
+ mConnectorListener.getValue().connectionReady(mFeatureManager);
+
+ try {
+ controller.registerImsRegistrationCallback(0 /*subId*/, regCb);
+ controller.registerRcsAvailabilityCallback(0 /*subId*/, capCb);
+ controller.isCapable(RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ controller.isAvailable(RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE);
+ controller.getRegistrationTech(integer -> {
+ });
+ verify(mFeatureManager).registerImsRegistrationCallback(0, regCb);
+ verify(mFeatureManager).registerRcsAvailabilityCallback(0, capCb);
+ verify(mFeatureManager).isCapable(
+ RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ verify(mFeatureManager).isAvailable(
+ RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE);
+ verify(mFeatureManager).getImsRegistrationTech(any());
+ } catch (ImsException e) {
+ fail("ImsException not expected.");
+ }
+
+ controller.unregisterImsRegistrationCallback(0, regCb);
+ controller.unregisterRcsAvailabilityCallback(0, capCb);
+ verify(mFeatureManager).unregisterImsRegistrationCallback(0, regCb);
+ verify(mFeatureManager).unregisterRcsAvailabilityCallback(0, capCb);
+ }
+
+ @Test
+ public void testFeatureManagerConnectedHelper() throws Exception {
+ RcsFeatureController controller = createFeatureController();
+ // Connect the RcsFeatureManager
+ mConnectorListener.getValue().connectionReady(mFeatureManager);
+ ArgumentCaptor<IImsRegistrationCallback> captor =
+ ArgumentCaptor.forClass(IImsRegistrationCallback.class);
+ verify(mFeatureManager).registerImsRegistrationCallback(captor.capture());
+ assertNotNull(captor.getValue());
+
+ captor.getValue().onDeregistered(REASON_DISCONNECTED);
+ controller.getRegistrationState(result -> {
+ assertNotNull(result);
+ assertEquals(RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED, result.intValue());
+ });
+ verify(mRegistrationCallback).handleImsUnregistered(REASON_DISCONNECTED);
+
+ captor.getValue().onRegistering(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ controller.getRegistrationState(result -> {
+ assertNotNull(result);
+ assertEquals(RegistrationManager.REGISTRATION_STATE_REGISTERING, result.intValue());
+ });
+ verify(mRegistrationCallback).handleImsRegistering(
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+
+ captor.getValue().onRegistered(ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ controller.getRegistrationState(result -> {
+ assertNotNull(result);
+ assertEquals(RegistrationManager.REGISTRATION_STATE_REGISTERED, result.intValue());
+ });
+ verify(mRegistrationCallback).handleImsRegistered(
+ AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ }
+
+ @Test
+ public void testFeatureManagerDisconnectedAddFeature() {
+ RcsFeatureController controller = createFeatureController();
+ // Disconnect the RcsFeatureManager
+ mConnectorListener.getValue().connectionUnavailable();
+ controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+
+ verify(mMockFeature).onRcsDisconnected();
+ }
+
+ @Test
+ public void testFeatureManagerDisconnectedException() {
+ RcsFeatureController controller = createFeatureController();
+ IImsRegistrationCallback regCb = mock(IImsRegistrationCallback.class);
+ IImsCapabilityCallback capCb = mock(IImsCapabilityCallback.class);
+ // Disconnect the RcsFeatureManager
+ mConnectorListener.getValue().connectionUnavailable();
+
+ try {
+ controller.registerImsRegistrationCallback(0 /*subId*/, null /*callback*/);
+ fail("ImsException expected for IMS registration.");
+ } catch (ImsException e) {
+ //expected
+ }
+ try {
+ controller.registerRcsAvailabilityCallback(0 /*subId*/, null /*callback*/);
+ fail("ImsException expected for availability");
+ } catch (ImsException e) {
+ //expected
+ }
+ try {
+ controller.isCapable(RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
+ fail("ImsException expected for capability check");
+ } catch (ImsException e) {
+ //expected
+ }
+ try {
+ controller.isAvailable(RcsFeature.RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE);
+ fail("ImsException expected for availability check");
+ } catch (ImsException e) {
+ //expected
+ }
+ controller.getRegistrationTech(integer -> {
+ assertNotNull(integer);
+ assertEquals(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, integer.intValue());
+ });
+ controller.unregisterImsRegistrationCallback(0, regCb);
+ controller.unregisterRcsAvailabilityCallback(0, capCb);
+ verify(mFeatureManager, never()).unregisterImsRegistrationCallback(0, regCb);
+ verify(mFeatureManager, never()).unregisterRcsAvailabilityCallback(0, capCb);
+ }
+
+ @Test
+ public void testChangeSubId() throws Exception {
+ RcsFeatureController controller = createFeatureController();
+ // Connect the RcsFeatureManager
+ mConnectorListener.getValue().connectionReady(mFeatureManager);
+ verify(mFeatureManager).updateCapabilities();
+ controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+
+ controller.updateAssociatedSubscription(1 /*new sub id*/);
+
+ verify(mFeatureManager, times(2)).updateCapabilities();
+ verify(mMockFeature).onAssociatedSubscriptionUpdated(1 /*new sub id*/);
+ }
+
+ @Test
+ public void testDestroy() throws Exception {
+ RcsFeatureController controller = createFeatureController();
+ // Connect the RcsFeatureManager
+ mConnectorListener.getValue().connectionReady(mFeatureManager);
+ controller.addFeature(mMockFeature, RcsFeatureController.Feature.class);
+ controller.destroy();
+
+ verify(mFeatureConnector).disconnect();
+ verify(mMockFeature).onRcsDisconnected();
+ verify(mMockFeature).onDestroy();
+ assertNull(controller.getFeature(RcsFeatureController.Feature.class));
+ }
+
+ private RcsFeatureController createFeatureController() {
+ RcsFeatureController controller = new RcsFeatureController(mContext, 0 /*slotId*/,
+ mRegistrationFactory);
+ controller.setFeatureConnectorFactory(mFeatureFactory);
+ doReturn(mFeatureConnector).when(mFeatureFactory).create(any(), anyInt(),
+ mConnectorListener.capture(), any(), any());
+ controller.connect();
+ assertNotNull(mConnectorListener.getValue());
+ return controller;
+ }
+}
diff --git a/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
new file mode 100644
index 0000000..cfb68b7
--- /dev/null
+++ b/tests/src/com/android/services/telephony/rcs/TelephonyRcsServiceTest.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony.rcs;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.TelephonyTestBase;
+import com.android.ims.FeatureConnector;
+import com.android.ims.RcsFeatureManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+
+@RunWith(AndroidJUnit4.class)
+public class TelephonyRcsServiceTest extends TelephonyTestBase {
+
+ @Captor ArgumentCaptor<BroadcastReceiver> mReceiverCaptor;
+ @Mock TelephonyRcsService.FeatureFactory mFeatureFactory;
+ @Mock UserCapabilityExchangeImpl mMockUceSlot0;
+ @Mock UserCapabilityExchangeImpl mMockUceSlot1;
+ @Mock RcsFeatureController.RegistrationHelperFactory mRegistrationFactory;
+ @Mock RcsFeatureController.FeatureConnectorFactory<RcsFeatureManager> mFeatureConnectorFactory;
+ @Mock FeatureConnector<RcsFeatureManager> mFeatureConnector;
+
+ private RcsFeatureController mFeatureControllerSlot0;
+ private RcsFeatureController mFeatureControllerSlot1;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ doReturn(mFeatureConnector).when(mFeatureConnectorFactory).create(any(), anyInt(),
+ any(), any(), any());
+ mFeatureControllerSlot0 = createFeatureController(0 /*slotId*/);
+ mFeatureControllerSlot1 = createFeatureController(1 /*slotId*/);
+ doReturn(mFeatureControllerSlot0).when(mFeatureFactory).createController(any(), eq(0));
+ doReturn(mFeatureControllerSlot1).when(mFeatureFactory).createController(any(), eq(1));
+ doReturn(mMockUceSlot0).when(mFeatureFactory).createUserCapabilityExchange(any(), eq(0),
+ anyInt());
+ doReturn(mMockUceSlot1).when(mFeatureFactory).createUserCapabilityExchange(any(), eq(1),
+ anyInt());
+ //set up default slot-> sub ID mappings.
+ setSlotToSubIdMapping(0 /*slotId*/, 1/*subId*/);
+ setSlotToSubIdMapping(1 /*slotId*/, 2/*subId*/);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @Test
+ public void testUserCapabilityExchangePresenceConnected() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+ }
+
+ @Test
+ public void testUserCapabilityExchangeOptionsConnected() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_SIP_OPTIONS_BOOL, true /*isEnabled*/);
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+ }
+
+ @Test
+ public void testNoFeaturesEnabled() {
+ createRcsService(1 /*numSlots*/);
+ // No carrier config set for UCE.
+ verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, never()).connect();
+ }
+
+ @Test
+ public void testNoFeaturesEnabledCarrierConfigChanged() {
+ createRcsService(1 /*numSlots*/);
+ // No carrier config set for UCE.
+
+ sendCarrierConfigChanged(0, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, never()).connect();
+ verify(mFeatureControllerSlot0, never()).updateAssociatedSubscription(anyInt());
+ }
+
+
+ @Test
+ public void testSlotUpdates() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+ TelephonyRcsService service = createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+
+ // there should be no changes if the new num slots = old num
+ service.updateFeatureControllerSize(1 /*newNumSlots*/);
+ verify(mFeatureControllerSlot0, times(1)).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, times(1)).connect();
+
+ // Add a new slot.
+ verify(mFeatureControllerSlot1, never()).addFeature(mMockUceSlot1,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot1, never()).connect();
+ service.updateFeatureControllerSize(2 /*newNumSlots*/);
+ // This shouldn't have changed for slot 0.
+ verify(mFeatureControllerSlot0, times(1)).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, times(1)).connect();
+ verify(mFeatureControllerSlot1).addFeature(mMockUceSlot1, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot1, times(1)).connect();
+
+ // Remove a slot.
+ verify(mFeatureControllerSlot0, never()).destroy();
+ verify(mFeatureControllerSlot1, never()).destroy();
+ service.updateFeatureControllerSize(1 /*newNumSlots*/);
+ // addFeature/connect shouldn't have been called again
+ verify(mFeatureControllerSlot0, times(1)).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, times(1)).connect();
+ verify(mFeatureControllerSlot1, times(1)).addFeature(mMockUceSlot1,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot1, times(1)).connect();
+ // Verify destroy is only called for slot 1.
+ verify(mFeatureControllerSlot0, never()).destroy();
+ verify(mFeatureControllerSlot1, times(1)).destroy();
+ }
+
+ @Test
+ public void testCarrierConfigUpdate() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+ createRcsService(2 /*numSlots*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot1).addFeature(mMockUceSlot1, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+ verify(mFeatureControllerSlot1).connect();
+
+
+ // Send carrier config update for each slot.
+ sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+ verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+ verify(mFeatureControllerSlot1, never()).updateAssociatedSubscription(1);
+ sendCarrierConfigChanged(1 /*slotId*/, 2 /*subId*/);
+ verify(mFeatureControllerSlot0, never()).updateAssociatedSubscription(2);
+ verify(mFeatureControllerSlot1, times(1)).updateAssociatedSubscription(2);
+ }
+
+ @Test
+ public void testCarrierConfigUpdateUceToNoUce() {
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+
+
+ // Send carrier config update for each slot.
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, false /*isEnabled*/);
+ sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+ verify(mFeatureControllerSlot0).removeFeature(UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+ }
+
+ @Test
+ public void testCarrierConfigUpdateNoUceToUce() {
+ createRcsService(1 /*numSlots*/);
+ verify(mFeatureControllerSlot0, never()).addFeature(mMockUceSlot0,
+ UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0, never()).connect();
+
+
+ // Send carrier config update for each slot.
+ setCarrierConfig(CarrierConfigManager.KEY_USE_RCS_PRESENCE_BOOL, true /*isEnabled*/);
+ sendCarrierConfigChanged(0 /*slotId*/, 1 /*subId*/);
+ verify(mFeatureControllerSlot0).addFeature(mMockUceSlot0, UserCapabilityExchangeImpl.class);
+ verify(mFeatureControllerSlot0).connect();
+ verify(mFeatureControllerSlot0).updateAssociatedSubscription(1);
+ }
+
+ private void sendCarrierConfigChanged(int slotId, int subId) {
+ Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
+ intent.putExtra(CarrierConfigManager.EXTRA_SLOT_INDEX, slotId);
+ intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, subId);
+ mReceiverCaptor.getValue().onReceive(mContext, intent);
+ }
+
+ private void setCarrierConfig(String key, boolean value) {
+ PersistableBundle bundle = mContext.getCarrierConfig();
+ bundle.putBoolean(key, value);
+ }
+
+ private void setSlotToSubIdMapping(int slotId, int loadedSubId) {
+ SubscriptionManager m = mContext.getSystemService(SubscriptionManager.class);
+ int [] subIds = new int[1];
+ subIds[0] = loadedSubId;
+ doReturn(subIds).when(m).getSubscriptionIds(eq(slotId));
+ }
+
+ private TelephonyRcsService createRcsService(int numSlots) {
+ TelephonyRcsService service = new TelephonyRcsService(mContext, numSlots);
+ service.setFeatureFactory(mFeatureFactory);
+ service.initialize();
+ verify(mContext).registerReceiver(mReceiverCaptor.capture(), any());
+ return service;
+ }
+
+ private RcsFeatureController createFeatureController(int slotId) {
+ // Create a spy instead of a mock because TelephonyRcsService relies on state provided by
+ // RcsFeatureController.
+ RcsFeatureController controller = spy(new RcsFeatureController(mContext, slotId,
+ mRegistrationFactory));
+ controller.setFeatureConnectorFactory(mFeatureConnectorFactory);
+ return controller;
+ }
+}