Catch SIP exceptions which can crash Phone process on answer. am: 232a03b341 -s ours am: 5b52037b55 am: d6f335dff5 am: a0ba18f893 am: 216f7000ef am: 9cab826be9 am: 9b220dbac9 am: 16244eb4ee
am: eb5a259c5f
Change-Id: I5216def0a90112416df4a5ea141572edbae4329a
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 36a5c07..b5fd399 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -49,6 +49,7 @@
<protected-broadcast android:name="android.intent.action.DATA_SMS_RECEIVED" />
<protected-broadcast android:name="android.provider.Telephony.SMS_RECEIVED" />
<protected-broadcast android:name="android.provider.Telephony.SMS_DELIVER" />
+ <protected-broadcast android:name="android.provider.Telephony.SMS_REJECTED" />
<protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
<protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
<protected-broadcast android:name="android.provider.Telephony.SMS_CB_RECEIVED" />
@@ -70,6 +71,8 @@
<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= "com.android.phone.vvm.omtp.sms.REQUEST_SENT" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CALL_PHONE" />
@@ -366,22 +369,6 @@
</intent-filter>
</activity>
- <activity android:name="GsmUmtsOptions"
- android:label="@string/gsm_umts_options"
- android:theme="@style/DialerSettingsLight">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
-
- <activity android:name="CdmaOptions"
- android:label="@string/cdma_options"
- android:theme="@style/DialerSettingsLight">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
-
<activity android:name="GsmUmtsCallOptions"
android:label="@string/gsm_umts_options"
android:theme="@style/DialerSettingsLight">
@@ -416,14 +403,6 @@
</intent-filter>
</activity>
- <activity android:name="CellBroadcastSms"
- android:label="@string/cell_broadcast_sms"
- android:theme="@android:style/Theme.Holo.DialogWhenLarge">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
-
<!-- fdn setting -->
<activity android:name="com.android.phone.settings.fdn.FdnSetting"
android:label="@string/fdn"
@@ -468,23 +447,6 @@
android:label="@string/delete_fdn_contact">
</activity>
- <activity android:name="DataRoamingReenable"
- android:label="@string/dialog_alert_title"
- android:theme="@android:style/Theme.Holo.Dialog">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
-
- <!-- data roaming setting -->
- <activity android:name="RoamingSetting"
- android:label="@string/roaming"
- android:theme="@android:style/Theme.Holo.DialogWhenLarge">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
-
<!-- "Call settings" UI, used only on voice-capable phone devices. -->
<activity android:name="CallFeaturesSetting"
android:label="@string/call_settings"
diff --git a/res/layout/voicemail_change_pin.xml b/res/layout/voicemail_change_pin.xml
index ba0d823..b0db64b 100644
--- a/res/layout/voicemail_change_pin.xml
+++ b/res/layout/voicemail_change_pin.xml
@@ -28,7 +28,9 @@
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
- android:padding="48dp">
+ android:paddingTop="48dp"
+ android:paddingStart="48dp"
+ android:paddingEnd="48dp">
<TextView
android:id="@+id/headerText"
android:layout_width="match_parent"
diff --git a/res/layout/voicemail_dialog_change_pin.xml b/res/layout/voicemail_dialog_change_pin.xml
deleted file mode 100644
index a5cfa80..0000000
--- a/res/layout/voicemail_dialog_change_pin.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="?android:attr/dialogPreferredPadding">
-
- <TextView
- android:id="@+id/vm_old_pin_label"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/vm_change_pin_old_pin"
- android:labelFor="@+id/vm_old_pin"/>
-
- <EditText android:id="@id/vm_old_pin"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="?android:attr/textColorSecondary"
- android:inputType="numberPassword"/>
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/vm_change_pin_new_pin"
- android:labelFor="@+id/vm_new_pin"/>
-
- <EditText android:id="@id/vm_new_pin"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textColor="?android:attr/textColorSecondary"
- android:inputType="numberPassword"/>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 62b56f3..00472ea 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -569,7 +569,7 @@
<string name="sim_description_emergency_calls" msgid="7535215397212301562">"Samo za hitne pozive"</string>
<string name="sim_description_default" msgid="4778679519938775515">"SIM kartica, otvor: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
<string name="accessibility_settings_activity_title" msgid="8562004288733103868">"Pristupačnost"</string>
- <string name="status_hint_label_incoming_wifi_call" msgid="8772915926382037499">"Dolazni Wi-Fi poziv"</string>
+ <string name="status_hint_label_incoming_wifi_call" msgid="5932176406432044638">"Wi-Fi poziv od"</string>
<string name="status_hint_label_wifi_call" msgid="8900805254974653903">"Wi-Fi poziv"</string>
<string name="emergency_action_launch_hint" msgid="4906759256275562674">"Dodirnite ponovo da biste otvorili"</string>
<string name="message_decode_error" msgid="3456481534066924855">"Došlo je do greške pri dekodiranju poruke."</string>
diff --git a/res/values-be-rBY/strings.xml b/res/values-be-rBY/strings.xml
index e33db92..2a3bc77 100644
--- a/res/values-be-rBY/strings.xml
+++ b/res/values-be-rBY/strings.xml
@@ -572,7 +572,7 @@
<string name="sim_description_emergency_calls" msgid="7535215397212301562">"Толькі экстранныя выклікі"</string>
<string name="sim_description_default" msgid="4778679519938775515">"SIM-карта, гняздо: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
<string name="accessibility_settings_activity_title" msgid="8562004288733103868">"Спецыяльныя магчымасці"</string>
- <string name="status_hint_label_incoming_wifi_call" msgid="8772915926382037499">"Уваход. выклік праз Wi-Fi"</string>
+ <string name="status_hint_label_incoming_wifi_call" msgid="5932176406432044638">"Выклік праз Wi-Fi ад"</string>
<string name="status_hint_label_wifi_call" msgid="8900805254974653903">"Выклік праз Wi-Fi"</string>
<string name="emergency_action_launch_hint" msgid="4906759256275562674">"Дакраніцеся яшчэ раз, каб адкрыць"</string>
<string name="message_decode_error" msgid="3456481534066924855">"Памылка расшыфравання паведамлення."</string>
diff --git a/res/values-bs-rBA/strings.xml b/res/values-bs-rBA/strings.xml
index c711127..3e8eb07 100644
--- a/res/values-bs-rBA/strings.xml
+++ b/res/values-bs-rBA/strings.xml
@@ -569,7 +569,7 @@
<string name="sim_description_emergency_calls" msgid="7535215397212301562">"Samo hitni pozivi"</string>
<string name="sim_description_default" msgid="4778679519938775515">"SIM kartica, utor: <xliff:g id="SLOT_ID">%s</xliff:g>"</string>
<string name="accessibility_settings_activity_title" msgid="8562004288733103868">"Pristupačnost"</string>
- <string name="status_hint_label_incoming_wifi_call" msgid="8772915926382037499">"Dolazni Wi-Fi poziv"</string>
+ <string name="status_hint_label_incoming_wifi_call" msgid="5932176406432044638">"Wi-Fi poziv od"</string>
<string name="status_hint_label_wifi_call" msgid="8900805254974653903">"Wi-Fi poziv"</string>
<string name="emergency_action_launch_hint" msgid="4906759256275562674">"Dodirnite ponovo da otvorite"</string>
<string name="message_decode_error" msgid="3456481534066924855">"Došlo je do greške prilikom dekodiranja poruke."</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index fe87ee6..e095c18 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -364,7 +364,7 @@
<string name="tty_mode_option_summary" msgid="1073835131534808732">"تنظیم حالت TTY"</string>
<string name="auto_retry_mode_title" msgid="4073265511427813322">"سعی مجدد خودکار"</string>
<string name="auto_retry_mode_summary" msgid="4973886004067532288">"فعال کردن حالت سعی مجدد خودکار"</string>
- <string name="tty_mode_not_allowed_video_call" msgid="3795846787901909176">"تغییر حالت TTY در طول تماس ویدئویی مجاز نیست"</string>
+ <string name="tty_mode_not_allowed_video_call" msgid="3795846787901909176">"تغییر حالت TTY در طول تماس ویدیویی مجاز نیست"</string>
<string name="menu_add" msgid="1882023737425114762">"افزودن مخاطب"</string>
<string name="menu_edit" msgid="7143003705504672374">"ویرایش مخاطب"</string>
<string name="menu_delete" msgid="3977150783449642851">"حذف مخاطب"</string>
@@ -476,7 +476,7 @@
<string name="onscreenManageCallsText" msgid="5473231160123254154">"مدیریت تماسها"</string>
<string name="onscreenManageConferenceText" msgid="6485935856534311346">"مدیریت کنفرانس"</string>
<string name="onscreenAudioText" msgid="1710087112800041743">"صوتی"</string>
- <string name="onscreenVideoCallText" msgid="4800924186056115442">"تماس ویدئویی"</string>
+ <string name="onscreenVideoCallText" msgid="4800924186056115442">"تماس ویدیویی"</string>
<string name="importSimEntry" msgid="6614358325359736031">"وارد کردن"</string>
<string name="importAllSimEntries" msgid="1503181169636198673">"وارد کردن همه"</string>
<string name="importingSimContacts" msgid="7374056215462575769">"وارد کردن مخاطبین سیم"</string>
@@ -558,8 +558,8 @@
<string name="voicemail_notification_ringtone_title" msgid="2609519527849101590">"صدا"</string>
<string name="preference_category_ringtone" msgid="5197960752529332721">"آهنگ زنگ و لرزش"</string>
<string name="pstn_connection_service_label" msgid="1743245930577325900">"سیمکارتهای داخلی"</string>
- <string name="enable_video_calling_title" msgid="7237253660669000899">"روشن کردن تماس ویدئویی"</string>
- <string name="enable_video_calling_dialog_msg" msgid="8948186136957417948">"برای روشن کردن تماس ویدئویی، باید حالت پیشرفته 4G LTE را در تنظیمات شبکه فعال کنید."</string>
+ <string name="enable_video_calling_title" msgid="7237253660669000899">"روشن کردن تماس ویدیویی"</string>
+ <string name="enable_video_calling_dialog_msg" msgid="8948186136957417948">"برای روشن کردن تماس ویدیویی، باید حالت پیشرفته 4G LTE را در تنظیمات شبکه فعال کنید."</string>
<string name="enable_video_calling_dialog_settings" msgid="576528473599603249">"تنظیمات شبکه"</string>
<string name="enable_video_calling_dialog_close" msgid="7411471282167927991">"بستن"</string>
<string name="sim_label_emergency_calls" msgid="4847699229529306397">"تماسهای اضطراری"</string>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index dccc579..774ecab 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -21,7 +21,7 @@
<string name="emergencyDialerIconLabel" msgid="7812140032168171053">"ತುರ್ತು ಡಯಲರ್"</string>
<string name="phoneIconLabel" msgid="2331230813161304895">"ಫೋನ್"</string>
<string name="fdnListLabel" msgid="8630418672279521003">"FDN ಪಟ್ಟಿ"</string>
- <string name="unknown" msgid="6878797917991465859">"ಅಪರಿಚಿತ"</string>
+ <string name="unknown" msgid="6878797917991465859">"ಅಜ್ಞಾತ"</string>
<string name="private_num" msgid="6713286113000232309">"ಖಾಸಗಿ ಸಂಖ್ಯೆ"</string>
<string name="payphone" msgid="4793877574636445118">"ಪೇಫೋನ್"</string>
<string name="onHold" msgid="9035493194749959955">"ತಡೆಹಿಡಿಯಲಾಗಿದೆ"</string>
diff --git a/res/xml/vvm_config.xml b/res/xml/vvm_config.xml
index 8807ca9..19c667e 100644
--- a/res/xml/vvm_config.xml
+++ b/res/xml/vvm_config.xml
@@ -23,6 +23,26 @@
</pbundle_as_map>
<pbundle_as_map>
+ <!-- Orange France -->
+ <string-array name="mccmnc">
+ <item value="20801"/>
+ <item value="20802"/>
+ </string-array>
+
+ <int name="vvm_port_number_int" value="20481"/>
+ <string name="vvm_destination_number_string">21101</string>
+ <string-array name="carrier_vvm_package_name_string_array">
+ <item value="com.orange.vvm"/>
+ </string-array>
+ <string name="vvm_type_string">vvm_type_omtp</string>
+ <boolean name="vvm_cellular_data_required_bool" value="true"/>
+ <string-array name="vvm_disabled_capabilities_string_array">
+ <!-- b/32365569 -->
+ <item value="STARTTLS"/>
+ </string-array>
+ </pbundle_as_map>
+
+ <pbundle_as_map>
<!-- T-Mobile USA-->
<string-array name="mccmnc">
<item value="310160"/>
diff --git a/src/com/android/phone/CellBroadcastSms.java b/src/com/android/phone/CellBroadcastSms.java
deleted file mode 100644
index 7428321..0000000
--- a/src/com/android/phone/CellBroadcastSms.java
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.phone;
-
-import android.os.Bundle;
-import android.preference.CheckBoxPreference;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceScreen;
-import android.preference.PreferenceActivity;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.RILConstants;
-
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-
-/**
- * List of Phone-specific settings screens.
- */
-public class CellBroadcastSms extends PreferenceActivity
- implements Preference.OnPreferenceChangeListener{
- // debug data
- private static final String LOG_TAG = "CellBroadcastSms";
- private static final boolean DBG = false;
-
- //String keys for preference lookup
- private static final String BUTTON_ENABLE_DISABLE_BC_SMS_KEY =
- "button_enable_disable_cell_bc_sms";
- private static final String LIST_LANGUAGE_KEY =
- "list_language";
- private static final String BUTTON_EMERGENCY_BROADCAST_KEY =
- "button_emergency_broadcast";
- private static final String BUTTON_ADMINISTRATIVE_KEY =
- "button_administrative";
- private static final String BUTTON_MAINTENANCE_KEY =
- "button_maintenance";
- private static final String BUTTON_LOCAL_WEATHER_KEY =
- "button_local_weather";
- private static final String BUTTON_ATR_KEY =
- "button_atr";
- private static final String BUTTON_LAFS_KEY =
- "button_lafs";
- private static final String BUTTON_RESTAURANTS_KEY =
- "button_restaurants";
- private static final String BUTTON_LODGINGS_KEY =
- "button_lodgings";
- private static final String BUTTON_RETAIL_DIRECTORY_KEY =
- "button_retail_directory";
- private static final String BUTTON_ADVERTISEMENTS_KEY =
- "button_advertisements";
- private static final String BUTTON_STOCK_QUOTES_KEY =
- "button_stock_quotes";
- private static final String BUTTON_EO_KEY =
- "button_eo";
- private static final String BUTTON_MHH_KEY =
- "button_mhh";
- private static final String BUTTON_TECHNOLOGY_NEWS_KEY =
- "button_technology_news";
- private static final String BUTTON_MULTI_CATEGORY_KEY =
- "button_multi_category";
-
- private static final String BUTTON_LOCAL_GENERAL_NEWS_KEY =
- "button_local_general_news";
- private static final String BUTTON_REGIONAL_GENERAL_NEWS_KEY =
- "button_regional_general_news";
- private static final String BUTTON_NATIONAL_GENERAL_NEWS_KEY =
- "button_national_general_news";
- private static final String BUTTON_INTERNATIONAL_GENERAL_NEWS_KEY =
- "button_international_general_news";
-
- private static final String BUTTON_LOCAL_BF_NEWS_KEY =
- "button_local_bf_news";
- private static final String BUTTON_REGIONAL_BF_NEWS_KEY =
- "button_regional_bf_news";
- private static final String BUTTON_NATIONAL_BF_NEWS_KEY =
- "button_national_bf_news";
- private static final String BUTTON_INTERNATIONAL_BF_NEWS_KEY =
- "button_international_bf_news";
-
- private static final String BUTTON_LOCAL_SPORTS_NEWS_KEY =
- "button_local_sports_news";
- private static final String BUTTON_REGIONAL_SPORTS_NEWS_KEY =
- "button_regional_sports_news";
- private static final String BUTTON_NATIONAL_SPORTS_NEWS_KEY =
- "button_national_sports_news";
- private static final String BUTTON_INTERNATIONAL_SPORTS_NEWS_KEY =
- "button_international_sports_news";
-
- private static final String BUTTON_LOCAL_ENTERTAINMENT_NEWS_KEY =
- "button_local_entertainment_news";
- private static final String BUTTON_REGIONAL_ENTERTAINMENT_NEWS_KEY =
- "button_regional_entertainment_news";
- private static final String BUTTON_NATIONAL_ENTERTAINMENT_NEWS_KEY =
- "button_national_entertainment_news";
- private static final String BUTTON_INTERNATIONAL_ENTERTAINMENT_NEWS_KEY =
- "button_international_entertainment_news";
-
- //Class constants
- //These values are related to the C structs. See the comments in method
- //setCbSmsConfig for more information.
- private static final int NO_OF_SERVICE_CATEGORIES = 31;
- private static final int NO_OF_INTS_STRUCT_1 = 3;
- private static final int MAX_LENGTH_RESULT = NO_OF_SERVICE_CATEGORIES * NO_OF_INTS_STRUCT_1 + 1;
- //Handler keys
- private static final int MESSAGE_ACTIVATE_CB_SMS = 1;
- private static final int MESSAGE_GET_CB_SMS_CONFIG = 2;
- private static final int MESSAGE_SET_CB_SMS_CONFIG = 3;
-
- //UI objects
- private CheckBoxPreference mButtonBcSms;
-
- private ListPreference mListLanguage;
-
- private CheckBoxPreference mButtonEmergencyBroadcast;
- private CheckBoxPreference mButtonAdministrative;
- private CheckBoxPreference mButtonMaintenance;
- private CheckBoxPreference mButtonLocalWeather;
- private CheckBoxPreference mButtonAtr;
- private CheckBoxPreference mButtonLafs;
- private CheckBoxPreference mButtonRestaurants;
- private CheckBoxPreference mButtonLodgings;
- private CheckBoxPreference mButtonRetailDirectory;
- private CheckBoxPreference mButtonAdvertisements;
- private CheckBoxPreference mButtonStockQuotes;
- private CheckBoxPreference mButtonEo;
- private CheckBoxPreference mButtonMhh;
- private CheckBoxPreference mButtonTechnologyNews;
- private CheckBoxPreference mButtonMultiCategory;
-
- private CheckBoxPreference mButtonLocal1;
- private CheckBoxPreference mButtonRegional1;
- private CheckBoxPreference mButtonNational1;
- private CheckBoxPreference mButtonInternational1;
-
- private CheckBoxPreference mButtonLocal2;
- private CheckBoxPreference mButtonRegional2;
- private CheckBoxPreference mButtonNational2;
- private CheckBoxPreference mButtonInternational2;
-
- private CheckBoxPreference mButtonLocal3;
- private CheckBoxPreference mButtonRegional3;
- private CheckBoxPreference mButtonNational3;
- private CheckBoxPreference mButtonInternational3;
-
- private CheckBoxPreference mButtonLocal4;
- private CheckBoxPreference mButtonRegional4;
- private CheckBoxPreference mButtonNational4;
- private CheckBoxPreference mButtonInternational4;
-
-
- //Member variables
- private Phone mPhone;
- private MyHandler mHandler;
-
- /**
- * Invoked on each preference click in this hierarchy, overrides
- * PreferenceActivity's implementation. Used to make sure we track the
- * preference click events.
- */
- @Override
- public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
- Preference preference) {
- if (preference == mButtonBcSms) {
- if (DBG) Log.d(LOG_TAG, "onPreferenceTreeClick: preference == mButtonBcSms.");
- if(mButtonBcSms.isChecked()) {
- mPhone.activateCellBroadcastSms(RILConstants.CDMA_CELL_BROADCAST_SMS_ENABLED,
- Message.obtain(mHandler, MESSAGE_ACTIVATE_CB_SMS));
- android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
- android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
- RILConstants.CDMA_CELL_BROADCAST_SMS_ENABLED);
- enableDisableAllCbConfigButtons(true);
- } else {
- mPhone.activateCellBroadcastSms(RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED,
- Message.obtain(mHandler, MESSAGE_ACTIVATE_CB_SMS));
- android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
- android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
- RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
- enableDisableAllCbConfigButtons(false);
- }
- } else if (preference == mListLanguage) {
- //Do nothing here, because this click will be handled in onPreferenceChange
- } else if (preference == mButtonEmergencyBroadcast) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonEmergencyBroadcast.isChecked(), 1);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(
- mButtonEmergencyBroadcast.isChecked(), 1);
- } else if (preference == mButtonAdministrative) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonAdministrative.isChecked(), 2);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonAdministrative.isChecked(), 2);
- } else if (preference == mButtonMaintenance) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonMaintenance.isChecked(), 3);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonMaintenance.isChecked(), 3);
- } else if (preference == mButtonLocalWeather) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonLocalWeather.isChecked(), 20);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLocalWeather.isChecked(), 20);
- } else if (preference == mButtonAtr) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonAtr.isChecked(), 21);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonAtr.isChecked(), 21);
- } else if (preference == mButtonLafs) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLafs.isChecked(), 22);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLafs.isChecked(), 22);
- } else if (preference == mButtonRestaurants) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonRestaurants.isChecked(), 23);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRestaurants.isChecked(), 23);
- } else if (preference == mButtonLodgings) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLodgings.isChecked(), 24);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLodgings.isChecked(), 24);
- } else if (preference == mButtonRetailDirectory) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonRetailDirectory.isChecked(), 25);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRetailDirectory.isChecked(), 25);
- } else if (preference == mButtonAdvertisements) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonAdvertisements.isChecked(), 26);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonAdvertisements.isChecked(), 26);
- } else if (preference == mButtonStockQuotes) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonStockQuotes.isChecked(), 27);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonStockQuotes.isChecked(), 27);
- } else if (preference == mButtonEo) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonEo.isChecked(), 28);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonEo.isChecked(), 28);
- } else if (preference == mButtonMhh) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonMhh.isChecked(), 29);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonMhh.isChecked(), 29);
- } else if (preference == mButtonTechnologyNews) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonTechnologyNews.isChecked(), 30);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonTechnologyNews.isChecked(), 30);
- } else if (preference == mButtonMultiCategory) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonMultiCategory.isChecked(), 31);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonMultiCategory.isChecked(), 31);
- } else if (preference == mButtonLocal1) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLocal1.isChecked(), 4);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLocal1.isChecked(), 4);
- } else if (preference == mButtonRegional1) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonRegional1.isChecked(), 5);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRegional1.isChecked(), 5);
- } else if (preference == mButtonNational1) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonNational1.isChecked(), 6);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonNational1.isChecked(), 6);
- } else if (preference == mButtonInternational1) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonInternational1.isChecked(), 7);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonInternational1.isChecked(), 7);
- } else if (preference == mButtonLocal2) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLocal2.isChecked(), 8);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLocal2.isChecked(), 8);
- } else if (preference == mButtonRegional2) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonRegional2.isChecked(), 9);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRegional2.isChecked(), 9);
- } else if (preference == mButtonNational2) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonNational2.isChecked(), 10);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonNational2.isChecked(), 10);
- } else if (preference == mButtonInternational2) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonInternational2.isChecked(), 11);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonInternational2.isChecked(), 11);
- } else if (preference == mButtonLocal3) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLocal3.isChecked(), 12);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLocal3.isChecked(), 12);
- } else if (preference == mButtonRegional3) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonRegional3.isChecked(), 13);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRegional3.isChecked(), 13);
- } else if (preference == mButtonNational3) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonNational3.isChecked(), 14);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonNational3.isChecked(), 14);
- } else if (preference == mButtonInternational3) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonInternational3.isChecked(), 15);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonInternational3.isChecked(), 15);
- } else if (preference == mButtonLocal4) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(mButtonLocal4.isChecked(), 16);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonLocal4.isChecked(), 16);
- } else if (preference == mButtonRegional4) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonRegional4.isChecked(), 17);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonRegional4.isChecked(), 17);
- } else if (preference == mButtonNational4) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonNational4.isChecked(), 18);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonNational4.isChecked(), 18);
- } else if (preference == mButtonInternational4) {
- CellBroadcastSmsConfig.setConfigDataCompleteBSelected(
- mButtonInternational4.isChecked(), 19);
- CellBroadcastSmsConfig.setCbSmsBSelectedValue(mButtonInternational4.isChecked(), 19);
- } else {
- preferenceScreen.setEnabled(false);
- return false;
- }
-
- return true;
- }
-
- public boolean onPreferenceChange(Preference preference, Object objValue) {
- if (preference == mListLanguage) {
- // set the new language to the array which will be transmitted later
- CellBroadcastSmsConfig.setConfigDataCompleteLanguage(
- mListLanguage.findIndexOfValue((String) objValue) + 1);
- }
-
- // always let the preference setting proceed.
- return true;
- }
-
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- addPreferencesFromResource(R.xml.cell_broadcast_sms);
-
- mPhone = PhoneGlobals.getPhone();
- mHandler = new MyHandler();
-
- PreferenceScreen prefSet = getPreferenceScreen();
-
- mButtonBcSms = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_ENABLE_DISABLE_BC_SMS_KEY);
- mListLanguage = (ListPreference) prefSet.findPreference(
- LIST_LANGUAGE_KEY);
- // set the listener for the language list preference
- mListLanguage.setOnPreferenceChangeListener(this);
- mButtonEmergencyBroadcast = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_EMERGENCY_BROADCAST_KEY);
- mButtonAdministrative = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_ADMINISTRATIVE_KEY);
- mButtonMaintenance = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_MAINTENANCE_KEY);
- mButtonLocalWeather = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_LOCAL_WEATHER_KEY);
- mButtonAtr = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_ATR_KEY);
- mButtonLafs = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_LAFS_KEY);
- mButtonRestaurants = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_RESTAURANTS_KEY);
- mButtonLodgings = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_LODGINGS_KEY);
- mButtonRetailDirectory = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_RETAIL_DIRECTORY_KEY);
- mButtonAdvertisements = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_ADVERTISEMENTS_KEY);
- mButtonStockQuotes = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_STOCK_QUOTES_KEY);
- mButtonEo = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_EO_KEY);
- mButtonMhh = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_MHH_KEY);
- mButtonTechnologyNews = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_TECHNOLOGY_NEWS_KEY);
- mButtonMultiCategory = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_MULTI_CATEGORY_KEY);
-
- mButtonLocal1 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_LOCAL_GENERAL_NEWS_KEY);
- mButtonRegional1 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_REGIONAL_GENERAL_NEWS_KEY);
- mButtonNational1 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_NATIONAL_GENERAL_NEWS_KEY);
- mButtonInternational1 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_INTERNATIONAL_GENERAL_NEWS_KEY);
-
- mButtonLocal2 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_LOCAL_BF_NEWS_KEY);
- mButtonRegional2 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_REGIONAL_BF_NEWS_KEY);
- mButtonNational2 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_NATIONAL_BF_NEWS_KEY);
- mButtonInternational2 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_INTERNATIONAL_BF_NEWS_KEY);
-
- mButtonLocal3 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_LOCAL_SPORTS_NEWS_KEY);
- mButtonRegional3 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_REGIONAL_SPORTS_NEWS_KEY);
- mButtonNational3 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_NATIONAL_SPORTS_NEWS_KEY);
- mButtonInternational3 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_INTERNATIONAL_SPORTS_NEWS_KEY);
-
- mButtonLocal4 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_LOCAL_ENTERTAINMENT_NEWS_KEY);
- mButtonRegional4 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_REGIONAL_ENTERTAINMENT_NEWS_KEY);
- mButtonNational4 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_NATIONAL_ENTERTAINMENT_NEWS_KEY);
- mButtonInternational4 = (CheckBoxPreference) prefSet.findPreference(
- BUTTON_INTERNATIONAL_ENTERTAINMENT_NEWS_KEY);
- }
-
- @Override
- protected void onResume() {
- super.onResume();
-
- getPreferenceScreen().setEnabled(true);
-
- int settingCbSms = android.provider.Settings.Global.getInt(
- mPhone.getContext().getContentResolver(),
- android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
- RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
- mButtonBcSms.setChecked(settingCbSms == RILConstants.CDMA_CELL_BROADCAST_SMS_ENABLED);
-
- if(mButtonBcSms.isChecked()) {
- enableDisableAllCbConfigButtons(true);
- } else {
- enableDisableAllCbConfigButtons(false);
- }
-
- mPhone.getCellBroadcastSmsConfig(Message.obtain(mHandler, MESSAGE_GET_CB_SMS_CONFIG));
- }
-
- @Override
- protected void onPause() {
- super.onPause();
-
- CellBroadcastSmsConfig.setCbSmsNoOfStructs(NO_OF_SERVICE_CATEGORIES);
-
- mPhone.setCellBroadcastSmsConfig(CellBroadcastSmsConfig.getCbSmsAllValues(),
- Message.obtain(mHandler, MESSAGE_SET_CB_SMS_CONFIG));
- }
-
- private void enableDisableAllCbConfigButtons(boolean enable) {
- mButtonEmergencyBroadcast.setEnabled(enable);
- mListLanguage.setEnabled(enable);
- mButtonAdministrative.setEnabled(enable);
- mButtonMaintenance.setEnabled(enable);
- mButtonLocalWeather.setEnabled(enable);
- mButtonAtr.setEnabled(enable);
- mButtonLafs.setEnabled(enable);
- mButtonRestaurants.setEnabled(enable);
- mButtonLodgings.setEnabled(enable);
- mButtonRetailDirectory.setEnabled(enable);
- mButtonAdvertisements.setEnabled(enable);
- mButtonStockQuotes.setEnabled(enable);
- mButtonEo.setEnabled(enable);
- mButtonMhh.setEnabled(enable);
- mButtonTechnologyNews.setEnabled(enable);
- mButtonMultiCategory.setEnabled(enable);
-
- mButtonLocal1.setEnabled(enable);
- mButtonRegional1.setEnabled(enable);
- mButtonNational1.setEnabled(enable);
- mButtonInternational1.setEnabled(enable);
-
- mButtonLocal2.setEnabled(enable);
- mButtonRegional2.setEnabled(enable);
- mButtonNational2.setEnabled(enable);
- mButtonInternational2.setEnabled(enable);
-
- mButtonLocal3.setEnabled(enable);
- mButtonRegional3.setEnabled(enable);
- mButtonNational3.setEnabled(enable);
- mButtonInternational3.setEnabled(enable);
-
- mButtonLocal4.setEnabled(enable);
- mButtonRegional4.setEnabled(enable);
- mButtonNational4.setEnabled(enable);
- mButtonInternational4.setEnabled(enable);
- }
-
- private void setAllCbConfigButtons(int[] configArray) {
- //These buttons are in a well defined sequence. If you want to change it,
- //be sure to map the buttons to their corresponding slot in the configArray !
- mButtonEmergencyBroadcast.setChecked(configArray[1] != 0);
- //subtract 1, because the values are handled in an array which starts with 0 and not with 1
- mListLanguage.setValueIndex(CellBroadcastSmsConfig.getConfigDataLanguage() - 1);
- mButtonAdministrative.setChecked(configArray[2] != 0);
- mButtonMaintenance.setChecked(configArray[3] != 0);
- mButtonLocalWeather.setChecked(configArray[20] != 0);
- mButtonAtr.setChecked(configArray[21] != 0);
- mButtonLafs.setChecked(configArray[22] != 0);
- mButtonRestaurants.setChecked(configArray[23] != 0);
- mButtonLodgings.setChecked(configArray[24] != 0);
- mButtonRetailDirectory.setChecked(configArray[25] != 0);
- mButtonAdvertisements.setChecked(configArray[26] != 0);
- mButtonStockQuotes.setChecked(configArray[27] != 0);
- mButtonEo.setChecked(configArray[28] != 0);
- mButtonMhh.setChecked(configArray[29] != 0);
- mButtonTechnologyNews.setChecked(configArray[30] != 0);
- mButtonMultiCategory.setChecked(configArray[31] != 0);
-
- mButtonLocal1.setChecked(configArray[4] != 0);
- mButtonRegional1.setChecked(configArray[5] != 0);
- mButtonNational1.setChecked(configArray[6] != 0);
- mButtonInternational1.setChecked(configArray[7] != 0);
-
- mButtonLocal2.setChecked(configArray[8] != 0);
- mButtonRegional2.setChecked(configArray[9] != 0);
- mButtonNational2.setChecked(configArray[10] != 0);
- mButtonInternational2.setChecked(configArray[11] != 0);
-
- mButtonLocal3.setChecked(configArray[12] != 0);
- mButtonRegional3.setChecked(configArray[13] != 0);
- mButtonNational3.setChecked(configArray[14] != 0);
- mButtonInternational3.setChecked(configArray[15] != 0);
-
- mButtonLocal4.setChecked(configArray[16] != 0);
- mButtonRegional4.setChecked(configArray[17] != 0);
- mButtonNational4.setChecked(configArray[18] != 0);
- mButtonInternational4.setChecked(configArray[19] != 0);
- }
-
- private class MyHandler extends Handler {
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_ACTIVATE_CB_SMS:
- //Only a log message here, because the received response is always null
- if (DBG) Log.d(LOG_TAG, "Cell Broadcast SMS enabled/disabled.");
- break;
- case MESSAGE_GET_CB_SMS_CONFIG:
- int result[] = (int[])((AsyncResult)msg.obj).result;
-
- // check if the actual service categoties table size on the NV is '0'
- if (result[0] == 0) {
- result[0] = NO_OF_SERVICE_CATEGORIES;
-
- mButtonBcSms.setChecked(false);
- mPhone.activateCellBroadcastSms(RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED,
- Message.obtain(mHandler, MESSAGE_ACTIVATE_CB_SMS));
- android.provider.Settings.Global.putInt(mPhone.getContext().getContentResolver(),
- android.provider.Settings.Global.CDMA_CELL_BROADCAST_SMS,
- RILConstants.CDMA_CELL_BROADCAST_SMS_DISABLED);
- enableDisableAllCbConfigButtons(false);
- }
-
- CellBroadcastSmsConfig.setCbSmsConfig(result);
- setAllCbConfigButtons(CellBroadcastSmsConfig.getCbSmsBselectedValues());
-
- break;
- case MESSAGE_SET_CB_SMS_CONFIG:
- //Only a log message here, because the received response is always null
- if (DBG) Log.d(LOG_TAG, "Set Cell Broadcast SMS values.");
- break;
- default:
- Log.e(LOG_TAG, "Error! Unhandled message in CellBroadcastSms.java. Message: "
- + msg.what);
- break;
- }
- }
- }
-
- private static final class CellBroadcastSmsConfig {
-
- //The values in this array are stored in a particular order. This order
- //is calculated in the setCbSmsConfig method of this class.
- //For more information see comments below...
- //NO_OF_SERVICE_CATEGORIES +1 is used, because we will leave the first array entry 0
- private static int mBSelected[] = new int[NO_OF_SERVICE_CATEGORIES + 1];
- private static int mConfigDataComplete[] = new int[MAX_LENGTH_RESULT];
-
- private static void setCbSmsConfig(int[] configData) {
- if(configData == null) {
- Log.e(LOG_TAG, "Error! No cell broadcast service categories returned.");
- return;
- }
-
- if(configData[0] > MAX_LENGTH_RESULT) {
- Log.e(LOG_TAG, "Error! Wrong number of service categories returned from RIL");
- return;
- }
-
- //The required config values for broadcast SMS are stored in a C struct:
- //
- // typedef struct {
- // int size;
- // RIL_CDMA_BcServiceInfo *entries;
- // } RIL_CDMA_BcSMSConfig;
- //
- // typedef struct {
- // int uServiceCategory;
- // int uLanguage;
- // unsigned char bSelected;
- // } RIL_CDMA_BcServiceInfo;
- //
- // This means, that we have to ignore the first value and check every
- // 3rd value starting with the 2nd of all. This value indicates, where we
- // will store the appropriate bSelected value, which is 2 values behind it.
- for(int i = 1; i < configData.length; i += NO_OF_INTS_STRUCT_1) {
- mBSelected[configData[i]] = configData[i +2];
- }
-
- //Store all values in an extra array
- mConfigDataComplete = configData;
- }
-
- private static void setCbSmsBSelectedValue(boolean value, int pos) {
- if(pos < mBSelected.length) {
- mBSelected[pos] = (value == true ? 1 : 0);
- } else {
- Log.e(LOG_TAG,"Error! Invalid value position.");
- }
- }
-
- private static int[] getCbSmsBselectedValues() {
- return(mBSelected);
- }
-
- // TODO: Change the return value to a RIL_BroadcastSMSConfig
- private static int[] getCbSmsAllValues() {
- return(mConfigDataComplete);
- }
-
- private static void setCbSmsNoOfStructs(int value) {
- //Sets the size parameter, which contains the number of structs
- //that will be transmitted
- mConfigDataComplete[0] = value;
- }
-
- private static void setConfigDataCompleteBSelected(boolean value, int serviceCategory) {
- //Sets the bSelected value for a specific serviceCategory
- for(int i = 1; i < mConfigDataComplete.length; i += NO_OF_INTS_STRUCT_1) {
- if(mConfigDataComplete[i] == serviceCategory) {
- mConfigDataComplete[i + 2] = value == true ? 1 : 0;
- break;
- }
- }
- }
-
- private static void setConfigDataCompleteLanguage(int language) {
- //It is only possible to set the same language for all entries
- for(int i = 2; i < mConfigDataComplete.length; i += NO_OF_INTS_STRUCT_1) {
- mConfigDataComplete[i] = language;
- }
- }
-
- private static int getConfigDataLanguage() {
- int language = mConfigDataComplete[2];
- //2 is the language value of the first entry
- //It is only possible to set the same language for all entries
- if (language < 1 || language > 7) {
- Log.e(LOG_TAG, "Error! Wrong language returned from RIL...defaulting to 1, english");
- return 1;
- }
- else {
- return language;
- }
- }
- }
-}
diff --git a/src/com/android/phone/EmergencyDialer.java b/src/com/android/phone/EmergencyDialer.java
index 227e112..1d34788 100644
--- a/src/com/android/phone/EmergencyDialer.java
+++ b/src/com/android/phone/EmergencyDialer.java
@@ -515,6 +515,11 @@
*/
private void placeCall() {
mLastNumber = mDigits.getText().toString();
+ // Convert into emergency number if necessary
+ // This is required in some regions (e.g. Taiwan).
+ if (PhoneNumberUtils.isConvertToEmergencyNumberEnabled()) {
+ mLastNumber = PhoneNumberUtils.convertToEmergencyNumber(mLastNumber);
+ }
if (PhoneNumberUtils.isLocalEmergencyNumber(this, mLastNumber)) {
if (DBG) Log.d(LOG_TAG, "placing call to " + mLastNumber);
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index 9504f34..d40b08e 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -47,11 +47,13 @@
import android.util.ArrayMap;
import android.util.Log;
import android.widget.Toast;
+
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.TelephonyCapabilities;
import com.android.phone.settings.VoicemailNotificationSettingsUtil;
import com.android.phone.settings.VoicemailSettingsActivity;
import com.android.phone.vvm.omtp.sync.VoicemailStatusQueryHelper;
+
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -72,6 +74,9 @@
// Do not check in with VDBG = true, since that may write PII to the system log.
private static final boolean VDBG = false;
+ private static final String MWI_SHOULD_CHECK_VVM_CONFIGURATION_KEY_PREFIX =
+ "mwi_should_check_vvm_configuration_state_";
+
// notification types
static final int MMI_NOTIFICATION = 1;
static final int NETWORK_SELECTION_NOTIFICATION = 2;
@@ -201,6 +206,27 @@
}
}
+ public void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, boolean enabled) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ Log.e(LOG_TAG, "setShouldCheckVisualVoicemailConfigurationForMwi: invalid subId"
+ + subId);
+ return;
+ }
+
+ PreferenceManager.getDefaultSharedPreferences(mContext).edit()
+ .putBoolean(MWI_SHOULD_CHECK_VVM_CONFIGURATION_KEY_PREFIX + subId, enabled)
+ .apply();
+ }
+
+ private boolean shouldCheckVisualVoicemailConfigurationForMwi(int subId) {
+ if (!SubscriptionManager.isValidSubscriptionId(subId)) {
+ Log.e(LOG_TAG, "shouldCheckVisualVoicemailConfigurationForMwi: invalid subId" + subId);
+ return true;
+ }
+ return PreferenceManager
+ .getDefaultSharedPreferences(mContext)
+ .getBoolean(MWI_SHOULD_CHECK_VVM_CONFIGURATION_KEY_PREFIX + subId, true);
+ }
/**
* Updates the message waiting indicator (voicemail) notification.
*
@@ -226,7 +252,7 @@
}
Phone phone = PhoneGlobals.getPhone(subId);
- if (visible && phone != null) {
+ if (visible && phone != null && shouldCheckVisualVoicemailConfigurationForMwi(subId)) {
VoicemailStatusQueryHelper queryHelper = new VoicemailStatusQueryHelper(mContext);
PhoneAccountHandle phoneAccount = PhoneUtils.makePstnPhoneAccountHandle(phone);
if (queryHelper.isVoicemailSourceConfigured(phoneAccount)) {
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 2d87e78..14a451f 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -45,6 +45,7 @@
import android.telephony.SubscriptionManager;
import android.util.Log;
import android.widget.Toast;
+
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallManager;
import com.android.internal.telephony.IccCardConstants;
@@ -856,4 +857,23 @@
phone.setVoiceMessageCount(0);
}
}
+
+ /**
+ * Enables or disables the visual voicemail check for message waiting indicator. Default value
+ * is true. MWI is the traditional voicemail notification which should be suppressed if visual
+ * voicemail is active. {@link NotificationMgr#updateMwi(int, boolean, boolean)} currently
+ * checks the {@link android.provider.VoicemailContract.Status#CONFIGURATION_STATE} to suppress
+ * the MWI, but there are several issues. b/31229016 is a bug that when the device boots the
+ * configuration state will be cleared and the MWI for voicemail that arrives when the device
+ * is offline will be cleared, even if the account cannot be activated. A full solution will be
+ * adding a setMwiEnabled() method and stop checking the configuration state, but that is too
+ * risky at this moment. This is a temporary workaround to shut down the configuration state
+ * check if visual voicemail cannot be activated.
+ * <p>TODO(twyen): implement the setMwiEnabled() mentioned above.
+ *
+ * @param subId the account to set the enabled state
+ */
+ public void setShouldCheckVisualVoicemailConfigurationForMwi(int subId, boolean enabled) {
+ notificationMgr.setShouldCheckVisualVoicemailConfigurationForMwi(subId, enabled);
+ }
}
diff --git a/src/com/android/phone/VoicemailStatus.java b/src/com/android/phone/VoicemailStatus.java
index 4d7d388..00130f1 100644
--- a/src/com/android/phone/VoicemailStatus.java
+++ b/src/com/android/phone/VoicemailStatus.java
@@ -83,17 +83,29 @@
return this;
}
- public void apply() {
+ /**
+ * Apply the changes to the {@link VoicemailStatus} {@link #Editor}.
+ *
+ * @return {@code true} if the changes were successfully applied, {@code false} otherwise.
+ */
+ public boolean apply() {
if (mPhoneAccountHandle == null) {
- return;
+ return false;
}
mValues.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
mPhoneAccountHandle.getComponentName().flattenToString());
mValues.put(Status.PHONE_ACCOUNT_ID, mPhoneAccountHandle.getId());
ContentResolver contentResolver = mContext.getContentResolver();
Uri statusUri = VoicemailContract.Status.buildSourceUri(mContext.getPackageName());
- contentResolver.insert(statusUri, mValues);
+ try {
+ contentResolver.insert(statusUri, mValues);
+ } catch (IllegalArgumentException iae) {
+ VvmLog.e(TAG, "apply :: failed to insert content resolver ", iae);
+ mValues.clear();
+ return false;
+ }
mValues.clear();
+ return true;
}
public ContentValues getValues() {
@@ -114,8 +126,9 @@
}
@Override
- public void apply() {
+ public boolean apply() {
// Do nothing
+ return true;
}
public void deferredApply() {
diff --git a/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java b/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
index f78dbdf..436d03c 100644
--- a/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
+++ b/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
@@ -54,7 +54,7 @@
*/
public static class Data {
- private static final String CHARSET = "utf-8'";
+ private static final String CHARSET = "utf-8";
public String username;
public String password;
diff --git a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
index b556aa1..22fb70e 100644
--- a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
+++ b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
@@ -17,8 +17,6 @@
import android.content.Context;
import android.telecom.PhoneAccountHandle;
-import com.android.internal.telephony.Phone;
-import com.android.phone.PhoneUtils;
import com.android.phone.R;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
@@ -67,11 +65,6 @@
PhoneAccountHandleConverter.toSubId(phoneAccount)).isEnabledByDefault();
}
- public static boolean isEnabled(Phone phone) {
- return isEnabled(phone.getContext(),
- PhoneUtils.makePstnPhoneAccountHandle(phone));
- }
-
/**
* Whether the client enabled status is explicitly set by user or by default(Whether carrier VVM
* app is installed). This is used to determine whether to disable the client when the carrier
diff --git a/src/com/android/phone/settings/VoicemailChangePinActivity.java b/src/com/android/phone/settings/VoicemailChangePinActivity.java
index 8027dc1..33da27a 100644
--- a/src/com/android/phone/settings/VoicemailChangePinActivity.java
+++ b/src/com/android/phone/settings/VoicemailChangePinActivity.java
@@ -35,6 +35,7 @@
import android.text.InputFilter.LengthFilter;
import android.text.TextWatcher;
import android.view.KeyEvent;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
@@ -436,7 +437,19 @@
}
}
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (!mNextButton.isEnabled()) {
+ return true;
+ }
// Check if this was the result of hitting the enter or "done" key
if (actionId == EditorInfo.IME_NULL
|| actionId == EditorInfo.IME_ACTION_DONE
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
index 92e1b5f..35d9a1c 100644
--- a/src/com/android/phone/settings/VoicemailSettingsActivity.java
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -45,7 +45,9 @@
import com.android.phone.PhoneUtils;
import com.android.phone.R;
import com.android.phone.SubscriptionInfoHelper;
+import com.android.phone.vvm.omtp.OmtpConstants;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -193,6 +195,7 @@
private boolean mForeground;
private Phone mPhone;
+ private PhoneAccountHandle mPhoneAccountHandle;
private SubscriptionInfoHelper mSubscriptionInfoHelper;
private OmtpVvmCarrierConfigHelper mOmtpVvmCarrierConfigHelper;
@@ -221,6 +224,7 @@
mSubscriptionInfoHelper.setActionBarTitle(
getActionBar(), getResources(), R.string.voicemail_settings_with_label);
mPhone = mSubscriptionInfoHelper.getPhone();
+ mPhoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(mPhone);
mOmtpVvmCarrierConfigHelper = new OmtpVvmCarrierConfigHelper(
mPhone.getContext(), mPhone.getSubId());
}
@@ -265,13 +269,12 @@
mVoicemailChangePinPreference = findPreference(
getResources().getString(R.string.voicemail_change_pin_key));
- PhoneAccountHandle phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(mPhone);
Intent changePinIntent = new Intent(new Intent(this, VoicemailChangePinActivity.class));
changePinIntent.putExtra(VoicemailChangePinActivity.EXTRA_PHONE_ACCOUNT_HANDLE,
- phoneAccountHandle);
+ mPhoneAccountHandle);
mVoicemailChangePinPreference.setIntent(changePinIntent);
- if (VoicemailChangePinActivity.isDefaultOldPinSet(this, phoneAccountHandle)) {
+ if (VoicemailChangePinActivity.isDefaultOldPinSet(this, mPhoneAccountHandle)) {
mVoicemailChangePinPreference.setTitle(R.string.voicemail_set_pin_dialog_title);
} else {
mVoicemailChangePinPreference.setTitle(R.string.voicemail_change_pin_dialog_title);
@@ -280,7 +283,10 @@
if (mOmtpVvmCarrierConfigHelper.isValid()) {
mVoicemailVisualVoicemail.setOnPreferenceChangeListener(this);
mVoicemailVisualVoicemail.setChecked(
- VisualVoicemailSettingsUtil.isEnabled(mPhone));
+ VisualVoicemailSettingsUtil.isEnabled(this, mPhoneAccountHandle));
+ if (!isVisualVoicemailActivated()) {
+ prefSet.removePreference(mVoicemailChangePinPreference);
+ }
} else {
prefSet.removePreference(mVoicemailVisualVoicemail);
prefSet.removePreference(mVoicemailChangePinPreference);
@@ -406,11 +412,10 @@
mPhone, Boolean.TRUE.equals(objValue));
} else if (preference.getKey().equals(mVoicemailVisualVoicemail.getKey())) {
boolean isEnabled = (boolean) objValue;
- PhoneAccountHandle handle = PhoneUtils.makePstnPhoneAccountHandle(mPhone);
VisualVoicemailSettingsUtil
- .setEnabled(mPhone.getContext(), handle, isEnabled);
+ .setEnabled(mPhone.getContext(), mPhoneAccountHandle, isEnabled);
PreferenceScreen prefSet = getPreferenceScreen();
- if (isEnabled) {
+ if (isVisualVoicemailActivated()) {
prefSet.addPreference(mVoicemailChangePinPreference);
} else {
prefSet.removePreference(mVoicemailChangePinPreference);
@@ -1150,6 +1155,16 @@
return true;
}
+ private boolean isVisualVoicemailActivated() {
+ if (!VisualVoicemailSettingsUtil.isEnabled(this, mPhoneAccountHandle)) {
+ return false;
+ }
+ VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(this,
+ mPhoneAccountHandle);
+ return preferences.getString(OmtpConstants.SERVER_ADDRESS, null) != null;
+
+ }
+
private static void log(String msg) {
Log.d(LOG_TAG, msg);
}
diff --git a/src/com/android/phone/vvm/omtp/ActivationTask.java b/src/com/android/phone/vvm/omtp/ActivationTask.java
index 9c58b95..72f1f54 100644
--- a/src/com/android/phone/vvm/omtp/ActivationTask.java
+++ b/src/com/android/phone/vvm/omtp/ActivationTask.java
@@ -24,10 +24,10 @@
import android.os.Bundle;
import android.provider.Settings;
import android.provider.Settings.Global;
-import android.provider.VoicemailContract.Status;
import android.telecom.PhoneAccountHandle;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
+
import com.android.phone.Assert;
import com.android.phone.PhoneGlobals;
import com.android.phone.VoicemailStatus;
@@ -40,9 +40,11 @@
import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService;
import com.android.phone.vvm.omtp.sync.SyncTask;
import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
+
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
@@ -67,7 +69,7 @@
private final RetryPolicy mRetryPolicy;
- private Bundle mData;
+ private Bundle mMessageData;
public ActivationTask() {
super(TASK_ACTIVATION);
@@ -83,7 +85,12 @@
context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) == 1;
}
- public static void start(Context context, int subId, @Nullable Bundle data) {
+ /**
+ * @param messageData The optional bundle from {@link android.provider.VoicemailContract#
+ * EXTRA_VOICEMAIL_SMS_FIELDS}, if the task is initiated by a status SMS. If null the task will
+ * request a status SMS itself.
+ */
+ public static void start(Context context, int subId, @Nullable Bundle messageData) {
if (!isDeviceProvisioned(context)) {
VvmLog.i(TAG, "Activation requested while device is not provisioned, postponing");
// Activation might need information such as system language to be set, so wait until
@@ -93,31 +100,22 @@
return;
}
- // Check for signal before activating. The event often happen while boot and the
- // network is not connected yet. Launching activation will likely to cause the SMS
- // sending to fail and waste unnecessary time waiting for time out.
- if (context.getSystemService(TelephonyManager.class)
- .getServiceStateForSubscriber(subId).getState()
- != ServiceState.STATE_IN_SERVICE) {
- VvmLog.i(TAG, "Activation requested while not in service, rejecting");
- }
-
Intent intent = BaseTask.createIntent(context, ActivationTask.class, subId);
- if (data != null) {
- intent.putExtra(EXTRA_MESSAGE_DATA_BUNDLE, data);
+ if (messageData != null) {
+ intent.putExtra(EXTRA_MESSAGE_DATA_BUNDLE, messageData);
}
context.startService(intent);
}
public void onCreate(Context context, Intent intent, int flags, int startId) {
super.onCreate(context, intent, flags, startId);
- mData = intent.getParcelableExtra(EXTRA_MESSAGE_DATA_BUNDLE);
+ mMessageData = intent.getParcelableExtra(EXTRA_MESSAGE_DATA_BUNDLE);
}
@Override
public Intent createRestartIntent() {
Intent intent = super.createRestartIntent();
- // mData is discarded, request a fresh STATUS SMS for retries.
+ // mMessageData is discarded, request a fresh STATUS SMS for retries.
return intent;
}
@@ -140,8 +138,22 @@
VoicemailStatus.disable(getContext(), phoneAccountHandle);
return;
}
+
+ // OmtpVvmCarrierConfigHelper can start the activation process; it will pass in a vvm
+ // content provider URI which we will use. On some occasions, setting that URI will
+ // fail, so we will perform a few attempts to ensure that the vvm content provider has
+ // a good chance of being started up.
+ if (!VoicemailStatus.edit(getContext(), phoneAccountHandle)
+ .setType(helper.getVvmType())
+ .apply()) {
+ VvmLog.e(TAG, "Failed to configure content provider - " + helper.getVvmType());
+ fail();
+ }
+ VvmLog.i(TAG, "VVM content provider configured - " + helper.getVvmType());
+
if (!OmtpVvmSourceManager.getInstance(getContext())
.isVvmSourceRegistered(phoneAccountHandle)) {
+ // This account has not been activated before during the lifetime of this boot.
VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(getContext(),
phoneAccountHandle);
if (preferences.getString(OmtpConstants.SERVER_ADDRESS, null) == null) {
@@ -153,12 +165,20 @@
} else {
// The account has been activated on this device before. Pretend it is already
// activated. If there are any activation error it will overwrite this status.
- VoicemailStatus.edit(getContext(), phoneAccountHandle)
- .setConfigurationState(Status.CONFIGURATION_STATE_OK)
- .apply();
+ helper.handleEvent(VoicemailStatus.edit(getContext(), phoneAccountHandle),
+ OmtpEvents.CONFIG_ACTIVATING_SUBSEQUENT);
}
}
+ if (!hasSignal(getContext(), subId)) {
+ VvmLog.i(TAG, "Service lost during activation, aborting");
+ // Restore the "NO SIGNAL" state since it will be overwritten by the CONFIG_ACTIVATING
+ // event.
+ helper.handleEvent(VoicemailStatus.edit(getContext(), phoneAccountHandle),
+ OmtpEvents.NOTIFICATION_SERVICE_LOST);
+ // Don't retry, a new activation will be started after the signal returned.
+ return;
+ }
helper.activateSmsFilter();
VoicemailStatus.Editor status = mRetryPolicy.getVoicemailStatusEditor();
@@ -166,13 +186,13 @@
VisualVoicemailProtocol protocol = helper.getProtocol();
Bundle data;
- if (mData != null) {
+ if (mMessageData != null) {
// The content of STATUS SMS is provided to launch this task, no need to request it
// again.
- data = mData;
+ data = mMessageData;
} else {
try (StatusSmsFetcher fetcher = new StatusSmsFetcher(getContext(), subId)) {
- protocol.startActivation(helper);
+ protocol.startActivation(helper, fetcher.getSentIntent());
// Both the fetcher and OmtpMessageReceiver will be triggered, but
// OmtpMessageReceiver will just route the SMS back to ActivationTask, which will be
// rejected because the task is still running.
@@ -183,6 +203,10 @@
helper.handleEvent(status, OmtpEvents.CONFIG_STATUS_SMS_TIME_OUT);
fail();
return;
+ } catch (CancellationException e) {
+ VvmLog.e(TAG, "Unable to send status request SMS");
+ fail();
+ return;
} catch (InterruptedException | ExecutionException | IOException e) {
VvmLog.e(TAG, "can't get future STATUS SMS", e);
fail();
@@ -210,6 +234,7 @@
} else {
VvmLog.i(TAG, "Subscriber not ready but provisioning is not supported");
helper.handleEvent(status, OmtpEvents.CONFIG_SERVICE_NOT_AVAILABLE);
+ PhoneGlobals.getInstance().setShouldCheckVisualVoicemailConfigurationForMwi(subId, false);
}
}
}
@@ -231,14 +256,21 @@
vvmSourceManager.addSource(phone);
SyncTask.start(context, phone, OmtpVvmSyncService.SYNC_FULL_SYNC);
- // Remove the message waiting indicator, which is a stick notification fo traditional
+ // Remove the message waiting indicator, which is a sticky notification for traditional
// voicemails.
+ PhoneGlobals.getInstance()
+ .setShouldCheckVisualVoicemailConfigurationForMwi(subId, true);
PhoneGlobals.getInstance().clearMwiIndicator(subId);
} else {
VvmLog.e(TAG, "Visual voicemail not available for subscriber.");
}
}
+ private static boolean hasSignal(Context context, int subId) {
+ return context.getSystemService(TelephonyManager.class)
+ .getServiceStateForSubscriber(subId).getState() == ServiceState.STATE_IN_SERVICE;
+ }
+
private static void queueActivationAfterProvisioned(Context context, int subId) {
if (sDeviceProvisionedObserver == null) {
sDeviceProvisionedObserver = new DeviceProvisionedObserver(context);
diff --git a/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java b/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
index 88943c9..0c19a6a 100644
--- a/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
+++ b/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.provider.VoicemailContract;
import android.provider.VoicemailContract.Status;
+
import com.android.phone.VoicemailStatus;
import com.android.phone.vvm.omtp.OmtpEvents.Type;
@@ -49,6 +50,7 @@
private static void handleConfigurationEvent(Context context, VoicemailStatus.Editor status,
OmtpEvents event) {
switch (event) {
+ case CONFIG_DEFAULT_PIN_REPLACED:
case CONFIG_REQUEST_STATUS_SUCCESS:
case CONFIG_PIN_SET:
status
@@ -61,8 +63,14 @@
// for this activation.
status
.setConfigurationState(Status.CONFIGURATION_STATE_CONFIGURING)
- .setDataChannelState(Status.DATA_CHANNEL_STATE_OK)
- .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK).apply();
+ .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK)
+ .setDataChannelState(Status.DATA_CHANNEL_STATE_OK).apply();
+ break;
+ case CONFIG_ACTIVATING_SUBSEQUENT:
+ status
+ .setConfigurationState(Status.CONFIGURATION_STATE_OK)
+ .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK)
+ .setDataChannelState(Status.DATA_CHANNEL_STATE_OK).apply();
break;
case CONFIG_SERVICE_NOT_AVAILABLE:
status
@@ -116,6 +124,7 @@
case DATA_SSL_INVALID_HOST_NAME:
case DATA_CANNOT_ESTABLISH_SSL_SESSION:
case DATA_IOE_ON_OPEN:
+ case DATA_GENERIC_IMAP_IOE:
status
.setDataChannelState(
VoicemailContract.Status.DATA_CHANNEL_STATE_COMMUNICATION_ERROR)
@@ -137,6 +146,7 @@
case DATA_REJECTED_SERVER_RESPONSE:
case DATA_INVALID_INITIAL_SERVER_RESPONSE:
+ case DATA_MAILBOX_OPEN_FAILED:
case DATA_SSL_EXCEPTION:
case DATA_ALL_SOCKET_CONNECTION_FAILED:
status
diff --git a/src/com/android/phone/vvm/omtp/OmtpEvents.java b/src/com/android/phone/vvm/omtp/OmtpEvents.java
index 648e0d0..7a89418 100644
--- a/src/com/android/phone/vvm/omtp/OmtpEvents.java
+++ b/src/com/android/phone/vvm/omtp/OmtpEvents.java
@@ -17,6 +17,7 @@
package com.android.phone.vvm.omtp;
import android.annotation.IntDef;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -34,6 +35,8 @@
// The voicemail PIN is replaced with a generated PIN, user should change it.
CONFIG_DEFAULT_PIN_REPLACED(Type.CONFIGURATION, true),
CONFIG_ACTIVATING(Type.CONFIGURATION, true),
+ // There are already activation records, this is only a book-keeping activation.
+ CONFIG_ACTIVATING_SUBSEQUENT(Type.CONFIGURATION, true),
CONFIG_STATUS_SMS_TIME_OUT(Type.CONFIGURATION),
CONFIG_SERVICE_NOT_AVAILABLE(Type.CONFIGURATION),
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
index b4fbb3f..0b321b5 100644
--- a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
+++ b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
@@ -16,6 +16,7 @@
package com.android.phone.vvm.omtp;
import android.annotation.Nullable;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
@@ -315,9 +316,15 @@
// Error logged in getPhoneAccountHandle().
return;
}
- VoicemailStatus.edit(mContext, phoneAccountHandle)
- .setType(getVvmType())
- .apply();
+
+ if (mVvmType == null || mVvmType.isEmpty()) {
+ // The VVM type is invalid; we should never have gotten here in the first place since
+ // this is loaded initially in the constructor, and callers should check isValid()
+ // before trying to start activation anyways.
+ VvmLog.e(TAG, "startActivation : vvmType is null or empty for account " +
+ phoneAccountHandle);
+ return;
+ }
activateSmsFilter();
@@ -358,9 +365,9 @@
}
}
- public void requestStatus() {
+ public void requestStatus(@Nullable PendingIntent sentIntent) {
if (mProtocol != null) {
- mProtocol.requestStatus(this);
+ mProtocol.requestStatus(this, sentIntent);
}
}
diff --git a/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java b/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
index 94e616c..7e2472b 100644
--- a/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
+++ b/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
@@ -20,7 +20,7 @@
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
-import com.android.phone.PhoneGlobals;
+
import com.android.phone.PhoneUtils;
import com.android.phone.VoicemailStatus;
import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
@@ -75,7 +75,6 @@
.v(TAG, "Notifications channel is active for " + subId);
helper.handleEvent(VoicemailStatus.edit(mContext, mPhoneAccount),
OmtpEvents.NOTIFICATION_IN_SERVICE);
- PhoneGlobals.getInstance().clearMwiIndicator(subId);
}
}
diff --git a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
index e0b6359..6e6d6ef 100644
--- a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
@@ -17,6 +17,7 @@
package com.android.phone.vvm.omtp.protocol;
import android.annotation.Nullable;
+import android.app.PendingIntent;
import android.content.Context;
import android.os.Bundle;
import android.telecom.PhoneAccountHandle;
@@ -34,10 +35,10 @@
/**
* Activation should cause the carrier to respond with a STATUS SMS.
*/
- public void startActivation(OmtpVvmCarrierConfigHelper config) {
+ public void startActivation(OmtpVvmCarrierConfigHelper config, PendingIntent sentIntent) {
OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config);
if (messageSender != null) {
- messageSender.requestVvmActivation(null);
+ messageSender.requestVvmActivation(sentIntent);
}
}
@@ -58,10 +59,11 @@
// Do nothing
}
- public void requestStatus(OmtpVvmCarrierConfigHelper config) {
+ public void requestStatus(OmtpVvmCarrierConfigHelper config,
+ @Nullable PendingIntent sentIntent) {
OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config);
if (messageSender != null) {
- messageSender.requestVvmStatus(null);
+ messageSender.requestVvmStatus(sentIntent);
}
}
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
index 39d2b34..93e8fb9 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
@@ -17,12 +17,15 @@
package com.android.phone.vvm.omtp.protocol;
import android.annotation.Nullable;
+import android.app.PendingIntent;
import android.content.Context;
import android.net.Network;
import android.os.Bundle;
import android.telecom.PhoneAccountHandle;
import android.telephony.SmsManager;
import android.text.TextUtils;
+
+import com.android.phone.PhoneGlobals;
import com.android.phone.VoicemailStatus;
import com.android.phone.common.mail.MessagingException;
import com.android.phone.settings.VisualVoicemailSettingsUtil;
@@ -41,6 +44,7 @@
import com.android.phone.vvm.omtp.sync.VvmNetworkRequest;
import com.android.phone.vvm.omtp.sync.VvmNetworkRequest.NetworkWrapper;
import com.android.phone.vvm.omtp.sync.VvmNetworkRequest.RequestFailedException;
+
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Locale;
@@ -82,12 +86,13 @@
private static final int DEFAULT_PIN_LENGTH = 6;
@Override
- public void startActivation(OmtpVvmCarrierConfigHelper config) {
+ public void startActivation(OmtpVvmCarrierConfigHelper config,
+ @Nullable PendingIntent sentIntent) {
// VVM3 does not support activation SMS.
// Send a status request which will start the provisioning process if the user is not
// provisioned.
VvmLog.i(TAG, "Activating");
- config.requestStatus();
+ config.requestStatus(sentIntent);
}
@Override
@@ -114,6 +119,8 @@
new Vvm3Subscriber(task, phoneAccountHandle, config, status, data).subscribe();
} else {
config.handleEvent(status, OmtpEvents.VVM3_SUBSCRIBER_UNKNOWN);
+ PhoneGlobals.getInstance().setShouldCheckVisualVoicemailConfigurationForMwi(task.getSubId(),
+ false);
}
} else if (OmtpConstants.SUBSCRIBER_NEW.equals(message.getProvisioningStatus())) {
VvmLog.i(TAG, "setting up new user");
@@ -127,9 +134,13 @@
VvmLog.i(TAG, "User provisioned but not activated, disabling VVM");
VisualVoicemailSettingsUtil
.setEnabled(config.getContext(), phoneAccountHandle, false);
+ PhoneGlobals.getInstance().setShouldCheckVisualVoicemailConfigurationForMwi(task.getSubId(),
+ false);
} else if (OmtpConstants.SUBSCRIBER_BLOCKED.equals(message.getProvisioningStatus())) {
VvmLog.i(TAG, "User blocked");
config.handleEvent(status, OmtpEvents.VVM3_SUBSCRIBER_BLOCKED);
+ PhoneGlobals.getInstance().setShouldCheckVisualVoicemailConfigurationForMwi(task.getSubId(),
+ false);
}
}
@@ -215,7 +226,7 @@
helper.closeNewUserTutorial();
VvmLog.i(TAG, "new user: NUT closed");
- config.requestStatus();
+ config.requestStatus(null);
}
} catch (InitializingException | MessagingException | IOException e) {
config.handleEvent(status, OmtpEvents.VVM3_NEW_USER_SETUP_FAILED);
diff --git a/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java b/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java
index 1e099e8..3d6fcdb 100644
--- a/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java
+++ b/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java
@@ -19,6 +19,8 @@
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.annotation.WorkerThread;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
@@ -30,6 +32,7 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
+import android.os.SystemClock;
import com.android.internal.annotations.VisibleForTesting;
import com.android.phone.Assert;
import com.android.phone.NeededForTesting;
@@ -45,9 +48,25 @@
*/
public class TaskSchedulerService extends Service {
- private static final String TAG = "TaskSchedulerService";
+ private static final String TAG = "VvmTaskScheduler";
+
+ private static final String ACTION_WAKEUP = "action_wakeup";
private static final int READY_TOLERANCE_MILLISECONDS = 100;
+
+ /**
+ * Threshold to determine whether to do a short or long sleep when a task is scheduled in the
+ * future.
+ *
+ * <p>A short sleep will continue to held the wake lock and use {@link
+ * Handler#postDelayed(Runnable, long)} to wait for the next task.
+ *
+ * <p>A long sleep will release the wake lock and set a {@link AlarmManager} alarm. The alarm is
+ * exact and will wake up the device. Note: as this service is run in the telephony process it
+ * does not seem to be restricted by doze or sleep, it will fire exactly at the moment. The
+ * unbundled version should take doze into account.
+ */
+ private static final int SHORT_SLEEP_THRESHOLD_MILLISECONDS = 60_000;
/**
* When there are no more tasks to be run the service should be stopped. But when all tasks has
* finished there might still be more tasks in the message queue waiting to be processed,
@@ -141,7 +160,7 @@
super.onCreate();
mWakeLock = getSystemService(PowerManager.class)
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG);
- mWakeLock.acquire();
+ mWakeLock.setReferenceCounted(false);
HandlerThread thread = new HandlerThread("VvmTaskSchedulerService");
thread.start();
@@ -159,12 +178,20 @@
@MainThread
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Assert.isMainThread();
- Task task = createTask(intent, flags, startId);
- if (task == null) {
- VvmLog.e(TAG, "cannot create task form intent");
+ // maybeRunNextTask() will release the wakelock either by entering a long sleep or stopping
+ // the service.
+ mWakeLock.acquire();
+ if (ACTION_WAKEUP.equals(intent.getAction())) {
+ VvmLog.d(TAG, "woke up by AlarmManager");
} else {
- addTask(task);
+ Task task = createTask(intent, flags, startId);
+ if (task == null) {
+ VvmLog.e(TAG, "cannot create task form intent");
+ } else {
+ addTask(task);
+ }
}
+ maybeRunNextTask();
// STICKY means the service will be automatically restarted will the last intent if it is
// killed.
return START_NOT_STICKY;
@@ -187,7 +214,6 @@
mMainThreadHandler.removeCallbacks(mStopServiceWithDelay);
getTasks().add(task);
maybeRunNextTask();
-
}
@MainThread
@@ -258,6 +284,8 @@
@MainThread
void runNextTask() {
Assert.isMainThread();
+ // The current alarm is no longer valid, a new one will be set up if required.
+ getSystemService(AlarmManager.class).cancel(getWakeupIntent());
if (getTasks().isEmpty()) {
prepareStop();
return;
@@ -280,15 +308,37 @@
}
VvmLog.d(TAG, "minimal wait time:" + minimalWaitTime);
if (!mTaskAutoRunDisabledForTesting && minimalWaitTime != null) {
- // No tests are currently ready. Sleep until the next one should be.
+ // No tasks are currently ready. Sleep until the next one should be.
// If a new task is added during the sleep the service will wake immediately.
+ sleep(minimalWaitTime);
+ }
+ }
+
+ private void sleep(long timeMillis) {
+ if (timeMillis < SHORT_SLEEP_THRESHOLD_MILLISECONDS) {
mMainThreadHandler.postDelayed(new Runnable() {
@Override
public void run() {
maybeRunNextTask();
}
- }, minimalWaitTime);
+ }, timeMillis);
+ return;
}
+
+ // Tasks does not have a strict timing requirement, use AlarmManager.set() so the OS could
+ // optimize the battery usage. As this service currently run in the telephony process the
+ // OS give it privileges to behave the same as setExact(), but set() is the targeted
+ // behavior once this is unbundled.
+ getSystemService(AlarmManager.class).set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+ SystemClock.elapsedRealtime() + timeMillis,
+ getWakeupIntent());
+ mWakeLock.release();
+ VvmLog.d(TAG, "Long sleep for " + timeMillis + " millis");
+ }
+
+ private PendingIntent getWakeupIntent() {
+ Intent intent = new Intent(ACTION_WAKEUP, null, this, getClass());
+ return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
}
private void prepareStop() {
diff --git a/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java b/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
index 2c37dd9..69e4f5f 100644
--- a/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
+++ b/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
@@ -17,20 +17,27 @@
package com.android.phone.vvm.omtp.sms;
import android.annotation.MainThread;
+import android.annotation.Nullable;
import android.annotation.WorkerThread;
+import android.app.Activity;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.provider.VoicemailContract;
+import android.telephony.SmsManager;
+
import com.android.phone.Assert;
import com.android.phone.vvm.omtp.OmtpConstants;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
import com.android.phone.vvm.omtp.VvmLog;
import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocol;
+
import java.io.Closeable;
import java.io.IOException;
+import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
@@ -44,6 +51,9 @@
private static final String TAG = "VvmStatusSmsFetcher";
private static final long STATUS_SMS_TIMEOUT_MILLIS = 60_000;
+ private static final String ACTION_REQUEST_SENT_INTENT
+ = "com.android.phone.vvm.omtp.sms.REQUEST_SENT";
+ private static final int ACTION_REQUEST_SENT_REQUEST_CODE = 0;
private CompletableFuture<Bundle> mFuture = new CompletableFuture<>();
@@ -54,6 +64,7 @@
mContext = context;
mSubId = subId;
IntentFilter filter = new IntentFilter(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED);
+ filter.addAction(ACTION_REQUEST_SENT_INTENT);
context.registerReceiver(this, filter);
}
@@ -63,16 +74,39 @@
}
@WorkerThread
- public Bundle get()
- throws InterruptedException, ExecutionException, TimeoutException {
+ @Nullable
+ public Bundle get() throws InterruptedException, ExecutionException, TimeoutException,
+ CancellationException {
Assert.isNotMainThread();
return mFuture.get(STATUS_SMS_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
}
+ public PendingIntent getSentIntent() {
+ Intent intent = new Intent(ACTION_REQUEST_SENT_INTENT);
+ intent.setPackage(mContext.getPackageName());
+ // Because the receiver is registered dynamically, implicit intent must be used.
+ // There should only be a single status SMS request at a time.
+ return PendingIntent.getBroadcast(mContext, ACTION_REQUEST_SENT_REQUEST_CODE, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ }
+
@Override
@MainThread
public void onReceive(Context context, Intent intent) {
Assert.isMainThread();
+ if (ACTION_REQUEST_SENT_INTENT.equals(intent.getAction())) {
+ int resultCode = getResultCode();
+
+ if (resultCode == Activity.RESULT_OK) {
+ VvmLog.d(TAG, "Request SMS successfully sent");
+ return;
+ }
+
+ VvmLog.e(TAG, "Request SMS send failed: " + sentSmsResultToString(resultCode));
+ mFuture.cancel(true);
+ return;
+ }
+
int subId = intent.getExtras().getInt(VoicemailContract.EXTRA_VOICEMAIL_SMS_SUBID);
if (mSubId != subId) {
@@ -105,4 +139,21 @@
mFuture.complete(translatedBundle);
}
}
+
+ private static String sentSmsResultToString(int resultCode) {
+ switch (resultCode) {
+ case Activity.RESULT_OK:
+ return "OK";
+ case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
+ return "RESULT_ERROR_GENERIC_FAILURE";
+ case SmsManager.RESULT_ERROR_NO_SERVICE:
+ return "RESULT_ERROR_GENERIC_FAILURE";
+ case SmsManager.RESULT_ERROR_NULL_PDU:
+ return "RESULT_ERROR_GENERIC_FAILURE";
+ case SmsManager.RESULT_ERROR_RADIO_OFF:
+ return "RESULT_ERROR_GENERIC_FAILURE";
+ default:
+ return "UNKNOWN CODE: " + resultCode;
+ }
+ }
}
diff --git a/src/com/android/services/telephony/CdmaConnection.java b/src/com/android/services/telephony/CdmaConnection.java
index 8020996..29ccc6c 100644
--- a/src/com/android/services/telephony/CdmaConnection.java
+++ b/src/com/android/services/telephony/CdmaConnection.java
@@ -184,7 +184,7 @@
}
@Override
- public void performConference(TelephonyConnection otherConnection) {
+ public void performConference(android.telecom.Connection otherConnection) {
if (isImsConnection()) {
super.performConference(otherConnection);
} else {
diff --git a/src/com/android/services/telephony/DisconnectCauseUtil.java b/src/com/android/services/telephony/DisconnectCauseUtil.java
index bcc22fd..6eb4a4e 100644
--- a/src/com/android/services/telephony/DisconnectCauseUtil.java
+++ b/src/com/android/services/telephony/DisconnectCauseUtil.java
@@ -128,6 +128,7 @@
case android.telephony.DisconnectCause.MAXIMUM_NUMBER_OF_CALLS_REACHED:
case android.telephony.DisconnectCause.DATA_DISABLED:
case android.telephony.DisconnectCause.DATA_LIMIT_REACHED:
+ case android.telephony.DisconnectCause.DIALED_ON_WRONG_SLOT:
return DisconnectCause.ERROR;
case android.telephony.DisconnectCause.DIALED_MMI:
@@ -377,7 +378,7 @@
break;
case android.telephony.DisconnectCause.DATA_LIMIT_REACHED:
- resourceId = R.string.callFailed_data_limit_reached;
+ resourceId = R.string.callFailed_data_limit_reached_description;
break;
default:
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 3f49c6f..4acb6f8 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -20,6 +20,7 @@
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.telecom.Conference;
import android.telecom.ConferenceParticipant;
import android.telecom.Connection.VideoProvider;
@@ -29,6 +30,7 @@
import android.telecom.PhoneAccountHandle;
import android.telecom.StatusHints;
import android.telecom.VideoProfile;
+import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
import android.util.Pair;
@@ -36,6 +38,7 @@
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
+import com.android.phone.PhoneGlobals;
import com.android.phone.PhoneUtils;
import com.android.phone.R;
@@ -279,8 +282,11 @@
mTelephonyConnectionService = telephonyConnectionService;
setConferenceHost(conferenceHost);
- int capabilities = Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD |
- Connection.CAPABILITY_MUTE | Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN;
+ int capabilities = Connection.CAPABILITY_MUTE |
+ Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN;
+ if (canHoldImsCalls()) {
+ capabilities |= Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD;
+ }
capabilities = applyHostCapabilities(capabilities,
mConferenceHost.getConnectionCapabilities(),
mConferenceHost.isCarrierVideoConferencingSupported());
@@ -433,7 +439,7 @@
@Override
public void onMerge(android.telecom.Connection connection) {
try {
- Phone phone = ((TelephonyConnection) connection).getPhone();
+ Phone phone = mConferenceHost.getPhone();
if (phone != null) {
phone.conference();
}
@@ -976,4 +982,22 @@
sb.append("]");
return sb.toString();
}
+
+ private boolean canHoldImsCalls() {
+ PersistableBundle b = getCarrierConfig();
+ // Return true if the CarrierConfig is unavailable
+ return b == null || b.getBoolean(CarrierConfigManager.KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL);
+ }
+
+ private PersistableBundle getCarrierConfig() {
+ if (mConferenceHost == null) {
+ return null;
+ }
+
+ Phone phone = mConferenceHost.getPhone();
+ if (phone == null) {
+ return null;
+ }
+ return PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
+ }
}
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 6669482..f7d587d 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -187,6 +187,7 @@
Log.v(this, "recalculateConferenceable : %d", mTelephonyConnections.size());
HashSet<Conferenceable> conferenceableSet = new HashSet<>(mTelephonyConnections.size() +
mImsConferences.size());
+ HashSet<Conferenceable> conferenceParticipantsSet = new HashSet<>();
// Loop through and collect all calls which are active or holding
for (TelephonyConnection connection : mTelephonyConnections) {
@@ -240,6 +241,7 @@
case Connection.STATE_ACTIVE:
//fall through
case Connection.STATE_HOLDING:
+ conferenceParticipantsSet.addAll(conference.getConnections());
conferenceableSet.add(conference);
continue;
default:
@@ -256,6 +258,16 @@
.stream()
.filter(conferenceable -> c != conferenceable)
.collect(Collectors.toList());
+ // TODO: Remove this once RemoteConnection#setConferenceableConnections is fixed.
+ // Add all conference participant connections as conferenceable with a standalone
+ // Connection. We need to do this to ensure that RemoteConnections work properly.
+ // At the current time, a RemoteConnection will not be conferenceable with a
+ // Conference, so we need to add its children to ensure the user can merge the call
+ // into the conference.
+ // We should add support for RemoteConnection#setConferenceables, which accepts a
+ // list of remote conferences and connections in the future.
+ conferenceables.addAll(conferenceParticipantsSet);
+
((Connection) c).setConferenceables(conferenceables);
} else if (c instanceof Conference) {
// Remove all conferences from the set, since we can not conference a conference
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index 3810699..c4f9c9a 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -33,6 +33,7 @@
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
+import android.telephony.DisconnectCause;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.util.Pair;
@@ -254,6 +255,7 @@
*/
public abstract static class TelephonyConnectionListener {
public void onOriginalConnectionConfigured(TelephonyConnection c) {}
+ public void onOriginalConnectionRetry(TelephonyConnection c) {}
}
private final PostDialListener mPostDialListener = new PostDialListener() {
@@ -681,7 +683,7 @@
}
}
- public void performConference(TelephonyConnection otherConnection) {
+ public void performConference(Connection otherConnection) {
Log.d(this, "performConference - %s", this);
if (getPhone() != null) {
try {
@@ -738,7 +740,7 @@
// shown.
Phone phone = getPhone();
if (phone != null && phone.isInEcm()) {
- connectionProperties |= PROPERTY_SHOW_CALLBACK_NUMBER;
+ connectionProperties |= PROPERTY_EMERGENCY_CALLBACK_MODE;
}
return connectionProperties;
@@ -973,7 +975,8 @@
private boolean canHoldImsCalls() {
PersistableBundle b = getCarrierConfig();
// Return true if the CarrierConfig is unavailable
- return b == null || b.getBoolean(CarrierConfigManager.KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL);
+ return !doesDeviceRespectHoldCarrierConfig() || b == null ||
+ b.getBoolean(CarrierConfigManager.KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL);
}
private PersistableBundle getCarrierConfig() {
@@ -985,6 +988,23 @@
}
/**
+ * Determines if the device will respect the value of the
+ * {@link CarrierConfigManager#KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} configuration option.
+ *
+ * @return {@code false} if the device always supports holding IMS calls, {@code true} if it
+ * will use {@link CarrierConfigManager#KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL} to determine if
+ * hold is supported.
+ */
+ private boolean doesDeviceRespectHoldCarrierConfig() {
+ Phone phone = getPhone();
+ if (phone == null) {
+ return true;
+ }
+ return phone.getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_device_respects_hold_carrier_config);
+ }
+
+ /**
* Whether the connection should be treated as an emergency.
* @return {@code true} if the connection should be treated as an emergency call based
* on the number dialed, {@code false} otherwise.
@@ -1248,10 +1268,19 @@
setRinging();
break;
case DISCONNECTED:
- setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
- mOriginalConnection.getDisconnectCause(),
- mOriginalConnection.getVendorDisconnectCause()));
- close();
+ // We can get into a situation where the radio wants us to redial the same
+ // emergency call on the other available slot. This will not set the state to
+ // disconnected and will instead tell the TelephonyConnectionService to create
+ // a new originalConnection using the new Slot.
+ if (mOriginalConnection.getDisconnectCause() ==
+ DisconnectCause.DIALED_ON_WRONG_SLOT) {
+ fireOnOriginalConnectionRetryDial();
+ } else {
+ setDisconnected(DisconnectCauseUtil.toTelecomDisconnectCause(
+ mOriginalConnection.getDisconnectCause(),
+ mOriginalConnection.getVendorDisconnectCause()));
+ close();
+ }
break;
case DISCONNECTING:
break;
@@ -1629,6 +1658,12 @@
}
}
+ private final void fireOnOriginalConnectionRetryDial() {
+ for (TelephonyConnectionListener l : mTelephonyListeners) {
+ l.onOriginalConnectionRetry(this);
+ }
+ }
+
/**
* Handles exiting ECM mode.
*/
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 54cbda7..5afdd72 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -33,10 +33,12 @@
import android.telecom.VideoProfile;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneNumberUtils;
+import android.telephony.RadioAccessFamily;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
+import android.util.Pair;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
@@ -52,8 +54,11 @@
import com.android.phone.PhoneUtils;
import com.android.phone.R;
+import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
@@ -77,6 +82,13 @@
private EmergencyCallHelper mEmergencyCallHelper;
private EmergencyTonePlayer mEmergencyTonePlayer;
+ // Contains one TelephonyConnection that has placed a call and a memory of which Phones it has
+ // already tried to connect with. There should be only one TelephonyConnection trying to place a
+ // call at one time. We also only access this cache from a TelephonyConnection that wishes to
+ // redial, so we use a WeakReference that will become stale once the TelephonyConnection is
+ // destroyed.
+ private Pair<WeakReference<TelephonyConnection>, List<Phone>> mEmergencyRetryCache;
+
/**
* A listener to actionable events specific to the TelephonyConnection.
*/
@@ -86,6 +98,11 @@
public void onOriginalConnectionConfigured(TelephonyConnection c) {
addConnectionToConferenceController(c);
}
+
+ @Override
+ public void onOriginalConnectionRetry(TelephonyConnection c) {
+ retryOutgoingOriginalConnection(c);
+ }
};
@Override
@@ -112,7 +129,7 @@
}
String scheme = handle.getScheme();
- final String number;
+ String number;
if (PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
// TODO: We don't check for SecurityException here (requires
// CALL_PRIVILEGED permission).
@@ -176,14 +193,36 @@
}
}
- final boolean isEmergencyNumber = PhoneNumberUtils.isLocalEmergencyNumber(this, number);
+ // Convert into emergency number if necessary
+ // This is required in some regions (e.g. Taiwan).
+ if (!PhoneNumberUtils.isLocalEmergencyNumber(this, number) &&
+ PhoneNumberUtils.isConvertToEmergencyNumberEnabled()) {
+ final Phone phone = getPhoneForAccount(request.getAccountHandle(), false);
+ // We only do the conversion if the phone is not in service. The un-converted
+ // emergency numbers will go to the correct destination when the phone is in-service,
+ // so they will only need the special emergency call setup when the phone is out of
+ // service.
+ if (phone == null || phone.getServiceState().getState()
+ != ServiceState.STATE_IN_SERVICE) {
+ String convertedNumber = PhoneNumberUtils.convertToEmergencyNumber(number);
+ if (!TextUtils.equals(convertedNumber, number)) {
+ Log.i(this, "onCreateOutgoingConnection, converted to emergency number");
+ number = convertedNumber;
+ handle = Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
+ }
+ }
+ }
+ final String numberToDial = number;
+
+ final boolean isEmergencyNumber =
+ PhoneNumberUtils.isLocalEmergencyNumber(this, numberToDial);
if (isEmergencyNumber && !isRadioOn()) {
final Uri emergencyHandle = handle;
// By default, Connection based on the default Phone, since we need to return to Telecom
// now.
final int defaultPhoneType = PhoneFactory.getDefaultPhone().getPhoneType();
- final Connection emergencyConnection = getTelephonyConnection(request, number,
+ final Connection emergencyConnection = getTelephonyConnection(request, numberToDial,
isEmergencyNumber, emergencyHandle, PhoneFactory.getDefaultPhone());
if (mEmergencyCallHelper == null) {
mEmergencyCallHelper = new EmergencyCallHelper(this);
@@ -206,7 +245,7 @@
// Phone, then we need create a new Connection using that PhoneType and
// replace it in Telecom.
if (phone.getPhoneType() != defaultPhoneType) {
- Connection repConnection = getTelephonyConnection(request, number,
+ Connection repConnection = getTelephonyConnection(request, numberToDial,
isEmergencyNumber, emergencyHandle, phone);
// If there was a failure, the resulting connection will not be a
// TelephonyConnection, so don't place the call, just return!
@@ -256,8 +295,8 @@
// Get the right phone object from the account data passed in.
final Phone phone = getPhoneForAccount(request.getAccountHandle(), isEmergencyNumber);
- Connection resultConnection = getTelephonyConnection(request, number, isEmergencyNumber,
- handle, phone);
+ Connection resultConnection = getTelephonyConnection(request, numberToDial,
+ isEmergencyNumber, handle, phone);
// If there was a failure, the resulting connection will not be a TelephonyConnection,
// so don't place the call!
if(resultConnection instanceof TelephonyConnection) {
@@ -577,14 +616,35 @@
}
}
+ /**
+ * Conferences two connections.
+ *
+ * Note: The {@link android.telecom.RemoteConnection#setConferenceableConnections(List)} API has
+ * a limitation in that it can only specify conferenceables which are instances of
+ * {@link android.telecom.RemoteConnection}. In the case of an {@link ImsConference}, the
+ * regular {@link Connection#setConferenceables(List)} API properly handles being able to merge
+ * a {@link Conference} and a {@link Connection}. As a result when, merging a
+ * {@link android.telecom.RemoteConnection} into a {@link android.telecom.RemoteConference}
+ * require merging a {@link ConferenceParticipantConnection} which is a child of the
+ * {@link Conference} with a {@link TelephonyConnection}. The
+ * {@link ConferenceParticipantConnection} class does not have the capability to initiate a
+ * conference merge, so we need to call
+ * {@link TelephonyConnection#performConference(Connection)} on either {@code connection1} or
+ * {@code connection2}, one of which is an instance of {@link TelephonyConnection}.
+ *
+ * @param connection1 A connection to merge into a conference call.
+ * @param connection2 A connection to merge into a conference call.
+ */
@Override
public void onConference(Connection connection1, Connection connection2) {
- if (connection1 instanceof TelephonyConnection &&
- connection2 instanceof TelephonyConnection) {
- ((TelephonyConnection) connection1).performConference(
- (TelephonyConnection) connection2);
+ if (connection1 instanceof TelephonyConnection) {
+ ((TelephonyConnection) connection1).performConference(connection2);
+ } else if (connection2 instanceof TelephonyConnection) {
+ ((TelephonyConnection) connection2).performConference(connection1);
+ } else {
+ Log.w(this, "onConference - cannot merge connections " +
+ "Connection1: %s, Connection2: %2", connection1, connection2);
}
-
}
private boolean isRadioOn() {
@@ -595,14 +655,78 @@
return result;
}
+ private Pair<WeakReference<TelephonyConnection>, List<Phone>> makeCachedConnectionPhonePair(
+ TelephonyConnection c) {
+ List<Phone> phones = new ArrayList<>(Arrays.asList(PhoneFactory.getPhones()));
+ return new Pair<>(new WeakReference<>(c), phones);
+ }
+
+ // Check the mEmergencyRetryCache to see if it contains the TelephonyConnection. If it doesn't,
+ // then it is stale. Create a new one!
+ private void updateCachedConnectionPhonePair(TelephonyConnection c) {
+ if (mEmergencyRetryCache == null) {
+ Log.i(this, "updateCachedConnectionPhonePair, cache is null. Generating new cache");
+ mEmergencyRetryCache = makeCachedConnectionPhonePair(c);
+ } else {
+ // Check to see if old cache is stale. If it is, replace it
+ WeakReference<TelephonyConnection> cachedConnection = mEmergencyRetryCache.first;
+ if (cachedConnection.get() != c) {
+ Log.i(this, "updateCachedConnectionPhonePair, cache is stale. Regenerating.");
+ mEmergencyRetryCache = makeCachedConnectionPhonePair(c);
+ }
+ }
+ }
+
+ /**
+ * Returns the first Phone that has not been used yet to place the call. Any Phones that have
+ * been used to place a call will have already been removed from mEmergencyRetryCache.second.
+ * The phone that it excluded will be removed from mEmergencyRetryCache.second in this method.
+ * @param phoneToExclude The Phone object that will be removed from our cache of available
+ * phones.
+ * @return the first Phone that is available to be used to retry the call.
+ */
+ private Phone getPhoneForRedial(Phone phoneToExclude) {
+ List<Phone> cachedPhones = mEmergencyRetryCache.second;
+ if (cachedPhones.contains(phoneToExclude)) {
+ Log.i(this, "getPhoneForRedial, removing Phone[" + phoneToExclude.getPhoneId() +
+ "] from the available Phone cache.");
+ cachedPhones.remove(phoneToExclude);
+ }
+ return cachedPhones.isEmpty() ? null : cachedPhones.get(0);
+ }
+
+ private void retryOutgoingOriginalConnection(TelephonyConnection c) {
+ updateCachedConnectionPhonePair(c);
+ Phone newPhoneToUse = getPhoneForRedial(c.getPhone());
+ if (newPhoneToUse != null) {
+ int videoState = c.getVideoState();
+ Bundle connExtras = c.getExtras();
+ Log.i(this, "retryOutgoingOriginalConnection, redialing on Phone Id: " + newPhoneToUse);
+ c.clearOriginalConnection();
+ placeOutgoingConnection(c, newPhoneToUse, videoState, connExtras);
+ } else {
+ // We have run out of Phones to use. Disconnect the call and destroy the connection.
+ Log.i(this, "retryOutgoingOriginalConnection, no more Phones to use. Disconnecting.");
+ c.setDisconnected(new DisconnectCause(DisconnectCause.ERROR));
+ c.clearOriginalConnection();
+ c.destroy();
+ }
+ }
+
private void placeOutgoingConnection(
TelephonyConnection connection, Phone phone, ConnectionRequest request) {
+ placeOutgoingConnection(connection, phone, request.getVideoState(), request.getExtras());
+ }
+
+ private void placeOutgoingConnection(
+ TelephonyConnection connection, Phone phone, int videoState, Bundle extras) {
String number = connection.getAddress().getSchemeSpecificPart();
- com.android.internal.telephony.Connection originalConnection;
+ com.android.internal.telephony.Connection originalConnection = null;
try {
- originalConnection =
- phone.dial(number, null, request.getVideoState(), request.getExtras());
+ if (phone != null) {
+ originalConnection = phone.dial(number, null, videoState, extras);
+ }
} catch (CallStateException e) {
Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
int cause = android.telephony.DisconnectCause.OUTGOING_FAILURE;
@@ -699,12 +823,11 @@
* list (for multi-SIM devices):
* 1) The User's SIM preference for Voice calling
* 2) The First Phone that is currently IN_SERVICE or is available for emergency calling
- * 3) The First Phone that has a SIM card in it (Starting from Slot 0...N)
- * 4) The Default Phone (Currently set as Slot 0)
+ * 3) The Phone with more Capabilities.
+ * 4) The First Phone that has a SIM card in it (Starting from Slot 0...N)
+ * 5) The Default Phone (Currently set as Slot 0)
*/
private Phone getFirstPhoneForEmergencyCall() {
- Phone firstPhoneWithSim = null;
-
// 1)
int phoneId = SubscriptionManager.getDefaultVoicePhoneId();
if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) {
@@ -714,32 +837,77 @@
}
}
- for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+ Phone firstPhoneWithSim = null;
+ int phoneCount = TelephonyManager.getDefault().getPhoneCount();
+ List<Pair<Integer, Integer>> phoneNetworkType = new ArrayList<>(phoneCount);
+ for (int i = 0; i < phoneCount; i++) {
Phone phone = PhoneFactory.getPhone(i);
if (phone == null)
continue;
// 2)
if (isAvailableForEmergencyCalls(phone)) {
// the slot has the radio on & state is in service.
- Log.d(this, "getFirstPhoneForEmergencyCall, radio on & in service, Phone Id:" + i);
+ Log.i(this, "getFirstPhoneForEmergencyCall, radio on & in service, Phone Id:" + i);
return phone;
}
// 3)
+ // Store the RAF Capabilities for sorting later only if there are capabilities to sort.
+ int radioAccessFamily = phone.getRadioAccessFamily();
+ if(RadioAccessFamily.getHighestRafCapability(radioAccessFamily) != 0) {
+ phoneNetworkType.add(new Pair<>(i, radioAccessFamily));
+ Log.i(this, "getFirstPhoneForEmergencyCall, RAF:" +
+ Integer.toHexString(radioAccessFamily) + " saved for Phone Id:" + i);
+ }
+ // 4)
if (firstPhoneWithSim == null && TelephonyManager.getDefault().hasIccCard(i)) {
// The slot has a SIM card inserted, but is not in service, so keep track of this
// Phone. Do not return because we want to make sure that none of the other Phones
// are in service (because that is always faster).
- Log.d(this, "getFirstPhoneForEmergencyCall, SIM card inserted, Phone Id:" + i);
+ Log.i(this, "getFirstPhoneForEmergencyCall, SIM card inserted, Phone Id:" + i);
firstPhoneWithSim = phone;
}
}
- // 4)
- if (firstPhoneWithSim == null) {
+ // 5)
+ if (firstPhoneWithSim == null && phoneNetworkType.isEmpty()) {
// No SIMs inserted, get the default.
- Log.d(this, "getFirstPhoneForEmergencyCall, return default phone");
+ Log.i(this, "getFirstPhoneForEmergencyCall, return default phone");
return PhoneFactory.getDefaultPhone();
} else {
- return firstPhoneWithSim;
+ // 3)
+ final Phone firstOccupiedSlot = firstPhoneWithSim;
+ if (!phoneNetworkType.isEmpty()) {
+ // Only sort if there are enough elements to do so.
+ if(phoneNetworkType.size() > 1) {
+ Collections.sort(phoneNetworkType, (o1, o2) -> {
+ // First start by sorting by number of RadioAccessFamily Capabilities.
+ int compare = Integer.bitCount(o1.second) - Integer.bitCount(o2.second);
+ if (compare == 0) {
+ // Sort by highest RAF Capability if the number is the same.
+ compare = RadioAccessFamily.getHighestRafCapability(o1.second) -
+ RadioAccessFamily.getHighestRafCapability(o2.second);
+ if (compare == 0 && firstOccupiedSlot != null) {
+ // If the RAF capability is the same, choose based on whether or not
+ // any of the slots are occupied with a SIM card (if both are,
+ // always choose the first).
+ if (o1.first == firstOccupiedSlot.getPhoneId()) {
+ return 1;
+ } else if (o2.first == firstOccupiedSlot.getPhoneId()) {
+ return -1;
+ }
+ // Compare is still 0, return equal.
+ }
+ }
+ return compare;
+ });
+ }
+ int mostCapablePhoneId = phoneNetworkType.get(phoneNetworkType.size()-1).first;
+ Log.i(this, "getFirstPhoneForEmergencyCall, Using Phone Id: " + mostCapablePhoneId +
+ "with highest capability");
+ return PhoneFactory.getPhone(mostCapablePhoneId);
+ } else {
+ // 4)
+ return firstPhoneWithSim;
+ }
}
}
diff --git a/tests/src/com/android/phone/common/mail/store/imap/DigestMd5UtilsTest.java b/tests/src/com/android/phone/common/mail/store/imap/DigestMd5UtilsTest.java
index 5534632..81717a1 100644
--- a/tests/src/com/android/phone/common/mail/store/imap/DigestMd5UtilsTest.java
+++ b/tests/src/com/android/phone/common/mail/store/imap/DigestMd5UtilsTest.java
@@ -50,4 +50,24 @@
assertEquals("ea40f60335c427b5527b84dbabcdfffd", response);
}
+ public void testData_createResponse() {
+ DigestMd5Utils.Data data = new DigestMd5Utils.Data();
+ data.username = "chris";
+ data.password = "secret";
+ data.realm = "elwood.innosoft.com";
+ data.nonce = "OA6MG9tEQGm2hh";
+ data.cnonce = "OA6MHXh6VqTrRk";
+ data.nc = "00000001";
+ data.qop = "auth";
+ data.digestUri = "imap/elwood.innosoft.com";
+ assertEquals(data.createResponse(), "CHARSET=utf-8,"
+ + "username=\"chris\","
+ + "realm=\"elwood.innosoft.com\","
+ + "nonce=\"OA6MG9tEQGm2hh\","
+ + "nc=00000001,"
+ + "cnonce=\"OA6MHXh6VqTrRk\","
+ + "digest-uri=\"imap/elwood.innosoft.com\","
+ + "response=d388dad90d4bbd760a152321f2143af7,"
+ + "qop=auth");
+ }
}