Merge "Update samples for new DownloadRequest API"
am: 10f4fb6469
Change-Id: Idf59dd026b9bfb76355193efbde05f65d8bff93f
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e2001fd..c2b9800 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -54,15 +54,16 @@
<protected-broadcast android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
<protected-broadcast android:name="android.provider.Telephony.SMS_CB_RECEIVED" />
<protected-broadcast android:name="android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED" />
- <protected-broadcast android:name= "android.intent.action.stk.command" />
- <protected-broadcast android:name= "android.intent.action.stk.session_end" />
- <protected-broadcast android:name= "android.intent.action.stk.icc_status_change" />
- <protected-broadcast android:name= "android.intent.action.stk.alpha_notify" />
+ <protected-broadcast android:name="android.provider.Telephony.SECRET_CODE" />
+ <protected-broadcast android:name= "com.android.internal.stk.command" />
+ <protected-broadcast android:name= "com.android.internal.stk.session_end" />
+ <protected-broadcast android:name= "com.android.internal.stk.icc_status_change" />
+ <protected-broadcast android:name= "com.android.internal.stk.alpha_notify" />
<protected-broadcast android:name= "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
<protected-broadcast android:name= "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED" />
<protected-broadcast android:name= "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE" />
<protected-broadcast android:name= "com.android.internal.telephony.CARRIER_SIGNAL_RESET" />
- <protected-broadcast android:name= "android.intent.action.VOICEMAIL_SMS_RECEIVED" />
+ <protected-broadcast android:name= "com.android.internal.provider.action.VOICEMAIL_SMS_RECEIVED" />
<protected-broadcast android:name= "com.android.intent.isim_refresh" />
<protected-broadcast android:name= "com.android.ims.IMS_SERVICE_UP" />
<protected-broadcast android:name= "com.android.ims.IMS_SERVICE_DOWN" />
@@ -74,10 +75,18 @@
<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" />
+ <protected-broadcast android:name= "com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT" />
+ <protected-broadcast android:name= "com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED" />
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.CALL_PRIVILEGED" />
+ <!-- TELEPHONY_SECRET_CODE used to be sent by the Dialer app, but is now sent by
+ the phone process through an API added in O. Since the broadcast was unprotected prior to
+ O, apps may have required this permission (which only Dialer has) in their receivers.
+ So, declare this permission here for backwards compatibility so the phone process can send
+ the broadcasts to those same receivers. -->
+ <uses-permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
@@ -321,7 +330,7 @@
<!-- "Mobile network settings" screen, used on both
non-voice-capable tablets and regular phone devices. -->
<activity android:name="MobileNetworkSettings"
- android:label="@string/mobile_networks"
+ android:label="@string/network_settings_title"
android:theme="@style/NetworkOperatorsSettingsTheme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -604,70 +613,14 @@
android:exported="false"
androidprv:systemUserOnly="true">
<intent-filter>
- <action android:name="android.intent.action.VOICEMAIL_SMS_RECEIVED"/>
- </intent-filter>
- </receiver>
- <receiver
- android:name="com.android.phone.vvm.omtp.SimChangeReceiver"
- android:exported="true"
- androidprv:systemUserOnly="true">
- <intent-filter>
- <action android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />
- <action android:name="android.intent.action.SIM_STATE_CHANGED" />
- </intent-filter>
- </receiver>
- <receiver
- android:name="com.android.phone.vvm.omtp.VvmBootCompletedReceiver"
- android:exported="true"
- android:permission="android.permission.RECEIVE_BOOT_COMPLETED"
- androidprv:systemUserOnly="true">
- <intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED"/>
- </intent-filter>
- </receiver>
- <receiver
- android:name="com.android.phone.vvm.omtp.fetch.FetchVoicemailReceiver"
- android:exported="true"
- android:permission="com.android.voicemail.permission.READ_VOICEMAIL"
- androidprv:systemUserOnly="true">
- <intent-filter>
- <action android:name="android.intent.action.FETCH_VOICEMAIL" />
- <data
- android:scheme="content"
- android:host="com.android.voicemail"
- android:mimeType="vnd.android.cursor.item/voicemail" />
- </intent-filter>
- </receiver>
- <receiver
- android:name="com.android.phone.vvm.omtp.sync.OmtpVvmSyncReceiver"
- android:exported="true"
- android:permission="com.android.voicemail.permission.READ_VOICEMAIL"
- androidprv:systemUserOnly="true">
- <intent-filter>
- <action android:name="android.provider.action.SYNC_VOICEMAIL"/>
- </intent-filter>
- </receiver>
- <receiver
- android:name="com.android.phone.vvm.omtp.sync.VoicemailProviderChangeReceiver"
- android:exported="true"
- androidprv:systemUserOnly="true">
- <intent-filter>
- <action android:name="android.intent.action.PROVIDER_CHANGED" />
- <data
- android:scheme="content"
- android:host="com.android.voicemail"
- android:mimeType="vnd.android.cursor.dir/voicemails"/>
+ <action android:name="com.android.internal.provider.action.VOICEMAIL_SMS_RECEIVED"/>
</intent-filter>
</receiver>
-
- <service
- android:name="com.android.phone.vvm.omtp.scheduling.TaskSchedulerService"
- android:exported="false" />
-
<receiver
- android:name="com.android.phone.vvm.VvmSimStateTracker"
- android:exported="false">
+ android:name="com.android.phone.vvm.VvmSimStateTracker"
+ android:exported="false"
+ androidprv:systemUserOnly="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.telephony.action.CARRIER_CONFIG_CHANGED"/>
@@ -675,22 +628,6 @@
</intent-filter>
</receiver>
- <receiver android:name="com.android.phone.vvm.omtp.VvmPackageInstallReceiver"
- androidprv:systemUserOnly="true">
- <intent-filter>
- <action android:name="android.intent.action.PACKAGE_INSTALL" />
- <action android:name="android.intent.action.PACKAGE_ADDED" />
- <data android:scheme="package"/>
- </intent-filter>
- </receiver>
-
- <activity
- android:name="com.android.phone.settings.VoicemailChangePinActivity"
- android:exported="false"
- android:theme="@style/DialerSettingsLight"
- android:windowSoftInputMode="stateVisible|adjustResize">
- </activity>
-
<service
android:name="com.android.phone.vvm.RemoteVvmTaskManager"
android:exported="false"/>
diff --git a/res/values-af/config.xml b/res/values-af/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-af/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 4094084..d910d7c 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Vermiste stemboodskapnommer"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Geen stemboodskapnommer is op die SIM-kaart gestoor nie."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Voeg nommer by"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Stemboodskapinstellings kan slegs deur die primêre gebruiker gewysig word."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Jou SIM-kaart is oopgesluit. Jou foon sluit tans oop…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM-netwerk ontsluit PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Ontsluit"</string>
@@ -451,7 +452,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Verlaat noodterugbelmodus om \'n nienoodoproep te maak."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Nie geregistreer op netwerk nie."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobiele netwerk nie beskikbaar nie."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobiele netwerk is nie beskikbaar nie. Koppel aan \'n draadlose netwerk om \'n oproep te maak."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Voer \'n geldige nommer in om \'n oproep te maak."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Oproep het misluk."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Oproep kan nie op die oomblik bygevoeg word nie."</string>
diff --git a/res/values-am/config.xml b/res/values-am/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-am/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 90c5443..edf36e5 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"የድምፅመልዕክት ቁጥርአመለጠ"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"በSIM ካርዱ ላይምንም የድምፅመልዕክት ቁጥር አልከተቀመጠም።"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"ቁጥር አክል"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"የድምፅ መልዕክት ቅንብሮች መለወጥ የሚችሉት በቀዳሚ ተጠቃሚው ብቻ ነው።"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"የSIM ካርድዎ አልታገደም። ስልክዎ በመከፈት ላይነው..."</string>
<string name="label_ndp" msgid="780479633159517250">"የSIM አውታረመረብ መክፈቻ ፒን"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"ክፈት"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"አስቸኳይ ያልሆነ ጥሪ ለማድረግ ከአስቸኳይ መልሰህ ደውል ሁነታ ይውጡ።"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"በአውታረ መረቡ ላይ አልተመዘገበም።"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"የተንቀሳቃሽ አደራጅ የለም።"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"የተንቀሳቃሽ ስልክ አውታረ መረብ አይገኝም። ጥሪ ለማድረግ ከሽቦ አልባ አውታረ መረብ ጋር ያገናኙ።"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"አንድ ጥሪ ለማድረግ የሚሰራ ቁጥር ያስገቡ።"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"ጥሪ አልተሳካም።"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"ጥሪ በአሁኑ ጊዜ ሊታከል አይችልም።"</string>
diff --git a/res/values-ar/config.xml b/res/values-ar/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ar/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 751052f..1157af5 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"رقم البريد الصوتي مفقود"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"لم يتم تخزين رقم بريد صوتي على شريحة SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"إضافة رقم"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"يمكن تعديل إعدادات البريد الصوتي عن طريق المستخدم الأساسي فقط."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"تم إلغاء حظر شريحة SIM. جارٍ إلغاء تأمين الهاتف..."</string>
<string name="label_ndp" msgid="780479633159517250">"رمز PIN لإلغاء تأمين شبكة SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"إلغاء تأمين"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"ينبغي الخروج من وضع معاودة الاتصال بالطوارئ لإجراء مكالمة غير طارئة."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"غير مسجل على الشبكة."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"شبكة الجوال غير متاحة."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"شبكة الجوّال ليست متوفرة. اتصل بشبكة لاسلكية لإجراء مكالمة."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"لإجراء مكالمة، أدخل رقمًا صالحًا."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"أخفقت المكالمة."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"لا يمكن إضافة مكالمة في الوقت الحالي."</string>
@@ -484,7 +486,7 @@
<string name="importingSimContacts" msgid="7374056215462575769">"استيراد جهات اتصال شريحة SIM"</string>
<string name="importToFDNfromContacts" msgid="2130620207013368580">"استيراد من جهات الاتصال"</string>
<string name="singleContactImportedMsg" msgid="6868483416182599206">"تم استيراد جهة اتصال"</string>
- <string name="failedToImportSingleContactMsg" msgid="415399285420353917">"تعذّر استيراد جهة اتصال"</string>
+ <string name="failedToImportSingleContactMsg" msgid="415399285420353917">"أخفق استيراد جهة اتصال"</string>
<string name="hac_mode_title" msgid="8740268574688743289">"أدوات السمع المساعدة"</string>
<string name="hac_mode_summary" msgid="6833851160514929341">"تشغيل التوافق مع أداة السمع"</string>
<string-array name="tty_mode_entries">
diff --git a/res/values-az-rAZ/arrays.xml b/res/values-az/arrays.xml
similarity index 100%
rename from res/values-az-rAZ/arrays.xml
rename to res/values-az/arrays.xml
diff --git a/res/values-az/config.xml b/res/values-az/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-az/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az/strings.xml
similarity index 99%
rename from res/values-az-rAZ/strings.xml
rename to res/values-az/strings.xml
index 3754b1c..0f82a91 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Səsli poçt nömrəsi çatışmır"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kartda heç bir səsli poçt nömrəsi yoxdur."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Nömrə əlavə edin"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Səsli E-məktub Ayarları yalnız Əsas İstifadəçi tərəfindən dəyişdirilə bilər."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM kartınızın kilidi açıldı. Telefonunuzun da kilidi açılır…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM şəbəkəni kiliddən çıxaran PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Kilidi aç"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Qeyri-fövqəladə zəng etmək üçün fövqəladə zəng rejimindən çıxın."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Şəbəkədə qeydə alınmayıb."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobil şəbəkə əlçatımlı deyil."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobil şəbəkə əlçatmazdır. Zəng etmək üçün Wi-Fi şəbəkəsinə qoşulun."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Zəngi yerləşdirmək üçün düzgün nömrə daxil edin."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Zəng alınmadı."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Hazırda çağrı edilə bilməz."</string>
diff --git a/res/values-b+sr+Latn/config.xml b/res/values-b+sr+Latn/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-b+sr+Latn/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index bef9186..d4a82ea 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="phoneAppLabel" product="tablet" msgid="1107073389495104784">"Podaci za mobilne uređaje"</string>
+ <string name="phoneAppLabel" product="tablet" msgid="8576272342240415145">"Podaci za mobilne uređaje"</string>
<string name="phoneAppLabel" product="default" msgid="6790717591729922998">"Telefonske usluge"</string>
<string name="emergencyDialerIconLabel" msgid="7812140032168171053">"Hitni pozivi"</string>
<string name="phoneIconLabel" msgid="2331230813161304895">"Telefon"</string>
@@ -29,7 +29,7 @@
<string name="ussdRunning" msgid="485588686340541690">"USSD kôd je pokrenut…"</string>
<string name="mmiCancelled" msgid="2771923949751842276">"MMI kôd je otkazan"</string>
<string name="cancel" msgid="5044513931633602634">"Otkaži"</string>
- <string name="enter_input" msgid="1810529547726803893">"USSD poruka mora da ima između <xliff:g id="MIN_LEN">%d</xliff:g> i <xliff:g id="MAX_LEN">%d</xliff:g> znakova. Pokušajte ponovo."</string>
+ <string name="enter_input" msgid="1810529547726803893">"USSD poruka mora da ima između <xliff:g id="MIN_LEN">%d</xliff:g> i <xliff:g id="MAX_LEN">%d</xliff:g> znakova. Probajte ponovo."</string>
<string name="manageConferenceLabel" msgid="4691922394301969053">"Upravljanje konferencijskim pozivom"</string>
<string name="ok" msgid="3811371167865772377">"Potvrdi"</string>
<string name="audio_mode_speaker" msgid="27649582100085266">"Zvučnik"</string>
@@ -45,6 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Nedostaje broj za govornu poštu"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Nije uskladišten nijedan broj govorne pošte na SIM kartici."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Dodaj broj"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Vaša SIM kartica je odblokirana. Telefon se otključava..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN za otključavanje mreže na SIM kartici"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Otključaj"</string>
@@ -52,7 +54,7 @@
<string name="requesting_unlock" msgid="6412629401033249351">"Traženje otključavanja mreže"</string>
<string name="unlock_failed" msgid="6490531697031504225">"Neuspešan zahtev za zaključavanje mreže."</string>
<string name="unlock_success" msgid="6770085622238180152">"Uspešno otključavanje mreže"</string>
- <string name="mobile_network_settings_not_available" msgid="3831911315358856062">"Podešavanja mobilne mreže nisu dostupna za ovog korisnika"</string>
+ <string name="mobile_network_settings_not_available" msgid="7355254462995117896">"Podešavanja mobilne mreže nisu dostupna za ovog korisnika"</string>
<string name="labelGSMMore" msgid="5930842194056092106">"Podešavanja GSM poziva"</string>
<string name="labelGsmMore_with_label" msgid="2674012918829238901">"Podešavanja GSM poziva (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
<string name="labelCDMAMore" msgid="1630676740428229339">"CDMA podešavanja poziva"</string>
@@ -63,6 +65,7 @@
<string name="phone_accounts_make_calls_with" msgid="1969188078933152231">"Upućujte pozive pomoću"</string>
<string name="phone_accounts_make_sip_calls_with" msgid="4677789312053828493">"Upućujte SIP pozive pomoću"</string>
<string name="phone_accounts_ask_every_time" msgid="4346499067149985702">"Prvo pitaj"</string>
+ <string name="phone_accounts_default_account_label" msgid="4183772241814460014">"Mreža nije dostupna"</string>
<string name="phone_accounts_settings_header" msgid="4141710640883261094">"Podešavanja"</string>
<string name="phone_accounts_choose_accounts" msgid="5232948804226424002">"Izaberite naloge"</string>
<string name="phone_accounts_selection_header" msgid="1365215726106915865">"Nalozi na telefonu"</string>
@@ -106,15 +109,15 @@
<string name="sum_cfb_enabled" msgid="5984198104833116690">"Prosleđuje se na <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
<string name="sum_cfb_disabled" msgid="4913145177320506827">"Isključeno"</string>
<string name="disable_cfb_forbidden" msgid="3506984333877998061">"Operater ne podržava onemogućavanje preusmeravanja poziva kada je telefon zauzet."</string>
- <string name="labelCFNRy" msgid="1736067178393744351">"Kad se ne javite"</string>
- <string name="messageCFNRy" msgid="672317899884380374">"Broj kad se ne javite"</string>
+ <string name="labelCFNRy" msgid="1736067178393744351">"Kad se ne javim"</string>
+ <string name="messageCFNRy" msgid="672317899884380374">"Broj kad se ne javim"</string>
<string name="sum_cfnry_enabled" msgid="6955775691317662910">"Prosleđuje se na <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
<string name="sum_cfnry_disabled" msgid="3884684060443538097">"Isključeno"</string>
<string name="disable_cfnry_forbidden" msgid="4308233959150658058">"Operater ne podržava onemogućavanje preusmeravanja poziva kada se na poziv ne odgovori."</string>
- <string name="labelCFNRc" msgid="2614827454402079766">"Kada je nedostupno"</string>
+ <string name="labelCFNRc" msgid="2614827454402079766">"Kad sam nedostupan/a"</string>
<string name="messageCFNRc" msgid="6380695421020295119">"Broj kad je nedostupno"</string>
<string name="sum_cfnrc_enabled" msgid="7010898346095497421">"Prosleđuje se na <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
- <string name="sum_cfnrc_disabled" msgid="7222141261321276464">"Onemogućeno"</string>
+ <string name="sum_cfnrc_disabled" msgid="2684474391807469832">"Isključeno"</string>
<string name="disable_cfnrc_forbidden" msgid="5646361343094064333">"Mobilni operater ne podržava onemogućavanje preusmeravanja poziva kada je telefon nedostupan."</string>
<string name="updating_title" msgid="6146755386174019046">"Podešavanja poziva"</string>
<string name="call_settings_admin_user_only" msgid="4526094783818216374">"Samo korisniku sa administratorskim pravima je dozvoljeno da menja podešavanja poziva."</string>
@@ -146,7 +149,17 @@
<string name="no_change" msgid="3186040086622435212">"Nisu izvršene nikakve promene."</string>
<string name="sum_voicemail_choose_provider" msgid="59911196126278922">"Odaberite uslugu govorne pošte"</string>
<string name="voicemail_default" msgid="2001233554889016880">"Mobilni operater"</string>
- <string name="mobile_networks" msgid="2843854043339307375">"Podešavanja mobilne mreže"</string>
+ <string name="vm_change_pin_old_pin" msgid="7295220109886682573">"Stari PIN"</string>
+ <string name="vm_change_pin_new_pin" msgid="5412922262839438097">"Novi PIN"</string>
+ <string name="vm_change_pin_progress_message" msgid="3977357361934350336">"Sačekajte."</string>
+ <string name="vm_change_pin_error_too_short" msgid="5974971097302710497">"Novi PIN je prekratak."</string>
+ <string name="vm_change_pin_error_too_long" msgid="8476870806115051865">"Novi PIN je predugačak."</string>
+ <string name="vm_change_pin_error_too_weak" msgid="7883744811891784882">"Novi PIN je preslab. Jaka lozinka ne treba da sadrži uzastopni niz ni ponovljene cifre."</string>
+ <string name="vm_change_pin_error_mismatch" msgid="2754685537970757317">"Stari PIN se ne podudara."</string>
+ <string name="vm_change_pin_error_invalid" msgid="3972205462701668653">"Novi PIN sadrži nevažeće znakove."</string>
+ <string name="vm_change_pin_error_system_error" msgid="6610603326230000207">"Promena PIN-a nije uspela"</string>
+ <string name="vvm_unsupported_message_format" msgid="11795090778411977">"Nepodržani tip poruke. Pozovite <xliff:g id="NUMBER">%s</xliff:g> da biste je preslušali."</string>
+ <string name="mobile_networks" msgid="5540397602919106177">"Podešavanja za mob. mrežu"</string>
<string name="label_available" msgid="1181658289009300430">"Dostupne mreže"</string>
<string name="load_networks_progress" msgid="5230707536168902952">"Pretražuje se…"</string>
<string name="empty_networks_list" msgid="4249426905018815316">"Nisu pronađene mreže."</string>
@@ -154,7 +167,7 @@
<string name="network_query_error" msgid="6828516148953325006">"Greška tokom traženja mreža."</string>
<string name="register_on_network" msgid="9055203954040805084">"Registrovanje na <xliff:g id="NETWORK">%s</xliff:g>…"</string>
<string name="not_allowed" msgid="5613353860205691579">"SIM kartica ne dozvoljava vezu sa ovom mrežom."</string>
- <string name="connect_later" msgid="2308119155752343975">"Trenutno nije moguće povezati se sa ovom mrežom. Pokušajte ponovo kasnije."</string>
+ <string name="connect_later" msgid="2308119155752343975">"Trenutno nije moguće povezati se sa ovom mrežom. Probajte ponovo kasnije."</string>
<string name="registration_done" msgid="495135664535876612">"Registrovano na mreži."</string>
<string name="sum_carrier_select" msgid="3494252551249882718">"Izaberite mrežnog operatera"</string>
<string name="sum_search_networks" msgid="2921092249873272715">"Potraži sve dostupne mreže"</string>
@@ -197,9 +210,11 @@
<item msgid="3817924849415716259">"GSM/WCDMA ima prednost"</item>
</string-array>
<string name="enhanced_4g_lte_mode_title" msgid="522191650223239171">"Poboljšani 4G LTE režim"</string>
+ <string name="enhanced_4g_lte_mode_title_variant" msgid="4871126028907265406">"Napredno pozivanje"</string>
<string name="enhanced_4g_lte_mode_summary" msgid="2332175070522125850">"Korišćenje LTE usluga za poboljšanje glasovnih i drugih komunikacija (preporučeno)"</string>
<string name="data_enabled" msgid="5972538663568715366">"Podaci su omogućeni"</string>
<string name="data_enable_summary" msgid="2382798156640007971">"Omogućavanje potrošnje podataka"</string>
+ <string name="dialog_alert_title" msgid="6751344986194435476">"Pažnja"</string>
<string name="roaming" msgid="8871412572928323707">"Prenos podataka u romingu"</string>
<string name="roaming_enable" msgid="7331106985174381987">"Povezivanje sa uslugom za podatke tokom rominga"</string>
<string name="roaming_disable" msgid="1843417228755568110">"Povezivanje sa uslugom za podatke tokom rominga"</string>
@@ -218,7 +233,7 @@
<string name="throttle_data_rate_reduced_subtext" msgid="7492763592720107737">"<xliff:g id="USED_0">%1$s</xliff:g> maksimum je premašen\nStopa prenosa podataka smanjena je na <xliff:g id="USED_1">%2$d</xliff:g> Kb/s"</string>
<string name="throttle_time_frame_subtext" msgid="7732763021560399960">"<xliff:g id="USED_0">%1$d</xliff:g>٪ je proteklo od ciklusa\nSledeći period počinje za <xliff:g id="USED_1">%2$d</xliff:g> dana (<xliff:g id="USED_2">%3$s</xliff:g>)"</string>
<string name="throttle_rate_subtext" msgid="2149102656120726855">"Brzina prenosa podataka smanjena je na <xliff:g id="USED">%1$d</xliff:g> Kb/s ako je premašeno ograničenje za korišćenje podataka"</string>
- <string name="throttle_help_subtext" msgid="3633091498168446044">"Više informacija o smernicama za korišćenje podataka mobilne mreže operatera"</string>
+ <string name="throttle_help_subtext" msgid="5217706521499010816">"Više informacija o smernicama za korišćenje podataka mobilne mreže operatera"</string>
<string name="cell_broadcast_sms" msgid="5584192824053625842">"SMS info servisa"</string>
<string name="enable_disable_cell_bc_sms" msgid="4851147873691392255">"SMS info servisa"</string>
<string name="cell_bc_sms_enable" msgid="6441688565738921084">"Omogućen je SMS info servisa"</string>
@@ -330,19 +345,19 @@
<string name="cdma_activate_device" msgid="3793805892364814518">"Aktiviranje uređaja"</string>
<string name="cdma_lte_data_service" msgid="4255018217292548962">"Podesite usl. prenosa podataka"</string>
<string name="carrier_settings_title" msgid="9028166176523012300">"Podešavanja operatera"</string>
- <string name="fdn" msgid="7878832555095183202">"Fiksni birani brojevi"</string>
+ <string name="fdn" msgid="7878832555095183202">"Brojevi za fiksno biranje"</string>
<string name="fdn_with_label" msgid="187084204115493366">"Brojevi za fiksno biranje (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
<string name="manage_fdn_list" msgid="8777755791892122369">"Lista brojeva za fiksno biranje"</string>
<string name="fdn_list_with_label" msgid="7437232552210469217">"Lista brojeva za fiksno biranje (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
<string name="fdn_activation" msgid="2156479741307463576">"FDN aktivacija"</string>
- <string name="fdn_enabled" msgid="5238109009915521240">"Omogućeni su fiksni birani brojevi"</string>
- <string name="fdn_disabled" msgid="4700049736675368279">"Onemogućeni su fiksni birani brojevi"</string>
+ <string name="fdn_enabled" msgid="5238109009915521240">"Omogućeni su brojevi za fiksno biranje"</string>
+ <string name="fdn_disabled" msgid="4700049736675368279">"Onemogućeni su brojevi za fiksno biranje"</string>
<string name="enable_fdn" msgid="3740191529180493851">"Omogući broj za fiksno biranje"</string>
<string name="disable_fdn" msgid="7944020890722540616">"Onemogući broj za fiksno biranje"</string>
<string name="change_pin2" msgid="2153563695382176676">"Promeni PIN2"</string>
<string name="enable_fdn_ok" msgid="7215588870329688132">"Onemogući broj za fiksno biranje"</string>
<string name="disable_fdn_ok" msgid="5727046928930740173">"Omogući broj za fiksno biranje"</string>
- <string name="sum_fdn" msgid="1959399454900272878">"Upravljanje fiksnim biranim brojevima"</string>
+ <string name="sum_fdn" msgid="1959399454900272878">"Upravljanje brojevima za fiksno biranje"</string>
<string name="sum_fdn_change_pin" msgid="6666549734792827932">"Promeni PIN za pristup broju za fiksno biranje"</string>
<string name="sum_fdn_manage_list" msgid="8431088265332628316">"Upravljanje listom telefonskih brojeva"</string>
<string name="voice_privacy" msgid="3776841382844614716">"Privatnost glasa"</string>
@@ -355,6 +370,7 @@
<string name="menu_add" msgid="1882023737425114762">"Dodaj kontakt"</string>
<string name="menu_edit" msgid="7143003705504672374">"Izmeni kontakt"</string>
<string name="menu_delete" msgid="3977150783449642851">"Izbriši kontakt"</string>
+ <string name="menu_dial" msgid="3223106222819685808">"Pozovi kontakt"</string>
<string name="get_pin2" msgid="8204677063922225311">"Unesite PIN2"</string>
<string name="name" msgid="7329028332786872378">"Ime"</string>
<string name="number" msgid="7905950798349903858">"Broj"</string>
@@ -369,7 +385,7 @@
<string name="deleting_fdn_contact" msgid="5669163206349319969">"Brisanje broja za fiksno biranje…"</string>
<string name="fdn_contact_deleted" msgid="7154162327112259569">"Izbrisan je broj za fiksno biranje."</string>
<string name="pin2_invalid" msgid="5470854099230755944">"Broj za fiksno biranje nije ažuriran jer ste uneli netačan PIN kôd."</string>
- <string name="fdn_invalid_number" msgid="1494755047900009147">"Broj za fiksno biranje nije ažuriran jer broj ne sme da premašuje 20 cifara."</string>
+ <string name="fdn_invalid_number" msgid="8602417141715473998">"Broj za fiksno biranje nije ažuriran jer je prazan ili ima više od 20 cifara."</string>
<string name="pin2_or_fdn_invalid" msgid="6025144083384701197">"FDN nije ažuriran. PIN2 je netačan ili je broj telefona odbačen."</string>
<string name="fdn_failed" msgid="540018079008319747">"Radnja sa brojem za fiksno biranje nije uspela."</string>
<string name="simContacts_emptyLoading" msgid="2203331234764498011">"Čita se sa SIM kartice…"</string>
@@ -382,8 +398,8 @@
<string name="oldPinLabel" msgid="5287773661246368314">"Stari PIN"</string>
<string name="newPinLabel" msgid="207488227285336897">"Novi PIN"</string>
<string name="confirmPinLabel" msgid="257597715098070206">"Potvrdite novi PIN"</string>
- <string name="badPin" msgid="8955102849303984935">"Stari PIN kôd koji ste uneli je netačan. Pokušajte ponovo."</string>
- <string name="mismatchPin" msgid="5923253370683071889">"PIN kodovi koje ste uneli se ne podudaraju. Pokušajte ponovo."</string>
+ <string name="badPin" msgid="8955102849303984935">"Stari PIN kôd koji ste uneli je netačan. Probajte ponovo."</string>
+ <string name="mismatchPin" msgid="5923253370683071889">"PIN kodovi koje ste uneli se ne podudaraju. Probajte ponovo."</string>
<string name="invalidPin" msgid="5981171102258684792">"Otkucajte PIN koji ima od 4 do 8 brojeva."</string>
<string name="disable_sim_pin" msgid="3419351358300716472">"Brisanje PIN-a za SIM"</string>
<string name="enable_sim_pin" msgid="4845145659651484248">"Podešavanje PIN-a za SIM"</string>
@@ -397,9 +413,9 @@
<string name="oldPin2Label" msgid="8559146795026261502">"Stari PIN2"</string>
<string name="newPin2Label" msgid="4573956902204349054">"Novi PIN2"</string>
<string name="confirmPin2Label" msgid="8100319484454787708">"Potvrdite novi PIN2"</string>
- <string name="badPuk2" msgid="7910064009531541708">"PUK2 nije tačan. Pokušajte ponovo."</string>
- <string name="badPin2" msgid="6646896629970023109">"Stari PIN2 nije tačan. Pokušajte ponovo."</string>
- <string name="mismatchPin2" msgid="4177967478551851117">"PIN2 kodovi se ne podudaraju. Pokušajte ponovo."</string>
+ <string name="badPuk2" msgid="7910064009531541708">"PUK2 nije tačan. Probajte ponovo."</string>
+ <string name="badPin2" msgid="6646896629970023109">"Stari PIN2 nije tačan. Probajte ponovo."</string>
+ <string name="mismatchPin2" msgid="4177967478551851117">"PIN2 kodovi se ne podudaraju. Probajte ponovo."</string>
<string name="invalidPin2" msgid="1757045131429105595">"Unesite PIN2 koji sadrži 4 do 8 cifara."</string>
<string name="invalidPuk2" msgid="7059081153334815973">"Unesite PUK2 koji sadrži 8 cifara."</string>
<string name="pin2_changed" msgid="3724522579945610956">"PIN2 je ažuriran"</string>
@@ -426,15 +442,17 @@
<string name="notification_voicemail_no_vm_number" msgid="760963466895609716">"Nepoznat broj govorne pošte"</string>
<string name="notification_network_selection_title" msgid="4224455487793492772">"Nema usluge"</string>
<string name="notification_network_selection_text" msgid="2607085729661923269">"Izabrana mreža (<xliff:g id="OPERATOR_NAME">%s</xliff:g>) nije dostupna"</string>
- <string name="incall_error_power_off" msgid="2947938060513306698">"Isključite režim rada u avionu da biste uputili poziv."</string>
+ <string name="incall_error_power_off" product="watch" msgid="772302793483607711">"Isključite režim rada u avionu ili uštede baterije da biste uputili poziv."</string>
+ <string name="incall_error_power_off" product="default" msgid="2947938060513306698">"Isključite režim rada u avionu da biste uputili poziv."</string>
<string name="incall_error_power_off_wfc" msgid="8711428920632416575">"Isključite režim rada u avionu ili se povežite na bežičnu mrežu da biste uputili poziv."</string>
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Izađite iz režima hitnog povratnog poziva da biste uputili poziv koji nije hitan."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Nije registrovano na mreži."</string>
- <string name="incall_error_out_of_service" msgid="4100065333878929223">"Mobilna mreža nije dostupna."</string>
- <string name="incall_error_out_of_service_wfc" msgid="323851839058697057">"Mobilna mreža nije dostupna. Povežite se na bežičnu mrežu da biste uputili poziv."</string>
+ <string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobilna mreža nije dostupna."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Da biste uputili poziv, unesite važeći broj."</string>
- <string name="incall_error_call_failed" msgid="6302746943230078197">"Poziv nije uspeo."</string>
- <string name="incall_status_dialed_mmi" msgid="3672498861336189563">"Pokretanje MMI sekvence"</string>
+ <string name="incall_error_call_failed" msgid="5891978320269774095">"Poziv nije uspeo."</string>
+ <string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Trenutno nije moguće dodati poziv."</string>
<string name="incall_error_supp_service_unknown" msgid="655570339115407698">"Usluga nije podržana"</string>
<string name="incall_error_supp_service_switch" msgid="5237002176899962862">"Zamena poziva nije uspela."</string>
<string name="incall_error_supp_service_separate" msgid="7224393405134545246">"Razdvajanje poziva nije uspelo."</string>
@@ -442,10 +460,13 @@
<string name="incall_error_supp_service_conference" msgid="2505727299596357312">"Konferencijski pozivi nisu mogući."</string>
<string name="incall_error_supp_service_reject" msgid="8998568661508655638">"Odbijanje poziva nije uspelo."</string>
<string name="incall_error_supp_service_hangup" msgid="7434513517153834426">"Uspostavljanje poziva nije uspelo."</string>
+ <string name="incall_error_supp_service_hold" msgid="7967020511232222078">"Nije moguće stavljati pozive na čekanje."</string>
<string name="incall_error_wfc_only_no_wireless_network" msgid="1782466780452640089">"Povežite se na bežičnu mrežu da biste uputili poziv."</string>
+ <string name="incall_error_promote_wfc" msgid="106510757624022064">"Omogućite pozivanje preko Wi-Fi-ja da biste uputili poziv."</string>
<string name="emergency_enable_radio_dialog_title" msgid="4627849966634578257">"Hitan poziv"</string>
<string name="emergency_enable_radio_dialog_message" msgid="207613549344420291">"Uključivanje radija…"</string>
<string name="emergency_enable_radio_dialog_retry" msgid="5960061579996526883">"Nema mreže. Ponovni pokušaj…"</string>
+ <string name="radio_off_during_emergency_call" msgid="2535800034010306830">"Ulazak u režim rada u avionu nije moguć tokom hitnog poziva."</string>
<string name="dial_emergency_error" msgid="1509085166367420355">"Poziv nije uspeo. <xliff:g id="NON_EMERGENCY_NUMBER">%s</xliff:g> nije broj za hitne slučajeve."</string>
<string name="dial_emergency_empty_error" msgid="9130194953830414638">"Poziv nije uspeo. Pozovite broj za hitne slučajeve."</string>
<string name="dialerKeyboardHintText" msgid="9192914825413747792">"Koristite tastaturu za pozivanje"</string>
@@ -469,7 +490,7 @@
<string name="hac_mode_title" msgid="8740268574688743289">"Slušni aparat"</string>
<string name="hac_mode_summary" msgid="6833851160514929341">"Uključi kompatibilnost sa slušnim aparatom"</string>
<string-array name="tty_mode_entries">
- <item msgid="512950011423868021">"TTY isključeno"</item>
+ <item msgid="512950011423868021">"TTY je isključen"</item>
<item msgid="3971695875449640648">"TTY je pun"</item>
<item msgid="1937509904407445684">"TTY HCO"</item>
<item msgid="5644925873488772224">"TTY VCO"</item>
@@ -497,10 +518,10 @@
<string name="ota_progress" msgid="460876637828044519">"Telefon se programira…"</string>
<string name="ota_failure" msgid="7713756181204620397">"Programiranje telefona nije uspelo"</string>
<string name="ota_successful" msgid="1880780692887077407">"Telefon je sada aktiviran. Možda će biti potrebno najviše 15 minuta da bi se usluga pokrenula."</string>
- <string name="ota_unsuccessful" msgid="8072141612635635357">"Telefon se nije aktivirao. \nMožda je potrebno da pronađete oblast sa boljom pokrivenošću (blizu prozora ili napolju). \n\nPokušajte ponovo ili pozovite korisničku podršku za još opcija."</string>
+ <string name="ota_unsuccessful" msgid="8072141612635635357">"Telefon se nije aktivirao. \nMožda je potrebno da pronađete oblast sa boljom pokrivenošću (blizu prozora ili napolju). \n\nProbajte ponovo ili pozovite korisničku podršku za još opcija."</string>
<string name="ota_spc_failure" msgid="3909983542575030796">"SLUČAJNA SPC GREŠKA"</string>
<string name="ota_call_end" msgid="4537279738134612388">"Nazad"</string>
- <string name="ota_try_again" msgid="7685477206465902290">"Pokušaj ponovo"</string>
+ <string name="ota_try_again" msgid="7685477206465902290">"Probaj ponovo"</string>
<string name="ota_next" msgid="3904945374358235910">"Sledeće"</string>
<string name="ecm_exit_dialog" msgid="4448531867763097533">"Dijalog za izlazak iz režima hitnog povratnog poziva"</string>
<string name="phone_entered_ecm_text" msgid="6266424252578731203">"Unet je režim za hitan povratni poziv"</string>
@@ -531,7 +552,7 @@
<string name="voicemail_number_not_set" msgid="6724904736891087856">"<Nije podešeno>"</string>
<string name="other_settings" msgid="3672912580359716394">"Druga podešavanja poziva"</string>
<string name="calling_via_template" msgid="4839419581866928142">"Pozivanje preko <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
- <string name="contactPhoto" msgid="4713193418046639466">"fotografija kontakta"</string>
+ <string name="contactPhoto" msgid="4713193418046639466">"slika kontakta"</string>
<string name="goPrivate" msgid="865837794424530980">"idi na privatno"</string>
<string name="selectContact" msgid="781975788478987237">"izaberite kontakt"</string>
<string name="not_voice_capable" msgid="2739898841461577811">"Audio pozivi nisu podržani"</string>
@@ -539,6 +560,8 @@
<string name="voicemail_notification_vibrate_when_title" msgid="8361970092063604886">"Vibracija"</string>
<string name="voicemail_notification_vibarte_when_dialog_title" msgid="5739583146522136440">"Vibracija"</string>
<string name="voicemail_visual_voicemail_switch_title" msgid="5012622186976275457">"Vizuelna govorna pošta"</string>
+ <string name="voicemail_set_pin_dialog_title" msgid="2797924461029093837">"Podesite PIN"</string>
+ <string name="voicemail_change_pin_dialog_title" msgid="6035421908626121564">"Promenite PIN"</string>
<string name="voicemail_notification_ringtone_title" msgid="2609519527849101590">"Zvuk"</string>
<string name="preference_category_ringtone" msgid="5197960752529332721">"Melodija zvona i vibracija"</string>
<string name="pstn_connection_service_label" msgid="1743245930577325900">"Ugrađene SIM kartice"</string>
@@ -550,9 +573,24 @@
<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="5841511849007540970">"Dodirnite ponovo da biste otvorili"</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>
<string name="callFailed_cdma_activation" msgid="2307989779233262164">"SIM kartica je aktivirala uslugu i ažurirala funkcije rominga na telefonu."</string>
+ <string name="callFailed_cdma_call_limit" msgid="1556916577171457086">"Ima previše aktivnih poziva. Završite ili objedinite postojeće pozive pre nego što uputite novi."</string>
+ <string name="callFailed_imei_not_accepted" msgid="132192626901238542">"Povezivanje nije uspelo, ubacite važeću SIM karticu."</string>
+ <string name="callFailed_wifi_lost" msgid="5968076625137297184">"Wi-Fi veza je prekinuta. Poziv je završen."</string>
+ <string name="change_pin_title" msgid="7790232089699034029">"Promenite PIN kôd govorne pošte"</string>
+ <string name="change_pin_continue_label" msgid="2135088662420163447">"Nastavi"</string>
+ <string name="change_pin_cancel_label" msgid="353535488390948596">"Otkaži"</string>
+ <string name="change_pin_ok_label" msgid="6204308560844889926">"Potvrdi"</string>
+ <string name="change_pin_enter_old_pin_header" msgid="419179847657548887">"Potvrdite stari PIN"</string>
+ <string name="change_pin_enter_old_pin_hint" msgid="8579171678763615453">"kôd govorne pošte da biste nastavili."</string>
+ <string name="change_pin_enter_new_pin_header" msgid="2611191814590251532">"Podesite novi PIN"</string>
+ <string name="change_pin_enter_new_pin_hint" msgid="2322940054329689309">"Broj cifara koje PIN mora da sadrži: <xliff:g id="MIN">%1$d</xliff:g>–<xliff:g id="MAX">%2$d</xliff:g>."</string>
+ <string name="change_pin_confirm_pin_header" msgid="8113764019347322170">"Potvrdite PIN"</string>
+ <string name="change_pin_confirm_pins_dont_match" msgid="4795052654904027909">"PIN-ovi se ne podudaraju"</string>
+ <string name="change_pin_succeeded" msgid="2022852286442211151">"PIN kôd govorne pošte je ažuriran"</string>
+ <string name="change_pin_system_error" msgid="8308462387154257840">"Podešavanje PIN-a nije uspelo"</string>
</resources>
diff --git a/res/values-gl-rES/arrays.xml b/res/values-be/arrays.xml
similarity index 100%
copy from res/values-gl-rES/arrays.xml
copy to res/values-be/arrays.xml
diff --git a/res/values-be/config.xml b/res/values-be/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-be/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
new file mode 100644
index 0000000..aa1ef68
--- /dev/null
+++ b/res/values-be/strings.xml
@@ -0,0 +1,600 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="phoneAppLabel" product="tablet" msgid="8576272342240415145">"Mobile Data"</string>
+ <string name="phoneAppLabel" product="default" msgid="6790717591729922998">"Тэлефонныя службы"</string>
+ <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="private_num" msgid="6713286113000232309">"Прыватны нумар"</string>
+ <string name="payphone" msgid="4793877574636445118">"Таксафон"</string>
+ <string name="onHold" msgid="9035493194749959955">"У чаканні"</string>
+ <string name="mmiStarted" msgid="6347869857061147003">"Пачалося выкананне MMI кода"</string>
+ <string name="ussdRunning" msgid="485588686340541690">"Запускаецца USSD-код..."</string>
+ <string name="mmiCancelled" msgid="2771923949751842276">"Код MMI адменены"</string>
+ <string name="cancel" msgid="5044513931633602634">"Адмяніць"</string>
+ <string name="enter_input" msgid="1810529547726803893">"Паведамленне USSD павінна складацца з наступнай колькасцi знакаў: ад <xliff:g id="MIN_LEN">%d</xliff:g> да <xliff:g id="MAX_LEN">%d</xliff:g>. Паспрабуйце яшчэ раз."</string>
+ <string name="manageConferenceLabel" msgid="4691922394301969053">"Кіраванне канферэнц-выклікам"</string>
+ <string name="ok" msgid="3811371167865772377">"ОК"</string>
+ <string name="audio_mode_speaker" msgid="27649582100085266">"Дынамік"</string>
+ <string name="audio_mode_earpiece" msgid="4156527186373869107">"Дынамік тэлефона"</string>
+ <string name="audio_mode_wired_headset" msgid="1465350758489175975">"Правадная гарнітура"</string>
+ <string name="audio_mode_bluetooth" msgid="3047641300848211128">"Bluetooth"</string>
+ <string name="wait_prompt_str" msgid="7601815427707856238">"Адправіць наступныя тоны?\n"</string>
+ <string name="pause_prompt_str" msgid="1789964702154314806">"Адпраўка сігналаў\n"</string>
+ <string name="send_button" msgid="4106860097497818751">"Адправіць"</string>
+ <string name="pause_prompt_yes" msgid="3564467212025151797">"Так"</string>
+ <string name="pause_prompt_no" msgid="6686238803236884877">"Не"</string>
+ <string name="wild_prompt_str" msgid="5543521676355533577">"Замяніце выпадковы сімвал:"</string>
+ <string name="no_vm_number" msgid="4164780423805688336">"Адсутнічае нумар галасавой пошты"</string>
+ <string name="no_vm_number_msg" msgid="1300729501030053828">"На SIM-карце няма нумару галасавой пошты."</string>
+ <string name="add_vm_number_str" msgid="4676479471644687453">"Дадаць нумар"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
+ <string name="puk_unlocked" msgid="2284912838477558454">"Ваша SIM-карта была разблакаваная. Ваш тэлефон разблакоўваецца..."</string>
+ <string name="label_ndp" msgid="780479633159517250">"PIN-код разблакавання сеткі SIM"</string>
+ <string name="sim_ndp_unlock_text" msgid="683628237760543009">"Разблакаваць"</string>
+ <string name="sim_ndp_dismiss_text" msgid="1604823375752456947">"Адхіліць"</string>
+ <string name="requesting_unlock" msgid="6412629401033249351">"Запыт разблакавання сеткі..."</string>
+ <string name="unlock_failed" msgid="6490531697031504225">"Запыт разблакавання сеткі няўдалы."</string>
+ <string name="unlock_success" msgid="6770085622238180152">"Сетка паспяхова разблакавана."</string>
+ <!-- no translation found for mobile_network_settings_not_available (7355254462995117896) -->
+ <skip />
+ <string name="labelGSMMore" msgid="5930842194056092106">"Налады выклікаў GSM"</string>
+ <string name="labelGsmMore_with_label" msgid="2674012918829238901">"Налады выклікаў GSM (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="labelCDMAMore" msgid="1630676740428229339">"Налады выклікаў CDMA"</string>
+ <string name="labelCdmaMore_with_label" msgid="6333588719319970399">"Налады выклікаў CDMA (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="apn_settings" msgid="9043423184895642077">"Назвы кропак доступу"</string>
+ <string name="settings_label" msgid="3876743539816984008">"Налады сеткі"</string>
+ <string name="phone_accounts" msgid="6376603393888116364">"Уліковыя запісы для выклікаў"</string>
+ <string name="phone_accounts_make_calls_with" msgid="1969188078933152231">"Рабіць выклікі праз"</string>
+ <string name="phone_accounts_make_sip_calls_with" msgid="4677789312053828493">"Рабіць SIP-выклікі праз"</string>
+ <string name="phone_accounts_ask_every_time" msgid="4346499067149985702">"Спачатку запытваць"</string>
+ <string name="phone_accounts_default_account_label" msgid="4183772241814460014">"Даступных сетак няма"</string>
+ <string name="phone_accounts_settings_header" msgid="4141710640883261094">"Налады"</string>
+ <string name="phone_accounts_choose_accounts" msgid="5232948804226424002">"Выбраць уліковыя запісы"</string>
+ <string name="phone_accounts_selection_header" msgid="1365215726106915865">"Уліковыя запісы тэлефона"</string>
+ <string name="phone_accounts_add_sip_account" msgid="2023821743341923271">"Дадаць уліковы запіс SIP"</string>
+ <string name="phone_accounts_configure_account_settings" msgid="1361715069911607109">"Канфігурацыя налад уліковых запісаў"</string>
+ <string name="phone_accounts_all_calling_accounts" msgid="207619531589278471">"Усе ўліковыя запісы выклікаў"</string>
+ <string name="phone_accounts_all_calling_accounts_summary" msgid="8594186415822657011">"Выберыце, з якіх уліковых запісаў можна рабіць выклікі"</string>
+ <string name="wifi_calling" msgid="739018212480165598">"Wi-Fi-тэлефанія"</string>
+ <string name="connection_service_default_label" msgid="1498481943805913754">"Убудаваная служба злучэнняў"</string>
+ <string name="voicemail" msgid="8693759337917898954">"Галасавая пошта"</string>
+ <string name="voicemail_settings_with_label" msgid="152724978380748296">"Галасавая пошта (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="voicemail_abbreviated" msgid="2215592488517217448">"ГП:"</string>
+ <string name="networks" msgid="8873030692174541976">"Сеткавыя аператары"</string>
+ <string name="cell_broadcast_settings" msgid="8740238216690502563">"Экстранныя трансляцыі"</string>
+ <string name="call_settings" msgid="6112441768261754562">"Налады выклікаў"</string>
+ <string name="additional_gsm_call_settings" msgid="1391795981938800617">"Дадатковыя налады"</string>
+ <string name="additional_gsm_call_settings_with_label" msgid="1385241520708457376">"Дадатковыя налады (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="sum_gsm_call_settings" msgid="4076647190996778012">"Дадатковыя налады выклікаў толькі для GSM"</string>
+ <string name="additional_cdma_call_settings" msgid="8628958775721886909">"Дадатковыя налады выклікаў CDMA"</string>
+ <string name="sum_cdma_call_settings" msgid="284753265979035549">"Дадатковыя налады толькі для выклікаў CDMA"</string>
+ <string name="labelNwService" msgid="4699970172021870983">"Налады сеткавых паслуг"</string>
+ <string name="labelCallerId" msgid="3888899447379069198">"АВН"</string>
+ <string name="sum_loading_settings" msgid="1826692909391168620">"Загрузка налад..."</string>
+ <string name="sum_hide_caller_id" msgid="1071407020290873782">"Нумар схаваны з выходных выклікаў"</string>
+ <string name="sum_show_caller_id" msgid="6768534125447290401">"Нумар, якi паказваецца ў выходных выкліках"</string>
+ <string name="sum_default_caller_id" msgid="1954518825510901365">"Выкарыстоўваць налады па змаўчаннi, каб аператар мог адлюстроўваць мой нумар у выходных выкліках"</string>
+ <string name="labelCW" msgid="6120513814915920200">"Чаканне выкліку"</string>
+ <string name="sum_cw_enabled" msgid="8083061901633671397">"Паведамляць пра ўваходныя выклікі падчас размовы"</string>
+ <string name="sum_cw_disabled" msgid="3648693907300104575">"Паведамляць пра ўваходныя выклікі падчас размовы"</string>
+ <string name="call_forwarding_settings" msgid="3378927671091537173">"Налады пераадрасацыі выкліку"</string>
+ <string name="call_forwarding_settings_with_label" msgid="8569489414006897127">"Налады пераадрасацыі выкліку (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="labelCF" msgid="2574386948026924737">"Пераадрасацыя выкліку"</string>
+ <string name="labelCFU" msgid="8147177368148660600">"Заўсёды пераадрасоўваць"</string>
+ <string name="messageCFU" msgid="3560082430662923687">"Заўсёды выкарыстоўваць гэты нумар"</string>
+ <string name="sum_cfu_enabled_indicator" msgid="4014187342724130197">"Пераадрасацыя ўсіх выклікаў"</string>
+ <string name="sum_cfu_enabled" msgid="2450052502198827927">"Пераадрасацыя ўсіх тэлефанаванняў на <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+ <string name="sum_cfu_enabled_no_number" msgid="6591985777096823616">"Нумар недаступны"</string>
+ <string name="sum_cfu_disabled" msgid="8384177689501334080">"Выкл."</string>
+ <string name="labelCFB" msgid="6139853033106283172">"Калі заняты"</string>
+ <string name="messageCFB" msgid="3711089705936187129">"Нумар, калі занята"</string>
+ <string name="sum_cfb_enabled" msgid="5984198104833116690">"Пераадрасацыя на <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+ <string name="sum_cfb_disabled" msgid="4913145177320506827">"Выкл."</string>
+ <string name="disable_cfb_forbidden" msgid="3506984333877998061">"Ваш аператар не падтрымлівае адключэнне перанакіравання выклікаў, калі тэлефон заняты."</string>
+ <string name="labelCFNRy" msgid="1736067178393744351">"Калі няма адказу"</string>
+ <string name="messageCFNRy" msgid="672317899884380374">"Нумар, калі няма адказу"</string>
+ <string name="sum_cfnry_enabled" msgid="6955775691317662910">"Пераадрасацыя на <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+ <string name="sum_cfnry_disabled" msgid="3884684060443538097">"Выкл."</string>
+ <string name="disable_cfnry_forbidden" msgid="4308233959150658058">"Ваш аператар не падтрымлівае адключэнне перанакіравання выклікаў, калі тэлефон не адказвае."</string>
+ <string name="labelCFNRc" msgid="2614827454402079766">"Калі недасягальны"</string>
+ <string name="messageCFNRc" msgid="6380695421020295119">"Нумар, калі недаступны"</string>
+ <string name="sum_cfnrc_enabled" msgid="7010898346095497421">"Пераадрасацыя на <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+ <string name="sum_cfnrc_disabled" msgid="2684474391807469832">"Выключаны"</string>
+ <string name="disable_cfnrc_forbidden" msgid="5646361343094064333">"Ваш аператар не падтрымлівае адключэнне пераадрасацыi выклікаў, калі тэлефон недаступны."</string>
+ <string name="updating_title" msgid="6146755386174019046">"Налады выклікаў"</string>
+ <string name="call_settings_admin_user_only" msgid="4526094783818216374">"Налады выклікаў можа мяняць толькі адміністратар."</string>
+ <string name="call_settings_with_label" msgid="3401177261468593519">"Налады (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="error_updating_title" msgid="7970259216988931777">"Памылка налад выкліку"</string>
+ <string name="reading_settings" msgid="1920291699287055284">"Чытанне налад..."</string>
+ <string name="updating_settings" msgid="8171225533884883252">"Абнаўленне налад..."</string>
+ <string name="reverting_settings" msgid="4752151682666912828">"Вяртанне налад..."</string>
+ <string name="response_error" msgid="6674110501330139405">"Нечаканы адказ ад сеткі."</string>
+ <string name="exception_error" msgid="7027667130619518211">"Памылка сеткі ці SIM-карты."</string>
+ <string name="stk_cc_ss_to_dial_error" msgid="2816779198916570502">"Запыт SS зменены на запыт DIAL."</string>
+ <string name="stk_cc_ss_to_ussd_error" msgid="7490626178582654236">"Запыт SS зменены на запыт USSD."</string>
+ <string name="stk_cc_ss_to_ss_error" msgid="5057846756489053759">"Запыт SS зменены на новы запыт SS."</string>
+ <string name="fdn_check_failure" msgid="18200614306525434">"Уключаны дазволеныя нумары. У выніку некаторыя функцыі адносна званкоў не працуюць."</string>
+ <string name="radio_off_error" msgid="2304459933248513376">"Перад праглядам гэтых параметраў уключыце радыё."</string>
+ <string name="close_dialog" msgid="2365884406356986917">"ОК"</string>
+ <string name="enable" msgid="7248657275000173526">"Уключыць"</string>
+ <string name="disable" msgid="4678348128118573672">"Адключыць"</string>
+ <string name="change_num" msgid="239476305819844391">"Абнавіць"</string>
+ <string-array name="clir_display_values">
+ <item msgid="5560134294467334594">"Для сеткі па змаўчаннi"</item>
+ <item msgid="7876195870037833661">"Схаваць нумар"</item>
+ <item msgid="1108394741608734023">"Паказаць нумар"</item>
+ </string-array>
+ <string name="vm_changed" msgid="380744030726254139">"Нумар галасавой пошты змяніўся."</string>
+ <string name="vm_change_failed" msgid="3352934863246208918">"Не атрымалася змяніць нумар галасавой пошты.\nКалі праблема не вырашыцца, звярніцеся да свайго аператара."</string>
+ <string name="fw_change_failed" msgid="5298103228470214665">"Не атрымалася змяніць нумар для пераадрасацыi.\nКалі гэтая праблема не вырашыцца, звярніцеся да свайго аператара."</string>
+ <string name="fw_get_in_vm_failed" msgid="8862896836093833973">"Немагчыма атрымаць і захаваць бягучыя налады пераадрасацыі нумару.\nУсё роўна пераключыць на новага пастаўшчыка?"</string>
+ <string name="no_change" msgid="3186040086622435212">"Змены не выкананы."</string>
+ <string name="sum_voicemail_choose_provider" msgid="59911196126278922">"Выберыце службу галасавой пошты"</string>
+ <string name="voicemail_default" msgid="2001233554889016880">"Ваш аператар"</string>
+ <string name="vm_change_pin_old_pin" msgid="7295220109886682573">"Стары PIN-код"</string>
+ <string name="vm_change_pin_new_pin" msgid="5412922262839438097">"Новы PIN-код"</string>
+ <string name="vm_change_pin_progress_message" msgid="3977357361934350336">"Пачакайце."</string>
+ <string name="vm_change_pin_error_too_short" msgid="5974971097302710497">"Новы PIN-код занадта кароткі."</string>
+ <string name="vm_change_pin_error_too_long" msgid="8476870806115051865">"Новы PIN-код занадта доўгі."</string>
+ <string name="vm_change_pin_error_too_weak" msgid="7883744811891784882">"Новы PIN-код занадта слабы. Моцны пароль не павінен змяшчаць знакаў, што ідуць па чарзе, або лічбы, якія паўтараюцца."</string>
+ <string name="vm_change_pin_error_mismatch" msgid="2754685537970757317">"Стары PIN-код не падыходзіць."</string>
+ <string name="vm_change_pin_error_invalid" msgid="3972205462701668653">"Новы PIN-код змяшчае несапраўдныя сімвалы."</string>
+ <string name="vm_change_pin_error_system_error" msgid="6610603326230000207">"Немагчыма змяніць PIN-код"</string>
+ <string name="vvm_unsupported_message_format" msgid="11795090778411977">"Гэты тып паведамлення не падтрымліваецца; каб праслухаць, патэлефануйце на <xliff:g id="NUMBER">%s</xliff:g>."</string>
+ <string name="mobile_networks" msgid="5540397602919106177">"Налады мабільнай сеткі"</string>
+ <string name="label_available" msgid="1181658289009300430">"Даступныя сеткі"</string>
+ <string name="load_networks_progress" msgid="5230707536168902952">"Пошук..."</string>
+ <string name="empty_networks_list" msgid="4249426905018815316">"Сеткі не знойдзены."</string>
+ <string name="search_networks" msgid="1601136049300882441">"Шукаць сеткі"</string>
+ <string name="network_query_error" msgid="6828516148953325006">"Памылка падчас пошуку сетак."</string>
+ <string name="register_on_network" msgid="9055203954040805084">"Рэгістрацыя ў сетцы <xliff:g id="NETWORK">%s</xliff:g>..."</string>
+ <string name="not_allowed" msgid="5613353860205691579">"Ваша SIM-карта не дазваляе падключацца да гэтай сеткі."</string>
+ <string name="connect_later" msgid="2308119155752343975">"Зараз немагчыма падключыцца да гэтай сеткі. Паўтарыце спробу пазней."</string>
+ <string name="registration_done" msgid="495135664535876612">"Зарэгістраваны ў сетцы."</string>
+ <string name="sum_carrier_select" msgid="3494252551249882718">"Выберыце аператара сеткі"</string>
+ <string name="sum_search_networks" msgid="2921092249873272715">"Пошук усіх даступных сетак"</string>
+ <string name="select_automatically" msgid="5628402124471810174">"Выбраць аўтаматычна"</string>
+ <string name="sum_select_automatically" msgid="5614890115123292400">"Аўтаматычна выбраць прыярытэтную сетку"</string>
+ <string name="register_automatically" msgid="6017849844573519637">"Аўтаматычная рэгістрацыя..."</string>
+ <string name="preferred_network_mode_title" msgid="2336624679902659306">"Прыярытэтны тып сеткі"</string>
+ <string name="preferred_network_mode_summary" msgid="1434820673166126609">"Змяніць рэжым работы сеткі"</string>
+ <string name="preferred_network_mode_dialogtitle" msgid="4048082093347807230">"Прыярытэтны тып сеткі"</string>
+ <string name="preferred_network_mode_wcdma_perf_summary" msgid="8521677230113533809">"Пераважны рэжым сеткі: пераважна WCDMA"</string>
+ <string name="preferred_network_mode_gsm_only_summary" msgid="3352445413437453511">"Пераважны рэжым сеткі: толькі GSM"</string>
+ <string name="preferred_network_mode_wcdma_only_summary" msgid="2836897236221063413">"Пераважны рэжым сеткі: толькі WCDMA"</string>
+ <string name="preferred_network_mode_gsm_wcdma_summary" msgid="3161255745326408587">"Пераважны рэжым сеткі: GSM/WCDMA"</string>
+ <string name="preferred_network_mode_cdma_summary" msgid="3175690187294334241">"Пераважны рэжым сеткі: CDMA"</string>
+ <string name="preferred_network_mode_cdma_evdo_summary" msgid="8332063064712726618">"Пераважны рэжым сеткі: CDMA/EvDo"</string>
+ <string name="preferred_network_mode_cdma_only_summary" msgid="1309770926198634150">"Пераважны рэжым сеткі: толькі CDMA"</string>
+ <string name="preferred_network_mode_evdo_only_summary" msgid="8472220691721269155">"Пераважны рэжым сеткі: толькі EvDo"</string>
+ <string name="preferred_network_mode_cdma_evdo_gsm_wcdma_summary" msgid="4726682079415227330">"Пераважная сетка: CDMA/EvDo/GSM/WCDMA"</string>
+ <string name="preferred_network_mode_lte_summary" msgid="574752287596469136">"Пераважная сетка: LTE"</string>
+ <string name="preferred_network_mode_lte_gsm_wcdma_summary" msgid="8455358514068283935">"Пераважная сетка: GSM/WCDMA/LTE"</string>
+ <string name="preferred_network_mode_lte_cdma_evdo_summary" msgid="228702246343742853">"Пераважная сетка: CDMA+LTE/EVDO"</string>
+ <string name="preferred_network_mode_global_summary" msgid="1633134285545730364">"Пераважная сетка: глабальная"</string>
+ <string name="preferred_network_mode_lte_wcdma_summary" msgid="9180775701594742750">"Пераважная сетка: LTE / WCDMA"</string>
+ <string name="preferred_network_mode_lte_gsm_umts_summary" msgid="633315028976225026">"Пажаданы рэжым сеткі: LTE / GSM / UMTS"</string>
+ <string name="preferred_network_mode_lte_cdma_summary" msgid="3722647806454528426">"Пераважны рэжым сеткі: LTE/CDMA"</string>
+ <string name="preferred_network_mode_tdscdma_summary" msgid="8021016193718678775">"Пажаданы рэжым сеткі: TDSCDMA"</string>
+ <string-array name="preferred_network_mode_choices">
+ <item msgid="7886739962255042385">"LTE / WCDMA"</item>
+ <item msgid="577652050447385699">"LTE"</item>
+ <item msgid="6813597571293773656">"Глабальныя"</item>
+ <item msgid="127064712132619032">"GSM/WCDMA/LTE"</item>
+ <item msgid="1126767511633425977">"CDMA + LTE/EvDo"</item>
+ <item msgid="6389676313771670660">"CDMA/EvDo/GSM/WCDMA"</item>
+ <item msgid="545430093607698090">"Толькі EVDO"</item>
+ <item msgid="1508557726283094448">"CDMA без EvDo"</item>
+ <item msgid="4341433122263841224">"Аўтаматычны выбар CDMA/EvDo"</item>
+ <item msgid="5958053792390386668">"Аўтаматычны выбар GSM/WCDMA"</item>
+ <item msgid="7913148405605373434">"Толькі WCDMA"</item>
+ <item msgid="1524224863879435516">"Толькі GSM"</item>
+ <item msgid="3817924849415716259">"Пажадана GSM/WCDMA"</item>
+ </string-array>
+ <string name="enhanced_4g_lte_mode_title" msgid="522191650223239171">"Удасканалены рэжым 4G LTE"</string>
+ <string name="enhanced_4g_lte_mode_title_variant" msgid="4871126028907265406">"Пашыраны выклік"</string>
+ <string name="enhanced_4g_lte_mode_summary" msgid="2332175070522125850">"Карыстайцеся службамі LTE, каб палепшыць галасавую і іншую сувязь (рэкаменд.)"</string>
+ <string name="data_enabled" msgid="5972538663568715366">"Дадзеныя ўключаныя"</string>
+ <string name="data_enable_summary" msgid="2382798156640007971">"Дазволіць выкарыстанне даных"</string>
+ <string name="dialog_alert_title" msgid="6751344986194435476">"Увага"</string>
+ <string name="roaming" msgid="8871412572928323707">"Перадача даных у роўмінгу"</string>
+ <string name="roaming_enable" msgid="7331106985174381987">"Падключацца да сэрвісаў перадачы даных у роўмінгу"</string>
+ <string name="roaming_disable" msgid="1843417228755568110">"Падключацца да сэрвісаў перадачы даных у роўмінгу"</string>
+ <string name="roaming_reenable_message" msgid="8913735676127858115">"Падлучэнне для перадачы дадзеных страчана, таму што вы выйшлі з зоны пакрыцця сваёй сеткі, а перадача дадзеных у роўмінгу адключана."</string>
+ <string name="roaming_warning" msgid="1603164667540144353">"Гэта можа прывесці да значных выдаткаў."</string>
+ <string name="roaming_alert_title" msgid="3654815360303826008">"Дазволіць перадачу даных у роўмінгу?"</string>
+ <string name="gsm_umts_options" msgid="6538311689850981686">"Параметры GSM/UMTS"</string>
+ <string name="cdma_options" msgid="4016822858172249884">"Параметры CDMA"</string>
+ <string name="throttle_data_usage" msgid="3715677828160555808">"Выкарыстанне трафіку"</string>
+ <string name="throttle_current_usage" msgid="8762280193043815361">"Выкарыстанне даных у бягучы перыяд"</string>
+ <string name="throttle_time_frame" msgid="1915198770363734685">"Перыяд выкарыстання дадзеных"</string>
+ <string name="throttle_rate" msgid="4710388992676803508">"Палітыка хуткасці перадачы дадзеных"</string>
+ <string name="throttle_help" msgid="243651091785169900">"Дадатковая iнфармацыя"</string>
+ <string name="throttle_status_subtext" msgid="1657318943142085170">"Выкарыстана <xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g>??) з максімуму перыяду <xliff:g id="USED_2">%3$s</xliff:g>\nНаступны перыяд пачнецца праз <xliff:g id="USED_3">%4$d</xliff:g> д. (<xliff:g id="USED_4">%5$s</xliff:g>)"</string>
+ <string name="throttle_data_usage_subtext" msgid="6029276011123694701">"Выкарыстана <xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g>??) з максімуму перыяду (<xliff:g id="USED_2">%3$s</xliff:g>)"</string>
+ <string name="throttle_data_rate_reduced_subtext" msgid="7492763592720107737">"Максімум <xliff:g id="USED_0">%1$s</xliff:g> перавышаны\nХуткасць перадачы дадзеных зніжана да <xliff:g id="USED_1">%2$d</xliff:g> Кб/с"</string>
+ <string name="throttle_time_frame_subtext" msgid="7732763021560399960">"<xliff:g id="USED_0">%1$d</xliff:g>?? цыклу прайшло\nНаступны перыяд пачнецца праз <xliff:g id="USED_1">%2$d</xliff:g> д. (<xliff:g id="USED_2">%3$s</xliff:g>)"</string>
+ <string name="throttle_rate_subtext" msgid="2149102656120726855">"Хуткасць перадачы дадзеных зніжаецца да <xliff:g id="USED">%1$d</xliff:g> Кб/с, калі абмежаванне выкарыстання дадзеных перавышанае"</string>
+ <string name="throttle_help_subtext" msgid="5217706521499010816">"Больш падрабязная інфармацыя аб палітыцы выкарыстання дадзеных у сетцы вашага мабільнага аператара"</string>
+ <string name="cell_broadcast_sms" msgid="5584192824053625842">"Перадача SMS на сотавыя"</string>
+ <string name="enable_disable_cell_bc_sms" msgid="4851147873691392255">"Перадача SMS на сотавыя"</string>
+ <string name="cell_bc_sms_enable" msgid="6441688565738921084">"Перадача SMS на сотавыя ўключана"</string>
+ <string name="cell_bc_sms_disable" msgid="3398365088309408749">"Перадача SMS на сотавыя адключаная"</string>
+ <string name="cb_sms_settings" msgid="651715019785107312">"Налады перадачы SMS на сотавыя"</string>
+ <string name="enable_disable_emergency_broadcast" msgid="2157014609041245335">"Экстраная перадача"</string>
+ <string name="emergency_broadcast_enable" msgid="2645980025414010211">"Уключаная экстраная перадача"</string>
+ <string name="emergency_broadcast_disable" msgid="3665199821267569426">"Экстраная перадача адключаная"</string>
+ <string name="enable_disable_administrative" msgid="6501582322182059412">"Адміністрацыйны"</string>
+ <string name="administrative_enable" msgid="1750086122962032235">"Адміністрацыйныя функцыi ўключаныя"</string>
+ <string name="administrative_disable" msgid="8433273857248698539">"Адміністрацыйныя функцыi адключаны"</string>
+ <string name="enable_disable_maintenance" msgid="1819693083025106678">"Абслугоўванне"</string>
+ <string name="maintenance_enable" msgid="8566636458770971189">"Тэхнічнае абслугоўванне ўключана"</string>
+ <string name="maintenance_disable" msgid="7340189100885066077">"Абслугоўванне адключана"</string>
+ <string name="general_news_settings" msgid="4968779723948432978">"Агульныя навіны"</string>
+ <string name="bf_news_settings" msgid="3935593091894685267">"Навіны бізнэсу і фінансаў"</string>
+ <string name="sports_news_settings" msgid="7649399631270052835">"Навіны спорту"</string>
+ <string name="entertainment_news_settings" msgid="5051153952959405035">"Забаўляльныя навіны"</string>
+ <string name="enable_disable_local" msgid="7890281063123416120">"Мясцовы"</string>
+ <string name="local_enable" msgid="6370463247609136359">"Мясцовыя навіны ўключаны"</string>
+ <string name="local_disable" msgid="4405691986943795798">"Мясцовыя навіны адключаны"</string>
+ <string name="enable_disable_regional" msgid="4905652414535565872">"Рэгіянальныя"</string>
+ <string name="regional_enable" msgid="4434680415437834759">"Рэгіянальныя навіны ўключаны"</string>
+ <string name="regional_disable" msgid="5359325527213850077">"Рэгіянальныя навіны адключаны"</string>
+ <string name="enable_disable_national" msgid="236278090206880734">"Нацыянальны"</string>
+ <string name="national_enable" msgid="1172443648912246952">"Нацыянальныя навіны ўключаныя"</string>
+ <string name="national_disable" msgid="326018148178601166">"Нацыянальныя навіны адключаныя"</string>
+ <string name="enable_disable_international" msgid="7535348799604565592">"Міжнародны"</string>
+ <string name="international_enable" msgid="5855356769925044927">"Уключаны міжнародныя навіны"</string>
+ <string name="international_disable" msgid="2850648591041088931">"Міжнародныя навіны адключаныя"</string>
+ <string name="list_language_title" msgid="2841683501919760043">"Мова"</string>
+ <string name="list_language_summary" msgid="8109546531071241601">"Выберыце мову навін"</string>
+ <string-array name="list_language_entries">
+ <item msgid="6137851079727305485">"Англійская"</item>
+ <item msgid="1151988412809572526">"Французская"</item>
+ <item msgid="577840534704312665">"Іспанская"</item>
+ <item msgid="8385712091143148180">"Японская"</item>
+ <item msgid="1858401628368130638">"Карэйская"</item>
+ <item msgid="1933212028684529632">"Кітайская"</item>
+ <item msgid="1908428006803639064">"Іўрыт"</item>
+ </string-array>
+ <string-array name="list_language_values">
+ <item msgid="1804908636436467150">"1"</item>
+ <item msgid="289708030346890334">"2"</item>
+ <item msgid="1121469729692402684">"3"</item>
+ <item msgid="2614093115912897722">"4"</item>
+ <item msgid="2411164639857960614">"5"</item>
+ <item msgid="5884448729274543324">"6"</item>
+ <item msgid="5511864807618312598">"7"</item>
+ </string-array>
+ <string name="list_language_dtitle" msgid="5442908726538951934">"Мовы"</string>
+ <string name="enable_disable_local_weather" msgid="986967454867219114">"Мясцовае надвор\'е"</string>
+ <string name="local_weather_enable" msgid="6199315114382448922">"Мясцовае надвор\'е ўключана"</string>
+ <string name="local_weather_disable" msgid="2510158089142626480">"Мясцовае надвор\'е адключана"</string>
+ <string name="enable_disable_atr" msgid="8339572391278872343">"Мясцовыя транспартныя паведамленні"</string>
+ <string name="atr_enable" msgid="5541757457789181799">"Мясцовыя транспартныя паведамленні ўключаны"</string>
+ <string name="atr_disable" msgid="7085558154727596455">"Мясцовыя транспартныя паведамленні адключаны"</string>
+ <string name="enable_disable_lafs" msgid="668189073721277199">"Расклады палётаў мясцовага аэрапорту"</string>
+ <string name="lafs_enable" msgid="2791978667205137052">"Уключаныя расклады палётаў мясцовага аэрапорта"</string>
+ <string name="lafs_disable" msgid="2391212397725495350">"Расклады палётаў мясцовага аэрапорта адключаныя"</string>
+ <string name="enable_disable_restaurants" msgid="6240381945336814024">"Рэстараны"</string>
+ <string name="restaurants_enable" msgid="5137657479469118847">"Рэстараны ўключаны"</string>
+ <string name="restaurants_disable" msgid="3678480270938424092">"Рэстараны адключаныя"</string>
+ <string name="enable_disable_lodgings" msgid="1822029172658551202">"Жыллё"</string>
+ <string name="lodgings_enable" msgid="3230042508992850322">"Жыллё ўключана"</string>
+ <string name="lodgings_disable" msgid="3387879742320682391">"Жыллё адключана"</string>
+ <string name="enable_disable_retail_directory" msgid="1357809784475660303">"Рознічны каталог"</string>
+ <string name="retail_directory_enable" msgid="3280626290436111496">"Рознічны каталог ўключаны"</string>
+ <string name="retail_directory_disable" msgid="6479739816662879027">"Рознічны каталог адключаны"</string>
+ <string name="enable_disable_advertisements" msgid="5999495926176182128">"Рэклама"</string>
+ <string name="advertisements_enable" msgid="2050305021264683786">"Рэклама ўключаная"</string>
+ <string name="advertisements_disable" msgid="8350985908788707935">"Рэклама адключана"</string>
+ <string name="enable_disable_stock_quotes" msgid="6397810445293533603">"Катыроўкі акцый"</string>
+ <string name="stock_quotes_enable" msgid="4384802470887170543">"Кацiроўкі акцый уключаны"</string>
+ <string name="stock_quotes_disable" msgid="4781450084565594998">"Кацiроўкі акцый выключаны"</string>
+ <string name="enable_disable_eo" msgid="4863043263443942494">"Магчымасці працаўладкавання"</string>
+ <string name="eo_enable" msgid="8623559062015685813">"Магчымасці працаўладкавання ўключаны"</string>
+ <string name="eo_disable" msgid="3863812478090907609">"Магчымасці працаўладкавання адключаныя"</string>
+ <string name="enable_disable_mhh" msgid="908214593528968522">"Медыцына, здароўе і бальніцы"</string>
+ <string name="mhh_enable" msgid="5544500632306446815">"Уключаны раздзел \"Медыцына, здароўе і бальніцы\""</string>
+ <string name="mhh_disable" msgid="8998210550117117437">"Адключаны раздзел \"Медыцына, здароўе і бальніцы\""</string>
+ <string name="enable_disable_technology_news" msgid="3517184627114999149">"Навіны тэхналогій"</string>
+ <string name="technology_news_enable" msgid="7995209394210455181">"Навіны тэхналогій уключаны"</string>
+ <string name="technology_news_disable" msgid="5483490380561851946">"Навіны тэхналогій адключаны"</string>
+ <string name="enable_disable_multi_category" msgid="626771003122899280">"Мульці-катэгорыя"</string>
+ <string name="multi_category_enable" msgid="1179299804641721768">"Мульці-катэгорыя ўключана"</string>
+ <string name="multi_category_disable" msgid="880104702904139505">"Мульці-катэгорыя адключаная"</string>
+ <string name="network_lte" msgid="7702681952521375754">"LTE (рэкамендуецца)"</string>
+ <string name="network_4G" msgid="2723512640529983138">"4G (рэкамендуецца)"</string>
+ <string name="network_global" msgid="1323190488685355309">"Глабальныя"</string>
+ <string name="cdma_system_select_title" msgid="5757657769327732833">"Выбар сістэмы"</string>
+ <string name="cdma_system_select_summary" msgid="60460043745797517">"Змяніць рэжым роўмінгу CDMA"</string>
+ <string name="cdma_system_select_dialogtitle" msgid="6083355415165359075">"Выбар сістэмы"</string>
+ <string-array name="cdma_system_select_choices">
+ <item msgid="176474317493999285">"Толькі галоўная"</item>
+ <item msgid="1205664026446156265">"Аўтаматычна"</item>
+ </string-array>
+ <string name="cdma_subscription_title" msgid="1162564010076763284">"Падпіска CDMA"</string>
+ <string name="cdma_subscription_summary" msgid="2530890766115781140">"Пераключацца паміж RUIM/SIM і NV"</string>
+ <string name="cdma_subscription_dialogtitle" msgid="2699527950523333110">"падпіска"</string>
+ <string-array name="cdma_subscription_choices">
+ <item msgid="2258014151300708431">"RUIM/SIM"</item>
+ <item msgid="5127722015571873880">"NV"</item>
+ </string-array>
+ <string-array name="cdma_subscription_values">
+ <item msgid="7494167883478914080">"0"</item>
+ <item msgid="6043847456049107742">"1"</item>
+ </string-array>
+ <string name="cdma_activate_device" msgid="3793805892364814518">"Актывацыя прылады"</string>
+ <string name="cdma_lte_data_service" msgid="4255018217292548962">"Налады службы перад. дадзеных"</string>
+ <string name="carrier_settings_title" msgid="9028166176523012300">"Налады аператара"</string>
+ <string name="fdn" msgid="7878832555095183202">"Фіксаваныя нумары"</string>
+ <string name="fdn_with_label" msgid="187084204115493366">"Нумары закрытай абаненцкай групы (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="manage_fdn_list" msgid="8777755791892122369">"Спіс FDN"</string>
+ <string name="fdn_list_with_label" msgid="7437232552210469217">"Спіс закрытай абаненцкай групы (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="fdn_activation" msgid="2156479741307463576">"Актывацыя FDN"</string>
+ <string name="fdn_enabled" msgid="5238109009915521240">"Фіксаваныя нумары ўключаны"</string>
+ <string name="fdn_disabled" msgid="4700049736675368279">"Фіксаваныя нумары адключаны"</string>
+ <string name="enable_fdn" msgid="3740191529180493851">"Уключыць FDN"</string>
+ <string name="disable_fdn" msgid="7944020890722540616">"Адключыць FDN"</string>
+ <string name="change_pin2" msgid="2153563695382176676">"Змяніць PIN2"</string>
+ <string name="enable_fdn_ok" msgid="7215588870329688132">"Адключыць FDN"</string>
+ <string name="disable_fdn_ok" msgid="5727046928930740173">"Уключыць FDN"</string>
+ <string name="sum_fdn" msgid="1959399454900272878">"Кіраванне зафіксаванымі нумарамі"</string>
+ <string name="sum_fdn_change_pin" msgid="6666549734792827932">"Змяніць PIN-код для доступу FDN"</string>
+ <string name="sum_fdn_manage_list" msgid="8431088265332628316">"Кіраванне спісам тэлефонных нумароў"</string>
+ <string name="voice_privacy" msgid="3776841382844614716">"Палiтыка прыватнасцi Voice"</string>
+ <string name="voice_privacy_summary" msgid="3159383389833516214">"Уключыць пашыраны рэжым прыватнасці"</string>
+ <string name="tty_mode_option_title" msgid="9033098925144434669">"Рэжым TTY"</string>
+ <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="menu_add" msgid="1882023737425114762">"Дадаць кантакт"</string>
+ <string name="menu_edit" msgid="7143003705504672374">"Рэдагаваць кантакт"</string>
+ <string name="menu_delete" msgid="3977150783449642851">"Выдаліць кантакт"</string>
+ <string name="menu_dial" msgid="3223106222819685808">"Набраць нумар кантакту"</string>
+ <string name="get_pin2" msgid="8204677063922225311">"Увядзіце код PIN2"</string>
+ <string name="name" msgid="7329028332786872378">"Імя"</string>
+ <string name="number" msgid="7905950798349903858">"Нумар"</string>
+ <string name="save" msgid="4094274636321939086">"Захаваць"</string>
+ <string name="add_fdn_contact" msgid="2481915899633353976">"Дадаць дазволены нумар"</string>
+ <string name="adding_fdn_contact" msgid="7627379633721940991">"Даданне дазволенага нумару..."</string>
+ <string name="fdn_contact_added" msgid="7458335758501736665">"Даданы дазволены нумар."</string>
+ <string name="edit_fdn_contact" msgid="7976936035587081480">"Змяніць дазволены нумар"</string>
+ <string name="updating_fdn_contact" msgid="8370929876849803600">"Абнаўленне дазволенага нумару..."</string>
+ <string name="fdn_contact_updated" msgid="5497828782609005017">"Дазволеныя нумары абноўленыя."</string>
+ <string name="delete_fdn_contact" msgid="6668958073074151717">"Выдаліць дазволены нумар"</string>
+ <string name="deleting_fdn_contact" msgid="5669163206349319969">"Выдаленне дазволенага нумару..."</string>
+ <string name="fdn_contact_deleted" msgid="7154162327112259569">"Дазволены нумар выдалены."</string>
+ <string name="pin2_invalid" msgid="5470854099230755944">"FDN не быў абноўлены, таму што вы набралі няправільны PIN-код."</string>
+ <string name="fdn_invalid_number" msgid="8602417141715473998">"FDN не быў абноўлены, таму што нумар пусты або перавышае 20 знакаў."</string>
+ <string name="pin2_or_fdn_invalid" msgid="6025144083384701197">"Cпiс дазволеных нумароў не адноўлены. PIN2 ўведзены няправiльна, або нумар быў адхiлены."</string>
+ <string name="fdn_failed" msgid="540018079008319747">"Аперацыя ў закрытай абаненцкай групе не ўдалася."</string>
+ <string name="simContacts_emptyLoading" msgid="2203331234764498011">"Чытанне з SIM-карты..."</string>
+ <string name="simContacts_empty" msgid="5270660846489561932">"На вашай SIM-карце няма кантактаў."</string>
+ <string name="simContacts_title" msgid="1861472842524839921">"Выберыце кантакты для імпарту"</string>
+ <string name="simContacts_airplaneMode" msgid="5254946758982621072">"Адключыце рэжым палёту, каб імпартаваць кантакты з SIM-карты."</string>
+ <string name="enable_pin" msgid="5422767284133234860">"Уключэнне/адключэнне PIN-коду SIM-карты"</string>
+ <string name="change_pin" msgid="9174186126330785343">"Змена PIN-коду SIM-карты"</string>
+ <string name="enter_pin_text" msgid="8532615714751931951">"PIN-код SIM-карты:"</string>
+ <string name="oldPinLabel" msgid="5287773661246368314">"Стары PIN"</string>
+ <string name="newPinLabel" msgid="207488227285336897">"Новы PIN"</string>
+ <string name="confirmPinLabel" msgid="257597715098070206">"Пацвердзіць новы PIN"</string>
+ <string name="badPin" msgid="8955102849303984935">"Стары PIN-код, які вы ўвялі, няправільны. Паспрабуйце яшчэ раз."</string>
+ <string name="mismatchPin" msgid="5923253370683071889">"PIN-коды, якія вы ўвялі, не супадаюць. Паспрабуйце яшчэ раз."</string>
+ <string name="invalidPin" msgid="5981171102258684792">"Увядзіце PIN-код, які змяшчае ад 4 да 8 лічбаў."</string>
+ <string name="disable_sim_pin" msgid="3419351358300716472">"Выдаліць PIN-код SIM-карты"</string>
+ <string name="enable_sim_pin" msgid="4845145659651484248">"Задаць PIN-код SIM-карты"</string>
+ <string name="enable_in_progress" msgid="3417917024688497010">"Задаецца PIN-код…"</string>
+ <string name="enable_pin_ok" msgid="2918545971413270063">"PIN-код зададзены"</string>
+ <string name="disable_pin_ok" msgid="2109571368635883688">"PIN-код выдалены"</string>
+ <string name="pin_failed" msgid="5644377896213584760">"PIN-код няправільны"</string>
+ <string name="pin_changed" msgid="4455736268023261662">"PIN-код абноўлены"</string>
+ <string name="puk_requested" msgid="5921393215789090200">"Пароль няправільны. Зараз PIN-код заблакіраваны. Запытаны PUK-код."</string>
+ <string name="enter_pin2_text" msgid="8339444124477720345">"PIN2"</string>
+ <string name="oldPin2Label" msgid="8559146795026261502">"Стары PIN2"</string>
+ <string name="newPin2Label" msgid="4573956902204349054">"Новы PIN2"</string>
+ <string name="confirmPin2Label" msgid="8100319484454787708">"Пацвердзіць новы PIN2"</string>
+ <string name="badPuk2" msgid="7910064009531541708">"PUK2 няправільны. Паўтарыце спробу."</string>
+ <string name="badPin2" msgid="6646896629970023109">"Стары код PIN2 няправільны. Паўтарыце спробу."</string>
+ <string name="mismatchPin2" msgid="4177967478551851117">"Коды PIN2 не супадаюць. Паўтарыце спробу."</string>
+ <string name="invalidPin2" msgid="1757045131429105595">"Увядзіце код PIN2 даўжынёй ад 4 да 8 лічбаў."</string>
+ <string name="invalidPuk2" msgid="7059081153334815973">"Увядзіце код PUK2 даўжынёй 8 лічбаў."</string>
+ <string name="pin2_changed" msgid="3724522579945610956">"Код PIN2 абноўлены"</string>
+ <string name="label_puk2_code" msgid="4688069961795341948">"Увядзіце код PUK2"</string>
+ <string name="fdn_enable_puk2_requested" msgid="4991074891459554705">"Пароль няправільны. Зараз код PIN2 заблакіраваны. Каб паўтарыць спробу, змяніце код PIN 2."</string>
+ <string name="puk2_requested" msgid="5831015200030161434">"Пароль няправільны. Зараз SIM-карта заблакіравана. Увядзіце код PUK2."</string>
+ <string name="puk2_blocked" msgid="3150263853077280049">"Код PUK2 заблакіраваны назаўжды."</string>
+ <string name="pin2_attempts" msgid="720736232885011507">\n"У вас засталося спроб: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+ <string name="pin2_unblocked" msgid="7791600368153469078">"Код PIN2 больш не заблакіраваны"</string>
+ <string name="pin2_error_exception" msgid="1088689322248996699">"Памылка сеткі або SIM-карты"</string>
+ <string name="doneButton" msgid="2859593360997984240">"Гатова"</string>
+ <string name="voicemail_settings_number_label" msgid="8524164258691887790">"Нумар галасавой пошты"</string>
+ <string name="card_title_dialing" msgid="5769417478498348054">"Набор"</string>
+ <string name="card_title_redialing" msgid="8253487008234167266">"Паўторны набор"</string>
+ <string name="card_title_conf_call" msgid="1162980346189744501">"Канферэнц-выклік"</string>
+ <string name="card_title_incoming_call" msgid="7364539451234646909">"Уваходны выклік"</string>
+ <string name="card_title_call_ended" msgid="5544730338889702298">"Выклік скончаны"</string>
+ <string name="card_title_on_hold" msgid="821463117892339942">"У чаканні"</string>
+ <string name="card_title_hanging_up" msgid="3999101620995182450">"Завяршэнне"</string>
+ <string name="card_title_in_call" msgid="6346543933068225205">"У выкліку"</string>
+ <string name="notification_voicemail_title" msgid="8933468752045550523">"Новая галасавая пошта"</string>
+ <string name="notification_voicemail_title_count" msgid="4366360747660929916">"Новыя паведамленнi галасавой пошты (<xliff:g id="COUNT">%d</xliff:g>)"</string>
+ <string name="notification_voicemail_text_format" msgid="4447323569453981685">"Набраць <xliff:g id="VOICEMAIL_NUMBER">%s</xliff:g>"</string>
+ <string name="notification_voicemail_no_vm_number" msgid="760963466895609716">"Невядомы нумар галасавой пошты"</string>
+ <string name="notification_network_selection_title" msgid="4224455487793492772">"Не абслугоўваецца"</string>
+ <string name="notification_network_selection_text" msgid="2607085729661923269">"Выбраная сетка (<xliff:g id="OPERATOR_NAME">%s</xliff:g>) недаступная"</string>
+ <string name="incall_error_power_off" product="watch" msgid="772302793483607711">"Каб зрабіць выклік, адключыце рэжым палёту ці рэжым эканоміі зараду."</string>
+ <string name="incall_error_power_off" product="default" msgid="2947938060513306698">"Адключыце рэжым палёту, каб зрабіць выклік."</string>
+ <string name="incall_error_power_off_wfc" msgid="8711428920632416575">"Адключыце рэжым палёту або падлучыцеся да бесправадной сеткі, каб зрабіць выклік."</string>
+ <string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Выйдзіце з рэжыму экстранных зваротных выклікаў, каб зрабіць няэкстранны выклік."</string>
+ <string name="incall_error_emergency_only" msgid="4678640422710818317">"Не зарэгістраваны ў сетцы."</string>
+ <string name="incall_error_out_of_service" msgid="8587993036435080418">"Мабільная сетка недаступная."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
+ <string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Каб зрабіць выклік, увядзіце сапраўдны нумар."</string>
+ <string name="incall_error_call_failed" msgid="5891978320269774095">"Збой выклiку."</string>
+ <string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Зараз немагчыма дадаць выклік."</string>
+ <string name="incall_error_supp_service_unknown" msgid="655570339115407698">"Служба не падтрымліваецца"</string>
+ <string name="incall_error_supp_service_switch" msgid="5237002176899962862">"Немагчыма пераключыць выклікі."</string>
+ <string name="incall_error_supp_service_separate" msgid="7224393405134545246">"Немагчыма аддзяліць выклік."</string>
+ <string name="incall_error_supp_service_transfer" msgid="7235952238189391438">"Немагчыма перадаць выклік."</string>
+ <string name="incall_error_supp_service_conference" msgid="2505727299596357312">"Канферэнц-выклікі немагчымы."</string>
+ <string name="incall_error_supp_service_reject" msgid="8998568661508655638">"Немагчыма адхіліць выклік."</string>
+ <string name="incall_error_supp_service_hangup" msgid="7434513517153834426">"Немагчыма скончыць выклік(і)."</string>
+ <string name="incall_error_supp_service_hold" msgid="7967020511232222078">"Немагчыма ўтрымліваць выклікі."</string>
+ <string name="incall_error_wfc_only_no_wireless_network" msgid="1782466780452640089">"Падлучыцеся да бесправадной сеткі, каб зрабіць выклік."</string>
+ <string name="incall_error_promote_wfc" msgid="106510757624022064">"Дазволіць выклік па Wi-Fi-тэлефаніі."</string>
+ <string name="emergency_enable_radio_dialog_title" msgid="4627849966634578257">"Экстраны выклік"</string>
+ <string name="emergency_enable_radio_dialog_message" msgid="207613549344420291">"Уключэнне радыё..."</string>
+ <string name="emergency_enable_radio_dialog_retry" msgid="5960061579996526883">"Не абслугоўваецца. Паўтор спробы..."</string>
+ <string name="radio_off_during_emergency_call" msgid="2535800034010306830">"Немагчыма ўвайсцi ў рэжым палёту падчас экстранага выклiку"</string>
+ <string name="dial_emergency_error" msgid="1509085166367420355">"Выклік немагчымы. <xliff:g id="NON_EMERGENCY_NUMBER">%s</xliff:g> не з\'яўляецца нумарам экстраннай службы."</string>
+ <string name="dial_emergency_empty_error" msgid="9130194953830414638">"Выклік немагчымы. Набраць нумар экстраннай службы."</string>
+ <string name="dialerKeyboardHintText" msgid="9192914825413747792">"Выкарыстоўвайце клавіятуру, каб набраць нумар"</string>
+ <string name="onscreenHoldText" msgid="2285258239691145872">"Утрымліваць"</string>
+ <string name="onscreenEndCallText" msgid="4403855834875398585">"Скончыць"</string>
+ <string name="onscreenShowDialpadText" msgid="8561805492659639893">"Кнопкі набору"</string>
+ <string name="onscreenMuteText" msgid="5011369181754261374">"Выключыць гук"</string>
+ <string name="onscreenAddCallText" msgid="5140385634712287403">"Дадаць выклік"</string>
+ <string name="onscreenMergeCallsText" msgid="6640195098064538950">"Аб\'яднаць выклікі"</string>
+ <string name="onscreenSwapCallsText" msgid="1602990689244030047">"Пераключыць"</string>
+ <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="importSimEntry" msgid="6614358325359736031">"Імпартаваць"</string>
+ <string name="importAllSimEntries" msgid="1503181169636198673">"Імпартаваць усе"</string>
+ <string name="importingSimContacts" msgid="7374056215462575769">"Імпартаванне кантактаў з SIM-карты"</string>
+ <string name="importToFDNfromContacts" msgid="2130620207013368580">"Імпартаваць з кантактаў"</string>
+ <string name="singleContactImportedMsg" msgid="6868483416182599206">"Імпартаваны кантакт"</string>
+ <string name="failedToImportSingleContactMsg" msgid="415399285420353917">"Не ўдалося імпартаваць кантакт"</string>
+ <string name="hac_mode_title" msgid="8740268574688743289">"Слыхавы апарат"</string>
+ <string name="hac_mode_summary" msgid="6833851160514929341">"Уключыць функцыю сумяшчальнасці са слыхавым апаратам"</string>
+ <string-array name="tty_mode_entries">
+ <item msgid="512950011423868021">"TTY адключаны"</item>
+ <item msgid="3971695875449640648">"TTY поўны"</item>
+ <item msgid="1937509904407445684">"TTY HCO"</item>
+ <item msgid="5644925873488772224">"TTY VCO"</item>
+ </string-array>
+ <string name="dtmf_tones_title" msgid="5163153771291340803">"Сігналы DTMF"</string>
+ <string name="dtmf_tones_summary" msgid="3351820372864020331">"Задаць даўжыню тонаў DTMF"</string>
+ <string-array name="dtmf_tone_entries">
+ <item msgid="899650777817315681">"Звычайны"</item>
+ <item msgid="2883365539347850535">"Доўгі"</item>
+ </string-array>
+ <string name="network_info_message" msgid="7738596060242881930">"Паведамленне сеткі"</string>
+ <string name="network_error_message" msgid="3394780436230411413">"Паведамленне аб памылцы"</string>
+ <string name="ota_title_activate" msgid="8616918561356194398">"Актываваць тэлефон"</string>
+ <string name="ota_touch_activate" msgid="6553212803262586244">"Каб актываваць абслугоўванне вашага тэлефона, трэба выканаць спецыяльны выклік. \n\nНацісніце \"Актываваць\" і слухайце інструкцыі, неабходныя для актывацыі тэлефона."</string>
+ <string name="ota_hfa_activation_title" msgid="2234246934160473981">"Актывацыя..."</string>
+ <string name="ota_hfa_activation_dialog_message" msgid="8092479227918463415">"На тэлефоне ідзе актывацыя службы мабільнай перадачы даных.\n\nГэта можа заняць да 5 хвілін."</string>
+ <string name="ota_skip_activation_dialog_title" msgid="2943366608272261306">"Прапусціць актывацыю?"</string>
+ <string name="ota_skip_activation_dialog_message" msgid="2440770373498870550">"Калі прапусціць актывацыю, вы не зможаце здзяйсняць званкі або падлучэнні да мабільных сетак перадачы дадзеных (хаця вы зможаце падлучыцца да Wi-Fi). Кожны раз пры ўключэнні тэлефона вам будзе прапанавана актываваць яго."</string>
+ <string name="ota_skip_activation_dialog_skip_label" msgid="3458532775091563208">"Прапусціць"</string>
+ <string name="ota_activate" msgid="1368528132525626264">"Актываваць"</string>
+ <string name="ota_title_activate_success" msgid="6570240212263372046">"Тэлефон актываваны."</string>
+ <string name="ota_title_problem_with_activation" msgid="7095824491970084367">"Праблема з актывацыяй"</string>
+ <string name="ota_listen" msgid="162923839877584937">"Выконвайце гукавыя інструкцыі, пакуль не пачуеце, што актывацыя завершаная."</string>
+ <string name="ota_speaker" msgid="6904589278542719647">"Дынамік"</string>
+ <string name="ota_progress" msgid="460876637828044519">"Ідзе праграмаванне вашага тэлефона..."</string>
+ <string name="ota_failure" msgid="7713756181204620397">"Не ўдалося запраграмаваць тэлефон"</string>
+ <string name="ota_successful" msgid="1880780692887077407">"Цяпер тэлефон актываваны. Запуск службы можа заняць да 15 хвілін."</string>
+ <string name="ota_unsuccessful" msgid="8072141612635635357">"Ваш тэлефон не актываваны. \nМагчыма, вам спатрэбіцца знайсці вобласць з лепшым пакрыццём (каля акна ці на вуліцы). \n\nПаўтарыце спробу ці звярнiцеся ў цэнтр абслугоўвання кліентаў, каб атрымаць дадатковую інфармацыю."</string>
+ <string name="ota_spc_failure" msgid="3909983542575030796">"ПАМЫЛКІ ПЕРАВЫШЭННЯ SPC"</string>
+ <string name="ota_call_end" msgid="4537279738134612388">"Назад"</string>
+ <string name="ota_try_again" msgid="7685477206465902290">"Паспрабаваць яшчэ раз"</string>
+ <string name="ota_next" msgid="3904945374358235910">"Далей"</string>
+ <string name="ecm_exit_dialog" msgid="4448531867763097533">"EcmExitDialog"</string>
+ <string name="phone_entered_ecm_text" msgid="6266424252578731203">"У рэжыме аварыйнага зваротнага выкліку"</string>
+ <string name="phone_in_ecm_notification_title" msgid="3226896828951687085">"Рэжым аварыйнага зваротнага выкліку"</string>
+ <string name="phone_in_ecm_call_notification_text" msgid="4611608947314729773">"Падлучэнне для перадачы дадзеных адключана"</string>
+ <plurals name="phone_in_ecm_notification_time" formatted="false" msgid="8308381858502470919">
+ <item quantity="one">Злучэння для перадачы даных няма на працягу <xliff:g id="COUNT_1">%s</xliff:g> хвіліны</item>
+ <item quantity="few">Злучэння для перадачы даных няма на працягу <xliff:g id="COUNT_1">%s</xliff:g> хвілін</item>
+ <item quantity="many">Злучэння для перадачы даных няма на працягу <xliff:g id="COUNT_1">%s</xliff:g> хвілін</item>
+ <item quantity="other">Злучэння для перадачы даных няма на працягу <xliff:g id="COUNT_1">%s</xliff:g> хвіліны</item>
+ </plurals>
+ <plurals name="alert_dialog_exit_ecm" formatted="false" msgid="7179911675595441201">
+ <item quantity="one">Тэлефон пяройдзе ў рэжым экстраннага зваротнага выкліку на <xliff:g id="COUNT_1">%s</xliff:g> хвіліну. У гэтым рэжыме немагчыма карыстацца праграмамі, якія выкарыстоўваюць злучэнне для перадачы даных. Жадаеце выйсці зараз?</item>
+ <item quantity="few">Тэлефон пяройдзе ў рэжым экстраннага зваротнага выкліку на <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. У гэтым рэжыме немагчыма карыстацца праграмамі, якія выкарыстоўваюць злучэнне для перадачы даных. Жадаеце выйсці зараз?</item>
+ <item quantity="many">Тэлефон пяройдзе ў рэжым экстраннага зваротнага выкліку на <xliff:g id="COUNT_1">%s</xliff:g> хвілін. У гэтым рэжыме немагчыма карыстацца праграмамі, якія выкарыстоўваюць злучэнне для перадачы даных. Жадаеце выйсці зараз?</item>
+ <item quantity="other">Тэлефон пяройдзе ў рэжым экстраннага зваротнага выкліку на <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. У гэтым рэжыме немагчыма карыстацца праграмамі, якія выкарыстоўваюць злучэнне для перадачы даных. Жадаеце выйсці зараз?</item>
+ </plurals>
+ <plurals name="alert_dialog_not_avaialble_in_ecm" formatted="false" msgid="8042973425225093895">
+ <item quantity="one">Выбранае дзеянне недаступнае ў рэжыме экстраннага зваротнага выкліку. Тэлефон застанецца ў гэтым рэжыме на <xliff:g id="COUNT_1">%s</xliff:g> хвіліну. Жадаеце выйсці зараз?</item>
+ <item quantity="few">Выбранае дзеянне недаступнае ў рэжыме экстраннага зваротнага выкліку. Тэлефон застанецца ў гэтым рэжыме на <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. Жадаеце выйсці зараз?</item>
+ <item quantity="many">Выбранае дзеянне недаступнае ў рэжыме экстраннага зваротнага выкліку. Тэлефон застанецца ў гэтым рэжыме на <xliff:g id="COUNT_1">%s</xliff:g> хвілін. Жадаеце выйсці зараз?</item>
+ <item quantity="other">Выбранае дзеянне недаступнае ў рэжыме экстраннага зваротнага выкліку. Тэлефон застанецца ў гэтым рэжыме на <xliff:g id="COUNT_1">%s</xliff:g> хвіліны. Жадаеце выйсці зараз?</item>
+ </plurals>
+ <string name="alert_dialog_in_ecm_call" msgid="1886723687211887104">"Выбранае дзеянне недаступнае падчас экстранага выкліку."</string>
+ <string name="progress_dialog_exiting_ecm" msgid="4835734101617817074">"Выхад з рэжыму экстранага выкліку"</string>
+ <string name="alert_dialog_yes" msgid="6674268047820703974">"Так"</string>
+ <string name="alert_dialog_no" msgid="1476091437797628703">"Не"</string>
+ <string name="alert_dialog_dismiss" msgid="2491494287075907171">"Скасаваць"</string>
+ <string name="voicemail_provider" msgid="5135942703327136909">"Сэрвіс"</string>
+ <string name="voicemail_settings" msgid="72448049107749316">"Наладка"</string>
+ <string name="voicemail_number_not_set" msgid="6724904736891087856">"<Не заданы>"</string>
+ <string name="other_settings" msgid="3672912580359716394">"Іншыя налады выкліку"</string>
+ <string name="calling_via_template" msgid="4839419581866928142">"Званкі праз правайдара <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
+ <string name="contactPhoto" msgid="4713193418046639466">"фатаграфія кантакта"</string>
+ <string name="goPrivate" msgid="865837794424530980">"перайсці да прыватнай гаворкі"</string>
+ <string name="selectContact" msgid="781975788478987237">"выбраць кантакт"</string>
+ <string name="not_voice_capable" msgid="2739898841461577811">"Галасавы выклік не падтрымліваецца"</string>
+ <string name="description_dial_button" msgid="7459705245418435351">"набор"</string>
+ <string name="voicemail_notification_vibrate_when_title" msgid="8361970092063604886">"Вібрацыя"</string>
+ <string name="voicemail_notification_vibarte_when_dialog_title" msgid="5739583146522136440">"Вібрацыя"</string>
+ <string name="voicemail_visual_voicemail_switch_title" msgid="5012622186976275457">"Візуальная галасавая пошта"</string>
+ <string name="voicemail_set_pin_dialog_title" msgid="2797924461029093837">"Задаць PIN-код"</string>
+ <string name="voicemail_change_pin_dialog_title" msgid="6035421908626121564">"Змяніць PIN-код"</string>
+ <string name="voicemail_notification_ringtone_title" msgid="2609519527849101590">"Гук"</string>
+ <string name="preference_category_ringtone" msgid="5197960752529332721">"Рынгтон і вiбрацыя"</string>
+ <string name="pstn_connection_service_label" msgid="1743245930577325900">"Убудаваныя SIM-карты"</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>
+ <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="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>
+ <string name="callFailed_cdma_activation" msgid="2307989779233262164">"SIM-карта актывавала вашу службу і абнавіла функцыі роўмінгу вашага тэлефона."</string>
+ <string name="callFailed_cdma_call_limit" msgid="1556916577171457086">"Занадта шмат актыўных выклікаў. Скончыце ці аб\'яднайце існуючыя выклікі, перш чым рабіць новы выклік."</string>
+ <string name="callFailed_imei_not_accepted" msgid="132192626901238542">"Немагчыма падключыцца, устаўце сапраўдную SIM-карту."</string>
+ <string name="callFailed_wifi_lost" msgid="5968076625137297184">"Страчана падключэнне да Wi-Fi. Выклік завершаны."</string>
+ <string name="change_pin_title" msgid="7790232089699034029">"Змяніць PIN-код галасавой пошты"</string>
+ <string name="change_pin_continue_label" msgid="2135088662420163447">"Працягнуць"</string>
+ <string name="change_pin_cancel_label" msgid="353535488390948596">"Скасаваць"</string>
+ <string name="change_pin_ok_label" msgid="6204308560844889926">"ОК"</string>
+ <string name="change_pin_enter_old_pin_header" msgid="419179847657548887">"Пацвердзіце свой стары PIN-код"</string>
+ <string name="change_pin_enter_old_pin_hint" msgid="8579171678763615453">"Каб працягнуць, увядзіце PIN-код галасавой пошты."</string>
+ <string name="change_pin_enter_new_pin_header" msgid="2611191814590251532">"Задайце новы PIN-код"</string>
+ <string name="change_pin_enter_new_pin_hint" msgid="2322940054329689309">"PIN-код павінен утрымліваць <xliff:g id="MIN">%1$d</xliff:g>-<xliff:g id="MAX">%2$d</xliff:g> лічбаў."</string>
+ <string name="change_pin_confirm_pin_header" msgid="8113764019347322170">"Пацвердзіце PIN-код"</string>
+ <string name="change_pin_confirm_pins_dont_match" msgid="4795052654904027909">"PIN-код не супадае"</string>
+ <string name="change_pin_succeeded" msgid="2022852286442211151">"PIN-код галасавой пошты абноўлены"</string>
+ <string name="change_pin_system_error" msgid="8308462387154257840">"Немагчыма прызначыць PIN-код"</string>
+</resources>
diff --git a/res/values-bg/config.xml b/res/values-bg/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-bg/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index a4828a1..52b3987 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Липсващ номер на гласова поща"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"На SIM картата няма съхранен номер за гласова поща."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Добавяне на номер"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Само основният потребител може да променя настройките на гласовата поща."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM картата ви е отблокирана. Телефонът ви се отключва…"</string>
<string name="label_ndp" msgid="780479633159517250">"PIN за отключване на SIM мрежа"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Отключване"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Излезте от режима на обратно обаждане при спешност, за да можете да извършвате обаждания, които не са спешни."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Няма регистрация в мрежата."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Няма мобилна мрежа."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Няма мобилна мрежа. Свържете се с безжична, за да се обадите."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"За да извършите обаждане, въведете валиден номер."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Обаждането не бе успешно."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Понастоящем обаждането не може да бъде добавено."</string>
diff --git a/res/values-bn-rBD/arrays.xml b/res/values-bn/arrays.xml
similarity index 100%
rename from res/values-bn-rBD/arrays.xml
rename to res/values-bn/arrays.xml
diff --git a/res/values-bn/config.xml b/res/values-bn/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-bn/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn/strings.xml
similarity index 98%
rename from res/values-bn-rBD/strings.xml
rename to res/values-bn/strings.xml
index 1c81ab7..ea9c68b 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"ভয়েসমেল নম্বর অনুপস্থিত"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"সিম কার্ডটিতে কোনো ভয়েসমেল নম্বর সংরক্ষিত নেই৷"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"একটি নম্বর যোগ করুন"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"ভয়েসমেল সেটিংস কেবলমাত্র প্রাথমিক ব্যবহারকারী দ্বারা পরিবর্তন করা যাবে।"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"আপনার সিম কার্ডকে অবরোধ মুক্ত করা হয়েছে৷ আপনার ফোন আনলক করা হচ্ছে..."</string>
<string name="label_ndp" msgid="780479633159517250">"সিম নেটওয়ার্ক আনলক পিন"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"আনলক করুন"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"একটি সাধারণ কল করতে জরুরি কলব্যাক মোডের বাইরে আসুন৷"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"নেটওয়ার্কে নিবন্ধিত নয়৷"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"মোবাইল নেটওয়ার্ক উপলব্ধ নয়৷"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"মোবাইল নেটওয়ার্ক উপলব্ধ নেই৷ একটি কল করতে কোনো ওয়্যারলেস নেটওয়ার্কে সংযোগ করুন৷"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"কোনো কল স্থাপন করতে, একটি বৈধ নম্বর লিখুন৷"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"কল ব্যর্থ হয়েছে৷"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"এই মুহূর্তে কল যোগ করা যাবে না৷"</string>
diff --git a/res/values-bs/arrays.xml b/res/values-bs/arrays.xml
new file mode 100644
index 0000000..42d6395
--- /dev/null
+++ b/res/values-bs/arrays.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string-array name="preferred_network_mode_choices_world_mode">
+ <item msgid="3391522821603584785">"Globalno"</item>
+ <item msgid="6753774959494729275">"LTE / CDMA"</item>
+ <item msgid="8658695584186942227">"LTE / GSM / UMTS"</item>
+ </string-array>
+ <string-array name="preferred_network_mode_values_world_mode">
+ <item msgid="8390941159766263625">"10"</item>
+ <item msgid="6103348346295810336">"8"</item>
+ <item msgid="3494519853214024879">"9"</item>
+ </string-array>
+</resources>
diff --git a/res/values-bs/config.xml b/res/values-bs/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-bs/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
new file mode 100644
index 0000000..af16abc
--- /dev/null
+++ b/res/values-bs/strings.xml
@@ -0,0 +1,597 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2007 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="phoneAppLabel" product="tablet" msgid="8576272342240415145">"Mobilni podaci"</string>
+ <string name="phoneAppLabel" product="default" msgid="6790717591729922998">"Telefonske usluge"</string>
+ <string name="emergencyDialerIconLabel" msgid="7812140032168171053">"Hitno biranje"</string>
+ <string name="phoneIconLabel" msgid="2331230813161304895">"Telefon"</string>
+ <string name="fdnListLabel" msgid="8630418672279521003">"FDN lista"</string>
+ <string name="unknown" msgid="6878797917991465859">"Nepoznato"</string>
+ <string name="private_num" msgid="6713286113000232309">"Privatni broj"</string>
+ <string name="payphone" msgid="4793877574636445118">"Telefonska govornica"</string>
+ <string name="onHold" msgid="9035493194749959955">"Na čekanju"</string>
+ <string name="mmiStarted" msgid="6347869857061147003">"MMI kȏd je pokrenut"</string>
+ <string name="ussdRunning" msgid="485588686340541690">"USSD kȏd je pokrenut…"</string>
+ <string name="mmiCancelled" msgid="2771923949751842276">"MMI kȏd je otkazan"</string>
+ <string name="cancel" msgid="5044513931633602634">"Otkaži"</string>
+ <string name="enter_input" msgid="1810529547726803893">"USSD poruka mora imati između <xliff:g id="MIN_LEN">%d</xliff:g> i <xliff:g id="MAX_LEN">%d</xliff:g> znakova. Pokušajte ponovo."</string>
+ <string name="manageConferenceLabel" msgid="4691922394301969053">"Upravljaj konferencijskim pozivom"</string>
+ <string name="ok" msgid="3811371167865772377">"Uredu"</string>
+ <string name="audio_mode_speaker" msgid="27649582100085266">"Zvučnik"</string>
+ <string name="audio_mode_earpiece" msgid="4156527186373869107">"Slušalice telefona"</string>
+ <string name="audio_mode_wired_headset" msgid="1465350758489175975">"Žičane slušalice"</string>
+ <string name="audio_mode_bluetooth" msgid="3047641300848211128">"Bluetooth"</string>
+ <string name="wait_prompt_str" msgid="7601815427707856238">"Poslati sljedeće tonove?\n"</string>
+ <string name="pause_prompt_str" msgid="1789964702154314806">"Slanje tonova\n"</string>
+ <string name="send_button" msgid="4106860097497818751">"Pošalji"</string>
+ <string name="pause_prompt_yes" msgid="3564467212025151797">"Da"</string>
+ <string name="pause_prompt_no" msgid="6686238803236884877">"Ne"</string>
+ <string name="wild_prompt_str" msgid="5543521676355533577">"Zamijeni zamjenski znak sa"</string>
+ <string name="no_vm_number" msgid="4164780423805688336">"Nedostaje broj govorne pošte"</string>
+ <string name="no_vm_number_msg" msgid="1300729501030053828">"Broj govorne pošte nije pohranjen na SIM kartici."</string>
+ <string name="add_vm_number_str" msgid="4676479471644687453">"Dodaj broj"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
+ <string name="puk_unlocked" msgid="2284912838477558454">"Vaša SIM kartica je odblokirana. Telefon se otključava…"</string>
+ <string name="label_ndp" msgid="780479633159517250">"PIN za otključavanje mreže na SIM kartici"</string>
+ <string name="sim_ndp_unlock_text" msgid="683628237760543009">"Otključaj"</string>
+ <string name="sim_ndp_dismiss_text" msgid="1604823375752456947">"Odbaci"</string>
+ <string name="requesting_unlock" msgid="6412629401033249351">"Traži se otključavanje mreže…"</string>
+ <string name="unlock_failed" msgid="6490531697031504225">"Neuspješan zahtjev za otključavanje mreže."</string>
+ <string name="unlock_success" msgid="6770085622238180152">"Mreža je uspješno otključana"</string>
+ <!-- no translation found for mobile_network_settings_not_available (7355254462995117896) -->
+ <skip />
+ <string name="labelGSMMore" msgid="5930842194056092106">"Postavke za GSM poziv"</string>
+ <string name="labelGsmMore_with_label" msgid="2674012918829238901">"Postavke za GSM poziv (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="labelCDMAMore" msgid="1630676740428229339">"Postavke za CDMA poziv"</string>
+ <string name="labelCdmaMore_with_label" msgid="6333588719319970399">"Postavke za CDMA poziv (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="apn_settings" msgid="9043423184895642077">"Nazivi pristupnih tačaka"</string>
+ <string name="settings_label" msgid="3876743539816984008">"Postavke mreže"</string>
+ <string name="phone_accounts" msgid="6376603393888116364">"Računi za pozivanje"</string>
+ <string name="phone_accounts_make_calls_with" msgid="1969188078933152231">"Uputi pozive putem"</string>
+ <string name="phone_accounts_make_sip_calls_with" msgid="4677789312053828493">"Uputi SIP pozive putem"</string>
+ <string name="phone_accounts_ask_every_time" msgid="4346499067149985702">"Prvo pitaj"</string>
+ <string name="phone_accounts_default_account_label" msgid="4183772241814460014">"Nema dostupnih mreža"</string>
+ <string name="phone_accounts_settings_header" msgid="4141710640883261094">"Postavke"</string>
+ <string name="phone_accounts_choose_accounts" msgid="5232948804226424002">"Izaberi račune"</string>
+ <string name="phone_accounts_selection_header" msgid="1365215726106915865">"Telefonski računi"</string>
+ <string name="phone_accounts_add_sip_account" msgid="2023821743341923271">"Dodaj SIP račun"</string>
+ <string name="phone_accounts_configure_account_settings" msgid="1361715069911607109">"Konfiguriraj postavke računa"</string>
+ <string name="phone_accounts_all_calling_accounts" msgid="207619531589278471">"Svi računi za pozivanje"</string>
+ <string name="phone_accounts_all_calling_accounts_summary" msgid="8594186415822657011">"Odaberite koji računi mogu upućivati pozive"</string>
+ <string name="wifi_calling" msgid="739018212480165598">"Wi-Fi pozivanje"</string>
+ <string name="connection_service_default_label" msgid="1498481943805913754">"Ugrađena usluga povezivanja"</string>
+ <string name="voicemail" msgid="8693759337917898954">"Govorna pošta"</string>
+ <string name="voicemail_settings_with_label" msgid="152724978380748296">"Govorna pošta (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="voicemail_abbreviated" msgid="2215592488517217448">"GP:"</string>
+ <string name="networks" msgid="8873030692174541976">"Mrežni operateri"</string>
+ <string name="cell_broadcast_settings" msgid="8740238216690502563">"Hitna emitiranja"</string>
+ <string name="call_settings" msgid="6112441768261754562">"Postavke poziva"</string>
+ <string name="additional_gsm_call_settings" msgid="1391795981938800617">"Dodatne postavke"</string>
+ <string name="additional_gsm_call_settings_with_label" msgid="1385241520708457376">"Dodatne postavke (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="sum_gsm_call_settings" msgid="4076647190996778012">"Dodatne postavke samo GSM poziva"</string>
+ <string name="additional_cdma_call_settings" msgid="8628958775721886909">"Dodatne postavke za CDMA poziv"</string>
+ <string name="sum_cdma_call_settings" msgid="284753265979035549">"Dodatne postavke samo CDMA poziva"</string>
+ <string name="labelNwService" msgid="4699970172021870983">"Postavke mrežne usluge"</string>
+ <string name="labelCallerId" msgid="3888899447379069198">"ID pozivaoca"</string>
+ <string name="sum_loading_settings" msgid="1826692909391168620">"Učitavanje postavki…"</string>
+ <string name="sum_hide_caller_id" msgid="1071407020290873782">"Broj je skriven u odlaznim pozivima"</string>
+ <string name="sum_show_caller_id" msgid="6768534125447290401">"Broj je prikazan u odlaznim pozivima"</string>
+ <string name="sum_default_caller_id" msgid="1954518825510901365">"Koristi zadane postavke operatera za prikaz mog broja u odlaznim pozivima"</string>
+ <string name="labelCW" msgid="6120513814915920200">"Poziv na čekanju"</string>
+ <string name="sum_cw_enabled" msgid="8083061901633671397">"Tokom poziva, obavijesti me o dolaznim pozivima"</string>
+ <string name="sum_cw_disabled" msgid="3648693907300104575">"Tokom poziva, obavijesti me o dolaznim pozivima"</string>
+ <string name="call_forwarding_settings" msgid="3378927671091537173">"Postavke preusmjeravanja poziva"</string>
+ <string name="call_forwarding_settings_with_label" msgid="8569489414006897127">"Postavke preusmjeravanja poziva (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="labelCF" msgid="2574386948026924737">"Preusmjeravanje poziva"</string>
+ <string name="labelCFU" msgid="8147177368148660600">"Uvijek preusmjeri"</string>
+ <string name="messageCFU" msgid="3560082430662923687">"Uvijek koristi ovaj broj"</string>
+ <string name="sum_cfu_enabled_indicator" msgid="4014187342724130197">"Preusmjeravanje svih poziva"</string>
+ <string name="sum_cfu_enabled" msgid="2450052502198827927">"Preusmjeravaju se svi pozivi na <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+ <string name="sum_cfu_enabled_no_number" msgid="6591985777096823616">"Broj je nedostupan"</string>
+ <string name="sum_cfu_disabled" msgid="8384177689501334080">"Isključeno"</string>
+ <string name="labelCFB" msgid="6139853033106283172">"Kada je zauzeto"</string>
+ <string name="messageCFB" msgid="3711089705936187129">"Broj kada je zauzeto"</string>
+ <string name="sum_cfb_enabled" msgid="5984198104833116690">"Preusmjerava se na <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+ <string name="sum_cfb_disabled" msgid="4913145177320506827">"Isključeno"</string>
+ <string name="disable_cfb_forbidden" msgid="3506984333877998061">"Vaš operater ne podržava onemogućavanje preusmjeravanja poziva kada je telefon zauzet."</string>
+ <string name="labelCFNRy" msgid="1736067178393744351">"Kada nema odgovora"</string>
+ <string name="messageCFNRy" msgid="672317899884380374">"Broj kada nema odgovora"</string>
+ <string name="sum_cfnry_enabled" msgid="6955775691317662910">"Preusmjerava se na <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+ <string name="sum_cfnry_disabled" msgid="3884684060443538097">"Isključeno"</string>
+ <string name="disable_cfnry_forbidden" msgid="4308233959150658058">"Vaš operater ne podržava onemogućavanje preusmjeravanja poziva kada se ne odgovori na poziv."</string>
+ <string name="labelCFNRc" msgid="2614827454402079766">"Kada je nedostupno"</string>
+ <string name="messageCFNRc" msgid="6380695421020295119">"Broj kada je nedostupno"</string>
+ <string name="sum_cfnrc_enabled" msgid="7010898346095497421">"Preusmjerava se na <xliff:g id="PHONENUMBER">{0}</xliff:g>"</string>
+ <string name="sum_cfnrc_disabled" msgid="2684474391807469832">"Isključeno"</string>
+ <string name="disable_cfnrc_forbidden" msgid="5646361343094064333">"Vaš operater ne podržava onemogućavanje preusmjeravanja poziva kada ste nedostupni."</string>
+ <string name="updating_title" msgid="6146755386174019046">"Postavke poziva"</string>
+ <string name="call_settings_admin_user_only" msgid="4526094783818216374">"Postavke poziva može promijeniti samo administrator."</string>
+ <string name="call_settings_with_label" msgid="3401177261468593519">"Postavke (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="error_updating_title" msgid="7970259216988931777">"Greška u postavkama poziva"</string>
+ <string name="reading_settings" msgid="1920291699287055284">"Čitanje postavki u toku…"</string>
+ <string name="updating_settings" msgid="8171225533884883252">"Ažuriranje postavki u toku…"</string>
+ <string name="reverting_settings" msgid="4752151682666912828">"Vraćanje postavki u toku…"</string>
+ <string name="response_error" msgid="6674110501330139405">"Neočekivani odgovor mreže."</string>
+ <string name="exception_error" msgid="7027667130619518211">"Greška s mrežom ili SIM karticom."</string>
+ <string name="stk_cc_ss_to_dial_error" msgid="2816779198916570502">"SS zahtjev je izmijenjen u DIAL zahtjev."</string>
+ <string name="stk_cc_ss_to_ussd_error" msgid="7490626178582654236">"SS zahtjev je izmijenjen u USSD zahtjev."</string>
+ <string name="stk_cc_ss_to_ss_error" msgid="5057846756489053759">"SS zahtjev je izmijenjen u novi SS zahtjev."</string>
+ <string name="fdn_check_failure" msgid="18200614306525434">"Uključena je postavka brojeva fiksnog biranja u Aplikaciji za telefon. Zbog toga ne rade neke funkcije vezane za pozive."</string>
+ <string name="radio_off_error" msgid="2304459933248513376">"Uključite radio prije prikazivanja ovih postavki."</string>
+ <string name="close_dialog" msgid="2365884406356986917">"Uredu"</string>
+ <string name="enable" msgid="7248657275000173526">"Uključi"</string>
+ <string name="disable" msgid="4678348128118573672">"Isključi"</string>
+ <string name="change_num" msgid="239476305819844391">"Ažuriraj"</string>
+ <string-array name="clir_display_values">
+ <item msgid="5560134294467334594">"Zadana vrijednost mreže"</item>
+ <item msgid="7876195870037833661">"Sakrij broj"</item>
+ <item msgid="1108394741608734023">"Prikaži broj"</item>
+ </string-array>
+ <string name="vm_changed" msgid="380744030726254139">"Broj govorne pošte je promijenjen."</string>
+ <string name="vm_change_failed" msgid="3352934863246208918">"Nije moguće promijeniti broj govorne pošte.\nObratite se svom operateru ako se ovaj problem nastavi."</string>
+ <string name="fw_change_failed" msgid="5298103228470214665">"Nije moguće promijeniti broj za preusmjeravanje.\nObratite se svom operateru ako se ovaj problem nastavi."</string>
+ <string name="fw_get_in_vm_failed" msgid="8862896836093833973">"Nije moguće preuzeti i sačuvati trenutne postavke broja za preusmjeravanje.\nŽelite li i dalje preći na novu mrežu?"</string>
+ <string name="no_change" msgid="3186040086622435212">"Nisu izvršene promjene."</string>
+ <string name="sum_voicemail_choose_provider" msgid="59911196126278922">"Izaberite uslugu govorne pošte"</string>
+ <string name="voicemail_default" msgid="2001233554889016880">"Vaš operater"</string>
+ <string name="vm_change_pin_old_pin" msgid="7295220109886682573">"Stari PIN"</string>
+ <string name="vm_change_pin_new_pin" msgid="5412922262839438097">"Novi PIN"</string>
+ <string name="vm_change_pin_progress_message" msgid="3977357361934350336">"Pričekajte."</string>
+ <string name="vm_change_pin_error_too_short" msgid="5974971097302710497">"Novi PIN je prekratak."</string>
+ <string name="vm_change_pin_error_too_long" msgid="8476870806115051865">"Novi PIN je predug."</string>
+ <string name="vm_change_pin_error_too_weak" msgid="7883744811891784882">"Novi PIN je preslab. Jaka lozinka ne smije sadržavati uzastopni niz ili ponovljene cifre."</string>
+ <string name="vm_change_pin_error_mismatch" msgid="2754685537970757317">"Stari PIN se ne podudara."</string>
+ <string name="vm_change_pin_error_invalid" msgid="3972205462701668653">"Novi PIN sadrži nevažeće znakove."</string>
+ <string name="vm_change_pin_error_system_error" msgid="6610603326230000207">"Nije moguće promijeniti PIN"</string>
+ <string name="vvm_unsupported_message_format" msgid="11795090778411977">"Nepodržana vrsta poruke. Pozovite <xliff:g id="NUMBER">%s</xliff:g> da je preslušate."</string>
+ <string name="mobile_networks" msgid="5540397602919106177">"Postavke mobilne mreže"</string>
+ <string name="label_available" msgid="1181658289009300430">"Dostupne mreže"</string>
+ <string name="load_networks_progress" msgid="5230707536168902952">"Pretraživanje…"</string>
+ <string name="empty_networks_list" msgid="4249426905018815316">"Nije pronađena nijedna mreža."</string>
+ <string name="search_networks" msgid="1601136049300882441">"Pretraži mreže"</string>
+ <string name="network_query_error" msgid="6828516148953325006">"Greška prilikom traženja mreža."</string>
+ <string name="register_on_network" msgid="9055203954040805084">"Registriranje na <xliff:g id="NETWORK">%s</xliff:g> u toku…"</string>
+ <string name="not_allowed" msgid="5613353860205691579">"Vaša SIM kartica ne dozvoljava povezivanje na ovu mrežu."</string>
+ <string name="connect_later" msgid="2308119155752343975">"Trenutno nije moguće povezati se s ovom mrežom. Pokušajte ponovo kasnije."</string>
+ <string name="registration_done" msgid="495135664535876612">"Registrirano na mrežu."</string>
+ <string name="sum_carrier_select" msgid="3494252551249882718">"Odaberite operatera"</string>
+ <string name="sum_search_networks" msgid="2921092249873272715">"Traži sve dostupne mreže"</string>
+ <string name="select_automatically" msgid="5628402124471810174">"Izaberi automatski"</string>
+ <string name="sum_select_automatically" msgid="5614890115123292400">"Automatski izaberi preferiranu mrežu"</string>
+ <string name="register_automatically" msgid="6017849844573519637">"Automatska registracija u toku…"</string>
+ <string name="preferred_network_mode_title" msgid="2336624679902659306">"Preferirana vrsta mreže"</string>
+ <string name="preferred_network_mode_summary" msgid="1434820673166126609">"Promijeni način rada mreže"</string>
+ <string name="preferred_network_mode_dialogtitle" msgid="4048082093347807230">"Preferirana vrsta mreže"</string>
+ <string name="preferred_network_mode_wcdma_perf_summary" msgid="8521677230113533809">"Preferirani način rada mreže: preferiraj WCDMA"</string>
+ <string name="preferred_network_mode_gsm_only_summary" msgid="3352445413437453511">"Preferirani način rada mreže: samo GSM"</string>
+ <string name="preferred_network_mode_wcdma_only_summary" msgid="2836897236221063413">"Preferirani način rada mreže: samo WCDMA"</string>
+ <string name="preferred_network_mode_gsm_wcdma_summary" msgid="3161255745326408587">"Preferirani način rada mreže: GSM / WCDMA"</string>
+ <string name="preferred_network_mode_cdma_summary" msgid="3175690187294334241">"Preferirani način rada mreže: CDMA"</string>
+ <string name="preferred_network_mode_cdma_evdo_summary" msgid="8332063064712726618">"Preferirani način rada mreže: CDMA / EvDo"</string>
+ <string name="preferred_network_mode_cdma_only_summary" msgid="1309770926198634150">"Preferirani način rada mreže: samo CDMA"</string>
+ <string name="preferred_network_mode_evdo_only_summary" msgid="8472220691721269155">"Preferirani način rada mreže: samo EvDo"</string>
+ <string name="preferred_network_mode_cdma_evdo_gsm_wcdma_summary" msgid="4726682079415227330">"Preferirani način rada mreže: CDMA/EvDo/GSM/WCDMA"</string>
+ <string name="preferred_network_mode_lte_summary" msgid="574752287596469136">"Preferirani način rada mreže: LTE"</string>
+ <string name="preferred_network_mode_lte_gsm_wcdma_summary" msgid="8455358514068283935">"Preferirani način rada mreže: GSM/WCDMA/LTE"</string>
+ <string name="preferred_network_mode_lte_cdma_evdo_summary" msgid="228702246343742853">"Preferirani način rada mreže: CDMA+LTE/EVDO"</string>
+ <string name="preferred_network_mode_global_summary" msgid="1633134285545730364">"Preferirani način rada mreže: globalno"</string>
+ <string name="preferred_network_mode_lte_wcdma_summary" msgid="9180775701594742750">"Preporučeni način rada mreže: LTE / WCDMA"</string>
+ <string name="preferred_network_mode_lte_gsm_umts_summary" msgid="633315028976225026">"Preferirani način rada mreže: LTE / GSM / UMTS"</string>
+ <string name="preferred_network_mode_lte_cdma_summary" msgid="3722647806454528426">"Preferirani način rada mreže: LTE / CDMA"</string>
+ <string name="preferred_network_mode_tdscdma_summary" msgid="8021016193718678775">"Preferirani način rada mreže: TDSCDMA"</string>
+ <string-array name="preferred_network_mode_choices">
+ <item msgid="7886739962255042385">"LTE / WCDMA"</item>
+ <item msgid="577652050447385699">"LTE"</item>
+ <item msgid="6813597571293773656">"Globalno"</item>
+ <item msgid="127064712132619032">"GSM/WCDMA/LTE"</item>
+ <item msgid="1126767511633425977">"CDMA + LTE/EvDo"</item>
+ <item msgid="6389676313771670660">"CDMA/EvDo/GSM/WCDMA"</item>
+ <item msgid="545430093607698090">"Samo EvDo"</item>
+ <item msgid="1508557726283094448">"CDMA w/o EvDo"</item>
+ <item msgid="4341433122263841224">"CDMA / EVDO automatski"</item>
+ <item msgid="5958053792390386668">"Automatski GSM/WCDMA"</item>
+ <item msgid="7913148405605373434">"Samo WCDMA"</item>
+ <item msgid="1524224863879435516">"Samo GSM"</item>
+ <item msgid="3817924849415716259">"Preferiraj GSM/WCDMA"</item>
+ </string-array>
+ <string name="enhanced_4g_lte_mode_title" msgid="522191650223239171">"Poboljšani 4G LTE način rada"</string>
+ <string name="enhanced_4g_lte_mode_title_variant" msgid="4871126028907265406">"Napredno pozivanje"</string>
+ <string name="enhanced_4g_lte_mode_summary" msgid="2332175070522125850">"Koristi LTE usluge za poboljšanje glasovne i drugih komunikacija (preporučeno)"</string>
+ <string name="data_enabled" msgid="5972538663568715366">"Podaci su omogućeni"</string>
+ <string name="data_enable_summary" msgid="2382798156640007971">"Dozvoli korištenje podataka"</string>
+ <string name="dialog_alert_title" msgid="6751344986194435476">"Pažnja"</string>
+ <string name="roaming" msgid="8871412572928323707">"Roming podataka"</string>
+ <string name="roaming_enable" msgid="7331106985174381987">"Poveži se na usluge prijenosa podataka u romingu"</string>
+ <string name="roaming_disable" msgid="1843417228755568110">"Poveži se na usluge prijenosa podataka u romingu"</string>
+ <string name="roaming_reenable_message" msgid="8913735676127858115">"Izgubili ste podatkovnu vezu jer ste napustili matičnu mrežu dok je roming podataka isključen."</string>
+ <string name="roaming_warning" msgid="1603164667540144353">"Može dovesti do značajnih troškova."</string>
+ <string name="roaming_alert_title" msgid="3654815360303826008">"Dozvoliti roming podataka?"</string>
+ <string name="gsm_umts_options" msgid="6538311689850981686">"GSM/UMTS opcije"</string>
+ <string name="cdma_options" msgid="4016822858172249884">"CDMA opcije"</string>
+ <string name="throttle_data_usage" msgid="3715677828160555808">"Korištenje podataka"</string>
+ <string name="throttle_current_usage" msgid="8762280193043815361">"Iskorišteni podaci u trenutnom periodu"</string>
+ <string name="throttle_time_frame" msgid="1915198770363734685">"Period korištenja podataka"</string>
+ <string name="throttle_rate" msgid="4710388992676803508">"Pravila o brzini prijenosa podataka"</string>
+ <string name="throttle_help" msgid="243651091785169900">"Saznajte više"</string>
+ <string name="throttle_status_subtext" msgid="1657318943142085170">"<xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g> ٪) od <xliff:g id="USED_2">%3$s</xliff:g> maksimuma perioda\nSljedeći period počinje za <xliff:g id="USED_3">%4$d</xliff:g> dan(a) (<xliff:g id="USED_4">%5$s</xliff:g>)"</string>
+ <string name="throttle_data_usage_subtext" msgid="6029276011123694701">"<xliff:g id="USED_0">%1$s</xliff:g> (<xliff:g id="USED_1">%2$d</xliff:g> ٪) od <xliff:g id="USED_2">%3$s</xliff:g> maksimuma perioda"</string>
+ <string name="throttle_data_rate_reduced_subtext" msgid="7492763592720107737">"<xliff:g id="USED_0">%1$s</xliff:g> ograničenje je prekoračeno \nBrzina prijenosa podataka je smanjena na <xliff:g id="USED_1">%2$d</xliff:g> Kb/s"</string>
+ <string name="throttle_time_frame_subtext" msgid="7732763021560399960">"Proteklo je <xliff:g id="USED_0">%1$d</xliff:g> ٪ ciklusa\nSljedeći period počinje za <xliff:g id="USED_1">%2$d</xliff:g> dan(a) (<xliff:g id="USED_2">%3$s</xliff:g>)"</string>
+ <string name="throttle_rate_subtext" msgid="2149102656120726855">"Brzina prijenosa podataka se smanjuje na <xliff:g id="USED">%1$d</xliff:g> Kb/s ako se prekorači ograničenje korištenja podataka"</string>
+ <string name="throttle_help_subtext" msgid="5217706521499010816">"Više informacija o pravilima korištenja podataka mobilne mreže vašeg operatera"</string>
+ <string name="cell_broadcast_sms" msgid="5584192824053625842">"SMS info servisa"</string>
+ <string name="enable_disable_cell_bc_sms" msgid="4851147873691392255">"SMS info servisa"</string>
+ <string name="cell_bc_sms_enable" msgid="6441688565738921084">"SMS info servisa je omogućen"</string>
+ <string name="cell_bc_sms_disable" msgid="3398365088309408749">"SMS info servisa je onemogućen"</string>
+ <string name="cb_sms_settings" msgid="651715019785107312">"Postavke SMS-a info servisa"</string>
+ <string name="enable_disable_emergency_broadcast" msgid="2157014609041245335">"Hitno emitiranje"</string>
+ <string name="emergency_broadcast_enable" msgid="2645980025414010211">"Hitno emitiranje je omogućeno"</string>
+ <string name="emergency_broadcast_disable" msgid="3665199821267569426">"Hitno emitiranje je onemogućeno"</string>
+ <string name="enable_disable_administrative" msgid="6501582322182059412">"Administrativno"</string>
+ <string name="administrative_enable" msgid="1750086122962032235">"Administrativno je omogućeno"</string>
+ <string name="administrative_disable" msgid="8433273857248698539">"Administrativno je onemogućeno"</string>
+ <string name="enable_disable_maintenance" msgid="1819693083025106678">"Održavanje"</string>
+ <string name="maintenance_enable" msgid="8566636458770971189">"Održavanje je omogućeno"</string>
+ <string name="maintenance_disable" msgid="7340189100885066077">"Održavanje je onemogućeno"</string>
+ <string name="general_news_settings" msgid="4968779723948432978">"Opće vijesti"</string>
+ <string name="bf_news_settings" msgid="3935593091894685267">"Poslovne i finansijske vijesti"</string>
+ <string name="sports_news_settings" msgid="7649399631270052835">"Sportske vijesti"</string>
+ <string name="entertainment_news_settings" msgid="5051153952959405035">"Vijesti iz svijeta zabave"</string>
+ <string name="enable_disable_local" msgid="7890281063123416120">"Lokalno"</string>
+ <string name="local_enable" msgid="6370463247609136359">"Lokalne vijesti su omogućene"</string>
+ <string name="local_disable" msgid="4405691986943795798">"Lokalne vijesti su onemogućene"</string>
+ <string name="enable_disable_regional" msgid="4905652414535565872">"Regionalno"</string>
+ <string name="regional_enable" msgid="4434680415437834759">"Regionalne vijesti su omogućene"</string>
+ <string name="regional_disable" msgid="5359325527213850077">"Regionalne vijesti su onemogućene"</string>
+ <string name="enable_disable_national" msgid="236278090206880734">"Državno"</string>
+ <string name="national_enable" msgid="1172443648912246952">"Državne vijesti su omogućene"</string>
+ <string name="national_disable" msgid="326018148178601166">"Državne vijesti su onemogućene"</string>
+ <string name="enable_disable_international" msgid="7535348799604565592">"Međunarodno"</string>
+ <string name="international_enable" msgid="5855356769925044927">"Međunarodne vijesti su omogućene"</string>
+ <string name="international_disable" msgid="2850648591041088931">"Međunarodne vijesti su onemogućene"</string>
+ <string name="list_language_title" msgid="2841683501919760043">"Jezik"</string>
+ <string name="list_language_summary" msgid="8109546531071241601">"Odaberite jezik vijesti"</string>
+ <string-array name="list_language_entries">
+ <item msgid="6137851079727305485">"engleski"</item>
+ <item msgid="1151988412809572526">"francuski"</item>
+ <item msgid="577840534704312665">"španski"</item>
+ <item msgid="8385712091143148180">"japanski"</item>
+ <item msgid="1858401628368130638">"korejanski"</item>
+ <item msgid="1933212028684529632">"kineski"</item>
+ <item msgid="1908428006803639064">"hebrejski"</item>
+ </string-array>
+ <string-array name="list_language_values">
+ <item msgid="1804908636436467150">"1"</item>
+ <item msgid="289708030346890334">"2"</item>
+ <item msgid="1121469729692402684">"3"</item>
+ <item msgid="2614093115912897722">"4"</item>
+ <item msgid="2411164639857960614">"5"</item>
+ <item msgid="5884448729274543324">"6"</item>
+ <item msgid="5511864807618312598">"7"</item>
+ </string-array>
+ <string name="list_language_dtitle" msgid="5442908726538951934">"Jezici"</string>
+ <string name="enable_disable_local_weather" msgid="986967454867219114">"Lokalna vremenska prognoza"</string>
+ <string name="local_weather_enable" msgid="6199315114382448922">"Lokalna vremenska prognoza je omogućena"</string>
+ <string name="local_weather_disable" msgid="2510158089142626480">"Lokalna vremenska prognoza je onemogućena"</string>
+ <string name="enable_disable_atr" msgid="8339572391278872343">"Izvještaji o lokalnom saobraćaju"</string>
+ <string name="atr_enable" msgid="5541757457789181799">"Izvještaji o lokalnom saobraćaju su omogućeni"</string>
+ <string name="atr_disable" msgid="7085558154727596455">"Izvještaji o lokalnom saobraćaju su onemogućeni"</string>
+ <string name="enable_disable_lafs" msgid="668189073721277199">"Raspored letova za lokalni aerodrom"</string>
+ <string name="lafs_enable" msgid="2791978667205137052">"Raspored letova za lokalni aerodrom je omogućen"</string>
+ <string name="lafs_disable" msgid="2391212397725495350">"Raspored letova za lokalni aerodrom je onemogućen"</string>
+ <string name="enable_disable_restaurants" msgid="6240381945336814024">"Restorani"</string>
+ <string name="restaurants_enable" msgid="5137657479469118847">"Restorani su omogućeni"</string>
+ <string name="restaurants_disable" msgid="3678480270938424092">"Restorani su onemogućeni"</string>
+ <string name="enable_disable_lodgings" msgid="1822029172658551202">"Smještaj"</string>
+ <string name="lodgings_enable" msgid="3230042508992850322">"Smještaj je omogućen"</string>
+ <string name="lodgings_disable" msgid="3387879742320682391">"Smještaj je onemogućen"</string>
+ <string name="enable_disable_retail_directory" msgid="1357809784475660303">"Katalog maloprodaje"</string>
+ <string name="retail_directory_enable" msgid="3280626290436111496">"Katalog maloprodaje je omogućen"</string>
+ <string name="retail_directory_disable" msgid="6479739816662879027">"Katalog maloprodaje je onemogućen"</string>
+ <string name="enable_disable_advertisements" msgid="5999495926176182128">"Oglasi"</string>
+ <string name="advertisements_enable" msgid="2050305021264683786">"Oglasi su omogućeni"</string>
+ <string name="advertisements_disable" msgid="8350985908788707935">"Oglasi su onemogućeni"</string>
+ <string name="enable_disable_stock_quotes" msgid="6397810445293533603">"Cijene dionica"</string>
+ <string name="stock_quotes_enable" msgid="4384802470887170543">"Cijene akcija su omogućene"</string>
+ <string name="stock_quotes_disable" msgid="4781450084565594998">"Cijene dionica su onemogućene"</string>
+ <string name="enable_disable_eo" msgid="4863043263443942494">"Prilike za zapošljavanje"</string>
+ <string name="eo_enable" msgid="8623559062015685813">"Prilike za zapošljavanje su omogućene"</string>
+ <string name="eo_disable" msgid="3863812478090907609">"Prilike za zapošljavanje su onemogućene"</string>
+ <string name="enable_disable_mhh" msgid="908214593528968522">"Medicina, zdravlje i bolnice"</string>
+ <string name="mhh_enable" msgid="5544500632306446815">"Medicina, zdravlje i bolnice su omogućene"</string>
+ <string name="mhh_disable" msgid="8998210550117117437">"Medicina, zdravlje i bolnice su onemogućene"</string>
+ <string name="enable_disable_technology_news" msgid="3517184627114999149">"Tehnološke vijesti"</string>
+ <string name="technology_news_enable" msgid="7995209394210455181">"Tehnološke vijesti su omogućene"</string>
+ <string name="technology_news_disable" msgid="5483490380561851946">"Tehnološke vijesti su onemogućene"</string>
+ <string name="enable_disable_multi_category" msgid="626771003122899280">"Više kategorija"</string>
+ <string name="multi_category_enable" msgid="1179299804641721768">"Više kategorija je omogućeno"</string>
+ <string name="multi_category_disable" msgid="880104702904139505">"Više kategorija je onemogućeno"</string>
+ <string name="network_lte" msgid="7702681952521375754">"LTE (preporučeno)"</string>
+ <string name="network_4G" msgid="2723512640529983138">"4G (preporučeno)"</string>
+ <string name="network_global" msgid="1323190488685355309">"Globalno"</string>
+ <string name="cdma_system_select_title" msgid="5757657769327732833">"Odabir sistema"</string>
+ <string name="cdma_system_select_summary" msgid="60460043745797517">"Promijeni način rada CDMA rominga"</string>
+ <string name="cdma_system_select_dialogtitle" msgid="6083355415165359075">"Odabir sistema"</string>
+ <string-array name="cdma_system_select_choices">
+ <item msgid="176474317493999285">"Samo kuća"</item>
+ <item msgid="1205664026446156265">"Automatski"</item>
+ </string-array>
+ <string name="cdma_subscription_title" msgid="1162564010076763284">"CDMA pretplata"</string>
+ <string name="cdma_subscription_summary" msgid="2530890766115781140">"Promjena između RUIM/SIM i NV"</string>
+ <string name="cdma_subscription_dialogtitle" msgid="2699527950523333110">"pretplata"</string>
+ <string-array name="cdma_subscription_choices">
+ <item msgid="2258014151300708431">"RUIM/SIM"</item>
+ <item msgid="5127722015571873880">"NV"</item>
+ </string-array>
+ <string-array name="cdma_subscription_values">
+ <item msgid="7494167883478914080">"0"</item>
+ <item msgid="6043847456049107742">"1"</item>
+ </string-array>
+ <string name="cdma_activate_device" msgid="3793805892364814518">"Aktiviraj uređaj"</string>
+ <string name="cdma_lte_data_service" msgid="4255018217292548962">"Postavi prijenos podataka"</string>
+ <string name="carrier_settings_title" msgid="9028166176523012300">"Postavke operatera"</string>
+ <string name="fdn" msgid="7878832555095183202">"Brojevi fiksnog biranja"</string>
+ <string name="fdn_with_label" msgid="187084204115493366">"Brojevi fiksnog biranja (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="manage_fdn_list" msgid="8777755791892122369">"FDN lista"</string>
+ <string name="fdn_list_with_label" msgid="7437232552210469217">"FDN lista (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
+ <string name="fdn_activation" msgid="2156479741307463576">"FDN aktivacija"</string>
+ <string name="fdn_enabled" msgid="5238109009915521240">"Brojevi fiksnog biranja su omogućeni"</string>
+ <string name="fdn_disabled" msgid="4700049736675368279">"Brojevi fiksnog biranja su onemogućeni"</string>
+ <string name="enable_fdn" msgid="3740191529180493851">"Omogući FDN"</string>
+ <string name="disable_fdn" msgid="7944020890722540616">"Onemogući FDN"</string>
+ <string name="change_pin2" msgid="2153563695382176676">"Promijeni PIN2"</string>
+ <string name="enable_fdn_ok" msgid="7215588870329688132">"Onemogući FDN"</string>
+ <string name="disable_fdn_ok" msgid="5727046928930740173">"Omogući FDN"</string>
+ <string name="sum_fdn" msgid="1959399454900272878">"Upravljaj brojevima fiksnog biranja"</string>
+ <string name="sum_fdn_change_pin" msgid="6666549734792827932">"Promijeni PIN za FDN pristup"</string>
+ <string name="sum_fdn_manage_list" msgid="8431088265332628316">"Upravljaj listom brojeva telefona"</string>
+ <string name="voice_privacy" msgid="3776841382844614716">"Privatnost glasa"</string>
+ <string name="voice_privacy_summary" msgid="3159383389833516214">"Omogući poboljšani naćin rada za privatnost"</string>
+ <string name="tty_mode_option_title" msgid="9033098925144434669">"TTY način rada"</string>
+ <string name="tty_mode_option_summary" msgid="1073835131534808732">"Postavi TTY način rada"</string>
+ <string name="auto_retry_mode_title" msgid="4073265511427813322">"Automatski ponovni pokušaj"</string>
+ <string name="auto_retry_mode_summary" msgid="4973886004067532288">"Omogući način rada za automatski ponovni pokušaj"</string>
+ <string name="tty_mode_not_allowed_video_call" msgid="3795846787901909176">"Promjena TTY načina rada nije dozvoljena tokom videopoziva"</string>
+ <string name="menu_add" msgid="1882023737425114762">"Dodaj kontakt"</string>
+ <string name="menu_edit" msgid="7143003705504672374">"Uredi kontakt"</string>
+ <string name="menu_delete" msgid="3977150783449642851">"Izbriši kontakt"</string>
+ <string name="menu_dial" msgid="3223106222819685808">"Pozivanje kontakta"</string>
+ <string name="get_pin2" msgid="8204677063922225311">"Upišite PIN2"</string>
+ <string name="name" msgid="7329028332786872378">"Ime"</string>
+ <string name="number" msgid="7905950798349903858">"Broj"</string>
+ <string name="save" msgid="4094274636321939086">"Sačuvaj"</string>
+ <string name="add_fdn_contact" msgid="2481915899633353976">"Dodaj broj fiksnog biranja"</string>
+ <string name="adding_fdn_contact" msgid="7627379633721940991">"Dodaje se broj fiksnog biranja…"</string>
+ <string name="fdn_contact_added" msgid="7458335758501736665">"Broj fiksnog biranja je dodan."</string>
+ <string name="edit_fdn_contact" msgid="7976936035587081480">"Uredi broj fiksnog biranja"</string>
+ <string name="updating_fdn_contact" msgid="8370929876849803600">"Ažuriranje broja fiksnog biranja u toku…"</string>
+ <string name="fdn_contact_updated" msgid="5497828782609005017">"Broj fiksnog biranja je ažuriran."</string>
+ <string name="delete_fdn_contact" msgid="6668958073074151717">"Izbriši broj fiksnog biranja"</string>
+ <string name="deleting_fdn_contact" msgid="5669163206349319969">"Brisanje broja fiksnog biranja u toku…"</string>
+ <string name="fdn_contact_deleted" msgid="7154162327112259569">"Broj fiksnog biranja je izbrisan."</string>
+ <string name="pin2_invalid" msgid="5470854099230755944">"FDN nije ažuriran jer ste upisali netačan PIN."</string>
+ <string name="fdn_invalid_number" msgid="8602417141715473998">"FDN nije ažuriran jer je broj prazan ili ima više od 20 cifara."</string>
+ <string name="pin2_or_fdn_invalid" msgid="6025144083384701197">"FDN nije ažuriran. PIN2 je netačan ili je broj telefona odbijen."</string>
+ <string name="fdn_failed" msgid="540018079008319747">"FDN operacija nije uspjela."</string>
+ <string name="simContacts_emptyLoading" msgid="2203331234764498011">"Čitanje sa SIM kartice u toku…"</string>
+ <string name="simContacts_empty" msgid="5270660846489561932">"Nema kontakata na SIM kartici."</string>
+ <string name="simContacts_title" msgid="1861472842524839921">"Odaberite kontakte za uvoz"</string>
+ <string name="simContacts_airplaneMode" msgid="5254946758982621072">"Isključite način rada u avionu da uvezete kontakte sa SIM kartice."</string>
+ <string name="enable_pin" msgid="5422767284133234860">"Omogući/onemogući PIN za SIM"</string>
+ <string name="change_pin" msgid="9174186126330785343">"Promijeni PIN za SIM"</string>
+ <string name="enter_pin_text" msgid="8532615714751931951">"PIN za SIM:"</string>
+ <string name="oldPinLabel" msgid="5287773661246368314">"Stari PIN"</string>
+ <string name="newPinLabel" msgid="207488227285336897">"Novi PIN"</string>
+ <string name="confirmPinLabel" msgid="257597715098070206">"Potvrdi novi PIN"</string>
+ <string name="badPin" msgid="8955102849303984935">"Stari PIN koji ste upisali nije tačan. Pokušajte ponovo."</string>
+ <string name="mismatchPin" msgid="5923253370683071889">"PIN-ovi koje ste upisali se ne podudaraju. Pokušajte ponovo."</string>
+ <string name="invalidPin" msgid="5981171102258684792">"Unesite PIN koji sadrži od 4 do 8 brojeva."</string>
+ <string name="disable_sim_pin" msgid="3419351358300716472">"Obriši PIN za SIM"</string>
+ <string name="enable_sim_pin" msgid="4845145659651484248">"Postavi PIN za SIM"</string>
+ <string name="enable_in_progress" msgid="3417917024688497010">"Postavljanje PIN-a u toku…"</string>
+ <string name="enable_pin_ok" msgid="2918545971413270063">"PIN je postavljen"</string>
+ <string name="disable_pin_ok" msgid="2109571368635883688">"PIN je obrisan"</string>
+ <string name="pin_failed" msgid="5644377896213584760">"PIN je netačan"</string>
+ <string name="pin_changed" msgid="4455736268023261662">"PIN je ažuriran"</string>
+ <string name="puk_requested" msgid="5921393215789090200">"Lozinka je netačna. PIN je sada blokiran. Traži se PUK."</string>
+ <string name="enter_pin2_text" msgid="8339444124477720345">"PIN2"</string>
+ <string name="oldPin2Label" msgid="8559146795026261502">"Stari PIN2"</string>
+ <string name="newPin2Label" msgid="4573956902204349054">"Novi PIN2"</string>
+ <string name="confirmPin2Label" msgid="8100319484454787708">"Potvrdite novi PIN2"</string>
+ <string name="badPuk2" msgid="7910064009531541708">"PUK2 je pogrešan. Pokušajte ponovo."</string>
+ <string name="badPin2" msgid="6646896629970023109">"Stari PIN2 je netačan. Pokušajte ponovo."</string>
+ <string name="mismatchPin2" msgid="4177967478551851117">"PIN2 kodovi se ne podudaraju. Pokušajte ponovo."</string>
+ <string name="invalidPin2" msgid="1757045131429105595">"Unesite PIN2 koji sadrži od 4 do 8 brojeva."</string>
+ <string name="invalidPuk2" msgid="7059081153334815973">"Unesite PUK2 koji sadrži 8 brojeva."</string>
+ <string name="pin2_changed" msgid="3724522579945610956">"PIN2 je ažuriran"</string>
+ <string name="label_puk2_code" msgid="4688069961795341948">"Unesite PUK2 kȏd"</string>
+ <string name="fdn_enable_puk2_requested" msgid="4991074891459554705">"Lozinka je netačna. PIN2 je sada blokiran. Da pokušate ponovo, promijenite PIN 2."</string>
+ <string name="puk2_requested" msgid="5831015200030161434">"Lozinka je netačna. SIM je sada zaključan. Unesite PUK2."</string>
+ <string name="puk2_blocked" msgid="3150263853077280049">"PUK2 je trajno blokiran."</string>
+ <string name="pin2_attempts" msgid="720736232885011507">\n"Broj preostalih pokušaja: <xliff:g id="NUMBER">%d</xliff:g>."</string>
+ <string name="pin2_unblocked" msgid="7791600368153469078">"PIN2 više nije blokiran"</string>
+ <string name="pin2_error_exception" msgid="1088689322248996699">"Greška s mrežom ili SIM karticom"</string>
+ <string name="doneButton" msgid="2859593360997984240">"Gotovo"</string>
+ <string name="voicemail_settings_number_label" msgid="8524164258691887790">"Broj govorne pošte"</string>
+ <string name="card_title_dialing" msgid="5769417478498348054">"Biranje"</string>
+ <string name="card_title_redialing" msgid="8253487008234167266">"Ponovno biranje"</string>
+ <string name="card_title_conf_call" msgid="1162980346189744501">"Konferencijski poziv"</string>
+ <string name="card_title_incoming_call" msgid="7364539451234646909">"Dolazni poziv"</string>
+ <string name="card_title_call_ended" msgid="5544730338889702298">"Poziv je završen"</string>
+ <string name="card_title_on_hold" msgid="821463117892339942">"Na čekanju"</string>
+ <string name="card_title_hanging_up" msgid="3999101620995182450">"Prekid veze"</string>
+ <string name="card_title_in_call" msgid="6346543933068225205">"Poziv u toku"</string>
+ <string name="notification_voicemail_title" msgid="8933468752045550523">"Nova govorna pošta"</string>
+ <string name="notification_voicemail_title_count" msgid="4366360747660929916">"Nova govorna pošta (<xliff:g id="COUNT">%d</xliff:g>)"</string>
+ <string name="notification_voicemail_text_format" msgid="4447323569453981685">"Pozovi <xliff:g id="VOICEMAIL_NUMBER">%s</xliff:g>"</string>
+ <string name="notification_voicemail_no_vm_number" msgid="760963466895609716">"Nepoznat broj govorne pošte"</string>
+ <string name="notification_network_selection_title" msgid="4224455487793492772">"Nema mreže"</string>
+ <string name="notification_network_selection_text" msgid="2607085729661923269">"Odabrana mreža (<xliff:g id="OPERATOR_NAME">%s</xliff:g>) je nedostupna"</string>
+ <string name="incall_error_power_off" product="watch" msgid="772302793483607711">"Isključite način rada u avionu ili način uštede baterije da uputite poziv."</string>
+ <string name="incall_error_power_off" product="default" msgid="2947938060513306698">"Isključite način rada u avionu da uputite poziv."</string>
+ <string name="incall_error_power_off_wfc" msgid="8711428920632416575">"Isključite način rada u avionu ili se povežite na bežičnu mrežu da uputite poziv."</string>
+ <string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Izađite iz načina rada za hitni povratni poziv da uputite poziv koji nije hitan."</string>
+ <string name="incall_error_emergency_only" msgid="4678640422710818317">"Nije registrirano na mreži."</string>
+ <string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobilna mreža nije dostupna."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
+ <string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Da uputite poziv, upišite važeći broj."</string>
+ <string name="incall_error_call_failed" msgid="5891978320269774095">"Poziv nije uspio."</string>
+ <string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Trenutno nije moguće dodati poziv."</string>
+ <string name="incall_error_supp_service_unknown" msgid="655570339115407698">"Usluga nije podržana"</string>
+ <string name="incall_error_supp_service_switch" msgid="5237002176899962862">"Nije moguće prebacivanje poziva."</string>
+ <string name="incall_error_supp_service_separate" msgid="7224393405134545246">"Nije moguće odvojiti poziv."</string>
+ <string name="incall_error_supp_service_transfer" msgid="7235952238189391438">"Prijenos nije moguć."</string>
+ <string name="incall_error_supp_service_conference" msgid="2505727299596357312">"Nije moguće uspostaviti konferencijske pozive."</string>
+ <string name="incall_error_supp_service_reject" msgid="8998568661508655638">"Nije moguće odbiti poziv."</string>
+ <string name="incall_error_supp_service_hangup" msgid="7434513517153834426">"Nije moguće uputiti poziv(e)."</string>
+ <string name="incall_error_supp_service_hold" msgid="7967020511232222078">"Nije moguće staviti pozive na čekanje."</string>
+ <string name="incall_error_wfc_only_no_wireless_network" msgid="1782466780452640089">"Povežite se na bežičnu mrežu da uputite poziv."</string>
+ <string name="incall_error_promote_wfc" msgid="106510757624022064">"Omogućite Wi-Fi pozivanje da uputite poziv."</string>
+ <string name="emergency_enable_radio_dialog_title" msgid="4627849966634578257">"Hitni poziv"</string>
+ <string name="emergency_enable_radio_dialog_message" msgid="207613549344420291">"Uključivanje radija u toku…"</string>
+ <string name="emergency_enable_radio_dialog_retry" msgid="5960061579996526883">"Nema mreže. Novi pokušaj u toku…"</string>
+ <string name="radio_off_during_emergency_call" msgid="2535800034010306830">"Nije moguće aktivirati način rada u avionu tokom hitnog poziva."</string>
+ <string name="dial_emergency_error" msgid="1509085166367420355">"Nije moguće pozvati. <xliff:g id="NON_EMERGENCY_NUMBER">%s</xliff:g> nije broj za hitne slučajeve."</string>
+ <string name="dial_emergency_empty_error" msgid="9130194953830414638">"Nije moguće pozvati. Birajte broj za hitne slučajeve."</string>
+ <string name="dialerKeyboardHintText" msgid="9192914825413747792">"Koristi tastaturu za biranje"</string>
+ <string name="onscreenHoldText" msgid="2285258239691145872">"Stavi na čekanje"</string>
+ <string name="onscreenEndCallText" msgid="4403855834875398585">"Prekini"</string>
+ <string name="onscreenShowDialpadText" msgid="8561805492659639893">"Telefonska tipkovnica"</string>
+ <string name="onscreenMuteText" msgid="5011369181754261374">"Isključi zvuk poziva"</string>
+ <string name="onscreenAddCallText" msgid="5140385634712287403">"Dodaj poziv"</string>
+ <string name="onscreenMergeCallsText" msgid="6640195098064538950">"Spoji pozive"</string>
+ <string name="onscreenSwapCallsText" msgid="1602990689244030047">"Zamijeni"</string>
+ <string name="onscreenManageCallsText" msgid="5473231160123254154">"Upravljaj pozivima"</string>
+ <string name="onscreenManageConferenceText" msgid="6485935856534311346">"Upravljaj konferenc."</string>
+ <string name="onscreenAudioText" msgid="1710087112800041743">"Zvuk"</string>
+ <string name="onscreenVideoCallText" msgid="4800924186056115442">"Videopoziv"</string>
+ <string name="importSimEntry" msgid="6614358325359736031">"Uvezi"</string>
+ <string name="importAllSimEntries" msgid="1503181169636198673">"Uvezi sve"</string>
+ <string name="importingSimContacts" msgid="7374056215462575769">"Uvoz kontakata sa SIM kartice u toku"</string>
+ <string name="importToFDNfromContacts" msgid="2130620207013368580">"Uvezi iz kontakata"</string>
+ <string name="singleContactImportedMsg" msgid="6868483416182599206">"Kontakt je uvezen"</string>
+ <string name="failedToImportSingleContactMsg" msgid="415399285420353917">"Uvoz kontakta nije uspio"</string>
+ <string name="hac_mode_title" msgid="8740268574688743289">"Slušni aparat"</string>
+ <string name="hac_mode_summary" msgid="6833851160514929341">"Uključi kompatibilnost za slušni aparat"</string>
+ <string-array name="tty_mode_entries">
+ <item msgid="512950011423868021">"TTY je isključen"</item>
+ <item msgid="3971695875449640648">"TTY je pun"</item>
+ <item msgid="1937509904407445684">"TTY HCO"</item>
+ <item msgid="5644925873488772224">"TTY VCO"</item>
+ </string-array>
+ <string name="dtmf_tones_title" msgid="5163153771291340803">"DTMF tonovi"</string>
+ <string name="dtmf_tones_summary" msgid="3351820372864020331">"Postavi dužinu DTMF tonova"</string>
+ <string-array name="dtmf_tone_entries">
+ <item msgid="899650777817315681">"Normalno"</item>
+ <item msgid="2883365539347850535">"Dugo"</item>
+ </string-array>
+ <string name="network_info_message" msgid="7738596060242881930">"Mrežna poruka"</string>
+ <string name="network_error_message" msgid="3394780436230411413">"Poruka o grešci"</string>
+ <string name="ota_title_activate" msgid="8616918561356194398">"Aktivirajte svoj telefon"</string>
+ <string name="ota_touch_activate" msgid="6553212803262586244">"Za aktiviranje telefonske usluge potrebno je uputiti poseban poziv. \n\nNakon što pritisnete „Aktiviraj“, poslušajte uputstva za aktiviranje telefona."</string>
+ <string name="ota_hfa_activation_title" msgid="2234246934160473981">"Aktivacija u toku..."</string>
+ <string name="ota_hfa_activation_dialog_message" msgid="8092479227918463415">"Telefon aktivira uslugu prijenosa mobilnih podataka.\n\nTo može potrajati do 5 minuta."</string>
+ <string name="ota_skip_activation_dialog_title" msgid="2943366608272261306">"Preskočiti aktivaciju?"</string>
+ <string name="ota_skip_activation_dialog_message" msgid="2440770373498870550">"Ako preskočite aktivaciju, nećete moći upućivati pozive niti se povezati na mobilne podatkovne mreže (iako se možete povezati na Wi-Fi mreže). Dok ne aktivirate telefon, prikazivat će se upit za aktivaciju svaki put kada upalite telefon."</string>
+ <string name="ota_skip_activation_dialog_skip_label" msgid="3458532775091563208">"Preskoči"</string>
+ <string name="ota_activate" msgid="1368528132525626264">"Aktiviraj"</string>
+ <string name="ota_title_activate_success" msgid="6570240212263372046">"Telefon je aktiviran."</string>
+ <string name="ota_title_problem_with_activation" msgid="7095824491970084367">"Problem s aktivacijom"</string>
+ <string name="ota_listen" msgid="162923839877584937">"Slijedite govorna uputstva dok ne čujete da je aktivacija završena."</string>
+ <string name="ota_speaker" msgid="6904589278542719647">"Zvučnik"</string>
+ <string name="ota_progress" msgid="460876637828044519">"Programiranje telefona u toku…"</string>
+ <string name="ota_failure" msgid="7713756181204620397">"Nije moguće programirati telefon"</string>
+ <string name="ota_successful" msgid="1880780692887077407">"Vaš telefon je sada aktiviran. Može biti potrebno do 15 minuta za pokretanje usluge."</string>
+ <string name="ota_unsuccessful" msgid="8072141612635635357">"Telefon se nije aktivirao. \nMožda biste trebali pronaći područje s boljom pokrivenošću (pored prozora ili napolju).\n\nPokušajte ponovo ili pozovite službu za korisnike za više opcija."</string>
+ <string name="ota_spc_failure" msgid="3909983542575030796">"GREŠKE PRETJERANOG SPC-a"</string>
+ <string name="ota_call_end" msgid="4537279738134612388">"Nazad"</string>
+ <string name="ota_try_again" msgid="7685477206465902290">"Pokušaj ponovo"</string>
+ <string name="ota_next" msgid="3904945374358235910">"Sljedeće"</string>
+ <string name="ecm_exit_dialog" msgid="4448531867763097533">"EcmExitDialog"</string>
+ <string name="phone_entered_ecm_text" msgid="6266424252578731203">"Aktiviran način rada za hitni povratni poziv"</string>
+ <string name="phone_in_ecm_notification_title" msgid="3226896828951687085">"Način rada za hitni povratni poziv"</string>
+ <string name="phone_in_ecm_call_notification_text" msgid="4611608947314729773">"Podatkovna veza je onemogućena"</string>
+ <plurals name="phone_in_ecm_notification_time" formatted="false" msgid="8308381858502470919">
+ <item quantity="one">Nema podatkovne veze <xliff:g id="COUNT_1">%s</xliff:g> minutu</item>
+ <item quantity="few">Nema podatkovne veze <xliff:g id="COUNT_1">%s</xliff:g> minute</item>
+ <item quantity="other">Nema podatkovne veze <xliff:g id="COUNT_1">%s</xliff:g> minuta</item>
+ </plurals>
+ <plurals name="alert_dialog_exit_ecm" formatted="false" msgid="7179911675595441201">
+ <item quantity="one">Telefon će biti u Načinu rada za hitni povratni poziv <xliff:g id="COUNT_1">%s</xliff:g> minutu. Dok se nalazi u ovom načinu rada, ne mogu se upotrebljavati aplikacije koje koriste podatkovnu vezu. Želite li izaći iz ovog načina rada sada?</item>
+ <item quantity="few">Telefon će biti u Načinu rada za hitni povratni poziv u <xliff:g id="COUNT_1">%s</xliff:g> minute. Dok se nalazi u ovom načinu rada, ne mogu se upotrebljavati aplikacije koje koriste podatkovnu vezu. Želite li izaći iz ovog načina rada sada?</item>
+ <item quantity="other">Telefon će biti u Načinu rada za hitni povratni poziv <xliff:g id="COUNT_1">%s</xliff:g> minuta. Dok se nalazi u ovom načinu rada, ne mogu se upotrebljavati aplikacije koje koriste podatkovnu vezu. Želite li izaći iz ovog načina rada sada?</item>
+ </plurals>
+ <plurals name="alert_dialog_not_avaialble_in_ecm" formatted="false" msgid="8042973425225093895">
+ <item quantity="one">Odabrana radnja nije dostupna u načinu rada za hitni povratni poziv. Telefon će biti u ovom načinu rada <xliff:g id="COUNT_1">%s</xliff:g> minutu. Želite li izaći iz ovog načina rada sada?</item>
+ <item quantity="few">Odabrana radnja nije dostupna u načinu rada za hitni povratni poziv. Telefon će biti u ovom načinu rada <xliff:g id="COUNT_1">%s</xliff:g> minute. Želite li izaći iz ovog načina rada sada?</item>
+ <item quantity="other">Odabrana radnja nije dostupna u načinu rada za hitni povratni poziv. Telefon će biti u ovom načinu rada <xliff:g id="COUNT_1">%s</xliff:g> minuta. Želite li izaći iz ovog načina rada sada?</item>
+ </plurals>
+ <string name="alert_dialog_in_ecm_call" msgid="1886723687211887104">"Odabrana radnja nije dostupna tokom hitnog poziva."</string>
+ <string name="progress_dialog_exiting_ecm" msgid="4835734101617817074">"Izlazak iz načina rada za hitni povratni poziv"</string>
+ <string name="alert_dialog_yes" msgid="6674268047820703974">"Da"</string>
+ <string name="alert_dialog_no" msgid="1476091437797628703">"Ne"</string>
+ <string name="alert_dialog_dismiss" msgid="2491494287075907171">"Odbaci"</string>
+ <string name="voicemail_provider" msgid="5135942703327136909">"Usluga"</string>
+ <string name="voicemail_settings" msgid="72448049107749316">"Postavljanje"</string>
+ <string name="voicemail_number_not_set" msgid="6724904736891087856">"<Nije postavljeno>"</string>
+ <string name="other_settings" msgid="3672912580359716394">"Ostale postavke poziva"</string>
+ <string name="calling_via_template" msgid="4839419581866928142">"Pozivanje putem mreže <xliff:g id="PROVIDER_NAME">%s</xliff:g>"</string>
+ <string name="contactPhoto" msgid="4713193418046639466">"fotografija kontakta"</string>
+ <string name="goPrivate" msgid="865837794424530980">"idi na privatno"</string>
+ <string name="selectContact" msgid="781975788478987237">"odaberi kontakt"</string>
+ <string name="not_voice_capable" msgid="2739898841461577811">"Glasovni pozivi nisu podržani"</string>
+ <string name="description_dial_button" msgid="7459705245418435351">"biraj"</string>
+ <string name="voicemail_notification_vibrate_when_title" msgid="8361970092063604886">"Vibriranje"</string>
+ <string name="voicemail_notification_vibarte_when_dialog_title" msgid="5739583146522136440">"Vibriranje"</string>
+ <string name="voicemail_visual_voicemail_switch_title" msgid="5012622186976275457">"Vizuelna govorna pošta"</string>
+ <string name="voicemail_set_pin_dialog_title" msgid="2797924461029093837">"Postavljanje PIN-a"</string>
+ <string name="voicemail_change_pin_dialog_title" msgid="6035421908626121564">"Promijeni PIN"</string>
+ <string name="voicemail_notification_ringtone_title" msgid="2609519527849101590">"Zvuk"</string>
+ <string name="preference_category_ringtone" msgid="5197960752529332721">"Melodija zvona i vibracija"</string>
+ <string name="pstn_connection_service_label" msgid="1743245930577325900">"Ugrađene SIM kartice"</string>
+ <string name="enable_video_calling_title" msgid="7237253660669000899">"Uključi videopozive"</string>
+ <string name="enable_video_calling_dialog_msg" msgid="8948186136957417948">"Da uključite videopozive, omogućite Poboljšani 4G LTE način rada u postavkama mreže."</string>
+ <string name="enable_video_calling_dialog_settings" msgid="576528473599603249">"Postavke mreže"</string>
+ <string name="enable_video_calling_dialog_close" msgid="7411471282167927991">"Zatvori"</string>
+ <string name="sim_label_emergency_calls" msgid="4847699229529306397">"Hitni pozivi"</string>
+ <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="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>
+ <string name="callFailed_cdma_activation" msgid="2307989779233262164">"SIM kartica je aktivirala vašu uslugu i ažurirala mogućnosti rominga za telefon."</string>
+ <string name="callFailed_cdma_call_limit" msgid="1556916577171457086">"Previše aktivnih poziva. Prekinite ili spojite postojeće pozive prije upućivanja novog poziva."</string>
+ <string name="callFailed_imei_not_accepted" msgid="132192626901238542">"Povezivanje nije moguće, umetnite važeću SIM karticu."</string>
+ <string name="callFailed_wifi_lost" msgid="5968076625137297184">"Wi-Fi veza je prekinuta. Poziv je završen."</string>
+ <string name="change_pin_title" msgid="7790232089699034029">"Promijeni PIN govorne pošte"</string>
+ <string name="change_pin_continue_label" msgid="2135088662420163447">"Nastavi"</string>
+ <string name="change_pin_cancel_label" msgid="353535488390948596">"Otkaži"</string>
+ <string name="change_pin_ok_label" msgid="6204308560844889926">"Uredu"</string>
+ <string name="change_pin_enter_old_pin_header" msgid="419179847657548887">"Potvrdite stari PIN"</string>
+ <string name="change_pin_enter_old_pin_hint" msgid="8579171678763615453">"Za nastavak unesite PIN govorne pošte."</string>
+ <string name="change_pin_enter_new_pin_header" msgid="2611191814590251532">"Postavite novi PIN"</string>
+ <string name="change_pin_enter_new_pin_hint" msgid="2322940054329689309">"PIN mora imati između <xliff:g id="MIN">%1$d</xliff:g> i <xliff:g id="MAX">%2$d</xliff:g> cifri."</string>
+ <string name="change_pin_confirm_pin_header" msgid="8113764019347322170">"Potvrdite PIN"</string>
+ <string name="change_pin_confirm_pins_dont_match" msgid="4795052654904027909">"PIN-ovi se ne podudaraju"</string>
+ <string name="change_pin_succeeded" msgid="2022852286442211151">"PIN govorne pošte je ažuriran"</string>
+ <string name="change_pin_system_error" msgid="8308462387154257840">"Nije moguće postaviti PIN"</string>
+</resources>
diff --git a/res/values-ca/config.xml b/res/values-ca/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ca/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 7035dd3..af1b307 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Falta el número de la bústia de veu"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"No hi ha cap número de bústia de veu emmagatzemat a la targeta SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Afegeix número"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Només l\'usuari principal pot modificar la configuració dels missatges de veu."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"La targeta SIM s\'ha desbloquejat. El telèfon s\'està desbloquejant..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN de desbloqueig de xarxa SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Desbloqueja"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Surt del mode de devolució de trucada d\'emergència per fer un altre tipus de trucada."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"No registrat a la xarxa."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"La xarxa mòbil no està disponible."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"La xarxa mòbil no està disponible. Per fer una trucada, connecta\'t a una xarxa sense fil."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Per realitzar una trucada, introdueix un número vàlid."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"No s\'ha pogut fer la trucada."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"En aquest moment no es pot afegir la trucada."</string>
diff --git a/res/values-cs/config.xml b/res/values-cs/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-cs/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index e145a4b..d78ae5d 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Chybí číslo hlasové schránky"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Na SIM kartě není uloženo žádné číslo hlasové schránky."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Přidat číslo"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Nastavení hlasové schránky může změnit pouze primární uživatel."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM karta byla odblokována. Telefon se odblokovává..."</string>
<string name="label_ndp" msgid="780479633159517250">"Kód PIN odblokování sítě pro SIM kartu"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Odemknout"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Chcete-li uskutečnit běžný hovor, opusťte režim tísňového volání."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Přihlášení k síti nebylo úspěšné."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobilní síť je nedostupná."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobilní síť není k dispozici. Pokud chcete provést hovor, připojte se k bezdrátové síti."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Chcete-li uskutečnit hovor, zadejte platné telefonní číslo."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Volání se nezdařilo."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Hovor teď není možné přidat."</string>
diff --git a/res/values-da/config.xml b/res/values-da/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-da/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 3e2833f..6f9ee3b 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Telefonsvarernummer mangler"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Der er ikke gemt noget telefonsvarernummer på SIM-kortet."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Tilføj nummer"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Indstillingerne for telefonsvareren kan kun ændres af den primære bruger."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Blokeringen af dit SIM-kort er blevet ophævet. Din telefon låser op ..."</string>
<string name="label_ndp" msgid="780479633159517250">"Pinkode til oplåsning af SIM-netværket"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Lås op"</string>
@@ -453,7 +454,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Afslut nødtilbagekaldstilstand for at foretage et almindeligt opkald."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Ikke registreret på netværk."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobilnetværket er ikke tilgængeligt."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobilnetværk er ikke tilgængeligt. Opret forbindelse til et trådløst netværk for at foretage et opkald."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Indtast et gyldigt nummer for at foretage et opkald."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Opkald mislykkedes."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Opkaldet kan ikke tilføjes på nuværende tidspunkt."</string>
diff --git a/res/values-de/config.xml b/res/values-de/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-de/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 983a675..2b598a3 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Fehlende Mailbox-Nummer"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Auf der SIM-Karte ist keine Mailbox-Nummer gespeichert."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Nummer hinzufügen"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Mailboxeinstellungen können nur vom primären Nutzer geändert werden."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Deine SIM-Karte wurde entsperrt. Dein Telefon wird nun entsperrt..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN zur Entsperrung des SIM-Netzwerks"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Entsperren"</string>
@@ -451,7 +452,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Beende den Notfallrückrufmodus, um einen Anruf zu tätigen, bei dem es sich nicht um einen Notfall handelt."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Nicht in Netzwerk registriert."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobilfunknetz ist nicht verfügbar."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Es ist kein Mobilfunknetz verfügbar. Stelle zum Telefonieren eine WLAN-Verbindung her."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Gib eine gültige Nummer ein."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Fehler beim Anruf."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Der Anruf kann momentan nicht hinzugefügt werden."</string>
diff --git a/res/values-el/config.xml b/res/values-el/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-el/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 1b9d28f..bf12f80 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Λείπει ο αριθμός αυτόματου τηλεφωνητή"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Δεν έχει αποθηκευτεί αριθμός για τον αυτόματο τηλεφωνητή στην κάρτα SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Προσθήκη αριθμού"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Οι ρυθμίσεις αυτόματου τηλεφωνητή μπορούν να αλλάξουν μόνο από τον κύριο χρήστη."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Καταργήθηκε ο αποκλεισμός της κάρτας SIM. Το τηλέφωνό σας ξεκλειδώνεται..."</string>
<string name="label_ndp" msgid="780479633159517250">"Αριθμός PIN ξεκλειδώματος δικτύου κάρτας SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Ξεκλείδωμα"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Πραγματοποιήστε έξοδο από τη λειτουργία επιστροφής κλήσης έκτακτης ανάγκης για να πραγματοποιήσετε μια κλήση μη έκτακτης ανάγκης."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Δεν έχετε εγγραφεί στο δίκτυο."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Το δίκτυο κινητής τηλεφωνίας δεν είναι διαθέσιμο."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Το δίκτυο κινητής τηλεφωνίας δεν είναι διαθέσιμο. Συνδεθείτε σε ένα ασύρματο δίκτυο για να πραγματοποιήσετε μια κλήση."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Για να πραγματοποιήσετε κλήση, εισαγάγετε έναν έγκυρο αριθμό."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Η κλήση απέτυχε."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Δεν είναι δυνατή η προσθήκη κλήσης αυτήν τη στιγμή."</string>
diff --git a/res/values-en-rAU/config.xml b/res/values-en-rAU/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-en-rAU/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 4eaa258..e819396 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Missing voicemail number"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"No voicemail number is stored on the SIM card."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Add number"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Voicemail settings can only be modified by the primary user."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Your SIM card has been unblocked. Your phone is unlocking…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM network unlock PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Unlock"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Exit emergency callback mode to make a non-emergency call."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Not registered on network."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobile network not available."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobile network isn\'t available. Connect to a wireless network to make a call."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"To place a call, enter a valid number."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Call failed."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Call cannot be added at the moment."</string>
diff --git a/res/values-en-rGB/config.xml b/res/values-en-rGB/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-en-rGB/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 4eaa258..e819396 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Missing voicemail number"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"No voicemail number is stored on the SIM card."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Add number"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Voicemail settings can only be modified by the primary user."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Your SIM card has been unblocked. Your phone is unlocking…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM network unlock PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Unlock"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Exit emergency callback mode to make a non-emergency call."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Not registered on network."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobile network not available."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobile network isn\'t available. Connect to a wireless network to make a call."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"To place a call, enter a valid number."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Call failed."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Call cannot be added at the moment."</string>
diff --git a/res/values-en-rIN/config.xml b/res/values-en-rIN/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-en-rIN/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 4eaa258..e819396 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Missing voicemail number"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"No voicemail number is stored on the SIM card."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Add number"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Voicemail settings can only be modified by the primary user."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Your SIM card has been unblocked. Your phone is unlocking…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM network unlock PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Unlock"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Exit emergency callback mode to make a non-emergency call."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Not registered on network."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobile network not available."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobile network isn\'t available. Connect to a wireless network to make a call."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"To place a call, enter a valid number."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Call failed."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Call cannot be added at the moment."</string>
diff --git a/res/values-es-rUS/config.xml b/res/values-es-rUS/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-es-rUS/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index becfbd7..f8c5b98 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Falta el número de correo de voz"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"No hay un número de correo de voz almacenado en la tarjeta SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Agregar número"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Solo el usuario principal puede cambiar la configuración del correo de voz."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Tu tarjeta SIM ha sido desbloqueada. Tu dispositivo está desbloqueando..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN de desbloqueo de red de tarjeta SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Desbloquear"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Para realizar una llamada que no sea de emergencia, sal del modo de devolución de llamada de emergencia."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"No registrado en la red."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"La red móvil no está disponible."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"La red móvil no está disponible. Conéctate a una red inalámbrica para realizar una llamada."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Para realizar una llamada, ingresa un número válido."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Error en la llamada"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"No se puede agregar la llamada en este momento."</string>
diff --git a/res/values-es/config.xml b/res/values-es/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-es/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 1aa9d03..6a2849f 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Falta el número del buzón de voz."</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"No se ha almacenado ningún número de buzón de voz en la tarjeta SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Añadir número"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"El usuario principal es el único que puede modificar los ajustes del buzón de voz."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"La tarjeta SIM se ha desbloqueado. El teléfono se está desbloqueando..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN de desbloqueo de red de tarjeta SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Desbloquear"</string>
@@ -451,7 +452,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Sal del modo de devolución de llamada de emergencia para hacer otro tipo de llamada."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"No se ha podido conectar a la red"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"La red móvil no está disponible."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"La red de telefonía móvil no está disponible. Conéctate a una para llamar."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Para realizar una llamada, introduce un número válido."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"No se ha podido llamar."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"No se puede añadir la llamada en este momento."</string>
diff --git a/res/values-et-rEE/arrays.xml b/res/values-et/arrays.xml
similarity index 100%
rename from res/values-et-rEE/arrays.xml
rename to res/values-et/arrays.xml
diff --git a/res/values-et/config.xml b/res/values-et/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-et/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-et-rEE/strings.xml b/res/values-et/strings.xml
similarity index 99%
rename from res/values-et-rEE/strings.xml
rename to res/values-et/strings.xml
index 0e61108..4352332 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Puudub kõnepostinumber"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM-kaardile pole salvestatud ühtegi kõnepostinumbrit."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Lisa number"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Kõneposti seadeid saab muuta ainult peamine kasutaja."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Teie SIM-kaardi blokeering on tühistatud. Teie telefoni avamine ..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM-võrgu avamise PIN-kood"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Ava"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Muude kui hädaabikõne tegemiseks väljuge hädaabikõnede režiimist."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Ei ole võrku registreeritud."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobiilsidevõrk pole saadaval."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobiilsidevõrk pole saadaval. Helistamiseks looge ühendus traadita võrguga."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Helistamiseks sisestage kehtiv number."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Kõne ebaõnnestus."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Kõnet ei saa praegu lisada."</string>
diff --git a/res/values-eu-rES/arrays.xml b/res/values-eu/arrays.xml
similarity index 100%
rename from res/values-eu-rES/arrays.xml
rename to res/values-eu/arrays.xml
diff --git a/res/values-eu/config.xml b/res/values-eu/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-eu/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu/strings.xml
similarity index 99%
rename from res/values-eu-rES/strings.xml
rename to res/values-eu/strings.xml
index 936a693..ad6285a 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Erantzungailuaren zenbakia falta da"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Ez da erantzungailuaren zenbakirik gorde SIM txartelean."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Gehitu zenbakia"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Erabiltzaile nagusiak bakarrik alda ditzake erantzungailuaren ezarpenak."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM txartela desblokeatu da. Telefonoa desblokeatzen…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM sarea desblokeatzeko PIN kodea"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Desblokeatu"</string>
@@ -453,7 +454,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Larrialdikoak ez diren deiak egiteko, irten larrialdi-deiak soilik jasotzeko modutik."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Ez dago sarean erregistratuta."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Sare mugikorra ez dago erabilgarri."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Sare mugikorra ez dago erabilgarri. Deia egiteko, konektatu haririk gabeko sare batera."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Deitzeko, idatzi balio duen zenbaki bat."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Ezin izan da deitu."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Une honetan ezin da gehitu deirik."</string>
diff --git a/res/values-fa/config.xml b/res/values-fa/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-fa/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index c20421e..afb5d4c 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"عدم وجود شماره پست صوتی"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"شماره پست صوتی در سیم کارت ذخیره نشده است."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"افزودن شماره"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"فقط «کاربر اصلی» میتواند «تنظیمات پست صوتی» را تغییر دهد."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"قفل سیم کارت شما باز شده است. قفل گوشی در حال باز شدن است..."</string>
<string name="label_ndp" msgid="780479633159517250">"پین بازگشایی قفل شبکه سیم"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"بازگشایی قفل"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"برای برقراری تماس غیراضطراری از حالت پاسخ تماس اضطراری خارج شوید."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"در شبکه ثبت نشده است."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"شبکهٔ تلفن همراه موجود نیست."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"شبکه تلفن همراه دردسترس نیست. برای برقراری تماس به شبکه بیسیم متصل شوید."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"برای برقراری تماس، یک شماره معتبر وارد کنید."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"تماس ناموفق بود."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"فعلاً نمیتوانید تماس اضافه کنید."</string>
diff --git a/res/values-fi/config.xml b/res/values-fi/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-fi/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 4e511d5..4ac6080 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Puhelinvastaajan numero puuttuu"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM-kortille ei ole tallennettu puhelinvastaajan numeroa."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Lisää numero"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Vain ensisijainen käyttäjä voi muuttaa vastaajan asetuksia."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM-korttisi esto on purettu. Puhelimen lukitusta poistetaan..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM-verkko, PIN-koodin lukituksen poisto"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Poista lukitus"</string>
@@ -451,7 +452,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Poistu hätäpuhelujen takaisinsoittotilasta soittaaksesi muun kuin hätäpuhelun."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Ei rekisteröity verkkoon."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobiiliverkko ei käytettävissä."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobiiliverkko ei ole käytettävissä. Yhdistä langattomaan verkkoon, jos haluat soittaa puhelun."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Soita antamalla kelvollinen numero."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Puhelu epäonnistui."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Puhelua ei voi lisätä juuri nyt."</string>
diff --git a/res/values-fr-rCA/config.xml b/res/values-fr-rCA/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-fr-rCA/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 524dc8b..7493910 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Numéro de messagerie vocale manquant"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Aucun numéro de messagerie vocale n\'est enregistré sur la carte SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Ajouter un numéro"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Seul l\'utilisateur principal peut modifier les paramètres de la messagerie vocale."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Votre carte SIM a été déverrouillée. Votre téléphone est en cours de déverrouillage..."</string>
<string name="label_ndp" msgid="780479633159517250">"NIP de déblocage du réseau SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Déverrouiller"</string>
@@ -451,7 +452,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Quittez le mode de rappel d\'urgence pour effectuer un appel non urgent."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Non enregistré sur le réseau"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Réseau pour mobile non disponible"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Le réseau mobile n\'est pas accessible. Connectez-vous à un réseau sans fil pour effectuer un appel."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Pour faire un appel, entrez un numéro valide."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Échec de l\'appel."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Impossible d\'ajouter l\'appel pour le moment."</string>
diff --git a/res/values-fr/config.xml b/res/values-fr/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-fr/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index d8dd524..05c49a8 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Numéro de messagerie vocale manquant"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Aucun numéro de messagerie vocale n\'est enregistré sur la carte SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Ajouter un numéro"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Seul l\'utilisateur principal de la messagerie vocale peut en modifier les paramètres."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Votre carte SIM a été déverrouillée. Votre téléphone est en cours de déverrouillage..."</string>
<string name="label_ndp" msgid="780479633159517250">"Code PIN de déblocage du réseau SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Déverrouiller"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Veuillez quitter le mode de rappel d\'urgence pour passer un appel standard."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Non enregistré sur le réseau."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Réseau mobile non disponible"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Le réseau mobile n\'est pas disponible. Connectez-vous à un réseau sans fil pour passer un appel."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Pour émettre un appel, veuillez saisir un numéro valide."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Échec de l\'appel."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Impossible d\'ajouter un appel pour le moment."</string>
diff --git a/res/values-gl-rES/arrays.xml b/res/values-gl/arrays.xml
similarity index 100%
rename from res/values-gl-rES/arrays.xml
rename to res/values-gl/arrays.xml
diff --git a/res/values-gl/config.xml b/res/values-gl/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-gl/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl/strings.xml
similarity index 99%
rename from res/values-gl-rES/strings.xml
rename to res/values-gl/strings.xml
index 0fe400f..3a3722a 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Falta o número de correo de voz"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Non hai ningún número de correo de voz almacenado na tarxeta SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Engadir número"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"O usuario principal é o único que pode modificar a configuración do correo de voz."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Desbloqueouse a tarxeta SIM. O teléfono estase desbloqueando..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN de desbloqueo da rede SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Desbloquear"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Sae do modo de devolución de chamada de emerxencia para facer unha chamada que non sexa de emerxencia."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Sen rexistro na rede"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"A rede móbil non está dispoñible."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"A rede móbil non está dispoñible. Conéctate a unha rede sen fíos para facer unha chamada."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Para realizar unha chamada, introduce un número válido."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Produciuse un erro na chamada."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Non se pode engadir a chamada neste momento."</string>
diff --git a/res/values-gu-rIN/arrays.xml b/res/values-gu/arrays.xml
similarity index 100%
rename from res/values-gu-rIN/arrays.xml
rename to res/values-gu/arrays.xml
diff --git a/res/values-gu/config.xml b/res/values-gu/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-gu/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-gu-rIN/strings.xml b/res/values-gu/strings.xml
similarity index 98%
rename from res/values-gu-rIN/strings.xml
rename to res/values-gu/strings.xml
index 5e2e08b..c56e77c 100644
--- a/res/values-gu-rIN/strings.xml
+++ b/res/values-gu/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"વૉઇસમેઇલ નંબર ખૂટે છે"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM કાર્ડ પર કોઈ વૉઇસમેઇલ નંબર સંગ્રહિત નથી."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"નંબર ઉમેરો"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"વૉઇસમેઇલ સેટિંગ્સને ફક્ત પ્રાથમિક વપરાશકર્તા દ્વારા જ સંશોધિત કરી શકાય છે."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"તમારા SIM કાર્ડને અનાવરોધિત કરવામાં આવ્યું છે. તમારા ફોનને અનલૉક કરી રહ્યાં છે…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM નેટવર્ક અનલૉક PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"અનલૉક કરો"</string>
@@ -53,7 +54,8 @@
<string name="requesting_unlock" msgid="6412629401033249351">"નેટવર્ક અનલૉકની વિનંતી કરી રહ્યાં છે…"</string>
<string name="unlock_failed" msgid="6490531697031504225">"નેટવર્ક અનલૉક વિનંતી અસફળ."</string>
<string name="unlock_success" msgid="6770085622238180152">"નેટવર્ક અનલૉક સફળ."</string>
- <string name="mobile_network_settings_not_available" msgid="7355254462995117896">"મોબાઇલ નેટવર્ક સેટિંગ્સ આ વપરાશકર્તા માટે ઉપલબ્ધ નથી"</string>
+ <!-- no translation found for mobile_network_settings_not_available (7355254462995117896) -->
+ <skip />
<string name="labelGSMMore" msgid="5930842194056092106">"GSM કૉલ સેટિંગ્સ"</string>
<string name="labelGsmMore_with_label" msgid="2674012918829238901">"GSM કૉલ સેટિંગ્સ (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
<string name="labelCDMAMore" msgid="1630676740428229339">"CDMA કૉલ સેટિંગ્સ"</string>
@@ -447,7 +449,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"બિન-કટોકટીનો કૉલ કરવા માટે કટોકટી કૉલબૅક મોડમાંથી બહાર નીકળો."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"નેટવર્ક પર નોંધણી કરાયેલ નથી."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"મોબાઇલ નેટવર્ક ઉપલબ્ધ નથી."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"મોબાઇલ નેટવર્ક ઉપલબ્ધ નથી. કૉલ કરવા માટે વાયરલેસ નેટવર્ક સાથે કનેક્ટ કરો."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"કૉલ કરવા માટે, માન્ય નંબર દાખલ કરો."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"કૉલ નિષ્ફળ થયો."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"આ સમયે કૉલ ઉમેરી શકાતો નથી."</string>
diff --git a/res/values-hi/config.xml b/res/values-hi/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-hi/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index c1df472..a17fd10 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"गुम वॉयस मेल नंबर"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"सिम कार्ड पर कोई वॉयस मेल नंबर संग्रहित नहीं है."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"नंबर जोड़ें"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"वॉइसमेल सेटिंग को केवल प्राथमिक उपयोगकर्ता ही बदल सकता है."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"आपका सिम कार्ड अनब्लॉक कर दिया गया है. आपका फ़ोन अनलॉक किया जा रहा है..."</string>
<string name="label_ndp" msgid="780479633159517250">"सिम नेटवर्क अनलॉक पिन"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"अनब्लॉक करें"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"गैर-आपातकालीन कॉल करने के लिए आपातकालीन कॉलबैक मोड से बाहर निकलें."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"नेटवर्क पर पंजीकृत नहीं."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"मोबाइल नेटवर्क उपलब्ध नहीं."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"मोबाइल नेटवर्क उपलब्ध नहीं है. कॉल करने के लिए किसी वायरलेस नेटवर्क से कनेक्ट करें."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"कॉल करने के लिए, मान्य नंबर डालें."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"कॉल विफल."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"इस समय कॉल नहीं जोड़ा जा सकता."</string>
diff --git a/res/values-hr/config.xml b/res/values-hr/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-hr/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 3a8bd6c..b2936a4 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Nedostaje broj govorne pošte"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Na SIM kartici nije spremljen broj govorne pošte."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Dodaj broj"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Postavke govorne pošte može izmijeniti samo primarni korisnik."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Vaša je SIM kartica odblokirana. Telefon se odblokira…"</string>
<string name="label_ndp" msgid="780479633159517250">"Mrežni PIN za otključavanje SIM-a"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Otključaj"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Isključite način hitnih poziva da biste uputili poziv koji nije hitan."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Nije registrirano na mreži."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobilna mreža nije dostupna."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobilna mreža nije dostupna. Povežite se s bežičnom mrežom da biste uputili poziv."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Unesite važeći broj da biste uspostavili poziv."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Poziv nije uspio."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Poziv trenutačno nije moguć."</string>
diff --git a/res/values-hu/config.xml b/res/values-hu/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-hu/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 71dab61..c0cd686 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Hiányzik a hangposta száma"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Nincs hangpostaszám a SIM kártyán."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Szám hozzáadása"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"A hangposta-beállításokat csak az elsődleges felhasználó módosíthatja."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM kártyája letiltása megszűnt. Feloldás folyamatban..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM hálózati függetlenítő PIN kódja"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Feloldás"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Lépjen ki a Segélykérő visszahívása módból nem vészjellegű hívás kezdeményezéséhez."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Nincs regisztrálva a hálózaton."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"A mobilhálózat nem érhető el."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"A mobilhálózat nem érhető el. Hívás indításához csatlakozzon egy vezeték nélküli hálózathoz."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Hívásindításhoz adjon meg egy érvényes számot."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Sikertelen hívás."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Jelenleg nem lehet hívást indítani."</string>
diff --git a/res/values-hy-rAM/arrays.xml b/res/values-hy/arrays.xml
similarity index 100%
rename from res/values-hy-rAM/arrays.xml
rename to res/values-hy/arrays.xml
diff --git a/res/values-hy/config.xml b/res/values-hy/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-hy/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy/strings.xml
similarity index 99%
rename from res/values-hy-rAM/strings.xml
rename to res/values-hy/strings.xml
index 2d55b41..81af46e 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Բացակայում է ձայնային փոստի համարը"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM քարտում ձայնային փոստի ոչ մի համար գրանցված չէ:"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Ավելացնել համար"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Ձայնային փոստի կարգավորումները կարող է փոխել միայն հիմնական օգտագործողը:"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Ձեր SIM քարտը ապակողպված է: Ձեր հեռախոսը ապակողպվում է..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM ցանցով PIN-ի ապակողպում"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Ապակողպել"</string>
@@ -453,7 +454,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Սովորական զանգ կատարելու համար դուրս եկեք շտապ կանչի ռեժիմից։"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Ցանցում գրանցված չէ:"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Բջջային ցանցն անհասանելի է:"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Բջջային ցանցն անհասանելի է: Զանգելու համար միացեք Wi-Fi ցանցին:"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Զանգ կատարելու համար մուտքագրեք ճիշտ համար:"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Զանգը ձախողվեց:"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Այս պահին հնարավոր չէ զանգել:"</string>
diff --git a/res/values-in/config.xml b/res/values-in/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-in/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 315f9a2..c0f7fb8 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Nomor kotak pesan hilang"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Tidak ada nomor kotak pesan tersimpan pada kartu SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Tambahkan nomor"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Setelan Pesan Suara hanya dapat diubah oleh Pengguna Utama."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Kartu SIM Anda tidak lagi dicekal. Ponsel Anda sedang dibuka kuncinya..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN pembuka kunci jaringan SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Buka kunci"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Keluar dari mode telepon balik darurat untuk melakukan panggilan non-darurat."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Tidak terdaftar pada jaringan."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Jaringan seluler tidak tersedia."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Jaringan seluler tidak tersedia. Sambungkan ke jaringan nirkabel untuk melakukan panggilan."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Untuk melakukan panggilan telepon, masukkan nomor yang valid."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Telepon gagal."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Panggilan tidak dapat ditambahkan untuk saat ini."</string>
diff --git a/res/values-is-rIS/arrays.xml b/res/values-is/arrays.xml
similarity index 100%
rename from res/values-is-rIS/arrays.xml
rename to res/values-is/arrays.xml
diff --git a/res/values-is/config.xml b/res/values-is/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-is/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-is-rIS/strings.xml b/res/values-is/strings.xml
similarity index 99%
rename from res/values-is-rIS/strings.xml
rename to res/values-is/strings.xml
index 46bba8c..e20232d 100644
--- a/res/values-is-rIS/strings.xml
+++ b/res/values-is/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Talhólfsnúmer vantar"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Ekkert talhólfsnúmer er vistað á SIM-kortinu."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Bæta númeri við"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Aðeins aðalnotandinn má breyta talhólfsstillingum."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Opnað var fyrir SIM-kortið. Verið er að opna símann…"</string>
<string name="label_ndp" msgid="780479633159517250">"PIN-númer SIM-korts til að opna síma"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Taka úr lás"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Hætta í stillingu fyrir svarhringingu neyðarsímtala til að hringja símtal sem ekki er neyðarsímtal."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Ekki skráð á símkerfi."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Farsímakerfi ekki tiltækt."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Farsímakerfi er ekki tiltækt. Tengstu þráðlausu neti til að hringja."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Sláðu inn gilt númer til að hringja símtal."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Tókst ekki að hringja."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Ekki er hægt að bæta símtali við sem stendur."</string>
diff --git a/res/values-it/config.xml b/res/values-it/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-it/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index d39446c..c08e9f1 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Numero segreteria mancante"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Nessun numero di segreteria presente nella SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Aggiungi numero"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Le impostazioni della segreteria possono essere modificate solo dall\'utente principale."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"La SIM è stata sbloccata. Sblocco del telefono..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN sblocco rete SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Sblocca"</string>
@@ -451,7 +452,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Per effettuare chiamate non di emergenza, esci dalla modalità di richiamata di emergenza."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Non registrato sulla rete."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Rete cellulare non disponibile."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"La rete cellulare non è disponibile. Connettiti a una rete wireless per effettuare una chiamata."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Per effettuare una chiamata, inserisci un numero valido."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Chiamata non riuscita."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Al momento non è possibile aggiungere la chiamata."</string>
diff --git a/res/values-iw/config.xml b/res/values-iw/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-iw/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index c253d95..720386d 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"חסר מספר של דואר קולי"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"בכרטיס ה-SIM לא מאוחסן מספר של דואר קולי."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"הוסף מספר"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"רק המשתמש הראשי יכול לשנות את ההגדרות של הדואר הקולי."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"בוטלה החסימה של כרטיס SIM. מבטל את חסימת הטלפון..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN לביטול נעילה של רשת SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"בטל נעילה"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"עליך לצאת ממצב חירום של התקשרות חזרה כדי לבצע שיחות שאינן שיחות חירום."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"לא רשום ברשת."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"הרשת הסלולרית אינה זמינה."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"הרשת הסלולרית לא זמינה. עליך להתחבר לרשת אלחוטית כדי להתקשר."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"כדי להתקשר, הזן מספר טלפון חוקי."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"השיחה נכשלה."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"לא ניתן להוסיף את השיחה כרגע."</string>
diff --git a/res/values-ja/config.xml b/res/values-ja/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ja/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 8b8b1cc..09114e2 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"ボイスメール番号がありません"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIMカードにボイスメールの番号がありません。"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"番号を追加"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"ボイスメール設定を変更できるのはメインユーザーのみに限られています。"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIMカードロックを解除しました。端末のロックを解除しています..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIMネットワークのロック解除PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"ロック解除"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"緊急通報以外の通話を発信するには、緊急通報待機モードを終了してください。"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"ご加入の通信サービスがありません"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"モバイルネットワークが利用できません。"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"モバイル ネットワークを利用できません。電話をかけるにはワイヤレス ネットワークに接続してください。"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"発信するには、有効な番号を入力してください。"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"発信できませんでした。"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"現在、通話を追加できません。"</string>
diff --git a/res/values-ka-rGE/arrays.xml b/res/values-ka/arrays.xml
similarity index 100%
rename from res/values-ka-rGE/arrays.xml
rename to res/values-ka/arrays.xml
diff --git a/res/values-ka/config.xml b/res/values-ka/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ka/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka/strings.xml
similarity index 99%
rename from res/values-ka-rGE/strings.xml
rename to res/values-ka/strings.xml
index 9d1415e..60a9ba7 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"ხმოვანი ფოსტის ნომერი არ არის"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM ბარათზე ხმოვანი ფოსტის ნომერი შენახული არ არის."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"ნომრის დამატება"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"ხმოვანი ფოსტის პარამეტრების შეცვლა მხოლოდ ძირითად მომხმარებელს შეუძლია."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"თქვენი SIM ბარათი განიბლოკა. მიმდინარეობს თქვენი ტელეფონის განბლოკვა…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM ქსელის განბლოკვის PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"განბლოკვა"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"გამოდით გადაუდებელი გადმორეკვის რეჟიმიდან არაგადაუდებელი ზარის განსახორციელებლად."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"ქსელში რეგისტრირებული არ არის."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"მობილური ქსელი მიუწვდომელია."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"მობილური ქსელი მიუწვდომელია. ზარის განსახორციელებლად დაუკავშირდით უსადენო ქსელს."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"ზარის განხორციელებისათვის, შეიყვანეთ მოქმედი ნომერი."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"ზარი ვერ განხორციელდა."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"ამჯერად ზარის დამატება ვერ ხერხდება."</string>
diff --git a/res/values-kk-rKZ/arrays.xml b/res/values-kk/arrays.xml
similarity index 100%
rename from res/values-kk-rKZ/arrays.xml
rename to res/values-kk/arrays.xml
diff --git a/res/values-kk/config.xml b/res/values-kk/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-kk/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk/strings.xml
similarity index 99%
rename from res/values-kk-rKZ/strings.xml
rename to res/values-kk/strings.xml
index 427342b..c9d5aa9 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Дауыс хабарының нөмірі жоқ"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM картасында ешқандай дауыс хабарының нөмірі сақталмаған."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Нөмір қосу"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Дауыстық пошта параметрлерін тек негізгі пайдаланушы өзгерте алады."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM картаңыз ашылды. Телефоныңыздың бекітпесі ашылуда…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM желісін ашатын PIN код"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Бекітпесін ашу"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Төтенше емес қоңырау шалу үшін төтенше қоңырауды кері шалу режимінен шығыңыз."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Желіде тіркелмеген."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Ұялы желі қол жетімсіз."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Мобильдік желі қолжетімді емес. Қоңырау шалу үшін сымсыз желіге қосылыңыз."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Қоңырау шалу үшін жарамды нөмірді енгізіңіз."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Қоңырау шалынбады."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Қоңырауды қазіргі уақытта қосу мүмкін емес."</string>
diff --git a/res/values-km-rKH/arrays.xml b/res/values-km/arrays.xml
similarity index 100%
rename from res/values-km-rKH/arrays.xml
rename to res/values-km/arrays.xml
diff --git a/res/values-km/config.xml b/res/values-km/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-km/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-km-rKH/strings.xml b/res/values-km/strings.xml
similarity index 99%
rename from res/values-km-rKH/strings.xml
rename to res/values-km/strings.xml
index 0f4aab1..1c90391 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"បាត់ចំនួនសារជាសំឡេង"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"គ្មានចំនួនសារជាសំឡេងត្រូវបានរក្សាទុកនៅលើស៊ីមកាតទេ។"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"បន្ថែមលេខ"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"មានតែអ្នកប្រើប្រាស់ចម្បងទើបអាចកែប្រែការកំណត់សារជាសំឡេងបាន។"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"បានដោះសោស៊ីមកាតរបស់អ្នក។ ទូរស័ព្ទរបស់អ្នកកំពុងដោះសោ…"</string>
<string name="label_ndp" msgid="780479633159517250">"ដោះសោកូដ PIN បណ្ដាញស៊ីមកាត"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"ដោះសោ"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"ចាកចេញពីរបៀបហៅទៅវិញពេលមានអាសន្នដើម្បីធ្វើការហៅធម្មតា។"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"មិនបានចុះឈ្មោះនៅលើបណ្ដាញ។"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"បណ្ដាញឧបករណ៍ចល័តមិនអាចប្រើបាន។"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"មិនមានបណ្តាញទូរសព្ទទេ។ ភ្ជាប់ទៅបណ្តាញឥតខ្សែ ដើម្បីអាចហៅទូរសព្ទបាន។"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"ដើម្បីធ្វើការហៅ បញ្ចូលលេខដែលមានសុពលភាព។"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"បានបរាជ័យការហៅ។"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"មិនអាចបន្ថែមការហៅទូរសព្ទនៅពេលនេះបានទេ។"</string>
diff --git a/res/values-kn-rIN/arrays.xml b/res/values-kn/arrays.xml
similarity index 100%
rename from res/values-kn-rIN/arrays.xml
rename to res/values-kn/arrays.xml
diff --git a/res/values-kn/config.xml b/res/values-kn/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-kn/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn/strings.xml
similarity index 99%
rename from res/values-kn-rIN/strings.xml
rename to res/values-kn/strings.xml
index ae6c76f..55d4f0a 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"ಧ್ವನಿಮೇಲ್ ಸಂಖ್ಯೆಯು ಕಾಣೆಯಾಗಿದೆ"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"ಸಿಮ್ ಕಾರ್ಡ್ನಲ್ಲಿ ಯಾವುದೇ ಧ್ವನಿಮೇಲ್ ಸಂಖ್ಯೆಯನ್ನು ಸಂಗ್ರಹಿಸಿಲ್ಲ."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"ಸಂಖ್ಯೆಯನ್ನು ಸೇರಿಸಿ"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"ಧ್ವನಿಮೇಲ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಕೇವಲ ಪ್ರಾಥಮಿಕ ಬಳಕೆದಾರರು ಮಾತ್ರ ಮಾರ್ಪಡಿಸಬಹುದು."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"ನಿಮ್ಮ ಸಿಮ್ ಕಾರ್ಡ್ನ ನಿರ್ಬಂಧವನ್ನು ತೆಗೆಯಲಾಗಿದೆ. ನಿಮ್ಮ ಫೋನ್ ಅನ್ಲಾಕ್ ಆಗುತ್ತಿದೆ…"</string>
<string name="label_ndp" msgid="780479633159517250">"ಸಿಮ್ ನೆಟ್ವರ್ಕ್ನ ಅನ್ಲಾಕ್ ಮಾಡುವ ಪಿನ್"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"ಅನ್ಲಾಕ್"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"ತುರ್ತು ರಹಿತ ಕರೆಯನ್ನು ಮಾಡಲು ತುರ್ತು ಮರು ಕರೆಮಾಡುವಿಕೆ ಮೋಡ್ ಅನ್ನು ನಿರ್ಗಮಿಸಿ."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"ನೆಟ್ವರ್ಕ್ನಲ್ಲಿ ಇನ್ನೂ ನೋಂದಣಿಯಾಗಿಲ್ಲ."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ ಲಭ್ಯವಿಲ್ಲ."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"ಮೊಬೈಲ್ ನೆಟ್ವರ್ಕ್ ಲಭ್ಯವಿಲ್ಲ. ಕರೆ ಮಾಡಲು ವೈರ್ಲೆಸ್ ನೆಟ್ವರ್ಕ್ಗೆ ಸಂಪರ್ಕಪಡಿಸಿ."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"ಕರೆಯನ್ನು ಮಾಡಲು, ಮಾನ್ಯವಾದ ಸಂಖ್ಯೆಯನ್ನು ನಮೂದಿಸಿ."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"ಕರೆ ವಿಫಲವಾಗಿದೆ."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"ಕರೆಯನ್ನು ಈ ಸಮಯದಲ್ಲಿ ಸೇರಿಸಲಾಗುವುದಿಲ್ಲ."</string>
diff --git a/res/values-ko/config.xml b/res/values-ko/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ko/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index e5455f6..fab8041 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"음성사서함 번호 없음"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM 카드에 저장된 음성사서함 번호가 없습니다."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"번호 추가"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"기본 사용자만 음성사서함 설정을 변경할 수 있습니다."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM 카드의 잠금이 해제되었습니다. 휴대전화의 잠금해제 중..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM 네트워크 잠금해제 PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"잠금해제"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"일반 전화를 걸려면 긴급 콜백 모드를 해제하세요."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"네트워크에서 등록되지 않았습니다."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"모바일 네트워크를 사용할 수 없습니다."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"모바일 네트워크를 사용할 수 없습니다. 전화를 걸려면 무선 네트워크에 연결하세요."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"전화를 걸려면 올바른 번호를 입력하세요."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"전화 연결 실패"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"현재 통화를 추가할 수 없습니다."</string>
diff --git a/res/values-ky-rKG/arrays.xml b/res/values-ky/arrays.xml
similarity index 100%
rename from res/values-ky-rKG/arrays.xml
rename to res/values-ky/arrays.xml
diff --git a/res/values-ky/config.xml b/res/values-ky/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ky/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky/strings.xml
similarity index 99%
rename from res/values-ky-rKG/strings.xml
rename to res/values-ky/strings.xml
index 328ff12..83af801 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky/strings.xml
@@ -46,7 +46,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Үн почтасынын номери жок болуп жатат"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM-картада сакталган үн почтасынын номери жок."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Номер кошуу"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Үн почта жөндөөлөрүн алгачкы колдонуучу гана өзгөртө алат."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM-картаңыз бөгөттөн чыгарылган. Телефонуңуздун кулпусу ачылууда…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM-карта тармагынын кулпусун ачуучу PIN код"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Кулпусун ачуу"</string>
@@ -451,7 +452,8 @@
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Тармакта катталган эмес."</string>
<!-- no translation found for incall_error_out_of_service (8587993036435080418) -->
<skip />
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Мобилдик тармак жеткиликтүү эмес. Чалуу үчүн зымсыз тармакка туташыңыз."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Чалуу үчүн, жарактуу номер киргизиңиз."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Чалынбай калды."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Бул жолу чалууну кошуу мүмкүн эмес."</string>
diff --git a/res/values-lo-rLA/arrays.xml b/res/values-lo/arrays.xml
similarity index 100%
rename from res/values-lo-rLA/arrays.xml
rename to res/values-lo/arrays.xml
diff --git a/res/values-lo/config.xml b/res/values-lo/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-lo/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo/strings.xml
similarity index 99%
rename from res/values-lo-rLA/strings.xml
rename to res/values-lo/strings.xml
index 153ea70..70387cf 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"ບໍ່ມີເບີຂໍ້ຄວາມສຽງ"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"ບໍ່ມີເບີຂໍ້ຄວາມສຽງຖືກບັນທຶກໃນ SIM card."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"ເພີ່ມໝາຍເລກ"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"ການຕັ້ງຄ່າຂໍ້ຄວາມສຽງສາມາດແກ້ໄຂໄດ້ໂດຍຜູ້ໃຊ້ຫຼັກເທົ່ານັ້ນ."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"ຍົກເລີກການປິດກັ້ນ SIM card ຂອງທ່ານແລ້ວ. ໂທລະສັບຂອງທ່ານກຳລັງຖືກປົດລັອກ..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN ປົດລັອກເຄືອຂ່າຍ SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"ປົດລັອກ"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"ອອກຈາກໂໝດໂທກັບສຸກເສີນ ເພື່ອເຮັດການໂທປົກກະຕິ."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"ບໍ່ໄດ້ລົງທະບຽນໃນເຄືອຂ່າຍ."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"ເຄືອຂ່າຍມືຖືບໍ່ສາມາດໃຊ້ໄດ້."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"ບໍ່ສາມາດໃຊ້ອິນເຕີເນັດມືຖືໄດ້. ກະລຸນາເຊື່ອມຕໍ່ຫາ Wi-Fi ເພື່ອໂທ."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"ເພື່ອທີ່ຈະໂທ, ປ້ອນເບີໂທທີ່ໃຊ້ໄດ້ເຂົ້າໄປ."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"ໂທບໍ່ສຳເລັດ."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"ບໍ່ສາມາດເພີ່ມການໂທໄດ້ໃນເວລານີ້."</string>
diff --git a/res/values-lt/config.xml b/res/values-lt/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-lt/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 23d7d13..3d44653 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Trūksta balso pašto numerio"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kortelėje nėra išsaugoto balso pašto numerio."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Pridėti numerį"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Balso pašto nustatymus gali keisti tik pagrindinis naudotojas."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Jūsų SIM kortelė buvo atblokuota. Atrakinamas telefonas..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM tinklo atrakinimo PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Atblokuoti"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Jei norite skambinti ne pagalbos numeriu, išjunkite atgalinio skambinimo pagalbos numeriu režimą."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Neregistruota tinkle."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobilusis tinklas negalimas."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobiliojo ryšio tinklas nepasiekiamas. Prisijunkite prie belaidžio ryšio tinklo, kad galėtumėte skambinti."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Kad galėtumėte paskambinti, įveskite tinkamą numerį."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Paskambinti nepavyko."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Šiuo metu skambučio atlikti negalima."</string>
diff --git a/res/values-lv/config.xml b/res/values-lv/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-lv/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 08ad8f0..8c87fe2 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Trūkst balss pasta numura"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kartē neviens balss pasta numurs nav saglabāts."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Pievienot numuru"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Tikai galvenais lietotājs var mainīt balss pasta iestatījumus."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM karte ir atbloķēta. Notiek tālruņa atbloķēšana..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM tīkla atbloķēšanas PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Atbloķēt"</string>
@@ -449,7 +450,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Lai veiktu parastu zvanu, izejiet no ārkārtas atzvana režīma."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Tīklā nav reģistrēts."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobilais tīkls nav pieejams."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobilais tīkls nav pieejams. Lai veiktu zvanu, izveidojiet savienojumu ar bezvadu tīklu."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Lai veiktu zvanu, ievadiet derīgu numuru."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Zvans neizdevās."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Pašlaik nevar pievienot zvanu."</string>
diff --git a/res/values-mcc262-mnc01/strings.xml b/res/values-mcc262-mnc01/strings.xml
new file mode 100644
index 0000000..0765a73
--- /dev/null
+++ b/res/values-mcc262-mnc01/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Status hint label for an incoming call over a wifi network which has not been accepted yet.
+ DO NOT TRANSLATE. -->
+ <string name="status_hint_label_incoming_wifi_call">WLAN Call from</string>
+ <!-- Status hint label for a call being made over a wifi network. DO NOT TRANSLATE. -->
+ <string name="status_hint_label_wifi_call">WLAN Call</string>
+</resources>
diff --git a/res/values-mk-rMK/arrays.xml b/res/values-mk/arrays.xml
similarity index 100%
rename from res/values-mk-rMK/arrays.xml
rename to res/values-mk/arrays.xml
diff --git a/res/values-mk/config.xml b/res/values-mk/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-mk/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk/strings.xml
similarity index 99%
rename from res/values-mk-rMK/strings.xml
rename to res/values-mk/strings.xml
index 40382bb..427c450 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Недостасува број на говорна пошта"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Нема мемориран број на говорна пошта на СИМ картичката."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Додај број"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Поставките за говорна пошта може да ги измени само примарниот корисник."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Вашата СИМ картичка е одблокирана. Вашиот телефон се отклучува..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN за отклучување мрежа на СИМ"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Отклучи"</string>
@@ -453,7 +454,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Излезете од режимот на итен повратен повик за да направите обичен повик."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Не е регистриран на мрежа."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Не е достапна мобилна мрежа."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Не е достапна мобилна мрежа. Поврзете се на безжична мрежа за да повикате."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"За да повикате, внесете важечки број."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Повикот не успеа."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Повикот не може да се додаде во моментов."</string>
diff --git a/res/values-ml-rIN/arrays.xml b/res/values-ml/arrays.xml
similarity index 100%
rename from res/values-ml-rIN/arrays.xml
rename to res/values-ml/arrays.xml
diff --git a/res/values-ml/config.xml b/res/values-ml/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ml/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml/strings.xml
similarity index 98%
rename from res/values-ml-rIN/strings.xml
rename to res/values-ml/strings.xml
index 4c4bbce..c7b51ea 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"വോയ്സ്മെയിൽ നമ്പർ കാണുന്നില്ല"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"സിം കാർഡിൽ വോയ്സ്മെയിൽ നമ്പറൊന്നും സംഭരിച്ചിട്ടില്ല."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"നമ്പർ ചേർക്കുക"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"പ്രാഥമിക ഉപയോക്താവിന് മാത്രമേ വോയ്സ്മെയിൽ ക്രമീകരണം പരിഷ്ക്കരിക്കാനാവൂ."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"സിം കാർഡ് തടഞ്ഞത് മാറ്റി. നിങ്ങളുടെ ഫോൺ അൺലോക്കുചെയ്യുന്നു…"</string>
<string name="label_ndp" msgid="780479633159517250">"സിം നെറ്റ്വർക്ക് അൺലോക്ക് പിൻ"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"അൺലോക്കുചെയ്യുക"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"അടിയന്തിരമല്ലാത്ത കോൾ ചെയ്യാൻ അടിയന്തിര കോൾബാക്ക് മോഡിൽ നിന്ന് പുറത്തുകടക്കുക."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"നെറ്റ്വർക്കിൽ രജിസ്റ്റർ ചെയ്തിട്ടില്ല."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"മൊബൈൽ നെറ്റ്വർക്ക് ലഭ്യമല്ല."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"മൊബൈൽ നെറ്റ്വർക്ക് ലഭ്യമല്ല. കോൾ വിളിക്കാൻ വയർലെസ്സ് നെറ്റ്വർക്കിലേക്ക് കണക്റ്റുചെയ്യുക."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"ഒരു കോൾ ചെയ്യുന്നതിന്, സാധുതയുള്ള നമ്പർ നൽകുക."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"കോൾ ചെയ്യാനായില്ല."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"കോൾ ഇപ്പോൾ ചേർക്കാനാകില്ല."</string>
diff --git a/res/values-mn-rMN/arrays.xml b/res/values-mn/arrays.xml
similarity index 100%
rename from res/values-mn-rMN/arrays.xml
rename to res/values-mn/arrays.xml
diff --git a/res/values-mn/config.xml b/res/values-mn/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-mn/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn/strings.xml
similarity index 99%
rename from res/values-mn-rMN/strings.xml
rename to res/values-mn/strings.xml
index afb0e83..c9be114 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Дуут шуудангийн дугаар байхгүй"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM карт дээр дуут шуудангийн дугаар хадгалагдаагүй байна."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Дугаар нэмэх"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Дуут шуудангийн тохиргоог зөвхөн Үндсэн хэрэглэгч өөрчлөх боломжтой."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Таны SIM карт тайлагдлаа. Таны утас тайлагдаж байна…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM сүлжээ тайлах PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Тайлах"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Яаралтай түргэн тусламжийн бус дуудлага хийхийн тулд яаралтай түргэн тусламжийн callback горимоос гарна уу."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Сүлжээнд бүртгэгдээгүй."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Мобайль сүлжээ байхгүй."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Мобайл сүлжээнд холбогдох боломжгүй байна. Дуудлага хийхийн тулд утасгүй интернетэд холбогдоно уу."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Дуудлага хийхийн тулд хүчин төгөлдөр дугаар оруулна уу."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Дуудлага амжилтгүй болсон."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Одоо дуудлага нэмэх боломжгүй."</string>
diff --git a/res/values-mr-rIN/arrays.xml b/res/values-mr/arrays.xml
similarity index 100%
rename from res/values-mr-rIN/arrays.xml
rename to res/values-mr/arrays.xml
diff --git a/res/values-mr/config.xml b/res/values-mr/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-mr/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr/strings.xml
similarity index 99%
rename from res/values-mr-rIN/strings.xml
rename to res/values-mr/strings.xml
index 3192746..88f59f3 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"व्हॉइसमेल नंबर गहाळ"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"सिम कार्डवर कोणताही व्हॉइसमेल नंबर संचयित केला नाही."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"नंबर जोडा"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"केवळ प्राथमिक वापरकर्ता व्हॉइसमेल सेटिंग्ज बदलू शकतो."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"आपले सिम कार्ड अवरोधित करणे रद्द केले गेले आहे. आपला फोन अनलॉक होत आहे…"</string>
<string name="label_ndp" msgid="780479633159517250">"सिम नेटवर्क अनलॉक पिन"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"अनलॉक करा"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"आणीबाणी नसलेला कॉल करण्यासाठी आणीबाणी कॉलबॅक मोडमधून बाहेर पडा."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"नेटवर्कवर नोंदणीकृत नाही."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"मोबाइल नेटवर्क उपलब्ध नाही."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"मोबाइल नेटवर्क उपलब्ध नाही. कॉल करण्यासाठी वायरलेस नेटवर्कशी कनेक्ट करा."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"कॉल करण्यासाठी, एक वैध नंबर प्रविष्ट करा."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"कॉल अयशस्वी झाला."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"यावेळी कॉल जोडला जाऊ शकत नाही."</string>
diff --git a/res/values-ms-rMY/arrays.xml b/res/values-ms/arrays.xml
similarity index 100%
rename from res/values-ms-rMY/arrays.xml
rename to res/values-ms/arrays.xml
diff --git a/res/values-ms/config.xml b/res/values-ms/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ms/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms/strings.xml
similarity index 99%
rename from res/values-ms-rMY/strings.xml
rename to res/values-ms/strings.xml
index 2a36a7f..5b22850 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Nombor mel suara tiada"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Tidak ada nombor mel suara disimpan pada kad SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Tambah nombor"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Tetapan Mel Suara hanya boleh diubah suai oleh Pengguna Utama."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Kad SIM anda telah dinyahsekat. Telefon anda dibuka kunci..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN buka kunci rangkaian SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Buka kunci"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Keluar daripada mod panggil balik kecemasan untuk membuat panggilan bukan kecemasan."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Tidak didaftarkan pada rangkaian."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Rangkaian mudah alih tidak tersedia."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Rangkaian selular tidak tersedia. Sambung ke rangkaian wayarles untuk membuat panggilan."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Untuk membuat panggilan, masukkan nombor yang sah."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Panggilan gagal."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Panggilan tidak boleh ditambahkan pada masa ini."</string>
diff --git a/res/values-my-rMM/arrays.xml b/res/values-my/arrays.xml
similarity index 100%
rename from res/values-my-rMM/arrays.xml
rename to res/values-my/arrays.xml
diff --git a/res/values-my/config.xml b/res/values-my/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-my/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-my-rMM/strings.xml b/res/values-my/strings.xml
similarity index 99%
rename from res/values-my-rMM/strings.xml
rename to res/values-my/strings.xml
index e474d23..07eb615 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"အသံစာပို့စနစ် နံပါတ် ပျောက်နေပါသည်"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"ဆင်းမ်ကဒ်ပေါ်တွင် အသံစာပို့စနစ် နံပါတ် သိမ်းဆည်ထားခြင်း မရှိပါ"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"နံပါတ်ထပ်ထည့်ရန်"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"အသံမေးလ်ဆက်တင်များကို အဓိကအသုံးပြုသူသာ ပြင်ဆင်နိုင်ပါသည်။"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"သင့် ဆင်းမ်ကဒ်အား ပိတ်ဆို့မှုကို ဖယ်ရှားပြီးပါပြီ။ သင့်ဖုန်းဟာ သော့ဖွင့်နေပါသည်…"</string>
<string name="label_ndp" msgid="780479633159517250">"ဆင်းမ်ကဒ် ကွန်ရက် သော့ဖွင့်သော ပင်နံပါတ်"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"ဖွင့်ရန်"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"အရေးပေါ် မဟုတ်သည့် ခေါ်ဆိုမှုကို ပြုလုပ်ရန် အရေးပေါ် ဖုန်းခေါ်မှုမှ ထွက်ပါ။"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"ကွန်ယက်ပေါ်မှာ မှတ်ပုံတင်မှု မပြုလုပ်ထားပါ"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"မိုဘိုင်းကွန်ယက်များ မရှိပါ"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"မိုဘိုင်းကွန်ရက် မရနိုင်ပါ။ ခေါ်ဆိုမှုပြုလုပ်ရန် ကြိုးမဲ့ကွန်ရက်သို့ ချိတ်ဆက်လိုက်ပါ။"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"ဖုန်းခေါ်ရန်အတွက်၊ သင့်လျော်သည့်နံပါတ် ရိုက်ထည့်ပါ။"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"ခေါ်ဆို၍ မရပါ။"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"ယခုအချိန်တွင် ခေါ်ဆိုမှု ထပ်မထည့်နိုင်ပါ။"</string>
diff --git a/res/values-nb/config.xml b/res/values-nb/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-nb/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index c6f7344..d528a6b 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Mangler nummer til talepostkasse"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Det er ikke lagret noe nummer for talepostkasse på SIM-kortet."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Legg til nummer"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Talepost-innstillinger kan bare endres av hovedbrukeren."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM-kortet er blitt avblokkert. Telefonen låses opp…"</string>
<string name="label_ndp" msgid="780479633159517250">"PIN-kode for å fjerne operatørlås"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Lås opp"</string>
@@ -453,7 +454,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Avslutt modusen for nødanrop for å gjøre et vanlig anrop."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Ikke registrert på nettverket."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobilnettverket er ikke tilgjengelig."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobilnettverk er ikke tilgjengelig. Koble til et trådløst nettverk for å ringe."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Skriv inn et gyldig nummer for å plassere en samtale."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Anropet mislyktes."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Anropet kan ikke legges til akkurat nå."</string>
diff --git a/res/values-ne-rNP/arrays.xml b/res/values-ne/arrays.xml
similarity index 100%
rename from res/values-ne-rNP/arrays.xml
rename to res/values-ne/arrays.xml
diff --git a/res/values-ne/config.xml b/res/values-ne/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ne/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne/strings.xml
similarity index 98%
rename from res/values-ne-rNP/strings.xml
rename to res/values-ne/strings.xml
index b0cdc8d..1bba620 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"भ्वाइसमेल नम्बर हराइरहेको छ"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM कार्डमा कुनै पनि भ्वाइसमेल नम्बर भण्डारण भएको छैन।"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"नम्बर थप्नुहोस्"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"प्राथमिक प्रयोगकर्ताले मात्र भ्वाइस मेल सेटिङहरू परिमार्जन गर्न सक्नुहुन्छ।"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"तपाईँको SIM कार्ड अनब्लक गरिएको छ। तपाईँको फोन अनलक हुँदैछ ..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM नेटवर्क अनलक PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"अनलोक गर्नुहोस्"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"गैर-आपतकालीन कल गर्न आपतकालीन कलब्याक मोडबाट निस्कनुहोस्।"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"नेटवर्कमा दर्ता भएको छैन।"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"मोबाइल नेटवर्क उपलब्ध छैन।"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"मोबाइल नेटवर्क उपलब्ध छैन। कल गर्न तारविनाको नेटवर्कमा जडान गर्नुहोस्।"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"एक कल गर्नको लागि, एक वैध नम्बर प्रविष्ट गर्नुहोस्।"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"कल विफल भयो।"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"यतिबेला कल थप गर्न सकिँदैन।"</string>
diff --git a/res/values-nl/config.xml b/res/values-nl/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-nl/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 49c3cb5..d01b280 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Voicemailnummer ontbreekt"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Er is geen voicemailnummer op de SIM-kaart opgeslagen."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Nummer toevoegen"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Voicemailinstellingen kunnen alleen worden gewijzigd door de primaire gebruiker."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Je SIM-kaart is gedeblokkeerd. Je telefoon wordt ontgrendeld..."</string>
<string name="label_ndp" msgid="780479633159517250">"Pincode voor ontgrendelen SIM-netwerk"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Ontgrendelen"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Sluit de modus voor noodoproepen af om een niet-noodoproep te plaatsen."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Niet geregistreerd op netwerk."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobiel netwerk niet beschikbaar."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobiel netwerk is niet beschikbaar. Maak verbinding met een draadloos netwerk om te bellen."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Als je wilt bellen, moet je een geldig nummer invoeren."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Oproep mislukt."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Oproep kan momenteel niet worden toegevoegd."</string>
diff --git a/res/values-pa-rIN/arrays.xml b/res/values-pa/arrays.xml
similarity index 100%
rename from res/values-pa-rIN/arrays.xml
rename to res/values-pa/arrays.xml
diff --git a/res/values-pa/config.xml b/res/values-pa/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-pa/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-pa-rIN/strings.xml b/res/values-pa/strings.xml
similarity index 98%
rename from res/values-pa-rIN/strings.xml
rename to res/values-pa/strings.xml
index 152ca45..3473363 100644
--- a/res/values-pa-rIN/strings.xml
+++ b/res/values-pa/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"ਲੁਪਤ ਵੌਇਸਮੇਲ ਨੰਬਰ"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM ਕਾਰਡ ਤੇ ਕੋਈ ਵੌਇਸਮੇਲ ਨੰਬਰ ਸਟੋਰ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ।"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"ਨੰਬਰ ਜੋੜੋ"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"ਵੌਇਸਮੇਲ ਸੈਟਿੰਗਾਂ ਸਿਰਫ਼ ਪ੍ਰਾਇਮਰੀ ਵਰਤੋਂਕਾਰ ਦੁਆਰਾ ਹੀ ਸੰਸ਼ੋਧਿਤ ਕੀਤੀਆਂ ਜਾ ਸਕਦੀਆਂ ਹਨ।"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"ਤੁਹਾਡਾ SIM ਕਾਰਡ ਅਨਬਲੌਕ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ। ਤੁਹਾਡਾ ਫੋਨ ਅਨੌਲਕ ਹੋ ਰਿਹਾ ਹੈ..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM ਨੈਟਵਰਕ ਅਨਲੌਕ PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"ਅਨਲੌਕ ਕਰੋ"</string>
@@ -53,7 +54,8 @@
<string name="requesting_unlock" msgid="6412629401033249351">"ਨੈਟਵਰਕ ਅਨਲੌਕ ਦੀ ਬੇਨਤੀ ਕਰ ਰਿਹਾ ਹੈ…"</string>
<string name="unlock_failed" msgid="6490531697031504225">"ਨੈਟਵਰਕ ਅਨਲੌਕ ਬੇਨਤੀ ਅਸਫਲ।"</string>
<string name="unlock_success" msgid="6770085622238180152">"ਨੈਟਵਰਕ ਅਨਲੌਕ ਸਫਲ।"</string>
- <string name="mobile_network_settings_not_available" msgid="7355254462995117896">"ਇਸ ਵਰਤੋਂਕਾਰ ਲਈ ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਸੈਟਿੰਗਾਂ ਉਪਲਬਧ ਨਹੀਂ ਹਨ"</string>
+ <!-- no translation found for mobile_network_settings_not_available (7355254462995117896) -->
+ <skip />
<string name="labelGSMMore" msgid="5930842194056092106">"GSM ਕਾਲ ਸੈਟਿੰਗਾਂ"</string>
<string name="labelGsmMore_with_label" msgid="2674012918829238901">"GSM ਕਾਲ ਸੈਟਿੰਗਾਂ (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
<string name="labelCDMAMore" msgid="1630676740428229339">"CDMA ਕਾਲ ਸੈਟਿੰਗਾਂ"</string>
@@ -447,7 +449,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"ਇੱਕ ਗ਼ੈਰ-ਅਪਾਤਕਾਲ ਕਾਲ ਕਰਨ ਲਈ ਅਪਾਤਕਾਲ ਕਾਲਬੈਕ ਮੋਡ ਤੋਂ ਬਾਹਰ ਆਓ।"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"ਨੈਟਵਰਕ ਤੇ ਰਜਿਸਟਰ ਨਹੀਂ ਕੀਤਾ।"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"ਮੋਬਾਈਲ ਨੈਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ।"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"ਮੋਬਾਈਲ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ। ਕਾਲ ਕਰਨ ਲਈ ਕਿਸੇ ਵਾਇਰਲੈੱਸ ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕਰੋ।"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"ਇੱਕ ਕਾਲ ਕਰਨ ਲਈ, ਇੱਕ ਪ੍ਰਮਾਣਿਕ ਨੰਬਰ ਦਰਜ ਕਰੋ।"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"ਕਾਲ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ।"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"ਇਸ ਵੇਲੇ ਕਾਲ ਸ਼ਾਮਲ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ।"</string>
diff --git a/res/values-pl/config.xml b/res/values-pl/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-pl/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 5833897..c99bf4d 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Brakuje numeru poczty głosowej"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Na karcie SIM nie ma zapisanego numeru poczty głosowej."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Dodaj numer"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Ustawienia poczty głosowej może zmienić tylko użytkownik główny."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Karta SIM została odblokowana. Odblokowywanie telefonu..."</string>
<string name="label_ndp" msgid="780479633159517250">"Kod PIN do karty SIM odblokowujący sieć"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Odblokuj"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Aby zadzwonić normalnie, wyjdź z trybu alarmowego połączenia zwrotnego."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Nie zarejestrowano w sieci"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Sieć komórkowa jest niedostępna."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Sieć komórkowa jest niedostępna. Połącz się z siecią bezprzewodową, by zadzwonić."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Aby zadzwonić, wybierz prawidłowy numer."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Nie udało się połączyć."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Nie można w tej chwili dodać połączenia."</string>
diff --git a/res/values-pt-rPT/config.xml b/res/values-pt-rPT/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-pt-rPT/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index f304dba..d23bc92 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Número do correio de voz em falta"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Não existe um número de correio de voz armazenado no cartão SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Adicionar número"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"As definições do correio de voz só podem ser modificadas pelo utilizador principal."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"O cartão SIM foi desbloqueado. O telefone está a ser desbloqueado..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN para desbloqueio de rede do cartão SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Desbloquear"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Sair do modo de chamada de retorno de emergência para efetuar uma chamada que não é de emergência."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Sem registo na rede."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Rede móvel não disponível."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"A rede móvel não está disponível. Ligue-se a uma rede sem fios para efetuar uma chamada."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Para telefonar, introduza um número válido."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"A chamada falhou."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Não é possível adicionar a chamada neste momento."</string>
diff --git a/res/values-pt/config.xml b/res/values-pt/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-pt/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 94bbb35..3280423 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Número correio de voz ausente"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Não há um número correio de voz armazenado no cartão SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Adicionar número"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"As configurações do correio de voz só podem ser modificadas pelo usuário principal."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"O seu cartão SIM foi desbloqueado. O seu telefone está desbloqueando…"</string>
<string name="label_ndp" msgid="780479633159517250">"PIN de desbloqueio da rede SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Desbloquear"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Saia do modo de retorno de chamada de emergência para fazer uma chamada que não seja de emergência."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Não registrado na rede."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Rede móvel não disponível."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"A rede móvel não está disponível. Conecte-se a uma rede sem fio para fazer uma chamada."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Para realizar uma chamada, digite um número válido."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Falha na chamada."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"No momento, não é possível adicionar a chamada."</string>
diff --git a/res/values-ro/config.xml b/res/values-ro/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ro/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index d0d73e7..835c255 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Lipsește numărul mesageriei vocale"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Niciun număr de mesagerie vocală nu este stocat pe cardul SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Adăugați numărul"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Setările pentru mesagerie vocală pot fi modificate numai de utilizatorul principal."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Cardul dvs. SIM a fost deblocat. Telefonul dvs. se deblochează..."</string>
<string name="label_ndp" msgid="780479633159517250">"Codul PIN de deblocare a rețelei SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Deblocați"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Ieșiți din modul de apelare inversă de urgență pentru a efectua un apel care nu este de urgență."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Neînregistrat în rețea."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Rețeaua mobilă nu este disponibilă."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Rețeaua mobilă nu este disponibilă. Pentru a apela, conectați-vă la o rețea wireless."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Pentru a apela, introduceți un număr valid."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Apelul nu a fost inițiat."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Apelul nu poate fi adăugat în acest moment."</string>
diff --git a/res/values-ru/config.xml b/res/values-ru/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ru/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 744ff7a..4d81465 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Не указан номер голосовой почты"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"На SIM-карте нет ни одного номера голосовой почты."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Добавить номер"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Настройки голосовой почты может изменить только основной пользователь"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM-карта разблокирована. Осуществляется разблокировка телефона..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN для разблокировки сети SIM-карты"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Разблокировать"</string>
@@ -449,7 +450,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Чтобы сделать обычный звонок, выйдите из режима экстренных обратных вызовов."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Нет регистрации в сети."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Мобильная сеть недоступна."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Мобильная сеть недоступна. Чтобы позвонить, подключитесь к Wi-Fi."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Недействительный номер."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Не удалось отправить вызов."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Невозможно позвонить в данный момент."</string>
diff --git a/res/values-si-rLK/arrays.xml b/res/values-si/arrays.xml
similarity index 100%
rename from res/values-si-rLK/arrays.xml
rename to res/values-si/arrays.xml
diff --git a/res/values-si/config.xml b/res/values-si/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-si/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-si-rLK/strings.xml b/res/values-si/strings.xml
similarity index 98%
rename from res/values-si-rLK/strings.xml
rename to res/values-si/strings.xml
index cdc3078..3daa529 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"හඬ තැපැල් අංකය නැත"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM කාඩ් පතෙහි හඬ තැපැල් අංකයක් ආචිත වී නැත."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"අංකයක් එක් කරන්න"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"හඬ තැපැල් සැකසීම් මූලික පරිශීලක විසින් පමණක් වෙනස් කිරීමට හැකිය."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"ඔබගේ SIM කාඩ්පත අඟුළු හැර තිබේ. ඔබගේ දුරකතනයේ අඟුළු හරිමින්…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM ජාල අඟුළු හැරීමේ PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"අඟුල අරින්න"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"හදිසි-නොවන ඇමතුමක් සිදු කිරීමට හදිසි අවස්ථා පසු ඇමතුම් ප්රකාරයෙන් ඉවත් වන්න."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"ජාලය මත ලියාපදිංචි වී නැත."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"ජංගම ජාලය නොමැත."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"ජංගම ජාලය ලබා ගැනීමට නොහැකිය. ඇමතුමක් කිරීමට රැහැන් රහිත ජාලයකට සම්බන්ධ කරන්න."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"ඇමතුමක් ලබාගැනීමට, වලංගු අංකයක් ලබාගන්න."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"ඇමතුම අසාර්ථක විය."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"ඇමතුම මේ අවස්ථාවේදී එක් කළ නොහැකිය."</string>
diff --git a/res/values-sk/config.xml b/res/values-sk/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-sk/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 014ebed..7e701ff 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Chýba číslo hlasovej schránky"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Na SIM karte nie je uložené žiadne číslo hlasovej schránky."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Pridať číslo"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Nastavenia hlasovej schránky môže zmeniť iba primárny používateľ."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM karta bola odblokovaná. Prebieha odomykanie telefónu..."</string>
<string name="label_ndp" msgid="780479633159517250">"Kód PIN odomknutia siete pre SIM kartu"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Odomknúť"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Ak chcete volať štandardným spôsobom, ukončite režim tiesňového spätného volania."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Prihlásenie do siete nebolo úspešné."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobilná sieť nie je k dispozícii."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobilná sieť nie je k dispozícii. Ak chcete volať, pripojte sa k bezdrôtovej sieti."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Ak chcete volať, zadajte platné číslo"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Hovor zlyhal."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Hovor momentálne nie je možné pridať."</string>
diff --git a/res/values-sl/config.xml b/res/values-sl/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-sl/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 639885c..baf1c6a 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Manjkajoča številka glasovne pošte"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Na kartici SIM ni shranjena številka glasovne pošte."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Dodaj številko"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Nastavitve odzivnika lahko spremeni samo primarni uporabnik."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Kartica SIM je bila deblokirana. Telefon se odklepa ..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN za odklep omrežja kartice SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Odkleni"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Če ne gre za klic v sili, zaprite način za povratni klici v sili."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Ni registrirano v omrežju."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Omrežje prenosnega telefona ni na voljo."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobilno omrežje ni na voljo. Če želite opraviti klic, vzpostavite povezavo z brezžičnim omrežjem."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Če želite opraviti klic, vnesite veljavno številko."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Klic ni uspel."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Klica trenutno ni mogoče dodati."</string>
diff --git a/res/values-sq-rAL/arrays.xml b/res/values-sq/arrays.xml
similarity index 100%
rename from res/values-sq-rAL/arrays.xml
rename to res/values-sq/arrays.xml
diff --git a/res/values-sq/config.xml b/res/values-sq/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-sq/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-sq-rAL/strings.xml b/res/values-sq/strings.xml
similarity index 98%
rename from res/values-sq-rAL/strings.xml
rename to res/values-sq/strings.xml
index 054108a..e01e260 100644
--- a/res/values-sq-rAL/strings.xml
+++ b/res/values-sq/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Mungon numri i postës zanore"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Nuk ka numër të ruajtur në kartën SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Shto numër"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Cilësimet e postës zanore mund të modifikohen vetëm nga \"Përdoruesi kryesor\""</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Karta jote SIM u zhbllokua. Telefoni yt po shkyçet..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN-i i shkyçjes së rrjetit të kartës SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Shkyçe"</string>
@@ -53,7 +54,8 @@
<string name="requesting_unlock" msgid="6412629401033249351">"Po kërkon shkyçjen e rrjetit…"</string>
<string name="unlock_failed" msgid="6490531697031504225">"Kërkesa për shkyçjen e rrjetit ishte e pasuksesshme."</string>
<string name="unlock_success" msgid="6770085622238180152">"Shkyçja e rrjetit ishte e suksesshme."</string>
- <string name="mobile_network_settings_not_available" msgid="7355254462995117896">"Cilësimet e rrjetit celular nuk ofrohen për këtë përdorues"</string>
+ <!-- no translation found for mobile_network_settings_not_available (7355254462995117896) -->
+ <skip />
<string name="labelGSMMore" msgid="5930842194056092106">"Cilësimet e telefonatës GSM"</string>
<string name="labelGsmMore_with_label" msgid="2674012918829238901">"Cilësimet e telefonatës GSM (<xliff:g id="SUBSCRIPTIONLABEL">%s</xliff:g>)"</string>
<string name="labelCDMAMore" msgid="1630676740428229339">"Cilësimet e telefonatës CDMA"</string>
@@ -447,7 +449,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Dil nga modaliteti i kthimit të telefonatës së urgjencës për të bërë një telefonatë jo urgjente."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"I paregjistruar në rrjet."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Rrjeti celular nuk mundësohet."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Rrjeti celular nuk ofrohet. Lidhu me një rrjet pa tel për të bërë një telefonatë."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Për të kryer një telefonatë, fut një numër të vlefshëm."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Thirrja dështoi."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Telefonata nuk mund të shtohet këtë herë."</string>
diff --git a/res/values-sr/config.xml b/res/values-sr/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-sr/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 8f3fbc1..66e10a1 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Недостаје број за говорну пошту"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Није ускладиштен ниједан број говорне поште на SIM картици."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Додај број"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Само примарни корисник може да мења подешавања говорне поште."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Ваша SIM картица је одблокирана. Телефон се откључава..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN за откључавање мреже на SIM картици"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Откључај"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Изађите из режима хитног повратног позива да бисте упутили позив који није хитан."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Није регистровано на мрежи."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Мобилна мрежа није доступна."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Мобилна мрежа није доступна. Повежите се на бежичну да бисте упутили позив."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Да бисте упутили позив, унесите важећи број."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Позив није успео."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Тренутно није могуће додати позив."</string>
diff --git a/res/values-sv/config.xml b/res/values-sv/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-sv/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 6713a7f..7b3ccdf 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Nummer till röstbrevlåda saknas"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Det finns inget nummer till röstbrevlådan sparat på SIM-kortet."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Lägg till nummer"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Endast den primära användaren får ändra röstbrevlådans inställningar."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM-kortets spärr har tagits bort. Låser upp telefonen…"</string>
<string name="label_ndp" msgid="780479633159517250">"PIN-kod för upplåsning av SIM-nätverk"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Lås upp"</string>
@@ -453,7 +454,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Avsluta läget för återuppringning vid nödsamtal om du vill ringa ett vanligt samtal."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Inte registrerat på nätverk."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Inget mobilt nätverk är tillgängligt."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Det finns inga tillgängliga mobilnätverk. Anslut till ett trådlöst nätverk om du vill ringa."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Ange ett giltigt nummer om du vill ringa ett samtal."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Det gick inte att koppla samtalet."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Det går inte att lägga till samtalet just nu."</string>
diff --git a/res/values-sw/config.xml b/res/values-sw/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-sw/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index ed62747..3369839 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Nambari ya sauti inayokosekana"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Hakuna nambari ya ujumbe wa sauti iliyohifadhiwa katika SIM kadi."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Ongeza nambari"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Mipangilio ya ujumbe wa sauti inaweza kubadilishwa na Mtumiaji wa Msingi Pekee."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Kadi yako ya simu imefunguliwa. Simu yangu inafungua…."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN ya kufungua mtandao wa SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Fungua"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Ondoka kwenye hali ya kupiga simu za dharura ili upige simu zisizokuwa za dharura."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Haijasajiliwa kwa mitandao"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mtandao wa simu haupatikani."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mtandao wa simu za mkononi haupatikani. Unganisha kwenye mtandao pasiwaya ili upige simu."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Ili upige simu, weka nambari sahihi."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Imeshindwa kupiga simu."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Hangout haiwezi kuongezwa kwa wakati huu."</string>
diff --git a/res/values-ta-rIN/arrays.xml b/res/values-ta/arrays.xml
similarity index 100%
rename from res/values-ta-rIN/arrays.xml
rename to res/values-ta/arrays.xml
diff --git a/res/values-ta/config.xml b/res/values-ta/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ta/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta/strings.xml
similarity index 99%
rename from res/values-ta-rIN/strings.xml
rename to res/values-ta/strings.xml
index 92eb0ca..3d6b09d 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"குரலஞ்சல் எண் இல்லை"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"சிம் கார்டில் குரலஞ்சலுக்கான எண் எதுவும் சேமிக்கப்படவில்லை."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"எண்ணைச் சேர்"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"முதன்மை பயனர் மட்டுமே குரலஞ்சல் அமைப்புகளை மாற்ற முடியும்."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"சிம் கார்டின் தடுப்பு நீக்கப்பட்டது. மொபைல் திறக்கப்படுகிறது…"</string>
<string name="label_ndp" msgid="780479633159517250">"சிம் நெட்வொர்க்கின் தடைநீக்க பின்"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"தடைநீக்கு"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"வழக்கமான அழைப்பிற்கு, அவசரகாலத் திரும்ப அழைக்கும் பயன்முறையிலிருந்து வெளியேறவும்."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"நெட்வொர்க்கில் பதிவுசெய்யப்படவில்லை."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"மொபைல் நெட்வொர்க் கிடைக்கவில்லை."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"மொபைல் நெட்வொர்க் கிடைக்கவில்லை. அழைக்க, வயர்லெஸ் நெட்வொர்க்குடன் இணைக்கவும்."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"அழைக்க, சரியான எண்ணை உள்ளிடவும்."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"அழைப்பு தோல்வியடைந்தது."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"இப்போது அழைப்பைச் சேர்க்க முடியாது."</string>
diff --git a/res/values-te-rIN/arrays.xml b/res/values-te/arrays.xml
similarity index 100%
rename from res/values-te-rIN/arrays.xml
rename to res/values-te/arrays.xml
diff --git a/res/values-te/config.xml b/res/values-te/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-te/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-te-rIN/strings.xml b/res/values-te/strings.xml
similarity index 98%
rename from res/values-te-rIN/strings.xml
rename to res/values-te/strings.xml
index 2dcfdf3..9848c67 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"వాయిస్ మెయిల్ నంబర్ లేదు"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"సిమ్ కార్డులో వాయిస్ మెయిల్ నంబర్ ఏదీ నిల్వ చేయబడలేదు."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"నంబర్ను జోడించు"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"వాయిస్ మెయిల్ సెట్టింగ్లను ప్రాథమిక వినియోగదారు మాత్రమే సవరించగలరు."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"మీ SIM కార్డు అన్బ్లాక్ చేయబడింది. మీ ఫోన్ అన్లాక్ చేయబడుతోంది…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM నెట్వర్క్ అన్లాక్ పిన్"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"అన్లాక్ చేయి"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"సాధారణ కాల్ చేయడానికి అత్యవసర కాల్బ్యాక్ మోడ్ నుండి నిష్క్రమించండి."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"నెట్వర్క్లో నమోదు కాలేదు."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"మొబైల్ నెట్వర్క్ అందుబాటులో లేదు."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"మొబైల్ నెట్వర్క్ అందుబాటులో లేదు. కాల్ చేయడానికి వైర్లెస్ నెట్వర్క్కు కనెక్ట్ చేయండి."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"కాల్ చేయడానికి, చెల్లుబాటు అయ్యే నంబర్ను నమోదు చేయండి."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"కాల్ విఫలమైంది."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"ఈ సమయంలో కాల్ను జోడించడం సాధ్యపడదు."</string>
diff --git a/res/values-th/config.xml b/res/values-th/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-th/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 9508583..7d9c311 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"ไม่มีหมายเลขข้อความเสียง"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"ไม่มีหมายเลขข้อความเสียงจัดเก็บอยู่ในซิมการ์ด"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"เพิ่มหมายเลข"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"ผู้ใช้หลักเท่านั้นที่สามารถเปลี่ยนการตั้งค่าข้อความเสียงได้"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"ยกเลิกการปิดกั้นซิมการ์ดแล้ว กำลังปลดล็อกโทรศัพท์ของคุณ..."</string>
<string name="label_ndp" msgid="780479633159517250">"PIN ปลดล็อกเครือข่ายซิม"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"ปลดล็อก"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"โปรดออกจากโหมดการโทรกลับกรณีฉุกเฉินเพื่อโทรไปยังหมายเลขที่ไม่ใช่หมายเลขฉุกเฉิน"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"ยังไม่ได้ลงทะเบียนบนเครือข่าย"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"เครือข่ายมือถือใช้งานไม่ได้"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"เครือข่ายมือถือไม่พร้อมใช้งาน โปรดเชื่อมต่อเครือข่ายไร้สายเพื่อโทรออก"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"หากต้องการโทรออก โปรดป้อนหมายเลขที่ถูกต้อง"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"การโทรล้มเหลว"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"ไม่สามารถเพิ่มสายได้ในขณะนี้"</string>
diff --git a/res/values-tl/config.xml b/res/values-tl/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-tl/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 267fb98..a0339f9 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Nawawala ang numero ng voicemail"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Walang nakaimbak na numero ng voicemail sa SIM card."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Magdagdag ng numero"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Maaari lang baguhin ng Pangunahing User ang Mga Setting ng Voicemail."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Naalis sa pagkaka-block ang iyong SIM card. Nag-a-unlock ang iyong telepono…"</string>
<string name="label_ndp" msgid="780479633159517250">"PIN na pang-unlock ng SIM network"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"I-unlock"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Lumabas sa emergency callback mode upang makapagsagawa ng hindi pang-emergency na pagtawag."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Hindi nakarehistro sa network."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Hindi available ang mobile network."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Hindi available ang mobile network. Kumonekta sa isang wireless network upang tumawag."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Upang tumawag, maglagay ng wastong numero."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Nabigo ang tawag."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Hindi maidaragdag ang tawag sa oras na ito."</string>
diff --git a/res/values-tr/config.xml b/res/values-tr/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-tr/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 41bafec..cc44ec0 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Eksik sesli mesaj numarası"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kartta depolanan sesli mesaj numarası yok."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Numara ekle"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Sesli Mesaj Ayarları yalnızca Birincil Kullanıcı tarafından değiştirilebilir."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"SIM kartınızın engellemesi kaldırıldı. Telefonunuzun kilidi açılıyor..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM ağı kilit açma PIN kodu"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Kilit Aç"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Acil durum çağrısı dışında bir çağrı yapmak için acil durumda geri aranma modundan çıkın."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Ağda kayıtlı değil."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mobil ağ kullanılamıyor."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobil ağ kullanılamıyor. Telefon etmek için kablosuz ağa bağlanın."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Arama yapmak için geçerli bir numara girin."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Sesli arama başarısız oldu."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Çağrı şu anda eklenemiyor."</string>
diff --git a/res/values-uk/config.xml b/res/values-uk/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-uk/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 3ee546e..32c1bae 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Відстуній номер голосової пошти"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"На SIM-карті немає збереж. номерів голос. пошти."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Додати номер"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Налаштування голосової пошти може змінювати лише основний користувач."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Вашу SIM-карту розблоковано. Ваш телефон розблоковується..."</string>
<string name="label_ndp" msgid="780479633159517250">"Розбл. PIN-код мережі SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Розблок."</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Щоб зателефонувати на звичайний номер, вимкніть режим екстрених викликів."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Не зареєстровано в мережі."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Мобільна мережа недоступна."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Мобільна мережа недоступна. Щоб зателефонувати, під’єднайтеся до бездротової мережі."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Щоб зателефонувати, введіть дійсний номер."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Не вдалося здійснити виклик."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Зараз не можна додати виклик."</string>
diff --git a/res/values-ur-rPK/arrays.xml b/res/values-ur/arrays.xml
similarity index 100%
rename from res/values-ur-rPK/arrays.xml
rename to res/values-ur/arrays.xml
diff --git a/res/values-ur/config.xml b/res/values-ur/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-ur/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur/strings.xml
similarity index 99%
rename from res/values-ur-rPK/strings.xml
rename to res/values-ur/strings.xml
index 7178e84..7c202d5 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"صوتی میل نمبر درج نہیں ہے"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM کارڈ پر کوئی بھی صوتی میل نمبر اسٹور نہیں ہے۔"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"نمبر شامل کریں"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"صرف بنیادی صارف ہی صوتی میل کی ترتیبات تبدیل کر سکتا ہے۔"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"آپ کا SIM کارڈ غیر مسدود ہوگیا ہے۔ آپ کا فون غیر مقفل ہو رہا ہے…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM نیٹ ورک غیر مقفل کرنے کا PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"غیر مقفل کریں"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"غیر ہنگامی کال کرنے کیلئے ہنگامی کال بیک موڈ سے اخراج کریں۔"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"نیٹ ورک پر رجسٹرڈ نہیں ہے۔"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"موبائل نیٹ ورک دستیاب نہیں ہے۔"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"موبائل نیٹ ورک دستیاب نہیں ہے۔ کال کرنے کیلئے کسی وائرلیس نیٹ ورک سے منسلک ہوں۔"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"کال کرنے کیلئے، ایک درست نمبر درج کریں۔"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"کال ناکام ہوگئی۔"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"اس وقت کال شامل نہیں ہو سکتی۔"</string>
diff --git a/res/values-uz-rUZ/arrays.xml b/res/values-uz/arrays.xml
similarity index 100%
rename from res/values-uz-rUZ/arrays.xml
rename to res/values-uz/arrays.xml
diff --git a/res/values-uz/config.xml b/res/values-uz/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-uz/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz/strings.xml
similarity index 99%
rename from res/values-uz-rUZ/strings.xml
rename to res/values-uz/strings.xml
index a8a6fa2..8352f57 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Ovozli pochta raqami ko‘rsatilmagan"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM kartada birorta ham ovozli pochta raqami yo‘q."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Raqam qo‘shish"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Ovozli pochta sozlamalarini faqat bosh foydalanuvchi o‘zgartira oladi."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"To‘sib qo‘yilgan SIM kartangiz ochildi. Telefoningiz qulfdan chiqarilmoqda…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM kartani tarmoqdagi qulfidan chiqarish PIN kodi"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Qulfdan chiqarish"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Odatiy qo‘ng‘iroq qilish uchun favqulodda qayta qo‘ng‘iroq rejimidan chiqing."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Tarmoqda ro‘yxatdan o‘tmagan."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Uyali tarmoq mavjud emas."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Mobil tarmoqdan foydalanib bo‘lmaydi. Qo‘ng‘iroq qilish uchun Wi-Fi tarmog‘iga ulaning."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Qo‘ng‘iroq qilish uchun raqamni to‘g‘ri kiriting."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Qo‘ng‘iroq amalga oshmadi."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Hozirgi vaqtda qo‘ng‘iroq qo‘shib bo‘lmaydi."</string>
diff --git a/res/values-vi/config.xml b/res/values-vi/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-vi/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 52b5dea..3d0fa4a 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Thiếu số thư thoại"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Không có số thư thoại nào được lưu trữ trên thẻ SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Thêm số điện thoại"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Chỉ người dùng chính mới có thể sửa đổi Cài đặt thư thoại."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Thẻ SIM của bạn đã được bỏ chặn. Điện thoại của bạn đang mở khóa…"</string>
<string name="label_ndp" msgid="780479633159517250">"Mã PIM mở khóa mạng SIM"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Mở khóa"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Thoát khỏi chế độ gọi lại khẩn cấp để thực hiện cuộc gọi không khẩn cấp."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Chưa được đăng ký trên mạng."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Mạng di động không khả dụng."</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Hiện không có mạng di động. Hãy kết nối với mạng không dây để thực hiện cuộc gọi."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Để thực hiện cuộc gọi, hãy nhập một số hợp lệ."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Cuộc gọi không thành công."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Không thể thêm cuộc gọi tại thời điểm này."</string>
diff --git a/res/values-zh-rCN/config.xml b/res/values-zh-rCN/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-zh-rCN/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 90e5fa0..50cb074 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"缺少语音信箱号码"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM卡上未存储语音信箱号码。"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"添加号码"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"只有主用户才能修改语音信箱设置。"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"您的SIM卡已解锁。正在解锁您的手机..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM网络解锁PIN码"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"解锁"</string>
@@ -447,7 +448,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"要拨打非紧急电话,请先退出紧急回拨模式。"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"尚未注册网络。"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"无法连接到移动网络"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"移动网络不可用。需连接至无线网络才能拨打电话。"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"要拨打电话,请输入有效的电话号码。"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"无法通话。"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"目前无法添加通话。"</string>
diff --git a/res/values-zh-rHK/config.xml b/res/values-zh-rHK/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-zh-rHK/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 9810965..1eddb7c 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"未填留言信箱號碼"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM 卡中沒有儲存任何留言信箱號碼。"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"新增電話號碼"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"只有主要使用者可以修改留言設定。"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"您的 SIM 卡已解除封鎖。您的手機正在解除鎖定..."</string>
<string name="label_ndp" msgid="780479633159517250">"SIM 網絡解除鎖定 PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"解除鎖定"</string>
@@ -453,7 +454,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"離開緊急回撥模式即可撥打非緊急電話。"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"未在網絡上完成註冊。"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"無法使用流動網絡。"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"無法使用流動網絡。請連接無線網絡,以撥打電話。"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"要撥打電話,請輸入有效的號碼。"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"無法接通。"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"目前無法新增通話。"</string>
diff --git a/res/values-zh-rTW/config.xml b/res/values-zh-rTW/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-zh-rTW/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index b96048a..ba0eb2a 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"遺失語音信箱號碼"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"SIM 卡中未儲存語音信箱號碼。"</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"新增號碼"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"只有主要使用者可以修改語音信箱設定。"</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"您的 SIM 卡已解鎖。正在解鎖手機中…"</string>
<string name="label_ndp" msgid="780479633159517250">"SIM 網路解鎖 PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"解除鎖定"</string>
@@ -453,7 +454,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"結束緊急回撥模式,以便撥打非緊急電話。"</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"尚未註冊網路。"</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"無法使用 Google 行動服務網路。"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"無法使用行動網路。連上 Wi-Fi 網路即可撥打電話。"</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"如要撥打電話,請輸入有效的號碼。"</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"無法通話。"</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"目前無法新增通話。"</string>
diff --git a/res/values-zu/config.xml b/res/values-zu/config.xml
new file mode 100644
index 0000000..509a3c8
--- /dev/null
+++ b/res/values-zu/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<!-- NOTE: Many variables that used to be in this file have been migrated to
+ CarrierConfigManager.java. Please consider whether new variables belong
+ there before adding to this file. Variables here should be more closely
+ related to devices than to networks. -->
+
+<!-- Phone app resources that may need to be customized
+ for different hardware or product builds. -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="system_visual_voicemail_client" msgid="1787338073957698459"></string>
+</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 23ac7db..1ec6d94 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -45,7 +45,8 @@
<string name="no_vm_number" msgid="4164780423805688336">"Inombolo engekho yomyalezo wezwi"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Ayikho inombolo yomlayezo wezwi egcinwe ekhadini le-SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Engeza inombolo"</string>
- <string name="voice_number_setting_primary_user_only" msgid="6596604364907022416">"Izilungiselelo zevoyisimeyili zingashintshwa kuphela umsebenzisi oyinhloko."</string>
+ <!-- no translation found for voice_number_setting_primary_user_only (6596604364907022416) -->
+ <skip />
<string name="puk_unlocked" msgid="2284912838477558454">"Ikhadi lakho le-SIM livuliwe. Ifoni yakho iyavula..."</string>
<string name="label_ndp" msgid="780479633159517250">"Inethiwekhi ye-SIM yokuvula i-PIN"</string>
<string name="sim_ndp_unlock_text" msgid="683628237760543009">"Vula"</string>
@@ -451,7 +452,8 @@
<string name="incall_error_ecm_emergency_only" msgid="738708660612388692">"Phuma kwimodi yokushayela emuva yesiko esiphuthumayo ukuze wenze ikholi yemodi engaphuthumi."</string>
<string name="incall_error_emergency_only" msgid="4678640422710818317">"Ayibhalisiwe kwinethiwekhi."</string>
<string name="incall_error_out_of_service" msgid="8587993036435080418">"Inethiwekhi yefoni ayitholakali"</string>
- <string name="incall_error_out_of_service_wfc" msgid="8741629779555132471">"Inethiwekhi yeselula ayitholakali. Xhumeka kunethiwekhi engenantambo ukuze wenze ikholi."</string>
+ <!-- no translation found for incall_error_out_of_service_wfc (8741629779555132471) -->
+ <skip />
<string name="incall_error_no_phone_number_supplied" msgid="1150414018684246528">"Ukuze wenze ikholi, faka inombolo evumelekile."</string>
<string name="incall_error_call_failed" msgid="5891978320269774095">"Ikholi ihlulekile."</string>
<string name="incall_error_cannot_add_call" msgid="5206923515522412110">"Ikholi ayikwazi ukungezwa ngalesi sikhathi."</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index d897d9a..2078049 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -223,9 +223,6 @@
<!-- Whether the emergency only account can make emergency calls -->
<bool name="config_pstnCanPlaceEmergencyCalls">true</bool>
- <!-- Whether the cellular radio is allowed to be power down when the Bluetooth can provide the data/call capabilities -->
- <bool name="config_allowRadioPowerDownOnBluetooth">false</bool>
-
<!-- The package name for the platform carrier config app, bundled with system image. -->
<string name="platform_carrier_config_package" translatable="false">com.android.carrierconfig</string>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 972af37..7009fd8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -172,6 +172,12 @@
<string name="voicemail_settings_with_label">Voicemail (<xliff:g id="subscriptionlabel" example="Mock Carrier">%s</xliff:g>)</string>
<!-- Call forwarding dialog box, voicemail number prefix -->
<string name="voicemail_abbreviated">VM:</string>
+ <!-- DO NOT TRANSLATE. Internal key for a voicemail notification preference. -->
+ <string name="voicemail_notifications_key" translatable="false">voicemail_notification_key</string>
+
+ <!-- Voicemail notifications title. The user clicks on this preference navigate to the system settings screen for that channel
+ .[CHAR LIMIT=30] -->
+ <string name="voicemail_notifications_preference_title">Notifications</string>
<!-- Mobile network settings screen, setting option name -->
<string name="networks">Network operators</string>
<!-- Cell Broadcast settings title. [CHAR LIMIT=50] -->
@@ -357,6 +363,8 @@
<!-- networks setting strings --><skip/>
<!-- Mobile network settings screen title -->
<string name="mobile_networks">Mobile network settings</string>
+ <!-- Mobile network settings screen title/heading -->
+ <string name="network_settings_title">Mobile network</string>
<!-- Available networks screen title/heading -->
<string name="label_available">Available networks</string>
<!-- Mobile network settings screen, toast when searching for available networks -->
@@ -983,7 +991,7 @@
<string name="notification_network_selection_text">Selected network (<xliff:g id="operator_name">%s</xliff:g>) unavailable</string>
<!-- In-call screen: call failure message displayed in an error dialog. [CHAR_LIMIT=NONE] -->
- <string name="incall_error_power_off" product="watch">Turn off airplane mode or battery saver mode to make a call.</string>
+ <string name="incall_error_power_off" product="watch">Turn on mobile network, turn off airplane mode or turn off battery saver mode to make a call.</string>
<!-- In-call screen: call failure message displayed in an error dialog. [CHAR_LIMIT=NONE] -->
<string name="incall_error_power_off" product="default">Turn off airplane mode to make a call.</string>
<!-- In-call screen: call failure message displayed in an error dialog when in airplane mode, WFC is enabled, not wifi-only, and not connected to wireless networks. [CHAR_LIMIT=NONE] -->
@@ -1255,11 +1263,6 @@
-->
<string name="description_dial_button">dial</string>
- <!-- Title for the vibration settings for voicemail notifications [CHAR LIMIT=40] -->
- <string name="voicemail_notification_vibrate_when_title" msgid="8731372580674292759">Vibrate</string>
- <!-- Dialog title for the vibration settings for voice mail notifications [CHAR LIMIT=40]-->
- <string name="voicemail_notification_vibarte_when_dialog_title" msgid="8995274609647451109">Vibrate</string>
-
<!-- Visual voicemail on/off title [CHAR LIMIT=40] -->
<string name="voicemail_visual_voicemail_switch_title">Visual Voicemail</string>
@@ -1268,21 +1271,6 @@
<!-- Voicemail change PIN dialog title [CHAR LIMIT=40] -->
<string name="voicemail_change_pin_dialog_title">Change PIN</string>
- <!-- Voicemail ringtone title. The user clicks on this preference to select
- which sound to play when a voicemail notification is received.
- [CHAR LIMIT=30] -->
- <string name="voicemail_notification_ringtone_title">Sound</string>
-
- <!-- The default value value for voicemail notification. -->
- <string name="voicemail_notification_vibrate_when_default" translatable="false">never</string>
-
- <!-- Actual values used in our code for voicemail notifications. DO NOT TRANSLATE -->
- <string-array name="voicemail_notification_vibrate_when_values" translatable="false">
- <item>always</item>
- <item>silent</item>
- <item>never</item>
- </string-array>
-
<!-- Title for the category "ringtone", which is shown above ringtone and vibration
related settings.
[CHAR LIMIT=30] -->
@@ -1329,10 +1317,6 @@
<!-- Status hint label for a call being made over a wifi network. [CHAR LIMIT=25] -->
<string name="status_hint_label_wifi_call">Wi-Fi call</string>
- <!-- DO NOT TRANSLATE. Internal key for a voicemail notification preference. -->
- <string name="voicemail_notification_ringtone_key">voicemail_notification_ringtone_key</string>
- <!-- DO NOT TRANSLATE. Internal key for a voicemail notification preference. -->
- <string name="voicemail_notification_vibrate_key">voicemail_notification_vibrate_key</string>
<!-- DO NOT TRANSLATE. Internal key for a visual voicemail preference. -->
<string name="voicemail_visual_voicemail_key">voicemail_visual_voicemail_key</string>
<!-- DO NOT TRANSLATE. Internal key for a voicemail change pin preference. -->
diff --git a/res/xml/voicemail_settings.xml b/res/xml/voicemail_settings.xml
index 439cc07..021a764 100644
--- a/res/xml/voicemail_settings.xml
+++ b/res/xml/voicemail_settings.xml
@@ -50,22 +50,7 @@
</PreferenceScreen>
- <com.android.phone.settings.VoicemailRingtonePreference
- android:key="@string/voicemail_notification_ringtone_key"
- android:title="@string/voicemail_notification_ringtone_title"
- android:persistent="false"
- android:ringtoneType="notification" />
-
- <SwitchPreference
- android:key="@string/voicemail_notification_vibrate_key"
- android:title="@string/voicemail_notification_vibrate_when_title"
- android:persistent="true" />
-
- <SwitchPreference
- android:key="@string/voicemail_visual_voicemail_key"
- android:title="@string/voicemail_visual_voicemail_switch_title" />"
-
<Preference
- android:key="@string/voicemail_change_pin_key"
- android:title="@string/voicemail_change_pin_dialog_title" />
+ android:key="@string/voicemail_notifications_key"
+ android:title="@string/voicemail_notifications_preference_title"/>
</PreferenceScreen>
diff --git a/res/xml/vvm_config.xml b/res/xml/vvm_config.xml
deleted file mode 100644
index 19c667e..0000000
--- a/res/xml/vvm_config.xml
+++ /dev/null
@@ -1,134 +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.
--->
-
-<list name="carrier_config_list">
- <pbundle_as_map>
- <!-- Test -->
- <string-array name="mccmnc">
- <item value="TEST"/>
- </string-array>
- </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"/>
- <item value="310200"/>
- <item value="310210"/>
- <item value="310220"/>
- <item value="310230"/>
- <item value="310240"/>
- <item value="310250"/>
- <item value="310260"/>
- <item value="310270"/>
- <item value="310300"/>
- <item value="310310"/>
- <item value="310490"/>
- <item value="310530"/>
- <item value="310590"/>
- <item value="310640"/>
- <item value="310660"/>
- <item value="310800"/>
- </string-array>
-
- <int name="vvm_port_number_int" value="1808"/>
- <int name="vvm_ssl_port_number_int" value="993"/>
- <string name="vvm_destination_number_string">122</string>
- <string-array name="carrier_vvm_package_name_string_array">
- <item value="com.tmobile.vvm.application"/>
- </string-array>
- <string name="vvm_type_string">vvm_type_cvvm</string>>
- <string-array name="vvm_disabled_capabilities_string_array">
- <!-- b/28717550 -->
- <item value="AUTH=DIGEST-MD5"/>
- </string-array>
- </pbundle_as_map>
-
- <pbundle_as_map>
- <!-- Verizon USA -->
- <string-array name="mccmnc">
- <item value="310004"/>
- <item value="310010"/>
- <item value="310012"/>
- <item value="310013"/>
- <item value="310590"/>
- <item value="310890"/>
- <item value="310910"/>
- <item value="311110"/>
- <item value="311270"/>
- <item value="311271"/>
- <item value="311272"/>
- <item value="311273"/>
- <item value="311274"/>
- <item value="311275"/>
- <item value="311276"/>
- <item value="311277"/>
- <item value="311278"/>
- <item value="311279"/>
- <item value="311280"/>
- <item value="311281"/>
- <item value="311282"/>
- <item value="311283"/>
- <item value="311284"/>
- <item value="311285"/>
- <item value="311286"/>
- <item value="311287"/>
- <item value="311288"/>
- <item value="311289"/>
- <item value="311390"/>
- <item value="311480"/>
- <item value="311481"/>
- <item value="311482"/>
- <item value="311483"/>
- <item value="311484"/>
- <item value="311485"/>
- <item value="311486"/>
- <item value="311487"/>
- <item value="311488"/>
- <item value="311489"/>
- </string-array>
-
- <int name="vvm_port_number_int" value="0"/>
- <string name="vvm_destination_number_string">900080006200</string>
- <string name="vvm_type_string">vvm_type_vvm3</string>
- <string name="vvm_client_prefix_string">//VZWVVM</string>
- <boolean name="vvm_cellular_data_required_bool" value="true"/>
- <boolean name="vvm_legacy_mode_enabled_bool" value="true"/>
- <!-- VVM3 specific value for the voicemail management gateway to use if the SMS didn't provide
- one -->
- <string name="default_vmg_url">https://mobile.vzw.com/VMGIMS/VMServices</string>
- </pbundle_as_map>
-</list>
diff --git a/sip/res/values-az-rAZ/strings.xml b/sip/res/values-az/strings.xml
similarity index 100%
rename from sip/res/values-az-rAZ/strings.xml
rename to sip/res/values-az/strings.xml
diff --git a/sip/res/values-b+sr+Latn/strings.xml b/sip/res/values-b+sr+Latn/strings.xml
index d438a2b..740a3d7 100644
--- a/sip/res/values-b+sr+Latn/strings.xml
+++ b/sip/res/values-b+sr+Latn/strings.xml
@@ -61,7 +61,9 @@
<string name="advanced_settings" msgid="6622996380747040711">"Opcionalna podešavanja"</string>
<string name="auth_username_title" msgid="8262491689004708265">"Korisničko ime za potvrdu identiteta"</string>
<string name="auth_username_summary" msgid="941160241371436473">"Za potvrdu identiteta koristi se korisničko ime"</string>
- <string name="default_preference_summary" msgid="1979249643719483249">"<Nije podešeno>"</string>
+ <string name="default_preference_summary_username" msgid="8404717434312826082">"<Nije podešeno>"</string>
+ <string name="default_preference_summary_password" msgid="4464464672997027904">"<Nije podešena>"</string>
+ <string name="default_preference_summary_domain_address" msgid="4871971710197441673">"<Nije podešena>"</string>
<string name="display_name_summary" msgid="7155076491675565407">"<Isto kao korisničko ime>"</string>
<string name="optional_summary" msgid="2363105560396317624">"<Opcionalno>"</string>
<string name="advanced_settings_show" msgid="7838761602853998622">"▷ Dodirnite da biste prikazali sve"</string>
diff --git a/sip/res/values-be/strings.xml b/sip/res/values-be/strings.xml
new file mode 100644
index 0000000..a848c52
--- /dev/null
+++ b/sip/res/values-be/strings.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="sip_settings" msgid="3768482698061677257">"Налады SIP"</string>
+ <string name="sip_accounts" msgid="85559497282185405">"Уліковыя запісы SIP"</string>
+ <string name="sip_accounts_title" msgid="2082527045326874519">"Уліковыя запісы"</string>
+ <string name="sip_receive_calls" msgid="426678617137462173">"Прымаць уваходныя выклікі"</string>
+ <string name="sip_receive_calls_summary" msgid="946161517528227523">"Спажывае больш зараду акумулятара"</string>
+ <string name="sip_call_options_title" msgid="8421210494703869806">"Выкарыстоўваць SIP-выклікі"</string>
+ <string name="sip_call_options_wifi_only_title" msgid="5112579243580893890">"Выкарыстоўваць SIP-выклікі (толькі Wi-Fi)"</string>
+ <string name="sip_call_options_entry_1" msgid="7217659161237099900">"Для ўсіх выклікаў, калі ёсць падлучэнне да сеткі перадачы даных"</string>
+ <string name="sip_call_options_entry_2" msgid="1815335903940609729">"Толькі для SIP-выклікаў"</string>
+ <string name="sip_call_options_wifi_only_entry_1" msgid="1358513095551847314">"Для ўсіх выклікаў"</string>
+ <string name="add_sip_account" msgid="800843669753980091">"Дадаць уліковы запіс"</string>
+ <string name="remove_sip_account" msgid="1367664438506503690">"Выдаліць уліковы запіс"</string>
+ <string name="sip_account_list" msgid="5610858485304821480">"Уліковыя запісы SIP"</string>
+ <string name="saving_account" msgid="5336529880235177448">"Захаванне ўліковага запісу..."</string>
+ <string name="removing_account" msgid="5537351356808985756">"Выдаленне ўліковага запісу..."</string>
+ <string name="sip_menu_save" msgid="7882219814563869225">"Захаваць"</string>
+ <string name="sip_menu_discard" msgid="2350421645423888438">"Скасаваць"</string>
+ <string name="alert_dialog_close" msgid="1326011828713435134">"Закрыць профіль"</string>
+ <string name="alert_dialog_ok" msgid="4752048404605388940">"OK"</string>
+ <string name="close_profile" msgid="3122414058856309881">"Закрыць"</string>
+ <string name="registration_status_checking_status" msgid="6136793741862200337">"Праверка стану..."</string>
+ <string name="registration_status_registering" msgid="2677183977796278749">"Рэгістрацыя..."</string>
+ <string name="registration_status_still_trying" msgid="7648151061205513458">"Спробы працягваюцца..."</string>
+ <string name="registration_status_not_receiving" msgid="7620333886153361090">"Выклікі не прымаюцца."</string>
+ <string name="registration_status_no_data" msgid="2541999976218192413">"Рэгістрацыя ўліковага запісу спынена, таму што няма падлучэння да інтэрнэту."</string>
+ <string name="registration_status_no_wifi_data" msgid="9154717387473039546">"Рэгістрацыя ўліковага запісу спынена, таму што няма падлучэння да Wi-Fi."</string>
+ <string name="registration_status_not_running" msgid="514205414303796800">"Няўдалая рэгістрацыя ўліковага запісу."</string>
+ <string name="registration_status_done" msgid="3264961069247314253">"Прыём выклікаў."</string>
+ <string name="registration_status_failed_try_later" msgid="2199970021756384317">"Няўдалая рэгістрацыя ўліковага запісу: (<xliff:g id="REGISTRATION_ERROR_MESSAGE">%s</xliff:g>); спроба будзе паўторана пазней"</string>
+ <string name="registration_status_invalid_credentials" msgid="8406872554323334182">"Няўдалая рэгістрацыя ўліковага запісу: няправільнае імя карыстальніка або пароль."</string>
+ <string name="registration_status_server_unreachable" msgid="7710275557045148634">"Няўдалая рэгістрацыя ўліковага запісу: праверце імя сервера."</string>
+ <string name="third_party_account_summary" msgid="9041060473615403041">"Гэты ўліковы запіс зараз выкарыстоўваецца праграмай <xliff:g id="ACCOUNT_OWNER">%s</xliff:g>."</string>
+ <string name="sip_edit_title" msgid="1967247832635750410">"Дэталі уліковага запісу SIP"</string>
+ <string name="sip_edit_new_title" msgid="266414118302574305">"Дэталі уліковага запісу SIP"</string>
+ <string name="domain_address_title" msgid="1968479941328225423">"Сервер"</string>
+ <string name="username_title" msgid="6770064611005663470">"Імя карыстальніка"</string>
+ <string name="password_title" msgid="5289013731515564295">"Пароль"</string>
+ <string name="display_name_title" msgid="579241787583079773">"Бачнае імя"</string>
+ <string name="proxy_address_title" msgid="6890163365640631841">"Адрас выходнага проксі-сервера"</string>
+ <string name="port_title" msgid="6693965912656593862">"Нумар порта"</string>
+ <string name="transport_title" msgid="889155457465372527">"Тып транспарту"</string>
+ <string name="send_keepalive_title" msgid="599627072150501159">"Адправіць паведамленне праверкі актыўнасці"</string>
+ <string name="advanced_settings" msgid="6622996380747040711">"Неабавязковыя налады"</string>
+ <string name="auth_username_title" msgid="8262491689004708265">"Імя карыстальніка для праверкі сапраўднасці"</string>
+ <string name="auth_username_summary" msgid="941160241371436473">"Імя карыстальніка, якое выкарыстоўваецца для праверкі сапраўднасці"</string>
+ <string name="default_preference_summary_username" msgid="8404717434312826082">"<Не зададзены>"</string>
+ <string name="default_preference_summary_password" msgid="4464464672997027904">"<Не зададзены>"</string>
+ <string name="default_preference_summary_domain_address" msgid="4871971710197441673">"<Не зададзены>"</string>
+ <string name="display_name_summary" msgid="7155076491675565407">"<Такі ж, як імя карыстальніка>"</string>
+ <string name="optional_summary" msgid="2363105560396317624">"<Неабавязкова>"</string>
+ <string name="advanced_settings_show" msgid="7838761602853998622">"▷ Дакраніцеся, каб паказаць усё"</string>
+ <string name="advanced_settings_hide" msgid="3480554978705290228">"▽ Дакраніцеся, каб схаваць усё"</string>
+ <string name="all_empty_alert" msgid="4087734950375192387">"Увесці інфармацыю аб новым уліковым запісе SIP."</string>
+ <string name="empty_alert" msgid="6659484914371384024">"Поле <xliff:g id="INPUT_FIELD_NAME">%s</xliff:g> з\'яўляецца абавязковым для запаўнення, яго нельга пакідаць пустым."</string>
+ <string name="not_a_valid_port" msgid="7931422555587011830">"Порт павінен мець нумар ад 1000 да 65534."</string>
+ <string name="no_internet_available" msgid="5523747991760017298">"Каб зрабіць SIP-выклік, спачатку праверце інтэрнэт-злучэнне."</string>
+ <string name="no_wifi_available" msgid="1955023904229673488">"Каб рабіць SIP-выклікі, вы павінны падлучыцца да сеткі Wi-Fi (скарыстайцеся раздзелам \"Бесправадная сувязь і сеткі\")."</string>
+ <string name="no_voip" msgid="3038021971231952704">"SIP-выклікі не падтрымліваюцца"</string>
+ <string name="sip_system_decide" msgid="5577696249416700671">"Аўтаматычна"</string>
+ <string name="sip_always_send_keepalive" msgid="4773022409239823318">"Заўсёды адпраўляць"</string>
+ <string name="sip_connection_service_label" msgid="6935325004265884453">"Убудаваныя SIP-выклікі"</string>
+</resources>
diff --git a/sip/res/values-bn-rBD/strings.xml b/sip/res/values-bn/strings.xml
similarity index 100%
rename from sip/res/values-bn-rBD/strings.xml
rename to sip/res/values-bn/strings.xml
diff --git a/sip/res/values-bs/strings.xml b/sip/res/values-bs/strings.xml
new file mode 100644
index 0000000..84b045e
--- /dev/null
+++ b/sip/res/values-bs/strings.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="sip_settings" msgid="3768482698061677257">"SIP postavke"</string>
+ <string name="sip_accounts" msgid="85559497282185405">"SIP računi"</string>
+ <string name="sip_accounts_title" msgid="2082527045326874519">"Računi"</string>
+ <string name="sip_receive_calls" msgid="426678617137462173">"Primi dolazne pozive"</string>
+ <string name="sip_receive_calls_summary" msgid="946161517528227523">"Troši više baterije"</string>
+ <string name="sip_call_options_title" msgid="8421210494703869806">"Koristi SIP pozivanje"</string>
+ <string name="sip_call_options_wifi_only_title" msgid="5112579243580893890">"Koristi SIP pozivanje (samo Wi-Fi)"</string>
+ <string name="sip_call_options_entry_1" msgid="7217659161237099900">"Za sve pozive kada je podatkovna mreža dostupna"</string>
+ <string name="sip_call_options_entry_2" msgid="1815335903940609729">"Samo za SIP pozive"</string>
+ <string name="sip_call_options_wifi_only_entry_1" msgid="1358513095551847314">"Za sve pozive"</string>
+ <string name="add_sip_account" msgid="800843669753980091">"Dodaj račun"</string>
+ <string name="remove_sip_account" msgid="1367664438506503690">"Ukloni račun"</string>
+ <string name="sip_account_list" msgid="5610858485304821480">"SIP računi"</string>
+ <string name="saving_account" msgid="5336529880235177448">"Spremanje računa u toku…"</string>
+ <string name="removing_account" msgid="5537351356808985756">"Račun se uklanja…"</string>
+ <string name="sip_menu_save" msgid="7882219814563869225">"Sačuvaj"</string>
+ <string name="sip_menu_discard" msgid="2350421645423888438">"Odbaci"</string>
+ <string name="alert_dialog_close" msgid="1326011828713435134">"Zatvori profil"</string>
+ <string name="alert_dialog_ok" msgid="4752048404605388940">"Uredu"</string>
+ <string name="close_profile" msgid="3122414058856309881">"Zatvori"</string>
+ <string name="registration_status_checking_status" msgid="6136793741862200337">"Provjera statusa u toku..."</string>
+ <string name="registration_status_registering" msgid="2677183977796278749">"Registriranje u toku…"</string>
+ <string name="registration_status_still_trying" msgid="7648151061205513458">"Još uvijek pokušavamo…"</string>
+ <string name="registration_status_not_receiving" msgid="7620333886153361090">"Ne prima pozive."</string>
+ <string name="registration_status_no_data" msgid="2541999976218192413">"Registracija računa je zaustavljena jer niste povezani na internet."</string>
+ <string name="registration_status_no_wifi_data" msgid="9154717387473039546">"Registracija računa je zaustavljena jer nema Wi-Fi veze."</string>
+ <string name="registration_status_not_running" msgid="514205414303796800">"Registracija računa neuspješna."</string>
+ <string name="registration_status_done" msgid="3264961069247314253">"Primanje poziva."</string>
+ <string name="registration_status_failed_try_later" msgid="2199970021756384317">"Registracija računa neuspješna: (<xliff:g id="REGISTRATION_ERROR_MESSAGE">%s</xliff:g>); pokušat ćemo kasnije"</string>
+ <string name="registration_status_invalid_credentials" msgid="8406872554323334182">"Registracija računa neuspješna: netačno korisničko ime ili lozinka."</string>
+ <string name="registration_status_server_unreachable" msgid="7710275557045148634">"Registracija računa neuspješna: provjerite naziv servera."</string>
+ <string name="third_party_account_summary" msgid="9041060473615403041">"Ovaj račun trenutno koristi aplikacija <xliff:g id="ACCOUNT_OWNER">%s</xliff:g>."</string>
+ <string name="sip_edit_title" msgid="1967247832635750410">"Detalji o SIP računima"</string>
+ <string name="sip_edit_new_title" msgid="266414118302574305">"Detalji o SIP računima"</string>
+ <string name="domain_address_title" msgid="1968479941328225423">"Server"</string>
+ <string name="username_title" msgid="6770064611005663470">"Korisničko ime"</string>
+ <string name="password_title" msgid="5289013731515564295">"Lozinka"</string>
+ <string name="display_name_title" msgid="579241787583079773">"Ime za prikaz"</string>
+ <string name="proxy_address_title" msgid="6890163365640631841">"Odlazna proksi adresa"</string>
+ <string name="port_title" msgid="6693965912656593862">"Broj priključka"</string>
+ <string name="transport_title" msgid="889155457465372527">"Vrsta prijenosa"</string>
+ <string name="send_keepalive_title" msgid="599627072150501159">"Pošalji keep-alive poruku"</string>
+ <string name="advanced_settings" msgid="6622996380747040711">"Opcionalne postavke"</string>
+ <string name="auth_username_title" msgid="8262491689004708265">"Korisničko ime za provjeru vjerodostojnosti"</string>
+ <string name="auth_username_summary" msgid="941160241371436473">"Korisničko ime upotrijebljeno za provjeru vjerodostojnosti"</string>
+ <string name="default_preference_summary_username" msgid="8404717434312826082">"<Nije postavljeno>"</string>
+ <string name="default_preference_summary_password" msgid="4464464672997027904">"<Nije postavljeno>"</string>
+ <string name="default_preference_summary_domain_address" msgid="4871971710197441673">"<Nije postavljeno>"</string>
+ <string name="display_name_summary" msgid="7155076491675565407">"<Isto kao korisničko ime>"</string>
+ <string name="optional_summary" msgid="2363105560396317624">"<Opcionalno>"</string>
+ <string name="advanced_settings_show" msgid="7838761602853998622">"▷ Dodirnite da prikažete sve"</string>
+ <string name="advanced_settings_hide" msgid="3480554978705290228">"▽ Dodirnite da sakrijete sve"</string>
+ <string name="all_empty_alert" msgid="4087734950375192387">"Unesite detalje novog SIP računa."</string>
+ <string name="empty_alert" msgid="6659484914371384024">"<xliff:g id="INPUT_FIELD_NAME">%s</xliff:g> je obavezno polje i ne može biti prazno."</string>
+ <string name="not_a_valid_port" msgid="7931422555587011830">"Broj priključka treba biti između 1000 i 65534."</string>
+ <string name="no_internet_available" msgid="5523747991760017298">"Da uputite SIP poziv, prvo provjerite internet vezu."</string>
+ <string name="no_wifi_available" msgid="1955023904229673488">"Trebate biti povezani na Wi-FI mrežu za SIP pozive (koristite postavke Bežično povezivanje i mreža)."</string>
+ <string name="no_voip" msgid="3038021971231952704">"SIP pozivanje nije podržano"</string>
+ <string name="sip_system_decide" msgid="5577696249416700671">"Automatski"</string>
+ <string name="sip_always_send_keepalive" msgid="4773022409239823318">"Uvijek pošalji"</string>
+ <string name="sip_connection_service_label" msgid="6935325004265884453">"Ugrađeno SIP pozivanje"</string>
+</resources>
diff --git a/sip/res/values-et-rEE/strings.xml b/sip/res/values-et/strings.xml
similarity index 100%
rename from sip/res/values-et-rEE/strings.xml
rename to sip/res/values-et/strings.xml
diff --git a/sip/res/values-eu-rES/strings.xml b/sip/res/values-eu/strings.xml
similarity index 100%
rename from sip/res/values-eu-rES/strings.xml
rename to sip/res/values-eu/strings.xml
diff --git a/sip/res/values-gl-rES/strings.xml b/sip/res/values-gl/strings.xml
similarity index 100%
rename from sip/res/values-gl-rES/strings.xml
rename to sip/res/values-gl/strings.xml
diff --git a/sip/res/values-gu-rIN/strings.xml b/sip/res/values-gu/strings.xml
similarity index 100%
rename from sip/res/values-gu-rIN/strings.xml
rename to sip/res/values-gu/strings.xml
diff --git a/sip/res/values-hy-rAM/strings.xml b/sip/res/values-hy/strings.xml
similarity index 100%
rename from sip/res/values-hy-rAM/strings.xml
rename to sip/res/values-hy/strings.xml
diff --git a/sip/res/values-is-rIS/strings.xml b/sip/res/values-is/strings.xml
similarity index 100%
rename from sip/res/values-is-rIS/strings.xml
rename to sip/res/values-is/strings.xml
diff --git a/sip/res/values-ka-rGE/strings.xml b/sip/res/values-ka/strings.xml
similarity index 100%
rename from sip/res/values-ka-rGE/strings.xml
rename to sip/res/values-ka/strings.xml
diff --git a/sip/res/values-kk-rKZ/strings.xml b/sip/res/values-kk/strings.xml
similarity index 100%
rename from sip/res/values-kk-rKZ/strings.xml
rename to sip/res/values-kk/strings.xml
diff --git a/sip/res/values-km-rKH/strings.xml b/sip/res/values-km/strings.xml
similarity index 100%
rename from sip/res/values-km-rKH/strings.xml
rename to sip/res/values-km/strings.xml
diff --git a/sip/res/values-kn-rIN/strings.xml b/sip/res/values-kn/strings.xml
similarity index 100%
rename from sip/res/values-kn-rIN/strings.xml
rename to sip/res/values-kn/strings.xml
diff --git a/sip/res/values-ky-rKG/strings.xml b/sip/res/values-ky/strings.xml
similarity index 100%
rename from sip/res/values-ky-rKG/strings.xml
rename to sip/res/values-ky/strings.xml
diff --git a/sip/res/values-lo-rLA/strings.xml b/sip/res/values-lo/strings.xml
similarity index 100%
rename from sip/res/values-lo-rLA/strings.xml
rename to sip/res/values-lo/strings.xml
diff --git a/sip/res/values-mk-rMK/strings.xml b/sip/res/values-mk/strings.xml
similarity index 100%
rename from sip/res/values-mk-rMK/strings.xml
rename to sip/res/values-mk/strings.xml
diff --git a/sip/res/values-ml-rIN/strings.xml b/sip/res/values-ml/strings.xml
similarity index 100%
rename from sip/res/values-ml-rIN/strings.xml
rename to sip/res/values-ml/strings.xml
diff --git a/sip/res/values-mn-rMN/strings.xml b/sip/res/values-mn/strings.xml
similarity index 100%
rename from sip/res/values-mn-rMN/strings.xml
rename to sip/res/values-mn/strings.xml
diff --git a/sip/res/values-mr-rIN/strings.xml b/sip/res/values-mr/strings.xml
similarity index 100%
rename from sip/res/values-mr-rIN/strings.xml
rename to sip/res/values-mr/strings.xml
diff --git a/sip/res/values-ms-rMY/strings.xml b/sip/res/values-ms/strings.xml
similarity index 100%
rename from sip/res/values-ms-rMY/strings.xml
rename to sip/res/values-ms/strings.xml
diff --git a/sip/res/values-my-rMM/strings.xml b/sip/res/values-my/strings.xml
similarity index 100%
rename from sip/res/values-my-rMM/strings.xml
rename to sip/res/values-my/strings.xml
diff --git a/sip/res/values-ne-rNP/strings.xml b/sip/res/values-ne/strings.xml
similarity index 100%
rename from sip/res/values-ne-rNP/strings.xml
rename to sip/res/values-ne/strings.xml
diff --git a/sip/res/values-pa-rIN/strings.xml b/sip/res/values-pa/strings.xml
similarity index 100%
rename from sip/res/values-pa-rIN/strings.xml
rename to sip/res/values-pa/strings.xml
diff --git a/sip/res/values-si-rLK/strings.xml b/sip/res/values-si/strings.xml
similarity index 100%
rename from sip/res/values-si-rLK/strings.xml
rename to sip/res/values-si/strings.xml
diff --git a/sip/res/values-sq-rAL/strings.xml b/sip/res/values-sq/strings.xml
similarity index 100%
rename from sip/res/values-sq-rAL/strings.xml
rename to sip/res/values-sq/strings.xml
diff --git a/sip/res/values-ta-rIN/strings.xml b/sip/res/values-ta/strings.xml
similarity index 100%
rename from sip/res/values-ta-rIN/strings.xml
rename to sip/res/values-ta/strings.xml
diff --git a/sip/res/values-te-rIN/strings.xml b/sip/res/values-te/strings.xml
similarity index 100%
rename from sip/res/values-te-rIN/strings.xml
rename to sip/res/values-te/strings.xml
diff --git a/sip/res/values-ur-rPK/strings.xml b/sip/res/values-ur/strings.xml
similarity index 100%
rename from sip/res/values-ur-rPK/strings.xml
rename to sip/res/values-ur/strings.xml
diff --git a/sip/res/values-uz-rUZ/strings.xml b/sip/res/values-uz/strings.xml
similarity index 100%
rename from sip/res/values-uz-rUZ/strings.xml
rename to sip/res/values-uz/strings.xml
diff --git a/src/com/android/phone/ADNList.java b/src/com/android/phone/ADNList.java
index cdd136d..b1cb16b 100644
--- a/src/com/android/phone/ADNList.java
+++ b/src/com/android/phone/ADNList.java
@@ -195,18 +195,12 @@
if (DBG) log("displayProgress: " + loading);
mEmptyText.setText(loading ? R.string.simContacts_emptyLoading:
- (isAirplaneModeOn(this) ? R.string.simContacts_airplaneMode :
- R.string.simContacts_empty));
+ R.string.simContacts_empty);
getWindow().setFeatureInt(
Window.FEATURE_INDETERMINATE_PROGRESS,
loading ? PROGRESS_VISIBILITY_ON : PROGRESS_VISIBILITY_OFF);
}
- private static boolean isAirplaneModeOn(Context context) {
- return Settings.System.getInt(context.getContentResolver(),
- Settings.System.AIRPLANE_MODE_ON, 0) != 0;
- }
-
private class QueryHandler extends AsyncQueryHandler {
public QueryHandler(ContentResolver cr) {
super(cr);
diff --git a/src/com/android/phone/CallFeaturesSetting.java b/src/com/android/phone/CallFeaturesSetting.java
index 9677acd..8386c34 100644
--- a/src/com/android/phone/CallFeaturesSetting.java
+++ b/src/com/android/phone/CallFeaturesSetting.java
@@ -25,7 +25,9 @@
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.PersistableBundle;
@@ -230,6 +232,8 @@
mVoicemailSettingsScreen.setIntent(mSubscriptionInfoHelper.getIntent(
VoicemailSettingsActivity.class));
+ maybeHideVoicemailSettings();
+
mButtonAutoRetry = (SwitchPreference) findPreference(BUTTON_RETRY_KEY);
mEnableVideoCalling = (SwitchPreference) findPreference(ENABLE_VIDEO_CALLING_KEY);
@@ -350,6 +354,41 @@
}
}
+ /**
+ * Hides the top level voicemail settings entry point if the default dialer contains a
+ * particular manifest metadata key. This is required when the default dialer wants to display
+ * its own version of voicemail settings.
+ */
+ private void maybeHideVoicemailSettings() {
+ String defaultDialer = getSystemService(TelecomManager.class).getDefaultDialerPackage();
+ if (defaultDialer == null) {
+ return;
+ }
+ try {
+ Bundle metadata = getPackageManager()
+ .getApplicationInfo(defaultDialer, PackageManager.GET_META_DATA).metaData;
+ if (metadata == null) {
+ return;
+ }
+ if (!metadata
+ .getBoolean(TelephonyManager.METADATA_HIDE_VOICEMAIL_SETTINGS_MENU, false)) {
+ if (DBG) {
+ log("maybeHideVoicemailSettings(): not disabled by default dialer");
+ }
+ return;
+ }
+ getPreferenceScreen().removePreference(mVoicemailSettingsScreen);
+ if (DBG) {
+ log("maybeHideVoicemailSettings(): disabled by default dialer");
+ }
+ } catch (NameNotFoundException e) {
+ // do nothing
+ if (DBG) {
+ log("maybeHideVoicemailSettings(): not controlled by default dialer");
+ }
+ }
+ }
+
@Override
protected void onNewIntent(Intent newIntent) {
setIntent(newIntent);
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index 5bbf35b..a33324b 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -20,7 +20,7 @@
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
import android.annotation.NonNull;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -395,10 +395,10 @@
private void broadcastConfigChangedIntent(int phoneId) {
Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+ Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
- ActivityManagerNative.broadcastStickyIntent(intent, READ_PHONE_STATE,
- UserHandle.USER_ALL);
+ ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
}
/** Binds to the default or carrier config app. */
diff --git a/src/com/android/phone/DumpsysHandler.java b/src/com/android/phone/DumpsysHandler.java
index d2ae38f..a0277fc 100644
--- a/src/com/android/phone/DumpsysHandler.java
+++ b/src/com/android/phone/DumpsysHandler.java
@@ -3,7 +3,7 @@
import android.content.Context;
-import com.android.phone.vvm.omtp.utils.VvmDumpHandler;
+import com.android.phone.vvm.VvmDumpHandler;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/src/com/android/phone/EmergencyCallbackModeService.java b/src/com/android/phone/EmergencyCallbackModeService.java
index ce50d82..a07f7aa 100644
--- a/src/com/android/phone/EmergencyCallbackModeService.java
+++ b/src/com/android/phone/EmergencyCallbackModeService.java
@@ -24,8 +24,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Resources;
-import android.graphics.BitmapFactory;
import android.os.AsyncResult;
import android.os.Binder;
import android.os.CountDownTimer;
@@ -37,9 +35,9 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
+import com.android.internal.telephony.util.NotificationChannelController;
import java.text.SimpleDateFormat;
@@ -213,6 +211,7 @@
completeTime);
}
builder.setContentText(text);
+ builder.setChannelId(NotificationChannelController.CHANNEL_ID_ALERT);
// Show notification
mNotificationManager.notify(R.string.phone_in_ecm_notification_title, builder.build());
diff --git a/src/com/android/phone/MMIDialogActivity.java b/src/com/android/phone/MMIDialogActivity.java
index 1e6fa41..4afa6be 100644
--- a/src/com/android/phone/MMIDialogActivity.java
+++ b/src/com/android/phone/MMIDialogActivity.java
@@ -32,6 +32,7 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -68,6 +69,7 @@
}
}
};
+ Log.d(TAG, "onCreate; registering for mmi complete.");
mCM.registerForMmiComplete(mHandler, PhoneGlobals.MMI_COMPLETE, null);
showMMIDialog();
}
@@ -87,12 +89,18 @@
}
private void showMMIDialog() {
- final List<? extends MmiCode> codes = mPhone.getPendingMmiCodes();
+ final List<MmiCode> codes = new ArrayList<>(mPhone.getPendingMmiCodes());
+ // If the phone has an IMS phone, also get pending imS MMIsl.
+ if (mPhone.getImsPhone() != null) {
+ codes.addAll(mPhone.getImsPhone().getPendingMmiCodes());
+ }
if (codes.size() > 0) {
final MmiCode mmiCode = codes.get(0);
final Message message = Message.obtain(mHandler, PhoneGlobals.MMI_CANCEL);
+ Log.d(TAG, "showMMIDialog: mmiCode = " + mmiCode);
mMMIDialog = PhoneUtils.displayMMIInitiate(this, mmiCode, message, mMMIDialog);
} else {
+ Log.d(TAG, "showMMIDialog: no pending MMIs; finishing");
finish();
}
}
@@ -104,6 +112,7 @@
// Check the code to see if the request is ready to
// finish, this includes any MMI state that is not
// PENDING.
+ Log.d(TAG, "onMMIComplete: mmi=" + mmiCode);
// if phone is a CDMA phone display feature code completed message
int phoneType = mPhone.getPhoneType();
@@ -111,8 +120,10 @@
PhoneUtils.displayMMIComplete(mPhone, this, mmiCode, null, null);
} else if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
if (mmiCode.getState() != MmiCode.State.PENDING) {
- Log.d(TAG, "Got MMI_COMPLETE, finishing dialog activity...");
+ Log.d(TAG, "onMMIComplete: Got MMI_COMPLETE, finishing dialog activity...");
dismissDialogsAndFinish();
+ } else {
+ Log.d(TAG, "onMMIComplete: still pending.");
}
}
}
@@ -137,7 +148,7 @@
// the in-call screen, since we'll be visible in a
// partially-constructed state as soon as the "MMI Started" dialog
// gets dismissed. So let's forcibly bail out right now.
- Log.d(TAG, "onMMICancel: finishing InCallScreen...");
+ Log.d(TAG, "onMMICancel: finishing MMI dialog...");
dismissDialogsAndFinish();
}
@@ -150,6 +161,7 @@
mCM.unregisterForMmiComplete(mHandler);
mHandler = null;
}
+ Log.v(TAG, "dismissDialogsAndFinish");
finish();
}
}
diff --git a/src/com/android/phone/MobileNetworkSettings.java b/src/com/android/phone/MobileNetworkSettings.java
index 5639a09..2d8ba6d 100644
--- a/src/com/android/phone/MobileNetworkSettings.java
+++ b/src/com/android/phone/MobileNetworkSettings.java
@@ -95,6 +95,18 @@
}
}
+ @Override
+ public boolean onOptionsItemSelected(final MenuItem item) {
+ final int itemId = item.getItemId();
+ switch (itemId) {
+ // Respond to the action bar's Up/Home button
+ case android.R.id.home:
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
public static class MobileNetworkFragment extends PreferenceFragment implements
Preference.OnPreferenceChangeListener, RoamingDialogFragment.RoamingDialogListener {
@@ -184,6 +196,13 @@
mButtonDataRoam.setChecked(true);
}
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ if (getListView() != null) {
+ getListView().setDivider(null);
+ }
+ }
+
/**
* Invoked on each preference click in this hierarchy, overrides
* PreferenceActivity's implementation. Used to make sure we track the
@@ -980,8 +999,10 @@
}
private void handleSetPreferredNetworkTypeResponse(Message msg) {
- if (getActivity().isDestroyed()) {
+ final Activity activity = getActivity();
+ if (activity == null || activity.isDestroyed()) {
// Access preferences of activity only if it is not destroyed
+ // or if fragment is not attached to an activity.
return;
}
diff --git a/src/com/android/phone/NetworkSetting.java b/src/com/android/phone/NetworkSetting.java
index 29608da..72ad513 100644
--- a/src/com/android/phone/NetworkSetting.java
+++ b/src/com/android/phone/NetworkSetting.java
@@ -394,7 +394,7 @@
if (phone != null) {
ServiceState ss = tm.getServiceStateForSubscriber(phone.getSubId());
if (ss != null) {
- app.notificationMgr.updateNetworkSelection(ss.getState());
+ app.notificationMgr.updateNetworkSelection(ss.getState(), phone.getSubId());
}
}
}
diff --git a/src/com/android/phone/NotificationMgr.java b/src/com/android/phone/NotificationMgr.java
index abe5397..31bca92 100644
--- a/src/com/android/phone/NotificationMgr.java
+++ b/src/com/android/phone/NotificationMgr.java
@@ -53,10 +53,10 @@
import android.widget.Toast;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyCapabilities;
-import com.android.phone.settings.VoicemailNotificationSettingsUtil;
+import com.android.internal.telephony.util.NotificationChannelController;
import com.android.phone.settings.VoicemailSettingsActivity;
-import com.android.phone.vvm.omtp.sync.VoicemailStatusQueryHelper;
import java.util.Iterator;
import java.util.List;
@@ -81,6 +81,15 @@
private static final String MWI_SHOULD_CHECK_VVM_CONFIGURATION_KEY_PREFIX =
"mwi_should_check_vvm_configuration_state_";
+ /**
+ * Boolean value representing whether the {@link
+ * TelephonyManager#ACTION_SHOW_VOICEMAIL_NOTIFICATION} is new or a refresh of an existing
+ * notification.
+ *
+ * TODO(b/62202833): make public
+ */
+ private static final String EXTRA_IS_REFRESH = "is_refresh";
+
// notification types
static final int MMI_NOTIFICATION = 1;
static final int NETWORK_SELECTION_NOTIFICATION = 2;
@@ -93,7 +102,6 @@
private static NotificationMgr sInstance;
private PhoneGlobals mApp;
- private Phone mPhone;
private Context mContext;
private NotificationManager mNotificationManager;
@@ -122,7 +130,6 @@
mStatusBarManager =
(StatusBarManager) app.getSystemService(Context.STATUS_BAR_SERVICE);
mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE);
- mPhone = app.mCM.getDefaultPhone();
mSubscriptionManager = SubscriptionManager.from(mContext);
mTelecomManager = TelecomManager.from(mContext);
mTelephonyManager = (TelephonyManager) app.getSystemService(Context.TELEPHONY_SERVICE);
@@ -198,7 +205,7 @@
if (mMwiVisible.containsKey(subId)) {
boolean mwiVisible = mMwiVisible.get(subId);
if (mwiVisible) {
- updateMwi(subId, mwiVisible, false /* enableNotificationSound */);
+ updateMwi(subId, mwiVisible, true /* isRefresh */);
}
}
}
@@ -230,7 +237,7 @@
* @param visible true if there are messages waiting
*/
/* package */ void updateMwi(int subId, boolean visible) {
- updateMwi(subId, visible, true /* enableNotificationSound */);
+ updateMwi(subId, visible, false /* isRefresh */);
}
/**
@@ -238,9 +245,10 @@
*
* @param subId the subId to update.
* @param visible true if there are messages waiting
- * @param enableNotificationSound {@code true} if the notification sound should be played.
+ * @param isRefresh {@code true} if the notification is a refresh and the user should not be
+ * notified again.
*/
- void updateMwi(int subId, boolean visible, boolean enableNotificationSound) {
+ void updateMwi(int subId, boolean visible, boolean isRefresh) {
if (!PhoneGlobals.sVoiceCapable) {
// Do not show the message waiting indicator on devices which are not voice capable.
// These events *should* be blocked at the telephony layer for such devices.
@@ -249,20 +257,6 @@
}
Phone phone = PhoneGlobals.getPhone(subId);
- if (visible && phone != null && shouldCheckVisualVoicemailConfigurationForMwi(subId)) {
- VoicemailStatusQueryHelper queryHelper = new VoicemailStatusQueryHelper(mContext);
- PhoneAccountHandle phoneAccount = PhoneUtils.makePstnPhoneAccountHandle(phone);
- if (queryHelper.isVoicemailSourceConfigured(phoneAccount)) {
- Log.v(LOG_TAG, "Source configured for visual voicemail, hiding mwi.");
- // MWI may not be suppressed if the PIN is not set on VVM3 because it is also a
- // "Not OK" configuration state. But VVM3 never send a MWI after the service is
- // activated so this should be fine.
- // TODO(twyen): once unbundled the client should be able to set a flag to suppress
- // MWI, instead of letting the NotificationMgr try to interpret the states.
- visible = false;
- }
- }
-
Log.i(LOG_TAG, "updateMwi(): subId " + subId + " update to " + visible);
mMwiVisible.put(subId, visible);
@@ -347,11 +341,6 @@
PendingIntent pendingIntent =
PendingIntent.getActivity(mContext, subId /* requestCode */, intent, 0);
- Uri ringtoneUri = null;
-
- if (enableNotificationSound) {
- ringtoneUri = VoicemailNotificationSettingsUtil.getRingtoneUri(phone);
- }
Resources res = mContext.getResources();
PersistableBundle carrierConfig = PhoneGlobals.getInstance().getCarrierConfigForSubId(
@@ -363,14 +352,11 @@
.setContentTitle(notificationTitle)
.setContentText(notificationText)
.setContentIntent(pendingIntent)
- .setSound(ringtoneUri)
.setColor(res.getColor(R.color.dialer_theme_color))
.setOngoing(carrierConfig.getBoolean(
- CarrierConfigManager.KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL));
-
- if (VoicemailNotificationSettingsUtil.isVibrationEnabled(phone)) {
- builder.setDefaults(Notification.DEFAULT_VIBRATE);
- }
+ CarrierConfigManager.KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL))
+ .setChannel(NotificationChannelController.CHANNEL_ID_VOICE_MAIL)
+ .setOnlyAlertOnce(isRefresh);
final Notification notification = builder.build();
List<UserInfo> users = mUserManager.getUsers(true);
@@ -380,8 +366,8 @@
if (!mUserManager.hasUserRestriction(
UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
&& !user.isManagedProfile()) {
- if (!maybeSendVoicemailNotificationUsingDefaultDialer(vmCount, vmNumber,
- pendingIntent, isSettingsIntent, userHandle)) {
+ if (!maybeSendVoicemailNotificationUsingDefaultDialer(phone, vmCount, vmNumber,
+ pendingIntent, isSettingsIntent, userHandle, isRefresh)) {
mNotificationManager.notifyAsUser(
Integer.toString(subId) /* tag */,
VOICEMAIL_NOTIFICATION,
@@ -398,8 +384,8 @@
if (!mUserManager.hasUserRestriction(
UserManager.DISALLOW_OUTGOING_CALLS, userHandle)
&& !user.isManagedProfile()) {
- if (!maybeSendVoicemailNotificationUsingDefaultDialer(0, null, null, false,
- userHandle)) {
+ if (!maybeSendVoicemailNotificationUsingDefaultDialer(phone, 0, null, null,
+ false, userHandle, isRefresh)) {
mNotificationManager.cancelAsUser(
Integer.toString(subId) /* tag */,
VOICEMAIL_NOTIFICATION,
@@ -415,6 +401,7 @@
* method is also used to indicate to the default dialer when to clear the
* notification. A pending intent can be passed to the default dialer to indicate an action to
* be taken as it would by a notification produced in this class.
+ * @param phone The phone the notification is sent from
* @param count The number of pending voicemail messages to indicate on the notification. A
* Value of 0 is passed here to indicate that the notification should be cleared.
* @param number The voicemail phone number if specified.
@@ -425,14 +412,17 @@
* dialer.
* @return {@code true} if the default was notified of the notification.
*/
- private boolean maybeSendVoicemailNotificationUsingDefaultDialer(Integer count, String number,
- PendingIntent pendingIntent, boolean isSettingsIntent, UserHandle userHandle) {
+ private boolean maybeSendVoicemailNotificationUsingDefaultDialer(Phone phone, Integer count,
+ String number, PendingIntent pendingIntent, boolean isSettingsIntent,
+ UserHandle userHandle, boolean isRefresh) {
if (shouldManageNotificationThroughDefaultDialer(userHandle)) {
Intent intent = getShowVoicemailIntentForDefaultDialer(userHandle);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setAction(TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION);
-
+ intent.putExtra(TelephonyManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ PhoneUtils.makePstnPhoneAccountHandle(phone));
+ intent.putExtra(EXTRA_IS_REFRESH, isRefresh);
if (count != null) {
intent.putExtra(TelephonyManager.EXTRA_NOTIFICATION_COUNT, count);
}
@@ -515,7 +505,8 @@
.setContentTitle(notificationTitle)
.setContentText(mContext.getString(R.string.sum_cfu_enabled_indicator))
.setShowWhen(false)
- .setOngoing(true);
+ .setOngoing(true)
+ .setChannel(NotificationChannelController.CHANNEL_ID_CALL_FORWARD);
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -565,7 +556,8 @@
.setSmallIcon(android.R.drawable.stat_sys_warning)
.setContentTitle(mContext.getText(R.string.roaming))
.setColor(mContext.getResources().getColor(R.color.dialer_theme_color))
- .setContentText(contentText);
+ .setContentText(contentText)
+ .setChannel(NotificationChannelController.CHANNEL_ID_MOBILE_DATA_ALERT);
List<UserInfo> users = mUserManager.getUsers(true);
for (int i = 0; i < users.size(); i++) {
@@ -593,8 +585,9 @@
/**
* Display the network selection "no service" notification
* @param operator is the numeric operator number
+ * @param subId is the subscription ID
*/
- private void showNetworkSelection(String operator) {
+ private void showNetworkSelection(String operator, int subId) {
if (DBG) log("showNetworkSelection(" + operator + ")...");
Notification.Builder builder = new Notification.Builder(mContext)
@@ -603,7 +596,8 @@
.setContentText(
mContext.getString(R.string.notification_network_selection_text, operator))
.setShowWhen(false)
- .setOngoing(true);
+ .setOngoing(true)
+ .setChannel(NotificationChannelController.CHANNEL_ID_ALERT);
// create the target network operators settings intent
Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -613,7 +607,7 @@
intent.setComponent(new ComponentName(
mContext.getString(R.string.network_operator_settings_package),
mContext.getString(R.string.network_operator_settings_class)));
- intent.putExtra(GsmUmtsOptions.EXTRA_SUB_ID, mPhone.getSubId());
+ intent.putExtra(GsmUmtsOptions.EXTRA_SUB_ID, subId);
PendingIntent contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0);
List<UserInfo> users = mUserManager.getUsers(true);
@@ -645,10 +639,13 @@
* Update notification about no service of user selected operator
*
* @param serviceState Phone service state
+ * @param subId The subscription ID
*/
- void updateNetworkSelection(int serviceState) {
- if (TelephonyCapabilities.supportsNetworkSelection(mPhone)) {
- int subId = mPhone.getSubId();
+ void updateNetworkSelection(int serviceState, int subId) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ Phone phone = SubscriptionManager.isValidPhoneId(phoneId) ?
+ PhoneFactory.getPhone(phoneId) : PhoneFactory.getDefaultPhone();
+ if (TelephonyCapabilities.supportsNetworkSelection(phone)) {
if (SubscriptionManager.isValidSubscriptionId(subId)) {
// get the shared preference of network_selection.
// empty is auto mode, otherwise it is the operator alpha name
@@ -667,7 +664,7 @@
if (serviceState == ServiceState.STATE_OUT_OF_SERVICE
&& !TextUtils.isEmpty(networkSelection)) {
- showNetworkSelection(networkSelection);
+ showNetworkSelection(networkSelection, subId);
mSelectedUnavailableNotify = true;
} else {
if (mSelectedUnavailableNotify) {
diff --git a/src/com/android/phone/OutgoingCallBroadcaster.java b/src/com/android/phone/OutgoingCallBroadcaster.java
index dab2077..6bb1388 100644
--- a/src/com/android/phone/OutgoingCallBroadcaster.java
+++ b/src/com/android/phone/OutgoingCallBroadcaster.java
@@ -18,7 +18,7 @@
import android.Manifest;
import android.app.Activity;
-import android.app.ActivityManagerNative;
+import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.AppOpsManager;
import android.app.Dialog;
@@ -388,9 +388,9 @@
int launchedFromUid;
String launchedFromPackage;
try {
- launchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
+ launchedFromUid = ActivityManager.getService().getLaunchedFromUid(
getActivityToken());
- launchedFromPackage = ActivityManagerNative.getDefault().getLaunchedFromPackage(
+ launchedFromPackage = ActivityManager.getService().getLaunchedFromPackage(
getActivityToken());
} catch (RemoteException e) {
launchedFromUid = -1;
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index a617b0c..2ed5139 100644
--- a/src/com/android/phone/PhoneGlobals.java
+++ b/src/com/android/phone/PhoneGlobals.java
@@ -57,6 +57,7 @@
import com.android.internal.telephony.TelephonyIntents;
import com.android.phone.common.CallLogAsync;
import com.android.phone.settings.SettingsConstants;
+import com.android.phone.vvm.CarrierVvmPackageInstalledReceiver;
import com.android.services.telephony.sip.SipUtil;
/**
@@ -159,6 +160,9 @@
// Broadcast receiver for various intent broadcasts (see onCreate())
private final BroadcastReceiver mReceiver = new PhoneAppBroadcastReceiver();
+ private final CarrierVvmPackageInstalledReceiver mCarrierVvmPackageInstalledReceiver =
+ new CarrierVvmPackageInstalledReceiver();
+
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -335,6 +339,8 @@
intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
registerReceiver(mReceiver, intentFilter);
+ mCarrierVvmPackageInstalledReceiver.register(this);
+
//set the default values for the preferences in the phone.
PreferenceManager.setDefaultValues(this, R.xml.network_setting_fragment, false);
@@ -593,6 +599,7 @@
Log.i(LOG_TAG, "Turning radio off - airplane");
Settings.Global.putInt(context.getContentResolver(), Settings.Global.CELL_ON,
PhoneConstants.CELL_OFF_DUE_TO_AIRPLANE_MODE_FLAG);
+ SystemProperties.set("persist.radio.airplane_mode_on", "1");
Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT, 0);
PhoneUtils.setRadioPower(false);
}
@@ -603,6 +610,7 @@
PhoneConstants.CELL_ON_FLAG);
Settings.Global.putInt(getContentResolver(), Settings.Global.ENABLE_CELLULAR_ON_BOOT,
1);
+ SystemProperties.set("persist.radio.airplane_mode_on", "0");
PhoneUtils.setRadioPower(true);
}
@@ -743,7 +751,9 @@
ServiceState ss = ServiceState.newFromBundle(extras);
if (ss != null) {
int state = ss.getState();
- notificationMgr.updateNetworkSelection(state);
+ int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ notificationMgr.updateNetworkSelection(state, subId);
}
}
}
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index b7c913c..6a8e7bd 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -39,6 +39,7 @@
import android.os.Message;
import android.os.Messenger;
import android.os.Process;
+import android.os.PersistableBundle;
import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -58,6 +59,7 @@
import android.telephony.NeighboringCellInfo;
import android.telephony.NetworkScanRequest;
import android.telephony.RadioAccessFamily;
+import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SmsManager;
@@ -65,6 +67,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyHistogram;
import android.telephony.TelephonyManager;
+import android.telephony.UssdResponse;
import android.telephony.VisualVoicemailSmsFilterSettings;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -76,6 +79,7 @@
import com.android.ims.internal.IImsServiceController;
import com.android.ims.internal.IImsServiceFeatureListener;
import com.android.internal.telephony.CallManager;
+import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.DefaultPhoneNotifier;
@@ -98,10 +102,12 @@
import com.android.internal.telephony.uicc.UiccCard;
import com.android.internal.telephony.uicc.UiccCardApplication;
import com.android.internal.telephony.uicc.UiccController;
+import com.android.internal.telephony.util.VoicemailNotificationSettingsUtil;
import com.android.internal.util.HexDump;
-import com.android.phone.settings.VisualVoicemailSettingsUtil;
-import com.android.phone.settings.VoicemailNotificationSettingsUtil;
+import com.android.phone.vvm.PhoneAccountHandleConverter;
import com.android.phone.vvm.RemoteVvmTaskManager;
+import com.android.phone.vvm.VisualVoicemailSettingsUtil;
+import com.android.phone.vvm.VisualVoicemailSmsFilterConfig;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -287,9 +293,29 @@
Pair<String, ResultReceiver> ussdObject = (Pair) request.argument;
String ussdRequest = ussdObject.first;
ResultReceiver wrappedCallback = ussdObject.second;
- request.result = phone != null ?
- phone.handleUssdRequest(ussdRequest, wrappedCallback)
- :false;
+
+ if (!isUssdApiAllowed(request.subId)) {
+ // Carrier does not support use of this API, return failure.
+ Rlog.w(LOG_TAG, "handleUssdRequest: carrier does not support USSD apis.");
+ UssdResponse response = new UssdResponse(ussdRequest, null);
+ Bundle returnData = new Bundle();
+ returnData.putParcelable(TelephonyManager.USSD_RESPONSE, response);
+ wrappedCallback.send(TelephonyManager.USSD_RETURN_FAILURE, returnData);
+
+ request.result = true;
+ synchronized (request) {
+ request.notifyAll();
+ }
+ return;
+ }
+
+ try {
+ request.result = phone != null ?
+ phone.handleUssdRequest(ussdRequest, wrappedCallback)
+ : false;
+ } catch (CallStateException cse) {
+ request.result = false;
+ }
// Wake up the requesting thread
synchronized (request) {
request.notifyAll();
@@ -1496,6 +1522,7 @@
}
public boolean setRadioPower(boolean turnOn) {
+ enforceModifyPermission();
final Phone defaultPhone = PhoneFactory.getDefaultPhone();
if (defaultPhone != null) {
defaultPhone.setRadioPower(turnOn);
@@ -2022,24 +2049,17 @@
}
@Override
- public void setVisualVoicemailEnabled(String callingPackage,
- PhoneAccountHandle phoneAccountHandle, boolean enabled) {
+ public Bundle getVisualVoicemailSettings(String callingPackage, int subId) {
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
- if (!TextUtils.equals(callingPackage,
- TelecomManager.from(mPhone.getContext()).getDefaultDialerPackage())) {
- enforceModifyPermissionOrCarrierPrivilege(
- PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccountHandle));
+ String systemDialer = TelecomManager.from(mPhone.getContext()).getSystemDialerPackage();
+ if (!TextUtils.equals(callingPackage, systemDialer)) {
+ throw new SecurityException("caller must be system dialer");
}
- VisualVoicemailSettingsUtil.setEnabled(mPhone.getContext(), phoneAccountHandle, enabled);
- }
-
- @Override
- public boolean isVisualVoicemailEnabled(String callingPackage,
- PhoneAccountHandle phoneAccountHandle) {
- if (!canReadPhoneState(callingPackage, "isVisualVoicemailEnabled")) {
- return false;
+ PhoneAccountHandle phoneAccountHandle = PhoneAccountHandleConverter.fromSubId(subId);
+ if (phoneAccountHandle == null){
+ return null;
}
- return VisualVoicemailSettingsUtil.isEnabled(mPhone.getContext(), phoneAccountHandle);
+ return VisualVoicemailSettingsUtil.dump(mPhone.getContext(), phoneAccountHandle);
}
@Override
@@ -2195,6 +2215,21 @@
}
/**
+ * Send the dialer code if called from the current default dialer or the caller has
+ * carrier privilege.
+ * @param inputCode The dialer code to send
+ */
+ @Override
+ public void sendDialerSpecialCode(String callingPackage, String inputCode) {
+ mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
+ String defaultDialer = TelecomManager.from(mPhone.getContext()).getDefaultDialerPackage();
+ if (!TextUtils.equals(callingPackage, defaultDialer)) {
+ enforceCarrierPrivilege(getDefaultSubscription());
+ }
+ mPhone.sendDialerSpecialCode(inputCode);
+ }
+
+ /**
* Returns the data network type.
* Legacy call, permission-free.
*
@@ -2283,9 +2318,8 @@
*/
@Override
public boolean hasIccCardUsingSlotIndex(int slotIndex) {
- int subId[] = mSubscriptionController.getSubIdUsingSlotIndex(slotIndex);
- final Phone phone = getPhone(subId[0]);
- if (subId != null && phone != null) {
+ final Phone phone = PhoneFactory.getPhone(slotIndex);
+ if (phone != null) {
return phone.getIccCard().hasIccCard();
} else {
return false;
@@ -3262,22 +3296,41 @@
Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED) {
return true;
}
+
try {
return canReadPhoneState(callingPackage, message);
} catch (SecurityException readPhoneStateSecurityException) {
- try {
- // Can be read with READ_SMS too.
- mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_SMS, message);
- return mAppOps.noteOp(AppOpsManager.OP_READ_SMS,
- Binder.getCallingUid(), callingPackage) == AppOpsManager.MODE_ALLOWED;
- } catch (SecurityException readSmsSecurityException) {
- // Throw exception with message including both READ_PHONE_STATE and READ_SMS
- // permissions
- throw new SecurityException(message + ": Neither user " + Binder.getCallingUid() +
- " nor current process has " + android.Manifest.permission.READ_PHONE_STATE +
- " or " + android.Manifest.permission.READ_SMS + ".");
- }
}
+ // Can be read with READ_SMS too.
+ try {
+ mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_SMS, message);
+ int opCode = mAppOps.permissionToOpCode(android.Manifest.permission.READ_SMS);
+ if (opCode != AppOpsManager.OP_NONE) {
+ return mAppOps.noteOp(opCode, Binder.getCallingUid(), callingPackage)
+ == AppOpsManager.MODE_ALLOWED;
+ } else {
+ return true;
+ }
+ } catch (SecurityException readSmsSecurityException) {
+ }
+ // Can be read with READ_PHONE_NUMBERS too.
+ try {
+ mApp.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_NUMBERS,
+ message);
+ int opCode = mAppOps.permissionToOpCode(android.Manifest.permission.READ_PHONE_NUMBERS);
+ if (opCode != AppOpsManager.OP_NONE) {
+ return mAppOps.noteOp(opCode, Binder.getCallingUid(), callingPackage)
+ == AppOpsManager.MODE_ALLOWED;
+ } else {
+ return true;
+ }
+ } catch (SecurityException readPhoneNumberSecurityException) {
+ }
+
+ throw new SecurityException(message + ": Neither user " + Binder.getCallingUid() +
+ " nor current process has" + android.Manifest.permission.READ_PHONE_STATE +
+ ", " + android.Manifest.permission.READ_SMS + ", or " +
+ android.Manifest.permission.READ_PHONE_NUMBERS);
}
@Override
@@ -3432,12 +3485,39 @@
*/
@Override
public Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) {
- final Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(accountHandle);
+ Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(accountHandle);
if (phone == null) {
- return null;
+ phone = mPhone;
}
- return VoicemailNotificationSettingsUtil.getRingtoneUri(phone);
+ return VoicemailNotificationSettingsUtil.getRingtoneUri(phone.getContext());
+ }
+
+ /**
+ * Sets the per-account voicemail ringtone.
+ *
+ * <p>Requires that the calling app is the default dialer, or has carrier privileges, or
+ * has permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+ *
+ * @param phoneAccountHandle The handle for the {@link PhoneAccount} for which to set the
+ * voicemail ringtone.
+ * @param uri The URI for the ringtone to play when receiving a voicemail from a specific
+ * PhoneAccount.
+ */
+ @Override
+ public void setVoicemailRingtoneUri(String callingPackage,
+ PhoneAccountHandle phoneAccountHandle, Uri uri) {
+ mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
+ if (!TextUtils.equals(callingPackage,
+ TelecomManager.from(mPhone.getContext()).getDefaultDialerPackage())) {
+ enforceModifyPermissionOrCarrierPrivilege(
+ PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccountHandle));
+ }
+ Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(phoneAccountHandle);
+ if (phone == null){
+ phone = mPhone;
+ }
+ VoicemailNotificationSettingsUtil.setRingtoneUri(phone.getContext(), uri);
}
/**
@@ -3449,12 +3529,40 @@
*/
@Override
public boolean isVoicemailVibrationEnabled(PhoneAccountHandle accountHandle) {
- final Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(accountHandle);
+ Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(accountHandle);
if (phone == null) {
- return false;
+ phone = mPhone;
}
- return VoicemailNotificationSettingsUtil.isVibrationEnabled(phone);
+ return VoicemailNotificationSettingsUtil.isVibrationEnabled(phone.getContext());
+ }
+
+ /**
+ * Sets the per-account voicemail vibration.
+ *
+ * <p>Requires that the calling app is the default dialer, or has carrier privileges, or
+ * has permission {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+ *
+ * @param phoneAccountHandle The handle for the {@link PhoneAccount} for which to set the
+ * voicemail vibration setting.
+ * @param enabled Whether to enable or disable vibration for voicemail notifications from a
+ * specific PhoneAccount.
+ */
+ @Override
+ public void setVoicemailVibrationEnabled(String callingPackage,
+ PhoneAccountHandle phoneAccountHandle, boolean enabled) {
+ mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
+ if (!TextUtils.equals(callingPackage,
+ TelecomManager.from(mPhone.getContext()).getDefaultDialerPackage())) {
+ enforceModifyPermissionOrCarrierPrivilege(
+ PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccountHandle));
+ }
+
+ Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(phoneAccountHandle);
+ if (phone == null){
+ phone = mPhone;
+ }
+ VoicemailNotificationSettingsUtil.setVibrationEnabled(phone.getContext(), enabled);
}
/**
@@ -3483,8 +3591,12 @@
* @throws SecurityException if the caller is not the visual voicemail package.
*/
private void enforceVisualVoicemailPackage(String callingPackage, int subId) {
- String vvmPackage = RemoteVvmTaskManager.getRemotePackage(mPhone.getContext(), subId)
- .getPackageName();
+ ComponentName componentName =
+ RemoteVvmTaskManager.getRemotePackage(mPhone.getContext(), subId);
+ if(componentName == null) {
+ throw new SecurityException("Caller not current active visual voicemail package[null]");
+ }
+ String vvmPackage = componentName.getPackageName();
if (!callingPackage.equals(vvmPackage)) {
throw new SecurityException("Caller not current active visual voicemail package[" +
vvmPackage + "]");
@@ -3580,6 +3692,11 @@
@Override
public int setAllowedCarriers(int slotIndex, List<CarrierIdentifier> carriers) {
enforceModifyPermission();
+
+ if (carriers == null) {
+ throw new NullPointerException("carriers cannot be null");
+ }
+
int subId = SubscriptionManager.getSubId(slotIndex)[0];
int[] retVal = (int[]) sendRequest(CMD_SET_ALLOWED_CARRIERS, carriers, subId);
return retVal[0];
@@ -3739,17 +3856,28 @@
@Override
public void setSimPowerStateForSlot(int slotIndex, int state) {
enforceModifyPermission();
- int subId[] = mSubscriptionController.getSubIdUsingSlotIndex(slotIndex);
- if (subId == null || subId.length == 0) {
- return;
- }
+ Phone phone = PhoneFactory.getPhone(slotIndex);
- final Phone phone = getPhone(subId[0]);
if (phone != null) {
phone.setSimPowerState(state);
}
}
+ private boolean isUssdApiAllowed(int subId) {
+ CarrierConfigManager configManager =
+ (CarrierConfigManager) mPhone.getContext().getSystemService(
+ Context.CARRIER_CONFIG_SERVICE);
+ if (configManager == null) {
+ return false;
+ }
+ PersistableBundle pb = configManager.getConfigForSubId(subId);
+ if (pb == null) {
+ return false;
+ }
+ return pb.getBoolean(
+ CarrierConfigManager.KEY_ALLOW_USSD_REQUESTS_VIA_TELEPHONY_MANAGER_BOOL);
+ }
+
/**
* Check if phone is in emergency callback mode
* @return true if phone is in emergency callback mode
diff --git a/src/com/android/phone/PhoneSearchIndexablesProvider.java b/src/com/android/phone/PhoneSearchIndexablesProvider.java
index 85ea653..171f74f 100644
--- a/src/com/android/phone/PhoneSearchIndexablesProvider.java
+++ b/src/com/android/phone/PhoneSearchIndexablesProvider.java
@@ -16,11 +16,14 @@
package com.android.phone;
+import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
+import android.os.UserManager;
import android.provider.SearchIndexableResource;
import android.provider.SearchIndexablesProvider;
+import static android.provider.SearchIndexablesContract.COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RANK;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_RESID;
import static android.provider.SearchIndexablesContract.COLUMN_INDEX_XML_RES_CLASS_NAME;
@@ -70,9 +73,23 @@
MatrixCursor cursor = new MatrixCursor(INDEXABLES_RAW_COLUMNS);
return cursor;
}
+
@Override
public Cursor queryNonIndexableKeys(String[] projection) {
MatrixCursor cursor = new MatrixCursor(NON_INDEXABLES_KEYS_COLUMNS);
+ final UserManager userManager = (UserManager) getContext().getSystemService(
+ Context.USER_SERVICE);
+ if (!userManager.isAdminUser()) {
+ final String[] values = new String[]{"preferred_network_mode_key", "button_roaming_key",
+ "cdma_lte_data_service_key", "enabled_networks_key", "enhanced_4g_lte",
+ "button_apn_key", "button_carrier_sel_key", "carrier_settings_key",
+ "cdma_system_select_key", "carrier_settings_euicc_key"};
+ for (String nik : values) {
+ final Object[] ref = new Object[NON_INDEXABLES_KEYS_COLUMNS.length];
+ ref[COLUMN_INDEX_NON_INDEXABLE_KEYS_KEY_VALUE] = nik;
+ cursor.addRow(ref);
+ }
+ }
return cursor;
}
}
diff --git a/src/com/android/phone/PhoneUtils.java b/src/com/android/phone/PhoneUtils.java
index d92d349..40025c1 100644
--- a/src/com/android/phone/PhoneUtils.java
+++ b/src/com/android/phone/PhoneUtils.java
@@ -787,7 +787,7 @@
MmiCode mmiCode,
Message buttonCallbackMessage,
Dialog previousAlert) {
- if (DBG) log("displayMMIInitiate: " + mmiCode);
+ log("displayMMIInitiate: " + android.telecom.Log.pii(mmiCode.toString()));
if (previousAlert != null) {
previousAlert.dismiss();
}
@@ -824,13 +824,13 @@
boolean isCancelable = (mmiCode != null) && mmiCode.isCancelable();
if (!isCancelable) {
- if (DBG) log("not a USSD code, displaying status toast.");
+ log("displayMMIInitiate: not a USSD code, displaying status toast.");
CharSequence text = context.getText(R.string.mmiStarted);
Toast.makeText(context, text, Toast.LENGTH_SHORT)
.show();
return null;
} else {
- if (DBG) log("running USSD code, displaying indeterminate progress.");
+ log("displayMMIInitiate: running USSD code, displaying intermediate progress.");
// create the indeterminate progress dialog and display it.
ProgressDialog pd = new ProgressDialog(context, THEME);
@@ -862,13 +862,13 @@
int title = 0; // title for the progress dialog, if needed.
MmiCode.State state = mmiCode.getState();
- if (DBG) log("displayMMIComplete: state=" + state);
+ log("displayMMIComplete: state=" + state);
switch (state) {
case PENDING:
// USSD code asking for feedback from user.
text = mmiCode.getMessage();
- if (DBG) log("- using text from PENDING MMI message: '" + text + "'");
+ log("displayMMIComplete: using text from PENDING MMI message: '" + text + "'");
break;
case CANCELLED:
text = null;
@@ -887,7 +887,7 @@
case FAILED:
text = mmiCode.getMessage();
- if (DBG) log("- using text from MMI message: '" + text + "'");
+ log("displayMMIComplete (failed): using text from MMI message: '" + text + "'");
break;
default:
throw new IllegalStateException("Unexpected MmiCode state: " + state);
@@ -929,9 +929,9 @@
// A USSD in a pending state means that it is still
// interacting with the user.
if (state != MmiCode.State.PENDING) {
- if (DBG) log("MMI code has finished running.");
+ log("displayMMIComplete: MMI code has finished running.");
- if (DBG) log("Extended NW displayMMIInitiate (" + text + ")");
+ log("displayMMIComplete: Extended NW displayMMIInitiate (" + text + ")");
if (text == null || text.length() == 0)
return;
@@ -966,7 +966,8 @@
sUssdDialog.setMessage(sUssdMsg.toString());
sUssdDialog.show();
} else {
- if (DBG) log("USSD code has requested user input. Constructing input dialog.");
+ log("displayMMIComplete: USSD code has requested user input. Constructing input "
+ + "dialog.");
// USSD MMI code that is interacting with the user. The
// basic set of steps is this:
diff --git a/src/com/android/phone/SpecialCharSequenceMgr.java b/src/com/android/phone/SpecialCharSequenceMgr.java
index 4e2120e..3c02a30 100644
--- a/src/com/android/phone/SpecialCharSequenceMgr.java
+++ b/src/com/android/phone/SpecialCharSequenceMgr.java
@@ -108,7 +108,7 @@
|| handleRegulatoryInfoDisplay(context, dialString)
|| handlePinEntry(context, dialString, pukInputActivity)
|| handleAdnEntry(context, dialString)
- || handleSecretCode(context, dialString)) {
+ || handleSecretCode(dialString)) {
return true;
}
@@ -143,24 +143,21 @@
}
/**
- * Handles secret codes to launch arbitrary activities in the form of *#*#<code>#*#*.
- * If a secret code is encountered an Intent is started with the android_secret_code://<code>
- * URI.
+ * Handles secret codes to launch arbitrary receivers in the form of *#*#<code>#*#*.
+ * If a secret code is encountered, an broadcast intent is sent with the
+ * android_secret_code://<code> URI.
*
- * @param context the context to use
* @param input the text to check for a secret code in
- * @return true if a secret code was encountered
+ * @return true if a secret code was encountered and intent is sent out
*/
- static private boolean handleSecretCode(Context context, String input) {
+ static private boolean handleSecretCode(String input) {
// Secret codes are in the form *#*#<code>#*#*
int len = input.length();
if (len > 8 && input.startsWith("*#*#") && input.endsWith("#*#*")) {
- Intent intent = new Intent(TelephonyIntents.SECRET_CODE_ACTION,
- Uri.parse("android_secret_code://" + input.substring(4, len - 4)));
- context.sendBroadcast(intent);
+ final Phone phone = PhoneGlobals.getPhone();
+ phone.sendDialerSpecialCode(input.substring(4, len - 4));
return true;
}
-
return false;
}
diff --git a/src/com/android/phone/VoicemailStatus.java b/src/com/android/phone/VoicemailStatus.java
deleted file mode 100644
index 00130f1..0000000
--- a/src/com/android/phone/VoicemailStatus.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone;
-
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.net.Uri;
-import android.provider.VoicemailContract;
-import android.provider.VoicemailContract.Status;
-import android.telecom.PhoneAccountHandle;
-import com.android.phone.vvm.omtp.VvmLog;
-
-public class VoicemailStatus {
-
- private static final String TAG = "VvmStatus";
-
- public static class Editor {
-
- private final Context mContext;
- @Nullable
- private final PhoneAccountHandle mPhoneAccountHandle;
-
- private ContentValues mValues = new ContentValues();
-
- private Editor(Context context, PhoneAccountHandle phoneAccountHandle) {
- mContext = context;
- mPhoneAccountHandle = phoneAccountHandle;
- if (mPhoneAccountHandle == null) {
- VvmLog.w(TAG, "VoicemailStatus.Editor created with null phone account, status will"
- + " not be written");
- }
- }
-
- @Nullable
- public PhoneAccountHandle getPhoneAccountHandle() {
- return mPhoneAccountHandle;
- }
-
- public Editor setType(String type) {
- mValues.put(Status.SOURCE_TYPE, type);
- return this;
- }
-
- public Editor setConfigurationState(int configurationState) {
- mValues.put(Status.CONFIGURATION_STATE, configurationState);
- return this;
- }
-
- public Editor setDataChannelState(int dataChannelState) {
- mValues.put(Status.DATA_CHANNEL_STATE, dataChannelState);
- return this;
- }
-
- public Editor setNotificationChannelState(int notificationChannelState) {
- mValues.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
- return this;
- }
-
- public Editor setQuota(int occupied, int total) {
- if (occupied == VoicemailContract.Status.QUOTA_UNAVAILABLE
- && total == VoicemailContract.Status.QUOTA_UNAVAILABLE) {
- return this;
- }
-
- mValues.put(Status.QUOTA_OCCUPIED, occupied);
- mValues.put(Status.QUOTA_TOTAL, total);
- return this;
- }
-
- /**
- * 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 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());
- 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() {
- return mValues;
- }
- }
-
- /**
- * A voicemail status editor that the decision of whether to actually write to the database can
- * be deferred. This object will be passed around as a usual {@link Editor}, but {@link
- * #apply()} doesn't do anything. If later the creator of this object decides any status changes
- * written to it should be committed, {@link #deferredApply()} should be called.
- */
- public static class DeferredEditor extends Editor {
-
- private DeferredEditor(Context context, PhoneAccountHandle phoneAccountHandle) {
- super(context, phoneAccountHandle);
- }
-
- @Override
- public boolean apply() {
- // Do nothing
- return true;
- }
-
- public void deferredApply() {
- super.apply();
- }
- }
-
- public static Editor edit(Context context, PhoneAccountHandle phoneAccountHandle) {
- return new Editor(context, phoneAccountHandle);
- }
-
- /**
- * Reset the status to the "disabled" state, which the UI should not show anything for this
- * subId.
- */
- public static void disable(Context context, PhoneAccountHandle phoneAccountHandle) {
- edit(context, phoneAccountHandle)
- .setConfigurationState(Status.CONFIGURATION_STATE_NOT_CONFIGURED)
- .setDataChannelState(Status.DATA_CHANNEL_STATE_NO_CONNECTION)
- .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION)
- .apply();
- }
-
- public static DeferredEditor deferredEdit(Context context,
- PhoneAccountHandle phoneAccountHandle) {
- return new DeferredEditor(context, phoneAccountHandle);
- }
-}
diff --git a/src/com/android/phone/common/mail/Address.java b/src/com/android/phone/common/mail/Address.java
deleted file mode 100644
index 5928b63..0000000
--- a/src/com/android/phone/common/mail/Address.java
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.Html;
-import android.text.TextUtils;
-import android.text.util.Rfc822Token;
-import android.text.util.Rfc822Tokenizer;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.phone.common.mail.utils.LogUtils;
-
-import org.apache.james.mime4j.codec.EncoderUtil;
-import org.apache.james.mime4j.decoder.DecoderUtil;
-
-import java.util.ArrayList;
-import java.util.regex.Pattern;
-
-/**
- * This class represent email address.
- *
- * RFC822 email address may have following format.
- * "name" <address> (comment)
- * "name" <address>
- * name <address>
- * address
- * Name and comment part should be MIME/base64 encoded in header if necessary.
- *
- */
-public class Address implements Parcelable {
- public static final String ADDRESS_DELIMETER = ",";
- /**
- * Address part, in the form local_part@domain_part. No surrounding angle brackets.
- */
- private String mAddress;
-
- /**
- * Name part. No surrounding double quote, and no MIME/base64 encoding.
- * This must be null if Address has no name part.
- */
- private String mPersonal;
-
- /**
- * When personal is set, it will return the first token of the personal
- * string. Otherwise, it will return the e-mail address up to the '@' sign.
- */
- private String mSimplifiedName;
-
- // Regex that matches address surrounded by '<>' optionally. '^<?([^>]+)>?$'
- private static final Pattern REMOVE_OPTIONAL_BRACKET = Pattern.compile("^<?([^>]+)>?$");
- // Regex that matches personal name surrounded by '""' optionally. '^"?([^"]+)"?$'
- private static final Pattern REMOVE_OPTIONAL_DQUOTE = Pattern.compile("^\"?([^\"]*)\"?$");
- // Regex that matches escaped character '\\([\\"])'
- private static final Pattern UNQUOTE = Pattern.compile("\\\\([\\\\\"])");
-
- // TODO: LOCAL_PART and DOMAIN_PART_PART are too permissive and can be improved.
- // TODO: Fix this to better constrain comments.
- /** Regex for the local part of an email address. */
- private static final String LOCAL_PART = "[^@]+";
- /** Regex for each part of the domain part, i.e. the thing between the dots. */
- private static final String DOMAIN_PART_PART = "[[\\w][\\d]\\-\\(\\)\\[\\]]+";
- /** Regex for the domain part, which is two or more {@link #DOMAIN_PART_PART} separated by . */
- private static final String DOMAIN_PART =
- "(" + DOMAIN_PART_PART + "\\.)+" + DOMAIN_PART_PART;
-
- /** Pattern to check if an email address is valid. */
- private static final Pattern EMAIL_ADDRESS =
- Pattern.compile("\\A" + LOCAL_PART + "@" + DOMAIN_PART + "\\z");
-
- private static final Address[] EMPTY_ADDRESS_ARRAY = new Address[0];
-
- // delimiters are chars that do not appear in an email address, used by fromHeader
- private static final char LIST_DELIMITER_EMAIL = '\1';
- private static final char LIST_DELIMITER_PERSONAL = '\2';
-
- private static final String LOG_TAG = "Email Address";
-
- @VisibleForTesting
- public Address(String address) {
- setAddress(address);
- }
-
- public Address(String address, String personal) {
- setPersonal(personal);
- setAddress(address);
- }
-
- /**
- * Returns a simplified string for this e-mail address.
- * When a name is known, it will return the first token of that name. Otherwise, it will
- * return the e-mail address up to the '@' sign.
- */
- public String getSimplifiedName() {
- if (mSimplifiedName == null) {
- if (TextUtils.isEmpty(mPersonal) && !TextUtils.isEmpty(mAddress)) {
- int atSign = mAddress.indexOf('@');
- mSimplifiedName = (atSign != -1) ? mAddress.substring(0, atSign) : "";
- } else if (!TextUtils.isEmpty(mPersonal)) {
-
- // TODO: use Contacts' NameSplitter for more reliable first-name extraction
-
- int end = mPersonal.indexOf(' ');
- while (end > 0 && mPersonal.charAt(end - 1) == ',') {
- end--;
- }
- mSimplifiedName = (end < 1) ? mPersonal : mPersonal.substring(0, end);
-
- } else {
- LogUtils.w(LOG_TAG, "Unable to get a simplified name");
- mSimplifiedName = "";
- }
- }
- return mSimplifiedName;
- }
-
- public static synchronized Address getEmailAddress(String rawAddress) {
- if (TextUtils.isEmpty(rawAddress)) {
- return null;
- }
- String name, address;
- final Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(rawAddress);
- if (tokens.length > 0) {
- final String tokenizedName = tokens[0].getName();
- name = tokenizedName != null ? Html.fromHtml(tokenizedName.trim()).toString()
- : "";
- address = Html.fromHtml(tokens[0].getAddress()).toString();
- } else {
- name = "";
- address = rawAddress == null ?
- "" : Html.fromHtml(rawAddress).toString();
- }
- return new Address(address, name);
- }
-
- public String getAddress() {
- return mAddress;
- }
-
- public void setAddress(String address) {
- mAddress = REMOVE_OPTIONAL_BRACKET.matcher(address).replaceAll("$1");
- }
-
- /**
- * Get name part as UTF-16 string. No surrounding double quote, and no MIME/base64 encoding.
- *
- * @return Name part of email address. Returns null if it is omitted.
- */
- public String getPersonal() {
- return mPersonal;
- }
-
- /**
- * Set personal part from UTF-16 string. Optional surrounding double quote will be removed.
- * It will be also unquoted and MIME/base64 decoded.
- *
- * @param personal name part of email address as UTF-16 string. Null is acceptable.
- */
- public void setPersonal(String personal) {
- mPersonal = decodeAddressPersonal(personal);
- }
-
- /**
- * Decodes name from UTF-16 string. Optional surrounding double quote will be removed.
- * It will be also unquoted and MIME/base64 decoded.
- *
- * @param personal name part of email address as UTF-16 string. Null is acceptable.
- */
- public static String decodeAddressPersonal(String personal) {
- if (personal != null) {
- personal = REMOVE_OPTIONAL_DQUOTE.matcher(personal).replaceAll("$1");
- personal = UNQUOTE.matcher(personal).replaceAll("$1");
- personal = DecoderUtil.decodeEncodedWords(personal);
- if (personal.length() == 0) {
- personal = null;
- }
- }
- return personal;
- }
-
- /**
- * This method is used to check that all the addresses that the user
- * entered in a list (e.g. To:) are valid, so that none is dropped.
- */
- @VisibleForTesting
- public static boolean isAllValid(String addressList) {
- // This code mimics the parse() method below.
- // I don't know how to better avoid the code-duplication.
- if (addressList != null && addressList.length() > 0) {
- Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(addressList);
- for (int i = 0, length = tokens.length; i < length; ++i) {
- Rfc822Token token = tokens[i];
- String address = token.getAddress();
- if (!TextUtils.isEmpty(address) && !isValidAddress(address)) {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * Parse a comma-delimited list of addresses in RFC822 format and return an
- * array of Address objects.
- *
- * @param addressList Address list in comma-delimited string.
- * @return An array of 0 or more Addresses.
- */
- public static Address[] parse(String addressList) {
- if (addressList == null || addressList.length() == 0) {
- return EMPTY_ADDRESS_ARRAY;
- }
- Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(addressList);
- ArrayList<Address> addresses = new ArrayList<Address>();
- for (int i = 0, length = tokens.length; i < length; ++i) {
- Rfc822Token token = tokens[i];
- String address = token.getAddress();
- if (!TextUtils.isEmpty(address)) {
- if (isValidAddress(address)) {
- String name = token.getName();
- if (TextUtils.isEmpty(name)) {
- name = null;
- }
- addresses.add(new Address(address, name));
- }
- }
- }
- return addresses.toArray(new Address[addresses.size()]);
- }
-
- /**
- * Checks whether a string email address is valid.
- * E.g. name@domain.com is valid.
- */
- @VisibleForTesting
- static boolean isValidAddress(final String address) {
- return EMAIL_ADDRESS.matcher(address).find();
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof Address) {
- // It seems that the spec says that the "user" part is case-sensitive,
- // while the domain part in case-insesitive.
- // So foo@yahoo.com and Foo@yahoo.com are different.
- // This may seem non-intuitive from the user POV, so we
- // may re-consider it if it creates UI trouble.
- // A problem case is "replyAll" sending to both
- // a@b.c and to A@b.c, which turn out to be the same on the server.
- // Leave unchanged for now (i.e. case-sensitive).
- return getAddress().equals(((Address) o).getAddress());
- }
- return super.equals(o);
- }
-
- @Override
- public int hashCode() {
- return getAddress().hashCode();
- }
-
- /**
- * Get human readable address string.
- * Do not use this for email header.
- *
- * @return Human readable address string. Not quoted and not encoded.
- */
- @Override
- public String toString() {
- if (mPersonal != null && !mPersonal.equals(mAddress)) {
- if (mPersonal.matches(".*[\\(\\)<>@,;:\\\\\".\\[\\]].*")) {
- return ensureQuotedString(mPersonal) + " <" + mAddress + ">";
- } else {
- return mPersonal + " <" + mAddress + ">";
- }
- } else {
- return mAddress;
- }
- }
-
- /**
- * Ensures that the given string starts and ends with the double quote character. The string is
- * not modified in any way except to add the double quote character to start and end if it's not
- * already there.
- *
- * sample -> "sample"
- * "sample" -> "sample"
- * ""sample"" -> "sample"
- * "sample"" -> "sample"
- * sa"mp"le -> "sa"mp"le"
- * "sa"mp"le" -> "sa"mp"le"
- * (empty string) -> ""
- * " -> ""
- */
- private static String ensureQuotedString(String s) {
- if (s == null) {
- return null;
- }
- if (!s.matches("^\".*\"$")) {
- return "\"" + s + "\"";
- } else {
- return s;
- }
- }
-
- /**
- * Get human readable comma-delimited address string.
- *
- * @param addresses Address array
- * @return Human readable comma-delimited address string.
- */
- @VisibleForTesting
- public static String toString(Address[] addresses) {
- return toString(addresses, ADDRESS_DELIMETER);
- }
-
- /**
- * Get human readable address strings joined with the specified separator.
- *
- * @param addresses Address array
- * @param separator Separator
- * @return Human readable comma-delimited address string.
- */
- public static String toString(Address[] addresses, String separator) {
- if (addresses == null || addresses.length == 0) {
- return null;
- }
- if (addresses.length == 1) {
- return addresses[0].toString();
- }
- StringBuilder sb = new StringBuilder(addresses[0].toString());
- for (int i = 1; i < addresses.length; i++) {
- sb.append(separator);
- // TODO: investigate why this .trim() is needed.
- sb.append(addresses[i].toString().trim());
- }
- return sb.toString();
- }
-
- /**
- * Get RFC822/MIME compatible address string.
- *
- * @return RFC822/MIME compatible address string.
- * It may be surrounded by double quote or quoted and MIME/base64 encoded if necessary.
- */
- public String toHeader() {
- if (mPersonal != null) {
- return EncoderUtil.encodeAddressDisplayName(mPersonal) + " <" + mAddress + ">";
- } else {
- return mAddress;
- }
- }
-
- /**
- * Get RFC822/MIME compatible comma-delimited address string.
- *
- * @param addresses Address array
- * @return RFC822/MIME compatible comma-delimited address string.
- * it may be surrounded by double quoted or quoted and MIME/base64 encoded if necessary.
- */
- public static String toHeader(Address[] addresses) {
- if (addresses == null || addresses.length == 0) {
- return null;
- }
- if (addresses.length == 1) {
- return addresses[0].toHeader();
- }
- StringBuilder sb = new StringBuilder(addresses[0].toHeader());
- for (int i = 1; i < addresses.length; i++) {
- // We need space character to be able to fold line.
- sb.append(", ");
- sb.append(addresses[i].toHeader());
- }
- return sb.toString();
- }
-
- /**
- * Get Human friendly address string.
- *
- * @return the personal part of this Address, or the address part if the
- * personal part is not available
- */
- @VisibleForTesting
- public String toFriendly() {
- if (mPersonal != null && mPersonal.length() > 0) {
- return mPersonal;
- } else {
- return mAddress;
- }
- }
-
- /**
- * Creates a comma-delimited list of addresses in the "friendly" format (see toFriendly() for
- * details on the per-address conversion).
- *
- * @param addresses Array of Address[] values
- * @return A comma-delimited string listing all of the addresses supplied. Null if source
- * was null or empty.
- */
- @VisibleForTesting
- public static String toFriendly(Address[] addresses) {
- if (addresses == null || addresses.length == 0) {
- return null;
- }
- if (addresses.length == 1) {
- return addresses[0].toFriendly();
- }
- StringBuilder sb = new StringBuilder(addresses[0].toFriendly());
- for (int i = 1; i < addresses.length; i++) {
- sb.append(", ");
- sb.append(addresses[i].toFriendly());
- }
- return sb.toString();
- }
-
- /**
- * Returns exactly the same result as Address.toString(Address.fromHeader(addressList)).
- */
- @VisibleForTesting
- public static String fromHeaderToString(String addressList) {
- return toString(fromHeader(addressList));
- }
-
- /**
- * Returns exactly the same result as Address.toHeader(Address.parse(addressList)).
- */
- @VisibleForTesting
- public static String parseToHeader(String addressList) {
- return Address.toHeader(Address.parse(addressList));
- }
-
- /**
- * Returns null if the addressList has 0 addresses, otherwise returns the first address.
- * The same as Address.fromHeader(addressList)[0] for non-empty list.
- * This is an utility method that offers some performance optimization opportunities.
- */
- @VisibleForTesting
- public static Address firstAddress(String addressList) {
- Address[] array = fromHeader(addressList);
- return array.length > 0 ? array[0] : null;
- }
-
- /**
- * This method exists to convert an address list formatted in a deprecated legacy format to the
- * standard RFC822 header format. {@link #fromHeader(String)} is capable of reading the legacy
- * format and the RFC822 format. {@link #toHeader()} always produces the RFC822 format.
- *
- * This implementation is brute-force, and could be replaced with a more efficient version
- * if desired.
- */
- public static String reformatToHeader(String addressList) {
- return toHeader(fromHeader(addressList));
- }
-
- /**
- * @param addressList a CSV of RFC822 addresses or the deprecated legacy string format
- * @return array of addresses parsed from <code>addressList</code>
- */
- @VisibleForTesting
- public static Address[] fromHeader(String addressList) {
- if (addressList == null || addressList.length() == 0) {
- return EMPTY_ADDRESS_ARRAY;
- }
- // IF we're CSV, just parse
- if ((addressList.indexOf(LIST_DELIMITER_PERSONAL) == -1) &&
- (addressList.indexOf(LIST_DELIMITER_EMAIL) == -1)) {
- return Address.parse(addressList);
- }
- // Otherwise, do backward-compatible unpack
- ArrayList<Address> addresses = new ArrayList<Address>();
- int length = addressList.length();
- int pairStartIndex = 0;
- int pairEndIndex;
-
- /* addressEndIndex is only re-scanned (indexOf()) when a LIST_DELIMITER_PERSONAL
- is used, not for every email address; i.e. not for every iteration of the while().
- This reduces the theoretical complexity from quadratic to linear,
- and provides some speed-up in practice by removing redundant scans of the string.
- */
- int addressEndIndex = addressList.indexOf(LIST_DELIMITER_PERSONAL);
-
- while (pairStartIndex < length) {
- pairEndIndex = addressList.indexOf(LIST_DELIMITER_EMAIL, pairStartIndex);
- if (pairEndIndex == -1) {
- pairEndIndex = length;
- }
- Address address;
- if (addressEndIndex == -1 || pairEndIndex <= addressEndIndex) {
- // in this case the DELIMITER_PERSONAL is in a future pair,
- // so don't use personal, and don't update addressEndIndex
- address = new Address(addressList.substring(pairStartIndex, pairEndIndex), null);
- } else {
- address = new Address(addressList.substring(pairStartIndex, addressEndIndex),
- addressList.substring(addressEndIndex + 1, pairEndIndex));
- // only update addressEndIndex when we use the LIST_DELIMITER_PERSONAL
- addressEndIndex = addressList.indexOf(LIST_DELIMITER_PERSONAL, pairEndIndex + 1);
- }
- addresses.add(address);
- pairStartIndex = pairEndIndex + 1;
- }
- return addresses.toArray(new Address[addresses.size()]);
- }
-
- public static final Creator<Address> CREATOR = new Creator<Address>() {
- @Override
- public Address createFromParcel(Parcel parcel) {
- return new Address(parcel);
- }
-
- @Override
- public Address[] newArray(int size) {
- return new Address[size];
- }
- };
-
- public Address(Parcel in) {
- setPersonal(in.readString());
- setAddress(in.readString());
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(mPersonal);
- out.writeString(mAddress);
- }
-}
diff --git a/src/com/android/phone/common/mail/AuthenticationFailedException.java b/src/com/android/phone/common/mail/AuthenticationFailedException.java
deleted file mode 100644
index f13ab45..0000000
--- a/src/com/android/phone/common/mail/AuthenticationFailedException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-public class AuthenticationFailedException extends MessagingException {
- public static final long serialVersionUID = -1;
-
- public AuthenticationFailedException(String message) {
- super(MessagingException.AUTHENTICATION_FAILED, message);
- }
-
- public AuthenticationFailedException(int exceptionType, String message) {
- super(exceptionType, message);
- }
-
- public AuthenticationFailedException(String message, Throwable throwable) {
- super(MessagingException.AUTHENTICATION_FAILED, message, throwable);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/Base64Body.java b/src/com/android/phone/common/mail/Base64Body.java
deleted file mode 100644
index 757b4b7..0000000
--- a/src/com/android/phone/common/mail/Base64Body.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import android.util.Base64;
-import android.util.Base64OutputStream;
-
-import org.apache.commons.io.IOUtils;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-public class Base64Body implements Body {
- private final InputStream mSource;
- // Because we consume the input stream, we can only write out once
- private boolean mAlreadyWritten;
-
- public Base64Body(InputStream source) {
- mSource = source;
- }
-
- @Override
- public InputStream getInputStream() throws MessagingException {
- return mSource;
- }
-
- /**
- * This method consumes the input stream, so can only be called once
- * @param out Stream to write to
- * @throws IllegalStateException If called more than once
- * @throws IOException
- * @throws MessagingException
- */
- @Override
- public void writeTo(OutputStream out)
- throws IllegalStateException, IOException, MessagingException {
- if (mAlreadyWritten) {
- throw new IllegalStateException("Base64Body can only be written once");
- }
- mAlreadyWritten = true;
- try {
- final Base64OutputStream b64out = new Base64OutputStream(out, Base64.DEFAULT);
- IOUtils.copyLarge(mSource, b64out);
- } finally {
- mSource.close();
- }
- }
-}
diff --git a/src/com/android/phone/common/mail/Body.java b/src/com/android/phone/common/mail/Body.java
deleted file mode 100644
index 8625ef2..0000000
--- a/src/com/android/phone/common/mail/Body.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-public interface Body {
- public InputStream getInputStream() throws MessagingException;
- public void writeTo(OutputStream out) throws IOException, MessagingException;
-}
diff --git a/src/com/android/phone/common/mail/BodyPart.java b/src/com/android/phone/common/mail/BodyPart.java
deleted file mode 100644
index 78140c8..0000000
--- a/src/com/android/phone/common/mail/BodyPart.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-public abstract class BodyPart implements Part {
- protected Multipart mParent;
-
- public Multipart getParent() {
- return mParent;
- }
-}
diff --git a/src/com/android/phone/common/mail/CertificateValidationException.java b/src/com/android/phone/common/mail/CertificateValidationException.java
deleted file mode 100644
index d8ae9b4..0000000
--- a/src/com/android/phone/common/mail/CertificateValidationException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-public class CertificateValidationException extends MessagingException {
- public static final long serialVersionUID = -1;
-
- public CertificateValidationException(String message) {
- super(MessagingException.CERTIFICATE_VALIDATION_ERROR, message);
- }
-
- public CertificateValidationException(String message, Throwable throwable) {
- super(MessagingException.CERTIFICATE_VALIDATION_ERROR, message, throwable);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/FetchProfile.java b/src/com/android/phone/common/mail/FetchProfile.java
deleted file mode 100644
index d88dc7c..0000000
--- a/src/com/android/phone/common/mail/FetchProfile.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import java.util.ArrayList;
-
-/**
- * <pre>
- * A FetchProfile is a list of items that should be downloaded in bulk for a set of messages.
- * FetchProfile can contain the following objects:
- * FetchProfile.Item: Described below.
- * Message: Indicates that the body of the entire message should be fetched.
- * Synonymous with FetchProfile.Item.BODY.
- * Part: Indicates that the given Part should be fetched. The provider
- * is expected have previously created the given BodyPart and stored
- * any information it needs to download the content.
- * </pre>
- */
-public class FetchProfile extends ArrayList<Fetchable> {
- /**
- * Default items available for pre-fetching. It should be expected that any
- * item fetched by using these items could potentially include all of the
- * previous items.
- */
- public enum Item implements Fetchable {
- /**
- * Download the flags of the message.
- */
- FLAGS,
-
- /**
- * Download the envelope of the message. This should include at minimum
- * the size and the following headers: date, subject, from, content-type, to, cc
- */
- ENVELOPE,
-
- /**
- * Download the structure of the message. This maps directly to IMAP's BODYSTRUCTURE
- * and may map to other providers.
- * The provider should, if possible, fill in a properly formatted MIME structure in
- * the message without actually downloading any message data. If the provider is not
- * capable of this operation it should specifically set the body of the message to null
- * so that upper levels can detect that a full body download is needed.
- */
- STRUCTURE,
-
- /**
- * A sane portion of the entire message, cut off at a provider determined limit.
- * This should generally be around 50kB.
- */
- BODY_SANE,
-
- /**
- * The entire message.
- */
- BODY,
- }
-
- /**
- * @return the first {@link Part} in this collection, or null if it doesn't contain
- * {@link Part}.
- */
- public Part getFirstPart() {
- for (Fetchable o : this) {
- if (o instanceof Part) {
- return (Part) o;
- }
- }
- return null;
- }
-}
diff --git a/src/com/android/phone/common/mail/Fetchable.java b/src/com/android/phone/common/mail/Fetchable.java
deleted file mode 100644
index 829c672..0000000
--- a/src/com/android/phone/common/mail/Fetchable.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-/**
- * Interface for classes that can be added to {@link FetchProfile}.
- * i.e. {@link Part} and its subclasses, and {@link FetchProfile.Item}.
- */
-public interface Fetchable {
-}
diff --git a/src/com/android/phone/common/mail/FixedLengthInputStream.java b/src/com/android/phone/common/mail/FixedLengthInputStream.java
deleted file mode 100644
index 499feca..0000000
--- a/src/com/android/phone/common/mail/FixedLengthInputStream.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * A filtering InputStream that stops allowing reads after the given length has been read. This
- * is used to allow a client to read directly from an underlying protocol stream without reading
- * past where the protocol handler intended the client to read.
- */
-public class FixedLengthInputStream extends InputStream {
- private final InputStream mIn;
- private final int mLength;
- private int mCount;
-
- public FixedLengthInputStream(InputStream in, int length) {
- this.mIn = in;
- this.mLength = length;
- }
-
- @Override
- public int available() throws IOException {
- return mLength - mCount;
- }
-
- @Override
- public int read() throws IOException {
- if (mCount < mLength) {
- mCount++;
- return mIn.read();
- } else {
- return -1;
- }
- }
-
- @Override
- public int read(byte[] b, int offset, int length) throws IOException {
- if (mCount < mLength) {
- int d = mIn.read(b, offset, Math.min(mLength - mCount, length));
- if (d == -1) {
- return -1;
- } else {
- mCount += d;
- return d;
- }
- } else {
- return -1;
- }
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- return read(b, 0, b.length);
- }
-
- public int getLength() {
- return mLength;
- }
-
- @Override
- public String toString() {
- return String.format("FixedLengthInputStream(in=%s, length=%d)", mIn.toString(), mLength);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/Flag.java b/src/com/android/phone/common/mail/Flag.java
deleted file mode 100644
index aa5d7e9..0000000
--- a/src/com/android/phone/common/mail/Flag.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-/**
- * Flags that can be applied to Messages.
- */
-public class Flag {
- // If adding new flags: ALL FLAGS MUST BE UPPER CASE.
- public static final String DELETED = "deleted";
- public static final String SEEN = "seen";
- public static final String ANSWERED = "answered";
- public static final String FLAGGED = "flagged";
- public static final String DRAFT = "draft";
- public static final String RECENT = "recent";
-}
diff --git a/src/com/android/phone/common/mail/MailTransport.java b/src/com/android/phone/common/mail/MailTransport.java
deleted file mode 100644
index 47b273c..0000000
--- a/src/com/android/phone/common/mail/MailTransport.java
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import android.content.Context;
-import android.net.Network;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.phone.common.mail.store.ImapStore;
-import com.android.phone.common.mail.utils.LogUtils;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.imap.ImapHelper;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
-
-/**
- * Make connection and perform operations on mail server by reading and writing lines.
- */
-public class MailTransport {
- private static final String TAG = "MailTransport";
-
- // TODO protected eventually
- /*protected*/ public static final int SOCKET_CONNECT_TIMEOUT = 10000;
- /*protected*/ public static final int SOCKET_READ_TIMEOUT = 60000;
-
- private static final HostnameVerifier HOSTNAME_VERIFIER =
- HttpsURLConnection.getDefaultHostnameVerifier();
-
- private final Context mContext;
- private final ImapHelper mImapHelper;
- private final Network mNetwork;
- private final String mHost;
- private final int mPort;
- private Socket mSocket;
- private BufferedInputStream mIn;
- private BufferedOutputStream mOut;
- private final int mFlags;
- private SocketCreator mSocketCreator;
- private InetSocketAddress mAddress;
-
- public MailTransport(Context context, ImapHelper imapHelper, Network network, String address,
- int port, int flags) {
- mContext = context;
- mImapHelper = imapHelper;
- mNetwork = network;
- mHost = address;
- mPort = port;
- mFlags = flags;
- }
-
- /**
- * Returns a new transport, using the current transport as a model. The new transport is
- * configured identically, but not opened or connected in any way.
- */
- @Override
- public MailTransport clone() {
- return new MailTransport(mContext, mImapHelper, mNetwork, mHost, mPort, mFlags);
- }
-
- public boolean canTrySslSecurity() {
- return (mFlags & ImapStore.FLAG_SSL) != 0;
- }
-
- public boolean canTrustAllCertificates() {
- return (mFlags & ImapStore.FLAG_TRUST_ALL) != 0;
- }
-
- /**
- * Attempts to open a connection using the Uri supplied for connection parameters. Will attempt
- * an SSL connection if indicated.
- */
- public void open() throws MessagingException {
- LogUtils.d(TAG, "*** IMAP open " + mHost + ":" + String.valueOf(mPort));
-
- List<InetSocketAddress> socketAddresses = new ArrayList<InetSocketAddress>();
-
- if (mNetwork == null) {
- socketAddresses.add(new InetSocketAddress(mHost, mPort));
- } else {
- try {
- InetAddress[] inetAddresses = mNetwork.getAllByName(mHost);
- if (inetAddresses.length == 0) {
- throw new MessagingException(MessagingException.IOERROR,
- "Host name " + mHost + "cannot be resolved on designated network");
- }
- for (int i = 0; i < inetAddresses.length; i++) {
- socketAddresses.add(new InetSocketAddress(inetAddresses[i], mPort));
- }
- } catch (IOException ioe) {
- LogUtils.d(TAG, ioe.toString());
- mImapHelper.handleEvent(OmtpEvents.DATA_CANNOT_RESOLVE_HOST_ON_NETWORK);
- throw new MessagingException(MessagingException.IOERROR, ioe.toString());
- }
- }
-
- boolean success = false;
- while (socketAddresses.size() > 0) {
- mSocket = createSocket();
- try {
- mAddress = socketAddresses.remove(0);
- mSocket.connect(mAddress, SOCKET_CONNECT_TIMEOUT);
-
- if (canTrySslSecurity()) {
- /*
- SSLSocket cannot be created with a connection timeout, so instead of doing a
- direct SSL connection, we connect with a normal connection and upgrade it into
- SSL
- */
- reopenTls();
- } else {
- mIn = new BufferedInputStream(mSocket.getInputStream(), 1024);
- mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512);
- mSocket.setSoTimeout(SOCKET_READ_TIMEOUT);
- }
- success = true;
- return;
- } catch (IOException ioe) {
- LogUtils.d(TAG, ioe.toString());
- if (socketAddresses.size() == 0) {
- // Only throw an error when there are no more sockets to try.
- mImapHelper.handleEvent(OmtpEvents.DATA_ALL_SOCKET_CONNECTION_FAILED);
- throw new MessagingException(MessagingException.IOERROR, ioe.toString());
- }
- } finally {
- if (!success) {
- try {
- mSocket.close();
- mSocket = null;
- } catch (IOException ioe) {
- throw new MessagingException(MessagingException.IOERROR, ioe.toString());
- }
-
- }
- }
- }
- }
-
- // For testing. We need something that can replace the behavior of "new Socket()"
- @VisibleForTesting
- interface SocketCreator {
-
- Socket createSocket() throws MessagingException;
- }
-
- @VisibleForTesting
- void setSocketCreator(SocketCreator creator) {
- mSocketCreator = creator;
- }
-
- protected Socket createSocket() throws MessagingException {
- if (mSocketCreator != null) {
- return mSocketCreator.createSocket();
- }
-
- if (mNetwork == null) {
- LogUtils.v(TAG, "createSocket: network not specified");
- return new Socket();
- }
-
- try {
- LogUtils.v(TAG, "createSocket: network specified");
- return mNetwork.getSocketFactory().createSocket();
- } catch (IOException ioe) {
- LogUtils.d(TAG, ioe.toString());
- throw new MessagingException(MessagingException.IOERROR, ioe.toString());
- }
- }
-
- /**
- * Attempts to reopen a normal connection into a TLS connection.
- */
- public void reopenTls() throws MessagingException {
- try {
- LogUtils.d(TAG, "open: converting to TLS socket");
- mSocket = HttpsURLConnection.getDefaultSSLSocketFactory()
- .createSocket(mSocket, mAddress.getHostName(), mAddress.getPort(), true);
- // After the socket connects to an SSL server, confirm that the hostname is as
- // expected
- if (!canTrustAllCertificates()) {
- verifyHostname(mSocket, mHost);
- }
- mSocket.setSoTimeout(SOCKET_READ_TIMEOUT);
- mIn = new BufferedInputStream(mSocket.getInputStream(), 1024);
- mOut = new BufferedOutputStream(mSocket.getOutputStream(), 512);
-
- } catch (SSLException e) {
- LogUtils.d(TAG, e.toString());
- throw new CertificateValidationException(e.getMessage(), e);
- } catch (IOException ioe) {
- LogUtils.d(TAG, ioe.toString());
- throw new MessagingException(MessagingException.IOERROR, ioe.toString());
- }
- }
-
- /**
- * Lightweight version of SSLCertificateSocketFactory.verifyHostname, which provides this
- * service but is not in the public API.
- *
- * Verify the hostname of the certificate used by the other end of a
- * connected socket. It is harmless to call this method redundantly if the hostname has already
- * been verified.
- *
- * <p>Wildcard certificates are allowed to verify any matching hostname,
- * so "foo.bar.example.com" is verified if the peer has a certificate
- * for "*.example.com".
- *
- * @param socket An SSL socket which has been connected to a server
- * @param hostname The expected hostname of the remote server
- * @throws IOException if something goes wrong handshaking with the server
- * @throws SSLPeerUnverifiedException if the server cannot prove its identity
- */
- private void verifyHostname(Socket socket, String hostname) throws IOException {
- // The code at the start of OpenSSLSocketImpl.startHandshake()
- // ensures that the call is idempotent, so we can safely call it.
- SSLSocket ssl = (SSLSocket) socket;
- ssl.startHandshake();
-
- SSLSession session = ssl.getSession();
- if (session == null) {
- mImapHelper.handleEvent(OmtpEvents.DATA_CANNOT_ESTABLISH_SSL_SESSION);
- throw new SSLException("Cannot verify SSL socket without session");
- }
- // TODO: Instead of reporting the name of the server we think we're connecting to,
- // we should be reporting the bad name in the certificate. Unfortunately this is buried
- // in the verifier code and is not available in the verifier API, and extracting the
- // CN & alts is beyond the scope of this patch.
- if (!HOSTNAME_VERIFIER.verify(hostname, session)) {
- mImapHelper.handleEvent(OmtpEvents.DATA_SSL_INVALID_HOST_NAME);
- throw new SSLPeerUnverifiedException("Certificate hostname not useable for server: "
- + session.getPeerPrincipal());
- }
- }
-
- public boolean isOpen() {
- return (mIn != null && mOut != null &&
- mSocket != null && mSocket.isConnected() && !mSocket.isClosed());
- }
-
- /**
- * Close the connection. MUST NOT return any exceptions - must be "best effort" and safe.
- */
- public void close() {
- try {
- mIn.close();
- } catch (Exception e) {
- // May fail if the connection is already closed.
- }
- try {
- mOut.close();
- } catch (Exception e) {
- // May fail if the connection is already closed.
- }
- try {
- mSocket.close();
- } catch (Exception e) {
- // May fail if the connection is already closed.
- }
- mIn = null;
- mOut = null;
- mSocket = null;
- }
-
- public String getHost() {
- return mHost;
- }
-
- public InputStream getInputStream() {
- return mIn;
- }
-
- public OutputStream getOutputStream() {
- return mOut;
- }
-
- /**
- * Writes a single line to the server using \r\n termination.
- */
- public void writeLine(String s, String sensitiveReplacement) throws IOException {
- if (sensitiveReplacement != null) {
- LogUtils.d(TAG, ">>> " + sensitiveReplacement);
- } else {
- LogUtils.d(TAG, ">>> " + s);
- }
-
- OutputStream out = getOutputStream();
- out.write(s.getBytes());
- out.write('\r');
- out.write('\n');
- out.flush();
- }
-
- /**
- * Reads a single line from the server, using either \r\n or \n as the delimiter. The
- * delimiter char(s) are not included in the result.
- */
- public String readLine(boolean loggable) throws IOException {
- StringBuffer sb = new StringBuffer();
- InputStream in = getInputStream();
- int d;
- while ((d = in.read()) != -1) {
- if (((char)d) == '\r') {
- continue;
- } else if (((char)d) == '\n') {
- break;
- } else {
- sb.append((char)d);
- }
- }
- if (d == -1) {
- LogUtils.d(TAG, "End of stream reached while trying to read line.");
- }
- String ret = sb.toString();
- if (loggable) {
- LogUtils.d(TAG, "<<< " + ret);
- }
- return ret;
- }
-}
diff --git a/src/com/android/phone/common/mail/MeetingInfo.java b/src/com/android/phone/common/mail/MeetingInfo.java
deleted file mode 100644
index 9fbafe7..0000000
--- a/src/com/android/phone/common/mail/MeetingInfo.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-public class MeetingInfo {
- // Predefined tags; others can be added
- public static final String MEETING_DTSTAMP = "DTSTAMP";
- public static final String MEETING_UID = "UID";
- public static final String MEETING_ORGANIZER_EMAIL = "ORGMAIL";
- public static final String MEETING_DTSTART = "DTSTART";
- public static final String MEETING_DTEND = "DTEND";
- public static final String MEETING_TITLE = "TITLE";
- public static final String MEETING_LOCATION = "LOC";
- public static final String MEETING_RESPONSE_REQUESTED = "RESPONSE";
- public static final String MEETING_ALL_DAY = "ALLDAY";
-}
diff --git a/src/com/android/phone/common/mail/Message.java b/src/com/android/phone/common/mail/Message.java
deleted file mode 100644
index 0a5ed35..0000000
--- a/src/com/android/phone/common/mail/Message.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.util.Date;
-import java.util.HashSet;
-
-public abstract class Message implements Part, Body {
- public static final Message[] EMPTY_ARRAY = new Message[0];
-
- public static final String RECIPIENT_TYPE_TO = "to";
- public static final String RECIPIENT_TYPE_CC = "cc";
- public static final String RECIPIENT_TYPE_BCC = "bcc";
- public enum RecipientType {
- TO, CC, BCC,
- }
-
- protected String mUid;
-
- private HashSet<String> mFlags = null;
-
- protected Date mInternalDate;
-
- public String getUid() {
- return mUid;
- }
-
- public void setUid(String uid) {
- this.mUid = uid;
- }
-
- public abstract String getSubject() throws MessagingException;
-
- public abstract void setSubject(String subject) throws MessagingException;
-
- public Date getInternalDate() {
- return mInternalDate;
- }
-
- public void setInternalDate(Date internalDate) {
- this.mInternalDate = internalDate;
- }
-
- public abstract Date getReceivedDate() throws MessagingException;
-
- public abstract Date getSentDate() throws MessagingException;
-
- public abstract void setSentDate(Date sentDate) throws MessagingException;
-
- public abstract Address[] getRecipients(String type) throws MessagingException;
-
- public abstract void setRecipients(String type, Address[] addresses)
- throws MessagingException;
-
- public void setRecipient(String type, Address address) throws MessagingException {
- setRecipients(type, new Address[] {
- address
- });
- }
-
- public abstract Address[] getFrom() throws MessagingException;
-
- public abstract void setFrom(Address from) throws MessagingException;
-
- public abstract Address[] getReplyTo() throws MessagingException;
-
- public abstract void setReplyTo(Address[] from) throws MessagingException;
-
- // Always use these instead of getHeader("Message-ID") or setHeader("Message-ID");
- public abstract void setMessageId(String messageId) throws MessagingException;
- public abstract String getMessageId() throws MessagingException;
-
- @Override
- public boolean isMimeType(String mimeType) throws MessagingException {
- return getContentType().startsWith(mimeType);
- }
-
- private HashSet<String> getFlagSet() {
- if (mFlags == null) {
- mFlags = new HashSet<String>();
- }
- return mFlags;
- }
-
- /*
- * TODO Refactor Flags at some point to be able to store user defined flags.
- */
- public String[] getFlags() {
- return getFlagSet().toArray(new String[] {});
- }
-
- /**
- * Set/clear a flag directly, without involving overrides of {@link #setFlag} in subclasses.
- * Only used for testing.
- */
- @VisibleForTesting
- private final void setFlagDirectlyForTest(String flag, boolean set) throws MessagingException {
- if (set) {
- getFlagSet().add(flag);
- } else {
- getFlagSet().remove(flag);
- }
- }
-
- public void setFlag(String flag, boolean set) throws MessagingException {
- setFlagDirectlyForTest(flag, set);
- }
-
- /**
- * This method calls setFlag(String, boolean)
- * @param flags
- * @param set
- */
- public void setFlags(String[] flags, boolean set) throws MessagingException {
- for (String flag : flags) {
- setFlag(flag, set);
- }
- }
-
- public boolean isSet(String flag) {
- return getFlagSet().contains(flag);
- }
-
- public abstract void saveChanges() throws MessagingException;
-
- @Override
- public String toString() {
- return getClass().getSimpleName() + ':' + mUid;
- }
-}
diff --git a/src/com/android/phone/common/mail/MessageDateComparator.java b/src/com/android/phone/common/mail/MessageDateComparator.java
deleted file mode 100644
index 5d8baa7..0000000
--- a/src/com/android/phone/common/mail/MessageDateComparator.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import java.util.Comparator;
-
-public class MessageDateComparator implements Comparator<Message> {
- @Override
- public int compare(Message o1, Message o2) {
- try {
- if (o1.getSentDate() == null) {
- return 1;
- } else if (o2.getSentDate() == null) {
- return -1;
- } else
- return o2.getSentDate().compareTo(o1.getSentDate());
- } catch (Exception e) {
- return 0;
- }
- }
-}
diff --git a/src/com/android/phone/common/mail/MessagingException.java b/src/com/android/phone/common/mail/MessagingException.java
deleted file mode 100644
index e4c674a..0000000
--- a/src/com/android/phone/common/mail/MessagingException.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-/**
- * This exception is used for most types of failures that occur during server interactions.
- *
- * Data passed through this exception should be considered non-localized. Any strings should
- * either be internal-only (for debugging) or server-generated.
- *
- * TO DO: Does it make sense to further collapse AuthenticationFailedException and
- * CertificateValidationException and any others into this?
- */
-public class MessagingException extends Exception {
- public static final long serialVersionUID = -1;
-
- public static final int NO_ERROR = -1;
- /** Any exception that does not specify a specific issue */
- public static final int UNSPECIFIED_EXCEPTION = 0;
- /** Connection or IO errors */
- public static final int IOERROR = 1;
- /** The configuration requested TLS but the server did not support it. */
- public static final int TLS_REQUIRED = 2;
- /** Authentication is required but the server did not support it. */
- public static final int AUTH_REQUIRED = 3;
- /** General security failures */
- public static final int GENERAL_SECURITY = 4;
- /** Authentication failed */
- public static final int AUTHENTICATION_FAILED = 5;
- /** Attempt to create duplicate account */
- public static final int DUPLICATE_ACCOUNT = 6;
- /** Required security policies reported - advisory only */
- public static final int SECURITY_POLICIES_REQUIRED = 7;
- /** Required security policies not supported */
- public static final int SECURITY_POLICIES_UNSUPPORTED = 8;
- /** The protocol (or protocol version) isn't supported */
- public static final int PROTOCOL_VERSION_UNSUPPORTED = 9;
- /** The server's SSL certificate couldn't be validated */
- public static final int CERTIFICATE_VALIDATION_ERROR = 10;
- /** Authentication failed during autodiscover */
- public static final int AUTODISCOVER_AUTHENTICATION_FAILED = 11;
- /** Autodiscover completed with a result (non-error) */
- public static final int AUTODISCOVER_AUTHENTICATION_RESULT = 12;
- /** Ambiguous failure; server error or bad credentials */
- public static final int AUTHENTICATION_FAILED_OR_SERVER_ERROR = 13;
- /** The server refused access */
- public static final int ACCESS_DENIED = 14;
- /** The server refused access */
- public static final int ATTACHMENT_NOT_FOUND = 15;
- /** A client SSL certificate is required for connections to the server */
- public static final int CLIENT_CERTIFICATE_REQUIRED = 16;
- /** The client SSL certificate specified is invalid */
- public static final int CLIENT_CERTIFICATE_ERROR = 17;
- /** The server indicates it does not support OAuth authentication */
- public static final int OAUTH_NOT_SUPPORTED = 18;
- /** The server indicates it experienced an internal error */
- public static final int SERVER_ERROR = 19;
-
- protected int mExceptionType;
- // Exception type-specific data
- protected Object mExceptionData;
-
- public MessagingException(String message, Throwable throwable) {
- this(UNSPECIFIED_EXCEPTION, message, throwable);
- }
-
- public MessagingException(int exceptionType, String message, Throwable throwable) {
- super(message, throwable);
- mExceptionType = exceptionType;
- mExceptionData = null;
- }
-
- /**
- * Constructs a MessagingException with an exceptionType and a null message.
- * @param exceptionType The exception type to set for this exception.
- */
- public MessagingException(int exceptionType) {
- this(exceptionType, null, null);
- }
-
- /**
- * Constructs a MessagingException with a message.
- * @param message the message for this exception
- */
- public MessagingException(String message) {
- this(UNSPECIFIED_EXCEPTION, message, null);
- }
-
- /**
- * Constructs a MessagingException with an exceptionType and a message.
- * @param exceptionType The exception type to set for this exception.
- */
- public MessagingException(int exceptionType, String message) {
- this(exceptionType, message, null);
- }
-
- /**
- * Constructs a MessagingException with an exceptionType, a message, and data
- * @param exceptionType The exception type to set for this exception.
- * @param message the message for the exception (or null)
- * @param data exception-type specific data for the exception (or null)
- */
- public MessagingException(int exceptionType, String message, Object data) {
- super(message);
- mExceptionType = exceptionType;
- mExceptionData = data;
- }
-
- /**
- * Return the exception type. Will be OTHER_EXCEPTION if not explicitly set.
- *
- * @return Returns the exception type.
- */
- public int getExceptionType() {
- return mExceptionType;
- }
- /**
- * Return the exception data. Will be null if not explicitly set.
- *
- * @return Returns the exception data.
- */
- public Object getExceptionData() {
- return mExceptionData;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/Multipart.java b/src/com/android/phone/common/mail/Multipart.java
deleted file mode 100644
index 77963c8..0000000
--- a/src/com/android/phone/common/mail/Multipart.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import java.util.ArrayList;
-
-public abstract class Multipart implements Body {
- protected Part mParent;
-
- protected ArrayList<BodyPart> mParts = new ArrayList<BodyPart>();
-
- protected String mContentType;
-
- public void addBodyPart(BodyPart part) throws MessagingException {
- mParts.add(part);
- }
-
- public void addBodyPart(BodyPart part, int index) throws MessagingException {
- mParts.add(index, part);
- }
-
- public BodyPart getBodyPart(int index) throws MessagingException {
- return mParts.get(index);
- }
-
- public String getContentType() throws MessagingException {
- return mContentType;
- }
-
- public int getCount() throws MessagingException {
- return mParts.size();
- }
-
- public boolean removeBodyPart(BodyPart part) throws MessagingException {
- return mParts.remove(part);
- }
-
- public void removeBodyPart(int index) throws MessagingException {
- mParts.remove(index);
- }
-
- public Part getParent() throws MessagingException {
- return mParent;
- }
-
- public void setParent(Part parent) throws MessagingException {
- this.mParent = parent;
- }
-}
diff --git a/src/com/android/phone/common/mail/PackedString.java b/src/com/android/phone/common/mail/PackedString.java
deleted file mode 100644
index 6cbba9e..0000000
--- a/src/com/android/phone/common/mail/PackedString.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A utility class for creating and modifying Strings that are tagged and packed together.
- *
- * Uses non-printable (control chars) for internal delimiters; Intended for regular displayable
- * strings only, so please use base64 or other encoding if you need to hide any binary data here.
- *
- * Binary compatible with Address.pack() format, which should migrate to use this code.
- */
-public class PackedString {
-
- /**
- * Packing format is:
- * element : [ value ] or [ value TAG-DELIMITER tag ]
- * packed-string : [ element ] [ ELEMENT-DELIMITER [ element ] ]*
- */
- private static final char DELIMITER_ELEMENT = '\1';
- private static final char DELIMITER_TAG = '\2';
-
- private String mString;
- private HashMap<String, String> mExploded;
- private static final HashMap<String, String> EMPTY_MAP = new HashMap<String, String>();
-
- /**
- * Create a packed string using an already-packed string (e.g. from database)
- * @param string packed string
- */
- public PackedString(String string) {
- mString = string;
- mExploded = null;
- }
-
- /**
- * Get the value referred to by a given tag. If the tag does not exist, return null.
- * @param tag identifier of string of interest
- * @return returns value, or null if no string is found
- */
- public String get(String tag) {
- if (mExploded == null) {
- mExploded = explode(mString);
- }
- return mExploded.get(tag);
- }
-
- /**
- * Return a map of all of the values referred to by a given tag. This is a shallow
- * copy, don't edit the values.
- * @return a map of the values in the packed string
- */
- public Map<String, String> unpack() {
- if (mExploded == null) {
- mExploded = explode(mString);
- }
- return new HashMap<String,String>(mExploded);
- }
-
- /**
- * Read out all values into a map.
- */
- private static HashMap<String, String> explode(String packed) {
- if (packed == null || packed.length() == 0) {
- return EMPTY_MAP;
- }
- HashMap<String, String> map = new HashMap<String, String>();
-
- int length = packed.length();
- int elementStartIndex = 0;
- int elementEndIndex = 0;
- int tagEndIndex = packed.indexOf(DELIMITER_TAG);
-
- while (elementStartIndex < length) {
- elementEndIndex = packed.indexOf(DELIMITER_ELEMENT, elementStartIndex);
- if (elementEndIndex == -1) {
- elementEndIndex = length;
- }
- String tag;
- String value;
- if (tagEndIndex == -1 || elementEndIndex <= tagEndIndex) {
- // in this case the DELIMITER_PERSONAL is in a future pair (or not found)
- // so synthesize a positional tag for the value, and don't update tagEndIndex
- value = packed.substring(elementStartIndex, elementEndIndex);
- tag = Integer.toString(map.size());
- } else {
- value = packed.substring(elementStartIndex, tagEndIndex);
- tag = packed.substring(tagEndIndex + 1, elementEndIndex);
- // scan forward for next tag, if any
- tagEndIndex = packed.indexOf(DELIMITER_TAG, elementEndIndex + 1);
- }
- map.put(tag, value);
- elementStartIndex = elementEndIndex + 1;
- }
-
- return map;
- }
-
- /**
- * Builder class for creating PackedString values. Can also be used for editing existing
- * PackedString representations.
- */
- static public class Builder {
- HashMap<String, String> mMap;
-
- /**
- * Create a builder that's empty (for filling)
- */
- public Builder() {
- mMap = new HashMap<String, String>();
- }
-
- /**
- * Create a builder using the values of an existing PackedString (for editing).
- */
- public Builder(String packed) {
- mMap = explode(packed);
- }
-
- /**
- * Add a tagged value
- * @param tag identifier of string of interest
- * @param value the value to record in this position. null to delete entry.
- */
- public void put(String tag, String value) {
- if (value == null) {
- mMap.remove(tag);
- } else {
- mMap.put(tag, value);
- }
- }
-
- /**
- * Get the value referred to by a given tag. If the tag does not exist, return null.
- * @param tag identifier of string of interest
- * @return returns value, or null if no string is found
- */
- public String get(String tag) {
- return mMap.get(tag);
- }
-
- /**
- * Pack the values and return a single, encoded string
- */
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- for (Map.Entry<String,String> entry : mMap.entrySet()) {
- if (sb.length() > 0) {
- sb.append(DELIMITER_ELEMENT);
- }
- sb.append(entry.getValue());
- sb.append(DELIMITER_TAG);
- sb.append(entry.getKey());
- }
- return sb.toString();
- }
- }
-}
diff --git a/src/com/android/phone/common/mail/Part.java b/src/com/android/phone/common/mail/Part.java
deleted file mode 100644
index d064e2a..0000000
--- a/src/com/android/phone/common/mail/Part.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-public interface Part extends Fetchable {
- public void addHeader(String name, String value) throws MessagingException;
-
- public void removeHeader(String name) throws MessagingException;
-
- public void setHeader(String name, String value) throws MessagingException;
-
- public Body getBody() throws MessagingException;
-
- public String getContentType() throws MessagingException;
-
- public String getDisposition() throws MessagingException;
-
- public String getContentId() throws MessagingException;
-
- public String[] getHeader(String name) throws MessagingException;
-
- public void setExtendedHeader(String name, String value) throws MessagingException;
-
- public String getExtendedHeader(String name) throws MessagingException;
-
- public int getSize() throws MessagingException;
-
- public boolean isMimeType(String mimeType) throws MessagingException;
-
- public String getMimeType() throws MessagingException;
-
- public void setBody(Body body) throws MessagingException;
-
- public void writeTo(OutputStream out) throws IOException, MessagingException;
-}
diff --git a/src/com/android/phone/common/mail/PeekableInputStream.java b/src/com/android/phone/common/mail/PeekableInputStream.java
deleted file mode 100644
index d29fc6b..0000000
--- a/src/com/android/phone/common/mail/PeekableInputStream.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * A filtering InputStream that allows single byte "peeks" without consuming the byte. The
- * client of this stream can call peek() to see the next available byte in the stream
- * and a subsequent read will still return the peeked byte.
- */
-public class PeekableInputStream extends InputStream {
- private final InputStream mIn;
- private boolean mPeeked;
- private int mPeekedByte;
-
- public PeekableInputStream(InputStream in) {
- this.mIn = in;
- }
-
- @Override
- public int read() throws IOException {
- if (!mPeeked) {
- return mIn.read();
- } else {
- mPeeked = false;
- return mPeekedByte;
- }
- }
-
- public int peek() throws IOException {
- if (!mPeeked) {
- mPeekedByte = read();
- mPeeked = true;
- }
- return mPeekedByte;
- }
-
- @Override
- public int read(byte[] b, int offset, int length) throws IOException {
- if (!mPeeked) {
- return mIn.read(b, offset, length);
- } else {
- b[0] = (byte)mPeekedByte;
- mPeeked = false;
- int r = mIn.read(b, offset + 1, length - 1);
- if (r == -1) {
- return 1;
- } else {
- return r + 1;
- }
- }
- }
-
- @Override
- public int read(byte[] b) throws IOException {
- return read(b, 0, b.length);
- }
-
- @Override
- public String toString() {
- return String.format("PeekableInputStream(in=%s, peeked=%b, peekedByte=%d)",
- mIn.toString(), mPeeked, mPeekedByte);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/TempDirectory.java b/src/com/android/phone/common/mail/TempDirectory.java
deleted file mode 100644
index 8fa0e44..0000000
--- a/src/com/android/phone/common/mail/TempDirectory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail;
-
-import android.content.Context;
-
-import java.io.File;
-
-/**
- * TempDirectory caches the directory used for caching file. It is set up during application
- * initialization.
- */
-public class TempDirectory {
- private static File sTempDirectory = null;
-
- public static void setTempDirectory(Context context) {
- sTempDirectory = context.getCacheDir();
- }
-
- public static File getTempDirectory() {
- if (sTempDirectory == null) {
- throw new RuntimeException(
- "TempDirectory not set. " +
- "If in a unit test, call Email.setTempDirectory(context) in setUp().");
- }
- return sTempDirectory;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/internet/BinaryTempFileBody.java b/src/com/android/phone/common/mail/internet/BinaryTempFileBody.java
deleted file mode 100644
index e2bdd89..0000000
--- a/src/com/android/phone/common/mail/internet/BinaryTempFileBody.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.internet;
-
-import com.android.phone.common.mail.Body;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.common.mail.TempDirectory;
-
-import org.apache.commons.io.IOUtils;
-
-import android.util.Base64;
-import android.util.Base64OutputStream;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * A Body that is backed by a temp file. The Body exposes a getOutputStream method that allows
- * the user to write to the temp file. After the write the body is available via getInputStream
- * and writeTo one time. After writeTo is called, or the InputStream returned from
- * getInputStream is closed the file is deleted and the Body should be considered disposed of.
- */
-public class BinaryTempFileBody implements Body {
- private File mFile;
-
- /**
- * An alternate way to put data into a BinaryTempFileBody is to simply supply an already-
- * created file. Note that this file will be deleted after it is read.
- * @param filePath The file containing the data to be stored on disk temporarily
- */
- public void setFile(String filePath) {
- mFile = new File(filePath);
- }
-
- public OutputStream getOutputStream() throws IOException {
- mFile = File.createTempFile("body", null, TempDirectory.getTempDirectory());
- mFile.deleteOnExit();
- return new FileOutputStream(mFile);
- }
-
- @Override
- public InputStream getInputStream() throws MessagingException {
- try {
- return new BinaryTempFileBodyInputStream(new FileInputStream(mFile));
- }
- catch (IOException ioe) {
- throw new MessagingException("Unable to open body", ioe);
- }
- }
-
- @Override
- public void writeTo(OutputStream out) throws IOException, MessagingException {
- InputStream in = getInputStream();
- Base64OutputStream base64Out = new Base64OutputStream(
- out, Base64.CRLF | Base64.NO_CLOSE);
- IOUtils.copy(in, base64Out);
- base64Out.close();
- mFile.delete();
- in.close();
- }
-
- class BinaryTempFileBodyInputStream extends FilterInputStream {
- public BinaryTempFileBodyInputStream(InputStream in) {
- super(in);
- }
-
- @Override
- public void close() throws IOException {
- super.close();
- mFile.delete();
- }
- }
-}
diff --git a/src/com/android/phone/common/mail/internet/MimeBodyPart.java b/src/com/android/phone/common/mail/internet/MimeBodyPart.java
deleted file mode 100644
index 286a4f2..0000000
--- a/src/com/android/phone/common/mail/internet/MimeBodyPart.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.internet;
-
-import com.android.phone.common.mail.Body;
-import com.android.phone.common.mail.BodyPart;
-import com.android.phone.common.mail.MessagingException;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.util.regex.Pattern;
-
-/**
- * TODO this is a close approximation of Message, need to update along with
- * Message.
- */
-public class MimeBodyPart extends BodyPart {
- protected MimeHeader mHeader = new MimeHeader();
- protected MimeHeader mExtendedHeader;
- protected Body mBody;
- protected int mSize;
-
- // regex that matches content id surrounded by "<>" optionally.
- private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$");
- // regex that matches end of line.
- private static final Pattern END_OF_LINE = Pattern.compile("\r?\n");
-
- public MimeBodyPart() throws MessagingException {
- this(null);
- }
-
- public MimeBodyPart(Body body) throws MessagingException {
- this(body, null);
- }
-
- public MimeBodyPart(Body body, String mimeType) throws MessagingException {
- if (mimeType != null) {
- setHeader(MimeHeader.HEADER_CONTENT_TYPE, mimeType);
- }
- setBody(body);
- }
-
- protected String getFirstHeader(String name) throws MessagingException {
- return mHeader.getFirstHeader(name);
- }
-
- @Override
- public void addHeader(String name, String value) throws MessagingException {
- mHeader.addHeader(name, value);
- }
-
- @Override
- public void setHeader(String name, String value) throws MessagingException {
- mHeader.setHeader(name, value);
- }
-
- @Override
- public String[] getHeader(String name) throws MessagingException {
- return mHeader.getHeader(name);
- }
-
- @Override
- public void removeHeader(String name) throws MessagingException {
- mHeader.removeHeader(name);
- }
-
- @Override
- public Body getBody() throws MessagingException {
- return mBody;
- }
-
- @Override
- public void setBody(Body body) throws MessagingException {
- this.mBody = body;
- if (body instanceof com.android.phone.common.mail.Multipart) {
- com.android.phone.common.mail.Multipart multipart =
- ((com.android.phone.common.mail.Multipart)body);
- multipart.setParent(this);
- setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType());
- }
- else if (body instanceof TextBody) {
- String contentType = String.format("%s;\n charset=utf-8", getMimeType());
- String name = MimeUtility.getHeaderParameter(getContentType(), "name");
- if (name != null) {
- contentType += String.format(";\n name=\"%s\"", name);
- }
- setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType);
- setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
- }
- }
-
- @Override
- public String getContentType() throws MessagingException {
- String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE);
- if (contentType == null) {
- return "text/plain";
- } else {
- return contentType;
- }
- }
-
- @Override
- public String getDisposition() throws MessagingException {
- String contentDisposition = getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION);
- if (contentDisposition == null) {
- return null;
- } else {
- return contentDisposition;
- }
- }
-
- @Override
- public String getContentId() throws MessagingException {
- String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID);
- if (contentId == null) {
- return null;
- } else {
- // remove optionally surrounding brackets.
- return REMOVE_OPTIONAL_BRACKETS.matcher(contentId).replaceAll("$1");
- }
- }
-
- @Override
- public String getMimeType() throws MessagingException {
- return MimeUtility.getHeaderParameter(getContentType(), null);
- }
-
- @Override
- public boolean isMimeType(String mimeType) throws MessagingException {
- return getMimeType().equals(mimeType);
- }
-
- public void setSize(int size) {
- this.mSize = size;
- }
-
- @Override
- public int getSize() throws MessagingException {
- return mSize;
- }
-
- /**
- * Set extended header
- *
- * @param name Extended header name
- * @param value header value - flattened by removing CR-NL if any
- * remove header if value is null
- * @throws MessagingException
- */
- @Override
- public void setExtendedHeader(String name, String value) throws MessagingException {
- if (value == null) {
- if (mExtendedHeader != null) {
- mExtendedHeader.removeHeader(name);
- }
- return;
- }
- if (mExtendedHeader == null) {
- mExtendedHeader = new MimeHeader();
- }
- mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll(""));
- }
-
- /**
- * Get extended header
- *
- * @param name Extended header name
- * @return header value - null if header does not exist
- * @throws MessagingException
- */
- @Override
- public String getExtendedHeader(String name) throws MessagingException {
- if (mExtendedHeader == null) {
- return null;
- }
- return mExtendedHeader.getFirstHeader(name);
- }
-
- /**
- * Write the MimeMessage out in MIME format.
- */
- @Override
- public void writeTo(OutputStream out) throws IOException, MessagingException {
- BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
- mHeader.writeTo(out);
- writer.write("\r\n");
- writer.flush();
- if (mBody != null) {
- mBody.writeTo(out);
- }
- }
-}
diff --git a/src/com/android/phone/common/mail/internet/MimeHeader.java b/src/com/android/phone/common/mail/internet/MimeHeader.java
deleted file mode 100644
index 7e6a07f..0000000
--- a/src/com/android/phone/common/mail/internet/MimeHeader.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.internet;
-
-import com.android.phone.common.mail.MessagingException;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.util.ArrayList;
-
-public class MimeHeader {
- /**
- * Application specific header that contains Store specific information about an attachment.
- * In IMAP this contains the IMAP BODYSTRUCTURE part id so that the ImapStore can later
- * retrieve the attachment at will from the server.
- * The info is recorded from this header on LocalStore.appendMessage and is put back
- * into the MIME data by LocalStore.fetch.
- */
- public static final String HEADER_ANDROID_ATTACHMENT_STORE_DATA = "X-Android-Attachment-StoreData";
-
- public static final String HEADER_CONTENT_TYPE = "Content-Type";
- public static final String HEADER_CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
- public static final String HEADER_CONTENT_DISPOSITION = "Content-Disposition";
- public static final String HEADER_CONTENT_ID = "Content-ID";
-
- /**
- * Fields that should be omitted when writing the header using writeTo()
- */
- private static final String[] WRITE_OMIT_FIELDS = {
-// HEADER_ANDROID_ATTACHMENT_DOWNLOADED,
-// HEADER_ANDROID_ATTACHMENT_ID,
- HEADER_ANDROID_ATTACHMENT_STORE_DATA
- };
-
- protected final ArrayList<Field> mFields = new ArrayList<Field>();
-
- public void clear() {
- mFields.clear();
- }
-
- public String getFirstHeader(String name) throws MessagingException {
- String[] header = getHeader(name);
- if (header == null) {
- return null;
- }
- return header[0];
- }
-
- public void addHeader(String name, String value) throws MessagingException {
- mFields.add(new Field(name, value));
- }
-
- public void setHeader(String name, String value) throws MessagingException {
- if (name == null || value == null) {
- return;
- }
- removeHeader(name);
- addHeader(name, value);
- }
-
- public String[] getHeader(String name) throws MessagingException {
- ArrayList<String> values = new ArrayList<String>();
- for (Field field : mFields) {
- if (field.name.equalsIgnoreCase(name)) {
- values.add(field.value);
- }
- }
- if (values.size() == 0) {
- return null;
- }
- return values.toArray(new String[] {});
- }
-
- public void removeHeader(String name) throws MessagingException {
- ArrayList<Field> removeFields = new ArrayList<Field>();
- for (Field field : mFields) {
- if (field.name.equalsIgnoreCase(name)) {
- removeFields.add(field);
- }
- }
- mFields.removeAll(removeFields);
- }
-
- /**
- * Write header into String
- *
- * @return CR-NL separated header string except the headers in writeOmitFields
- * null if header is empty
- */
- public String writeToString() {
- if (mFields.size() == 0) {
- return null;
- }
- StringBuilder builder = new StringBuilder();
- for (Field field : mFields) {
- if (!arrayContains(WRITE_OMIT_FIELDS, field.name)) {
- builder.append(field.name + ": " + field.value + "\r\n");
- }
- }
- return builder.toString();
- }
-
- public void writeTo(OutputStream out) throws IOException, MessagingException {
- BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
- for (Field field : mFields) {
- if (!arrayContains(WRITE_OMIT_FIELDS, field.name)) {
- writer.write(field.name + ": " + field.value + "\r\n");
- }
- }
- writer.flush();
- }
-
- private static class Field {
- final String name;
- final String value;
-
- public Field(String name, String value) {
- this.name = name;
- this.value = value;
- }
-
- @Override
- public String toString() {
- return name + "=" + value;
- }
- }
-
- @Override
- public String toString() {
- return (mFields == null) ? null : mFields.toString();
- }
-
- public final static boolean arrayContains(Object[] a, Object o) {
- int index = arrayIndex(a, o);
- return (index >= 0);
- }
-
- public final static int arrayIndex(Object[] a, Object o) {
- for (int i = 0, count = a.length; i < count; i++) {
- if (a[i].equals(o)) {
- return i;
- }
- }
- return -1;
- }
-}
diff --git a/src/com/android/phone/common/mail/internet/MimeMessage.java b/src/com/android/phone/common/mail/internet/MimeMessage.java
deleted file mode 100644
index f4c6c88..0000000
--- a/src/com/android/phone/common/mail/internet/MimeMessage.java
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.internet;
-
-import com.android.phone.common.mail.Address;
-import com.android.phone.common.mail.Body;
-import com.android.phone.common.mail.BodyPart;
-import com.android.phone.common.mail.Message;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.common.mail.Multipart;
-import com.android.phone.common.mail.Part;
-import com.android.phone.common.mail.utils.LogUtils;
-
-import org.apache.james.mime4j.BodyDescriptor;
-import org.apache.james.mime4j.ContentHandler;
-import org.apache.james.mime4j.EOLConvertingInputStream;
-import org.apache.james.mime4j.MimeStreamParser;
-import org.apache.james.mime4j.field.DateTimeField;
-import org.apache.james.mime4j.field.Field;
-
-import android.text.TextUtils;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.Stack;
-import java.util.regex.Pattern;
-
-/**
- * An implementation of Message that stores all of its metadata in RFC 822 and
- * RFC 2045 style headers.
- *
- * NOTE: Automatic generation of a local message-id is becoming unwieldy and should be removed.
- * It would be better to simply do it explicitly on local creation of new outgoing messages.
- */
-public class MimeMessage extends Message {
- private MimeHeader mHeader;
- private MimeHeader mExtendedHeader;
-
- // NOTE: The fields here are transcribed out of headers, and values stored here will supersede
- // the values found in the headers. Use caution to prevent any out-of-phase errors. In
- // particular, any adds/changes/deletes here must be echoed by changes in the parse() function.
- private Address[] mFrom;
- private Address[] mTo;
- private Address[] mCc;
- private Address[] mBcc;
- private Address[] mReplyTo;
- private Date mSentDate;
- private Body mBody;
- protected int mSize;
- private boolean mInhibitLocalMessageId = false;
- private boolean mComplete = true;
-
- // Shared random source for generating local message-id values
- private static final java.util.Random sRandom = new java.util.Random();
-
- // In MIME, en_US-like date format should be used. In other words "MMM" should be encoded to
- // "Jan", not the other localized format like "Ene" (meaning January in locale es).
- // This conversion is used when generating outgoing MIME messages. Incoming MIME date
- // headers are parsed by org.apache.james.mime4j.field.DateTimeField which does not have any
- // localization code.
- private static final SimpleDateFormat DATE_FORMAT =
- new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
-
- // regex that matches content id surrounded by "<>" optionally.
- private static final Pattern REMOVE_OPTIONAL_BRACKETS = Pattern.compile("^<?([^>]+)>?$");
- // regex that matches end of line.
- private static final Pattern END_OF_LINE = Pattern.compile("\r?\n");
-
- public MimeMessage() {
- mHeader = null;
- }
-
- /**
- * Generate a local message id. This is only used when none has been assigned, and is
- * installed lazily. Any remote (typically server-assigned) message id takes precedence.
- * @return a long, locally-generated message-ID value
- */
- private static String generateMessageId() {
- final StringBuilder sb = new StringBuilder();
- sb.append("<");
- for (int i = 0; i < 24; i++) {
- // We'll use a 5-bit range (0..31)
- final int value = sRandom.nextInt() & 31;
- final char c = "0123456789abcdefghijklmnopqrstuv".charAt(value);
- sb.append(c);
- }
- sb.append(".");
- sb.append(Long.toString(System.currentTimeMillis()));
- sb.append("@email.android.com>");
- return sb.toString();
- }
-
- /**
- * Parse the given InputStream using Apache Mime4J to build a MimeMessage.
- *
- * @param in InputStream providing message content
- * @throws IOException
- * @throws MessagingException
- */
- public MimeMessage(InputStream in) throws IOException, MessagingException {
- parse(in);
- }
-
- private MimeStreamParser init() {
- // Before parsing the input stream, clear all local fields that may be superceded by
- // the new incoming message.
- getMimeHeaders().clear();
- mInhibitLocalMessageId = true;
- mFrom = null;
- mTo = null;
- mCc = null;
- mBcc = null;
- mReplyTo = null;
- mSentDate = null;
- mBody = null;
-
- final MimeStreamParser parser = new MimeStreamParser();
- parser.setContentHandler(new MimeMessageBuilder());
- return parser;
- }
-
- protected void parse(InputStream in) throws IOException, MessagingException {
- final MimeStreamParser parser = init();
- parser.parse(new EOLConvertingInputStream(in));
- mComplete = !parser.getPrematureEof();
- }
-
- public void parse(InputStream in, EOLConvertingInputStream.Callback callback)
- throws IOException, MessagingException {
- final MimeStreamParser parser = init();
- parser.parse(new EOLConvertingInputStream(in, getSize(), callback));
- mComplete = !parser.getPrematureEof();
- }
-
- /**
- * Return the internal mHeader value, with very lazy initialization.
- * The goal is to save memory by not creating the headers until needed.
- */
- private MimeHeader getMimeHeaders() {
- if (mHeader == null) {
- mHeader = new MimeHeader();
- }
- return mHeader;
- }
-
- @Override
- public Date getReceivedDate() throws MessagingException {
- return null;
- }
-
- @Override
- public Date getSentDate() throws MessagingException {
- if (mSentDate == null) {
- try {
- DateTimeField field = (DateTimeField)Field.parse("Date: "
- + MimeUtility.unfoldAndDecode(getFirstHeader("Date")));
- mSentDate = field.getDate();
- // TODO: We should make it more clear what exceptions can be thrown here,
- // and whether they reflect a normal or error condition.
- } catch (Exception e) {
- LogUtils.v(LogUtils.TAG, "Message missing Date header");
- }
- }
- if (mSentDate == null) {
- // If we still don't have a date, fall back to "Delivery-date"
- try {
- DateTimeField field = (DateTimeField)Field.parse("Date: "
- + MimeUtility.unfoldAndDecode(getFirstHeader("Delivery-date")));
- mSentDate = field.getDate();
- // TODO: We should make it more clear what exceptions can be thrown here,
- // and whether they reflect a normal or error condition.
- } catch (Exception e) {
- LogUtils.v(LogUtils.TAG, "Message also missing Delivery-Date header");
- }
- }
- return mSentDate;
- }
-
- @Override
- public void setSentDate(Date sentDate) throws MessagingException {
- setHeader("Date", DATE_FORMAT.format(sentDate));
- this.mSentDate = sentDate;
- }
-
- @Override
- public String getContentType() throws MessagingException {
- final String contentType = getFirstHeader(MimeHeader.HEADER_CONTENT_TYPE);
- if (contentType == null) {
- return "text/plain";
- } else {
- return contentType;
- }
- }
-
- @Override
- public String getDisposition() throws MessagingException {
- return getFirstHeader(MimeHeader.HEADER_CONTENT_DISPOSITION);
- }
-
- @Override
- public String getContentId() throws MessagingException {
- final String contentId = getFirstHeader(MimeHeader.HEADER_CONTENT_ID);
- if (contentId == null) {
- return null;
- } else {
- // remove optionally surrounding brackets.
- return REMOVE_OPTIONAL_BRACKETS.matcher(contentId).replaceAll("$1");
- }
- }
-
- public boolean isComplete() {
- return mComplete;
- }
-
- @Override
- public String getMimeType() throws MessagingException {
- return MimeUtility.getHeaderParameter(getContentType(), null);
- }
-
- @Override
- public int getSize() throws MessagingException {
- return mSize;
- }
-
- /**
- * Returns a list of the given recipient type from this message. If no addresses are
- * found the method returns an empty array.
- */
- @Override
- public Address[] getRecipients(String type) throws MessagingException {
- if (type == RECIPIENT_TYPE_TO) {
- if (mTo == null) {
- mTo = Address.parse(MimeUtility.unfold(getFirstHeader("To")));
- }
- return mTo;
- } else if (type == RECIPIENT_TYPE_CC) {
- if (mCc == null) {
- mCc = Address.parse(MimeUtility.unfold(getFirstHeader("CC")));
- }
- return mCc;
- } else if (type == RECIPIENT_TYPE_BCC) {
- if (mBcc == null) {
- mBcc = Address.parse(MimeUtility.unfold(getFirstHeader("BCC")));
- }
- return mBcc;
- } else {
- throw new MessagingException("Unrecognized recipient type.");
- }
- }
-
- @Override
- public void setRecipients(String type, Address[] addresses) throws MessagingException {
- final int TO_LENGTH = 4; // "To: "
- final int CC_LENGTH = 4; // "Cc: "
- final int BCC_LENGTH = 5; // "Bcc: "
- if (type == RECIPIENT_TYPE_TO) {
- if (addresses == null || addresses.length == 0) {
- removeHeader("To");
- this.mTo = null;
- } else {
- setHeader("To", MimeUtility.fold(Address.toHeader(addresses), TO_LENGTH));
- this.mTo = addresses;
- }
- } else if (type == RECIPIENT_TYPE_CC) {
- if (addresses == null || addresses.length == 0) {
- removeHeader("CC");
- this.mCc = null;
- } else {
- setHeader("CC", MimeUtility.fold(Address.toHeader(addresses), CC_LENGTH));
- this.mCc = addresses;
- }
- } else if (type == RECIPIENT_TYPE_BCC) {
- if (addresses == null || addresses.length == 0) {
- removeHeader("BCC");
- this.mBcc = null;
- } else {
- setHeader("BCC", MimeUtility.fold(Address.toHeader(addresses), BCC_LENGTH));
- this.mBcc = addresses;
- }
- } else {
- throw new MessagingException("Unrecognized recipient type.");
- }
- }
-
- /**
- * Returns the unfolded, decoded value of the Subject header.
- */
- @Override
- public String getSubject() throws MessagingException {
- return MimeUtility.unfoldAndDecode(getFirstHeader("Subject"));
- }
-
- @Override
- public void setSubject(String subject) throws MessagingException {
- final int HEADER_NAME_LENGTH = 9; // "Subject: "
- setHeader("Subject", MimeUtility.foldAndEncode2(subject, HEADER_NAME_LENGTH));
- }
-
- @Override
- public Address[] getFrom() throws MessagingException {
- if (mFrom == null) {
- String list = MimeUtility.unfold(getFirstHeader("From"));
- if (list == null || list.length() == 0) {
- list = MimeUtility.unfold(getFirstHeader("Sender"));
- }
- mFrom = Address.parse(list);
- }
- return mFrom;
- }
-
- @Override
- public void setFrom(Address from) throws MessagingException {
- final int FROM_LENGTH = 6; // "From: "
- if (from != null) {
- setHeader("From", MimeUtility.fold(from.toHeader(), FROM_LENGTH));
- this.mFrom = new Address[] {
- from
- };
- } else {
- this.mFrom = null;
- }
- }
-
- @Override
- public Address[] getReplyTo() throws MessagingException {
- if (mReplyTo == null) {
- mReplyTo = Address.parse(MimeUtility.unfold(getFirstHeader("Reply-to")));
- }
- return mReplyTo;
- }
-
- @Override
- public void setReplyTo(Address[] replyTo) throws MessagingException {
- final int REPLY_TO_LENGTH = 10; // "Reply-to: "
- if (replyTo == null || replyTo.length == 0) {
- removeHeader("Reply-to");
- mReplyTo = null;
- } else {
- setHeader("Reply-to", MimeUtility.fold(Address.toHeader(replyTo), REPLY_TO_LENGTH));
- mReplyTo = replyTo;
- }
- }
-
- /**
- * Set the mime "Message-ID" header
- * @param messageId the new Message-ID value
- * @throws MessagingException
- */
- @Override
- public void setMessageId(String messageId) throws MessagingException {
- setHeader("Message-ID", messageId);
- }
-
- /**
- * Get the mime "Message-ID" header. This value will be preloaded with a locally-generated
- * random ID, if the value has not previously been set. Local generation can be inhibited/
- * overridden by explicitly clearing the headers, removing the message-id header, etc.
- * @return the Message-ID header string, or null if explicitly has been set to null
- */
- @Override
- public String getMessageId() throws MessagingException {
- String messageId = getFirstHeader("Message-ID");
- if (messageId == null && !mInhibitLocalMessageId) {
- messageId = generateMessageId();
- setMessageId(messageId);
- }
- return messageId;
- }
-
- @Override
- public void saveChanges() throws MessagingException {
- throw new MessagingException("saveChanges not yet implemented");
- }
-
- @Override
- public Body getBody() throws MessagingException {
- return mBody;
- }
-
- @Override
- public void setBody(Body body) throws MessagingException {
- this.mBody = body;
- if (body instanceof Multipart) {
- final Multipart multipart = ((Multipart)body);
- multipart.setParent(this);
- setHeader(MimeHeader.HEADER_CONTENT_TYPE, multipart.getContentType());
- setHeader("MIME-Version", "1.0");
- }
- else if (body instanceof TextBody) {
- setHeader(MimeHeader.HEADER_CONTENT_TYPE, String.format("%s;\n charset=utf-8",
- getMimeType()));
- setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING, "base64");
- }
- }
-
- protected String getFirstHeader(String name) throws MessagingException {
- return getMimeHeaders().getFirstHeader(name);
- }
-
- @Override
- public void addHeader(String name, String value) throws MessagingException {
- getMimeHeaders().addHeader(name, value);
- }
-
- @Override
- public void setHeader(String name, String value) throws MessagingException {
- getMimeHeaders().setHeader(name, value);
- }
-
- @Override
- public String[] getHeader(String name) throws MessagingException {
- return getMimeHeaders().getHeader(name);
- }
-
- @Override
- public void removeHeader(String name) throws MessagingException {
- getMimeHeaders().removeHeader(name);
- if ("Message-ID".equalsIgnoreCase(name)) {
- mInhibitLocalMessageId = true;
- }
- }
-
- /**
- * Set extended header
- *
- * @param name Extended header name
- * @param value header value - flattened by removing CR-NL if any
- * remove header if value is null
- * @throws MessagingException
- */
- @Override
- public void setExtendedHeader(String name, String value) throws MessagingException {
- if (value == null) {
- if (mExtendedHeader != null) {
- mExtendedHeader.removeHeader(name);
- }
- return;
- }
- if (mExtendedHeader == null) {
- mExtendedHeader = new MimeHeader();
- }
- mExtendedHeader.setHeader(name, END_OF_LINE.matcher(value).replaceAll(""));
- }
-
- /**
- * Get extended header
- *
- * @param name Extended header name
- * @return header value - null if header does not exist
- * @throws MessagingException
- */
- @Override
- public String getExtendedHeader(String name) throws MessagingException {
- if (mExtendedHeader == null) {
- return null;
- }
- return mExtendedHeader.getFirstHeader(name);
- }
-
- /**
- * Set entire extended headers from String
- *
- * @param headers Extended header and its value - "CR-NL-separated pairs
- * if null or empty, remove entire extended headers
- * @throws MessagingException
- */
- public void setExtendedHeaders(String headers) throws MessagingException {
- if (TextUtils.isEmpty(headers)) {
- mExtendedHeader = null;
- } else {
- mExtendedHeader = new MimeHeader();
- for (final String header : END_OF_LINE.split(headers)) {
- final String[] tokens = header.split(":", 2);
- if (tokens.length != 2) {
- throw new MessagingException("Illegal extended headers: " + headers);
- }
- mExtendedHeader.setHeader(tokens[0].trim(), tokens[1].trim());
- }
- }
- }
-
- /**
- * Get entire extended headers as String
- *
- * @return "CR-NL-separated extended headers - null if extended header does not exist
- */
- public String getExtendedHeaders() {
- if (mExtendedHeader != null) {
- return mExtendedHeader.writeToString();
- }
- return null;
- }
-
- /**
- * Write message header and body to output stream
- *
- * @param out Output steam to write message header and body.
- */
- @Override
- public void writeTo(OutputStream out) throws IOException, MessagingException {
- final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
- // Force creation of local message-id
- getMessageId();
- getMimeHeaders().writeTo(out);
- // mExtendedHeader will not be write out to external output stream,
- // because it is intended to internal use.
- writer.write("\r\n");
- writer.flush();
- if (mBody != null) {
- mBody.writeTo(out);
- }
- }
-
- @Override
- public InputStream getInputStream() throws MessagingException {
- return null;
- }
-
- class MimeMessageBuilder implements ContentHandler {
- private final Stack<Object> stack = new Stack<Object>();
-
- public MimeMessageBuilder() {
- }
-
- private void expect(Class<?> c) {
- if (!c.isInstance(stack.peek())) {
- throw new IllegalStateException("Internal stack error: " + "Expected '"
- + c.getName() + "' found '" + stack.peek().getClass().getName() + "'");
- }
- }
-
- @Override
- public void startMessage() {
- if (stack.isEmpty()) {
- stack.push(MimeMessage.this);
- } else {
- expect(Part.class);
- try {
- final MimeMessage m = new MimeMessage();
- ((Part)stack.peek()).setBody(m);
- stack.push(m);
- } catch (MessagingException me) {
- throw new Error(me);
- }
- }
- }
-
- @Override
- public void endMessage() {
- expect(MimeMessage.class);
- stack.pop();
- }
-
- @Override
- public void startHeader() {
- expect(Part.class);
- }
-
- @Override
- public void field(String fieldData) {
- expect(Part.class);
- try {
- final String[] tokens = fieldData.split(":", 2);
- ((Part)stack.peek()).addHeader(tokens[0], tokens[1].trim());
- } catch (MessagingException me) {
- throw new Error(me);
- }
- }
-
- @Override
- public void endHeader() {
- expect(Part.class);
- }
-
- @Override
- public void startMultipart(BodyDescriptor bd) {
- expect(Part.class);
-
- final Part e = (Part)stack.peek();
- try {
- final MimeMultipart multiPart = new MimeMultipart(e.getContentType());
- e.setBody(multiPart);
- stack.push(multiPart);
- } catch (MessagingException me) {
- throw new Error(me);
- }
- }
-
- @Override
- public void body(BodyDescriptor bd, InputStream in) throws IOException {
- expect(Part.class);
- final Body body = MimeUtility.decodeBody(in, bd.getTransferEncoding());
- try {
- ((Part)stack.peek()).setBody(body);
- } catch (MessagingException me) {
- throw new Error(me);
- }
- }
-
- @Override
- public void endMultipart() {
- stack.pop();
- }
-
- @Override
- public void startBodyPart() {
- expect(MimeMultipart.class);
-
- try {
- final MimeBodyPart bodyPart = new MimeBodyPart();
- ((MimeMultipart)stack.peek()).addBodyPart(bodyPart);
- stack.push(bodyPart);
- } catch (MessagingException me) {
- throw new Error(me);
- }
- }
-
- @Override
- public void endBodyPart() {
- expect(BodyPart.class);
- stack.pop();
- }
-
- @Override
- public void epilogue(InputStream is) throws IOException {
- expect(MimeMultipart.class);
- final StringBuilder sb = new StringBuilder();
- int b;
- while ((b = is.read()) != -1) {
- sb.append((char)b);
- }
- // TODO: why is this commented out?
- // ((Multipart) stack.peek()).setEpilogue(sb.toString());
- }
-
- @Override
- public void preamble(InputStream is) throws IOException {
- expect(MimeMultipart.class);
- final StringBuilder sb = new StringBuilder();
- int b;
- while ((b = is.read()) != -1) {
- sb.append((char)b);
- }
- try {
- ((MimeMultipart)stack.peek()).setPreamble(sb.toString());
- } catch (MessagingException me) {
- throw new Error(me);
- }
- }
-
- @Override
- public void raw(InputStream is) throws IOException {
- throw new UnsupportedOperationException("Not supported");
- }
- }
-}
diff --git a/src/com/android/phone/common/mail/internet/MimeMultipart.java b/src/com/android/phone/common/mail/internet/MimeMultipart.java
deleted file mode 100644
index 3e118e4..0000000
--- a/src/com/android/phone/common/mail/internet/MimeMultipart.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.internet;
-
-import com.android.phone.common.mail.BodyPart;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.common.mail.Multipart;
-
-import java.io.BufferedWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-
-public class MimeMultipart extends Multipart {
- protected String mPreamble;
-
- protected String mContentType;
-
- protected String mBoundary;
-
- protected String mSubType;
-
- public MimeMultipart() throws MessagingException {
- mBoundary = generateBoundary();
- setSubType("mixed");
- }
-
- public MimeMultipart(String contentType) throws MessagingException {
- this.mContentType = contentType;
- try {
- mSubType = MimeUtility.getHeaderParameter(contentType, null).split("/")[1];
- mBoundary = MimeUtility.getHeaderParameter(contentType, "boundary");
- if (mBoundary == null) {
- throw new MessagingException("MultiPart does not contain boundary: " + contentType);
- }
- } catch (Exception e) {
- throw new MessagingException(
- "Invalid MultiPart Content-Type; must contain subtype and boundary. ("
- + contentType + ")", e);
- }
- }
-
- public String generateBoundary() {
- StringBuffer sb = new StringBuffer();
- sb.append("----");
- for (int i = 0; i < 30; i++) {
- sb.append(Integer.toString((int)(Math.random() * 35), 36));
- }
- return sb.toString().toUpperCase();
- }
-
- public String getPreamble() throws MessagingException {
- return mPreamble;
- }
-
- public void setPreamble(String preamble) throws MessagingException {
- this.mPreamble = preamble;
- }
-
- @Override
- public String getContentType() throws MessagingException {
- return mContentType;
- }
-
- public void setSubType(String subType) throws MessagingException {
- this.mSubType = subType;
- mContentType = String.format("multipart/%s; boundary=\"%s\"", subType, mBoundary);
- }
-
- @Override
- public void writeTo(OutputStream out) throws IOException, MessagingException {
- BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out), 1024);
-
- if (mPreamble != null) {
- writer.write(mPreamble + "\r\n");
- }
-
- for (int i = 0, count = mParts.size(); i < count; i++) {
- BodyPart bodyPart = mParts.get(i);
- writer.write("--" + mBoundary + "\r\n");
- writer.flush();
- bodyPart.writeTo(out);
- writer.write("\r\n");
- }
-
- writer.write("--" + mBoundary + "--\r\n");
- writer.flush();
- }
-
- @Override
- public InputStream getInputStream() throws MessagingException {
- return null;
- }
-
- public String getSubTypeForTest() {
- return mSubType;
- }
-}
diff --git a/src/com/android/phone/common/mail/internet/MimeUtility.java b/src/com/android/phone/common/mail/internet/MimeUtility.java
deleted file mode 100644
index 7402a4c..0000000
--- a/src/com/android/phone/common/mail/internet/MimeUtility.java
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.internet;
-
-import android.text.TextUtils;
-import android.util.Base64;
-import android.util.Base64DataException;
-import android.util.Base64InputStream;
-
-import com.android.phone.common.mail.Body;
-import com.android.phone.common.mail.BodyPart;
-import com.android.phone.common.mail.Message;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.common.mail.Multipart;
-import com.android.phone.common.mail.Part;
-import com.android.phone.vvm.omtp.VvmLog;
-
-import org.apache.commons.io.IOUtils;
-import org.apache.james.mime4j.codec.EncoderUtil;
-import org.apache.james.mime4j.decoder.DecoderUtil;
-import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
-import org.apache.james.mime4j.util.CharsetUtil;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public class MimeUtility {
- private static final String LOG_TAG = "Email";
-
- public static final String MIME_TYPE_RFC822 = "message/rfc822";
- private final static Pattern PATTERN_CR_OR_LF = Pattern.compile("\r|\n");
-
- /**
- * Replace sequences of CRLF+WSP with WSP. Tries to preserve original string
- * object whenever possible.
- */
- public static String unfold(String s) {
- if (s == null) {
- return null;
- }
- Matcher patternMatcher = PATTERN_CR_OR_LF.matcher(s);
- if (patternMatcher.find()) {
- patternMatcher.reset();
- s = patternMatcher.replaceAll("");
- }
- return s;
- }
-
- public static String decode(String s) {
- if (s == null) {
- return null;
- }
- return DecoderUtil.decodeEncodedWords(s);
- }
-
- public static String unfoldAndDecode(String s) {
- return decode(unfold(s));
- }
-
- // TODO implement proper foldAndEncode
- // NOTE: When this really works, we *must* remove all calls to foldAndEncode2() to prevent
- // duplication of encoding.
- public static String foldAndEncode(String s) {
- return s;
- }
-
- /**
- * INTERIM version of foldAndEncode that will be used only by Subject: headers.
- * This is safer than implementing foldAndEncode() (see above) and risking unknown damage
- * to other headers.
- *
- * TODO: Copy this code to foldAndEncode(), get rid of this function, confirm all working OK.
- *
- * @param s original string to encode and fold
- * @param usedCharacters number of characters already used up by header name
-
- * @return the String ready to be transmitted
- */
- public static String foldAndEncode2(String s, int usedCharacters) {
- // james.mime4j.codec.EncoderUtil.java
- // encode: encodeIfNecessary(text, usage, numUsedInHeaderName)
- // Usage.TEXT_TOKENlooks like the right thing for subjects
- // use WORD_ENTITY for address/names
-
- String encoded = EncoderUtil.encodeIfNecessary(s, EncoderUtil.Usage.TEXT_TOKEN,
- usedCharacters);
-
- return fold(encoded, usedCharacters);
- }
-
- /**
- * INTERIM: From newer version of org.apache.james (but we don't want to import
- * the entire MimeUtil class).
- *
- * Splits the specified string into a multiple-line representation with
- * lines no longer than 76 characters (because the line might contain
- * encoded words; see <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC
- * 2047</a> section 2). If the string contains non-whitespace sequences
- * longer than 76 characters a line break is inserted at the whitespace
- * character following the sequence resulting in a line longer than 76
- * characters.
- *
- * @param s
- * string to split.
- * @param usedCharacters
- * number of characters already used up. Usually the number of
- * characters for header field name plus colon and one space.
- * @return a multiple-line representation of the given string.
- */
- public static String fold(String s, int usedCharacters) {
- final int maxCharacters = 76;
-
- final int length = s.length();
- if (usedCharacters + length <= maxCharacters)
- return s;
-
- StringBuilder sb = new StringBuilder();
-
- int lastLineBreak = -usedCharacters;
- int wspIdx = indexOfWsp(s, 0);
- while (true) {
- if (wspIdx == length) {
- sb.append(s.substring(Math.max(0, lastLineBreak)));
- return sb.toString();
- }
-
- int nextWspIdx = indexOfWsp(s, wspIdx + 1);
-
- if (nextWspIdx - lastLineBreak > maxCharacters) {
- sb.append(s.substring(Math.max(0, lastLineBreak), wspIdx));
- sb.append("\r\n");
- lastLineBreak = wspIdx;
- }
-
- wspIdx = nextWspIdx;
- }
- }
-
- /**
- * INTERIM: From newer version of org.apache.james (but we don't want to import
- * the entire MimeUtil class).
- *
- * Search for whitespace.
- */
- private static int indexOfWsp(String s, int fromIndex) {
- final int len = s.length();
- for (int index = fromIndex; index < len; index++) {
- char c = s.charAt(index);
- if (c == ' ' || c == '\t')
- return index;
- }
- return len;
- }
-
- /**
- * Returns the named parameter of a header field. If name is null the first
- * parameter is returned, or if there are no additional parameters in the
- * field the entire field is returned. Otherwise the named parameter is
- * searched for in a case insensitive fashion and returned. If the parameter
- * cannot be found the method returns null.
- *
- * TODO: quite inefficient with the inner trimming & splitting.
- * TODO: Also has a latent bug: uses "startsWith" to match the name, which can false-positive.
- * TODO: The doc says that for a null name you get the first param, but you get the header.
- * Should probably just fix the doc, but if other code assumes that behavior, fix the code.
- * TODO: Need to decode %-escaped strings, as in: filename="ab%22d".
- * ('+' -> ' ' conversion too? check RFC)
- *
- * @param header
- * @param name
- * @return the entire header (if name=null), the found parameter, or null
- */
- public static String getHeaderParameter(String header, String name) {
- if (header == null) {
- return null;
- }
- String[] parts = unfold(header).split(";");
- if (name == null) {
- return parts[0].trim();
- }
- String lowerCaseName = name.toLowerCase();
- for (String part : parts) {
- if (part.trim().toLowerCase().startsWith(lowerCaseName)) {
- String[] parameterParts = part.split("=", 2);
- if (parameterParts.length < 2) {
- return null;
- }
- String parameter = parameterParts[1].trim();
- if (parameter.startsWith("\"") && parameter.endsWith("\"")) {
- return parameter.substring(1, parameter.length() - 1);
- } else {
- return parameter;
- }
- }
- }
- return null;
- }
-
- /**
- * Reads the Part's body and returns a String based on any charset conversion that needed
- * to be done.
- * @param part The part containing a body
- * @return a String containing the converted text in the body, or null if there was no text
- * or an error during conversion.
- */
- public static String getTextFromPart(Part part) {
- try {
- if (part != null && part.getBody() != null) {
- InputStream in = part.getBody().getInputStream();
- String mimeType = part.getMimeType();
- if (mimeType != null && MimeUtility.mimeTypeMatches(mimeType, "text/*")) {
- /*
- * Now we read the part into a buffer for further processing. Because
- * the stream is now wrapped we'll remove any transfer encoding at this point.
- */
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- IOUtils.copy(in, out);
- in.close();
- in = null; // we want all of our memory back, and close might not release
-
- /*
- * We've got a text part, so let's see if it needs to be processed further.
- */
- String charset = getHeaderParameter(part.getContentType(), "charset");
- if (charset != null) {
- /*
- * See if there is conversion from the MIME charset to the Java one.
- */
- charset = CharsetUtil.toJavaCharset(charset);
- }
- /*
- * No encoding, so use us-ascii, which is the standard.
- */
- if (charset == null) {
- charset = "ASCII";
- }
- /*
- * Convert and return as new String
- */
- String result = out.toString(charset);
- out.close();
- return result;
- }
- }
-
- }
- catch (OutOfMemoryError oom) {
- /*
- * If we are not able to process the body there's nothing we can do about it. Return
- * null and let the upper layers handle the missing content.
- */
- VvmLog.e(LOG_TAG, "Unable to getTextFromPart " + oom.toString());
- }
- catch (Exception e) {
- /*
- * If we are not able to process the body there's nothing we can do about it. Return
- * null and let the upper layers handle the missing content.
- */
- VvmLog.e(LOG_TAG, "Unable to getTextFromPart " + e.toString());
- }
- return null;
- }
-
- /**
- * Returns true if the given mimeType matches the matchAgainst specification. The comparison
- * ignores case and the matchAgainst string may include "*" for a wildcard (e.g. "image/*").
- *
- * @param mimeType A MIME type to check.
- * @param matchAgainst A MIME type to check against. May include wildcards.
- * @return true if the mimeType matches
- */
- public static boolean mimeTypeMatches(String mimeType, String matchAgainst) {
- Pattern p = Pattern.compile(matchAgainst.replaceAll("\\*", "\\.\\*"),
- Pattern.CASE_INSENSITIVE);
- return p.matcher(mimeType).matches();
- }
-
- /**
- * Returns true if the given mimeType matches any of the matchAgainst specifications. The
- * comparison ignores case and the matchAgainst strings may include "*" for a wildcard
- * (e.g. "image/*").
- *
- * @param mimeType A MIME type to check.
- * @param matchAgainst An array of MIME types to check against. May include wildcards.
- * @return true if the mimeType matches any of the matchAgainst strings
- */
- public static boolean mimeTypeMatches(String mimeType, String[] matchAgainst) {
- for (String matchType : matchAgainst) {
- if (mimeTypeMatches(mimeType, matchType)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Given an input stream and a transfer encoding, return a wrapped input stream for that
- * encoding (or the original if none is required)
- * @param in the input stream
- * @param contentTransferEncoding the content transfer encoding
- * @return a properly wrapped stream
- */
- public static InputStream getInputStreamForContentTransferEncoding(InputStream in,
- String contentTransferEncoding) {
- if (contentTransferEncoding != null) {
- contentTransferEncoding =
- MimeUtility.getHeaderParameter(contentTransferEncoding, null);
- if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) {
- in = new QuotedPrintableInputStream(in);
- }
- else if ("base64".equalsIgnoreCase(contentTransferEncoding)) {
- in = new Base64InputStream(in, Base64.DEFAULT);
- }
- }
- return in;
- }
-
- /**
- * Removes any content transfer encoding from the stream and returns a Body.
- */
- public static Body decodeBody(InputStream in, String contentTransferEncoding)
- throws IOException {
- /*
- * We'll remove any transfer encoding by wrapping the stream.
- */
- in = getInputStreamForContentTransferEncoding(in, contentTransferEncoding);
- BinaryTempFileBody tempBody = new BinaryTempFileBody();
- OutputStream out = tempBody.getOutputStream();
- try {
- IOUtils.copy(in, out);
- } catch (Base64DataException bde) {
- // TODO Need to fix this somehow
- //String warning = "\n\n" + Email.getMessageDecodeErrorString();
- //out.write(warning.getBytes());
- } finally {
- out.close();
- }
- return tempBody;
- }
-
- /**
- * Recursively scan a Part (usually a Message) and sort out which of its children will be
- * "viewable" and which will be attachments.
- *
- * @param part The part to be broken down
- * @param viewables This arraylist will be populated with all parts that appear to be
- * the "message" (e.g. text/plain & text/html)
- * @param attachments This arraylist will be populated with all parts that appear to be
- * attachments (including inlines)
- * @throws MessagingException
- */
- public static void collectParts(Part part, ArrayList<Part> viewables,
- ArrayList<Part> attachments) throws MessagingException {
- String disposition = part.getDisposition();
- String dispositionType = MimeUtility.getHeaderParameter(disposition, null);
- // If a disposition is not specified, default to "inline"
- boolean inline =
- TextUtils.isEmpty(dispositionType) || "inline".equalsIgnoreCase(dispositionType);
- // The lower-case mime type
- String mimeType = part.getMimeType().toLowerCase();
-
- if (part.getBody() instanceof Multipart) {
- // If the part is Multipart but not alternative it's either mixed or
- // something we don't know about, which means we treat it as mixed
- // per the spec. We just process its pieces recursively.
- MimeMultipart mp = (MimeMultipart)part.getBody();
- boolean foundHtml = false;
- if (mp.getSubTypeForTest().equals("alternative")) {
- for (int i = 0; i < mp.getCount(); i++) {
- if (mp.getBodyPart(i).isMimeType("text/html")) {
- foundHtml = true;
- break;
- }
- }
- }
- for (int i = 0; i < mp.getCount(); i++) {
- // See if we have text and html
- BodyPart bp = mp.getBodyPart(i);
- // If there's html, don't bother loading text
- if (foundHtml && bp.isMimeType("text/plain")) {
- continue;
- }
- collectParts(bp, viewables, attachments);
- }
- } else if (part.getBody() instanceof Message) {
- // If the part is an embedded message we just continue to process
- // it, pulling any viewables or attachments into the running list.
- Message message = (Message)part.getBody();
- collectParts(message, viewables, attachments);
- } else if (inline && (mimeType.startsWith("text") || (mimeType.startsWith("image")))) {
- // We'll treat text and images as viewables
- viewables.add(part);
- } else {
- // Everything else is an attachment.
- attachments.add(part);
- }
- }
-}
diff --git a/src/com/android/phone/common/mail/internet/TextBody.java b/src/com/android/phone/common/mail/internet/TextBody.java
deleted file mode 100644
index 77bbd65..0000000
--- a/src/com/android/phone/common/mail/internet/TextBody.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.internet;
-
-import android.util.Base64;
-
-import com.android.phone.common.mail.Body;
-import com.android.phone.common.mail.MessagingException;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-
-public class TextBody implements Body {
- String mBody;
-
- public TextBody(String body) {
- this.mBody = body;
- }
-
- @Override
- public void writeTo(OutputStream out) throws IOException, MessagingException {
- byte[] bytes = mBody.getBytes("UTF-8");
- out.write(Base64.encode(bytes, Base64.CRLF));
- }
-
- /**
- * Get the text of the body in it's unencoded format.
- * @return
- */
- public String getText() {
- return mBody;
- }
-
- /**
- * Returns an InputStream that reads this body's text in UTF-8 format.
- */
- @Override
- public InputStream getInputStream() throws MessagingException {
- try {
- byte[] b = mBody.getBytes("UTF-8");
- return new ByteArrayInputStream(b);
- }
- catch (UnsupportedEncodingException usee) {
- return null;
- }
- }
-}
diff --git a/src/com/android/phone/common/mail/store/ImapConnection.java b/src/com/android/phone/common/mail/store/ImapConnection.java
deleted file mode 100644
index af8773b..0000000
--- a/src/com/android/phone/common/mail/store/ImapConnection.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store;
-
-import android.util.ArraySet;
-import android.util.Base64;
-import com.android.phone.common.mail.AuthenticationFailedException;
-import com.android.phone.common.mail.CertificateValidationException;
-import com.android.phone.common.mail.MailTransport;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.common.mail.store.ImapStore.ImapException;
-import com.android.phone.common.mail.store.imap.DigestMd5Utils;
-import com.android.phone.common.mail.store.imap.ImapConstants;
-import com.android.phone.common.mail.store.imap.ImapResponse;
-import com.android.phone.common.mail.store.imap.ImapResponseParser;
-import com.android.phone.common.mail.store.imap.ImapUtility;
-import com.android.phone.common.mail.utils.LogUtils;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.VvmLog;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-import javax.net.ssl.SSLException;
-
-/**
- * A cacheable class that stores the details for a single IMAP connection.
- */
-public class ImapConnection {
- private final String TAG = "ImapConnection";
-
- private String mLoginPhrase;
- private ImapStore mImapStore;
- private MailTransport mTransport;
- private ImapResponseParser mParser;
- private Set<String> mCapabilities = new ArraySet<>();
-
- static final String IMAP_REDACTED_LOG = "[IMAP command redacted]";
-
- /**
- * Next tag to use. All connections associated to the same ImapStore instance share the same
- * counter to make tests simpler.
- * (Some of the tests involve multiple connections but only have a single counter to track the
- * tag.)
- */
- private final AtomicInteger mNextCommandTag = new AtomicInteger(0);
-
- ImapConnection(ImapStore store) {
- setStore(store);
- }
-
- void setStore(ImapStore store) {
- // TODO: maybe we should throw an exception if the connection is not closed here,
- // if it's not currently closed, then we won't reopen it, so if the credentials have
- // changed, the connection will not be reestablished.
- mImapStore = store;
- mLoginPhrase = null;
- }
-
- /**
- * Generates and returns the phrase to be used for authentication. This will be a LOGIN with
- * username and password.
- *
- * @return the login command string to sent to the IMAP server
- */
- String getLoginPhrase() {
- if (mLoginPhrase == null) {
- if (mImapStore.getUsername() != null && mImapStore.getPassword() != null) {
- // build the LOGIN string once (instead of over-and-over again.)
- // apply the quoting here around the built-up password
- mLoginPhrase = ImapConstants.LOGIN + " " + mImapStore.getUsername() + " "
- + ImapUtility.imapQuoted(mImapStore.getPassword());
- }
- }
- return mLoginPhrase;
- }
-
- public void open() throws IOException, MessagingException {
- if (mTransport != null && mTransport.isOpen()) {
- return;
- }
-
- try {
- // copy configuration into a clean transport, if necessary
- if (mTransport == null) {
- mTransport = mImapStore.cloneTransport();
- }
-
- mTransport.open();
-
- createParser();
-
- // The server should greet us with something like
- // * OK IMAP4rev1 Server
- // consume the response before doing anything else.
- ImapResponse response = mParser.readResponse(false);
- if (!response.isOk()) {
- mImapStore.getImapHelper()
- .handleEvent(OmtpEvents.DATA_INVALID_INITIAL_SERVER_RESPONSE);
- throw new MessagingException(
- MessagingException.AUTHENTICATION_FAILED_OR_SERVER_ERROR,
- "Invalid server initial response");
- }
-
- queryCapability();
-
- maybeDoStartTls();
-
- // LOGIN
- doLogin();
- } catch (SSLException e) {
- LogUtils.d(TAG, "SSLException ", e);
- mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_SSL_EXCEPTION);
- throw new CertificateValidationException(e.getMessage(), e);
- } catch (IOException ioe) {
- LogUtils.d(TAG, "IOException", ioe);
- mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_IOE_ON_OPEN);
- throw ioe;
- } finally {
- destroyResponses();
- }
- }
-
- void logout() {
- try {
- sendCommand(ImapConstants.LOGOUT, false);
- if (!mParser.readResponse(true).is(0, ImapConstants.BYE)) {
- VvmLog.e(TAG, "Server did not respond LOGOUT with BYE");
- }
- if (!mParser.readResponse(false).isOk()) {
- VvmLog.e(TAG, "Server did not respond OK after LOGOUT");
- }
- } catch (IOException | MessagingException e) {
- VvmLog.e(TAG, "Error while logging out:" + e);
- }
- }
-
- /**
- * Closes the connection and releases all resources. This connection can not be used again
- * until {@link #setStore(ImapStore)} is called.
- */
- void close() {
- if (mTransport != null) {
- logout();
- mTransport.close();
- mTransport = null;
- }
- destroyResponses();
- mParser = null;
- mImapStore = null;
- }
-
- /**
- * Attempts to convert the connection into secure connection.
- */
- private void maybeDoStartTls() throws IOException, MessagingException {
- // STARTTLS is required in the OMTP standard but not every implementation support it.
- // Make sure the server does have this capability
- if (hasCapability(ImapConstants.CAPABILITY_STARTTLS)) {
- executeSimpleCommand(ImapConstants.STARTTLS);
- mTransport.reopenTls();
- createParser();
- // The cached capabilities should be refreshed after TLS is established.
- queryCapability();
- }
- }
-
- /**
- * Logs into the IMAP server
- */
- private void doLogin() throws IOException, MessagingException, AuthenticationFailedException {
- try {
- if (mCapabilities.contains(ImapConstants.CAPABILITY_AUTH_DIGEST_MD5)) {
- doDigestMd5Auth();
- } else {
- executeSimpleCommand(getLoginPhrase(), true);
- }
- } catch (ImapException ie) {
- LogUtils.d(TAG, "ImapException", ie);
- String status = ie.getStatus();
- String statusMessage = ie.getStatusMessage();
- String alertText = ie.getAlertText();
-
- if (ImapConstants.NO.equals(status)) {
- switch (statusMessage) {
- case ImapConstants.NO_UNKNOWN_USER:
- mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_AUTH_UNKNOWN_USER);
- break;
- case ImapConstants.NO_UNKNOWN_CLIENT:
- mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_AUTH_UNKNOWN_DEVICE);
- break;
- case ImapConstants.NO_INVALID_PASSWORD:
- mImapStore.getImapHelper()
- .handleEvent(OmtpEvents.DATA_AUTH_INVALID_PASSWORD);
- break;
- case ImapConstants.NO_MAILBOX_NOT_INITIALIZED:
- mImapStore.getImapHelper()
- .handleEvent(OmtpEvents.DATA_AUTH_MAILBOX_NOT_INITIALIZED);
- break;
- case ImapConstants.NO_SERVICE_IS_NOT_PROVISIONED:
- mImapStore.getImapHelper()
- .handleEvent(OmtpEvents.DATA_AUTH_SERVICE_NOT_PROVISIONED);
- break;
- case ImapConstants.NO_SERVICE_IS_NOT_ACTIVATED:
- mImapStore.getImapHelper()
- .handleEvent(OmtpEvents.DATA_AUTH_SERVICE_NOT_ACTIVATED);
- break;
- case ImapConstants.NO_USER_IS_BLOCKED:
- mImapStore.getImapHelper()
- .handleEvent(OmtpEvents.DATA_AUTH_USER_IS_BLOCKED);
- break;
- case ImapConstants.NO_APPLICATION_ERROR:
- mImapStore.getImapHelper()
- .handleEvent(OmtpEvents.DATA_REJECTED_SERVER_RESPONSE);
- default:
- mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_BAD_IMAP_CREDENTIAL);
- }
- throw new AuthenticationFailedException(alertText, ie);
- }
-
- mImapStore.getImapHelper().handleEvent(OmtpEvents.DATA_REJECTED_SERVER_RESPONSE);
- throw new MessagingException(alertText, ie);
- }
- }
-
- private void doDigestMd5Auth() throws IOException, MessagingException {
-
- // Initiate the authentication.
- // The server will issue us a challenge, asking to run MD5 on the nonce with our password
- // and other data, including the cnonce we randomly generated.
- //
- // C: a AUTHENTICATE DIGEST-MD5
- // S: (BASE64) realm="elwood.innosoft.com",nonce="OA6MG9tEQGm2hh",qop="auth",
- // algorithm=md5-sess,charset=utf-8
- List<ImapResponse> responses = executeSimpleCommand(
- ImapConstants.AUTHENTICATE + " " + ImapConstants.AUTH_DIGEST_MD5);
- String decodedChallenge = decodeBase64(responses.get(0).getStringOrEmpty(0).getString());
-
- Map<String, String> challenge = DigestMd5Utils.parseDigestMessage(decodedChallenge);
- DigestMd5Utils.Data data = new DigestMd5Utils.Data(mImapStore, mTransport, challenge);
-
- String response = data.createResponse();
- // Respond to the challenge. If the server accepts it, it will reply a response-auth which
- // is the MD5 of our password and the cnonce we've provided, to prove the server does know
- // the password.
- //
- // C: (BASE64) 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
- // S: (BASE64) rspauth=ea40f60335c427b5527b84dbabcdfffd
-
- responses = executeContinuationResponse(encodeBase64(response), true);
-
- // Verify response-auth.
- // If failed verifyResponseAuth() will throw a MessagingException, terminating the
- // connection
- String decodedResponseAuth = decodeBase64(responses.get(0).getStringOrEmpty(0).getString());
- data.verifyResponseAuth(decodedResponseAuth);
-
- // Send a empty response to indicate we've accepted the response-auth
- //
- // C: (empty)
- // S: a OK User logged in
- executeContinuationResponse("", false);
-
- }
-
- private static String decodeBase64(String string) {
- return new String(Base64.decode(string, Base64.DEFAULT));
- }
-
- private static String encodeBase64(String string) {
- return Base64.encodeToString(string.getBytes(), Base64.NO_WRAP);
- }
-
- private void queryCapability() throws IOException, MessagingException {
- List<ImapResponse> responses = executeSimpleCommand(ImapConstants.CAPABILITY);
- mCapabilities.clear();
- Set<String> disabledCapabilities = mImapStore.getImapHelper().getConfig()
- .getDisabledCapabilities();
- for (ImapResponse response : responses) {
- if (response.isTagged()) {
- continue;
- }
- for (int i = 0; i < response.size(); i++) {
- String capability = response.getStringOrEmpty(i).getString();
- if (disabledCapabilities != null) {
- if (!disabledCapabilities.contains(capability)) {
- mCapabilities.add(capability);
- }
- } else {
- mCapabilities.add(capability);
- }
- }
- }
-
- LogUtils.d(TAG, "Capabilities: " + mCapabilities.toString());
- }
-
- private boolean hasCapability(String capability) {
- return mCapabilities.contains(capability);
- }
- /**
- * Create an {@link ImapResponseParser} from {@code mTransport.getInputStream()} and
- * set it to {@link #mParser}.
- *
- * If we already have an {@link ImapResponseParser}, we
- * {@link #destroyResponses()} and throw it away.
- */
- private void createParser() {
- destroyResponses();
- mParser = new ImapResponseParser(mTransport.getInputStream());
- }
-
-
- public void destroyResponses() {
- if (mParser != null) {
- mParser.destroyResponses();
- }
- }
-
- public ImapResponse readResponse() throws IOException, MessagingException {
- return mParser.readResponse(false);
- }
-
- public List<ImapResponse> executeSimpleCommand(String command)
- throws IOException, MessagingException{
- return executeSimpleCommand(command, false);
- }
-
- /**
- * Send a single command to the server. The command will be preceded by an IMAP command
- * tag and followed by \r\n (caller need not supply them).
- * Execute a simple command at the server, a simple command being one that is sent in a single
- * line of text
- *
- * @param command the command to send to the server
- * @param sensitive whether the command should be redacted in logs (used for login)
- * @return a list of ImapResponses
- * @throws IOException
- * @throws MessagingException
- */
- public List<ImapResponse> executeSimpleCommand(String command, boolean sensitive)
- throws IOException, MessagingException {
- // TODO: It may be nice to catch IOExceptions and close the connection here.
- // Currently, we expect callers to do that, but if they fail to we'll be in a broken state.
- sendCommand(command, sensitive);
- return getCommandResponses();
- }
-
- public String sendCommand(String command, boolean sensitive)
- throws IOException, MessagingException {
- open();
-
- if (mTransport == null) {
- throw new IOException("Null transport");
- }
- String tag = Integer.toString(mNextCommandTag.incrementAndGet());
- String commandToSend = tag + " " + command;
- mTransport.writeLine(commandToSend, (sensitive ? IMAP_REDACTED_LOG : command));
- return tag;
- }
-
- List<ImapResponse> executeContinuationResponse(String response, boolean sensitive)
- throws IOException, MessagingException {
- mTransport.writeLine(response, (sensitive ? IMAP_REDACTED_LOG : response));
- return getCommandResponses();
- }
-
- /**
- * Read and return all of the responses from the most recent command sent to the server
- *
- * @return a list of ImapResponses
- * @throws IOException
- * @throws MessagingException
- */
- List<ImapResponse> getCommandResponses()
- throws IOException, MessagingException {
- final List<ImapResponse> responses = new ArrayList<ImapResponse>();
- ImapResponse response;
- do {
- response = mParser.readResponse(false);
- responses.add(response);
- } while (!(response.isTagged() || response.isContinuationRequest()));
-
- if (!(response.isOk() || response.isContinuationRequest())) {
- final String toString = response.toString();
- final String status = response.getStatusOrEmpty().getString();
- final String statusMessage = response.getStatusResponseTextOrEmpty().getString();
- final String alert = response.getAlertTextOrEmpty().getString();
- final String responseCode = response.getResponseCodeOrEmpty().getString();
- destroyResponses();
- throw new ImapException(toString, status, statusMessage, alert, responseCode);
- }
- return responses;
- }
-}
diff --git a/src/com/android/phone/common/mail/store/ImapFolder.java b/src/com/android/phone/common/mail/store/ImapFolder.java
deleted file mode 100644
index 4abb7f5..0000000
--- a/src/com/android/phone/common/mail/store/ImapFolder.java
+++ /dev/null
@@ -1,787 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.text.TextUtils;
-import android.util.Base64DataException;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.phone.common.R;
-import com.android.phone.common.mail.AuthenticationFailedException;
-import com.android.phone.common.mail.Body;
-import com.android.phone.common.mail.FetchProfile;
-import com.android.phone.common.mail.Flag;
-import com.android.phone.common.mail.Message;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.common.mail.Part;
-import com.android.phone.common.mail.internet.BinaryTempFileBody;
-import com.android.phone.common.mail.internet.MimeBodyPart;
-import com.android.phone.common.mail.internet.MimeHeader;
-import com.android.phone.common.mail.internet.MimeMultipart;
-import com.android.phone.common.mail.internet.MimeUtility;
-import com.android.phone.common.mail.store.ImapStore.ImapException;
-import com.android.phone.common.mail.store.ImapStore.ImapMessage;
-import com.android.phone.common.mail.store.imap.ImapConstants;
-import com.android.phone.common.mail.store.imap.ImapElement;
-import com.android.phone.common.mail.store.imap.ImapList;
-import com.android.phone.common.mail.store.imap.ImapResponse;
-import com.android.phone.common.mail.store.imap.ImapString;
-import com.android.phone.common.mail.utils.LogUtils;
-import com.android.phone.common.mail.utils.Utility;
-import com.android.phone.vvm.omtp.OmtpEvents;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Locale;
-
-public class ImapFolder {
- private static final String TAG = "ImapFolder";
- private final static String[] PERMANENT_FLAGS =
- { Flag.DELETED, Flag.SEEN, Flag.FLAGGED, Flag.ANSWERED };
- private static final int COPY_BUFFER_SIZE = 16*1024;
-
- private final ImapStore mStore;
- private final String mName;
- private int mMessageCount = -1;
- private ImapConnection mConnection;
- private String mMode;
- private boolean mExists;
- /** A set of hashes that can be used to track dirtiness */
- Object mHash[];
-
- public static final String MODE_READ_ONLY = "mode_read_only";
- public static final String MODE_READ_WRITE = "mode_read_write";
-
- public ImapFolder(ImapStore store, String name) {
- mStore = store;
- mName = name;
- }
-
- /**
- * Callback for each message retrieval.
- */
- public interface MessageRetrievalListener {
- public void messageRetrieved(Message message);
- }
-
- private void destroyResponses() {
- if (mConnection != null) {
- mConnection.destroyResponses();
- }
- }
-
- public void open(String mode) throws MessagingException {
- try {
- if (isOpen()) {
- throw new AssertionError("Duplicated open on ImapFolder");
- }
- synchronized (this) {
- mConnection = mStore.getConnection();
- }
- // * FLAGS (\Answered \Flagged \Deleted \Seen \Draft NonJunk
- // $MDNSent)
- // * OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft
- // NonJunk $MDNSent \*)] Flags permitted.
- // * 23 EXISTS
- // * 0 RECENT
- // * OK [UIDVALIDITY 1125022061] UIDs valid
- // * OK [UIDNEXT 57576] Predicted next UID
- // 2 OK [READ-WRITE] Select completed.
- try {
- doSelect();
- } catch (IOException ioe) {
- throw ioExceptionHandler(mConnection, ioe);
- } finally {
- destroyResponses();
- }
- } catch (AuthenticationFailedException e) {
- // Don't cache this connection, so we're forced to try connecting/login again
- mConnection = null;
- close(false);
- throw e;
- } catch (MessagingException e) {
- mExists = false;
- close(false);
- throw e;
- }
- }
-
- public boolean isOpen() {
- return mExists && mConnection != null;
- }
-
- public String getMode() {
- return mMode;
- }
-
- public void close(boolean expunge) {
- if (expunge) {
- try {
- expunge();
- } catch (MessagingException e) {
- LogUtils.e(TAG, e, "Messaging Exception");
- }
- }
- mMessageCount = -1;
- synchronized (this) {
- mConnection = null;
- }
- }
-
- public int getMessageCount() {
- return mMessageCount;
- }
-
- String[] getSearchUids(List<ImapResponse> responses) {
- // S: * SEARCH 2 3 6
- final ArrayList<String> uids = new ArrayList<String>();
- for (ImapResponse response : responses) {
- if (!response.isDataResponse(0, ImapConstants.SEARCH)) {
- continue;
- }
- // Found SEARCH response data
- for (int i = 1; i < response.size(); i++) {
- ImapString s = response.getStringOrEmpty(i);
- if (s.isString()) {
- uids.add(s.getString());
- }
- }
- }
- return uids.toArray(Utility.EMPTY_STRINGS);
- }
-
- @VisibleForTesting
- String[] searchForUids(String searchCriteria) throws MessagingException {
- checkOpen();
- try {
- try {
- final String command = ImapConstants.UID_SEARCH + " " + searchCriteria;
- final String[] result = getSearchUids(mConnection.executeSimpleCommand(command));
- LogUtils.d(TAG, "searchForUids '" + searchCriteria + "' results: " +
- result.length);
- return result;
- } catch (ImapException me) {
- LogUtils.d(TAG, "ImapException in search: " + searchCriteria, me);
- return Utility.EMPTY_STRINGS; // Not found
- } catch (IOException ioe) {
- LogUtils.d(TAG, "IOException in search: " + searchCriteria, ioe);
- mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE);
- throw ioExceptionHandler(mConnection, ioe);
- }
- } finally {
- destroyResponses();
- }
- }
-
- @Nullable
- public Message getMessage(String uid) throws MessagingException {
- checkOpen();
-
- final String[] uids = searchForUids(ImapConstants.UID + " " + uid);
- for (int i = 0; i < uids.length; i++) {
- if (uids[i].equals(uid)) {
- return new ImapMessage(uid, this);
- }
- }
- LogUtils.e(TAG, "UID " + uid + " not found on server");
- return null;
- }
-
- @VisibleForTesting
- protected static boolean isAsciiString(String str) {
- int len = str.length();
- for (int i = 0; i < len; i++) {
- char c = str.charAt(i);
- if (c >= 128) return false;
- }
- return true;
- }
-
- public Message[] getMessages(String[] uids) throws MessagingException {
- if (uids == null) {
- uids = searchForUids("1:* NOT DELETED");
- }
- return getMessagesInternal(uids);
- }
-
- public Message[] getMessagesInternal(String[] uids) {
- final ArrayList<Message> messages = new ArrayList<Message>(uids.length);
- for (int i = 0; i < uids.length; i++) {
- final String uid = uids[i];
- final ImapMessage message = new ImapMessage(uid, this);
- messages.add(message);
- }
- return messages.toArray(Message.EMPTY_ARRAY);
- }
-
- public void fetch(Message[] messages, FetchProfile fp,
- MessageRetrievalListener listener) throws MessagingException {
- try {
- fetchInternal(messages, fp, listener);
- } catch (RuntimeException e) { // Probably a parser error.
- LogUtils.w(TAG, "Exception detected: " + e.getMessage());
- throw e;
- }
- }
-
- public void fetchInternal(Message[] messages, FetchProfile fp,
- MessageRetrievalListener listener) throws MessagingException {
- if (messages.length == 0) {
- return;
- }
- checkOpen();
- HashMap<String, Message> messageMap = new HashMap<String, Message>();
- for (Message m : messages) {
- messageMap.put(m.getUid(), m);
- }
-
- /*
- * Figure out what command we are going to run:
- * FLAGS - UID FETCH (FLAGS)
- * ENVELOPE - UID FETCH (INTERNALDATE UID RFC822.SIZE FLAGS BODY.PEEK[
- * HEADER.FIELDS (date subject from content-type to cc)])
- * STRUCTURE - UID FETCH (BODYSTRUCTURE)
- * BODY_SANE - UID FETCH (BODY.PEEK[]<0.N>) where N = max bytes returned
- * BODY - UID FETCH (BODY.PEEK[])
- * Part - UID FETCH (BODY.PEEK[ID]) where ID = mime part ID
- */
-
- final LinkedHashSet<String> fetchFields = new LinkedHashSet<String>();
-
- fetchFields.add(ImapConstants.UID);
- if (fp.contains(FetchProfile.Item.FLAGS)) {
- fetchFields.add(ImapConstants.FLAGS);
- }
- if (fp.contains(FetchProfile.Item.ENVELOPE)) {
- fetchFields.add(ImapConstants.INTERNALDATE);
- fetchFields.add(ImapConstants.RFC822_SIZE);
- fetchFields.add(ImapConstants.FETCH_FIELD_HEADERS);
- }
- if (fp.contains(FetchProfile.Item.STRUCTURE)) {
- fetchFields.add(ImapConstants.BODYSTRUCTURE);
- }
-
- if (fp.contains(FetchProfile.Item.BODY_SANE)) {
- fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK_SANE);
- }
- if (fp.contains(FetchProfile.Item.BODY)) {
- fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK);
- }
-
- // TODO Why are we only fetching the first part given?
- final Part fetchPart = fp.getFirstPart();
- if (fetchPart != null) {
- final String[] partIds =
- fetchPart.getHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA);
- // TODO Why can a single part have more than one Id? And why should we only fetch
- // the first id if there are more than one?
- if (partIds != null) {
- fetchFields.add(ImapConstants.FETCH_FIELD_BODY_PEEK_BARE
- + "[" + partIds[0] + "]");
- }
- }
-
- try {
- mConnection.sendCommand(String.format(Locale.US,
- ImapConstants.UID_FETCH + " %s (%s)", ImapStore.joinMessageUids(messages),
- Utility.combine(fetchFields.toArray(new String[fetchFields.size()]), ' ')
- ), false);
- ImapResponse response;
- do {
- response = null;
- try {
- response = mConnection.readResponse();
-
- if (!response.isDataResponse(1, ImapConstants.FETCH)) {
- continue; // Ignore
- }
- final ImapList fetchList = response.getListOrEmpty(2);
- final String uid = fetchList.getKeyedStringOrEmpty(ImapConstants.UID)
- .getString();
- if (TextUtils.isEmpty(uid)) continue;
-
- ImapMessage message = (ImapMessage) messageMap.get(uid);
- if (message == null) continue;
-
- if (fp.contains(FetchProfile.Item.FLAGS)) {
- final ImapList flags =
- fetchList.getKeyedListOrEmpty(ImapConstants.FLAGS);
- for (int i = 0, count = flags.size(); i < count; i++) {
- final ImapString flag = flags.getStringOrEmpty(i);
- if (flag.is(ImapConstants.FLAG_DELETED)) {
- message.setFlagInternal(Flag.DELETED, true);
- } else if (flag.is(ImapConstants.FLAG_ANSWERED)) {
- message.setFlagInternal(Flag.ANSWERED, true);
- } else if (flag.is(ImapConstants.FLAG_SEEN)) {
- message.setFlagInternal(Flag.SEEN, true);
- } else if (flag.is(ImapConstants.FLAG_FLAGGED)) {
- message.setFlagInternal(Flag.FLAGGED, true);
- }
- }
- }
- if (fp.contains(FetchProfile.Item.ENVELOPE)) {
- final Date internalDate = fetchList.getKeyedStringOrEmpty(
- ImapConstants.INTERNALDATE).getDateOrNull();
- final int size = fetchList.getKeyedStringOrEmpty(
- ImapConstants.RFC822_SIZE).getNumberOrZero();
- final String header = fetchList.getKeyedStringOrEmpty(
- ImapConstants.BODY_BRACKET_HEADER, true).getString();
-
- message.setInternalDate(internalDate);
- message.setSize(size);
- message.parse(Utility.streamFromAsciiString(header));
- }
- if (fp.contains(FetchProfile.Item.STRUCTURE)) {
- ImapList bs = fetchList.getKeyedListOrEmpty(
- ImapConstants.BODYSTRUCTURE);
- if (!bs.isEmpty()) {
- try {
- parseBodyStructure(bs, message, ImapConstants.TEXT);
- } catch (MessagingException e) {
- LogUtils.v(TAG, e, "Error handling message");
- message.setBody(null);
- }
- }
- }
- if (fp.contains(FetchProfile.Item.BODY)
- || fp.contains(FetchProfile.Item.BODY_SANE)) {
- // Body is keyed by "BODY[]...".
- // Previously used "BODY[..." but this can be confused with "BODY[HEADER..."
- // TODO Should we accept "RFC822" as well??
- ImapString body = fetchList.getKeyedStringOrEmpty("BODY[]", true);
- InputStream bodyStream = body.getAsStream();
- message.parse(bodyStream);
- }
- if (fetchPart != null) {
- InputStream bodyStream =
- fetchList.getKeyedStringOrEmpty("BODY[", true).getAsStream();
- String encodings[] = fetchPart.getHeader(
- MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING);
-
- String contentTransferEncoding = null;
- if (encodings != null && encodings.length > 0) {
- contentTransferEncoding = encodings[0];
- } else {
- // According to http://tools.ietf.org/html/rfc2045#section-6.1
- // "7bit" is the default.
- contentTransferEncoding = "7bit";
- }
-
- try {
- // TODO Don't create 2 temp files.
- // decodeBody creates BinaryTempFileBody, but we could avoid this
- // if we implement ImapStringBody.
- // (We'll need to share a temp file. Protect it with a ref-count.)
- message.setBody(decodeBody(mStore.getContext(), bodyStream,
- contentTransferEncoding, fetchPart.getSize(), listener));
- } catch(Exception e) {
- // TODO: Figure out what kinds of exceptions might actually be thrown
- // from here. This blanket catch-all is because we're not sure what to
- // do if we don't have a contentTransferEncoding, and we don't have
- // time to figure out what exceptions might be thrown.
- LogUtils.e(TAG, "Error fetching body %s", e);
- }
- }
-
- if (listener != null) {
- listener.messageRetrieved(message);
- }
- } finally {
- destroyResponses();
- }
- } while (!response.isTagged());
- } catch (IOException ioe) {
- mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE);
- throw ioExceptionHandler(mConnection, ioe);
- }
- }
-
- /**
- * Removes any content transfer encoding from the stream and returns a Body.
- * This code is taken/condensed from MimeUtility.decodeBody
- */
- private static Body decodeBody(Context context,InputStream in, String contentTransferEncoding,
- int size, MessageRetrievalListener listener) throws IOException {
- // Get a properly wrapped input stream
- in = MimeUtility.getInputStreamForContentTransferEncoding(in, contentTransferEncoding);
- BinaryTempFileBody tempBody = new BinaryTempFileBody();
- OutputStream out = tempBody.getOutputStream();
- try {
- byte[] buffer = new byte[COPY_BUFFER_SIZE];
- int n = 0;
- int count = 0;
- while (-1 != (n = in.read(buffer))) {
- out.write(buffer, 0, n);
- count += n;
- }
- } catch (Base64DataException bde) {
- String warning = "\n\n" + context.getString(R.string.message_decode_error);
- out.write(warning.getBytes());
- } finally {
- out.close();
- }
- return tempBody;
- }
-
- public String[] getPermanentFlags() {
- return PERMANENT_FLAGS;
- }
-
- /**
- * Handle any untagged responses that the caller doesn't care to handle themselves.
- * @param responses
- */
- private void handleUntaggedResponses(List<ImapResponse> responses) {
- for (ImapResponse response : responses) {
- handleUntaggedResponse(response);
- }
- }
-
- /**
- * Handle an untagged response that the caller doesn't care to handle themselves.
- * @param response
- */
- private void handleUntaggedResponse(ImapResponse response) {
- if (response.isDataResponse(1, ImapConstants.EXISTS)) {
- mMessageCount = response.getStringOrEmpty(0).getNumberOrZero();
- }
- }
-
- private static void parseBodyStructure(ImapList bs, Part part, String id)
- throws MessagingException {
- if (bs.getElementOrNone(0).isList()) {
- /*
- * This is a multipart/*
- */
- MimeMultipart mp = new MimeMultipart();
- for (int i = 0, count = bs.size(); i < count; i++) {
- ImapElement e = bs.getElementOrNone(i);
- if (e.isList()) {
- /*
- * For each part in the message we're going to add a new BodyPart and parse
- * into it.
- */
- MimeBodyPart bp = new MimeBodyPart();
- if (id.equals(ImapConstants.TEXT)) {
- parseBodyStructure(bs.getListOrEmpty(i), bp, Integer.toString(i + 1));
-
- } else {
- parseBodyStructure(bs.getListOrEmpty(i), bp, id + "." + (i + 1));
- }
- mp.addBodyPart(bp);
-
- } else {
- if (e.isString()) {
- mp.setSubType(bs.getStringOrEmpty(i).getString().toLowerCase(Locale.US));
- }
- break; // Ignore the rest of the list.
- }
- }
- part.setBody(mp);
- } else {
- /*
- * This is a body. We need to add as much information as we can find out about
- * it to the Part.
- */
-
- /*
- body type
- body subtype
- body parameter parenthesized list
- body id
- body description
- body encoding
- body size
- */
-
- final ImapString type = bs.getStringOrEmpty(0);
- final ImapString subType = bs.getStringOrEmpty(1);
- final String mimeType =
- (type.getString() + "/" + subType.getString()).toLowerCase(Locale.US);
-
- final ImapList bodyParams = bs.getListOrEmpty(2);
- final ImapString cid = bs.getStringOrEmpty(3);
- final ImapString encoding = bs.getStringOrEmpty(5);
- final int size = bs.getStringOrEmpty(6).getNumberOrZero();
-
- if (MimeUtility.mimeTypeMatches(mimeType, MimeUtility.MIME_TYPE_RFC822)) {
- // A body type of type MESSAGE and subtype RFC822
- // contains, immediately after the basic fields, the
- // envelope structure, body structure, and size in
- // text lines of the encapsulated message.
- // [MESSAGE, RFC822, [NAME, filename.eml], NIL, NIL, 7BIT, 5974, NIL,
- // [INLINE, [FILENAME*0, Fwd: Xxx..., FILENAME*1, filename.eml]], NIL]
- /*
- * This will be caught by fetch and handled appropriately.
- */
- throw new MessagingException("BODYSTRUCTURE " + MimeUtility.MIME_TYPE_RFC822
- + " not yet supported.");
- }
-
- /*
- * Set the content type with as much information as we know right now.
- */
- final StringBuilder contentType = new StringBuilder(mimeType);
-
- /*
- * If there are body params we might be able to get some more information out
- * of them.
- */
- for (int i = 1, count = bodyParams.size(); i < count; i += 2) {
-
- // TODO We need to convert " into %22, but
- // because MimeUtility.getHeaderParameter doesn't recognize it,
- // we can't fix it for now.
- contentType.append(String.format(";\n %s=\"%s\"",
- bodyParams.getStringOrEmpty(i - 1).getString(),
- bodyParams.getStringOrEmpty(i).getString()));
- }
-
- part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, contentType.toString());
-
- // Extension items
- final ImapList bodyDisposition;
-
- if (type.is(ImapConstants.TEXT) && bs.getElementOrNone(9).isList()) {
- // If media-type is TEXT, 9th element might be: [body-fld-lines] := number
- // So, if it's not a list, use 10th element.
- // (Couldn't find evidence in the RFC if it's ALWAYS 10th element.)
- bodyDisposition = bs.getListOrEmpty(9);
- } else {
- bodyDisposition = bs.getListOrEmpty(8);
- }
-
- final StringBuilder contentDisposition = new StringBuilder();
-
- if (bodyDisposition.size() > 0) {
- final String bodyDisposition0Str =
- bodyDisposition.getStringOrEmpty(0).getString().toLowerCase(Locale.US);
- if (!TextUtils.isEmpty(bodyDisposition0Str)) {
- contentDisposition.append(bodyDisposition0Str);
- }
-
- final ImapList bodyDispositionParams = bodyDisposition.getListOrEmpty(1);
- if (!bodyDispositionParams.isEmpty()) {
- /*
- * If there is body disposition information we can pull some more
- * information about the attachment out.
- */
- for (int i = 1, count = bodyDispositionParams.size(); i < count; i += 2) {
-
- // TODO We need to convert " into %22. See above.
- contentDisposition.append(String.format(Locale.US, ";\n %s=\"%s\"",
- bodyDispositionParams.getStringOrEmpty(i - 1)
- .getString().toLowerCase(Locale.US),
- bodyDispositionParams.getStringOrEmpty(i).getString()));
- }
- }
- }
-
- if ((size > 0)
- && (MimeUtility.getHeaderParameter(contentDisposition.toString(), "size")
- == null)) {
- contentDisposition.append(String.format(Locale.US, ";\n size=%d", size));
- }
-
- if (contentDisposition.length() > 0) {
- /*
- * Set the content disposition containing at least the size. Attachment
- * handling code will use this down the road.
- */
- part.setHeader(MimeHeader.HEADER_CONTENT_DISPOSITION,
- contentDisposition.toString());
- }
-
- /*
- * Set the Content-Transfer-Encoding header. Attachment code will use this
- * to parse the body.
- */
- if (!encoding.isEmpty()) {
- part.setHeader(MimeHeader.HEADER_CONTENT_TRANSFER_ENCODING,
- encoding.getString());
- }
-
- /*
- * Set the Content-ID header.
- */
- if (!cid.isEmpty()) {
- part.setHeader(MimeHeader.HEADER_CONTENT_ID, cid.getString());
- }
-
- if (size > 0) {
- if (part instanceof ImapMessage) {
- ((ImapMessage) part).setSize(size);
- } else if (part instanceof MimeBodyPart) {
- ((MimeBodyPart) part).setSize(size);
- } else {
- throw new MessagingException("Unknown part type " + part.toString());
- }
- }
- part.setHeader(MimeHeader.HEADER_ANDROID_ATTACHMENT_STORE_DATA, id);
- }
-
- }
-
- public Message[] expunge() throws MessagingException {
- checkOpen();
- try {
- handleUntaggedResponses(mConnection.executeSimpleCommand(ImapConstants.EXPUNGE));
- } catch (IOException ioe) {
- mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE);
- throw ioExceptionHandler(mConnection, ioe);
- } finally {
- destroyResponses();
- }
- return null;
- }
-
- public void setFlags(Message[] messages, String[] flags, boolean value)
- throws MessagingException {
- checkOpen();
-
- String allFlags = "";
- if (flags.length > 0) {
- StringBuilder flagList = new StringBuilder();
- for (int i = 0, count = flags.length; i < count; i++) {
- String flag = flags[i];
- if (flag == Flag.SEEN) {
- flagList.append(" " + ImapConstants.FLAG_SEEN);
- } else if (flag == Flag.DELETED) {
- flagList.append(" " + ImapConstants.FLAG_DELETED);
- } else if (flag == Flag.FLAGGED) {
- flagList.append(" " + ImapConstants.FLAG_FLAGGED);
- } else if (flag == Flag.ANSWERED) {
- flagList.append(" " + ImapConstants.FLAG_ANSWERED);
- }
- }
- allFlags = flagList.substring(1);
- }
- try {
- mConnection.executeSimpleCommand(String.format(Locale.US,
- ImapConstants.UID_STORE + " %s %s" + ImapConstants.FLAGS_SILENT + " (%s)",
- ImapStore.joinMessageUids(messages),
- value ? "+" : "-",
- allFlags));
-
- } catch (IOException ioe) {
- mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE);
- throw ioExceptionHandler(mConnection, ioe);
- } finally {
- destroyResponses();
- }
- }
-
- /**
- * Selects the folder for use. Before performing any operations on this folder, it
- * must be selected.
- */
- private void doSelect() throws IOException, MessagingException {
- final List<ImapResponse> responses = mConnection.executeSimpleCommand(
- String.format(Locale.US, ImapConstants.SELECT + " \"%s\"", mName));
-
- // Assume the folder is opened read-write; unless we are notified otherwise
- mMode = MODE_READ_WRITE;
- int messageCount = -1;
- for (ImapResponse response : responses) {
- if (response.isDataResponse(1, ImapConstants.EXISTS)) {
- messageCount = response.getStringOrEmpty(0).getNumberOrZero();
- } else if (response.isOk()) {
- final ImapString responseCode = response.getResponseCodeOrEmpty();
- if (responseCode.is(ImapConstants.READ_ONLY)) {
- mMode = MODE_READ_ONLY;
- } else if (responseCode.is(ImapConstants.READ_WRITE)) {
- mMode = MODE_READ_WRITE;
- }
- } else if (response.isTagged()) { // Not OK
- mStore.getImapHelper().handleEvent(OmtpEvents.DATA_MAILBOX_OPEN_FAILED);
- throw new MessagingException("Can't open mailbox: "
- + response.getStatusResponseTextOrEmpty());
- }
- }
- if (messageCount == -1) {
- throw new MessagingException("Did not find message count during select");
- }
- mMessageCount = messageCount;
- mExists = true;
- }
-
- public class Quota {
-
- public final int occupied;
- public final int total;
-
- public Quota(int occupied, int total) {
- this.occupied = occupied;
- this.total = total;
- }
- }
-
- public Quota getQuota() throws MessagingException {
- try {
- final List<ImapResponse> responses = mConnection.executeSimpleCommand(
- String.format(Locale.US, ImapConstants.GETQUOTAROOT + " \"%s\"", mName));
-
- for (ImapResponse response : responses) {
- if (!response.isDataResponse(0, ImapConstants.QUOTA)) {
- continue;
- }
- ImapList list = response.getListOrEmpty(2);
- for (int i = 0; i < list.size(); i += 3) {
- if (!list.getStringOrEmpty(i).is("voice")) {
- continue;
- }
- return new Quota(
- list.getStringOrEmpty(i + 1).getNumber(-1),
- list.getStringOrEmpty(i + 2).getNumber(-1));
- }
- }
- } catch (IOException ioe) {
- mStore.getImapHelper().handleEvent(OmtpEvents.DATA_GENERIC_IMAP_IOE);
- throw ioExceptionHandler(mConnection, ioe);
- } finally {
- destroyResponses();
- }
- return null;
- }
-
- private void checkOpen() throws MessagingException {
- if (!isOpen()) {
- throw new MessagingException("Folder " + mName + " is not open.");
- }
- }
-
- private MessagingException ioExceptionHandler(ImapConnection connection, IOException ioe) {
- LogUtils.d(TAG, "IO Exception detected: ", ioe);
- connection.close();
- if (connection == mConnection) {
- mConnection = null; // To prevent close() from returning the connection to the pool.
- close(false);
- }
- return new MessagingException(MessagingException.IOERROR, "IO Error", ioe);
- }
-
- public Message createMessage(String uid) {
- return new ImapMessage(uid, this);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/ImapStore.java b/src/com/android/phone/common/mail/store/ImapStore.java
deleted file mode 100644
index 179d0f2..0000000
--- a/src/com/android/phone/common/mail/store/ImapStore.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store;
-
-import android.content.Context;
-import android.net.Network;
-
-import com.android.phone.common.mail.MailTransport;
-import com.android.phone.common.mail.Message;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.common.mail.internet.MimeMessage;
-import com.android.phone.vvm.omtp.imap.ImapHelper;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-public class ImapStore {
- /**
- * A global suggestion to Store implementors on how much of the body
- * should be returned on FetchProfile.Item.BODY_SANE requests. We'll use 125k now.
- */
- public static final int FETCH_BODY_SANE_SUGGESTED_SIZE = (125 * 1024);
- private final Context mContext;
- private final ImapHelper mHelper;
- private final String mUsername;
- private final String mPassword;
- private final MailTransport mTransport;
- private ImapConnection mConnection;
-
- public static final int FLAG_NONE = 0x00; // No flags
- public static final int FLAG_SSL = 0x01; // Use SSL
- public static final int FLAG_TLS = 0x02; // Use TLS
- public static final int FLAG_AUTHENTICATE = 0x04; // Use name/password for authentication
- public static final int FLAG_TRUST_ALL = 0x08; // Trust all certificates
- public static final int FLAG_OAUTH = 0x10; // Use OAuth for authentication
-
- /**
- * Contains all the information necessary to log into an imap server
- */
- public ImapStore(Context context, ImapHelper helper, String username, String password, int port,
- String serverName, int flags, Network network) {
- mContext = context;
- mHelper = helper;
- mUsername = username;
- mPassword = password;
- mTransport = new MailTransport(context, this.getImapHelper(),
- network, serverName, port, flags);
- }
-
- public Context getContext() {
- return mContext;
- }
-
- public ImapHelper getImapHelper() {
- return mHelper;
- }
-
- public String getUsername() {
- return mUsername;
- }
-
- public String getPassword() {
- return mPassword;
- }
-
- /** Returns a clone of the transport associated with this store. */
- MailTransport cloneTransport() {
- return mTransport.clone();
- }
-
- /**
- * Returns UIDs of Messages joined with "," as the separator.
- */
- static String joinMessageUids(Message[] messages) {
- StringBuilder sb = new StringBuilder();
- boolean notFirst = false;
- for (Message m : messages) {
- if (notFirst) {
- sb.append(',');
- }
- sb.append(m.getUid());
- notFirst = true;
- }
- return sb.toString();
- }
-
- static class ImapMessage extends MimeMessage {
- private ImapFolder mFolder;
-
- ImapMessage(String uid, ImapFolder folder) {
- mUid = uid;
- mFolder = folder;
- }
-
- public void setSize(int size) {
- mSize = size;
- }
-
- @Override
- public void parse(InputStream in) throws IOException, MessagingException {
- super.parse(in);
- }
-
- public void setFlagInternal(String flag, boolean set) throws MessagingException {
- super.setFlag(flag, set);
- }
-
- @Override
- public void setFlag(String flag, boolean set) throws MessagingException {
- super.setFlag(flag, set);
- mFolder.setFlags(new Message[] { this }, new String[] { flag }, set);
- }
- }
-
- static class ImapException extends MessagingException {
- private static final long serialVersionUID = 1L;
-
- private final String mStatus;
- private final String mStatusMessage;
- private final String mAlertText;
- private final String mResponseCode;
-
- public ImapException(String message, String status, String statusMessage, String alertText,
- String responseCode) {
- super(message);
- mStatus = status;
- mStatusMessage = statusMessage;
- mAlertText = alertText;
- mResponseCode = responseCode;
- }
-
- public String getStatus() {
- return mStatus;
- }
-
- public String getStatusMessage() {
- return mStatusMessage;
- }
-
- public String getAlertText() {
- return mAlertText;
- }
-
- public String getResponseCode() {
- return mResponseCode;
- }
- }
-
- public void closeConnection() {
- if (mConnection != null) {
- mConnection.close();
- mConnection = null;
- }
- }
-
- public ImapConnection getConnection() {
- if (mConnection == null) {
- mConnection = new ImapConnection(this);
- }
- return mConnection;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java b/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
deleted file mode 100644
index 436d03c..0000000
--- a/src/com/android/phone/common/mail/store/imap/DigestMd5Utils.java
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone.common.mail.store.imap;
-
-import android.annotation.Nullable;
-import android.util.ArrayMap;
-import android.util.Base64;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.phone.common.mail.MailTransport;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.common.mail.store.ImapStore;
-import com.android.phone.vvm.omtp.VvmLog;
-
-import java.nio.charset.StandardCharsets;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.Map;
-
-public class DigestMd5Utils {
-
- private static final String TAG = "DigestMd5Utils";
-
- private static final String DIGEST_CHARSET = "CHARSET";
- private static final String DIGEST_USERNAME = "username";
- private static final String DIGEST_REALM = "realm";
- private static final String DIGEST_NONCE = "nonce";
- private static final String DIGEST_NC = "nc";
- private static final String DIGEST_CNONCE = "cnonce";
- private static final String DIGEST_URI = "digest-uri";
- private static final String DIGEST_RESPONSE = "response";
- private static final String DIGEST_QOP = "qop";
-
- private static final String RESPONSE_AUTH_HEADER = "rspauth=";
- private static final String HEX_CHARS = "0123456789abcdef";
-
- /**
- * Represents the set of data we need to generate the DIGEST-MD5 response.
- */
- public static class Data {
-
- private static final String CHARSET = "utf-8";
-
- public String username;
- public String password;
- public String realm;
- public String nonce;
- public String nc;
- public String cnonce;
- public String digestUri;
- public String qop;
-
- @VisibleForTesting
- Data() {
- // Do nothing
- }
-
- public Data(ImapStore imapStore, MailTransport transport, Map<String, String> challenge) {
- username = imapStore.getUsername();
- password = imapStore.getPassword();
- realm = challenge.getOrDefault(DIGEST_REALM, "");
- nonce = challenge.get(DIGEST_NONCE);
- cnonce = createCnonce();
- nc = "00000001"; // Subsequent Authentication not supported, nounce count always 1.
- qop = "auth"; // Other config not supported
- digestUri = "imap/" + transport.getHost();
- }
-
- private static String createCnonce() {
- SecureRandom generator = new SecureRandom();
-
- // At least 64 bits of entropy is required
- byte[] rawBytes = new byte[8];
- generator.nextBytes(rawBytes);
-
- return Base64.encodeToString(rawBytes, Base64.NO_WRAP);
- }
-
- /**
- * Verify the response-auth returned by the server is correct.
- */
- public void verifyResponseAuth(String response)
- throws MessagingException {
- if (!response.startsWith(RESPONSE_AUTH_HEADER)) {
- throw new MessagingException("response-auth expected");
- }
- if (!response.substring(RESPONSE_AUTH_HEADER.length())
- .equals(DigestMd5Utils.getResponse(this, true))) {
- throw new MessagingException("invalid response-auth return from the server.");
- }
- }
-
- public String createResponse() {
- String response = getResponse(this, false);
- ResponseBuilder builder = new ResponseBuilder();
- builder
- .append(DIGEST_CHARSET, CHARSET)
- .appendQuoted(DIGEST_USERNAME, username)
- .appendQuoted(DIGEST_REALM, realm)
- .appendQuoted(DIGEST_NONCE, nonce)
- .append(DIGEST_NC, nc)
- .appendQuoted(DIGEST_CNONCE, cnonce)
- .appendQuoted(DIGEST_URI, digestUri)
- .append(DIGEST_RESPONSE, response)
- .append(DIGEST_QOP, qop);
- return builder.toString();
- }
-
- private static class ResponseBuilder {
-
- private StringBuilder mBuilder = new StringBuilder();
-
- public ResponseBuilder appendQuoted(String key, String value) {
- if (mBuilder.length() != 0) {
- mBuilder.append(",");
- }
- mBuilder.append(key).append("=\"").append(value).append("\"");
- return this;
- }
-
- public ResponseBuilder append(String key, String value) {
- if (mBuilder.length() != 0) {
- mBuilder.append(",");
- }
- mBuilder.append(key).append("=").append(value);
- return this;
- }
-
- @Override
- public String toString() {
- return mBuilder.toString();
- }
- }
- }
-
- /*
- response-value =
- toHex( getKeyDigest ( toHex(getMd5(a1)),
- { nonce-value, ":" nc-value, ":",
- cnonce-value, ":", qop-value, ":", toHex(getMd5(a2)) }))
- * @param isResponseAuth is the response the one the server is returning us. response-auth has
- * different a2 format.
- */
- @VisibleForTesting
- static String getResponse(Data data, boolean isResponseAuth) {
- StringBuilder a1 = new StringBuilder();
- a1.append(new String(
- getMd5(data.username + ":" + data.realm + ":" + data.password),
- StandardCharsets.ISO_8859_1));
- a1.append(":").append(data.nonce).append(":").append(data.cnonce);
-
- StringBuilder a2 = new StringBuilder();
- if (!isResponseAuth) {
- a2.append("AUTHENTICATE");
- }
- a2.append(":").append(data.digestUri);
-
- return toHex(getKeyDigest(
- toHex(getMd5(a1.toString())),
- data.nonce + ":" + data.nc + ":" + data.cnonce + ":" + data.qop + ":" + toHex(
- getMd5(a2.toString()))
- ));
- }
-
- /**
- * Let getMd5(s) be the 16 octet MD5 hash [RFC 1321] of the octet string s.
- */
- private static byte[] getMd5(String s) {
- try {
- MessageDigest digester = MessageDigest.getInstance("MD5");
- digester.update(s.getBytes(StandardCharsets.ISO_8859_1));
- return digester.digest();
- } catch (NoSuchAlgorithmException e) {
- throw new AssertionError(e);
- }
- }
-
- /**
- * Let getKeyDigest(k, s) be getMd5({k, ":", s}), i.e., the 16 octet hash of the string k, a colon and the
- * string s.
- */
- private static byte[] getKeyDigest(String k, String s) {
- StringBuilder builder = new StringBuilder(k).append(":").append(s);
- return getMd5(builder.toString());
- }
-
- /**
- * Let toHex(n) be the representation of the 16 octet MD5 hash n as a string of 32 hex digits
- * (with alphabetic characters always in lower case, since MD5 is case sensitive).
- */
- private static String toHex(byte[] n) {
- StringBuilder result = new StringBuilder();
- for (byte b : n) {
- int unsignedByte = b & 0xFF;
- result.append(HEX_CHARS.charAt(unsignedByte / 16))
- .append(HEX_CHARS.charAt(unsignedByte % 16));
- }
- return result.toString();
- }
-
- public static Map<String, String> parseDigestMessage(String message) throws MessagingException {
- Map<String, String> result = new DigestMessageParser(message).parse();
- if (!result.containsKey(DIGEST_NONCE)) {
- throw new MessagingException("nonce missing from server DIGEST-MD5 challenge");
- }
- return result;
- }
-
- /**
- * Parse the key-value pair returned by the server.
- */
- private static class DigestMessageParser {
-
- private final String mMessage;
- private int mPosition = 0;
- private Map<String, String> mResult = new ArrayMap<>();
-
- public DigestMessageParser(String message) {
- mMessage = message;
- }
-
- @Nullable
- public Map<String, String> parse() {
- try {
- while (mPosition < mMessage.length()) {
- parsePair();
- if (mPosition != mMessage.length()) {
- expect(',');
- }
- }
- } catch (IndexOutOfBoundsException e) {
- VvmLog.e(TAG, e.toString());
- return null;
- }
- return mResult;
- }
-
- private void parsePair() {
- String key = parseKey();
- expect('=');
- String value = parseValue();
- mResult.put(key, value);
- }
-
- private void expect(char c) {
- if (pop() != c) {
- throw new IllegalStateException(
- "unexpected character " + mMessage.charAt(mPosition));
- }
- }
-
- private char pop() {
- char result = peek();
- mPosition++;
- return result;
- }
-
- private char peek() {
- return mMessage.charAt(mPosition);
- }
-
- private void goToNext(char c) {
- while (peek() != c) {
- mPosition++;
- }
- }
-
- private String parseKey() {
- int start = mPosition;
- goToNext('=');
- return mMessage.substring(start, mPosition);
- }
-
- private String parseValue() {
- if (peek() == '"') {
- return parseQuotedValue();
- } else {
- return parseUnquotedValue();
- }
- }
-
- private String parseQuotedValue() {
- expect('"');
- StringBuilder result = new StringBuilder();
- while (true) {
- char c = pop();
- if (c == '\\') {
- result.append(pop());
- } else if (c == '"') {
- break;
- } else {
- result.append(c);
- }
- }
- return result.toString();
- }
-
- private String parseUnquotedValue() {
- StringBuilder result = new StringBuilder();
- while (true) {
- char c = pop();
- if (c == '\\') {
- result.append(pop());
- } else if (c == ',') {
- mPosition--;
- break;
- } else {
- result.append(c);
- }
-
- if (mPosition == mMessage.length()) {
- break;
- }
- }
- return result.toString();
- }
- }
-}
diff --git a/src/com/android/phone/common/mail/store/imap/ImapConstants.java b/src/com/android/phone/common/mail/store/imap/ImapConstants.java
deleted file mode 100644
index a2eab13..0000000
--- a/src/com/android/phone/common/mail/store/imap/ImapConstants.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store.imap;
-
-import com.android.phone.common.mail.store.ImapStore;
-
-import java.util.Locale;
-
-public final class ImapConstants {
- private ImapConstants() {}
-
- public static final String FETCH_FIELD_BODY_PEEK_BARE = "BODY.PEEK";
- public static final String FETCH_FIELD_BODY_PEEK = FETCH_FIELD_BODY_PEEK_BARE + "[]";
- public static final String FETCH_FIELD_BODY_PEEK_SANE = String.format(
- Locale.US, "BODY.PEEK[]<0.%d>", ImapStore.FETCH_BODY_SANE_SUGGESTED_SIZE);
- public static final String FETCH_FIELD_HEADERS =
- "BODY.PEEK[HEADER.FIELDS (date subject from content-type to cc message-id)]";
-
- public static final String ALERT = "ALERT";
- public static final String APPEND = "APPEND";
- public static final String AUTHENTICATE = "AUTHENTICATE";
- public static final String BAD = "BAD";
- public static final String BADCHARSET = "BADCHARSET";
- public static final String BODY = "BODY";
- public static final String BODY_BRACKET_HEADER = "BODY[HEADER";
- public static final String BODYSTRUCTURE = "BODYSTRUCTURE";
- public static final String BYE = "BYE";
- public static final String CAPABILITY = "CAPABILITY";
- public static final String CHECK = "CHECK";
- public static final String CLOSE = "CLOSE";
- public static final String COPY = "COPY";
- public static final String COPYUID = "COPYUID";
- public static final String CREATE = "CREATE";
- public static final String DELETE = "DELETE";
- public static final String EXAMINE = "EXAMINE";
- public static final String EXISTS = "EXISTS";
- public static final String EXPUNGE = "EXPUNGE";
- public static final String FETCH = "FETCH";
- public static final String FLAG_ANSWERED = "\\ANSWERED";
- public static final String FLAG_DELETED = "\\DELETED";
- public static final String FLAG_FLAGGED = "\\FLAGGED";
- public static final String FLAG_NO_SELECT = "\\NOSELECT";
- public static final String FLAG_SEEN = "\\SEEN";
- public static final String FLAGS = "FLAGS";
- public static final String FLAGS_SILENT = "FLAGS.SILENT";
- public static final String ID = "ID";
- public static final String INBOX = "INBOX";
- public static final String INTERNALDATE = "INTERNALDATE";
- public static final String LIST = "LIST";
- public static final String LOGIN = "LOGIN";
- public static final String LOGOUT = "LOGOUT";
- public static final String LSUB = "LSUB";
- public static final String NAMESPACE = "NAMESPACE";
- public static final String NO = "NO";
- public static final String NOOP = "NOOP";
- public static final String OK = "OK";
- public static final String PARSE = "PARSE";
- public static final String PERMANENTFLAGS = "PERMANENTFLAGS";
- public static final String PREAUTH = "PREAUTH";
- public static final String READ_ONLY = "READ-ONLY";
- public static final String READ_WRITE = "READ-WRITE";
- public static final String RENAME = "RENAME";
- public static final String RFC822_SIZE = "RFC822.SIZE";
- public static final String SEARCH = "SEARCH";
- public static final String SELECT = "SELECT";
- public static final String STARTTLS = "STARTTLS";
- public static final String STATUS = "STATUS";
- public static final String STORE = "STORE";
- public static final String SUBSCRIBE = "SUBSCRIBE";
- public static final String TEXT = "TEXT";
- public static final String TRYCREATE = "TRYCREATE";
- public static final String UID = "UID";
- public static final String UID_COPY = "UID COPY";
- public static final String UID_FETCH = "UID FETCH";
- public static final String UID_SEARCH = "UID SEARCH";
- public static final String UID_STORE = "UID STORE";
- public static final String UIDNEXT = "UIDNEXT";
- public static final String UIDPLUS = "UIDPLUS";
- public static final String UIDVALIDITY = "UIDVALIDITY";
- public static final String UNSEEN = "UNSEEN";
- public static final String UNSUBSCRIBE = "UNSUBSCRIBE";
- public static final String XOAUTH2 = "XOAUTH2";
- public static final String APPENDUID = "APPENDUID";
- public static final String NIL = "NIL";
-
- /**
- * NO responses
- */
- public static final String NO_COMMAND_NOT_ALLOWED = "command not allowed";
- public static final String NO_RESERVATION_FAILED = "reservation failed";
- public static final String NO_APPLICATION_ERROR = "application error";
- public static final String NO_INVALID_PARAMETER = "invalid parameter";
- public static final String NO_INVALID_COMMAND = "invalid command";
- public static final String NO_UNKNOWN_COMMAND = "unknown command";
- // AUTHENTICATE
- // The subscriber can not be located in the system.
- public static final String NO_UNKNOWN_USER = "unknown user";
- // The Client Type or Protocol Version is unknown.
- public static final String NO_UNKNOWN_CLIENT = "unknown client";
- // The password received from the client does not match the password defined in the subscriber's profile.
- public static final String NO_INVALID_PASSWORD = "invalid password";
- // The subscriber's mailbox has not yet been initialised via the TUI
- public static final String NO_MAILBOX_NOT_INITIALIZED = "mailbox not initialized";
- // The subscriber has not been provisioned for the VVM service.
- public static final String NO_SERVICE_IS_NOT_PROVISIONED =
- "service is not provisioned";
- // The subscriber is provisioned for the VVM service but the VVM service is currently not active
- public static final String NO_SERVICE_IS_NOT_ACTIVATED = "service is not activated";
- // The Voice Mail Blocked flag in the subscriber's profile is set to YES.
- public static final String NO_USER_IS_BLOCKED = "user is blocked";
-
- /**
- * extensions
- */
- public static final String GETQUOTA = "GETQUOTA";
- public static final String GETQUOTAROOT = "GETQUOTAROOT";
- public static final String QUOTAROOT = "QUOTAROOT";
- public static final String QUOTA = "QUOTA";
-
- /**
- * capabilities
- */
- public static final String CAPABILITY_AUTH_DIGEST_MD5 = "AUTH=DIGEST-MD5";
- public static final String CAPABILITY_STARTTLS = "STARTTLS";
-
- /**
- * authentication
- */
- public static final String AUTH_DIGEST_MD5 = "DIGEST-MD5";
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/imap/ImapElement.java b/src/com/android/phone/common/mail/store/imap/ImapElement.java
deleted file mode 100644
index 2d1824e..0000000
--- a/src/com/android/phone/common/mail/store/imap/ImapElement.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store.imap;
-
-/**
- * Class representing "element"s in IMAP responses.
- *
- * <p>Class hierarchy:
- * <pre>
- * ImapElement
- * |
- * |-- ImapElement.NONE (for 'index out of range')
- * |
- * |-- ImapList (isList() == true)
- * | |
- * | |-- ImapList.EMPTY
- * | |
- * | --- ImapResponse
- * |
- * --- ImapString (isString() == true)
- * |
- * |-- ImapString.EMPTY
- * |
- * |-- ImapSimpleString
- * |
- * |-- ImapMemoryLiteral
- * |
- * --- ImapTempFileLiteral
- * </pre>
- */
-public abstract class ImapElement {
- /**
- * An element that is returned by {@link ImapList#getElementOrNone} to indicate an index
- * is out of range.
- */
- public static final ImapElement NONE = new ImapElement() {
- @Override public void destroy() {
- // Don't call super.destroy().
- // It's a shared object. We don't want the mDestroyed to be set on this.
- }
-
- @Override public boolean isList() {
- return false;
- }
-
- @Override public boolean isString() {
- return false;
- }
-
- @Override public String toString() {
- return "[NO ELEMENT]";
- }
-
- @Override
- public boolean equalsForTest(ImapElement that) {
- return super.equalsForTest(that);
- }
- };
-
- private boolean mDestroyed = false;
-
- public abstract boolean isList();
-
- public abstract boolean isString();
-
- protected boolean isDestroyed() {
- return mDestroyed;
- }
-
- /**
- * Clean up the resources used by the instance.
- * It's for removing a temp file used by {@link ImapTempFileLiteral}.
- */
- public void destroy() {
- mDestroyed = true;
- }
-
- /**
- * Throws {@link RuntimeException} if it's already destroyed.
- */
- protected final void checkNotDestroyed() {
- if (mDestroyed) {
- throw new RuntimeException("Already destroyed");
- }
- }
-
- /**
- * Return a string that represents this object; it's purely for the debug purpose. Don't
- * mistake it for {@link ImapString#getString}.
- *
- * Abstract to force subclasses to implement it.
- */
- @Override
- public abstract String toString();
-
- /**
- * The equals implementation that is intended to be used only for unit testing.
- * (Because it may be heavy and has a special sense of "equal" for testing.)
- */
- public boolean equalsForTest(ImapElement that) {
- if (that == null) {
- return false;
- }
- return this.getClass() == that.getClass(); // Has to be the same class.
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/imap/ImapList.java b/src/com/android/phone/common/mail/store/imap/ImapList.java
deleted file mode 100644
index 93adc4f..0000000
--- a/src/com/android/phone/common/mail/store/imap/ImapList.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store.imap;
-
-import java.util.ArrayList;
-
-/**
- * Class represents an IMAP list.
- */
-public class ImapList extends ImapElement {
- /**
- * {@link ImapList} representing an empty list.
- */
- public static final ImapList EMPTY = new ImapList() {
- @Override public void destroy() {
- // Don't call super.destroy().
- // It's a shared object. We don't want the mDestroyed to be set on this.
- }
-
- @Override void add(ImapElement e) {
- throw new RuntimeException();
- }
- };
-
- private ArrayList<ImapElement> mList = new ArrayList<ImapElement>();
-
- /* package */ void add(ImapElement e) {
- if (e == null) {
- throw new RuntimeException("Can't add null");
- }
- mList.add(e);
- }
-
- @Override
- public final boolean isString() {
- return false;
- }
-
- @Override
- public final boolean isList() {
- return true;
- }
-
- public final int size() {
- return mList.size();
- }
-
- public final boolean isEmpty() {
- return size() == 0;
- }
-
- /**
- * Return true if the element at {@code index} exists, is string, and equals to {@code s}.
- * (case insensitive)
- */
- public final boolean is(int index, String s) {
- return is(index, s, false);
- }
-
- /**
- * Same as {@link #is(int, String)}, but does the prefix match if {@code prefixMatch}.
- */
- public final boolean is(int index, String s, boolean prefixMatch) {
- if (!prefixMatch) {
- return getStringOrEmpty(index).is(s);
- } else {
- return getStringOrEmpty(index).startsWith(s);
- }
- }
-
- /**
- * Return the element at {@code index}.
- * If {@code index} is out of range, returns {@link ImapElement#NONE}.
- */
- public final ImapElement getElementOrNone(int index) {
- return (index >= mList.size()) ? ImapElement.NONE : mList.get(index);
- }
-
- /**
- * Return the element at {@code index} if it's a list.
- * If {@code index} is out of range or not a list, returns {@link ImapList#EMPTY}.
- */
- public final ImapList getListOrEmpty(int index) {
- ImapElement el = getElementOrNone(index);
- return el.isList() ? (ImapList) el : EMPTY;
- }
-
- /**
- * Return the element at {@code index} if it's a string.
- * If {@code index} is out of range or not a string, returns {@link ImapString#EMPTY}.
- */
- public final ImapString getStringOrEmpty(int index) {
- ImapElement el = getElementOrNone(index);
- return el.isString() ? (ImapString) el : ImapString.EMPTY;
- }
-
- /**
- * Return an element keyed by {@code key}. Return null if not found. {@code key} has to be
- * at an even index.
- */
- /* package */ final ImapElement getKeyedElementOrNull(String key, boolean prefixMatch) {
- for (int i = 1; i < size(); i += 2) {
- if (is(i-1, key, prefixMatch)) {
- return mList.get(i);
- }
- }
- return null;
- }
-
- /**
- * Return an {@link ImapList} keyed by {@code key}.
- * Return {@link ImapList#EMPTY} if not found.
- */
- public final ImapList getKeyedListOrEmpty(String key) {
- return getKeyedListOrEmpty(key, false);
- }
-
- /**
- * Return an {@link ImapList} keyed by {@code key}.
- * Return {@link ImapList#EMPTY} if not found.
- */
- public final ImapList getKeyedListOrEmpty(String key, boolean prefixMatch) {
- ImapElement e = getKeyedElementOrNull(key, prefixMatch);
- return (e != null) ? ((ImapList) e) : ImapList.EMPTY;
- }
-
- /**
- * Return an {@link ImapString} keyed by {@code key}.
- * Return {@link ImapString#EMPTY} if not found.
- */
- public final ImapString getKeyedStringOrEmpty(String key) {
- return getKeyedStringOrEmpty(key, false);
- }
-
- /**
- * Return an {@link ImapString} keyed by {@code key}.
- * Return {@link ImapString#EMPTY} if not found.
- */
- public final ImapString getKeyedStringOrEmpty(String key, boolean prefixMatch) {
- ImapElement e = getKeyedElementOrNull(key, prefixMatch);
- return (e != null) ? ((ImapString) e) : ImapString.EMPTY;
- }
-
- /**
- * Return true if it contains {@code s}.
- */
- public final boolean contains(String s) {
- for (int i = 0; i < size(); i++) {
- if (getStringOrEmpty(i).is(s)) {
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void destroy() {
- if (mList != null) {
- for (ImapElement e : mList) {
- e.destroy();
- }
- mList = null;
- }
- super.destroy();
- }
-
- @Override
- public String toString() {
- return mList.toString();
- }
-
- /**
- * Return the text representations of the contents concatenated with ",".
- */
- public final String flatten() {
- return flatten(new StringBuilder()).toString();
- }
-
- /**
- * Returns text representations (i.e. getString()) of contents joined together with
- * "," as the separator.
- *
- * Only used for building the capability string passed to vendor policies.
- *
- * We can't use toString(), because it's for debugging (meaning the format may change any time),
- * and it won't expand literals.
- */
- private final StringBuilder flatten(StringBuilder sb) {
- sb.append('[');
- for (int i = 0; i < mList.size(); i++) {
- if (i > 0) {
- sb.append(',');
- }
- final ImapElement e = getElementOrNone(i);
- if (e.isList()) {
- getListOrEmpty(i).flatten(sb);
- } else if (e.isString()) {
- sb.append(getStringOrEmpty(i).getString());
- }
- }
- sb.append(']');
- return sb;
- }
-
- @Override
- public boolean equalsForTest(ImapElement that) {
- if (!super.equalsForTest(that)) {
- return false;
- }
- ImapList thatList = (ImapList) that;
- if (size() != thatList.size()) {
- return false;
- }
- for (int i = 0; i < size(); i++) {
- if (!mList.get(i).equalsForTest(thatList.getElementOrNone(i))) {
- return false;
- }
- }
- return true;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/imap/ImapMemoryLiteral.java b/src/com/android/phone/common/mail/store/imap/ImapMemoryLiteral.java
deleted file mode 100644
index 4811590..0000000
--- a/src/com/android/phone/common/mail/store/imap/ImapMemoryLiteral.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone.common.mail.store.imap;
-
-import com.android.phone.common.mail.FixedLengthInputStream;
-import com.android.phone.vvm.omtp.VvmLog;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-
-/**
- * Subclass of {@link ImapString} used for literals backed by an in-memory byte array.
- */
-public class ImapMemoryLiteral extends ImapString {
- private final String TAG = "ImapMemoryLiteral";
- private byte[] mData;
-
- /* package */ ImapMemoryLiteral(FixedLengthInputStream in) throws IOException {
- // We could use ByteArrayOutputStream and IOUtils.copy, but it'd perform an unnecessary
- // copy....
- mData = new byte[in.getLength()];
- int pos = 0;
- while (pos < mData.length) {
- int read = in.read(mData, pos, mData.length - pos);
- if (read < 0) {
- break;
- }
- pos += read;
- }
- if (pos != mData.length) {
- VvmLog.w(TAG, "length mismatch");
- }
- }
-
- @Override
- public void destroy() {
- mData = null;
- super.destroy();
- }
-
- @Override
- public String getString() {
- try {
- return new String(mData, "US-ASCII");
- } catch (UnsupportedEncodingException e) {
- VvmLog.e(TAG, "Unsupported encoding: ", e);
- }
- return null;
- }
-
- @Override
- public InputStream getAsStream() {
- return new ByteArrayInputStream(mData);
- }
-
- @Override
- public String toString() {
- return String.format("{%d byte literal(memory)}", mData.length);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/imap/ImapResponse.java b/src/com/android/phone/common/mail/store/imap/ImapResponse.java
deleted file mode 100644
index 4891966..0000000
--- a/src/com/android/phone/common/mail/store/imap/ImapResponse.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store.imap;
-
-/**
- * Class represents an IMAP response.
- */
-public class ImapResponse extends ImapList {
- private final String mTag;
- private final boolean mIsContinuationRequest;
-
- /* package */ ImapResponse(String tag, boolean isContinuationRequest) {
- mTag = tag;
- mIsContinuationRequest = isContinuationRequest;
- }
-
- /* package */ static boolean isStatusResponse(String symbol) {
- return ImapConstants.OK.equalsIgnoreCase(symbol)
- || ImapConstants.NO.equalsIgnoreCase(symbol)
- || ImapConstants.BAD.equalsIgnoreCase(symbol)
- || ImapConstants.PREAUTH.equalsIgnoreCase(symbol)
- || ImapConstants.BYE.equalsIgnoreCase(symbol);
- }
-
- /**
- * @return whether it's a tagged response.
- */
- public boolean isTagged() {
- return mTag != null;
- }
-
- /**
- * @return whether it's a continuation request.
- */
- public boolean isContinuationRequest() {
- return mIsContinuationRequest;
- }
-
- public boolean isStatusResponse() {
- return isStatusResponse(getStringOrEmpty(0).getString());
- }
-
- /**
- * @return whether it's an OK response.
- */
- public boolean isOk() {
- return is(0, ImapConstants.OK);
- }
-
- /**
- * @return whether it's an BAD response.
- */
- public boolean isBad() {
- return is(0, ImapConstants.BAD);
- }
-
- /**
- * @return whether it's an NO response.
- */
- public boolean isNo() {
- return is(0, ImapConstants.NO);
- }
-
- /**
- * @return whether it's an {@code responseType} data response. (i.e. not tagged).
- * @param index where {@code responseType} should appear. e.g. 1 for "FETCH"
- * @param responseType e.g. "FETCH"
- */
- public final boolean isDataResponse(int index, String responseType) {
- return !isTagged() && getStringOrEmpty(index).is(responseType);
- }
-
- /**
- * @return Response code (RFC 3501 7.1) if it's a status response.
- *
- * e.g. "ALERT" for "* OK [ALERT] System shutdown in 10 minutes"
- */
- public ImapString getResponseCodeOrEmpty() {
- if (!isStatusResponse()) {
- return ImapString.EMPTY; // Not a status response.
- }
- return getListOrEmpty(1).getStringOrEmpty(0);
- }
-
- /**
- * @return Alert message it it has ALERT response code.
- *
- * e.g. "System shutdown in 10 minutes" for "* OK [ALERT] System shutdown in 10 minutes"
- */
- public ImapString getAlertTextOrEmpty() {
- if (!getResponseCodeOrEmpty().is(ImapConstants.ALERT)) {
- return ImapString.EMPTY; // Not an ALERT
- }
- // The 3rd element contains all the rest of line.
- return getStringOrEmpty(2);
- }
-
- /**
- * @return Response text in a status response.
- */
- public ImapString getStatusResponseTextOrEmpty() {
- if (!isStatusResponse()) {
- return ImapString.EMPTY;
- }
- return getStringOrEmpty(getElementOrNone(1).isList() ? 2 : 1);
- }
-
- public ImapString getStatusOrEmpty() {
- if (!isStatusResponse()) {
- return ImapString.EMPTY;
- }
- return getStringOrEmpty(0);
- }
-
- @Override
- public String toString() {
- String tag = mTag;
- if (isContinuationRequest()) {
- tag = "+";
- }
- return "#" + tag + "# " + super.toString();
- }
-
- @Override
- public boolean equalsForTest(ImapElement that) {
- if (!super.equalsForTest(that)) {
- return false;
- }
- final ImapResponse thatResponse = (ImapResponse) that;
- if (mTag == null) {
- if (thatResponse.mTag != null) {
- return false;
- }
- } else {
- if (!mTag.equals(thatResponse.mTag)) {
- return false;
- }
- }
- if (mIsContinuationRequest != thatResponse.mIsContinuationRequest) {
- return false;
- }
- return true;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java b/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java
deleted file mode 100644
index 6fc5abe..0000000
--- a/src/com/android/phone/common/mail/store/imap/ImapResponseParser.java
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone.common.mail.store.imap;
-
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.phone.common.mail.FixedLengthInputStream;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.common.mail.PeekableInputStream;
-import com.android.phone.vvm.omtp.VvmLog;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-
-/**
- * IMAP response parser.
- */
-public class ImapResponseParser {
- private static final String TAG = "ImapResponseParser";
-
- /**
- * Literal larger than this will be stored in temp file.
- */
- public static final int LITERAL_KEEP_IN_MEMORY_THRESHOLD = 2 * 1024 * 1024;
-
- /** Input stream */
- private final PeekableInputStream mIn;
-
- private final int mLiteralKeepInMemoryThreshold;
-
- /** StringBuilder used by readUntil() */
- private final StringBuilder mBufferReadUntil = new StringBuilder();
-
- /** StringBuilder used by parseBareString() */
- private final StringBuilder mParseBareString = new StringBuilder();
-
- /**
- * We store all {@link ImapResponse} in it. {@link #destroyResponses()} must be called from
- * time to time to destroy them and clear it.
- */
- private final ArrayList<ImapResponse> mResponsesToDestroy = new ArrayList<ImapResponse>();
-
- /**
- * Exception thrown when we receive BYE. It derives from IOException, so it'll be treated
- * in the same way EOF does.
- */
- public static class ByeException extends IOException {
- public static final String MESSAGE = "Received BYE";
- public ByeException() {
- super(MESSAGE);
- }
- }
-
- /**
- * Public constructor for normal use.
- */
- public ImapResponseParser(InputStream in) {
- this(in, LITERAL_KEEP_IN_MEMORY_THRESHOLD);
- }
-
- /**
- * Constructor for testing to override the literal size threshold.
- */
- /* package for test */ ImapResponseParser(InputStream in, int literalKeepInMemoryThreshold) {
- mIn = new PeekableInputStream(in);
- mLiteralKeepInMemoryThreshold = literalKeepInMemoryThreshold;
- }
-
- private static IOException newEOSException() {
- final String message = "End of stream reached";
- VvmLog.d(TAG, message);
- return new IOException(message);
- }
-
- /**
- * Peek next one byte.
- *
- * Throws IOException() if reaches EOF. As long as logical response lines end with \r\n,
- * we shouldn't see EOF during parsing.
- */
- private int peek() throws IOException {
- final int next = mIn.peek();
- if (next == -1) {
- throw newEOSException();
- }
- return next;
- }
-
- /**
- * Read and return one byte from {@link #mIn}, and put it in {@link #mDiscourseLogger}.
- *
- * Throws IOException() if reaches EOF. As long as logical response lines end with \r\n,
- * we shouldn't see EOF during parsing.
- */
- private int readByte() throws IOException {
- int next = mIn.read();
- if (next == -1) {
- throw newEOSException();
- }
- return next;
- }
-
- /**
- * Destroy all the {@link ImapResponse}s stored in the internal storage and clear it.
- *
- * @see #readResponse()
- */
- public void destroyResponses() {
- for (ImapResponse r : mResponsesToDestroy) {
- r.destroy();
- }
- mResponsesToDestroy.clear();
- }
-
- /**
- * Reads the next response available on the stream and returns an
- * {@link ImapResponse} object that represents it.
- *
- * <p>When this method successfully returns an {@link ImapResponse}, the {@link ImapResponse}
- * is stored in the internal storage. When the {@link ImapResponse} is no longer used
- * {@link #destroyResponses} should be called to destroy all the responses in the array.
- *
- * @param byeExpected is a untagged BYE response expected? If not proper cleanup will be done
- * and {@link ByeException} will be thrown.
- * @return the parsed {@link ImapResponse} object.
- * @exception ByeException when detects BYE and <code>byeExpected</code> is false.
- */
- public ImapResponse readResponse(boolean byeExpected) throws IOException, MessagingException {
- ImapResponse response = null;
- try {
- response = parseResponse();
- } catch (RuntimeException e) {
- // Parser crash -- log network activities.
- onParseError(e);
- throw e;
- } catch (IOException e) {
- // Network error, or received an unexpected char.
- onParseError(e);
- throw e;
- }
-
- // Handle this outside of try-catch. We don't have to dump protocol log when getting BYE.
- if (!byeExpected && response.is(0, ImapConstants.BYE)) {
- Log.w(TAG, ByeException.MESSAGE);
- response.destroy();
- throw new ByeException();
- }
- mResponsesToDestroy.add(response);
- return response;
- }
-
- private void onParseError(Exception e) {
- // Read a few more bytes, so that the log will contain some more context, even if the parser
- // crashes in the middle of a response.
- // This also makes sure the byte in question will be logged, no matter where it crashes.
- // e.g. when parseAtom() peeks and finds at an unexpected char, it throws an exception
- // before actually reading it.
- // However, we don't want to read too much, because then it may get into an email message.
- try {
- for (int i = 0; i < 4; i++) {
- int b = readByte();
- if (b == -1 || b == '\n') {
- break;
- }
- }
- } catch (IOException ignore) {
- }
- VvmLog.w(TAG, "Exception detected: " + e.getMessage());
- }
-
- /**
- * Read next byte from stream and throw it away. If the byte is different from {@code expected}
- * throw {@link MessagingException}.
- */
- /* package for test */ void expect(char expected) throws IOException {
- final int next = readByte();
- if (expected != next) {
- throw new IOException(String.format("Expected %04x (%c) but got %04x (%c)",
- (int) expected, expected, next, (char) next));
- }
- }
-
- /**
- * Read bytes until we find {@code end}, and return all as string.
- * The {@code end} will be read (rather than peeked) and won't be included in the result.
- */
- /* package for test */ String readUntil(char end) throws IOException {
- mBufferReadUntil.setLength(0);
- for (;;) {
- final int ch = readByte();
- if (ch != end) {
- mBufferReadUntil.append((char) ch);
- } else {
- return mBufferReadUntil.toString();
- }
- }
- }
-
- /**
- * Read all bytes until \r\n.
- */
- /* package */ String readUntilEol() throws IOException {
- String ret = readUntil('\r');
- expect('\n'); // TODO Should this really be error?
- return ret;
- }
-
- /**
- * Parse and return the response line.
- */
- private ImapResponse parseResponse() throws IOException, MessagingException {
- // We need to destroy the response if we get an exception.
- // So, we first store the response that's being built in responseToDestroy, until it's
- // completely built, at which point we copy it into responseToReturn and null out
- // responseToDestroyt.
- // If responseToDestroy is not null in finally, we destroy it because that means
- // we got an exception somewhere.
- ImapResponse responseToDestroy = null;
- final ImapResponse responseToReturn;
-
- try {
- final int ch = peek();
- if (ch == '+') { // Continuation request
- readByte(); // skip +
- expect(' ');
- responseToDestroy = new ImapResponse(null, true);
-
- // If it's continuation request, we don't really care what's in it.
- responseToDestroy.add(new ImapSimpleString(readUntilEol()));
-
- // Response has successfully been built. Let's return it.
- responseToReturn = responseToDestroy;
- responseToDestroy = null;
- } else {
- // Status response or response data
- final String tag;
- if (ch == '*') {
- tag = null;
- readByte(); // skip *
- expect(' ');
- } else {
- tag = readUntil(' ');
- }
- responseToDestroy = new ImapResponse(tag, false);
-
- final ImapString firstString = parseBareString();
- responseToDestroy.add(firstString);
-
- // parseBareString won't eat a space after the string, so we need to skip it,
- // if exists.
- // If the next char is not ' ', it should be EOL.
- if (peek() == ' ') {
- readByte(); // skip ' '
-
- if (responseToDestroy.isStatusResponse()) { // It's a status response
-
- // Is there a response code?
- final int next = peek();
- if (next == '[') {
- responseToDestroy.add(parseList('[', ']'));
- if (peek() == ' ') { // Skip following space
- readByte();
- }
- }
-
- String rest = readUntilEol();
- if (!TextUtils.isEmpty(rest)) {
- // The rest is free-form text.
- responseToDestroy.add(new ImapSimpleString(rest));
- }
- } else { // It's a response data.
- parseElements(responseToDestroy, '\0');
- }
- } else {
- expect('\r');
- expect('\n');
- }
-
- // Response has successfully been built. Let's return it.
- responseToReturn = responseToDestroy;
- responseToDestroy = null;
- }
- } finally {
- if (responseToDestroy != null) {
- // We get an exception.
- responseToDestroy.destroy();
- }
- }
-
- return responseToReturn;
- }
-
- private ImapElement parseElement() throws IOException, MessagingException {
- final int next = peek();
- switch (next) {
- case '(':
- return parseList('(', ')');
- case '[':
- return parseList('[', ']');
- case '"':
- readByte(); // Skip "
- return new ImapSimpleString(readUntil('"'));
- case '{':
- return parseLiteral();
- case '\r': // CR
- readByte(); // Consume \r
- expect('\n'); // Should be followed by LF.
- return null;
- case '\n': // LF // There shouldn't be a bare LF, but just in case.
- readByte(); // Consume \n
- return null;
- default:
- return parseBareString();
- }
- }
-
- /**
- * Parses an atom.
- *
- * Special case: If an atom contains '[', everything until the next ']' will be considered
- * a part of the atom.
- * (e.g. "BODY[HEADER.FIELDS ("DATE" ...)]" will become a single ImapString)
- *
- * If the value is "NIL", returns an empty string.
- */
- private ImapString parseBareString() throws IOException, MessagingException {
- mParseBareString.setLength(0);
- for (;;) {
- final int ch = peek();
-
- // TODO Can we clean this up? (This condition is from the old parser.)
- if (ch == '(' || ch == ')' || ch == '{' || ch == ' ' ||
- // ']' is not part of atom (it's in resp-specials)
- ch == ']' ||
- // docs claim that flags are \ atom but atom isn't supposed to
- // contain
- // * and some flags contain *
- // ch == '%' || ch == '*' ||
- ch == '%' ||
- // TODO probably should not allow \ and should recognize
- // it as a flag instead
- // ch == '"' || ch == '\' ||
- ch == '"' || (0x00 <= ch && ch <= 0x1f) || ch == 0x7f) {
- if (mParseBareString.length() == 0) {
- throw new MessagingException("Expected string, none found.");
- }
- String s = mParseBareString.toString();
-
- // NIL will be always converted into the empty string.
- if (ImapConstants.NIL.equalsIgnoreCase(s)) {
- return ImapString.EMPTY;
- }
- return new ImapSimpleString(s);
- } else if (ch == '[') {
- // Eat all until next ']'
- mParseBareString.append((char) readByte());
- mParseBareString.append(readUntil(']'));
- mParseBareString.append(']'); // readUntil won't include the end char.
- } else {
- mParseBareString.append((char) readByte());
- }
- }
- }
-
- private void parseElements(ImapList list, char end)
- throws IOException, MessagingException {
- for (;;) {
- for (;;) {
- final int next = peek();
- if (next == end) {
- return;
- }
- if (next != ' ') {
- break;
- }
- // Skip space
- readByte();
- }
- final ImapElement el = parseElement();
- if (el == null) { // EOL
- return;
- }
- list.add(el);
- }
- }
-
- private ImapList parseList(char opening, char closing)
- throws IOException, MessagingException {
- expect(opening);
- final ImapList list = new ImapList();
- parseElements(list, closing);
- expect(closing);
- return list;
- }
-
- private ImapString parseLiteral() throws IOException, MessagingException {
- expect('{');
- final int size;
- try {
- size = Integer.parseInt(readUntil('}'));
- } catch (NumberFormatException nfe) {
- throw new MessagingException("Invalid length in literal");
- }
- if (size < 0) {
- throw new MessagingException("Invalid negative length in literal");
- }
- expect('\r');
- expect('\n');
- FixedLengthInputStream in = new FixedLengthInputStream(mIn, size);
- if (size > mLiteralKeepInMemoryThreshold) {
- return new ImapTempFileLiteral(in);
- } else {
- return new ImapMemoryLiteral(in);
- }
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/imap/ImapSimpleString.java b/src/com/android/phone/common/mail/store/imap/ImapSimpleString.java
deleted file mode 100644
index 9d65236..0000000
--- a/src/com/android/phone/common/mail/store/imap/ImapSimpleString.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store.imap;
-
-import com.android.phone.vvm.omtp.VvmLog;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-
-/**
- * Subclass of {@link ImapString} used for non literals.
- */
-public class ImapSimpleString extends ImapString {
- private final String TAG = "ImapSimpleString";
- private String mString;
-
- /* package */ ImapSimpleString(String string) {
- mString = (string != null) ? string : "";
- }
-
- @Override
- public void destroy() {
- mString = null;
- super.destroy();
- }
-
- @Override
- public String getString() {
- return mString;
- }
-
- @Override
- public InputStream getAsStream() {
- try {
- return new ByteArrayInputStream(mString.getBytes("US-ASCII"));
- } catch (UnsupportedEncodingException e) {
- VvmLog.e(TAG, "Unsupported encoding: ", e);
- }
- return null;
- }
-
- @Override
- public String toString() {
- // Purposefully not return just mString, in order to prevent using it instead of getString.
- return "\"" + mString + "\"";
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/imap/ImapString.java b/src/com/android/phone/common/mail/store/imap/ImapString.java
deleted file mode 100644
index dd7133c..0000000
--- a/src/com/android/phone/common/mail/store/imap/ImapString.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store.imap;
-
-import com.android.phone.vvm.omtp.VvmLog;
-
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-/**
- * Class represents an IMAP "element" that is not a list.
- *
- * An atom, quoted string, literal, are all represented by this. Values like OK, STATUS are too.
- * Also, this class class may contain more arbitrary value like "BODY[HEADER.FIELDS ("DATE")]".
- * See {@link ImapResponseParser}.
- */
-public abstract class ImapString extends ImapElement {
- private static final byte[] EMPTY_BYTES = new byte[0];
-
- public static final ImapString EMPTY = new ImapString() {
- @Override public void destroy() {
- // Don't call super.destroy().
- // It's a shared object. We don't want the mDestroyed to be set on this.
- }
-
- @Override public String getString() {
- return "";
- }
-
- @Override public InputStream getAsStream() {
- return new ByteArrayInputStream(EMPTY_BYTES);
- }
-
- @Override public String toString() {
- return "";
- }
- };
-
- // This is used only for parsing IMAP's FETCH ENVELOPE command, in which
- // en_US-like date format is used like "01-Jan-2009 11:20:39 -0800", so this should be
- // handled by Locale.US
- private final static SimpleDateFormat DATE_TIME_FORMAT =
- new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss Z", Locale.US);
-
- private boolean mIsInteger;
- private int mParsedInteger;
- private Date mParsedDate;
-
- @Override
- public final boolean isList() {
- return false;
- }
-
- @Override
- public final boolean isString() {
- return true;
- }
-
- /**
- * @return true if and only if the length of the string is larger than 0.
- *
- * Note: IMAP NIL is considered an empty string. See {@link ImapResponseParser
- * #parseBareString}.
- * On the other hand, a quoted/literal string with value NIL (i.e. "NIL" and {3}\r\nNIL) is
- * treated literally.
- */
- public final boolean isEmpty() {
- return getString().length() == 0;
- }
-
- public abstract String getString();
-
- public abstract InputStream getAsStream();
-
- /**
- * @return whether it can be parsed as a number.
- */
- public final boolean isNumber() {
- if (mIsInteger) {
- return true;
- }
- try {
- mParsedInteger = Integer.parseInt(getString());
- mIsInteger = true;
- return true;
- } catch (NumberFormatException e) {
- return false;
- }
- }
-
- /**
- * @return value parsed as a number, or 0 if the string is not a number.
- */
- public final int getNumberOrZero() {
- return getNumber(0);
- }
-
- /**
- * @return value parsed as a number, or {@code defaultValue} if the string is not a number.
- */
- public final int getNumber(int defaultValue) {
- if (!isNumber()) {
- return defaultValue;
- }
- return mParsedInteger;
- }
-
- /**
- * @return whether it can be parsed as a date using {@link #DATE_TIME_FORMAT}.
- */
- public final boolean isDate() {
- if (mParsedDate != null) {
- return true;
- }
- if (isEmpty()) {
- return false;
- }
- try {
- mParsedDate = DATE_TIME_FORMAT.parse(getString());
- return true;
- } catch (ParseException e) {
- VvmLog.w("ImapString", getString() + " can't be parsed as a date.");
- return false;
- }
- }
-
- /**
- * @return value it can be parsed as a {@link Date}, or null otherwise.
- */
- public final Date getDateOrNull() {
- if (!isDate()) {
- return null;
- }
- return mParsedDate;
- }
-
- /**
- * @return whether the value case-insensitively equals to {@code s}.
- */
- public final boolean is(String s) {
- if (s == null) {
- return false;
- }
- return getString().equalsIgnoreCase(s);
- }
-
-
- /**
- * @return whether the value case-insensitively starts with {@code s}.
- */
- public final boolean startsWith(String prefix) {
- if (prefix == null) {
- return false;
- }
- final String me = this.getString();
- if (me.length() < prefix.length()) {
- return false;
- }
- return me.substring(0, prefix.length()).equalsIgnoreCase(prefix);
- }
-
- // To force subclasses to implement it.
- @Override
- public abstract String toString();
-
- @Override
- public final boolean equalsForTest(ImapElement that) {
- if (!super.equalsForTest(that)) {
- return false;
- }
- ImapString thatString = (ImapString) that;
- return getString().equals(thatString.getString());
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/imap/ImapTempFileLiteral.java b/src/com/android/phone/common/mail/store/imap/ImapTempFileLiteral.java
deleted file mode 100644
index 67d5026..0000000
--- a/src/com/android/phone/common/mail/store/imap/ImapTempFileLiteral.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store.imap;
-
-import com.android.phone.common.mail.FixedLengthInputStream;
-import com.android.phone.common.mail.TempDirectory;
-import com.android.phone.common.mail.utils.Utility;
-import com.android.phone.common.mail.utils.LogUtils;
-
-import org.apache.commons.io.IOUtils;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/**
- * Subclass of {@link ImapString} used for literals backed by a temp file.
- */
-public class ImapTempFileLiteral extends ImapString {
- private final String TAG = "ImapTempFileLiteral";
-
- /* package for test */ final File mFile;
-
- /** Size is purely for toString() */
- private final int mSize;
-
- /* package */ ImapTempFileLiteral(FixedLengthInputStream stream) throws IOException {
- mSize = stream.getLength();
- mFile = File.createTempFile("imap", ".tmp", TempDirectory.getTempDirectory());
-
- // Unfortunately, we can't really use deleteOnExit(), because temp filenames are random
- // so it'd simply cause a memory leak.
- // deleteOnExit() simply adds filenames to a static list and the list will never shrink.
- // mFile.deleteOnExit();
- OutputStream out = new FileOutputStream(mFile);
- IOUtils.copy(stream, out);
- out.close();
- }
-
- /**
- * Make sure we delete the temp file.
- *
- * We should always be calling {@link ImapResponse#destroy()}, but it's here as a last resort.
- */
- @Override
- protected void finalize() throws Throwable {
- try {
- destroy();
- } finally {
- super.finalize();
- }
- }
-
- @Override
- public InputStream getAsStream() {
- checkNotDestroyed();
- try {
- return new FileInputStream(mFile);
- } catch (FileNotFoundException e) {
- // It's probably possible if we're low on storage and the system clears the cache dir.
- LogUtils.w(TAG, "ImapTempFileLiteral: Temp file not found");
-
- // Return 0 byte stream as a dummy...
- return new ByteArrayInputStream(new byte[0]);
- }
- }
-
- @Override
- public String getString() {
- checkNotDestroyed();
- try {
- byte[] bytes = IOUtils.toByteArray(getAsStream());
- // Prevent crash from OOM; we've seen this, but only rarely and not reproducibly
- if (bytes.length > ImapResponseParser.LITERAL_KEEP_IN_MEMORY_THRESHOLD) {
- throw new IOException();
- }
- return Utility.fromAscii(bytes);
- } catch (IOException e) {
- LogUtils.w(TAG, "ImapTempFileLiteral: Error while reading temp file", e);
- return "";
- }
- }
-
- @Override
- public void destroy() {
- try {
- if (!isDestroyed() && mFile.exists()) {
- mFile.delete();
- }
- } catch (RuntimeException re) {
- // Just log and ignore.
- LogUtils.w(TAG, "Failed to remove temp file: " + re.getMessage());
- }
- super.destroy();
- }
-
- @Override
- public String toString() {
- return String.format("{%d byte literal(file)}", mSize);
- }
-
- public boolean tempFileExistsForTest() {
- return mFile.exists();
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/store/imap/ImapUtility.java b/src/com/android/phone/common/mail/store/imap/ImapUtility.java
deleted file mode 100644
index 8551d44..0000000
--- a/src/com/android/phone/common/mail/store/imap/ImapUtility.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.store.imap;
-
-import com.android.phone.common.mail.utils.LogUtils;
-
-import java.util.ArrayList;
-
-/**
- * Utility methods for use with IMAP.
- */
-public class ImapUtility {
- public static final String TAG = "ImapUtility";
- /**
- * Apply quoting rules per IMAP RFC,
- * quoted = DQUOTE *QUOTED-CHAR DQUOTE
- * QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
- * quoted-specials = DQUOTE / "\"
- *
- * This is used primarily for IMAP login, but might be useful elsewhere.
- *
- * NOTE: Not very efficient - you may wish to preflight this, or perhaps it should check
- * for trouble chars before calling the replace functions.
- *
- * @param s The string to be quoted.
- * @return A copy of the string, having undergone quoting as described above
- */
- public static String imapQuoted(String s) {
-
- // First, quote any backslashes by replacing \ with \\
- // regex Pattern: \\ (Java string const = \\\\)
- // Substitute: \\\\ (Java string const = \\\\\\\\)
- String result = s.replaceAll("\\\\", "\\\\\\\\");
-
- // Then, quote any double-quotes by replacing " with \"
- // regex Pattern: " (Java string const = \")
- // Substitute: \\" (Java string const = \\\\\")
- result = result.replaceAll("\"", "\\\\\"");
-
- // return string with quotes around it
- return "\"" + result + "\"";
- }
-
- /**
- * Gets all of the values in a sequence set per RFC 3501. Any ranges are expanded into a
- * list of individual numbers. If the set is invalid, an empty array is returned.
- * <pre>
- * sequence-number = nz-number / "*"
- * sequence-range = sequence-number ":" sequence-number
- * sequence-set = (sequence-number / sequence-range) *("," sequence-set)
- * </pre>
- */
- public static String[] getImapSequenceValues(String set) {
- ArrayList<String> list = new ArrayList<String>();
- if (set != null) {
- String[] setItems = set.split(",");
- for (String item : setItems) {
- if (item.indexOf(':') == -1) {
- // simple item
- try {
- Integer.parseInt(item); // Don't need the value; just ensure it's valid
- list.add(item);
- } catch (NumberFormatException e) {
- LogUtils.d(TAG, "Invalid UID value", e);
- }
- } else {
- // range
- for (String rangeItem : getImapRangeValues(item)) {
- list.add(rangeItem);
- }
- }
- }
- }
- String[] stringList = new String[list.size()];
- return list.toArray(stringList);
- }
-
- /**
- * Expand the given number range into a list of individual numbers. If the range is not valid,
- * an empty array is returned.
- * <pre>
- * sequence-number = nz-number / "*"
- * sequence-range = sequence-number ":" sequence-number
- * sequence-set = (sequence-number / sequence-range) *("," sequence-set)
- * </pre>
- */
- public static String[] getImapRangeValues(String range) {
- ArrayList<String> list = new ArrayList<String>();
- try {
- if (range != null) {
- int colonPos = range.indexOf(':');
- if (colonPos > 0) {
- int first = Integer.parseInt(range.substring(0, colonPos));
- int second = Integer.parseInt(range.substring(colonPos + 1));
- if (first < second) {
- for (int i = first; i <= second; i++) {
- list.add(Integer.toString(i));
- }
- } else {
- for (int i = first; i >= second; i--) {
- list.add(Integer.toString(i));
- }
- }
- }
- }
- } catch (NumberFormatException e) {
- LogUtils.d(TAG, "Invalid range value", e);
- }
- String[] stringList = new String[list.size()];
- return list.toArray(stringList);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/utility/CountingOutputStream.java b/src/com/android/phone/common/mail/utility/CountingOutputStream.java
deleted file mode 100644
index f631c3e..0000000
--- a/src/com/android/phone/common/mail/utility/CountingOutputStream.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.utility;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * A simple pass-thru OutputStream that also counts how many bytes are written to it and
- * makes that count available to callers.
- */
-public class CountingOutputStream extends OutputStream {
- private long mCount;
- private final OutputStream mOutputStream;
-
- public CountingOutputStream(OutputStream outputStream) {
- mOutputStream = outputStream;
- }
-
- public long getCount() {
- return mCount;
- }
-
- @Override
- public void write(byte[] buffer, int offset, int count) throws IOException {
- mOutputStream.write(buffer, offset, count);
- mCount += count;
- }
-
- @Override
- public void write(int oneByte) throws IOException {
- mOutputStream.write(oneByte);
- mCount++;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/utility/EOLConvertingOutputStream.java b/src/com/android/phone/common/mail/utility/EOLConvertingOutputStream.java
deleted file mode 100644
index 1d55152..0000000
--- a/src/com/android/phone/common/mail/utility/EOLConvertingOutputStream.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2015 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.common.mail.utility;
-
-import java.io.FilterOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-public class EOLConvertingOutputStream extends FilterOutputStream {
- int lastChar;
-
- public EOLConvertingOutputStream(OutputStream out) {
- super(out);
- }
-
- @Override
- public void write(int oneByte) throws IOException {
- if (oneByte == '\n') {
- if (lastChar != '\r') {
- super.write('\r');
- }
- }
- super.write(oneByte);
- lastChar = oneByte;
- }
-
- @Override
- public void flush() throws IOException {
- if (lastChar == '\r') {
- super.write('\n');
- lastChar = '\n';
- }
- super.flush();
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/utils/LogUtils.java b/src/com/android/phone/common/mail/utils/LogUtils.java
deleted file mode 100644
index 6bd7be6..0000000
--- a/src/com/android/phone/common/mail/utils/LogUtils.java
+++ /dev/null
@@ -1,417 +0,0 @@
-/**
- * Copyright (c) 2015 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.common.mail.utils;
-
-import android.net.Uri;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.phone.vvm.omtp.VvmLog;
-
-import java.util.List;
-import java.util.regex.Pattern;
-
-public class LogUtils {
- public static final String TAG = "Email Log";
-
- // "GMT" + "+" or "-" + 4 digits
- private static final Pattern DATE_CLEANUP_PATTERN_WRONG_TIMEZONE =
- Pattern.compile("GMT([-+]\\d{4})$");
-
- private static final String ACCOUNT_PREFIX = "account:";
-
- /**
- * Priority constant for the println method; use LogUtils.v.
- */
- public static final int VERBOSE = Log.VERBOSE;
-
- /**
- * Priority constant for the println method; use LogUtils.d.
- */
- public static final int DEBUG = Log.DEBUG;
-
- /**
- * Priority constant for the println method; use LogUtils.i.
- */
- public static final int INFO = Log.INFO;
-
- /**
- * Priority constant for the println method; use LogUtils.w.
- */
- public static final int WARN = Log.WARN;
-
- /**
- * Priority constant for the println method; use LogUtils.e.
- */
- public static final int ERROR = Log.ERROR;
-
- /**
- * Used to enable/disable logging that we don't want included in
- * production releases. This should be set to DEBUG for production releases, and VERBOSE for
- * internal builds.
- */
- // STOPSHIP: ship with DEBUG set
- private static final int MAX_ENABLED_LOG_LEVEL = VERBOSE;
-
- private static Boolean sDebugLoggingEnabledForTests = null;
-
- /**
- * Enable debug logging for unit tests.
- */
- @VisibleForTesting
- public static void setDebugLoggingEnabledForTests(boolean enabled) {
- setDebugLoggingEnabledForTestsInternal(enabled);
- }
-
- protected static void setDebugLoggingEnabledForTestsInternal(boolean enabled) {
- sDebugLoggingEnabledForTests = Boolean.valueOf(enabled);
- }
-
- /**
- * Returns true if the build configuration prevents debug logging.
- */
- @VisibleForTesting
- public static boolean buildPreventsDebugLogging() {
- return MAX_ENABLED_LOG_LEVEL > VERBOSE;
- }
-
- /**
- * Returns a boolean indicating whether debug logging is enabled.
- */
- protected static boolean isDebugLoggingEnabled(String tag) {
- if (buildPreventsDebugLogging()) {
- return false;
- }
- if (sDebugLoggingEnabledForTests != null) {
- return sDebugLoggingEnabledForTests.booleanValue();
- }
- return Log.isLoggable(tag, Log.DEBUG) || Log.isLoggable(TAG, Log.DEBUG);
- }
-
- /**
- * Returns a String for the specified content provider uri. This will do
- * sanitation of the uri to remove PII if debug logging is not enabled.
- */
- public static String contentUriToString(final Uri uri) {
- return contentUriToString(TAG, uri);
- }
-
- /**
- * Returns a String for the specified content provider uri. This will do
- * sanitation of the uri to remove PII if debug logging is not enabled.
- */
- public static String contentUriToString(String tag, Uri uri) {
- if (isDebugLoggingEnabled(tag)) {
- // Debug logging has been enabled, so log the uri as is
- return uri.toString();
- } else {
- // Debug logging is not enabled, we want to remove the email address from the uri.
- List<String> pathSegments = uri.getPathSegments();
-
- Uri.Builder builder = new Uri.Builder()
- .scheme(uri.getScheme())
- .authority(uri.getAuthority())
- .query(uri.getQuery())
- .fragment(uri.getFragment());
-
- // This assumes that the first path segment is the account
- final String account = pathSegments.get(0);
-
- builder = builder.appendPath(sanitizeAccountName(account));
- for (int i = 1; i < pathSegments.size(); i++) {
- builder.appendPath(pathSegments.get(i));
- }
- return builder.toString();
- }
- }
-
- /**
- * Sanitizes an account name. If debug logging is not enabled, a sanitized name
- * is returned.
- */
- public static String sanitizeAccountName(String accountName) {
- if (TextUtils.isEmpty(accountName)) {
- return "";
- }
-
- return ACCOUNT_PREFIX + sanitizeName(TAG, accountName);
- }
-
- public static String sanitizeName(final String tag, final String name) {
- if (TextUtils.isEmpty(name)) {
- return "";
- }
-
- if (isDebugLoggingEnabled(tag)) {
- return name;
- }
-
- return String.valueOf(name.hashCode());
- }
-
- /**
- * Checks to see whether or not a log for the specified tag is loggable at the specified level.
- */
- public static boolean isLoggable(String tag, int level) {
- if (MAX_ENABLED_LOG_LEVEL > level) {
- return false;
- }
- return Log.isLoggable(tag, level) || Log.isLoggable(TAG, level);
- }
-
- /**
- * Send a {@link #VERBOSE} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int v(String tag, String format, Object... args) {
- if (isLoggable(tag, VERBOSE)) {
- return VvmLog.v(tag, String.format(format, args));
- }
- return 0;
- }
-
- /**
- * Send a {@link #VERBOSE} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param tr An exception to log
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int v(String tag, Throwable tr, String format, Object... args) {
- if (isLoggable(tag, VERBOSE)) {
- return VvmLog.v(tag, String.format(format, args), tr);
- }
- return 0;
- }
-
- /**
- * Send a {@link #DEBUG} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int d(String tag, String format, Object... args) {
- if (isLoggable(tag, DEBUG)) {
- return VvmLog.d(tag, String.format(format, args));
- }
- return 0;
- }
-
- /**
- * Send a {@link #DEBUG} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param tr An exception to log
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int d(String tag, Throwable tr, String format, Object... args) {
- if (isLoggable(tag, DEBUG)) {
- return VvmLog.d(tag, String.format(format, args), tr);
- }
- return 0;
- }
-
- /**
- * Send a {@link #INFO} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int i(String tag, String format, Object... args) {
- if (isLoggable(tag, INFO)) {
- return VvmLog.i(tag, String.format(format, args));
- }
- return 0;
- }
-
- /**
- * Send a {@link #INFO} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param tr An exception to log
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int i(String tag, Throwable tr, String format, Object... args) {
- if (isLoggable(tag, INFO)) {
- return VvmLog.i(tag, String.format(format, args), tr);
- }
- return 0;
- }
-
- /**
- * Send a {@link #WARN} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int w(String tag, String format, Object... args) {
- if (isLoggable(tag, WARN)) {
- return VvmLog.w(tag, String.format(format, args));
- }
- return 0;
- }
-
- /**
- * Send a {@link #WARN} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param tr An exception to log
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int w(String tag, Throwable tr, String format, Object... args) {
- if (isLoggable(tag, WARN)) {
- return VvmLog.w(tag, String.format(format, args), tr);
- }
- return 0;
- }
-
- /**
- * Send a {@link #ERROR} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int e(String tag, String format, Object... args) {
- if (isLoggable(tag, ERROR)) {
- return VvmLog.e(tag, String.format(format, args));
- }
- return 0;
- }
-
- /**
- * Send a {@link #ERROR} log message.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param tr An exception to log
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int e(String tag, Throwable tr, String format, Object... args) {
- if (isLoggable(tag, ERROR)) {
- return VvmLog.e(tag, String.format(format, args), tr);
- }
- return 0;
- }
-
- /**
- * What a Terrible Failure: Report a condition that should never happen.
- * The error will always be logged at level ASSERT with the call stack.
- * Depending on system configuration, a report may be added to the
- * {@link android.os.DropBoxManager} and/or the process may be terminated
- * immediately with an error dialog.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int wtf(String tag, String format, Object... args) {
- return VvmLog.wtf(tag, String.format(format, args), new Error());
- }
-
- /**
- * What a Terrible Failure: Report a condition that should never happen.
- * The error will always be logged at level ASSERT with the call stack.
- * Depending on system configuration, a report may be added to the
- * {@link android.os.DropBoxManager} and/or the process may be terminated
- * immediately with an error dialog.
- * @param tag Used to identify the source of a log message. It usually identifies
- * the class or activity where the log call occurs.
- * @param tr An exception to log
- * @param format the format string (see {@link java.util.Formatter#format})
- * @param args
- * the list of arguments passed to the formatter. If there are
- * more arguments than required by {@code format},
- * additional arguments are ignored.
- */
- public static int wtf(String tag, Throwable tr, String format, Object... args) {
- return VvmLog.wtf(tag, String.format(format, args), tr);
- }
-
-
- /**
- * Try to make a date MIME(RFC 2822/5322)-compliant.
- *
- * It fixes:
- * - "Thu, 10 Dec 09 15:08:08 GMT-0700" to "Thu, 10 Dec 09 15:08:08 -0700"
- * (4 digit zone value can't be preceded by "GMT")
- * We got a report saying eBay sends a date in this format
- */
- public static String cleanUpMimeDate(String date) {
- if (TextUtils.isEmpty(date)) {
- return date;
- }
- date = DATE_CLEANUP_PATTERN_WRONG_TIMEZONE.matcher(date).replaceFirst("$1");
- return date;
- }
-
-
- public static String byteToHex(int b) {
- return byteToHex(new StringBuilder(), b).toString();
- }
-
- public static StringBuilder byteToHex(StringBuilder sb, int b) {
- b &= 0xFF;
- sb.append("0123456789ABCDEF".charAt(b >> 4));
- sb.append("0123456789ABCDEF".charAt(b & 0xF));
- return sb;
- }
-
-}
\ No newline at end of file
diff --git a/src/com/android/phone/common/mail/utils/Utility.java b/src/com/android/phone/common/mail/utils/Utility.java
deleted file mode 100644
index d71b25e..0000000
--- a/src/com/android/phone/common/mail/utils/Utility.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * Copyright (c) 2015 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.common.mail.utils;
-
-import java.io.ByteArrayInputStream;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-
-/**
- * Simple utility methods used in email functions.
- */
-public class Utility {
- public static final Charset ASCII = Charset.forName("US-ASCII");
-
- public static final String[] EMPTY_STRINGS = new String[0];
-
- /**
- * Returns a concatenated string containing the output of every Object's
- * toString() method, each separated by the given separator character.
- */
- public static String combine(Object[] parts, char separator) {
- if (parts == null) {
- return null;
- }
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < parts.length; i++) {
- sb.append(parts[i].toString());
- if (i < parts.length - 1) {
- sb.append(separator);
- }
- }
- return sb.toString();
- }
-
- /** Converts a String to ASCII bytes */
- public static byte[] toAscii(String s) {
- return encode(ASCII, s);
- }
-
- /** Builds a String from ASCII bytes */
- public static String fromAscii(byte[] b) {
- return decode(ASCII, b);
- }
-
- private static byte[] encode(Charset charset, String s) {
- if (s == null) {
- return null;
- }
- final ByteBuffer buffer = charset.encode(CharBuffer.wrap(s));
- final byte[] bytes = new byte[buffer.limit()];
- buffer.get(bytes);
- return bytes;
- }
-
- private static String decode(Charset charset, byte[] b) {
- if (b == null) {
- return null;
- }
- final CharBuffer cb = charset.decode(ByteBuffer.wrap(b));
- return new String(cb.array(), 0, cb.length());
- }
-
- public static ByteArrayInputStream streamFromAsciiString(String ascii) {
- return new ByteArrayInputStream(toAscii(ascii));
- }
-}
diff --git a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
deleted file mode 100644
index 22fb70e..0000000
--- a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2015 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.settings;
-
-import android.content.Context;
-import android.telecom.PhoneAccountHandle;
-import com.android.phone.R;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
-/**
- * Save whether or not a particular account is enabled in shared to be retrieved later.
- */
-public class VisualVoicemailSettingsUtil {
-
- private static final String IS_ENABLED_KEY = "is_enabled";
-
-
- public static void setEnabled(Context context, PhoneAccountHandle phoneAccount,
- boolean isEnabled) {
- new VisualVoicemailPreferences(context, phoneAccount).edit()
- .putBoolean(IS_ENABLED_KEY, isEnabled)
- .apply();
- OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(context, phoneAccount);
- if (isEnabled) {
- OmtpVvmSourceManager.getInstance(context).addPhoneStateListener(phoneAccount);
- config.startActivation();
- } else {
- OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount);
- config.startDeactivation();
- }
- }
-
- public static boolean isEnabled(Context context,
- PhoneAccountHandle phoneAccount) {
- if (phoneAccount == null) {
- return false;
- }
- if (!context.getResources().getBoolean(R.bool.allow_visual_voicemail)) {
- return false;
- }
-
- VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phoneAccount);
- if (prefs.contains(IS_ENABLED_KEY)) {
- // isEnableByDefault is a bit expensive, so don't use it as default value of
- // getBoolean(). The "false" here should never be actually used.
- return prefs.getBoolean(IS_ENABLED_KEY, false);
- }
- return new OmtpVvmCarrierConfigHelper(context,
- PhoneAccountHandleConverter.toSubId(phoneAccount)).isEnabledByDefault();
- }
-
- /**
- * 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
- * VVM app is installed. If the carrier VVM app is installed the client should give priority to
- * it if the settings are not touched.
- */
- public static boolean isEnabledUserSet(Context context,
- PhoneAccountHandle phoneAccount) {
- if (phoneAccount == null) {
- return false;
- }
- VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phoneAccount);
- return prefs.contains(IS_ENABLED_KEY);
- }
-}
diff --git a/src/com/android/phone/settings/VoicemailChangePinActivity.java b/src/com/android/phone/settings/VoicemailChangePinActivity.java
deleted file mode 100644
index 33da27a..0000000
--- a/src/com/android/phone/settings/VoicemailChangePinActivity.java
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.settings;
-
-import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnDismissListener;
-import android.content.SharedPreferences;
-import android.net.Network;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.preference.PreferenceManager;
-import android.telecom.PhoneAccountHandle;
-import android.text.Editable;
-import android.text.InputFilter;
-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;
-import android.view.inputmethod.EditorInfo;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-import android.widget.Toast;
-import com.android.phone.PhoneUtils;
-import com.android.phone.R;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.OmtpConstants.ChangePinResult;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.imap.ImapHelper;
-import com.android.phone.vvm.omtp.imap.ImapHelper.InitializingException;
-import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback;
-
-/**
- * Dialog to change the voicemail PIN. The TUI (Telephony User Interface) PIN is used when accessing
- * traditional voicemail through phone call. The intent to launch this activity must contain {@link
- * #EXTRA_PHONE_ACCOUNT_HANDLE}
- */
-public class VoicemailChangePinActivity extends Activity implements OnClickListener,
- OnEditorActionListener, TextWatcher {
-
- private static final String TAG = "VmChangePinActivity";
-
- public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle";
-
- private static final String KEY_DEFAULT_OLD_PIN = "default_old_pin";
-
- private static final int MESSAGE_HANDLE_RESULT = 1;
-
- private PhoneAccountHandle mPhoneAccountHandle;
- private OmtpVvmCarrierConfigHelper mConfig;
-
- private int mPinMinLength;
- private int mPinMaxLength;
-
- private State mUiState = State.Initial;
- private String mOldPin;
- private String mFirstPin;
-
- private ProgressDialog mProgressDialog;
-
- private TextView mHeaderText;
- private TextView mHintText;
- private TextView mErrorText;
- private EditText mPinEntry;
- private Button mCancelButton;
- private Button mNextButton;
-
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == MESSAGE_HANDLE_RESULT) {
- mUiState.handleResult(VoicemailChangePinActivity.this, message.arg1);
- }
- }
- };
-
- private enum State {
- /**
- * Empty state to handle initial state transition. Will immediately switch into {@link
- * #VerifyOldPin} if a default PIN has been set by the OMTP client, or {@link #EnterOldPin}
- * if not.
- */
- Initial,
- /**
- * Prompt the user to enter old PIN. The PIN will be verified with the server before
- * proceeding to {@link #EnterNewPin}.
- */
- EnterOldPin {
- @Override
- public void onEnter(VoicemailChangePinActivity activity) {
- activity.setHeader(R.string.change_pin_enter_old_pin_header);
- activity.mHintText.setText(R.string.change_pin_enter_old_pin_hint);
- activity.mNextButton.setText(R.string.change_pin_continue_label);
- activity.mErrorText.setText(null);
- }
-
- @Override
- public void onInputChanged(VoicemailChangePinActivity activity) {
- activity.setNextEnabled(activity.getCurrentPasswordInput().length() > 0);
- }
-
-
- @Override
- public void handleNext(VoicemailChangePinActivity activity) {
- activity.mOldPin = activity.getCurrentPasswordInput();
- activity.verifyOldPin();
- }
-
- @Override
- public void handleResult(VoicemailChangePinActivity activity,
- @ChangePinResult int result) {
- if (result == OmtpConstants.CHANGE_PIN_SUCCESS) {
- activity.updateState(State.EnterNewPin);
- } else {
- CharSequence message = activity.getChangePinResultMessage(result);
- activity.showError(message);
- activity.mPinEntry.setText("");
- }
- }
- },
- /**
- * The default old PIN is found. Show a blank screen while verifying with the server to make
- * sure the PIN is still valid. If the PIN is still valid, proceed to {@link #EnterNewPin}.
- * If not, the user probably changed the PIN through other means, proceed to {@link
- * #EnterOldPin}. If any other issue caused the verifying to fail, show an error and exit.
- */
- VerifyOldPin {
- @Override
- public void onEnter(VoicemailChangePinActivity activity) {
- activity.findViewById(android.R.id.content).setVisibility(View.INVISIBLE);
- activity.verifyOldPin();
- }
-
- @Override
- public void handleResult(VoicemailChangePinActivity activity,
- @ChangePinResult int result) {
- if (result == OmtpConstants.CHANGE_PIN_SUCCESS) {
- activity.updateState(State.EnterNewPin);
- } else if (result == OmtpConstants.CHANGE_PIN_SYSTEM_ERROR) {
- activity.getWindow().setSoftInputMode(
- WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
- activity.showError(activity.getString(R.string.change_pin_system_error),
- new OnDismissListener() {
- @Override
- public void onDismiss(DialogInterface dialog) {
- activity.finish();
- }
- });
- } else {
- VvmLog.e(TAG, "invalid default old PIN: " + activity
- .getChangePinResultMessage(result));
- // If the default old PIN is rejected by the server, the PIN is probably changed
- // through other means, or the generated pin is invalid
- // Wipe the default old PIN so the old PIN input box will be shown to the user
- // on the next time.
- setDefaultOldPIN(activity, activity.mPhoneAccountHandle, null);
- activity.handleOmtpEvent(OmtpEvents.CONFIG_PIN_SET);
- activity.updateState(State.EnterOldPin);
- }
- }
-
- @Override
- public void onLeave(VoicemailChangePinActivity activity) {
- activity.findViewById(android.R.id.content).setVisibility(View.VISIBLE);
- }
- },
- /**
- * Let the user enter the new PIN and validate the format. Only length is enforced, PIN
- * strength check relies on the server. After a valid PIN is entered, proceed to {@link
- * #ConfirmNewPin}
- */
- EnterNewPin {
- @Override
- public void onEnter(VoicemailChangePinActivity activity) {
- activity.mHeaderText.setText(R.string.change_pin_enter_new_pin_header);
- activity.mNextButton.setText(R.string.change_pin_continue_label);
- activity.mHintText.setText(
- activity.getString(R.string.change_pin_enter_new_pin_hint,
- activity.mPinMinLength, activity.mPinMaxLength));
- }
-
- @Override
- public void onInputChanged(VoicemailChangePinActivity activity) {
- String password = activity.getCurrentPasswordInput();
- if (password.length() == 0) {
- activity.setNextEnabled(false);
- return;
- }
- CharSequence error = activity.validatePassword(password);
- if (error != null) {
- activity.mErrorText.setText(error);
- activity.setNextEnabled(false);
- } else {
- activity.mErrorText.setText(null);
- activity.setNextEnabled(true);
- }
- }
-
- @Override
- public void handleNext(VoicemailChangePinActivity activity) {
- CharSequence errorMsg;
- errorMsg = activity.validatePassword(activity.getCurrentPasswordInput());
- if (errorMsg != null) {
- activity.showError(errorMsg);
- return;
- }
- activity.mFirstPin = activity.getCurrentPasswordInput();
- activity.updateState(State.ConfirmNewPin);
- }
- },
- /**
- * Let the user type in the same PIN again to avoid typos. If the PIN matches then perform a
- * PIN change to the server. Finish the activity if succeeded. Return to {@link
- * #EnterOldPin} if the old PIN is rejected, {@link #EnterNewPin} for other failure.
- */
- ConfirmNewPin {
- @Override
- public void onEnter(VoicemailChangePinActivity activity) {
- activity.mHeaderText.setText(R.string.change_pin_confirm_pin_header);
- activity.mHintText.setText(null);
- activity.mNextButton.setText(R.string.change_pin_ok_label);
- }
-
- @Override
- public void onInputChanged(VoicemailChangePinActivity activity) {
- if (activity.getCurrentPasswordInput().length() == 0) {
- activity.setNextEnabled(false);
- return;
- }
- if (activity.getCurrentPasswordInput().equals(activity.mFirstPin)) {
- activity.setNextEnabled(true);
- activity.mErrorText.setText(null);
- } else {
- activity.setNextEnabled(false);
- activity.mErrorText.setText(R.string.change_pin_confirm_pins_dont_match);
- }
- }
-
- @Override
- public void handleResult(VoicemailChangePinActivity activity,
- @ChangePinResult int result) {
- if (result == OmtpConstants.CHANGE_PIN_SUCCESS) {
- // If the PIN change succeeded we no longer know what the old (current) PIN is.
- // Wipe the default old PIN so the old PIN input box will be shown to the user
- // on the next time.
- setDefaultOldPIN(activity, activity.mPhoneAccountHandle, null);
- activity.handleOmtpEvent(OmtpEvents.CONFIG_PIN_SET);
-
- activity.finish();
-
- Toast.makeText(activity, activity.getString(R.string.change_pin_succeeded),
- Toast.LENGTH_SHORT).show();
- } else {
- CharSequence message = activity.getChangePinResultMessage(result);
- VvmLog.i(TAG, "Change PIN failed: " + message);
- activity.showError(message);
- if (result == OmtpConstants.CHANGE_PIN_MISMATCH) {
- // Somehow the PIN has changed, prompt to enter the old PIN again.
- activity.updateState(State.EnterOldPin);
- } else {
- // The new PIN failed to fulfil other restrictions imposed by the server.
- activity.updateState(State.EnterNewPin);
- }
-
- }
-
- }
-
- @Override
- public void handleNext(VoicemailChangePinActivity activity) {
- activity.processPinChange(activity.mOldPin, activity.mFirstPin);
- }
- };
-
- /**
- * The activity has switched from another state to this one.
- */
- public void onEnter(VoicemailChangePinActivity activity) {
- // Do nothing
- }
-
- /**
- * The user has typed something into the PIN input field. Also called after {@link
- * #onEnter(VoicemailChangePinActivity)}
- */
- public void onInputChanged(VoicemailChangePinActivity activity) {
- // Do nothing
- }
-
- /**
- * The asynchronous call to change the PIN on the server has returned.
- */
- public void handleResult(VoicemailChangePinActivity activity, @ChangePinResult int result) {
- // Do nothing
- }
-
- /**
- * The user has pressed the "next" button.
- */
- public void handleNext(VoicemailChangePinActivity activity) {
- // Do nothing
- }
-
- /**
- * The activity has switched from this state to another one.
- */
- public void onLeave(VoicemailChangePinActivity activity) {
- // Do nothing
- }
-
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mPhoneAccountHandle = getIntent().getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE);
- mConfig = new OmtpVvmCarrierConfigHelper(this, mPhoneAccountHandle);
- setContentView(R.layout.voicemail_change_pin);
- setTitle(R.string.change_pin_title);
-
- readPinLength();
-
- View view = findViewById(android.R.id.content);
-
- mCancelButton = (Button) view.findViewById(R.id.cancel_button);
- mCancelButton.setOnClickListener(this);
- mNextButton = (Button) view.findViewById(R.id.next_button);
- mNextButton.setOnClickListener(this);
-
- mPinEntry = (EditText) view.findViewById(R.id.pin_entry);
- mPinEntry.setOnEditorActionListener(this);
- mPinEntry.addTextChangedListener(this);
- if (mPinMaxLength != 0) {
- mPinEntry.setFilters(new InputFilter[]{new LengthFilter(mPinMaxLength)});
- }
-
-
- mHeaderText = (TextView) view.findViewById(R.id.headerText);
- mHintText = (TextView) view.findViewById(R.id.hintText);
- mErrorText = (TextView) view.findViewById(R.id.errorText);
-
- migrateDefaultOldPin();
-
- if (isDefaultOldPinSet(this, mPhoneAccountHandle)) {
- mOldPin = getDefaultOldPin(this, mPhoneAccountHandle);
- updateState(State.VerifyOldPin);
- } else {
- updateState(State.EnterOldPin);
- }
- }
-
- private void handleOmtpEvent(OmtpEvents event) {
- mConfig.handleEvent(getVoicemailStatusEditor(), event);
- }
-
- private VoicemailStatus.Editor getVoicemailStatusEditor() {
- // This activity does not have any automatic retry mechanism, errors should be written right
- // away.
- return VoicemailStatus.edit(this, mPhoneAccountHandle);
- }
-
- /**
- * Extracts the pin length requirement sent by the server with a STATUS SMS.
- */
- private void readPinLength() {
- VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(this,
- mPhoneAccountHandle);
- // The OMTP pin length format is {min}-{max}
- String[] lengths = preferences.getString(OmtpConstants.TUI_PASSWORD_LENGTH, "").split("-");
- if (lengths.length == 2) {
- try {
- mPinMinLength = Integer.parseInt(lengths[0]);
- mPinMaxLength = Integer.parseInt(lengths[1]);
- } catch (NumberFormatException e) {
- mPinMinLength = 0;
- mPinMaxLength = 0;
- }
- } else {
- mPinMinLength = 0;
- mPinMaxLength = 0;
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- updateState(mUiState);
-
- }
-
- public void handleNext() {
- if (mPinEntry.length() == 0) {
- return;
- }
- mUiState.handleNext(this);
- }
-
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.next_button:
- handleNext();
- break;
-
- case R.id.cancel_button:
- finish();
- break;
- }
- }
-
- @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
- || actionId == EditorInfo.IME_ACTION_NEXT) {
- handleNext();
- return true;
- }
- return false;
- }
-
- public void afterTextChanged(Editable s) {
- mUiState.onInputChanged(this);
- }
-
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- // Do nothing
- }
-
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- // Do nothing
- }
-
- /**
- * After replacing the default PIN with a random PIN, call this to store the random PIN. The
- * stored PIN will be automatically entered when the user attempts to change the PIN.
- */
- public static void setDefaultOldPIN(Context context, PhoneAccountHandle phoneAccountHandle,
- String pin) {
- new VisualVoicemailPreferences(context, phoneAccountHandle)
- .edit().putString(KEY_DEFAULT_OLD_PIN, pin).apply();
- }
-
- public static boolean isDefaultOldPinSet(Context context,
- PhoneAccountHandle phoneAccountHandle) {
- return getDefaultOldPin(context, phoneAccountHandle) != null;
- }
-
- private static String getDefaultOldPin(Context context, PhoneAccountHandle phoneAccountHandle) {
- return new VisualVoicemailPreferences(context, phoneAccountHandle)
- .getString(KEY_DEFAULT_OLD_PIN);
- }
-
- /**
- * Storage location has changed mid development. Migrate from the old location to avoid losing
- * tester's default old pin.
- */
- private void migrateDefaultOldPin() {
- String key = "voicemail_pin_dialog_preference_"
- + PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccountHandle)
- + "_default_old_pin";
-
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
- if (preferences.contains(key)) {
- setDefaultOldPIN(this, mPhoneAccountHandle, preferences.getString(key, null));
- preferences.edit().putString(key, null).apply();
- }
- }
-
- private String getCurrentPasswordInput() {
- return mPinEntry.getText().toString();
- }
-
- private void updateState(State state) {
- State previousState = mUiState;
- mUiState = state;
- if (previousState != state) {
- previousState.onLeave(this);
- mPinEntry.setText("");
- mUiState.onEnter(this);
- }
- mUiState.onInputChanged(this);
- }
-
- /**
- * Validates PIN and returns a message to display if PIN fails test.
- *
- * @param password the raw password the user typed in
- * @return error message to show to user or null if password is OK
- */
- private CharSequence validatePassword(String password) {
- if (mPinMinLength == 0 && mPinMaxLength == 0) {
- // Invalid length requirement is sent by the server, just accept anything and let the
- // server decide.
- return null;
- }
-
- if (password.length() < mPinMinLength) {
- return getString(R.string.vm_change_pin_error_too_short);
- }
- return null;
- }
-
- private void setHeader(int text) {
- mHeaderText.setText(text);
- mPinEntry.setContentDescription(mHeaderText.getText());
- }
-
- /**
- * Get the corresponding message for the {@link ChangePinResult}.<code>result</code> must not
- * {@link OmtpConstants#CHANGE_PIN_SUCCESS}
- */
- private CharSequence getChangePinResultMessage(@ChangePinResult int result) {
- switch (result) {
- case OmtpConstants.CHANGE_PIN_TOO_SHORT:
- return getString(R.string.vm_change_pin_error_too_short);
- case OmtpConstants.CHANGE_PIN_TOO_LONG:
- return getString(R.string.vm_change_pin_error_too_long);
- case OmtpConstants.CHANGE_PIN_TOO_WEAK:
- return getString(R.string.vm_change_pin_error_too_weak);
- case OmtpConstants.CHANGE_PIN_INVALID_CHARACTER:
- return getString(R.string.vm_change_pin_error_invalid);
- case OmtpConstants.CHANGE_PIN_MISMATCH:
- return getString(R.string.vm_change_pin_error_mismatch);
- case OmtpConstants.CHANGE_PIN_SYSTEM_ERROR:
- return getString(R.string.vm_change_pin_error_system_error);
- default:
- VvmLog.wtf(TAG, "Unexpected ChangePinResult " + result);
- return null;
- }
- }
-
- private void verifyOldPin() {
- processPinChange(mOldPin, mOldPin);
- }
-
- private void setNextEnabled(boolean enabled) {
- mNextButton.setEnabled(enabled);
- }
-
-
- private void showError(CharSequence message) {
- showError(message, null);
- }
-
- private void showError(CharSequence message, @Nullable OnDismissListener callback) {
- new AlertDialog.Builder(this)
- .setMessage(message)
- .setPositiveButton(android.R.string.ok, null)
- .setOnDismissListener(callback)
- .show();
- }
-
- /**
- * Asynchronous call to change the PIN on the server.
- */
- private void processPinChange(String oldPin, String newPin) {
- mProgressDialog = new ProgressDialog(this);
- mProgressDialog.setCancelable(false);
- mProgressDialog.setMessage(getString(R.string.vm_change_pin_progress_message));
- mProgressDialog.show();
-
- ChangePinNetworkRequestCallback callback = new ChangePinNetworkRequestCallback(oldPin,
- newPin);
- callback.requestNetwork();
- }
-
- private class ChangePinNetworkRequestCallback extends VvmNetworkRequestCallback {
-
- private final String mOldPin;
- private final String mNewPin;
-
- public ChangePinNetworkRequestCallback(String oldPin, String newPin) {
- super(mConfig, mPhoneAccountHandle,
- VoicemailChangePinActivity.this.getVoicemailStatusEditor());
- mOldPin = oldPin;
- mNewPin = newPin;
- }
-
- @Override
- public void onAvailable(Network network) {
- super.onAvailable(network);
- try (ImapHelper helper =
- new ImapHelper(VoicemailChangePinActivity.this, mPhoneAccountHandle, network,
- getVoicemailStatusEditor())) {
-
- @ChangePinResult int result =
- helper.changePin(mOldPin, mNewPin);
- sendResult(result);
- } catch (InitializingException | MessagingException e) {
- VvmLog.e(TAG, "ChangePinNetworkRequestCallback: onAvailable: ", e);
- sendResult(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR);
- }
- }
-
- @Override
- public void onFailed(String reason) {
- super.onFailed(reason);
- sendResult(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR);
- }
-
- private void sendResult(@ChangePinResult int result) {
- VvmLog.i(TAG, "Change PIN result: " + result);
- if (mProgressDialog.isShowing() && !VoicemailChangePinActivity.this.isDestroyed() &&
- !VoicemailChangePinActivity.this.isFinishing()) {
- mProgressDialog.dismiss();
- } else {
- VvmLog.i(TAG, "Dialog not visible, not dismissing");
- }
- mHandler.obtainMessage(MESSAGE_HANDLE_RESULT, result, 0).sendToTarget();
- releaseNetwork();
- }
- }
-
-}
diff --git a/src/com/android/phone/settings/VoicemailNotificationSettingsUtil.java b/src/com/android/phone/settings/VoicemailNotificationSettingsUtil.java
deleted file mode 100644
index 9654ea7..0000000
--- a/src/com/android/phone/settings/VoicemailNotificationSettingsUtil.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone.settings;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.net.Uri;
-import android.preference.PreferenceManager;
-import android.provider.Settings;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-
-import com.android.internal.telephony.Phone;
-import com.android.phone.R;
-
-public class VoicemailNotificationSettingsUtil {
- private static final String VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY_PREFIX =
- "voicemail_notification_ringtone_";
- private static final String VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY_PREFIX =
- "voicemail_notification_vibrate_";
-
- // Old voicemail notification vibration string constants used for migration.
- private static final String OLD_VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY =
- "button_voicemail_notification_ringtone_key";
- private static final String OLD_VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY =
- "button_voicemail_notification_vibrate_key";
- private static final String OLD_VOICEMAIL_VIBRATE_WHEN_SHARED_PREFS_KEY =
- "button_voicemail_notification_vibrate_when_key";
- private static final String OLD_VOICEMAIL_RINGTONE_SHARED_PREFS_KEY =
- "button_voicemail_notification_ringtone_key";
- private static final String OLD_VOICEMAIL_VIBRATION_ALWAYS = "always";
- private static final String OLD_VOICEMAIL_VIBRATION_NEVER = "never";
-
- public static void setVibrationEnabled(Phone phone, boolean isEnabled) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(getVoicemailVibrationSharedPrefsKey(phone), isEnabled);
- editor.commit();
- }
-
- public static boolean isVibrationEnabled(Phone phone) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- migrateVoicemailVibrationSettingsIfNeeded(phone, prefs);
- return prefs.getBoolean(getVoicemailVibrationSharedPrefsKey(phone), false /* defValue */);
- }
-
- public static void setRingtoneUri(Phone phone, Uri ringtoneUri) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- String ringtoneUriStr = ringtoneUri != null ? ringtoneUri.toString() : "";
-
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(getVoicemailRingtoneSharedPrefsKey(phone), ringtoneUriStr);
- editor.commit();
- }
-
- public static Uri getRingtoneUri(Phone phone) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(phone.getContext());
- migrateVoicemailRingtoneSettingsIfNeeded(phone, prefs);
- String uriString = prefs.getString(
- getVoicemailRingtoneSharedPrefsKey(phone),
- Settings.System.DEFAULT_NOTIFICATION_URI.toString());
- return !TextUtils.isEmpty(uriString) ? Uri.parse(uriString) : null;
- }
-
- /**
- * Migrate voicemail settings from {@link #OLD_VIBRATE_WHEN_KEY} or
- * {@link #OLD_VOICEMAIL_NOTIFICATION_VIBRATE_KEY}.
- *
- * TODO: Add helper which migrates settings from old version to new version.
- */
- private static void migrateVoicemailVibrationSettingsIfNeeded(
- Phone phone, SharedPreferences prefs) {
- String key = getVoicemailVibrationSharedPrefsKey(phone);
- TelephonyManager telephonyManager = TelephonyManager.from(phone.getContext());
-
- // Skip if a preference exists, or if phone is MSIM.
- if (prefs.contains(key) || telephonyManager.getPhoneCount() != 1) {
- return;
- }
-
- if (prefs.contains(OLD_VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY)) {
- boolean voicemailVibrate = prefs.getBoolean(
- OLD_VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY, false /* defValue */);
-
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(key, voicemailVibrate)
- .remove(OLD_VOICEMAIL_VIBRATE_WHEN_SHARED_PREFS_KEY)
- .commit();
- }
-
- if (prefs.contains(OLD_VOICEMAIL_VIBRATE_WHEN_SHARED_PREFS_KEY)) {
- // If vibrateWhen is always, then voicemailVibrate should be true.
- // If it is "only in silent mode", or "never", then voicemailVibrate should be false.
- String vibrateWhen = prefs.getString(
- OLD_VOICEMAIL_VIBRATE_WHEN_SHARED_PREFS_KEY, OLD_VOICEMAIL_VIBRATION_NEVER);
- boolean voicemailVibrate = vibrateWhen.equals(OLD_VOICEMAIL_VIBRATION_ALWAYS);
-
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(key, voicemailVibrate)
- .remove(OLD_VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY)
- .commit();
- }
- }
-
- /**
- * Migrate voicemail settings from OLD_VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY.
- *
- * TODO: Add helper which migrates settings from old version to new version.
- */
- private static void migrateVoicemailRingtoneSettingsIfNeeded(
- Phone phone, SharedPreferences prefs) {
- String key = getVoicemailRingtoneSharedPrefsKey(phone);
- TelephonyManager telephonyManager = TelephonyManager.from(phone.getContext());
-
- // Skip if a preference exists, or if phone is MSIM.
- if (prefs.contains(key) || telephonyManager.getPhoneCount() != 1) {
- return;
- }
-
- if (prefs.contains(OLD_VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY)) {
- String uriString = prefs.getString(
- OLD_VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY, null /* defValue */);
-
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(key, uriString)
- .remove(OLD_VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY)
- .commit();
- }
- }
-
- private static String getVoicemailVibrationSharedPrefsKey(Phone phone) {
- return VOICEMAIL_NOTIFICATION_VIBRATION_SHARED_PREFS_KEY_PREFIX + phone.getSubId();
- }
-
- public static String getVoicemailRingtoneSharedPrefsKey(Phone phone) {
- return VOICEMAIL_NOTIFICATION_RINGTONE_SHARED_PREFS_KEY_PREFIX + phone.getSubId();
- }
-}
diff --git a/src/com/android/phone/settings/VoicemailRingtonePreference.java b/src/com/android/phone/settings/VoicemailRingtonePreference.java
deleted file mode 100644
index bb82d4f..0000000
--- a/src/com/android/phone/settings/VoicemailRingtonePreference.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.android.phone.settings;
-
-import android.content.Context;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-import android.preference.Preference;
-import android.preference.RingtonePreference;
-import android.util.AttributeSet;
-
-import com.android.internal.telephony.Phone;
-import com.android.phone.common.util.SettingsUtil;
-
-/**
- * Looks up the voicemail ringtone's name asynchronously and updates the preference's summary when
- * it is created or updated.
- */
-public class VoicemailRingtonePreference extends RingtonePreference {
- public interface VoicemailRingtoneNameChangeListener {
- void onVoicemailRingtoneNameChanged(CharSequence name);
- }
-
- private static final int MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY = 1;
-
- private VoicemailRingtoneNameChangeListener mVoicemailRingtoneNameChangeListener;
- private Runnable mVoicemailRingtoneLookupRunnable;
- private Handler mVoicemailRingtoneLookupComplete;
-
- private Phone mPhone;
-
- public VoicemailRingtonePreference(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mVoicemailRingtoneLookupComplete = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY:
- if (mVoicemailRingtoneNameChangeListener != null) {
- mVoicemailRingtoneNameChangeListener.onVoicemailRingtoneNameChanged(
- (CharSequence) msg.obj);
- }
- setSummary((CharSequence) msg.obj);
- break;
- }
- }
- };
- }
-
- public void init(Phone phone, CharSequence oldRingtoneName) {
- mPhone = phone;
-
- // Requesting the ringtone will trigger migration if necessary.
- VoicemailNotificationSettingsUtil.getRingtoneUri(phone);
-
- final Preference preference = this;
- final String preferenceKey =
- VoicemailNotificationSettingsUtil.getVoicemailRingtoneSharedPrefsKey(mPhone);
- setSummary(oldRingtoneName);
- mVoicemailRingtoneLookupRunnable = new Runnable() {
- @Override
- public void run() {
- SettingsUtil.updateRingtoneName(
- preference.getContext(),
- mVoicemailRingtoneLookupComplete,
- RingtoneManager.TYPE_NOTIFICATION,
- preferenceKey,
- MSG_UPDATE_VOICEMAIL_RINGTONE_SUMMARY);
- }
- };
-
- updateRingtoneName();
- }
-
- public void setVoicemailRingtoneNameChangeListener(VoicemailRingtoneNameChangeListener l) {
- mVoicemailRingtoneNameChangeListener = l;
- }
-
- @Override
- protected Uri onRestoreRingtone() {
- return VoicemailNotificationSettingsUtil.getRingtoneUri(mPhone);
- }
-
- @Override
- protected void onSaveRingtone(Uri ringtoneUri) {
- // Don't call superclass method because it uses the pref key as the SharedPreferences key.
- // Delegate to the voicemail notification utility to save the ringtone instead.
- VoicemailNotificationSettingsUtil.setRingtoneUri(mPhone, ringtoneUri);
-
- updateRingtoneName();
- }
-
- private void updateRingtoneName() {
- new Thread(mVoicemailRingtoneLookupRunnable).start();
- }
-}
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
index ef35f13..04e8bf5 100644
--- a/src/com/android/phone/settings/VoicemailSettingsActivity.java
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -30,7 +30,8 @@
import android.preference.PreferenceScreen;
import android.preference.SwitchPreference;
import android.provider.ContactsContract.CommonDataKinds;
-import android.telecom.PhoneAccountHandle;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
@@ -42,14 +43,12 @@
import com.android.internal.telephony.CallForwardInfo;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.util.NotificationChannelController;
import com.android.phone.EditPhoneNumberPreference;
import com.android.phone.PhoneGlobals;
-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;
@@ -60,8 +59,7 @@
implements DialogInterface.OnClickListener,
Preference.OnPreferenceChangeListener,
EditPhoneNumberPreference.OnDialogClosedListener,
- EditPhoneNumberPreference.GetDefaultNumberListener,
- VoicemailRingtonePreference.VoicemailRingtoneNameChangeListener {
+ EditPhoneNumberPreference.GetDefaultNumberListener{
private static final String LOG_TAG = VoicemailSettingsActivity.class.getSimpleName();
private static final boolean DBG = (PhoneGlobals.DBG_LEVEL >= 2);
@@ -188,8 +186,6 @@
private CallForwardInfo[] mNewFwdSettings;
private String mNewVMNumber;
- private CharSequence mOldVmRingtoneName = "";
-
/**
* Used to indicate that the voicemail preference should be shown.
*/
@@ -197,17 +193,12 @@
private boolean mForeground;
private Phone mPhone;
- private PhoneAccountHandle mPhoneAccountHandle;
private SubscriptionInfoHelper mSubscriptionInfoHelper;
- private OmtpVvmCarrierConfigHelper mOmtpVvmCarrierConfigHelper;
private EditPhoneNumberPreference mSubMenuVoicemailSettings = null;
private VoicemailProviderListPreference mVoicemailProviders;
private PreferenceScreen mVoicemailSettings;
- private VoicemailRingtonePreference mVoicemailNotificationRingtone;
- private SwitchPreference mVoicemailNotificationVibrate;
- private SwitchPreference mVoicemailVisualVoicemail;
- private Preference mVoicemailChangePinPreference;
+ private Preference mVoicemailNotificationPreference;
//*********************************************************************************************
// Preference Activity Methods
@@ -233,10 +224,15 @@
mSubscriptionInfoHelper.setActionBarTitle(
getActionBar(), getResources(), R.string.voicemail_settings_with_label);
mPhone = mSubscriptionInfoHelper.getPhone();
- mPhoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(mPhone);
- mOmtpVvmCarrierConfigHelper = new OmtpVvmCarrierConfigHelper(
- mPhone.getContext(), mPhone.getSubId());
addPreferencesFromResource(R.xml.voicemail_settings);
+
+ mVoicemailNotificationPreference =
+ findPreference(getString(R.string.voicemail_notifications_key));
+ final Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
+ intent.putExtra(Settings.EXTRA_CHANNEL_ID,
+ NotificationChannelController.CHANNEL_ID_VOICE_MAIL);
+ intent.putExtra(Settings.EXTRA_APP_PACKAGE, mPhone.getContext().getPackageName());
+ mVoicemailNotificationPreference.setIntent(intent);
}
@Override
@@ -264,45 +260,8 @@
mVoicemailSettings = (PreferenceScreen) findPreference(BUTTON_VOICEMAIL_SETTING_KEY);
- mVoicemailNotificationRingtone = (VoicemailRingtonePreference) findPreference(
- getResources().getString(R.string.voicemail_notification_ringtone_key));
- mVoicemailNotificationRingtone.setVoicemailRingtoneNameChangeListener(this);
- mVoicemailNotificationRingtone.init(mPhone, mOldVmRingtoneName);
+ maybeHidePublicSettings();
- mVoicemailNotificationVibrate = (SwitchPreference) findPreference(
- getResources().getString(R.string.voicemail_notification_vibrate_key));
- mVoicemailNotificationVibrate.setOnPreferenceChangeListener(this);
-
- mVoicemailVisualVoicemail = (SwitchPreference) prefSet.findPreference(
- getResources().getString(R.string.voicemail_visual_voicemail_key));
-
- mVoicemailChangePinPreference = prefSet.findPreference(
- getResources().getString(R.string.voicemail_change_pin_key));
- if (mVoicemailChangePinPreference != null) {
- Intent changePinIntent = new Intent(new Intent(this, VoicemailChangePinActivity.class));
- changePinIntent.putExtra(VoicemailChangePinActivity.EXTRA_PHONE_ACCOUNT_HANDLE,
- mPhoneAccountHandle);
-
- mVoicemailChangePinPreference.setIntent(changePinIntent);
- if (VoicemailChangePinActivity.isDefaultOldPinSet(this, mPhoneAccountHandle)) {
- mVoicemailChangePinPreference.setTitle(R.string.voicemail_set_pin_dialog_title);
- } else {
- mVoicemailChangePinPreference.setTitle(R.string.voicemail_change_pin_dialog_title);
- }
- }
- if (mVoicemailVisualVoicemail != null) {
- if (mOmtpVvmCarrierConfigHelper.isValid()) {
- mVoicemailVisualVoicemail.setOnPreferenceChangeListener(this);
- mVoicemailVisualVoicemail.setChecked(
- VisualVoicemailSettingsUtil.isEnabled(this, mPhoneAccountHandle));
- if (!isVisualVoicemailActivated()) {
- prefSet.removePreference(mVoicemailChangePinPreference);
- }
- } else {
- prefSet.removePreference(mVoicemailVisualVoicemail);
- prefSet.removePreference(mVoicemailChangePinPreference);
- }
- }
updateVMPreferenceWidgets(mVoicemailProviders.getValue());
// check the intent that started this activity and pop up the voicemail
@@ -324,9 +283,22 @@
updateVoiceNumberField();
mVMProviderSettingsForced = false;
+ }
- mVoicemailNotificationVibrate.setChecked(
- VoicemailNotificationSettingsUtil.isVibrationEnabled(mPhone));
+ /**
+ * Hides a subset of voicemail settings if required by the intent extra. This is used by the
+ * default dialer to show "advanced" voicemail settings from its own custom voicemail settings
+ * UI.
+ */
+ private void maybeHidePublicSettings() {
+ if(!getIntent().getBooleanExtra(TelephonyManager.EXTRA_HIDE_PUBLIC_SETTINGS, false)){
+ return;
+ }
+ if (DBG) {
+ log("maybeHidePublicSettings: settings hidden by EXTRA_HIDE_PUBLIC_SETTINGS");
+ }
+ PreferenceScreen preferenceScreen = getPreferenceScreen();
+ preferenceScreen.removePreference(mVoicemailNotificationPreference);
}
@Override
@@ -422,24 +394,7 @@
mChangingVMorFwdDueToProviderChange = true;
saveVoiceMailAndForwardingNumber(newProviderKey, newProviderSettings);
}
- } else if (preference.getKey().equals(mVoicemailNotificationVibrate.getKey())) {
- // Check key instead of comparing reference because closing the voicemail notification
- // ringtone dialog invokes onResume(), but leaves the old preference screen up,
- // TODO: Revert to checking reference after migrating voicemail to its own activity.
- VoicemailNotificationSettingsUtil.setVibrationEnabled(
- mPhone, Boolean.TRUE.equals(objValue));
- } else if (preference.getKey().equals(mVoicemailVisualVoicemail.getKey())) {
- boolean isEnabled = (boolean) objValue;
- VisualVoicemailSettingsUtil
- .setEnabled(mPhone.getContext(), mPhoneAccountHandle, isEnabled);
- PreferenceScreen prefSet = getPreferenceScreen();
- if (isVisualVoicemailActivated()) {
- prefSet.addPreference(mVoicemailChangePinPreference);
- } else {
- prefSet.removePreference(mVoicemailChangePinPreference);
- }
}
-
// Always let the preference setting proceed.
return true;
}
@@ -571,11 +526,6 @@
super.onActivityResult(requestCode, resultCode, data);
}
- @Override
- public void onVoicemailRingtoneNameChanged(CharSequence name) {
- mOldVmRingtoneName = name;
- }
-
/**
* Simulates user clicking on a passed preference.
* Usually needed when the preference is a dialog preference and we want to invoke
@@ -1044,7 +994,6 @@
mVoicemailProviders.setSummary(getString(R.string.sum_voicemail_choose_provider));
mVoicemailSettings.setEnabled(false);
mVoicemailSettings.setIntent(null);
- mVoicemailNotificationVibrate.setEnabled(false);
} else {
if (DBG) log("updateVMPreferenceWidget: key: " + key + " -> " + provider.toString());
@@ -1052,7 +1001,6 @@
mVoicemailProviders.setSummary(providerName);
mVoicemailSettings.setEnabled(true);
mVoicemailSettings.setIntent(provider.intent);
- mVoicemailNotificationVibrate.setEnabled(true);
}
}
@@ -1177,16 +1125,6 @@
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/CarrierVvmPackageInstalledReceiver.java b/src/com/android/phone/vvm/CarrierVvmPackageInstalledReceiver.java
new file mode 100644
index 0000000..ec0d3f6
--- /dev/null
+++ b/src/com/android/phone/vvm/CarrierVvmPackageInstalledReceiver.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.phone.vvm;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PersistableBundle;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
+import android.telephony.TelephonyManager;
+import android.telephony.VisualVoicemailService;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * Receives {@link Intent#ACTION_PACKAGE_ADDED} for the system dialer to inform it a carrier visual
+ * voicemail app has been installed. ACTION_PACKAGE_ADDED requires the receiver process to be
+ * running so the system dialer cannot receive it itself.
+ *
+ * Carrier VVM apps are usually regular apps, not a
+ * {@link VisualVoicemailService} nor {@link android.service.carrier.CarrierMessagingService} so it
+ * will not take precedence over the system dialer. The system dialer should disable VVM it self
+ * to let the carrier app take over since the installation is an explicit user interaction. Carrier
+ * customer support might also ask the user to switch to their app if they believe there's any
+ * issue in the system dialer so this transition should not require more user interaction.
+ *
+ * @see CarrierConfigManager#KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY
+ */
+public class CarrierVvmPackageInstalledReceiver extends BroadcastReceiver {
+
+ private static final String TAG = "VvmPkgInstalledRcvr";
+
+ /**
+ * Hidden broadcast to the system dialer
+ */
+ private static final String ACTION_CARRIER_VVM_PACKAGE_INSTALLED =
+ "com.android.internal.telephony.CARRIER_VVM_PACKAGE_INSTALLED";
+
+ public void register(Context context) {
+ IntentFilter intentFilter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addDataScheme("package");
+ context.registerReceiver(this, intentFilter);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getData() == null) {
+ return;
+ }
+ String packageName = intent.getData().getSchemeSpecificPart();
+ if (packageName == null) {
+ return;
+ }
+
+ TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
+ String systemDialer = telecomManager.getSystemDialerPackage();
+ TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+ for (PhoneAccountHandle phoneAccountHandle : telecomManager.getCallCapablePhoneAccounts()) {
+ TelephonyManager pinnedTelephonyManager = telephonyManager
+ .createForPhoneAccountHandle(phoneAccountHandle);
+
+ if (pinnedTelephonyManager == null) {
+ VvmLog.e(TAG, "cannot create TelephonyManager from " + phoneAccountHandle);
+ continue;
+ }
+
+ if (!getCarrierVvmPackages(telephonyManager).contains(packageName)) {
+ continue;
+ }
+
+ VvmLog.i(TAG, "Carrier VVM app " + packageName + " installed");
+
+ String vvmPackage = pinnedTelephonyManager.getVisualVoicemailPackageName();
+ if (!TextUtils.equals(vvmPackage, systemDialer)) {
+ // Non system dialer do not need to prioritize carrier vvm app.
+ VvmLog.i(TAG, "non system dialer " + vvmPackage + " ignored");
+ continue;
+ }
+
+ VvmLog.i(TAG, "sending broadcast to " + vvmPackage);
+ Intent broadcast = new Intent(ACTION_CARRIER_VVM_PACKAGE_INSTALLED);
+ broadcast.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+ broadcast.setPackage(vvmPackage);
+ context.sendBroadcast(broadcast);
+ }
+ }
+
+ private static Set<String> getCarrierVvmPackages(TelephonyManager pinnedTelephonyManager) {
+ Set<String> carrierPackages = new ArraySet<>();
+
+ PersistableBundle config = pinnedTelephonyManager.getCarrierConfig();
+ String singlePackage = config
+ .getString(CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING);
+ if (!TextUtils.isEmpty(singlePackage)) {
+ carrierPackages.add(singlePackage);
+ }
+ String[] arrayPackages = config
+ .getStringArray(CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY);
+ if (arrayPackages != null) {
+ Collections.addAll(carrierPackages, arrayPackages);
+ }
+
+ return carrierPackages;
+ }
+}
diff --git a/src/com/android/phone/vvm/omtp/utils/PhoneAccountHandleConverter.java b/src/com/android/phone/vvm/PhoneAccountHandleConverter.java
similarity index 95%
rename from src/com/android/phone/vvm/omtp/utils/PhoneAccountHandleConverter.java
rename to src/com/android/phone/vvm/PhoneAccountHandleConverter.java
index ad4c423..cb05215 100644
--- a/src/com/android/phone/vvm/omtp/utils/PhoneAccountHandleConverter.java
+++ b/src/com/android/phone/vvm/PhoneAccountHandleConverter.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.phone.vvm.omtp.utils;
+package com.android.phone.vvm;
import android.annotation.Nullable;
import android.telecom.PhoneAccountHandle;
@@ -22,7 +22,7 @@
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.phone.PhoneUtils;
-import com.android.phone.vvm.omtp.VvmLog;
+import com.android.phone.vvm.VvmLog;
/**
* Utility to convert between PhoneAccountHandle and subId, which is a common operation in OMTP
diff --git a/src/com/android/phone/vvm/RemoteVvmTaskManager.java b/src/com/android/phone/vvm/RemoteVvmTaskManager.java
index f48fc7e..4fc8c57 100644
--- a/src/com/android/phone/vvm/RemoteVvmTaskManager.java
+++ b/src/com/android/phone/vvm/RemoteVvmTaskManager.java
@@ -40,8 +40,6 @@
import com.android.phone.Assert;
import com.android.phone.R;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
import java.util.ArrayList;
import java.util.LinkedList;
@@ -66,6 +64,11 @@
private static final String ACTION_START_SMS_RECEIVED = "ACTION_START_SMS_RECEIVED";
private static final String ACTION_START_SIM_REMOVED = "ACTION_START_SIM_REMOVED";
+ // TODO(b/35766990): Remove after VisualVoicemailService API is stabilized.
+ private static final String ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT =
+ "com.android.phone.vvm.ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT";
+ private static final String EXTRA_WHAT = "what";
+
// TODO(twyen): track task individually to have time outs.
private int mTaskReferenceCount;
@@ -106,6 +109,11 @@
@Nullable
public static ComponentName getRemotePackage(Context context, int subId) {
+ ComponentName broadcastPackage = getBroadcastPackage(context);
+ if (broadcastPackage != null) {
+ return broadcastPackage;
+ }
+
Intent bindIntent = newBindIntent(context);
TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
@@ -131,14 +139,43 @@
bindIntent.setPackage(packageName);
ResolveInfo info = context.getPackageManager()
.resolveService(bindIntent, PackageManager.MATCH_ALL);
- if (info != null) {
- return info.getComponentInfo().getComponentName();
+ if (info == null) {
+ continue;
}
+ if (info.serviceInfo == null) {
+ VvmLog.w(TAG,
+ "Component " + info.getComponentInfo() + " is not a service, ignoring");
+ continue;
+ }
+ if (!android.Manifest.permission.BIND_VISUAL_VOICEMAIL_SERVICE
+ .equals(info.serviceInfo.permission)) {
+ VvmLog.w(TAG, "package " + info.serviceInfo.packageName
+ + " does not enforce BIND_VISUAL_VOICEMAIL_SERVICE, ignoring");
+ continue;
+ }
+
+ return info.getComponentInfo().getComponentName();
}
return null;
}
+ @Nullable
+ private static ComponentName getBroadcastPackage(Context context) {
+ Intent broadcastIntent = new Intent(ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT);
+ broadcastIntent.setPackage(
+ context.getSystemService(TelecomManager.class).getDefaultDialerPackage());
+ List<ResolveInfo> info = context.getPackageManager()
+ .queryBroadcastReceivers(broadcastIntent, PackageManager.MATCH_ALL);
+ if (info == null) {
+ return null;
+ }
+ if (info.isEmpty()) {
+ return null;
+ }
+ return info.get(0).getComponentInfo().getComponentName();
+ }
+
@Override
public void onCreate() {
Assert.isMainThread();
@@ -261,8 +298,26 @@
}
}
- private void send(ComponentName remotePackage,int what, Bundle extras) {
+ private void send(ComponentName remotePackage, int what, Bundle extras) {
Assert.isMainThread();
+
+ if (getBroadcastPackage(this) != null) {
+ /*
+ * Temporarily use a broadcast to notify dialer VVM events instead of using the
+ * VisualVoicemailService.
+ * b/35766990 The VisualVoicemailService is undergoing API changes. The dialer is in
+ * a different repository so it can not be updated in sync with android SDK. It is also
+ * hard to make a manifest service to work in the intermittent state.
+ */
+ VvmLog.i(TAG, "sending broadcast " + what + " to " + remotePackage);
+ Intent intent = new Intent(ACTION_VISUAL_VOICEMAIL_SERVICE_EVENT);
+ intent.putExtras(extras);
+ intent.putExtra(EXTRA_WHAT, what);
+ intent.setComponent(remotePackage);
+ sendBroadcast(intent);
+ return;
+ }
+
Message message = Message.obtain();
message.what = what;
message.setData(new Bundle(extras));
diff --git a/src/com/android/phone/vvm/omtp/VisualVoicemailPreferences.java b/src/com/android/phone/vvm/VisualVoicemailPreferences.java
similarity index 98%
rename from src/com/android/phone/vvm/omtp/VisualVoicemailPreferences.java
rename to src/com/android/phone/vvm/VisualVoicemailPreferences.java
index be51ea9..b28cea4 100644
--- a/src/com/android/phone/vvm/omtp/VisualVoicemailPreferences.java
+++ b/src/com/android/phone/vvm/VisualVoicemailPreferences.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License
*/
-package com.android.phone.vvm.omtp;
+package com.android.phone.vvm;
import android.annotation.Nullable;
import android.content.Context;
diff --git a/src/com/android/phone/vvm/VisualVoicemailSettingsUtil.java b/src/com/android/phone/vvm/VisualVoicemailSettingsUtil.java
new file mode 100644
index 0000000..8215261
--- /dev/null
+++ b/src/com/android/phone/vvm/VisualVoicemailSettingsUtil.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 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.vvm;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyManager;
+
+/**
+ * Save whether or not a particular account is enabled in shared to be retrieved later.
+ */
+public class VisualVoicemailSettingsUtil {
+
+ private static final String IS_ENABLED_KEY = "is_enabled";
+
+ private static final String DEFAULT_OLD_PIN_KEY = "default_old_pin";
+
+ public static Bundle dump(Context context, PhoneAccountHandle phoneAccountHandle){
+ Bundle result = new Bundle();
+ VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context,
+ phoneAccountHandle);
+ if (prefs.contains(IS_ENABLED_KEY)) {
+ result.putBoolean(TelephonyManager.EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL,
+ prefs.getBoolean(IS_ENABLED_KEY, false));
+ }
+ result.putString(TelephonyManager.EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING,
+ prefs.getString(DEFAULT_OLD_PIN_KEY));
+ return result;
+ }
+}
diff --git a/src/com/android/phone/VisualVoicemailSmsFilterConfig.java b/src/com/android/phone/vvm/VisualVoicemailSmsFilterConfig.java
similarity index 99%
rename from src/com/android/phone/VisualVoicemailSmsFilterConfig.java
rename to src/com/android/phone/vvm/VisualVoicemailSmsFilterConfig.java
index db79e2b..058f18e 100644
--- a/src/com/android/phone/VisualVoicemailSmsFilterConfig.java
+++ b/src/com/android/phone/vvm/VisualVoicemailSmsFilterConfig.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.phone;
+package com.android.phone.vvm;
import android.annotation.Nullable;
import android.content.ComponentName;
diff --git a/src/com/android/phone/vvm/omtp/utils/VvmDumpHandler.java b/src/com/android/phone/vvm/VvmDumpHandler.java
similarity index 63%
rename from src/com/android/phone/vvm/omtp/utils/VvmDumpHandler.java
rename to src/com/android/phone/vvm/VvmDumpHandler.java
index 227cf42..866927e 100644
--- a/src/com/android/phone/vvm/omtp/utils/VvmDumpHandler.java
+++ b/src/com/android/phone/vvm/VvmDumpHandler.java
@@ -1,12 +1,11 @@
-package com.android.phone.vvm.omtp.utils;
+package com.android.phone.vvm;
import android.content.Context;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import android.telephony.TelephonyManager;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VvmLog;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -15,6 +14,7 @@
public static void dump(Context context, FileDescriptor fd, PrintWriter writer,
String[] args) {
+ TelephonyManager telephonyManager = TelephonyManager.from(context);
IndentingPrintWriter indentedWriter = new IndentingPrintWriter(writer, " ");
indentedWriter.println("******* OmtpVvm *******");
indentedWriter.println("======= Configs =======");
@@ -22,8 +22,12 @@
for (PhoneAccountHandle handle : TelecomManager.from(context)
.getCallCapablePhoneAccounts()) {
int subId = PhoneAccountHandleConverter.toSubId(handle);
- OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(context, subId);
- indentedWriter.println(config.toString());
+ indentedWriter.println(
+ "VisualVoicemailPackageName:" + telephonyManager.createForSubscriptionId(subId)
+ .getVisualVoicemailPackageName());
+ indentedWriter.println(
+ "VisualVoicemailSmsFilterSettings(" + subId + "):" + telephonyManager
+ .getActiveVisualVoicemailSmsFilterSettings(subId));
}
indentedWriter.decreaseIndent();
indentedWriter.println("======== Logs =========");
diff --git a/src/com/android/phone/vvm/omtp/VvmLog.java b/src/com/android/phone/vvm/VvmLog.java
similarity index 98%
rename from src/com/android/phone/vvm/omtp/VvmLog.java
rename to src/com/android/phone/vvm/VvmLog.java
index 82d42af..9ee58b3 100644
--- a/src/com/android/phone/vvm/omtp/VvmLog.java
+++ b/src/com/android/phone/vvm/VvmLog.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License
*/
-package com.android.phone.vvm.omtp;
+package com.android.phone.vvm;
import android.util.LocalLog;
import android.util.Log;
diff --git a/src/com/android/phone/vvm/VvmSimStateTracker.java b/src/com/android/phone/vvm/VvmSimStateTracker.java
index 1059f86..c648d9c 100644
--- a/src/com/android/phone/vvm/VvmSimStateTracker.java
+++ b/src/com/android/phone/vvm/VvmSimStateTracker.java
@@ -22,6 +22,7 @@
import android.content.Intent;
import android.os.SystemProperties;
import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
@@ -34,8 +35,6 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.phone.PhoneUtils;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
import java.util.Map;
import java.util.Set;
@@ -123,11 +122,11 @@
case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(
intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))) {
- // onSimRemoved will scan all known accounts with isPhoneAccountActive() to find
+ // checkRemovedSim will scan all known accounts with isPhoneAccountActive() to find
// which SIM is removed.
// ACTION_SIM_STATE_CHANGED only provides subId which cannot be converted to a
// PhoneAccountHandle when the SIM is absent.
- onSimRemoved(context);
+ checkRemovedSim(context);
}
break;
case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
@@ -136,6 +135,7 @@
if (!SubscriptionManager.isValidSubscriptionId(subId)) {
VvmLog.i(TAG, "Received SIM change for invalid subscription id.");
+ checkRemovedSim(context);
return;
}
@@ -173,7 +173,7 @@
RemoteVvmTaskManager.startCellServiceConnected(context, phoneAccountHandle);
}
- private void onSimRemoved(Context context) {
+ private void checkRemovedSim(Context context) {
SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
if (!isBootCompleted()) {
for (PhoneAccountHandle phoneAccountHandle : sPreBootHandles) {
@@ -214,7 +214,19 @@
sPreBootHandles.add(phoneAccountHandle);
return;
}
- if (getTelephonyManager(context, phoneAccountHandle).getServiceState().getState()
+ TelephonyManager telephonyManager = getTelephonyManager(context, phoneAccountHandle);
+ if(telephonyManager == null){
+ int subId = context.getSystemService(TelephonyManager.class).getSubIdForPhoneAccount(
+ context.getSystemService(TelecomManager.class)
+ .getPhoneAccount(phoneAccountHandle));
+ VvmLog.e(TAG, "Cannot create TelephonyManager from " + phoneAccountHandle + ", subId="
+ + subId);
+ // TODO(b/33945549): investigate more why this is happening. The PhoneAccountHandle was
+ // just converted from a valid subId so createForPhoneAccountHandle shouldn't really
+ // return null.
+ return;
+ }
+ if (telephonyManager.getServiceState().getState()
== ServiceState.STATE_IN_SERVICE) {
sendConnected(context, phoneAccountHandle);
sListeners.put(phoneAccountHandle, null);
diff --git a/src/com/android/phone/vvm/VvmSmsReceiver.java b/src/com/android/phone/vvm/VvmSmsReceiver.java
index feaa46b..4bffa97 100644
--- a/src/com/android/phone/vvm/VvmSmsReceiver.java
+++ b/src/com/android/phone/vvm/VvmSmsReceiver.java
@@ -23,10 +23,6 @@
import android.telephony.SubscriptionManager;
import android.telephony.VisualVoicemailSms;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.sms.OmtpMessageReceiver;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
/**
* Receives the SMS filtered by {@link com.android.internal.telephony.VisualVoicemailSmsFilter} and
* redirect it to the visual voicemail client. The redirection is required to let telephony service
@@ -56,10 +52,8 @@
if (RemoteVvmTaskManager.hasRemoteService(context, subId)) {
VvmLog.i(TAG, "Sending SMS received event to remote service");
RemoteVvmTaskManager.startSmsReceived(context, sms);
- return;
- }
-
- OmtpMessageReceiver
- .onReceive(context, sms);
+ } else {
+ VvmLog.w(TAG, "Sending SMS received event to remote service");
+ };
}
}
diff --git a/src/com/android/phone/vvm/omtp/ActivationTask.java b/src/com/android/phone/vvm/omtp/ActivationTask.java
deleted file mode 100644
index 6fd42fd..0000000
--- a/src/com/android/phone/vvm/omtp/ActivationTask.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp;
-
-import android.annotation.Nullable;
-import android.annotation.WorkerThread;
-import android.content.Context;
-import android.content.Intent;
-import android.database.ContentObserver;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.provider.Settings.Global;
-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;
-import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocol;
-import com.android.phone.vvm.omtp.scheduling.BaseTask;
-import com.android.phone.vvm.omtp.scheduling.RetryPolicy;
-import com.android.phone.vvm.omtp.sms.StatusMessage;
-import com.android.phone.vvm.omtp.sms.StatusSmsFetcher;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
-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;
-
-/**
- * Task to activate the visual voicemail service. A request to activate VVM will be sent to the
- * carrier, which will respond with a STATUS SMS. The credentials will be updated from the SMS. If
- * the user is not provisioned provisioning will be attempted. Activation happens when the phone
- * boots, the SIM is inserted, signal returned when VVM is not activated yet, and when the carrier
- * spontaneously sent a STATUS SMS.
- */
-public class ActivationTask extends BaseTask {
-
- private static final String TAG = "VvmActivationTask";
-
- private static final int RETRY_TIMES = 4;
- private static final int RETRY_INTERVAL_MILLIS = 5_000;
-
- private static final String EXTRA_MESSAGE_DATA_BUNDLE = "extra_message_data_bundle";
-
- @Nullable
- private static DeviceProvisionedObserver sDeviceProvisionedObserver;
-
- private final RetryPolicy mRetryPolicy;
-
- private Bundle mMessageData;
-
- public ActivationTask() {
- super(TASK_ACTIVATION);
- mRetryPolicy = new RetryPolicy(RETRY_TIMES, RETRY_INTERVAL_MILLIS);
- addPolicy(mRetryPolicy);
- }
-
- /**
- * Has the user gone through the setup wizard yet.
- */
- private static boolean isDeviceProvisioned(Context context) {
- return Settings.Global.getInt(
- context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) == 1;
- }
-
- /**
- * @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
- // the setup wizard is finished. The data bundle from the SMS will be re-requested upon
- // activation.
- queueActivationAfterProvisioned(context, subId);
- return;
- }
-
- Intent intent = BaseTask.createIntent(context, ActivationTask.class, subId);
- 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);
- mMessageData = intent.getParcelableExtra(EXTRA_MESSAGE_DATA_BUNDLE);
- }
-
- @Override
- public Intent createRestartIntent() {
- Intent intent = super.createRestartIntent();
- // mMessageData is discarded, request a fresh STATUS SMS for retries.
- return intent;
- }
-
- @Override
- @WorkerThread
- public void onExecuteInBackgroundThread() {
- Assert.isNotMainThread();
- int subId = getSubId();
-
- PhoneAccountHandle phoneAccountHandle = PhoneAccountHandleConverter.fromSubId(subId);
- if (phoneAccountHandle == null) {
- // This should never happen
- VvmLog.e(TAG, "null phone account for subId " + subId);
- return;
- }
-
- OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(getContext(), subId);
- if (!helper.isValid()) {
- VvmLog.i(TAG, "VVM not supported on subId " + subId);
- OmtpVvmSourceManager.getInstance(getContext()).removeSource(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) {
- // Only show the "activating" message if activation has not been completed before.
- // Subsequent activations are more of a status check and usually does not
- // concern the user.
- helper.handleEvent(VoicemailStatus.edit(getContext(), phoneAccountHandle),
- OmtpEvents.CONFIG_ACTIVATING);
- } 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.
- 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();
-
- VisualVoicemailProtocol protocol = helper.getProtocol();
-
- Bundle data;
- if (mMessageData != null) {
- // The content of STATUS SMS is provided to launch this task, no need to request it
- // again.
- data = mMessageData;
- } else {
- try (StatusSmsFetcher fetcher = new StatusSmsFetcher(getContext(), subId)) {
- 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.
- data = fetcher.get();
- } catch (TimeoutException e) {
- // The carrier is expected to return an STATUS SMS within STATUS_SMS_TIMEOUT_MILLIS
- // handleEvent() will do the logging.
- 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();
- return;
- }
- }
-
- StatusMessage message = new StatusMessage(data);
- VvmLog.d(TAG, "STATUS SMS received: st=" + message.getProvisioningStatus()
- + ", rc=" + message.getReturnCode());
-
- if (message.getProvisioningStatus().equals(OmtpConstants.SUBSCRIBER_READY)) {
- VvmLog.d(TAG, "subscriber ready, no activation required");
- updateSource(getContext(), phoneAccountHandle, getSubId(), status, message);
- } else {
- if (helper.supportsProvisioning()) {
- VvmLog.i(TAG, "Subscriber not ready, start provisioning");
- helper.startProvisioning(this, phoneAccountHandle, status, message, data);
-
- } else if (message.getProvisioningStatus().equals(OmtpConstants.SUBSCRIBER_NEW)) {
- VvmLog.i(TAG, "Subscriber new but provisioning is not supported");
- // Ignore the non-ready state and attempt to use the provided info as is.
- // This is probably caused by not completing the new user tutorial.
- updateSource(getContext(), phoneAccountHandle, getSubId(), status, message);
- } 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);
- }
- }
- }
-
- public static void updateSource(Context context, PhoneAccountHandle phone, int subId,
- VoicemailStatus.Editor status, StatusMessage message) {
- OmtpVvmSourceManager vvmSourceManager =
- OmtpVvmSourceManager.getInstance(context);
-
- if (OmtpConstants.SUCCESS.equals(message.getReturnCode())) {
- OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, subId);
- helper.handleEvent(status, OmtpEvents.CONFIG_REQUEST_STATUS_SUCCESS);
-
- // Save the IMAP credentials in preferences so they are persistent and can be retrieved.
- VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phone);
- message.putStatus(prefs.edit()).apply();
-
- // Add the source to indicate that it is active.
- vvmSourceManager.addSource(phone);
-
- SyncTask.start(context, phone, OmtpVvmSyncService.SYNC_FULL_SYNC);
- // 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);
- context.getContentResolver()
- .registerContentObserver(Settings.Global.getUriFor(Global.DEVICE_PROVISIONED),
- false, sDeviceProvisionedObserver);
- }
- sDeviceProvisionedObserver.addSubId(subId);
- }
-
- private static class DeviceProvisionedObserver extends ContentObserver {
-
- private final Context mContext;
- private final Set<Integer> mSubIds = new HashSet<>();
-
- private DeviceProvisionedObserver(Context context) {
- super(null);
- mContext = context;
- }
-
- public void addSubId(int subId) {
- mSubIds.add(subId);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- if (isDeviceProvisioned(mContext)) {
- VvmLog.i(TAG, "device provisioned, resuming activation");
- for (int subId : mSubIds) {
- start(mContext, subId, null);
- }
- mContext.getContentResolver().unregisterContentObserver(sDeviceProvisionedObserver);
- sDeviceProvisionedObserver = null;
- }
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java b/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
deleted file mode 100644
index 0c19a6a..0000000
--- a/src/com/android/phone/vvm/omtp/DefaultOmtpEventHandler.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp;
-
-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;
-
-public class DefaultOmtpEventHandler {
-
- private static final String TAG = "DefErrorCodeHandler";
-
- public static void handleEvent(Context context, OmtpVvmCarrierConfigHelper config,
- VoicemailStatus.Editor status, OmtpEvents event) {
- switch (event.getType()) {
- case Type.CONFIGURATION:
- handleConfigurationEvent(context, status, event);
- break;
- case Type.DATA_CHANNEL:
- handleDataChannelEvent(context, status, event);
- break;
- case Type.NOTIFICATION_CHANNEL:
- handleNotificationChannelEvent(context, config, status, event);
- break;
- case Type.OTHER:
- handleOtherEvent(context, status, event);
- break;
- default:
- VvmLog.wtf(TAG, "invalid event type " + event.getType() + " for " + event);
- }
- }
-
- 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
- .setConfigurationState(VoicemailContract.Status.CONFIGURATION_STATE_OK)
- .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK)
- .apply();
- break;
- case CONFIG_ACTIVATING:
- // Wipe all errors from the last activation. All errors shown should be new errors
- // for this activation.
- status
- .setConfigurationState(Status.CONFIGURATION_STATE_CONFIGURING)
- .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
- .setConfigurationState(Status.CONFIGURATION_STATE_FAILED)
- .apply();
- break;
- case CONFIG_STATUS_SMS_TIME_OUT:
- status
- .setConfigurationState(Status.CONFIGURATION_STATE_FAILED)
- .apply();
- break;
- default:
- VvmLog.wtf(TAG, "invalid configuration event " + event);
- }
- }
-
- private static void handleDataChannelEvent(Context context, VoicemailStatus.Editor status,
- OmtpEvents event) {
- switch (event) {
- case DATA_IMAP_OPERATION_STARTED:
- case DATA_IMAP_OPERATION_COMPLETED:
- status
- .setDataChannelState(Status.DATA_CHANNEL_STATE_OK)
- .apply();
- break;
-
- case DATA_NO_CONNECTION:
- status
- .setDataChannelState(Status.DATA_CHANNEL_STATE_NO_CONNECTION)
- .apply();
- break;
-
- case DATA_NO_CONNECTION_CELLULAR_REQUIRED:
- status
- .setDataChannelState(
- Status.DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED)
- .apply();
- break;
- case DATA_INVALID_PORT:
- status
- .setDataChannelState(
- VoicemailContract.Status.DATA_CHANNEL_STATE_BAD_CONFIGURATION)
- .apply();
- break;
- case DATA_CANNOT_RESOLVE_HOST_ON_NETWORK:
- status
- .setDataChannelState(
- VoicemailContract.Status.DATA_CHANNEL_STATE_SERVER_CONNECTION_ERROR)
- .apply();
- break;
- 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)
- .apply();
- break;
- case DATA_BAD_IMAP_CREDENTIAL:
- case DATA_AUTH_UNKNOWN_USER:
- case DATA_AUTH_UNKNOWN_DEVICE:
- case DATA_AUTH_INVALID_PASSWORD:
- case DATA_AUTH_MAILBOX_NOT_INITIALIZED:
- case DATA_AUTH_SERVICE_NOT_PROVISIONED:
- case DATA_AUTH_SERVICE_NOT_ACTIVATED:
- case DATA_AUTH_USER_IS_BLOCKED:
- status
- .setDataChannelState(
- VoicemailContract.Status.DATA_CHANNEL_STATE_BAD_CONFIGURATION)
- .apply();
- break;
-
- 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
- .setDataChannelState(
- VoicemailContract.Status.DATA_CHANNEL_STATE_SERVER_ERROR)
- .apply();
- break;
-
- default:
- VvmLog.wtf(TAG, "invalid data channel event " + event);
- }
- }
-
- private static void handleNotificationChannelEvent(Context context,
- OmtpVvmCarrierConfigHelper config, VoicemailStatus.Editor status, OmtpEvents event) {
- switch (event) {
- case NOTIFICATION_IN_SERVICE:
- status
- .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK)
- // Clear the error state. A sync should follow signal return so any error
- // will be reposted.
- .setDataChannelState(Status.DATA_CHANNEL_STATE_OK)
- .apply();
- break;
- case NOTIFICATION_SERVICE_LOST:
- status.setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION);
- if (config.isCellularDataRequired()) {
- status.setDataChannelState(
- Status.DATA_CHANNEL_STATE_NO_CONNECTION_CELLULAR_REQUIRED);
- }
- status.apply();
- break;
- default:
- VvmLog.wtf(TAG, "invalid notification channel event " + event);
- }
- }
-
- private static void handleOtherEvent(Context context, VoicemailStatus.Editor status,
- OmtpEvents event) {
- switch (event) {
- case OTHER_SOURCE_REMOVED:
- status
- .setConfigurationState(Status.CONFIGURATION_STATE_NOT_CONFIGURED)
- .setNotificationChannelState(
- Status.NOTIFICATION_CHANNEL_STATE_NO_CONNECTION)
- .setDataChannelState(Status.DATA_CHANNEL_STATE_NO_CONNECTION)
- .apply();
- break;
- default:
- VvmLog.wtf(TAG, "invalid other event " + event);
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/OmtpConstants.java b/src/com/android/phone/vvm/omtp/OmtpConstants.java
deleted file mode 100644
index 3f5722f..0000000
--- a/src/com/android/phone/vvm/omtp/OmtpConstants.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Wrapper class to hold relevant OMTP constants as defined in the OMTP spec. <p> In essence this is
- * a programmatic representation of the relevant portions of OMTP spec.
- */
-public class OmtpConstants {
- public static final String SMS_FIELD_SEPARATOR = ";";
- public static final String SMS_KEY_VALUE_SEPARATOR = "=";
- public static final String SMS_PREFIX_SEPARATOR = ":";
-
- public static final String SYNC_SMS_PREFIX = "SYNC";
- public static final String STATUS_SMS_PREFIX = "STATUS";
-
- // This is the format designated by the OMTP spec.
- public static final String DATE_TIME_FORMAT = "dd/MM/yyyy HH:mm Z";
-
- /** OMTP protocol versions. */
- public static final String PROTOCOL_VERSION1_1 = "11";
- public static final String PROTOCOL_VERSION1_2 = "12";
- public static final String PROTOCOL_VERSION1_3 = "13";
-
- ///////////////////////// Client/Mobile originated SMS //////////////////////
-
- /** Mobile Originated requests */
- public static final String ACTIVATE_REQUEST = "Activate";
- public static final String DEACTIVATE_REQUEST = "Deactivate";
- public static final String STATUS_REQUEST = "Status";
-
- /** fields that can be present in a Mobile Originated OMTP SMS */
- public static final String CLIENT_TYPE = "ct";
- public static final String APPLICATION_PORT = "pt";
- public static final String PROTOCOL_VERSION = "pv";
-
-
- //////////////////////////////// Sync SMS fields ////////////////////////////
-
- /**
- * Sync SMS fields.
- * <p>
- * Each string constant is the field's key in the SMS body which is used by the parser to
- * identify the field's value, if present, in the SMS body.
- */
-
- /**
- * The event that triggered this SYNC SMS.
- * See {@link OmtpConstants#SYNC_TRIGGER_EVENT_VALUES}
- */
- public static final String SYNC_TRIGGER_EVENT = "ev";
- public static final String MESSAGE_UID = "id";
- public static final String MESSAGE_LENGTH = "l";
- public static final String NUM_MESSAGE_COUNT = "c";
- /** See {@link OmtpConstants#CONTENT_TYPE_VALUES} */
- public static final String CONTENT_TYPE = "t";
- public static final String SENDER = "s";
- public static final String TIME = "dt";
-
- /**
- * SYNC message trigger events.
- * <p>
- * These are the possible values of {@link OmtpConstants#SYNC_TRIGGER_EVENT}.
- */
- public static final String NEW_MESSAGE = "NM";
- public static final String MAILBOX_UPDATE = "MBU";
- public static final String GREETINGS_UPDATE = "GU";
-
- public static final String[] SYNC_TRIGGER_EVENT_VALUES = {
- NEW_MESSAGE,
- MAILBOX_UPDATE,
- GREETINGS_UPDATE
- };
-
- /**
- * Content types supported by OMTP VVM.
- * <p>
- * These are the possible values of {@link OmtpConstants#CONTENT_TYPE}.
- */
- public static final String VOICE = "v";
- public static final String VIDEO = "o";
- public static final String FAX = "f";
- /** Voice message deposited by an external application */
- public static final String INFOTAINMENT = "i";
- /** Empty Call Capture - i.e. voicemail with no voice message. */
- public static final String ECC = "e";
-
- public static final String[] CONTENT_TYPE_VALUES = {VOICE, VIDEO, FAX, INFOTAINMENT, ECC};
-
- ////////////////////////////// Status SMS fields ////////////////////////////
-
- /**
- * Status SMS fields.
- * <p>
- * Each string constant is the field's key in the SMS body which is used by the parser to
- * identify the field's value, if present, in the SMS body.
- */
- /** See {@link OmtpConstants#PROVISIONING_STATUS_VALUES} */
- public static final String PROVISIONING_STATUS = "st";
- /** See {@link OmtpConstants#RETURN_CODE_VALUES} */
- public static final String RETURN_CODE = "rc";
- /** URL to send users to for activation VVM */
- public static final String SUBSCRIPTION_URL = "rs";
- /** IMAP4/SMTP server IP address or fully qualified domain name */
- public static final String SERVER_ADDRESS = "srv";
- /** Phone number to access voicemails through Telephony User Interface */
- public static final String TUI_ACCESS_NUMBER = "tui";
- public static final String TUI_PASSWORD_LENGTH = "pw_len";
- /** Number to send client origination SMS */
- public static final String CLIENT_SMS_DESTINATION_NUMBER = "dn";
- public static final String IMAP_PORT = "ipt";
- public static final String IMAP_USER_NAME = "u";
- public static final String IMAP_PASSWORD = "pw";
- public static final String SMTP_PORT = "spt";
- public static final String SMTP_USER_NAME = "smtp_u";
- public static final String SMTP_PASSWORD = "smtp_pw";
-
- /**
- * User provisioning status values.
- * <p>
- * Referred by {@link OmtpConstants#PROVISIONING_STATUS}.
- */
- public static final String SUBSCRIBER_NEW = "N";
- public static final String SUBSCRIBER_READY = "R";
- public static final String SUBSCRIBER_PROVISIONED = "P";
- public static final String SUBSCRIBER_UNKNOWN = "U";
- public static final String SUBSCRIBER_BLOCKED = "B";
-
- public static final String[] PROVISIONING_STATUS_VALUES = {
- SUBSCRIBER_NEW,
- SUBSCRIBER_READY,
- SUBSCRIBER_PROVISIONED,
- SUBSCRIBER_UNKNOWN,
- SUBSCRIBER_BLOCKED
- };
-
- /**
- * The return code included in a status message.
- * <p>
- * These are the possible values of {@link OmtpConstants#RETURN_CODE}.
- */
- public static final String SUCCESS = "0";
- public static final String SYSTEM_ERROR = "1";
- public static final String SUBSCRIBER_ERROR = "2";
- public static final String MAILBOX_UNKNOWN = "3";
- public static final String VVM_NOT_ACTIVATED = "4";
- public static final String VVM_NOT_PROVISIONED = "5";
- public static final String VVM_CLIENT_UKNOWN = "6";
- public static final String VVM_MAILBOX_NOT_INITIALIZED = "7";
-
- public static final String[] RETURN_CODE_VALUES = {
- SUCCESS,
- SYSTEM_ERROR,
- SUBSCRIBER_ERROR,
- MAILBOX_UNKNOWN,
- VVM_NOT_ACTIVATED,
- VVM_NOT_PROVISIONED,
- VVM_CLIENT_UKNOWN,
- VVM_MAILBOX_NOT_INITIALIZED,
- };
-
- /**
- * A map of all the field keys to the possible values they can have.
- */
- public static final Map<String, String[]> possibleValuesMap = new HashMap<String, String[]>() {{
- put(SYNC_TRIGGER_EVENT, SYNC_TRIGGER_EVENT_VALUES);
- put(CONTENT_TYPE, CONTENT_TYPE_VALUES);
- put(PROVISIONING_STATUS, PROVISIONING_STATUS_VALUES);
- put(RETURN_CODE, RETURN_CODE_VALUES);
- }};
-
- /**
- * IMAP command extensions
- */
-
- /**
- * OMTP spec v1.3 2.3.1 Change password request syntax
- *
- * This changes the PIN to access the Telephone User Interface, the traditional voicemail
- * system.
- */
- public static final String IMAP_CHANGE_TUI_PWD_FORMAT = "XCHANGE_TUI_PWD PWD=%1$s OLD_PWD=%2$s";
-
- /**
- * OMTP spec v1.3 2.4.1 Change languate request syntax
- *
- * This changes the language in the Telephone User Interface.
- */
- public static final String IMAP_CHANGE_VM_LANG_FORMAT = "XCHANGE_VM_LANG LANG=%1$s";
-
- /**
- * OMTP spec v1.3 2.5.1 Close NUT Request syntax
- *
- * This disables the new user tutorial, the message played to new users calling in the Telephone
- * User Interface.
- */
- public static final String IMAP_CLOSE_NUT = "XCLOSE_NUT";
-
- /**
- * Possible NO responses for CHANGE_TUI_PWD
- */
-
- public static final String RESPONSE_CHANGE_PIN_TOO_SHORT = "password too short";
- public static final String RESPONSE_CHANGE_PIN_TOO_LONG = "password too long";
- public static final String RESPONSE_CHANGE_PIN_TOO_WEAK = "password too weak";
- public static final String RESPONSE_CHANGE_PIN_MISMATCH = "old password mismatch";
- public static final String RESPONSE_CHANGE_PIN_INVALID_CHARACTER =
- "password contains invalid characters";
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {CHANGE_PIN_SUCCESS, CHANGE_PIN_TOO_SHORT, CHANGE_PIN_TOO_LONG,
- CHANGE_PIN_TOO_WEAK, CHANGE_PIN_MISMATCH, CHANGE_PIN_INVALID_CHARACTER,
- CHANGE_PIN_SYSTEM_ERROR})
-
- public @interface ChangePinResult {
-
- }
-
- public static final int CHANGE_PIN_SUCCESS = 0;
- public static final int CHANGE_PIN_TOO_SHORT = 1;
- public static final int CHANGE_PIN_TOO_LONG = 2;
- public static final int CHANGE_PIN_TOO_WEAK = 3;
- public static final int CHANGE_PIN_MISMATCH = 4;
- public static final int CHANGE_PIN_INVALID_CHARACTER = 5;
- public static final int CHANGE_PIN_SYSTEM_ERROR = 6;
-
- /** Indicates the client is Google visual voicemail version 1.0. */
- public static final String CLIENT_TYPE_GOOGLE_10 = "google.vvm.10";
-}
diff --git a/src/com/android/phone/vvm/omtp/OmtpEvents.java b/src/com/android/phone/vvm/omtp/OmtpEvents.java
deleted file mode 100644
index 7a89418..0000000
--- a/src/com/android/phone/vvm/omtp/OmtpEvents.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp;
-
-import android.annotation.IntDef;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Events internal to the OMTP client. These should be translated into {@link
- * android.provider.VoicemailContract.Status} error codes before writing into the voicemail status
- * table.
- */
-public enum OmtpEvents {
-
- // Configuration State
- CONFIG_REQUEST_STATUS_SUCCESS(Type.CONFIGURATION, true),
-
- CONFIG_PIN_SET(Type.CONFIGURATION, true),
- // 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),
-
- // Data channel State
-
- // A new sync has started, old errors in data channel should be cleared.
- DATA_IMAP_OPERATION_STARTED(Type.DATA_CHANNEL, true),
- // Successfully downloaded/uploaded data from the server, which means the data channel is clear.
- DATA_IMAP_OPERATION_COMPLETED(Type.DATA_CHANNEL, true),
- // The port provided in the STATUS SMS is invalid.
- DATA_INVALID_PORT(Type.DATA_CHANNEL),
- // No connection to the internet, and the carrier requires cellular data
- DATA_NO_CONNECTION_CELLULAR_REQUIRED(Type.DATA_CHANNEL),
- // No connection to the internet.
- DATA_NO_CONNECTION(Type.DATA_CHANNEL),
- // Address lookup for the server hostname failed. DNS error?
- DATA_CANNOT_RESOLVE_HOST_ON_NETWORK(Type.DATA_CHANNEL),
- // All destination address that resolves to the server hostname are rejected or timed out
- DATA_ALL_SOCKET_CONNECTION_FAILED(Type.DATA_CHANNEL),
- // Failed to establish SSL with the server, either with a direct SSL connection or by
- // STARTTLS command
- DATA_CANNOT_ESTABLISH_SSL_SESSION(Type.DATA_CHANNEL),
- // Identity of the server cannot be verified.
- DATA_SSL_INVALID_HOST_NAME(Type.DATA_CHANNEL),
- // The server rejected our username/password
- DATA_BAD_IMAP_CREDENTIAL(Type.DATA_CHANNEL),
-
- DATA_AUTH_UNKNOWN_USER(Type.DATA_CHANNEL),
- DATA_AUTH_UNKNOWN_DEVICE(Type.DATA_CHANNEL),
- DATA_AUTH_INVALID_PASSWORD(Type.DATA_CHANNEL),
- DATA_AUTH_MAILBOX_NOT_INITIALIZED(Type.DATA_CHANNEL),
- DATA_AUTH_SERVICE_NOT_PROVISIONED(Type.DATA_CHANNEL),
- DATA_AUTH_SERVICE_NOT_ACTIVATED(Type.DATA_CHANNEL),
- DATA_AUTH_USER_IS_BLOCKED(Type.DATA_CHANNEL),
-
- // A command to the server didn't result with an "OK" or continuation request
- DATA_REJECTED_SERVER_RESPONSE(Type.DATA_CHANNEL),
- // The server did not greet us with a "OK", possibly not a IMAP server.
- DATA_INVALID_INITIAL_SERVER_RESPONSE(Type.DATA_CHANNEL),
- // An IOException occurred while trying to open an ImapConnection
- // TODO: reduce scope
- DATA_IOE_ON_OPEN(Type.DATA_CHANNEL),
- // The SELECT command on a mailbox is rejected
- DATA_MAILBOX_OPEN_FAILED(Type.DATA_CHANNEL),
- // An IOException has occurred
- // TODO: reduce scope
- DATA_GENERIC_IMAP_IOE(Type.DATA_CHANNEL),
- // An SslException has occurred while opening an ImapConnection
- // TODO: reduce scope
- DATA_SSL_EXCEPTION(Type.DATA_CHANNEL),
-
- // Notification Channel
-
- // Cell signal restored, can received VVM SMSs
- NOTIFICATION_IN_SERVICE(Type.NOTIFICATION_CHANNEL, true),
- // Cell signal lost, cannot received VVM SMSs
- NOTIFICATION_SERVICE_LOST(Type.NOTIFICATION_CHANNEL, false),
-
-
- // Other
- OTHER_SOURCE_REMOVED(Type.OTHER, false),
-
- // VVM3
- VVM3_NEW_USER_SETUP_FAILED,
- // Table 4. client internal error handling
- VVM3_VMG_DNS_FAILURE,
- VVM3_SPG_DNS_FAILURE,
- VVM3_VMG_CONNECTION_FAILED,
- VVM3_SPG_CONNECTION_FAILED,
- VVM3_VMG_TIMEOUT,
- VVM3_STATUS_SMS_TIMEOUT,
-
- VVM3_SUBSCRIBER_PROVISIONED,
- VVM3_SUBSCRIBER_BLOCKED,
- VVM3_SUBSCRIBER_UNKNOWN;
-
- public static class Type {
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({CONFIGURATION, DATA_CHANNEL, NOTIFICATION_CHANNEL, OTHER})
- public @interface Values {
-
- }
-
- public static final int CONFIGURATION = 1;
- public static final int DATA_CHANNEL = 2;
- public static final int NOTIFICATION_CHANNEL = 3;
- public static final int OTHER = 4;
- }
-
- private final int mType;
- private final boolean mIsSuccess;
-
- OmtpEvents(int type, boolean isSuccess) {
- mType = type;
- mIsSuccess = isSuccess;
- }
-
- OmtpEvents(int type) {
- mType = type;
- mIsSuccess = false;
- }
-
- OmtpEvents() {
- mType = Type.OTHER;
- mIsSuccess = false;
- }
-
- @Type.Values
- public int getType() {
- return mType;
- }
-
- public boolean isSuccess() {
- return mIsSuccess;
- }
-
-}
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
deleted file mode 100644
index 486b07c..0000000
--- a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp;
-
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
-import android.os.PersistableBundle;
-import android.telecom.PhoneAccountHandle;
-import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.telephony.VisualVoicemailSmsFilterSettings;
-import android.text.TextUtils;
-import android.util.ArraySet;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocol;
-import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocolFactory;
-import com.android.phone.vvm.omtp.sms.StatusMessage;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * Manages carrier dependent visual voicemail configuration values. The primary source is the value
- * retrieved from CarrierConfigManager. If CarrierConfigManager does not provide the config
- * (KEY_VVM_TYPE_STRING is empty, or "hidden" configs), then the value hardcoded in telephony will
- * be used (in res/xml/vvm_config.xml)
- *
- * Hidden configs are new configs that are planned for future APIs, or miscellaneous settings that
- * may clutter CarrierConfigManager too much.
- *
- * The current hidden configs are: {@link #getSslPort()} {@link #getDisabledCapabilities()}
- */
-public class OmtpVvmCarrierConfigHelper {
-
- private static final String TAG = "OmtpVvmCarrierCfgHlpr";
-
- static final String KEY_VVM_TYPE_STRING = CarrierConfigManager.KEY_VVM_TYPE_STRING;
- static final String KEY_VVM_DESTINATION_NUMBER_STRING =
- CarrierConfigManager.KEY_VVM_DESTINATION_NUMBER_STRING;
- static final String KEY_VVM_PORT_NUMBER_INT =
- CarrierConfigManager.KEY_VVM_PORT_NUMBER_INT;
- static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING =
- CarrierConfigManager.KEY_CARRIER_VVM_PACKAGE_NAME_STRING;
- static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY =
- "carrier_vvm_package_name_string_array";
- static final String KEY_VVM_PREFETCH_BOOL =
- CarrierConfigManager.KEY_VVM_PREFETCH_BOOL;
- static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL =
- CarrierConfigManager.KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL;
-
- /**
- * @see #getSslPort()
- */
- static final String KEY_VVM_SSL_PORT_NUMBER_INT =
- "vvm_ssl_port_number_int";
-
- /**
- * @see #isLegacyModeEnabled()
- */
- static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL =
- "vvm_legacy_mode_enabled_bool";
-
- /**
- * Ban a capability reported by the server from being used. The array of string should be a
- * subset of the capabilities returned IMAP CAPABILITY command.
- *
- * @see #getDisabledCapabilities()
- */
- static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY =
- "vvm_disabled_capabilities_string_array";
- static final String KEY_VVM_CLIENT_PREFIX_STRING =
- "vvm_client_prefix_string";
-
- private final Context mContext;
- private final int mSubId;
- private final PersistableBundle mCarrierConfig;
- private final String mVvmType;
- private final VisualVoicemailProtocol mProtocol;
- private final PersistableBundle mTelephonyConfig;
-
- private PhoneAccountHandle mPhoneAccountHandle;
-
- public OmtpVvmCarrierConfigHelper(Context context, int subId) {
- mContext = context;
- mSubId = subId;
- mCarrierConfig = getCarrierConfig();
-
- TelephonyManager telephonyManager =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- mTelephonyConfig = new TelephonyVvmConfigManager(context.getResources())
- .getConfig(telephonyManager.getSimOperator(subId));
-
- mVvmType = getVvmType();
- mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType);
- }
-
- public OmtpVvmCarrierConfigHelper(Context context, PhoneAccountHandle handle) {
- this(context, PhoneAccountHandleConverter.toSubId(handle));
- mPhoneAccountHandle = handle;
- }
-
- @VisibleForTesting
- OmtpVvmCarrierConfigHelper(Context context, PersistableBundle carrierConfig,
- PersistableBundle telephonyConfig) {
- mContext = context;
- mSubId = 0;
- mCarrierConfig = carrierConfig;
- mTelephonyConfig = telephonyConfig;
- mVvmType = getVvmType();
- mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType);
- }
-
- public Context getContext() {
- return mContext;
- }
-
- public int getSubId() {
- return mSubId;
- }
-
- @Nullable
- public PhoneAccountHandle getPhoneAccountHandle() {
- if (mPhoneAccountHandle == null) {
- mPhoneAccountHandle = PhoneAccountHandleConverter.fromSubId(mSubId);
- if (mPhoneAccountHandle == null) {
- VvmLog.e(TAG, "null phone account for subId " + mSubId);
- }
- }
- return mPhoneAccountHandle;
- }
-
- /**
- * return whether the carrier's visual voicemail is supported, with KEY_VVM_TYPE_STRING set as a
- * known protocol.
- */
- public boolean isValid() {
- return mProtocol != null;
- }
-
- @Nullable
- public String getVvmType() {
- return (String) getValue(KEY_VVM_TYPE_STRING);
- }
-
- @Nullable
- public VisualVoicemailProtocol getProtocol() {
- return mProtocol;
- }
-
- /**
- * @returns arbitrary String stored in the config file. Used for protocol specific values.
- */
- @Nullable
- public String getString(String key) {
- return (String) getValue(key);
- }
-
- @Nullable
- public Set<String> getCarrierVvmPackageNames() {
- Set<String> names = getCarrierVvmPackageNames(mCarrierConfig);
- if (names != null) {
- return names;
- }
- return getCarrierVvmPackageNames(mTelephonyConfig);
- }
-
- private static Set<String> getCarrierVvmPackageNames(@Nullable PersistableBundle bundle) {
- if (bundle == null) {
- return null;
- }
- Set<String> names = new ArraySet<>();
- if (bundle.containsKey(KEY_CARRIER_VVM_PACKAGE_NAME_STRING)) {
- names.add(bundle.getString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING));
- }
- if (bundle.containsKey(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY)) {
- String[] vvmPackages = bundle.getStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY);
- if (vvmPackages != null && vvmPackages.length > 0) {
- names.addAll(Arrays.asList(
- bundle.getStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY)));
- }
- }
- if (names.isEmpty()) {
- return null;
- }
- return names;
- }
-
- /**
- * For checking upon sim insertion whether visual voicemail should be enabled. This method does
- * so by checking if the carrier's voicemail app is installed.
- */
- public boolean isEnabledByDefault() {
- if (!isValid()) {
- return false;
- }
-
- Set<String> carrierPackages = getCarrierVvmPackageNames();
- if (carrierPackages == null) {
- return true;
- }
- for (String packageName : carrierPackages) {
- try {
- mContext.getPackageManager().getPackageInfo(packageName, 0);
- return false;
- } catch (NameNotFoundException e) {
- // Do nothing.
- }
- }
- return true;
- }
-
- public boolean isCellularDataRequired() {
- return (boolean) getValue(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL, false);
- }
-
- public boolean isPrefetchEnabled() {
- return (boolean) getValue(KEY_VVM_PREFETCH_BOOL, true);
- }
-
-
- public int getApplicationPort() {
- return (int) getValue(KEY_VVM_PORT_NUMBER_INT, 0);
- }
-
- @Nullable
- public String getDestinationNumber() {
- return (String) getValue(KEY_VVM_DESTINATION_NUMBER_STRING);
- }
-
- /**
- * Hidden config.
- *
- * @return Port to start a SSL IMAP connection directly.
- *
- * TODO: make config public and add to CarrierConfigManager
- */
- public int getSslPort() {
- return (int) getValue(KEY_VVM_SSL_PORT_NUMBER_INT, 0);
- }
-
- /**
- * Hidden Config.
- *
- * <p>Sometimes the server states it supports a certain feature but we found they have bug on
- * the server side. For example, in b/28717550 the server reported AUTH=DIGEST-MD5 capability
- * but using it to login will cause subsequent response to be erroneous.
- *
- * @return A set of capabilities that is reported by the IMAP CAPABILITY command, but determined
- * to have issues and should not be used.
- */
- @Nullable
- public Set<String> getDisabledCapabilities() {
- Set<String> disabledCapabilities = getDisabledCapabilities(mCarrierConfig);
- if (disabledCapabilities != null) {
- return disabledCapabilities;
- }
- return getDisabledCapabilities(mTelephonyConfig);
- }
-
- @Nullable
- private static Set<String> getDisabledCapabilities(@Nullable PersistableBundle bundle) {
- if (bundle == null) {
- return null;
- }
- if (!bundle.containsKey(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY)) {
- return null;
- }
- String[] disabledCapabilities =
- bundle.getStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY);
- if (disabledCapabilities != null && disabledCapabilities.length > 0) {
- ArraySet<String> result = new ArraySet<>();
- Collections.addAll(result, disabledCapabilities);
- return result;
- }
- return null;
- }
-
- public String getClientPrefix() {
- String prefix = (String) getValue(KEY_VVM_CLIENT_PREFIX_STRING);
- if (prefix != null) {
- return prefix;
- }
- return "//VVM";
- }
-
- /**
- * Should legacy mode be used when the OMTP VVM client is disabled?
- *
- * <p>Legacy mode is a mode that on the carrier side visual voicemail is still activated, but on
- * the client side all network operations are disabled. SMSs are still monitored so a new
- * message SYNC SMS will be translated to show a message waiting indicator, like traditional
- * voicemails.
- *
- * <p>This is for carriers that does not support VVM deactivation so voicemail can continue to
- * function without the data cost.
- */
- public boolean isLegacyModeEnabled() {
- return (boolean) getValue(KEY_VVM_LEGACY_MODE_ENABLED_BOOL, false);
- }
-
- public void startActivation() {
- PhoneAccountHandle phoneAccountHandle = getPhoneAccountHandle();
- if (phoneAccountHandle == null) {
- // This should never happen
- // Error logged in getPhoneAccountHandle().
- return;
- }
-
- 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();
-
- if (mProtocol != null) {
- ActivationTask.start(mContext, mSubId, null);
- }
- }
-
- public void activateSmsFilter() {
- TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
- telephonyManager.enableVisualVoicemailSmsFilter(mSubId,
- new VisualVoicemailSmsFilterSettings.Builder().setClientPrefix(getClientPrefix())
- .build());
- }
-
- public void startDeactivation() {
- if (!isLegacyModeEnabled()) {
- // SMS should still be filtered in legacy mode
- mContext.getSystemService(TelephonyManager.class)
- .disableVisualVoicemailSmsFilter(mSubId);
- }
- if (mProtocol != null) {
- mProtocol.startDeactivation(this);
- }
- }
-
- public boolean supportsProvisioning() {
- if (mProtocol != null) {
- return mProtocol.supportsProvisioning();
- }
- return false;
- }
-
- public void startProvisioning(ActivationTask task, PhoneAccountHandle phone,
- VoicemailStatus.Editor status, StatusMessage message, Bundle data) {
- if (mProtocol != null) {
- mProtocol.startProvisioning(task, phone, this, status, message, data);
- }
- }
-
- public void requestStatus(@Nullable PendingIntent sentIntent) {
- if (mProtocol != null) {
- mProtocol.requestStatus(this, sentIntent);
- }
- }
-
- public void handleEvent(VoicemailStatus.Editor status, OmtpEvents event) {
- VvmLog.i(TAG, "OmtpEvent:" + event);
- if (mProtocol != null) {
- mProtocol.handleEvent(mContext, this, status, event);
- }
- }
-
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder("OmtpVvmCarrierConfigHelper [");
- builder.append("subId: ").append(getSubId())
- .append(", carrierConfig: ").append(mCarrierConfig != null)
- .append(", telephonyConfig: ").append(mTelephonyConfig != null)
- .append(", type: ").append(getVvmType())
- .append(", destinationNumber: ").append(getDestinationNumber())
- .append(", applicationPort: ").append(getApplicationPort())
- .append(", sslPort: ").append(getSslPort())
- .append(", isEnabledByDefault: ").append(isEnabledByDefault())
- .append(", isCellularDataRequired: ").append(isCellularDataRequired())
- .append(", isPrefetchEnabled: ").append(isPrefetchEnabled())
- .append(", isLegacyModeEnabled: ").append(isLegacyModeEnabled())
- .append("]");
- return builder.toString();
- }
-
- @Nullable
- private PersistableBundle getCarrierConfig() {
- if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
- VvmLog
- .w(TAG, "Invalid subscriptionId or subscriptionId not provided in intent.");
- return null;
- }
-
- CarrierConfigManager carrierConfigManager = (CarrierConfigManager)
- mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- if (carrierConfigManager == null) {
- VvmLog.w(TAG, "No carrier config service found.");
- return null;
- }
-
- PersistableBundle config = carrierConfigManager.getConfigForSubId(mSubId);
-
- if (TextUtils.isEmpty(config.getString(CarrierConfigManager.KEY_VVM_TYPE_STRING))) {
- return null;
- }
- return config;
- }
-
- @Nullable
- private Object getValue(String key) {
- return getValue(key, null);
- }
-
- @Nullable
- private Object getValue(String key, Object defaultValue) {
- Object result;
- if (mCarrierConfig != null) {
- result = mCarrierConfig.get(key);
- if (result != null) {
- return result;
- }
- }
- if (mTelephonyConfig != null) {
- result = mTelephonyConfig.get(key);
- if (result != null) {
- return result;
- }
- }
- return defaultValue;
- }
-
-}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
deleted file mode 100644
index fb8f02d..0000000
--- a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.IPackageManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserManager;
-import android.telecom.PhoneAccountHandle;
-import android.telephony.CarrierConfigManager;
-import android.telephony.ServiceState;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.phone.settings.VisualVoicemailSettingsUtil;
-import com.android.phone.vvm.RemoteVvmTaskManager;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
-/**
- * This class listens to the {@link CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED} and {@link
- * TelephonyIntents#ACTION_SIM_STATE_CHANGED} to determine when a SIM is added, replaced, or
- * removed.
- *
- * When a SIM is added, send an activate SMS. When a SIM is removed, remove the sync accounts and
- * change the status in the voicemail_status table.
- */
-public class SimChangeReceiver extends BroadcastReceiver {
-
- private static final String TAG = "VvmSimChangeReceiver";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (action == null) {
- VvmLog.w(TAG, "Null action for intent.");
- return;
- }
-
- int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
- SubscriptionManager.INVALID_SUBSCRIPTION_ID);
-
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- VvmLog.i(TAG, "Received SIM change for invalid subscription id.");
- return;
- }
-
- if (RemoteVvmTaskManager.hasRemoteService(context, subId)) {
- return;
- }
-
- switch (action) {
- case TelephonyIntents.ACTION_SIM_STATE_CHANGED:
- if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(
- intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE))) {
- VvmLog.i(TAG, "Sim removed, removing inactive accounts");
- OmtpVvmSourceManager.getInstance(context).removeInactiveSources();
- }
- break;
- case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
-
-
- TelephonyManager telephonyManager = context
- .getSystemService(TelephonyManager.class);
- if(TextUtils.isEmpty(telephonyManager.getSimOperator())){
- VvmLog.e(TAG,
- "Empty MCCMNC, possible modem crash."
- + " Ignoring carrier config changed event");
- return;
- }
-
- PhoneAccountHandle phoneAccountHandle = PhoneAccountHandleConverter
- .fromSubId(subId);
- if("null".equals(phoneAccountHandle.getId())){
- VvmLog.e(TAG,
- "null phone account handle ID, possible modem crash."
- + " Ignoring carrier config changed event");
- return;
- }
-
- VvmLog.d(TAG, "Carrier config changed");
-
- if (UserManager.get(context).isUserUnlocked() && !isCryptKeeperMode()) {
- processSubId(context, subId);
- } else {
- VvmLog.d(TAG, "User locked, activation request delayed until unlock");
- // After the device is unlocked, VvmBootCompletedReceiver will iterate through
- // all call capable subIds, nothing need to be done here.
- }
- break;
- }
- }
-
- public static void processSubId(Context context, int subId) {
- PhoneAccountHandle phoneAccount = PhoneAccountHandleConverter.fromSubId(subId);
- if (phoneAccount == null) {
- // This should never happen
- VvmLog.e(TAG, "unable to convert subId " + subId + " to PhoneAccountHandle");
- return;
- }
-
- OmtpVvmCarrierConfigHelper carrierConfigHelper =
- new OmtpVvmCarrierConfigHelper(context, subId);
- if (carrierConfigHelper.isValid()) {
- if (VisualVoicemailSettingsUtil.isEnabled(context, phoneAccount)) {
- VvmLog.i(TAG, "Sim state or carrier config changed for " + subId);
- // Add a phone state listener so that changes to the communication channels
- // can be recorded.
- OmtpVvmSourceManager.getInstance(context).addPhoneStateListener(
- phoneAccount);
- if (context.getSystemService(TelephonyManager.class)
- .getServiceStateForSubscriber(subId).getState()
- != ServiceState.STATE_IN_SERVICE) {
- VvmLog.i(TAG, "Cellular signal not available, not activating");
- return;
- }
- carrierConfigHelper.startActivation();
- } else {
- if (carrierConfigHelper.isLegacyModeEnabled()) {
- // SMS still need to be filtered under legacy mode.
- VvmLog.i(TAG, "activating SMS filter for legacy mode");
- carrierConfigHelper.activateSmsFilter();
- }
- // It may be that the source was not registered to begin with but we want
- // to run through the steps to remove the source just in case.
- OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount);
- VvmLog.v(TAG, "Sim change for disabled account.");
- }
- } else {
- String mccMnc = context.getSystemService(TelephonyManager.class).getSimOperator(subId);
- VvmLog.d(TAG,
- "visual voicemail not supported for carrier " + mccMnc + " on subId " + subId);
- OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount);
- }
- }
-
- /**
- * CryptKeeper mode is the pre-file based encryption locked state, when the user has selected
- * "Require password to boot" and the device hasn't been unlocked yet during a reboot. {@link
- * UserManager#isUserUnlocked()} will still return true in this mode, but storage in /data and
- * all content providers will not be available(including SharedPreference).
- */
- private static boolean isCryptKeeperMode() {
- try {
- return IPackageManager.Stub.asInterface(ServiceManager.getService("package")).
- isOnlyCoreApps();
- } catch (RemoteException e) {
- }
- return false;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/TelephonyVvmConfigManager.java b/src/com/android/phone/vvm/omtp/TelephonyVvmConfigManager.java
deleted file mode 100644
index e91481e..0000000
--- a/src/com/android/phone/vvm/omtp/TelephonyVvmConfigManager.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp;
-
-import android.annotation.Nullable;
-import android.content.res.Resources;
-import android.os.PersistableBundle;
-import android.util.ArrayMap;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.phone.R;
-import com.android.phone.vvm.omtp.utils.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Map;
-import java.util.Map.Entry;
-
-/**
- * Load and caches telephony vvm config from res/xml/vvm_config.xml
- */
-public class TelephonyVvmConfigManager {
-
- private static final String TAG = "TelephonyVvmCfgMgr";
-
- private static final boolean USE_DEBUG_CONFIG = false; //STOPSHIP if true
-
- private static final String TAG_PERSISTABLEMAP = "pbundle_as_map";
-
- static final String KEY_MCCMNC = "mccmnc";
-
- private static Map<String, PersistableBundle> sCachedConfigs;
-
- private final Map<String, PersistableBundle> mConfigs;
-
- public TelephonyVvmConfigManager(Resources resources) {
- if (sCachedConfigs == null) {
- sCachedConfigs = loadConfigs(resources.getXml(R.xml.vvm_config));
- }
- mConfigs = sCachedConfigs;
- }
-
- @VisibleForTesting
- TelephonyVvmConfigManager(XmlPullParser parser) {
- mConfigs = loadConfigs(parser);
- }
-
- @Nullable
- public PersistableBundle getConfig(String mccMnc) {
- if (USE_DEBUG_CONFIG) {
- return mConfigs.get("TEST");
- }
- return mConfigs.get(mccMnc);
- }
-
- private static Map<String, PersistableBundle> loadConfigs(XmlPullParser parser) {
- Map<String, PersistableBundle> configs = new ArrayMap<>();
- try {
- ArrayList list = readBundleList(parser);
- for (Object object : list) {
- if (!(object instanceof PersistableBundle)) {
- throw new IllegalArgumentException("PersistableBundle expected, got " + object);
- }
- PersistableBundle bundle = (PersistableBundle) object;
- String[] mccMncs = bundle.getStringArray(KEY_MCCMNC);
- if (mccMncs == null) {
- throw new IllegalArgumentException("MCCMNC is null");
- }
- for (String mccMnc : mccMncs) {
- configs.put(mccMnc, bundle);
- }
- }
- } catch (IOException | XmlPullParserException e) {
- throw new RuntimeException(e);
- }
- return configs;
- }
-
- @Nullable
- public static ArrayList readBundleList(XmlPullParser in) throws IOException,
- XmlPullParserException {
- final int outerDepth = in.getDepth();
- int event;
- while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
- (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
- if (event == XmlPullParser.START_TAG) {
- final String startTag = in.getName();
- final String[] tagName = new String[1];
- in.next();
- return XmlUtils.readThisListXml(in, startTag, tagName,
- new MyReadMapCallback(), false);
- }
- }
- return null;
- }
-
- public static PersistableBundle restoreFromXml(XmlPullParser in) throws IOException,
- XmlPullParserException {
- final int outerDepth = in.getDepth();
- final String startTag = in.getName();
- final String[] tagName = new String[1];
- int event;
- while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
- (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
- if (event == XmlPullParser.START_TAG) {
- ArrayMap<String, ?> map =
- XmlUtils.readThisArrayMapXml(in, startTag, tagName,
- new MyReadMapCallback());
- PersistableBundle result = new PersistableBundle();
- for (Entry<String, ?> entry : map.entrySet()) {
- Object value = entry.getValue();
- if (value instanceof Integer) {
- result.putInt(entry.getKey(), (int) value);
- } else if (value instanceof Boolean) {
- result.putBoolean(entry.getKey(), (boolean) value);
- } else if (value instanceof String) {
- result.putString(entry.getKey(), (String) value);
- } else if (value instanceof String[]) {
- result.putStringArray(entry.getKey(), (String[]) value);
- } else if (value instanceof PersistableBundle) {
- result.putPersistableBundle(entry.getKey(), (PersistableBundle) value);
- }
- }
- return result;
- }
- }
- return PersistableBundle.EMPTY;
- }
-
- static class MyReadMapCallback implements XmlUtils.ReadMapCallback {
-
- @Override
- public Object readThisUnknownObjectXml(XmlPullParser in, String tag)
- throws XmlPullParserException, IOException {
- if (TAG_PERSISTABLEMAP.equals(tag)) {
- return restoreFromXml(in);
- }
- throw new XmlPullParserException("Unknown tag=" + tag);
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/VvmBootCompletedReceiver.java b/src/com/android/phone/vvm/omtp/VvmBootCompletedReceiver.java
deleted file mode 100644
index f725f96..0000000
--- a/src/com/android/phone/vvm/omtp/VvmBootCompletedReceiver.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
-import android.telephony.SubscriptionManager;
-
-import com.android.phone.vvm.RemoteVvmTaskManager;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
-/**
- * Upon boot iterate through all callable phone account to activate visual voicemail. This happens
- * after the device has been unlocked. {@link android.telephony.CarrierConfigManager#
- * ACTION_CARRIER_CONFIG_CHANGED} can also trigger activation upon boot but it can happen before the
- * device is unlocked and visual voicemail will not be activated.
- *
- * <p>TODO: An additional duplicated activation request will be sent as a result of this receiver,
- * but similar issues is already covered in b/28730056 and a scheduling system should be used to
- * resolve this.
- */
-public class VvmBootCompletedReceiver extends BroadcastReceiver {
-
- private static final String TAG = "VvmBootCompletedRcvr";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- // Listens to android.intent.action.BOOT_COMPLETED
- if (!intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
- return;
- }
-
- VvmLog.v(TAG, "processing subId list");
- for (PhoneAccountHandle handle : TelecomManager.from(context)
- .getCallCapablePhoneAccounts()) {
- int subId = PhoneAccountHandleConverter.toSubId(handle);
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- // getCallCapablePhoneAccounts() might return a PhoneAccountHandle with invalid
- // subId if no SIM is inserted. This is intended as it is for emergency calls.
- VvmLog.e(TAG, "phone account " + handle + " has invalid subId " + subId);
- continue;
- }
- if (RemoteVvmTaskManager.hasRemoteService(context, subId)) {
- return;
- }
-
- VvmLog.v(TAG, "processing subId " + subId);
- SimChangeReceiver.processSubId(context, subId);
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java b/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
deleted file mode 100644
index 7c20065..0000000
--- a/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.telecom.PhoneAccountHandle;
-
-import com.android.phone.PhoneUtils;
-import com.android.phone.settings.VisualVoicemailSettingsUtil;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
-
-import java.util.Set;
-
-/**
- * When a new package is installed, check if it matches any of the vvm carrier apps of the currently
- * enabled dialer vvm sources.
- */
-public class VvmPackageInstallReceiver extends BroadcastReceiver {
-
- private static final String TAG = "VvmPkgInstallReceiver";
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent.getData() == null) {
- return;
- }
-
- String packageName = intent.getData().getSchemeSpecificPart();
- if (packageName == null) {
- return;
- }
-
- OmtpVvmSourceManager vvmSourceManager = OmtpVvmSourceManager.getInstance(context);
- Set<PhoneAccountHandle> phoneAccounts = vvmSourceManager.getOmtpVvmSources();
- for (PhoneAccountHandle phoneAccount : phoneAccounts) {
- if (VisualVoicemailSettingsUtil.isEnabledUserSet(context, phoneAccount)) {
- // Skip the check if this voicemail source's setting is overridden by the user.
- continue;
- }
-
- OmtpVvmCarrierConfigHelper carrierConfigHelper = new OmtpVvmCarrierConfigHelper(
- context, PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount));
- if (carrierConfigHelper.getCarrierVvmPackageNames() == null) {
- continue;
- }
- if (carrierConfigHelper.getCarrierVvmPackageNames().contains(packageName)) {
- // Force deactivate the client. The user can re-enable it in the settings.
- // There are no need to update the settings for deactivation. At this point, if the
- // default value is used it should be false because a carrier package is present.
- VvmLog.i(TAG, "Carrier VVM package installed, disabling system VVM client");
- OmtpVvmSourceManager.getInstance(context).removeSource(phoneAccount);
- carrierConfigHelper.startDeactivation();
- }
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java b/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
deleted file mode 100644
index 75ffc71..0000000
--- a/src/com/android/phone/vvm/omtp/VvmPhoneStateListener.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp;
-
-import android.content.Context;
-import android.telecom.PhoneAccountHandle;
-import android.telephony.PhoneStateListener;
-import android.telephony.ServiceState;
-import android.telephony.SubscriptionManager;
-
-import com.android.phone.PhoneUtils;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.RemoteVvmTaskManager;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService;
-import com.android.phone.vvm.omtp.sync.SyncTask;
-import com.android.phone.vvm.omtp.sync.VoicemailStatusQueryHelper;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
-/**
- * Check if service is lost and indicate this in the voicemail status.
- */
-public class VvmPhoneStateListener extends PhoneStateListener {
-
- private static final String TAG = "VvmPhoneStateListener";
-
- private PhoneAccountHandle mPhoneAccount;
- private Context mContext;
- private int mPreviousState = -1;
-
- public VvmPhoneStateListener(Context context, PhoneAccountHandle accountHandle) {
- super(PhoneUtils.getSubIdForPhoneAccountHandle(accountHandle));
- mContext = context;
- mPhoneAccount = accountHandle;
- }
-
- @Override
- public void onServiceStateChanged(ServiceState serviceState) {
- int subId = PhoneAccountHandleConverter.toSubId(mPhoneAccount);
- if (!SubscriptionManager.isValidSubscriptionId(subId)) {
- VvmLog.e(TAG, "onServiceStateChanged on phoneAccount " + mPhoneAccount
- + " with invalid subId, ignoring");
- return;
- }
-
- if (RemoteVvmTaskManager.hasRemoteService(mContext, subId)) {
- return;
- }
-
- int state = serviceState.getState();
- if (state == mPreviousState || (state != ServiceState.STATE_IN_SERVICE
- && mPreviousState != ServiceState.STATE_IN_SERVICE)) {
- // Only interested in state changes or transitioning into or out of "in service".
- // Otherwise just quit.
- mPreviousState = state;
- return;
- }
-
- OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(mContext, subId);
-
- if (state == ServiceState.STATE_IN_SERVICE) {
-
- VoicemailStatusQueryHelper voicemailStatusQueryHelper =
- new VoicemailStatusQueryHelper(mContext);
- if (voicemailStatusQueryHelper.isVoicemailSourceConfigured(mPhoneAccount)) {
- if (!voicemailStatusQueryHelper.isNotificationsChannelActive(mPhoneAccount)) {
- VvmLog
- .v(TAG, "Notifications channel is active for " + subId);
- helper.handleEvent(VoicemailStatus.edit(mContext, mPhoneAccount),
- OmtpEvents.NOTIFICATION_IN_SERVICE);
- }
- }
-
- if (OmtpVvmSourceManager.getInstance(mContext).isVvmSourceRegistered(mPhoneAccount)) {
- VvmLog
- .v(TAG, "Signal returned: requesting resync for " + subId);
- // If the source is already registered, run a full sync in case something was missed
- // while signal was down.
- SyncTask.start(mContext, mPhoneAccount, OmtpVvmSyncService.SYNC_FULL_SYNC);
- } else {
- VvmLog.v(TAG,
- "Signal returned: reattempting activation for " + subId);
- // Otherwise initiate an activation because this means that an OMTP source was
- // recognized but either the activation text was not successfully sent or a response
- // was not received.
- helper.startActivation();
- }
- } else {
- VvmLog.v(TAG, "Notifications channel is inactive for " + subId);
-
- if (!OmtpVvmSourceManager.getInstance(mContext).isVvmSourceRegistered(mPhoneAccount)) {
- return;
- }
- helper.handleEvent(VoicemailStatus.edit(mContext, mPhoneAccount),
- OmtpEvents.NOTIFICATION_SERVICE_LOST);
- }
- mPreviousState = state;
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java b/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
deleted file mode 100644
index 9bda638..0000000
--- a/src/com/android/phone/vvm/omtp/fetch/FetchVoicemailReceiver.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.fetch;
-
-import android.annotation.Nullable;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.database.Cursor;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkRequest;
-import android.net.Uri;
-import android.provider.VoicemailContract;
-import android.provider.VoicemailContract.Voicemails;
-import android.telecom.PhoneAccountHandle;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import com.android.internal.telephony.Phone;
-import com.android.phone.PhoneUtils;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.imap.ImapHelper;
-import com.android.phone.vvm.omtp.imap.ImapHelper.InitializingException;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
-import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback;
-import java.util.concurrent.Executor;
-import java.util.concurrent.Executors;
-
-public class FetchVoicemailReceiver extends BroadcastReceiver {
-
- private static final String TAG = "FetchVoicemailReceiver";
-
- final static String[] PROJECTION = new String[]{
- Voicemails.SOURCE_DATA, // 0
- Voicemails.PHONE_ACCOUNT_ID, // 1
- Voicemails.PHONE_ACCOUNT_COMPONENT_NAME, // 2
- };
-
- public static final int SOURCE_DATA = 0;
- public static final int PHONE_ACCOUNT_ID = 1;
- public static final int PHONE_ACCOUNT_COMPONENT_NAME = 2;
-
- // Timeout used to call ConnectivityManager.requestNetwork
- private static final int NETWORK_REQUEST_TIMEOUT_MILLIS = 60 * 1000;
-
- // Number of retries
- private static final int NETWORK_RETRY_COUNT = 3;
-
- private ContentResolver mContentResolver;
- private Uri mUri;
- private NetworkRequest mNetworkRequest;
- private VvmNetworkRequestCallback mNetworkCallback;
- private Context mContext;
- private String mUid;
- private ConnectivityManager mConnectivityManager;
- private PhoneAccountHandle mPhoneAccount;
- private int mRetryCount = NETWORK_RETRY_COUNT;
-
- @Override
- public void onReceive(final Context context, Intent intent) {
- if (VoicemailContract.ACTION_FETCH_VOICEMAIL.equals(intent.getAction())) {
- VvmLog.i(TAG, "ACTION_FETCH_VOICEMAIL received");
- mContext = context;
- mContentResolver = context.getContentResolver();
- mUri = intent.getData();
-
- if (mUri == null) {
- VvmLog.w(TAG,
- VoicemailContract.ACTION_FETCH_VOICEMAIL + " intent sent with no data");
- return;
- }
-
- if (!context.getPackageName().equals(
- mUri.getQueryParameter(VoicemailContract.PARAM_KEY_SOURCE_PACKAGE))) {
- // Ignore if the fetch request is for a voicemail not from this package.
- VvmLog.e(TAG,
- "ACTION_FETCH_VOICEMAIL from foreign pacakge " + context.getPackageName());
- return;
- }
-
- Cursor cursor = mContentResolver.query(mUri, PROJECTION, null, null, null);
- if (cursor == null) {
- VvmLog.i(TAG, "ACTION_FETCH_VOICEMAIL query returned null");
- return;
- }
- try {
- if (cursor.moveToFirst()) {
- mUid = cursor.getString(SOURCE_DATA);
- String accountId = cursor.getString(PHONE_ACCOUNT_ID);
- if (TextUtils.isEmpty(accountId)) {
- TelephonyManager telephonyManager = (TelephonyManager)
- context.getSystemService(Context.TELEPHONY_SERVICE);
- accountId = telephonyManager.getSimSerialNumber();
-
- if (TextUtils.isEmpty(accountId)) {
- VvmLog.e(TAG, "Account null and no default sim found.");
- return;
- }
- }
-
- mPhoneAccount = new PhoneAccountHandle(
- ComponentName.unflattenFromString(
- cursor.getString(PHONE_ACCOUNT_COMPONENT_NAME)),
- cursor.getString(PHONE_ACCOUNT_ID));
- if (!OmtpVvmSourceManager.getInstance(context)
- .isVvmSourceRegistered(mPhoneAccount)) {
- mPhoneAccount = getAccountFromMarshmallowAccount(context, mPhoneAccount);
- if (mPhoneAccount == null) {
- VvmLog.w(TAG, "Account not registered - cannot retrieve message.");
- return;
- }
- VvmLog.i(TAG, "Fetching voicemail with Marshmallow PhoneAccountHandle");
- }
-
- int subId = PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccount);
- OmtpVvmCarrierConfigHelper carrierConfigHelper =
- new OmtpVvmCarrierConfigHelper(context, subId);
- VvmLog.i(TAG, "Requesting network to fetch voicemail");
- mNetworkCallback = new fetchVoicemailNetworkRequestCallback(context,
- mPhoneAccount);
- mNetworkCallback.requestNetwork();
- }
- } finally {
- cursor.close();
- }
- }
- }
-
- /**
- * In ag/930496 the format of PhoneAccountHandle has changed between Marshmallow and Nougat.
- * This method attempts to search the account from the old database in registered sources using
- * the old format. There's a chance of M phone account collisions on multi-SIM devices, but
- * visual voicemail is not supported on M multi-SIM.
- */
- @Nullable
- private static PhoneAccountHandle getAccountFromMarshmallowAccount(Context context,
- PhoneAccountHandle oldAccount) {
- for (PhoneAccountHandle handle : OmtpVvmSourceManager.getInstance(context)
- .getOmtpVvmSources()) {
- Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(handle);
- if (phone == null) {
- continue;
- }
- // getIccSerialNumber() is used for ID before N, and getFullIccSerialNumber() after.
- if (phone.getIccSerialNumber().equals(oldAccount.getId())) {
- return handle;
- }
- }
- return null;
- }
-
- private class fetchVoicemailNetworkRequestCallback extends VvmNetworkRequestCallback {
-
- public fetchVoicemailNetworkRequestCallback(Context context,
- PhoneAccountHandle phoneAccount) {
- super(context, phoneAccount, VoicemailStatus.edit(context, phoneAccount));
- }
-
- @Override
- public void onAvailable(final Network network) {
- super.onAvailable(network);
- fetchVoicemail(network, getVoicemailStatusEditor());
- }
- }
-
- private void fetchVoicemail(final Network network, final VoicemailStatus.Editor status) {
- Executor executor = Executors.newCachedThreadPool();
- executor.execute(new Runnable() {
- @Override
- public void run() {
- try {
- while (mRetryCount > 0) {
- VvmLog.i(TAG, "fetching voicemail, retry count=" + mRetryCount);
- try (ImapHelper imapHelper = new ImapHelper(mContext, mPhoneAccount,
- network, status)) {
- boolean success = imapHelper.fetchVoicemailPayload(
- new VoicemailFetchedCallback(mContext, mUri, mPhoneAccount),
- mUid);
- if (!success && mRetryCount > 0) {
- VvmLog.i(TAG, "fetch voicemail failed, retrying");
- mRetryCount--;
- } else {
- return;
- }
- } catch (InitializingException e) {
- VvmLog.w(TAG, "Can't retrieve Imap credentials ", e);
- return;
- }
- }
- } finally {
- if (mNetworkCallback != null) {
- mNetworkCallback.releaseNetwork();
- }
- }
- }
- });
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/fetch/VoicemailFetchedCallback.java b/src/com/android/phone/vvm/omtp/fetch/VoicemailFetchedCallback.java
deleted file mode 100644
index e70ba49..0000000
--- a/src/com/android/phone/vvm/omtp/fetch/VoicemailFetchedCallback.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.fetch;
-
-import android.annotation.Nullable;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.net.Uri;
-import android.provider.VoicemailContract.Voicemails;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
-import com.android.phone.R;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.imap.VoicemailPayload;
-import java.io.IOException;
-import java.io.OutputStream;
-import libcore.io.IoUtils;
-
-/**
- * Callback for when a voicemail payload is fetched. It copies the returned stream to the data
- * file corresponding to the voicemail.
- */
-public class VoicemailFetchedCallback {
- private static final String TAG = "VoicemailFetchedCallback";
-
- private final Context mContext;
- private final ContentResolver mContentResolver;
- private final Uri mUri;
- private final PhoneAccountHandle mPhoneAccountHandle;
-
- public VoicemailFetchedCallback(Context context, Uri uri,
- PhoneAccountHandle phoneAccountHandle) {
- mContext = context;
- mContentResolver = context.getContentResolver();
- mUri = uri;
- mPhoneAccountHandle = phoneAccountHandle;
- }
-
- /**
- * Saves the voicemail payload data into the voicemail provider then sets the "has_content" bit
- * of the voicemail to "1".
- *
- * @param voicemailPayload The object containing the content data for the voicemail
- */
- public void setVoicemailContent(@Nullable VoicemailPayload voicemailPayload) {
- if (voicemailPayload == null) {
- VvmLog.i(TAG, "Payload not found, message has unsupported format");
- ContentValues values = new ContentValues();
- values.put(Voicemails.TRANSCRIPTION,
- mContext.getString(R.string.vvm_unsupported_message_format,
- TelecomManager.from(mContext).getVoiceMailNumber(mPhoneAccountHandle)));
- updateVoicemail(values);
- return;
- }
-
- VvmLog.d(TAG, String.format("Writing new voicemail content: %s", mUri));
- OutputStream outputStream = null;
-
- try {
- outputStream = mContentResolver.openOutputStream(mUri);
- byte[] inputBytes = voicemailPayload.getBytes();
- if (inputBytes != null) {
- outputStream.write(inputBytes);
- }
- } catch (IOException e) {
- VvmLog.w(TAG, String.format("File not found for %s", mUri));
- return;
- } finally {
- IoUtils.closeQuietly(outputStream);
- }
-
- // Update mime_type & has_content after we are done with file update.
- ContentValues values = new ContentValues();
- values.put(Voicemails.MIME_TYPE, voicemailPayload.getMimeType());
- values.put(Voicemails.HAS_CONTENT, true);
- updateVoicemail(values);
- }
-
- private void updateVoicemail(ContentValues values) {
- int updatedCount = mContentResolver.update(mUri, values, null, null);
- if (updatedCount != 1) {
- VvmLog
- .e(TAG, "Updating voicemail should have updated 1 row, was: " + updatedCount);
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
deleted file mode 100644
index a03e421..0000000
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ /dev/null
@@ -1,705 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.imap;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkInfo;
-import android.provider.VoicemailContract;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.Voicemail;
-import android.util.Base64;
-import com.android.phone.PhoneUtils;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.common.mail.Address;
-import com.android.phone.common.mail.Body;
-import com.android.phone.common.mail.BodyPart;
-import com.android.phone.common.mail.FetchProfile;
-import com.android.phone.common.mail.Flag;
-import com.android.phone.common.mail.Message;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.common.mail.Multipart;
-import com.android.phone.common.mail.TempDirectory;
-import com.android.phone.common.mail.internet.MimeMessage;
-import com.android.phone.common.mail.store.ImapConnection;
-import com.android.phone.common.mail.store.ImapFolder;
-import com.android.phone.common.mail.store.ImapStore;
-import com.android.phone.common.mail.store.imap.ImapConstants;
-import com.android.phone.common.mail.store.imap.ImapResponse;
-import com.android.phone.common.mail.utils.LogUtils;
-import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.OmtpConstants.ChangePinResult;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
-import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService.TranscriptionFetchedCallback;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-import libcore.io.IoUtils;
-
-/**
- * A helper interface to abstract commands sent across IMAP interface for a given account.
- */
-public class ImapHelper implements Closeable {
-
- private static final String TAG = "ImapHelper";
-
- private ImapFolder mFolder;
- private ImapStore mImapStore;
-
- private final Context mContext;
- private final PhoneAccountHandle mPhoneAccount;
- private final Network mNetwork;
- private final VoicemailStatus.Editor mStatus;
-
- VisualVoicemailPreferences mPrefs;
- private static final String PREF_KEY_QUOTA_OCCUPIED = "quota_occupied_";
- private static final String PREF_KEY_QUOTA_TOTAL = "quota_total_";
-
- private int mQuotaOccupied;
- private int mQuotaTotal;
-
- private final OmtpVvmCarrierConfigHelper mConfig;
-
- public class InitializingException extends Exception {
-
- public InitializingException(String message) {
- super(message);
- }
- }
-
- public ImapHelper(Context context, PhoneAccountHandle phoneAccount, Network network,
- VoicemailStatus.Editor status)
- throws InitializingException {
- this(context, new OmtpVvmCarrierConfigHelper(context,
- PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount)), phoneAccount, network, status);
- }
-
- public ImapHelper(Context context, OmtpVvmCarrierConfigHelper config,
- PhoneAccountHandle phoneAccount, Network network, VoicemailStatus.Editor status)
- throws InitializingException {
- mContext = context;
- mPhoneAccount = phoneAccount;
- mNetwork = network;
- mStatus = status;
- mConfig = config;
- mPrefs = new VisualVoicemailPreferences(context,
- phoneAccount);
-
- try {
- TempDirectory.setTempDirectory(context);
-
- String username = mPrefs.getString(OmtpConstants.IMAP_USER_NAME, null);
- String password = mPrefs.getString(OmtpConstants.IMAP_PASSWORD, null);
- String serverName = mPrefs.getString(OmtpConstants.SERVER_ADDRESS, null);
- int port = Integer.parseInt(
- mPrefs.getString(OmtpConstants.IMAP_PORT, null));
- int auth = ImapStore.FLAG_NONE;
-
- int sslPort = mConfig.getSslPort();
- if (sslPort != 0) {
- port = sslPort;
- auth = ImapStore.FLAG_SSL;
- }
-
- mImapStore = new ImapStore(
- context, this, username, password, port, serverName, auth, network);
- } catch (NumberFormatException e) {
- handleEvent(OmtpEvents.DATA_INVALID_PORT);
- LogUtils.w(TAG, "Could not parse port number");
- throw new InitializingException("cannot initialize ImapHelper:" + e.toString());
- }
-
- mQuotaOccupied = mPrefs
- .getInt(PREF_KEY_QUOTA_OCCUPIED, VoicemailContract.Status.QUOTA_UNAVAILABLE);
- mQuotaTotal = mPrefs
- .getInt(PREF_KEY_QUOTA_TOTAL, VoicemailContract.Status.QUOTA_UNAVAILABLE);
- }
-
- @Override
- public void close() {
- mImapStore.closeConnection();
- }
-
- public boolean isRoaming() {
- ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- NetworkInfo info = connectivityManager.getNetworkInfo(mNetwork);
- if (info == null) {
- return false;
- }
- return info.isRoaming();
- }
-
- public OmtpVvmCarrierConfigHelper getConfig() {
- return mConfig;
- }
-
- public ImapConnection connect() {
- return mImapStore.getConnection();
- }
-
- /**
- * The caller thread will block until the method returns.
- */
- public boolean markMessagesAsRead(List<Voicemail> voicemails) {
- return setFlags(voicemails, Flag.SEEN);
- }
-
- /**
- * The caller thread will block until the method returns.
- */
- public boolean markMessagesAsDeleted(List<Voicemail> voicemails) {
- return setFlags(voicemails, Flag.DELETED);
- }
-
- public void handleEvent(OmtpEvents event) {
- mConfig.handleEvent(mStatus, event);
- }
-
- /**
- * Set flags on the server for a given set of voicemails.
- *
- * @param voicemails The voicemails to set flags for.
- * @param flags The flags to set on the voicemails.
- * @return {@code true} if the operation completes successfully, {@code false} otherwise.
- */
- private boolean setFlags(List<Voicemail> voicemails, String... flags) {
- if (voicemails.size() == 0) {
- return false;
- }
- try {
- mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE);
- if (mFolder != null) {
- mFolder.setFlags(convertToImapMessages(voicemails), flags, true);
- return true;
- }
- return false;
- } catch (MessagingException e) {
- LogUtils.e(TAG, e, "Messaging exception");
- return false;
- } finally {
- closeImapFolder();
- }
- }
-
- /**
- * Fetch a list of voicemails from the server.
- *
- * @return A list of voicemail objects containing data about voicemails stored on the server.
- */
- public List<Voicemail> fetchAllVoicemails() {
- List<Voicemail> result = new ArrayList<Voicemail>();
- Message[] messages;
- try {
- mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE);
- if (mFolder == null) {
- // This means we were unable to successfully open the folder.
- return null;
- }
-
- // This method retrieves lightweight messages containing only the uid of the message.
- messages = mFolder.getMessages(null);
-
- for (Message message : messages) {
- // Get the voicemail details (message structure).
- MessageStructureWrapper messageStructureWrapper = fetchMessageStructure(message);
- if (messageStructureWrapper != null) {
- result.add(getVoicemailFromMessageStructure(messageStructureWrapper));
- }
- }
- return result;
- } catch (MessagingException e) {
- LogUtils.e(TAG, e, "Messaging Exception");
- return null;
- } finally {
- closeImapFolder();
- }
- }
-
- /**
- * Extract voicemail details from the message structure. Also fetch transcription if a
- * transcription exists.
- */
- private Voicemail getVoicemailFromMessageStructure(
- MessageStructureWrapper messageStructureWrapper) throws MessagingException {
- Message messageDetails = messageStructureWrapper.messageStructure;
-
- TranscriptionFetchedListener listener = new TranscriptionFetchedListener();
- if (messageStructureWrapper.transcriptionBodyPart != null) {
- FetchProfile fetchProfile = new FetchProfile();
- fetchProfile.add(messageStructureWrapper.transcriptionBodyPart);
-
- mFolder.fetch(new Message[]{messageDetails}, fetchProfile, listener);
- }
-
- // Found an audio attachment, this is a valid voicemail.
- long time = messageDetails.getSentDate().getTime();
- String number = getNumber(messageDetails.getFrom());
- boolean isRead = Arrays.asList(messageDetails.getFlags()).contains(Flag.SEEN);
- return Voicemail.createForInsertion(time, number)
- .setPhoneAccount(mPhoneAccount)
- .setSourcePackage(mContext.getPackageName())
- .setSourceData(messageDetails.getUid())
- .setIsRead(isRead)
- .setTranscription(listener.getVoicemailTranscription())
- .build();
- }
-
- /**
- * The "from" field of a visual voicemail IMAP message is the number of the caller who left the
- * message. Extract this number from the list of "from" addresses.
- *
- * @param fromAddresses A list of addresses that comprise the "from" line.
- * @return The number of the voicemail sender.
- */
- private String getNumber(Address[] fromAddresses) {
- if (fromAddresses != null && fromAddresses.length > 0) {
- if (fromAddresses.length != 1) {
- LogUtils.w(TAG, "More than one from addresses found. Using the first one.");
- }
- String sender = fromAddresses[0].getAddress();
- int atPos = sender.indexOf('@');
- if (atPos != -1) {
- // Strip domain part of the address.
- sender = sender.substring(0, atPos);
- }
- return sender;
- }
- return null;
- }
-
- /**
- * Fetches the structure of the given message and returns a wrapper containing the message
- * structure and the transcription structure (if applicable).
- *
- * @throws MessagingException if fetching the structure of the message fails
- */
- private MessageStructureWrapper fetchMessageStructure(Message message)
- throws MessagingException {
- LogUtils.d(TAG, "Fetching message structure for " + message.getUid());
-
- MessageStructureFetchedListener listener = new MessageStructureFetchedListener();
-
- FetchProfile fetchProfile = new FetchProfile();
- fetchProfile.addAll(Arrays.asList(FetchProfile.Item.FLAGS, FetchProfile.Item.ENVELOPE,
- FetchProfile.Item.STRUCTURE));
-
- // The IMAP folder fetch method will call "messageRetrieved" on the listener when the
- // message is successfully retrieved.
- mFolder.fetch(new Message[]{message}, fetchProfile, listener);
- return listener.getMessageStructure();
- }
-
- public boolean fetchVoicemailPayload(VoicemailFetchedCallback callback, final String uid) {
- try {
- mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE);
- if (mFolder == null) {
- // This means we were unable to successfully open the folder.
- return false;
- }
- Message message = mFolder.getMessage(uid);
- if (message == null) {
- return false;
- }
- VoicemailPayload voicemailPayload = fetchVoicemailPayload(message);
- callback.setVoicemailContent(voicemailPayload);
- return true;
- } catch (MessagingException e) {
- } finally {
- closeImapFolder();
- }
- return false;
- }
-
- /**
- * Fetches the body of the given message and returns the parsed voicemail payload.
- *
- * @throws MessagingException if fetching the body of the message fails
- */
- private VoicemailPayload fetchVoicemailPayload(Message message)
- throws MessagingException {
- LogUtils.d(TAG, "Fetching message body for " + message.getUid());
-
- MessageBodyFetchedListener listener = new MessageBodyFetchedListener();
-
- FetchProfile fetchProfile = new FetchProfile();
- fetchProfile.add(FetchProfile.Item.BODY);
-
- mFolder.fetch(new Message[]{message}, fetchProfile, listener);
- return listener.getVoicemailPayload();
- }
-
- public boolean fetchTranscription(TranscriptionFetchedCallback callback, String uid) {
- try {
- mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE);
- if (mFolder == null) {
- // This means we were unable to successfully open the folder.
- return false;
- }
-
- Message message = mFolder.getMessage(uid);
- if (message == null) {
- return false;
- }
-
- MessageStructureWrapper messageStructureWrapper = fetchMessageStructure(message);
- if (messageStructureWrapper != null) {
- TranscriptionFetchedListener listener = new TranscriptionFetchedListener();
- if (messageStructureWrapper.transcriptionBodyPart != null) {
- FetchProfile fetchProfile = new FetchProfile();
- fetchProfile.add(messageStructureWrapper.transcriptionBodyPart);
-
- // This method is called synchronously so the transcription will be populated
- // in the listener once the next method is called.
- mFolder.fetch(new Message[]{message}, fetchProfile, listener);
- callback.setVoicemailTranscription(listener.getVoicemailTranscription());
- }
- }
- return true;
- } catch (MessagingException e) {
- LogUtils.e(TAG, e, "Messaging Exception");
- return false;
- } finally {
- closeImapFolder();
- }
- }
-
-
- @ChangePinResult
- public int changePin(String oldPin, String newPin)
- throws MessagingException {
- ImapConnection connection = mImapStore.getConnection();
- try {
- String command = getConfig().getProtocol()
- .getCommand(OmtpConstants.IMAP_CHANGE_TUI_PWD_FORMAT);
- connection.sendCommand(
- String.format(Locale.US, command, newPin, oldPin), true);
- return getChangePinResultFromImapResponse(connection.readResponse());
- } catch (IOException ioe) {
- VvmLog.e(TAG, "changePin: ", ioe);
- return OmtpConstants.CHANGE_PIN_SYSTEM_ERROR;
- } finally {
- connection.destroyResponses();
- }
- }
-
- public void changeVoicemailTuiLanguage(String languageCode)
- throws MessagingException {
- ImapConnection connection = mImapStore.getConnection();
- try {
- String command = getConfig().getProtocol()
- .getCommand(OmtpConstants.IMAP_CHANGE_VM_LANG_FORMAT);
- connection.sendCommand(
- String.format(Locale.US, command, languageCode), true);
- } catch (IOException ioe) {
- LogUtils.e(TAG, ioe.toString());
- } finally {
- connection.destroyResponses();
- }
- }
-
- public void closeNewUserTutorial() throws MessagingException {
- ImapConnection connection = mImapStore.getConnection();
- try {
- String command = getConfig().getProtocol()
- .getCommand(OmtpConstants.IMAP_CLOSE_NUT);
- connection.executeSimpleCommand(command, false);
- } catch (IOException ioe) {
- throw new MessagingException(MessagingException.SERVER_ERROR, ioe.toString());
- } finally {
- connection.destroyResponses();
- }
- }
-
- @ChangePinResult
- private static int getChangePinResultFromImapResponse(ImapResponse response)
- throws MessagingException {
- if (!response.isTagged()) {
- throw new MessagingException(MessagingException.SERVER_ERROR,
- "tagged response expected");
- }
- if (!response.isOk()) {
- String message = response.getStringOrEmpty(1).getString();
- LogUtils.d(TAG, "change PIN failed: " + message);
- if (OmtpConstants.RESPONSE_CHANGE_PIN_TOO_SHORT.equals(message)) {
- return OmtpConstants.CHANGE_PIN_TOO_SHORT;
- }
- if (OmtpConstants.RESPONSE_CHANGE_PIN_TOO_LONG.equals(message)) {
- return OmtpConstants.CHANGE_PIN_TOO_LONG;
- }
- if (OmtpConstants.RESPONSE_CHANGE_PIN_TOO_WEAK.equals(message)) {
- return OmtpConstants.CHANGE_PIN_TOO_WEAK;
- }
- if (OmtpConstants.RESPONSE_CHANGE_PIN_MISMATCH.equals(message)) {
- return OmtpConstants.CHANGE_PIN_MISMATCH;
- }
- if (OmtpConstants.RESPONSE_CHANGE_PIN_INVALID_CHARACTER.equals(message)) {
- return OmtpConstants.CHANGE_PIN_INVALID_CHARACTER;
- }
- return OmtpConstants.CHANGE_PIN_SYSTEM_ERROR;
- }
- LogUtils.d(TAG, "change PIN succeeded");
- return OmtpConstants.CHANGE_PIN_SUCCESS;
- }
-
- public void updateQuota() {
- try {
- mFolder = openImapFolder(ImapFolder.MODE_READ_WRITE);
- if (mFolder == null) {
- // This means we were unable to successfully open the folder.
- return;
- }
- updateQuota(mFolder);
- } catch (MessagingException e) {
- LogUtils.e(TAG, e, "Messaging Exception");
- } finally {
- closeImapFolder();
- }
- }
-
- private void updateQuota(ImapFolder folder) throws MessagingException {
- setQuota(folder.getQuota());
- }
-
- private void setQuota(ImapFolder.Quota quota) {
- if (quota == null) {
- return;
- }
- if (quota.occupied == mQuotaOccupied && quota.total == mQuotaTotal) {
- VvmLog.v(TAG, "Quota hasn't changed");
- return;
- }
- mQuotaOccupied = quota.occupied;
- mQuotaTotal = quota.total;
- VoicemailStatus.edit(mContext, mPhoneAccount)
- .setQuota(mQuotaOccupied, mQuotaTotal)
- .apply();
- mPrefs.edit()
- .putInt(PREF_KEY_QUOTA_OCCUPIED, mQuotaOccupied)
- .putInt(PREF_KEY_QUOTA_TOTAL, mQuotaTotal)
- .apply();
- VvmLog.v(TAG, "Quota changed to " + mQuotaOccupied + "/" + mQuotaTotal);
- }
-
- /**
- * A wrapper to hold a message with its header details and the structure for transcriptions (so
- * they can be fetched in the future).
- */
- public class MessageStructureWrapper {
-
- public Message messageStructure;
- public BodyPart transcriptionBodyPart;
-
- public MessageStructureWrapper() {
- }
- }
-
- /**
- * Listener for the message structure being fetched.
- */
- private final class MessageStructureFetchedListener
- implements ImapFolder.MessageRetrievalListener {
-
- private MessageStructureWrapper mMessageStructure;
-
- public MessageStructureFetchedListener() {
- }
-
- public MessageStructureWrapper getMessageStructure() {
- return mMessageStructure;
- }
-
- @Override
- public void messageRetrieved(Message message) {
- LogUtils.d(TAG, "Fetched message structure for " + message.getUid());
- LogUtils.d(TAG, "Message retrieved: " + message);
- try {
- mMessageStructure = getMessageOrNull(message);
- if (mMessageStructure == null) {
- LogUtils.d(TAG, "This voicemail does not have an attachment...");
- return;
- }
- } catch (MessagingException e) {
- LogUtils.e(TAG, e, "Messaging Exception");
- closeImapFolder();
- }
- }
-
- /**
- * Check if this IMAP message is a valid voicemail and whether it contains a transcription.
- *
- * @param message The IMAP message.
- * @return The MessageStructureWrapper object corresponding to an IMAP message and
- * transcription.
- */
- private MessageStructureWrapper getMessageOrNull(Message message)
- throws MessagingException {
- if (!message.getMimeType().startsWith("multipart/")) {
- LogUtils.w(TAG, "Ignored non multi-part message");
- return null;
- }
-
- MessageStructureWrapper messageStructureWrapper = new MessageStructureWrapper();
-
- Multipart multipart = (Multipart) message.getBody();
- for (int i = 0; i < multipart.getCount(); ++i) {
- BodyPart bodyPart = multipart.getBodyPart(i);
- String bodyPartMimeType = bodyPart.getMimeType().toLowerCase();
- LogUtils.d(TAG, "bodyPart mime type: " + bodyPartMimeType);
-
- if (bodyPartMimeType.startsWith("audio/")) {
- messageStructureWrapper.messageStructure = message;
- } else if (bodyPartMimeType.startsWith("text/")) {
- messageStructureWrapper.transcriptionBodyPart = bodyPart;
- } else {
- VvmLog.v(TAG, "Unknown bodyPart MIME: " + bodyPartMimeType);
- }
- }
-
- if (messageStructureWrapper.messageStructure != null) {
- return messageStructureWrapper;
- }
-
- // No attachment found, this is not a voicemail.
- return null;
- }
- }
-
- /**
- * Listener for the message body being fetched.
- */
- private final class MessageBodyFetchedListener implements ImapFolder.MessageRetrievalListener {
-
- private VoicemailPayload mVoicemailPayload;
-
- /**
- * Returns the fetch voicemail payload.
- */
- public VoicemailPayload getVoicemailPayload() {
- return mVoicemailPayload;
- }
-
- @Override
- public void messageRetrieved(Message message) {
- LogUtils.d(TAG, "Fetched message body for " + message.getUid());
- LogUtils.d(TAG, "Message retrieved: " + message);
- try {
- mVoicemailPayload = getVoicemailPayloadFromMessage(message);
- } catch (MessagingException e) {
- LogUtils.e(TAG, "Messaging Exception:", e);
- } catch (IOException e) {
- LogUtils.e(TAG, "IO Exception:", e);
- }
- }
-
- private VoicemailPayload getVoicemailPayloadFromMessage(Message message)
- throws MessagingException, IOException {
- Multipart multipart = (Multipart) message.getBody();
- List<String> mimeTypes = new ArrayList<>();
- for (int i = 0; i < multipart.getCount(); ++i) {
- BodyPart bodyPart = multipart.getBodyPart(i);
- String bodyPartMimeType = bodyPart.getMimeType().toLowerCase();
- mimeTypes.add(bodyPartMimeType);
- if (bodyPartMimeType.startsWith("audio/")) {
- byte[] bytes = getDataFromBody(bodyPart.getBody());
- LogUtils.d(TAG, String.format("Fetched %s bytes of data", bytes.length));
- return new VoicemailPayload(bodyPartMimeType, bytes);
- }
- }
- LogUtils.e(TAG, "No audio attachment found on this voicemail, mimeTypes:" + mimeTypes);
- return null;
- }
- }
-
- /**
- * Listener for the transcription being fetched.
- */
- private final class TranscriptionFetchedListener implements
- ImapFolder.MessageRetrievalListener {
-
- private String mVoicemailTranscription;
-
- /**
- * Returns the fetched voicemail transcription.
- */
- public String getVoicemailTranscription() {
- return mVoicemailTranscription;
- }
-
- @Override
- public void messageRetrieved(Message message) {
- LogUtils.d(TAG, "Fetched transcription for " + message.getUid());
- try {
- mVoicemailTranscription = new String(getDataFromBody(message.getBody()));
- } catch (MessagingException e) {
- LogUtils.e(TAG, "Messaging Exception:", e);
- } catch (IOException e) {
- LogUtils.e(TAG, "IO Exception:", e);
- }
- }
- }
-
- private ImapFolder openImapFolder(String modeReadWrite) {
- try {
- if (mImapStore == null) {
- return null;
- }
- ImapFolder folder = new ImapFolder(mImapStore, ImapConstants.INBOX);
- folder.open(modeReadWrite);
- return folder;
- } catch (MessagingException e) {
- LogUtils.e(TAG, e, "Messaging Exception");
- }
- return null;
- }
-
- private Message[] convertToImapMessages(List<Voicemail> voicemails) {
- Message[] messages = new Message[voicemails.size()];
- for (int i = 0; i < voicemails.size(); ++i) {
- messages[i] = new MimeMessage();
- messages[i].setUid(voicemails.get(i).getSourceData());
- }
- return messages;
- }
-
- private void closeImapFolder() {
- if (mFolder != null) {
- mFolder.close(true);
- }
- }
-
- private byte[] getDataFromBody(Body body) throws IOException, MessagingException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- BufferedOutputStream bufferedOut = new BufferedOutputStream(out);
- try {
- body.writeTo(bufferedOut);
- return Base64.decode(out.toByteArray(), Base64.DEFAULT);
- } finally {
- IoUtils.closeQuietly(bufferedOut);
- IoUtils.closeQuietly(out);
- }
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/imap/VoicemailPayload.java b/src/com/android/phone/vvm/omtp/imap/VoicemailPayload.java
deleted file mode 100644
index 0ffa018..0000000
--- a/src/com/android/phone/vvm/omtp/imap/VoicemailPayload.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.imap;
-
-/**
- * The payload for a voicemail, usually audio data.
- */
-public class VoicemailPayload {
- private final String mMimeType;
- private final byte[] mBytes;
-
- public VoicemailPayload(String mimeType, byte[] bytes) {
- mMimeType = mimeType;
- mBytes = bytes;
- }
-
- public byte[] getBytes() {
- return mBytes;
- }
-
- public String getMimeType() {
- return mMimeType;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/protocol/CvvmProtocol.java b/src/com/android/phone/vvm/omtp/protocol/CvvmProtocol.java
deleted file mode 100644
index 9960b18..0000000
--- a/src/com/android/phone/vvm/omtp/protocol/CvvmProtocol.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.protocol;
-
-import android.telephony.SmsManager;
-
-import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.sms.OmtpCvvmMessageSender;
-import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
-
-/**
- * A flavor of OMTP protocol with a different mobile originated (MO) format
- *
- * Used by carriers such as T-Mobile
- */
-public class CvvmProtocol extends VisualVoicemailProtocol {
-
- private static String IMAP_CHANGE_TUI_PWD_FORMAT = "CHANGE_TUI_PWD PWD=%1$s OLD_PWD=%2$s";
- private static String IMAP_CHANGE_VM_LANG_FORMAT = "CHANGE_VM_LANG Lang=%1$s";
- private static String IMAP_CLOSE_NUT = "CLOSE_NUT";
-
- @Override
- public OmtpMessageSender createMessageSender(SmsManager smsManager, short applicationPort,
- String destinationNumber) {
- return new OmtpCvvmMessageSender(smsManager, applicationPort, destinationNumber);
- }
-
- @Override
- public String getCommand(String command) {
- if (command == OmtpConstants.IMAP_CHANGE_TUI_PWD_FORMAT) {
- return IMAP_CHANGE_TUI_PWD_FORMAT;
- }
- if (command == OmtpConstants.IMAP_CLOSE_NUT) {
- return IMAP_CLOSE_NUT;
- }
- if (command == OmtpConstants.IMAP_CHANGE_VM_LANG_FORMAT) {
- return IMAP_CHANGE_VM_LANG_FORMAT;
- }
- return super.getCommand(command);
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/protocol/OmtpProtocol.java b/src/com/android/phone/vvm/omtp/protocol/OmtpProtocol.java
deleted file mode 100644
index 7ec3dba..0000000
--- a/src/com/android/phone/vvm/omtp/protocol/OmtpProtocol.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.protocol;
-
-import android.telephony.SmsManager;
-
-import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
-import com.android.phone.vvm.omtp.sms.OmtpStandardMessageSender;
-
-public class OmtpProtocol extends VisualVoicemailProtocol {
-
- @Override
- public OmtpMessageSender createMessageSender(SmsManager smsManager, short applicationPort,
- String destinationNumber) {
- return new OmtpStandardMessageSender(smsManager, applicationPort, destinationNumber,
- OmtpConstants.CLIENT_TYPE_GOOGLE_10, OmtpConstants.PROTOCOL_VERSION1_1,
- null /*clientPrefix*/);
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/protocol/ProtocolHelper.java b/src/com/android/phone/vvm/omtp/protocol/ProtocolHelper.java
deleted file mode 100644
index 748fd39..0000000
--- a/src/com/android/phone/vvm/omtp/protocol/ProtocolHelper.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.protocol;
-
-import android.telephony.SmsManager;
-import android.text.TextUtils;
-
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
-
-public class ProtocolHelper {
-
- private static final String TAG = "ProtocolHelper";
-
- public static OmtpMessageSender getMessageSender(VisualVoicemailProtocol protocol,
- OmtpVvmCarrierConfigHelper config) {
-
- int applicationPort = config.getApplicationPort();
- String destinationNumber = config.getDestinationNumber();
- if (TextUtils.isEmpty(destinationNumber)) {
- VvmLog.w(TAG, "No destination number for this carrier.");
- return null;
- }
-
- SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(config.getSubId());
- return protocol.createMessageSender(smsManager, (short) applicationPort, destinationNumber);
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
deleted file mode 100644
index 6e6d6ef..0000000
--- a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocol.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.protocol;
-
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.os.Bundle;
-import android.telecom.PhoneAccountHandle;
-import android.telephony.SmsManager;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.omtp.ActivationTask;
-import com.android.phone.vvm.omtp.DefaultOmtpEventHandler;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
-import com.android.phone.vvm.omtp.sms.StatusMessage;
-
-public abstract class VisualVoicemailProtocol {
-
- /**
- * Activation should cause the carrier to respond with a STATUS SMS.
- */
- public void startActivation(OmtpVvmCarrierConfigHelper config, PendingIntent sentIntent) {
- OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config);
- if (messageSender != null) {
- messageSender.requestVvmActivation(sentIntent);
- }
- }
-
- public void startDeactivation(OmtpVvmCarrierConfigHelper config) {
- OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config);
- if (messageSender != null) {
- messageSender.requestVvmDeactivation(null);
- }
- }
-
- public boolean supportsProvisioning() {
- return false;
- }
-
- public void startProvisioning(ActivationTask task, PhoneAccountHandle handle,
- OmtpVvmCarrierConfigHelper config, VoicemailStatus.Editor editor, StatusMessage message,
- Bundle data) {
- // Do nothing
- }
-
- public void requestStatus(OmtpVvmCarrierConfigHelper config,
- @Nullable PendingIntent sentIntent) {
- OmtpMessageSender messageSender = ProtocolHelper.getMessageSender(this, config);
- if (messageSender != null) {
- messageSender.requestVvmStatus(sentIntent);
- }
- }
-
- public abstract OmtpMessageSender createMessageSender(SmsManager smsManager,
- short applicationPort, String destinationNumber);
-
- /**
- * Translate an OMTP IMAP command to the protocol specific one. For example, changing the TUI
- * password on OMTP is XCHANGE_TUI_PWD, but on CVVM and VVM3 it is CHANGE_TUI_PWD.
- *
- * @param command A String command in {@link com.android.phone.vvm.omtp.OmtpConstants}, the exact
- * instance should be used instead of its' value.
- * @returns Translated command, or {@code null} if not available in this protocol
- */
- public String getCommand(String command) {
- return command;
- }
-
- public void handleEvent(Context context, OmtpVvmCarrierConfigHelper config,
- VoicemailStatus.Editor status, OmtpEvents event) {
- DefaultOmtpEventHandler.handleEvent(context, config, status, event);
- }
-
- /**
- * Given an VVM SMS with an unknown {@code event}, let the protocol attempt to translate it into
- * an equivalent STATUS SMS. Returns {@code null} if it cannot be translated.
- */
- @Nullable
- public Bundle translateStatusSmsBundle(OmtpVvmCarrierConfigHelper config, String event,
- Bundle data) {
- return null;
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocolFactory.java b/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocolFactory.java
deleted file mode 100644
index 4d39ae2..0000000
--- a/src/com/android/phone/vvm/omtp/protocol/VisualVoicemailProtocolFactory.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.protocol;
-
-import android.annotation.Nullable;
-import android.content.res.Resources;
-import android.telephony.TelephonyManager;
-
-import com.android.phone.R;
-import com.android.phone.vvm.omtp.VvmLog;
-
-public class VisualVoicemailProtocolFactory {
-
- private static final String TAG = "VvmProtocolFactory";
-
- private static final String VVM_TYPE_VVM3 = "vvm_type_vvm3";
-
- @Nullable
- public static VisualVoicemailProtocol create(Resources resources, String type) {
- if (type == null) {
- return null;
- }
- switch (type) {
- case TelephonyManager.VVM_TYPE_OMTP:
- return new OmtpProtocol();
- case TelephonyManager.VVM_TYPE_CVVM:
- return new CvvmProtocol();
- case VVM_TYPE_VVM3:
- if (resources.getBoolean(R.bool.vvm3_enabled)) {
- return new Vvm3Protocol();
- } else {
- VvmLog.e(TAG, "VVM3 is disabled");
- return null;
- }
- default:
- VvmLog.e(TAG, "Unexpected visual voicemail type: " + type);
- }
- return null;
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java
deleted file mode 100644
index 524c96d..0000000
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.protocol;
-
-import android.annotation.IntDef;
-import android.content.Context;
-import android.provider.VoicemailContract.Status;
-import android.telecom.PhoneAccountHandle;
-import android.util.Log;
-
-import com.android.phone.VoicemailStatus;
-import com.android.phone.settings.VoicemailChangePinActivity;
-import com.android.phone.vvm.omtp.DefaultOmtpEventHandler;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.OmtpEvents.Type;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Handles {@link OmtpEvents} when {@link Vvm3Protocol} is being used. This handler writes custom
- * error codes into the voicemail status table so support on the dialer side is required.
- *
- * TODO(b/29577838) disable VVM3 by default so support on system dialer can be ensured.
- */
-public class Vvm3EventHandler {
-
- private static final String TAG = "Vvm3EventHandler";
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({VMS_DNS_FAILURE, VMG_DNS_FAILURE, SPG_DNS_FAILURE, VMS_NO_CELLULAR, VMG_NO_CELLULAR,
- SPG_NO_CELLULAR, VMS_TIMEOUT, VMG_TIMEOUT, STATUS_SMS_TIMEOUT, SUBSCRIBER_BLOCKED,
- UNKNOWN_USER, UNKNOWN_DEVICE, INVALID_PASSWORD, MAILBOX_NOT_INITIALIZED,
- SERVICE_NOT_PROVISIONED, SERVICE_NOT_ACTIVATED, USER_BLOCKED, IMAP_GETQUOTA_ERROR,
- IMAP_SELECT_ERROR, IMAP_ERROR, VMG_INTERNAL_ERROR, VMG_DB_ERROR,
- VMG_COMMUNICATION_ERROR, SPG_URL_NOT_FOUND, VMG_UNKNOWN_ERROR, PIN_NOT_SET})
- public @interface ErrorCode {
-
- }
-
- public static final int VMS_DNS_FAILURE = -9001;
- public static final int VMG_DNS_FAILURE = -9002;
- public static final int SPG_DNS_FAILURE = -9003;
- public static final int VMS_NO_CELLULAR = -9004;
- public static final int VMG_NO_CELLULAR = -9005;
- public static final int SPG_NO_CELLULAR = -9006;
- public static final int VMS_TIMEOUT = -9007;
- public static final int VMG_TIMEOUT = -9008;
- public static final int STATUS_SMS_TIMEOUT = -9009;
-
- public static final int SUBSCRIBER_BLOCKED = -9990;
- public static final int UNKNOWN_USER = -9991;
- public static final int UNKNOWN_DEVICE = -9992;
- public static final int INVALID_PASSWORD = -9993;
- public static final int MAILBOX_NOT_INITIALIZED = -9994;
- public static final int SERVICE_NOT_PROVISIONED = -9995;
- public static final int SERVICE_NOT_ACTIVATED = -9996;
- public static final int USER_BLOCKED = -9998;
- public static final int IMAP_GETQUOTA_ERROR = -9997;
- public static final int IMAP_SELECT_ERROR = -9989;
- public static final int IMAP_ERROR = -9999;
-
- public static final int VMG_INTERNAL_ERROR = -101;
- public static final int VMG_DB_ERROR = -102;
- public static final int VMG_COMMUNICATION_ERROR = -103;
- public static final int SPG_URL_NOT_FOUND = -301;
-
- // Non VVM3 codes:
- public static final int VMG_UNKNOWN_ERROR = -1;
- public static final int PIN_NOT_SET = -100;
- // STATUS SMS returned st=U and rc!=2. The user cannot be provisioned and must contact customer
- // support.
- public static final int SUBSCRIBER_UNKNOWN = -99;
-
-
- public static void handleEvent(Context context, OmtpVvmCarrierConfigHelper config,
- VoicemailStatus.Editor status, OmtpEvents event) {
- boolean handled = false;
- switch (event.getType()) {
- case Type.CONFIGURATION:
- handled = handleConfigurationEvent(context, status, event);
- break;
- case Type.DATA_CHANNEL:
- handled = handleDataChannelEvent(status, event);
- break;
- case Type.NOTIFICATION_CHANNEL:
- handled = handleNotificationChannelEvent(status, event);
- break;
- case Type.OTHER:
- handled = handleOtherEvent(status, event);
- break;
- default:
- com.android.services.telephony.Log
- .wtf(TAG, "invalid event type " + event.getType() + " for " + event);
- }
- if (!handled) {
- DefaultOmtpEventHandler.handleEvent(context, config, status, event);
- }
- }
-
- private static boolean handleConfigurationEvent(Context context, VoicemailStatus.Editor status,
- OmtpEvents event) {
- switch (event) {
- case CONFIG_REQUEST_STATUS_SUCCESS:
- if (!isPinRandomized(context, status.getPhoneAccountHandle())) {
- return false;
- } else {
- postError(status, PIN_NOT_SET);
- }
- break;
- case CONFIG_ACTIVATING_SUBSEQUENT:
- if (isPinRandomized(context, status.getPhoneAccountHandle())) {
- status.setConfigurationState(PIN_NOT_SET);
- } else {
- status.setConfigurationState(Status.CONFIGURATION_STATE_OK);
- }
- status
- .setNotificationChannelState(Status.NOTIFICATION_CHANNEL_STATE_OK)
- .setDataChannelState(Status.DATA_CHANNEL_STATE_OK).apply();
- break;
- case CONFIG_DEFAULT_PIN_REPLACED:
- postError(status, PIN_NOT_SET);
- break;
- case CONFIG_STATUS_SMS_TIME_OUT:
- postError(status, STATUS_SMS_TIMEOUT);
- break;
- default:
- return false;
- }
- return true;
- }
-
- private static boolean handleDataChannelEvent(VoicemailStatus.Editor status, OmtpEvents event) {
- switch (event) {
- case DATA_NO_CONNECTION:
- case DATA_NO_CONNECTION_CELLULAR_REQUIRED:
- case DATA_ALL_SOCKET_CONNECTION_FAILED:
- postError(status, VMS_NO_CELLULAR);
- break;
- case DATA_SSL_INVALID_HOST_NAME:
- case DATA_CANNOT_ESTABLISH_SSL_SESSION:
- case DATA_IOE_ON_OPEN:
- postError(status, VMS_TIMEOUT);
- break;
- case DATA_CANNOT_RESOLVE_HOST_ON_NETWORK:
- postError(status, VMS_DNS_FAILURE);
- break;
- case DATA_BAD_IMAP_CREDENTIAL:
- postError(status, IMAP_ERROR);
- break;
- case DATA_AUTH_UNKNOWN_USER:
- postError(status, UNKNOWN_USER);
- break;
- case DATA_AUTH_UNKNOWN_DEVICE:
- postError(status, UNKNOWN_DEVICE);
- break;
- case DATA_AUTH_INVALID_PASSWORD:
- postError(status, INVALID_PASSWORD);
- break;
- case DATA_AUTH_MAILBOX_NOT_INITIALIZED:
- postError(status, MAILBOX_NOT_INITIALIZED);
- break;
- case DATA_AUTH_SERVICE_NOT_PROVISIONED:
- postError(status, SERVICE_NOT_PROVISIONED);
- break;
- case DATA_AUTH_SERVICE_NOT_ACTIVATED:
- postError(status, SERVICE_NOT_ACTIVATED);
- break;
- case DATA_AUTH_USER_IS_BLOCKED:
- postError(status, USER_BLOCKED);
- break;
- case DATA_REJECTED_SERVER_RESPONSE:
- case DATA_INVALID_INITIAL_SERVER_RESPONSE:
- case DATA_SSL_EXCEPTION:
- postError(status, IMAP_ERROR);
- break;
- default:
- return false;
- }
- return true;
- }
-
- private static boolean handleNotificationChannelEvent(VoicemailStatus.Editor status,
- OmtpEvents event) {
- return false;
- }
-
- private static boolean handleOtherEvent(VoicemailStatus.Editor status,
- OmtpEvents event) {
- switch (event) {
- case VVM3_NEW_USER_SETUP_FAILED:
- postError(status, MAILBOX_NOT_INITIALIZED);
- break;
- case VVM3_VMG_DNS_FAILURE:
- postError(status, VMG_DNS_FAILURE);
- break;
- case VVM3_SPG_DNS_FAILURE:
- postError(status, SPG_DNS_FAILURE);
- break;
- case VVM3_VMG_CONNECTION_FAILED:
- postError(status, VMG_NO_CELLULAR);
- break;
- case VVM3_SPG_CONNECTION_FAILED:
- postError(status, SPG_NO_CELLULAR);
- break;
- case VVM3_VMG_TIMEOUT:
- postError(status, VMG_TIMEOUT);
- break;
- case VVM3_SUBSCRIBER_PROVISIONED:
- postError(status, SERVICE_NOT_ACTIVATED);
- break;
- case VVM3_SUBSCRIBER_BLOCKED:
- postError(status, SUBSCRIBER_BLOCKED);
- break;
- case VVM3_SUBSCRIBER_UNKNOWN:
- postError(status, SUBSCRIBER_UNKNOWN);
- break;
- default:
- return false;
- }
- return true;
- }
-
- private static void postError(VoicemailStatus.Editor editor, @ErrorCode int errorCode) {
- switch (errorCode) {
- case VMG_DNS_FAILURE:
- case SPG_DNS_FAILURE:
- case VMG_NO_CELLULAR:
- case SPG_NO_CELLULAR:
- case VMG_TIMEOUT:
- case SUBSCRIBER_BLOCKED:
- case UNKNOWN_USER:
- case UNKNOWN_DEVICE:
- case INVALID_PASSWORD:
- case MAILBOX_NOT_INITIALIZED:
- case SERVICE_NOT_PROVISIONED:
- case SERVICE_NOT_ACTIVATED:
- case USER_BLOCKED:
- case VMG_UNKNOWN_ERROR:
- case SPG_URL_NOT_FOUND:
- case VMG_INTERNAL_ERROR:
- case VMG_DB_ERROR:
- case VMG_COMMUNICATION_ERROR:
- case PIN_NOT_SET:
- case SUBSCRIBER_UNKNOWN:
- editor.setConfigurationState(errorCode);
- break;
- case VMS_NO_CELLULAR:
- case VMS_DNS_FAILURE:
- case VMS_TIMEOUT:
- case IMAP_GETQUOTA_ERROR:
- case IMAP_SELECT_ERROR:
- case IMAP_ERROR:
- editor.setDataChannelState(errorCode);
- break;
- case STATUS_SMS_TIMEOUT:
- editor.setNotificationChannelState(errorCode);
- break;
- default:
- Log.wtf(TAG, "unknown error code: " + errorCode);
- }
- editor.apply();
- }
-
- private static boolean isPinRandomized(Context context, PhoneAccountHandle phoneAccountHandle) {
- if (phoneAccountHandle == null) {
- // This should never happen.
- Log.e(TAG, "status editor has null phone account handle");
- return false;
- }
- return VoicemailChangePinActivity.isDefaultOldPinSet(context, phoneAccountHandle);
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
deleted file mode 100644
index 93e8fb9..0000000
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.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;
-import com.android.phone.settings.VoicemailChangePinActivity;
-import com.android.phone.vvm.omtp.ActivationTask;
-import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.imap.ImapHelper;
-import com.android.phone.vvm.omtp.imap.ImapHelper.InitializingException;
-import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
-import com.android.phone.vvm.omtp.sms.StatusMessage;
-import com.android.phone.vvm.omtp.sms.Vvm3MessageSender;
-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;
-
-/**
- * A flavor of OMTP protocol with a different provisioning process
- *
- * Used by carriers such as Verizon Wireless
- */
-public class Vvm3Protocol extends VisualVoicemailProtocol {
-
- private static final String TAG = "Vvm3Protocol";
-
- private static final String SMS_EVENT_UNRECOGNIZED = "UNRECOGNIZED";
- private static final String SMS_EVENT_UNRECOGNIZED_CMD = "cmd";
- private static final String SMS_EVENT_UNRECOGNIZED_STATUS = "STATUS";
- private static final String DEFAULT_VMG_URL_KEY = "default_vmg_url";
-
- private static final String IMAP_CHANGE_TUI_PWD_FORMAT = "CHANGE_TUI_PWD PWD=%1$s OLD_PWD=%2$s";
- private static final String IMAP_CHANGE_VM_LANG_FORMAT = "CHANGE_VM_LANG Lang=%1$s";
- private static final String IMAP_CLOSE_NUT = "CLOSE_NUT";
-
- private static final String ISO639_Spanish = "es";
-
- /**
- * For VVM3, if the STATUS SMS returns {@link StatusMessage#getProvisioningStatus()} of {@link
- * OmtpConstants#SUBSCRIBER_UNKNOWN} and {@link StatusMessage#getReturnCode()} of this value,
- * the user can self-provision visual voicemail service. For other response codes, the user must
- * contact customer support to resolve the issue.
- */
- private static final String VVM3_UNKNOWN_SUBSCRIBER_CAN_SUBSCRIBE_RESPONSE_CODE = "2";
-
- // Default prompt level when using the telephone user interface.
- // Standard prompt when the user call into the voicemail, and no prompts when someone else is
- // leaving a voicemail.
- private static final String VVM3_VM_LANGUAGE_ENGLISH_STANDARD_NO_GUEST_PROMPTS = "5";
- private static final String VVM3_VM_LANGUAGE_SPANISH_STANDARD_NO_GUEST_PROMPTS = "6";
-
- private static final int DEFAULT_PIN_LENGTH = 6;
-
- @Override
- 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(sentIntent);
- }
-
- @Override
- public void startDeactivation(OmtpVvmCarrierConfigHelper config) {
- // VVM3 does not support deactivation.
- // do nothing.
- }
-
- @Override
- public boolean supportsProvisioning() {
- return true;
- }
-
- @Override
- public void startProvisioning(ActivationTask task, PhoneAccountHandle phoneAccountHandle,
- OmtpVvmCarrierConfigHelper config, VoicemailStatus.Editor status, StatusMessage message,
- Bundle data) {
- VvmLog.i(TAG, "start vvm3 provisioning");
- if (OmtpConstants.SUBSCRIBER_UNKNOWN.equals(message.getProvisioningStatus())) {
- VvmLog.i(TAG, "Provisioning status: Unknown");
- if (VVM3_UNKNOWN_SUBSCRIBER_CAN_SUBSCRIBE_RESPONSE_CODE
- .equals(message.getReturnCode())) {
- VvmLog.i(TAG, "Self provisioning available, subscribing");
- 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");
- // Save the IMAP credentials in preferences so they are persistent and can be retrieved.
- VisualVoicemailPreferences prefs =
- new VisualVoicemailPreferences(config.getContext(), phoneAccountHandle);
- message.putStatus(prefs.edit()).apply();
-
- startProvisionNewUser(task, phoneAccountHandle, config, status, message);
- } else if (OmtpConstants.SUBSCRIBER_PROVISIONED.equals(message.getProvisioningStatus())) {
- 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);
- }
- }
-
- @Override
- public OmtpMessageSender createMessageSender(SmsManager smsManager, short applicationPort,
- String destinationNumber) {
- return new Vvm3MessageSender(smsManager, applicationPort, destinationNumber);
- }
-
- @Override
- public void handleEvent(Context context, OmtpVvmCarrierConfigHelper config,
- VoicemailStatus.Editor status, OmtpEvents event) {
- Vvm3EventHandler.handleEvent(context, config, status, event);
- }
-
- @Override
- public String getCommand(String command) {
- if (command == OmtpConstants.IMAP_CHANGE_TUI_PWD_FORMAT) {
- return IMAP_CHANGE_TUI_PWD_FORMAT;
- }
- if (command == OmtpConstants.IMAP_CLOSE_NUT) {
- return IMAP_CLOSE_NUT;
- }
- if (command == OmtpConstants.IMAP_CHANGE_VM_LANG_FORMAT) {
- return IMAP_CHANGE_VM_LANG_FORMAT;
- }
- return super.getCommand(command);
- }
-
- @Override
- public Bundle translateStatusSmsBundle(OmtpVvmCarrierConfigHelper config, String event,
- Bundle data) {
- // UNRECOGNIZED?cmd=STATUS is the response of a STATUS request when the user is provisioned
- // with iPhone visual voicemail without VoLTE. Translate it into an unprovisioned status
- // so provisioning can be done.
- if (!SMS_EVENT_UNRECOGNIZED.equals(event)) {
- return null;
- }
- if (!SMS_EVENT_UNRECOGNIZED_STATUS.equals(data.getString(SMS_EVENT_UNRECOGNIZED_CMD))) {
- return null;
- }
- Bundle bundle = new Bundle();
- bundle.putString(OmtpConstants.PROVISIONING_STATUS, OmtpConstants.SUBSCRIBER_UNKNOWN);
- bundle.putString(OmtpConstants.RETURN_CODE,
- VVM3_UNKNOWN_SUBSCRIBER_CAN_SUBSCRIBE_RESPONSE_CODE);
- String vmgUrl = config.getString(DEFAULT_VMG_URL_KEY);
- if (TextUtils.isEmpty(vmgUrl)) {
- VvmLog.e(TAG, "Unable to translate STATUS SMS: VMG URL is not set in config");
- return null;
- }
- bundle.putString(Vvm3Subscriber.VMG_URL_KEY, vmgUrl);
- VvmLog.i(TAG, "UNRECOGNIZED?cmd=STATUS translated into unprovisioned STATUS SMS");
- return bundle;
- }
-
- private void startProvisionNewUser(ActivationTask task, PhoneAccountHandle phoneAccountHandle,
- OmtpVvmCarrierConfigHelper config, VoicemailStatus.Editor status,
- StatusMessage message) {
- try (NetworkWrapper wrapper = VvmNetworkRequest
- .getNetwork(config, phoneAccountHandle, status)) {
- Network network = wrapper.get();
-
- VvmLog.i(TAG, "new user: network available");
- try (ImapHelper helper = new ImapHelper(config.getContext(), phoneAccountHandle,
- network, status)) {
- // VVM3 has inconsistent error language code to OMTP. Just issue a raw command
- // here.
- // TODO(b/29082671): use LocaleList
- if (Locale.getDefault().getLanguage()
- .equals(new Locale(ISO639_Spanish).getLanguage())) {
- // Spanish
- helper.changeVoicemailTuiLanguage(
- VVM3_VM_LANGUAGE_SPANISH_STANDARD_NO_GUEST_PROMPTS);
- } else {
- // English
- helper.changeVoicemailTuiLanguage(
- VVM3_VM_LANGUAGE_ENGLISH_STANDARD_NO_GUEST_PROMPTS);
- }
- VvmLog.i(TAG, "new user: language set");
-
- if (setPin(config.getContext(), phoneAccountHandle, helper, message)) {
- // Only close new user tutorial if the PIN has been changed.
- helper.closeNewUserTutorial();
- VvmLog.i(TAG, "new user: NUT closed");
-
- config.requestStatus(null);
- }
- } catch (InitializingException | MessagingException | IOException e) {
- config.handleEvent(status, OmtpEvents.VVM3_NEW_USER_SETUP_FAILED);
- task.fail();
- VvmLog.e(TAG, e.toString());
- }
- } catch (RequestFailedException e) {
- config.handleEvent(status, OmtpEvents.DATA_NO_CONNECTION_CELLULAR_REQUIRED);
- task.fail();
- }
-
- }
-
-
- private static boolean setPin(Context context, PhoneAccountHandle phoneAccountHandle,
- ImapHelper helper, StatusMessage message)
- throws IOException, MessagingException {
- String defaultPin = getDefaultPin(message);
- if (defaultPin == null) {
- VvmLog.i(TAG, "cannot generate default PIN");
- return false;
- }
-
- if (VoicemailChangePinActivity.isDefaultOldPinSet(context, phoneAccountHandle)) {
- // The pin was already set
- VvmLog.i(TAG, "PIN already set");
- return true;
- }
- String newPin = generatePin(getMinimumPinLength(context, phoneAccountHandle));
- if (helper.changePin(defaultPin, newPin) == OmtpConstants.CHANGE_PIN_SUCCESS) {
- VoicemailChangePinActivity.setDefaultOldPIN(context, phoneAccountHandle, newPin);
- helper.handleEvent(OmtpEvents.CONFIG_DEFAULT_PIN_REPLACED);
- }
- VvmLog.i(TAG, "new user: PIN set");
- return true;
- }
-
- @Nullable
- private static String getDefaultPin(StatusMessage message) {
- // The IMAP username is [phone number]@example.com
- String username = message.getImapUserName();
- try {
- String number = username.substring(0, username.indexOf('@'));
- if (number.length() < 4) {
- VvmLog.e(TAG, "unable to extract number from IMAP username");
- return null;
- }
- return "1" + number.substring(number.length() - 4);
- } catch (StringIndexOutOfBoundsException e) {
- VvmLog.e(TAG, "unable to extract number from IMAP username");
- return null;
- }
-
- }
-
- private static int getMinimumPinLength(Context context, PhoneAccountHandle phoneAccountHandle) {
- VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(context,
- phoneAccountHandle);
- // The OMTP pin length format is {min}-{max}
- String[] lengths = preferences.getString(OmtpConstants.TUI_PASSWORD_LENGTH, "").split("-");
- if (lengths.length == 2) {
- try {
- return Integer.parseInt(lengths[0]);
- } catch (NumberFormatException e) {
- return DEFAULT_PIN_LENGTH;
- }
- }
- return DEFAULT_PIN_LENGTH;
- }
-
- private static String generatePin(int length) {
- SecureRandom random = new SecureRandom();
- return String.format(Locale.US, "%010d", Math.abs(random.nextLong()))
- .substring(0, length);
-
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java
deleted file mode 100644
index ad00aa4..0000000
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Subscriber.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.protocol;
-
-import android.annotation.WorkerThread;
-import android.net.Network;
-import android.os.Build;
-import android.os.Bundle;
-import android.telecom.PhoneAccountHandle;
-import android.telephony.TelephonyManager;
-import android.text.Html;
-import android.text.Spanned;
-import android.text.style.URLSpan;
-import android.util.ArrayMap;
-import com.android.phone.Assert;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.omtp.ActivationTask;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VvmLog;
-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 com.android.volley.AuthFailureError;
-import com.android.volley.Request;
-import com.android.volley.RequestQueue;
-import com.android.volley.toolbox.HurlStack;
-import com.android.volley.toolbox.RequestFuture;
-import com.android.volley.toolbox.StringRequest;
-import com.android.volley.toolbox.Volley;
-import java.io.IOException;
-import java.net.CookieHandler;
-import java.net.CookieManager;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Random;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Class to subscribe to basic VVM3 visual voicemail, for example, Verizon. Subscription is required
- * when the user is unprovisioned. This could happen when the user is on a legacy service, or
- * switched over from devices that used other type of visual voicemail.
- *
- * The STATUS SMS will come with a URL to the voicemail management gateway. From it we can find the
- * self provisioning gateway URL that we can modify voicemail services.
- *
- * A request to the self provisioning gateway to activate basic visual voicemail will return us with
- * a web page. If the user hasn't subscribe to it yet it will contain a link to confirm the
- * subscription. This link should be clicked through cellular network, and have cookies enabled.
- *
- * After the process is completed, the carrier should send us another STATUS SMS with a new or ready
- * user.
- */
-public class Vvm3Subscriber {
-
- private static final String TAG = "Vvm3Subscriber";
-
- private static final String OPERATION_GET_SPG_URL = "retrieveSPGURL";
- private static final String SPG_URL_TAG = "spgurl";
- private static final String TRANSACTION_ID_TAG = "transactionid";
- //language=XML
- private static final String VMG_XML_REQUEST_FORMAT = ""
- + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
- + "<VMGVVMRequest>"
- + " <MessageHeader>"
- + " <transactionid>%1$s</transactionid>"
- + " </MessageHeader>"
- + " <MessageBody>"
- + " <mdn>%2$s</mdn>"
- + " <operation>%3$s</operation>"
- + " <source>Device</source>"
- + " <devicemodel>%4$s</devicemodel>"
- + " </MessageBody>"
- + "</VMGVVMRequest>";
-
- static final String VMG_URL_KEY = "vmg_url";
-
- // Self provisioning POST key/values. VVM3 API 2.1.0 12.3
- private static final String SPG_VZW_MDN_PARAM = "VZW_MDN";
- private static final String SPG_VZW_SERVICE_PARAM = "VZW_SERVICE";
- private static final String SPG_VZW_SERVICE_BASIC = "BVVM";
- private static final String SPG_DEVICE_MODEL_PARAM = "DEVICE_MODEL";
- // Value for all android device
- private static final String SPG_DEVICE_MODEL_ANDROID = "DROID_4G";
- private static final String SPG_APP_TOKEN_PARAM = "APP_TOKEN";
- private static final String SPG_APP_TOKEN = "q8e3t5u2o1";
- private static final String SPG_LANGUAGE_PARAM = "SPG_LANGUAGE_PARAM";
- private static final String SPG_LANGUAGE_EN = "ENGLISH";
-
- private static final String BASIC_SUBSCRIBE_LINK_TEXT = "Subscribe to Basic Visual Voice Mail";
-
- private static final int REQUEST_TIMEOUT_SECONDS = 30;
-
- private final ActivationTask mTask;
- private final PhoneAccountHandle mHandle;
- private final OmtpVvmCarrierConfigHelper mHelper;
- private final VoicemailStatus.Editor mStatus;
- private final Bundle mData;
-
- private final String mNumber;
-
- private RequestQueue mRequestQueue;
-
- private static class ProvisioningException extends Exception {
-
- public ProvisioningException(String message) {
- super(message);
- }
- }
-
- static {
- // Set the default cookie handler to retain session data for the self provisioning gateway.
- // Note; this is not ideal as it is application-wide, and can easily get clobbered.
- // But it seems to be the preferred way to manage cookie for HttpURLConnection, and manually
- // managing cookies will greatly increase complexity.
- CookieManager cookieManager = new CookieManager();
- CookieHandler.setDefault(cookieManager);
- }
-
- @WorkerThread
- public Vvm3Subscriber(ActivationTask task, PhoneAccountHandle handle,
- OmtpVvmCarrierConfigHelper helper, VoicemailStatus.Editor status, Bundle data) {
- Assert.isNotMainThread();
- mTask = task;
- mHandle = handle;
- mHelper = helper;
- mStatus = status;
- mData = data;
-
- // Assuming getLine1Number() will work with VVM3. For unprovisioned users the IMAP username
- // is not included in the status SMS, thus no other way to get the current phone number.
- mNumber = mHelper.getContext().getSystemService(TelephonyManager.class)
- .getLine1Number(mHelper.getSubId());
- }
-
- @WorkerThread
- public void subscribe() {
- Assert.isNotMainThread();
- // Cellular data is required to subscribe.
- // processSubscription() is called after network is available.
- VvmLog.i(TAG, "Subscribing");
-
- try (NetworkWrapper wrapper = VvmNetworkRequest.getNetwork(mHelper, mHandle, mStatus)) {
- Network network = wrapper.get();
- VvmLog.d(TAG, "provisioning: network available");
- mRequestQueue = Volley
- .newRequestQueue(mHelper.getContext(), new NetworkSpecifiedHurlStack(network));
- processSubscription();
- } catch (RequestFailedException e) {
- mHelper.handleEvent(mStatus, OmtpEvents.VVM3_VMG_CONNECTION_FAILED);
- mTask.fail();
- }
- }
-
- private void processSubscription() {
- try {
- String gatewayUrl = getSelfProvisioningGateway();
- String selfProvisionResponse = getSelfProvisionResponse(gatewayUrl);
- String subscribeLink = findSubscribeLink(selfProvisionResponse);
- clickSubscribeLink(subscribeLink);
- } catch (ProvisioningException e) {
- VvmLog.e(TAG, e.toString());
- mTask.fail();
- }
- }
-
- /**
- * Get the URL to perform self-provisioning from the voicemail management gateway.
- */
- private String getSelfProvisioningGateway() throws ProvisioningException {
- VvmLog.i(TAG, "retrieving SPG URL");
- String response = vvm3XmlRequest(OPERATION_GET_SPG_URL);
- return extractText(response, SPG_URL_TAG);
- }
-
- /**
- * Sent a request to the self-provisioning gateway, which will return us with a webpage. The
- * page might contain a "Subscribe to Basic Visual Voice Mail" link to complete the
- * subscription. The cookie from this response and cellular data is required to click the link.
- */
- private String getSelfProvisionResponse(String url) throws ProvisioningException {
- VvmLog.i(TAG, "Retrieving self provisioning response");
-
- RequestFuture<String> future = RequestFuture.newFuture();
-
- StringRequest stringRequest = new StringRequest(Request.Method.POST, url, future, future) {
- @Override
- protected Map<String, String> getParams() {
- Map<String, String> params = new ArrayMap<>();
- params.put(SPG_VZW_MDN_PARAM, mNumber);
- params.put(SPG_VZW_SERVICE_PARAM, SPG_VZW_SERVICE_BASIC);
- params.put(SPG_DEVICE_MODEL_PARAM, SPG_DEVICE_MODEL_ANDROID);
- params.put(SPG_APP_TOKEN_PARAM, SPG_APP_TOKEN);
- // Language to display the subscription page. The page is never shown to the user
- // so just use English.
- params.put(SPG_LANGUAGE_PARAM, SPG_LANGUAGE_EN);
- return params;
- }
- };
-
- mRequestQueue.add(stringRequest);
- try {
- return future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- } catch (InterruptedException | ExecutionException | TimeoutException e) {
- mHelper.handleEvent(mStatus, OmtpEvents.VVM3_SPG_CONNECTION_FAILED);
- throw new ProvisioningException(e.toString());
- }
- }
-
- private void clickSubscribeLink(String subscribeLink) throws ProvisioningException {
- VvmLog.i(TAG, "Clicking subscribe link");
- RequestFuture<String> future = RequestFuture.newFuture();
-
- StringRequest stringRequest = new StringRequest(Request.Method.POST,
- subscribeLink, future, future);
- mRequestQueue.add(stringRequest);
- try {
- // A new STATUS SMS will be sent after this request.
- future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- } catch (TimeoutException | ExecutionException | InterruptedException e) {
- mHelper.handleEvent(mStatus, OmtpEvents.VVM3_SPG_CONNECTION_FAILED);
- throw new ProvisioningException(e.toString());
- }
- // It could take very long for the STATUS SMS to return. Waiting for it is unreliable.
- // Just leave the CONFIG STATUS as CONFIGURING and end the task. The user can always
- // manually retry if it took too long.
- }
-
- private String vvm3XmlRequest(String operation) throws ProvisioningException {
- VvmLog.d(TAG, "Sending vvm3XmlRequest for " + operation);
- String voicemailManagementGateway = mData.getString(VMG_URL_KEY);
- if (voicemailManagementGateway == null) {
- VvmLog.e(TAG, "voicemailManagementGateway url unknown");
- return null;
- }
- String transactionId = createTransactionId();
- String body = String.format(Locale.US, VMG_XML_REQUEST_FORMAT,
- transactionId, mNumber, operation, Build.MODEL);
-
- RequestFuture<String> future = RequestFuture.newFuture();
- StringRequest stringRequest = new StringRequest(Request.Method.POST,
- voicemailManagementGateway, future, future) {
- @Override
- public byte[] getBody() throws AuthFailureError {
- return body.getBytes();
- }
- };
- mRequestQueue.add(stringRequest);
-
- try {
- String response = future.get(REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- if (!transactionId.equals(extractText(response, TRANSACTION_ID_TAG))) {
- throw new ProvisioningException("transactionId mismatch");
- }
- return response;
- } catch (InterruptedException | ExecutionException | TimeoutException e) {
- mHelper.handleEvent(mStatus, OmtpEvents.VVM3_VMG_CONNECTION_FAILED);
- throw new ProvisioningException(e.toString());
- }
- }
-
- private String findSubscribeLink(String response) throws ProvisioningException {
- Spanned doc = Html.fromHtml(response, Html.FROM_HTML_MODE_LEGACY);
- URLSpan[] spans = doc.getSpans(0, doc.length(), URLSpan.class);
- StringBuilder fulltext = new StringBuilder();
- for (URLSpan span : spans) {
- String text = doc.subSequence(doc.getSpanStart(span), doc.getSpanEnd(span)).toString();
- if (BASIC_SUBSCRIBE_LINK_TEXT.equals(text)) {
- return span.getURL();
- }
- fulltext.append(text);
- }
- throw new ProvisioningException("Subscribe link not found: " + fulltext);
- }
-
- private String createTransactionId() {
- return String.valueOf(Math.abs(new Random().nextLong()));
- }
-
- private String extractText(String xml, String tag) throws ProvisioningException {
- Pattern pattern = Pattern.compile("<" + tag + ">(.*)<\\/" + tag + ">");
- Matcher matcher = pattern.matcher(xml);
- if (matcher.find()) {
- return matcher.group(1);
- }
- throw new ProvisioningException("Tag " + tag + " not found in xml response");
- }
-
- private static class NetworkSpecifiedHurlStack extends HurlStack {
-
- private final Network mNetwork;
-
- public NetworkSpecifiedHurlStack(Network network) {
- mNetwork = network;
- }
-
- @Override
- protected HttpURLConnection createConnection(URL url) throws IOException {
- return (HttpURLConnection) mNetwork.openConnection(url);
- }
-
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/scheduling/BaseTask.java b/src/com/android/phone/vvm/omtp/scheduling/BaseTask.java
deleted file mode 100644
index 76537fa..0000000
--- a/src/com/android/phone/vvm/omtp/scheduling/BaseTask.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import android.annotation.CallSuper;
-import android.annotation.MainThread;
-import android.annotation.WorkerThread;
-import android.content.Context;
-import android.content.Intent;
-import android.os.SystemClock;
-import android.support.annotation.NonNull;
-import android.telephony.SubscriptionManager;
-import com.android.phone.Assert;
-import com.android.phone.NeededForTesting;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Provides common utilities for task implementations, such as execution time and managing {@link
- * Policy}
- */
-public abstract class BaseTask implements Task {
-
- private static final String EXTRA_SUB_ID = "extra_sub_id";
-
- private Context mContext;
-
- private int mId;
- private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
- private boolean mHasStarted;
- private volatile boolean mHasFailed;
-
- @NonNull
- private final List<Policy> mPolicies = new ArrayList<>();
-
- private long mExecutionTime;
-
- private static Clock sClock = new Clock();
-
- protected BaseTask(int id) {
- mId = id;
- mExecutionTime = getTimeMillis();
- }
-
- /**
- * Modify the task ID to prevent arbitrary task from executing. Can only be called before {@link
- * #onCreate(Context, Intent, int, int)} returns.
- */
- @MainThread
- public void setId(int id) {
- Assert.isMainThread();
- mId = id;
- }
-
- @MainThread
- public boolean hasStarted() {
- Assert.isMainThread();
- return mHasStarted;
- }
-
- @MainThread
- public boolean hasFailed() {
- Assert.isMainThread();
- return mHasFailed;
- }
-
- public Context getContext() {
- return mContext;
- }
-
- public int getSubId() {
- return mSubId;
- }
- /**
- * Should be call in the constructor or {@link Policy#onCreate(BaseTask, Intent, int, int)} will
- * be missed.
- */
- @MainThread
- public BaseTask addPolicy(Policy policy) {
- Assert.isMainThread();
- mPolicies.add(policy);
- return this;
- }
-
- /**
- * Indicate the task has failed. {@link Policy#onFail()} will be triggered once the execution
- * ends. This mechanism is used by policies for actions such as determining whether to schedule
- * a retry. Must be call inside {@link #onExecuteInBackgroundThread()}
- */
- @WorkerThread
- public void fail() {
- Assert.isNotMainThread();
- mHasFailed = true;
- }
-
- @MainThread
- public void setExecutionTime(long timeMillis) {
- Assert.isMainThread();
- mExecutionTime = timeMillis;
- }
-
- public long getTimeMillis() {
- return sClock.getTimeMillis();
- }
-
- /**
- * Creates an intent that can be used to restart the current task. Derived class should build
- * their intent upon this.
- */
- public Intent createRestartIntent() {
- return createIntent(getContext(), this.getClass(), mSubId);
- }
-
- /**
- * Creates an intent that can be used to start the {@link TaskSchedulerService}. Derived class
- * should build their intent upon this.
- */
- public static Intent createIntent(Context context, Class<? extends BaseTask> task, int subId) {
- Intent intent = TaskSchedulerService.createIntent(context, task);
- intent.putExtra(EXTRA_SUB_ID, subId);
- return intent;
- }
-
- @Override
- public TaskId getId() {
- return new TaskId(mId, mSubId);
- }
-
- @Override
- @CallSuper
- public void onCreate(Context context, Intent intent, int flags, int startId) {
- mContext = context;
- mSubId = intent.getIntExtra(EXTRA_SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- for (Policy policy : mPolicies) {
- policy.onCreate(this, intent, flags, startId);
- }
- }
-
- @Override
- public long getReadyInMilliSeconds() {
- return mExecutionTime - getTimeMillis();
- }
-
- @Override
- @CallSuper
- public void onBeforeExecute() {
- for (Policy policy : mPolicies) {
- policy.onBeforeExecute();
- }
- mHasStarted = true;
- }
-
- @Override
- @CallSuper
- public void onCompleted() {
- if (mHasFailed) {
- for (Policy policy : mPolicies) {
- policy.onFail();
- }
- }
-
- for (Policy policy : mPolicies) {
- policy.onCompleted();
- }
- }
-
- @Override
- public void onDuplicatedTaskAdded(Task task) {
- for (Policy policy : mPolicies) {
- policy.onDuplicatedTaskAdded();
- }
- }
-
- @NeededForTesting
- static class Clock {
-
- public long getTimeMillis() {
- return SystemClock.elapsedRealtime();
- }
- }
-
- /**
- * Used to replace the clock with an deterministic clock
- */
- @NeededForTesting
- static void setClockForTesting(Clock clock) {
- sClock = clock;
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/scheduling/BlockerTask.java b/src/com/android/phone/vvm/omtp/scheduling/BlockerTask.java
deleted file mode 100644
index 9d91828..0000000
--- a/src/com/android/phone/vvm/omtp/scheduling/BlockerTask.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import android.content.Context;
-import android.content.Intent;
-
-import com.android.phone.vvm.omtp.VvmLog;
-
-/**
- * Task to block another task of the same ID from being queued for a certain amount of time.
- */
-public class BlockerTask extends BaseTask {
-
- private static final String TAG = "BlockerTask";
-
- public static final String EXTRA_TASK_ID = "extra_task_id";
- public static final String EXTRA_BLOCK_FOR_MILLIS = "extra_block_for_millis";
-
- public BlockerTask() {
- super(TASK_INVALID);
- }
-
- @Override
- public void onCreate(Context context, Intent intent, int flags, int startId) {
- super.onCreate(context, intent, flags, startId);
- setId(intent.getIntExtra(EXTRA_TASK_ID, TASK_INVALID));
- setExecutionTime(getTimeMillis() + intent.getIntExtra(EXTRA_BLOCK_FOR_MILLIS, 0));
- }
-
- @Override
- public void onExecuteInBackgroundThread() {
- // Do nothing.
- }
-
- @Override
- public void onDuplicatedTaskAdded(Task task) {
- VvmLog
- .v(TAG, task.toString() + "blocked, " + getReadyInMilliSeconds() + "millis remaining");
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/scheduling/MinimalIntervalPolicy.java b/src/com/android/phone/vvm/omtp/scheduling/MinimalIntervalPolicy.java
deleted file mode 100644
index 8bb22ca..0000000
--- a/src/com/android/phone/vvm/omtp/scheduling/MinimalIntervalPolicy.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import android.content.Intent;
-
-import com.android.phone.vvm.omtp.scheduling.Task.TaskId;
-
-/**
- * If a task with this policy succeeds, a {@link BlockerTask} with the same {@link TaskId} of the
- * task will be queued immediately, preventing the same task from running for a certain amount of
- * time.
- */
-public class MinimalIntervalPolicy implements Policy {
-
- BaseTask mTask;
- TaskId mId;
- int mBlockForMillis;
-
- public MinimalIntervalPolicy(int blockForMillis) {
- mBlockForMillis = blockForMillis;
- }
-
- @Override
- public void onCreate(BaseTask task, Intent intent, int flags, int startId) {
- mTask = task;
- mId = mTask.getId();
- }
-
- @Override
- public void onBeforeExecute() {
-
- }
-
- @Override
- public void onCompleted() {
- if (!mTask.hasFailed()) {
- Intent intent = mTask
- .createIntent(mTask.getContext(), BlockerTask.class, mId.subId);
- intent.putExtra(BlockerTask.EXTRA_TASK_ID, mId.id);
- intent.putExtra(BlockerTask.EXTRA_BLOCK_FOR_MILLIS, mBlockForMillis);
- mTask.getContext().startService(intent);
- }
- }
-
- @Override
- public void onFail() {
-
- }
-
- @Override
- public void onDuplicatedTaskAdded() {
-
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/scheduling/Policy.java b/src/com/android/phone/vvm/omtp/scheduling/Policy.java
deleted file mode 100644
index fcb01b8..0000000
--- a/src/com/android/phone/vvm/omtp/scheduling/Policy.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import android.content.Intent;
-
-/**
- * A set of listeners managed by {@link BaseTask} for common behaviors such as retrying. Call {@link
- * BaseTask#addPolicy(Policy)} to add a policy.
- */
-public interface Policy {
-
- void onCreate(BaseTask task, Intent intent, int flags, int startId);
-
- void onBeforeExecute();
-
- void onCompleted();
-
- void onFail();
-
- void onDuplicatedTaskAdded();
-}
diff --git a/src/com/android/phone/vvm/omtp/scheduling/PostponePolicy.java b/src/com/android/phone/vvm/omtp/scheduling/PostponePolicy.java
deleted file mode 100644
index f23d7f7..0000000
--- a/src/com/android/phone/vvm/omtp/scheduling/PostponePolicy.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import android.content.Intent;
-
-import com.android.phone.vvm.omtp.VvmLog;
-
-/**
- * A task with Postpone policy will not be executed immediately. It will wait for a while and if a
- * duplicated task is queued during the duration, the task will be postponed further. The task will
- * only be executed if no new task was added in postponeMillis. Useful to batch small tasks in quick
- * succession together.
- */
-public class PostponePolicy implements Policy {
-
- private static final String TAG = "PostponePolicy";
-
- private final int mPostponeMillis;
- private BaseTask mTask;
-
- public PostponePolicy(int postponeMillis) {
- mPostponeMillis = postponeMillis;
- }
-
- @Override
- public void onCreate(BaseTask task, Intent intent, int flags, int startId) {
- mTask = task;
- mTask.setExecutionTime(mTask.getTimeMillis() + mPostponeMillis);
- }
-
- @Override
- public void onBeforeExecute() {
- // Do nothing
- }
-
- @Override
- public void onCompleted() {
- // Do nothing
- }
-
- @Override
- public void onFail() {
- // Do nothing
- }
-
- @Override
- public void onDuplicatedTaskAdded() {
- if (mTask.hasStarted()) {
- return;
- }
- VvmLog.d(TAG, "postponing " + mTask);
- mTask.setExecutionTime(mTask.getTimeMillis() + mPostponeMillis);
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/scheduling/RetryPolicy.java b/src/com/android/phone/vvm/omtp/scheduling/RetryPolicy.java
deleted file mode 100644
index 4f4126a..0000000
--- a/src/com/android/phone/vvm/omtp/scheduling/RetryPolicy.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import android.content.Intent;
-import android.telecom.PhoneAccountHandle;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
-/**
- * A task with this policy will automatically re-queue itself if {@link BaseTask#fail()} has been
- * called during {@link BaseTask#onExecuteInBackgroundThread()}. A task will be retried at most
- * <code>retryLimit</code> times and with a <code>retryDelayMillis</code> interval in between.
- */
-public class RetryPolicy implements Policy {
-
- private static final String TAG = "RetryPolicy";
- private static final String EXTRA_RETRY_COUNT = "extra_retry_count";
-
- private final int mRetryLimit;
- private final int mRetryDelayMillis;
-
- private BaseTask mTask;
-
- private int mRetryCount;
- private boolean mFailed;
-
- private VoicemailStatus.DeferredEditor mVoicemailStatusEditor;
-
- public RetryPolicy(int retryLimit, int retryDelayMillis) {
- mRetryLimit = retryLimit;
- mRetryDelayMillis = retryDelayMillis;
- }
-
- private boolean hasMoreRetries() {
- return mRetryCount < mRetryLimit;
- }
-
- /**
- * Error status should only be set if retries has exhausted or the task is successful. Status
- * writes to this editor will be deferred until the task has ended, and will only be committed
- * if the task is successful or there are no retries left.
- */
- public VoicemailStatus.Editor getVoicemailStatusEditor() {
- return mVoicemailStatusEditor;
- }
-
- @Override
- public void onCreate(BaseTask task, Intent intent, int flags, int startId) {
- mTask = task;
- mRetryCount = intent.getIntExtra(EXTRA_RETRY_COUNT, 0);
- if (mRetryCount > 0) {
- VvmLog.d(TAG, "retry #" + mRetryCount + " for " + mTask + " queued, executing in "
- + mRetryDelayMillis);
- mTask.setExecutionTime(mTask.getTimeMillis() + mRetryDelayMillis);
- }
- PhoneAccountHandle phoneAccountHandle = PhoneAccountHandleConverter
- .fromSubId(task.getSubId());
- if (phoneAccountHandle == null) {
- VvmLog.e(TAG, "null phone account for subId " + task.getSubId());
- // This should never happen, but continue on if it does. The status write will be
- // discarded.
- }
- mVoicemailStatusEditor = VoicemailStatus
- .deferredEdit(task.getContext(), phoneAccountHandle);
- }
-
- @Override
- public void onBeforeExecute() {
-
- }
-
- @Override
- public void onCompleted() {
- if (!mFailed || !hasMoreRetries()) {
- if (!mFailed) {
- VvmLog.d(TAG, mTask.toString() + " completed successfully");
- }
- if (!hasMoreRetries()) {
- VvmLog.d(TAG, "Retry limit for " + mTask + " reached");
- }
- VvmLog.i(TAG, "committing deferred status: " + mVoicemailStatusEditor.getValues());
- mVoicemailStatusEditor.deferredApply();
- return;
- }
- VvmLog.i(TAG, "discarding deferred status: " + mVoicemailStatusEditor.getValues());
- Intent intent = mTask.createRestartIntent();
- intent.putExtra(EXTRA_RETRY_COUNT, mRetryCount + 1);
-
- mTask.getContext().startService(intent);
- }
-
- @Override
- public void onFail() {
- mFailed = true;
- }
-
- @Override
- public void onDuplicatedTaskAdded() {
-
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/scheduling/Task.java b/src/com/android/phone/vvm/omtp/scheduling/Task.java
deleted file mode 100644
index 05d86fd..0000000
--- a/src/com/android/phone/vvm/omtp/scheduling/Task.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import android.annotation.MainThread;
-import android.annotation.WorkerThread;
-import android.content.Context;
-import android.content.Intent;
-import java.util.Objects;
-
-/**
- * A task for {@link TaskSchedulerService} to execute. Since the task is sent through a intent to
- * the scheduler, The task must be constructable with the intent. Specifically, It must have a
- * constructor with zero arguments, and have all relevant data packed inside the intent. Use {@link
- * TaskSchedulerService#createIntent(Context, Class)} to create a intent that will construct the
- * Task.
- *
- * <p>Only {@link #onExecuteInBackgroundThread()} is run on the worker thread.
- */
-public interface Task {
-
- /**
- * TaskId to indicate it has not be set. If a task does not provide a default TaskId it should
- * be set before {@link Task#onCreate(Context, Intent, int, int) returns}
- */
- int TASK_INVALID = -1;
-
- /**
- * TaskId to indicate it should always be queued regardless of duplicates. {@link
- * Task#onDuplicatedTaskAdded(Task)} will never be called on tasks with this TaskId.
- */
- int TASK_ALLOW_DUPLICATES = -2;
-
- int TASK_UPLOAD = 1;
- int TASK_SYNC = 2;
- int TASK_ACTIVATION = 3;
-
- /**
- * Used to differentiate between types of tasks. If a task with the same TaskId is already in
- * the queue the new task will be rejected.
- */
- class TaskId {
-
- /**
- * Indicates the operation type of the task.
- */
- public final int id;
- /**
- * Same operation for a different subId is allowed. subId is used to differentiate phone
- * accounts in multi-SIM scenario. For example, each SIM can queue a sync task for their
- * own.
- */
- public final int subId;
-
- public TaskId(int id, int subId) {
- this.id = id;
- this.subId = subId;
- }
-
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof TaskId)) {
- return false;
- }
- TaskId other = (TaskId) object;
- return id == other.id && subId == other.subId;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(id, subId);
- }
- }
-
- TaskId getId();
-
- @MainThread
- void onCreate(Context context, Intent intent, int flags, int startId);
-
- /**
- * @return number of milliSeconds the scheduler should wait before running this task. A value
- * less than {@link TaskSchedulerService#READY_TOLERANCE_MILLISECONDS} will be considered ready.
- * If no tasks are ready, the scheduler will sleep for this amount of time before doing another
- * check (it will still wake if a new task is added). The first task in the queue that is ready
- * will be executed.
- */
- @MainThread
- long getReadyInMilliSeconds();
-
- /**
- * Called on the main thread when the scheduler is about to send the task into the worker
- * thread, calling {@link #onExecuteInBackgroundThread()}
- */
- @MainThread
- void onBeforeExecute();
-
- /**
- * The actual payload of the task, executed on the worker thread.
- */
- @WorkerThread
- void onExecuteInBackgroundThread();
-
- /**
- * Called on the main thread when {@link #onExecuteInBackgroundThread()} has finished or thrown
- * an uncaught exception. The task is already removed from the queue at this point, and a same
- * task can be queued again.
- */
- @MainThread
- void onCompleted();
-
- /**
- * Another task with the same TaskId has been added. Necessary data can be retrieved from the
- * other task, and after this returns the task will be discarded.
- */
- @MainThread
- void onDuplicatedTaskAdded(Task task);
-}
diff --git a/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java b/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java
deleted file mode 100644
index 3d6fcdb..0000000
--- a/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerService.java
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-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;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-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;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.scheduling.Task.TaskId;
-import java.util.ArrayDeque;
-import java.util.Queue;
-
-/**
- * A service to queue and run {@link Task} on a worker thread. Only one task will be ran at a time,
- * and same task cannot exist in the queue at the same time. The service will be started when a
- * intent is received, and stopped when there are no more tasks in the queue.
- */
-public class TaskSchedulerService extends Service {
-
- 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,
- * especially the ones submitted in {@link Task#onCompleted()}. Wait for a while before stopping
- * the service to make sure there are no pending messages.
- */
- private static final int STOP_DELAY_MILLISECONDS = 5_000;
- private static final String EXTRA_CLASS_NAME = "extra_class_name";
-
- private static final String WAKE_LOCK_TAG = "TaskSchedulerService_wakelock";
-
- // The thread to run tasks on
- private volatile WorkerThreadHandler mWorkerThreadHandler;
-
- private Context mContext = this;
- /**
- * Used by tests to turn task handling into a single threaded process by calling {@link
- * Handler#handleMessage(Message)} directly
- */
- private MessageSender mMessageSender = new MessageSender();
-
- private MainThreadHandler mMainThreadHandler;
-
- private WakeLock mWakeLock;
-
- /**
- * Main thread only, access through {@link #getTasks()}
- */
- private final Queue<Task> mTasks = new ArrayDeque<>();
- private boolean mWorkerThreadIsBusy = false;
-
- private final Runnable mStopServiceWithDelay = new Runnable() {
- @Override
- public void run() {
- VvmLog.d(TAG, "Stopping service");
- stopSelf();
- }
- };
- /**
- * Should attempt to run the next task when a task has finished or been added.
- */
- private boolean mTaskAutoRunDisabledForTesting = false;
-
- @VisibleForTesting
- final class WorkerThreadHandler extends Handler {
-
- public WorkerThreadHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- @WorkerThread
- public void handleMessage(Message msg) {
- Assert.isNotMainThread();
- Task task = (Task) msg.obj;
- try {
- VvmLog.v(TAG, "executing task " + task);
- task.onExecuteInBackgroundThread();
- } catch (Throwable throwable) {
- VvmLog.e(TAG, "Exception while executing task " + task + ":", throwable);
- }
-
- Message schedulerMessage = mMainThreadHandler.obtainMessage();
- schedulerMessage.obj = task;
- mMessageSender.send(schedulerMessage);
- }
- }
-
- @VisibleForTesting
- final class MainThreadHandler extends Handler {
-
- public MainThreadHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- @MainThread
- public void handleMessage(Message msg) {
- Assert.isMainThread();
- Task task = (Task) msg.obj;
- getTasks().remove(task);
- task.onCompleted();
- mWorkerThreadIsBusy = false;
- maybeRunNextTask();
- }
- }
-
- @Override
- @MainThread
- public void onCreate() {
- super.onCreate();
- mWakeLock = getSystemService(PowerManager.class)
- .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG);
- mWakeLock.setReferenceCounted(false);
- HandlerThread thread = new HandlerThread("VvmTaskSchedulerService");
- thread.start();
-
- mWorkerThreadHandler = new WorkerThreadHandler(thread.getLooper());
- mMainThreadHandler = new MainThreadHandler(Looper.getMainLooper());
- }
-
- @Override
- public void onDestroy() {
- mWorkerThreadHandler.getLooper().quit();
- mWakeLock.release();
- }
-
- @Override
- @MainThread
- public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
- Assert.isMainThread();
- // 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 {
- 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;
- }
-
- @MainThread
- @VisibleForTesting
- void addTask(Task task) {
- Assert.isMainThread();
- if (task.getId().id == Task.TASK_INVALID) {
- throw new AssertionError("Task id was not set to a valid value before adding.");
- }
- if (task.getId().id != Task.TASK_ALLOW_DUPLICATES) {
- Task oldTask = getTask(task.getId());
- if (oldTask != null) {
- oldTask.onDuplicatedTaskAdded(task);
- return;
- }
- }
- mMainThreadHandler.removeCallbacks(mStopServiceWithDelay);
- getTasks().add(task);
- maybeRunNextTask();
- }
-
- @MainThread
- @Nullable
- private Task getTask(TaskId taskId) {
- Assert.isMainThread();
- for (Task task : getTasks()) {
- if (task.getId().equals(taskId)) {
- return task;
- }
- }
- return null;
- }
-
- @MainThread
- private Queue<Task> getTasks() {
- Assert.isMainThread();
- return mTasks;
- }
-
- /**
- * Create an intent that will queue the <code>task</code>
- */
- public static Intent createIntent(Context context, Class<? extends Task> task) {
- Intent intent = new Intent(context, TaskSchedulerService.class);
- intent.putExtra(EXTRA_CLASS_NAME, task.getName());
- return intent;
- }
-
- @VisibleForTesting
- @MainThread
- @Nullable
- Task createTask(@Nullable Intent intent, int flags, int startId) {
- Assert.isMainThread();
- if (intent == null) {
- return null;
- }
- String className = intent.getStringExtra(EXTRA_CLASS_NAME);
- VvmLog.d(TAG, "create task:" + className);
- if (className == null) {
- throw new IllegalArgumentException("EXTRA_CLASS_NAME expected");
- }
- try {
- Task task = (Task) Class.forName(className).newInstance();
- task.onCreate(mContext, intent, flags, startId);
- return task;
- } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
- throw new IllegalArgumentException(e);
- }
- }
-
- @MainThread
- private void maybeRunNextTask() {
- Assert.isMainThread();
- if (mWorkerThreadIsBusy) {
- return;
- }
- if (mTaskAutoRunDisabledForTesting) {
- // If mTaskAutoRunDisabledForTesting is true, runNextTask() must be explicitly called
- // to run the next task.
- return;
- }
-
- runNextTask();
- }
-
- @VisibleForTesting
- @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;
- }
- Long minimalWaitTime = null;
- for (Task task : getTasks()) {
- long waitTime = task.getReadyInMilliSeconds();
- if (waitTime < READY_TOLERANCE_MILLISECONDS) {
- task.onBeforeExecute();
- Message message = mWorkerThreadHandler.obtainMessage();
- message.obj = task;
- mWorkerThreadIsBusy = true;
- mMessageSender.send(message);
- return;
- } else {
- if (minimalWaitTime == null || waitTime < minimalWaitTime) {
- minimalWaitTime = waitTime;
- }
- }
- }
- VvmLog.d(TAG, "minimal wait time:" + minimalWaitTime);
- if (!mTaskAutoRunDisabledForTesting && minimalWaitTime != null) {
- // 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();
- }
- }, 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() {
- VvmLog.d(TAG,
- "No more tasks, stopping service if no task are added in "
- + STOP_DELAY_MILLISECONDS + " millis");
- mMainThreadHandler.postDelayed(mStopServiceWithDelay, STOP_DELAY_MILLISECONDS);
- }
-
- static class MessageSender {
-
- public void send(Message message) {
- message.sendToTarget();
- }
- }
-
- @NeededForTesting
- void setContextForTest(Context context) {
- mContext = context;
- }
-
- @NeededForTesting
- void setTaskAutoRunDisabledForTest(boolean value) {
- mTaskAutoRunDisabledForTesting = value;
- }
-
- @NeededForTesting
- void setMessageSenderForTest(MessageSender sender) {
- mMessageSender = sender;
- }
-
- @NeededForTesting
- void clearTasksForTest() {
- mTasks.clear();
- }
-
- @Override
- @Nullable
- public IBinder onBind(Intent intent) {
- return new LocalBinder();
- }
-
- @NeededForTesting
- class LocalBinder extends Binder {
-
- @NeededForTesting
- public TaskSchedulerService getService() {
- return TaskSchedulerService.this;
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sms/LegacyModeSmsHandler.java b/src/com/android/phone/vvm/omtp/sms/LegacyModeSmsHandler.java
deleted file mode 100644
index 6a5f349..0000000
--- a/src/com/android/phone/vvm/omtp/sms/LegacyModeSmsHandler.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2016 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.sms;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.telephony.VisualVoicemailSms;
-
-import com.android.internal.telephony.Phone;
-import com.android.phone.PhoneUtils;
-import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VvmLog;
-
-/**
- * Class ot handle voicemail SMS under legacy mode
- *
- * @see OmtpVvmCarrierConfigHelper#isLegacyModeEnabled()
- */
-public class LegacyModeSmsHandler {
-
- private static final String TAG = "LegacyModeSmsHandler";
-
- public static void handle(Context context, VisualVoicemailSms sms) {
- VvmLog.v(TAG, "processing VVM SMS on legacy mode");
- String eventType = sms.getPrefix();
- Bundle data = sms.getFields();
-
- if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) {
- SyncMessage message = new SyncMessage(data);
- VvmLog.v(TAG, "Received SYNC sms for " + sms.getPhoneAccountHandle() +
- " with event " + message.getSyncTriggerEvent());
-
- switch (message.getSyncTriggerEvent()) {
- case OmtpConstants.NEW_MESSAGE:
- case OmtpConstants.MAILBOX_UPDATE:
- // The user has called into the voicemail and the new message count could
- // change.
- // For some carriers new message count could be set to 0 even if there are still
- // unread messages, to clear the message waiting indicator.
- VvmLog.v(TAG, "updating MWI");
- Phone phone = PhoneUtils.getPhoneForPhoneAccountHandle(
- sms.getPhoneAccountHandle());
- // Setting voicemail message count to non-zero will show the telephony voicemail
- // notification, and zero will clear it.
- phone.setVoiceMessageCount(message.getNewMessageCount());
- break;
- default:
- break;
- }
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpCvvmMessageSender.java b/src/com/android/phone/vvm/omtp/sms/OmtpCvvmMessageSender.java
deleted file mode 100644
index 98d8594..0000000
--- a/src/com/android/phone/vvm/omtp/sms/OmtpCvvmMessageSender.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.phone.vvm.omtp.sms;
-
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.telephony.SmsManager;
-
-import com.android.phone.vvm.omtp.OmtpConstants;
-
-/**
- * An implementation of the OmtpMessageSender for T-Mobile.
- */
-public class OmtpCvvmMessageSender extends OmtpMessageSender {
- public OmtpCvvmMessageSender(SmsManager smsManager, short applicationPort,
- String destinationNumber) {
- super(smsManager, applicationPort, destinationNumber);
- }
-
- @Override
- public void requestVvmActivation(@Nullable PendingIntent sentIntent) {
- sendCvvmMessage(OmtpConstants.ACTIVATE_REQUEST, sentIntent);
- }
-
- @Override
- public void requestVvmDeactivation(@Nullable PendingIntent sentIntent) {
- sendCvvmMessage(OmtpConstants.DEACTIVATE_REQUEST, sentIntent);
- }
-
- @Override
- public void requestVvmStatus(@Nullable PendingIntent sentIntent) {
- sendCvvmMessage(OmtpConstants.STATUS_REQUEST, sentIntent);
- }
-
- private void sendCvvmMessage(String request, PendingIntent sentIntent) {
- StringBuilder sb = new StringBuilder().append(request);
- sb.append(OmtpConstants.SMS_PREFIX_SEPARATOR);
- appendField(sb, "dt" /* device type */, "6" /* no VTT (transcription) support*/);
- sendSms(sb.toString(), sentIntent);
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
deleted file mode 100644
index d42e70e..0000000
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.sms;
-
-import android.content.ContentUris;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.UserManager;
-import android.provider.VoicemailContract;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.Voicemail;
-import android.telephony.VisualVoicemailSms;
-
-import com.android.phone.settings.VisualVoicemailSettingsUtil;
-import com.android.phone.vvm.omtp.ActivationTask;
-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 com.android.phone.vvm.omtp.sync.OmtpVvmSyncService;
-import com.android.phone.vvm.omtp.sync.SyncOneTask;
-import com.android.phone.vvm.omtp.sync.SyncTask;
-import com.android.phone.vvm.omtp.sync.VoicemailsQueryHelper;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
-/**
- * Receive SMS messages and send for processing by the OMTP visual voicemail source.
- */
-public class OmtpMessageReceiver {
-
- private static final String TAG = "OmtpMessageReceiver";
-
- public static void onReceive(Context context, VisualVoicemailSms sms) {
-
- PhoneAccountHandle phone = sms.getPhoneAccountHandle();
- int subId = PhoneAccountHandleConverter.toSubId(phone);
- if (!UserManager.get(context).isUserUnlocked()) {
- VvmLog.i(TAG, "Received message on locked device");
- // LegacyModeSmsHandler can handle new message notifications without storage access
- LegacyModeSmsHandler.handle(context, sms);
- // A full sync will happen after the device is unlocked, so nothing else need to be
- // done.
- return;
- }
-
- OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, subId);
- if (!VisualVoicemailSettingsUtil.isEnabled(context, phone)) {
- if (helper.isLegacyModeEnabled()) {
- LegacyModeSmsHandler.handle(context, sms);
- } else {
- VvmLog.i(TAG, "Received vvm message for disabled vvm source.");
- }
- return;
- }
-
- String eventType = sms.getPrefix();
- Bundle data = sms.getFields();
-
- if (eventType == null || data == null) {
- VvmLog.e(TAG, "Unparsable VVM SMS received, ignoring");
- return;
- }
-
- if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) {
- SyncMessage message = new SyncMessage(data);
-
- VvmLog.v(TAG, "Received SYNC sms for " + subId +
- " with event " + message.getSyncTriggerEvent());
- processSync(context, phone, message);
- } else if (eventType.equals(OmtpConstants.STATUS_SMS_PREFIX)) {
- VvmLog.v(TAG, "Received Status sms for " + subId);
- // If the STATUS SMS is initiated by ActivationTask the TaskSchedulerService will reject
- // the follow request. Providing the data will also prevent ActivationTask from
- // requesting another STATUS SMS. The following task will only run if the carrier
- // spontaneous send a STATUS SMS, in that case, the VVM service should be reactivated.
- ActivationTask.start(context, subId, data);
- } else {
- VvmLog.w(TAG, "Unknown prefix: " + eventType);
- VisualVoicemailProtocol protocol = helper.getProtocol();
- if (protocol == null) {
- return;
- }
- Bundle statusData = helper.getProtocol()
- .translateStatusSmsBundle(helper, eventType, data);
- if (statusData != null) {
- VvmLog.i(TAG, "Protocol recognized the SMS as STATUS, activating");
- ActivationTask.start(context, subId, data);
- }
- }
- }
-
- /**
- * A sync message has two purposes: to signal a new voicemail message, and to indicate the
- * voicemails on the server have changed remotely (usually through the TUI). Save the new
- * message to the voicemail provider if it is the former case and perform a full sync in the
- * latter case.
- *
- * @param message The sync message to extract data from.
- */
- private static void processSync(Context context, PhoneAccountHandle phone,
- SyncMessage message) {
- Intent serviceIntent = null;
- switch (message.getSyncTriggerEvent()) {
- case OmtpConstants.NEW_MESSAGE:
- if (!OmtpConstants.VOICE.equals(message.getContentType())) {
- VvmLog.i(TAG, "Non-voice message of type '" + message.getContentType()
- + "' received, ignoring");
- return;
- }
-
- Voicemail.Builder builder = Voicemail.createForInsertion(
- message.getTimestampMillis(), message.getSender())
- .setPhoneAccount(phone)
- .setSourceData(message.getId())
- .setDuration(message.getLength())
- .setSourcePackage(context.getPackageName());
- Voicemail voicemail = builder.build();
-
- VoicemailsQueryHelper queryHelper = new VoicemailsQueryHelper(context);
- if (queryHelper.isVoicemailUnique(voicemail)) {
- Uri uri = VoicemailContract.Voicemails.insert(context, voicemail);
- voicemail = builder.setId(ContentUris.parseId(uri)).setUri(uri).build();
- SyncOneTask.start(context, phone, voicemail);
- }
- break;
- case OmtpConstants.MAILBOX_UPDATE:
- SyncTask.start(context, phone, OmtpVvmSyncService.SYNC_DOWNLOAD_ONLY);
- break;
- case OmtpConstants.GREETINGS_UPDATE:
- // Not implemented in V1
- break;
- default:
- VvmLog.e(TAG,
- "Unrecognized sync trigger event: " + message.getSyncTriggerEvent());
- break;
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageSender.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageSender.java
deleted file mode 100644
index 9a775f0..0000000
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageSender.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.phone.vvm.omtp.sms;
-
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.telephony.SmsManager;
-
-import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.VvmLog;
-
-import java.io.UnsupportedEncodingException;
-import java.util.Locale;
-
-/**
- * Send client originated OMTP messages to the OMTP server.
- * <p>
- * Uses {@link PendingIntent} instead of a call back to notify when the message is
- * sent. This is primarily to keep the implementation simple and reuse what the underlying
- * {@link SmsManager} interface provides.
- * <p>
- * Provides simple APIs to send different types of mobile originated OMTP SMS to the VVM server.
- */
-public abstract class OmtpMessageSender {
- protected static final String TAG = "OmtpMessageSender";
- protected short mApplicationPort;
- protected String mDestinationNumber;
- protected SmsManager mSmsManager;
-
- public OmtpMessageSender(SmsManager smsManager, short applicationPort,
- String destinationNumber) {
- mSmsManager = smsManager;
- mApplicationPort = applicationPort;
- mDestinationNumber = destinationNumber;
- }
-
- /**
- * Sends a request to the VVM server to activate VVM for the current subscriber.
- *
- * @param sentIntent If not NULL this PendingIntent is broadcast when the message is
- * successfully sent, or failed.
- */
- public void requestVvmActivation(@Nullable PendingIntent sentIntent) {}
-
- /**
- * Sends a request to the VVM server to deactivate VVM for the current subscriber.
- *
- * @param sentIntent If not NULL this PendingIntent is broadcast when the message is
- * successfully sent, or failed.
- */
- public void requestVvmDeactivation(@Nullable PendingIntent sentIntent) {}
-
- /**
- * Send a request to the VVM server to get account status of the current subscriber.
- *
- * @param sentIntent If not NULL this PendingIntent is broadcast when the message is
- * successfully sent, or failed.
- */
- public void requestVvmStatus(@Nullable PendingIntent sentIntent) {}
-
- protected void sendSms(String text, PendingIntent sentIntent) {
- // If application port is set to 0 then send simple text message, else send data message.
- if (mApplicationPort == 0) {
- VvmLog
- .v(TAG, String.format("Sending TEXT sms '%s' to %s", text, mDestinationNumber));
- mSmsManager.sendTextMessageWithSelfPermissions(mDestinationNumber, null, text,
- sentIntent, null, false);
- } else {
- byte[] data;
- try {
- data = text.getBytes("UTF-8");
- } catch (UnsupportedEncodingException e) {
- throw new IllegalStateException("Failed to encode: " + text);
- }
- VvmLog.v(TAG,
- String.format(Locale.US, "Sending BINARY sms '%s' to %s:%d", text,
- mDestinationNumber, mApplicationPort));
- mSmsManager.sendDataMessageWithSelfPermissions(mDestinationNumber, null,
- mApplicationPort, data, sentIntent, null);
- }
- }
-
- protected void appendField(StringBuilder sb, String field, Object value) {
- sb.append(field).append(OmtpConstants.SMS_KEY_VALUE_SEPARATOR).append(value);
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpStandardMessageSender.java b/src/com/android/phone/vvm/omtp/sms/OmtpStandardMessageSender.java
deleted file mode 100644
index 05276e1..0000000
--- a/src/com/android/phone/vvm/omtp/sms/OmtpStandardMessageSender.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2015 Google Inc. All Rights Reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.phone.vvm.omtp.sms;
-
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.telephony.SmsManager;
-import android.text.TextUtils;
-
-import com.android.phone.vvm.omtp.OmtpConstants;
-
-/**
- * A implementation of the OmtpMessageSender using the standard OMTP sms protocol.
- */
-public class OmtpStandardMessageSender extends OmtpMessageSender {
- private final String mClientType;
- private final String mProtocolVersion;
- private final String mClientPrefix;
-
- /**
- * Creates a new instance of OmtpStandardMessageSender.
- *
- * @param smsManager SMS sending library. There is a different SmsManager for each SIM.
- * @param applicationPort If set to a value > 0 then a binary sms is sent to this port number.
- * Otherwise, a standard text SMS is sent.
- * @param destinationNumber Destination number to be used.
- * @param clientType The "ct" field to be set in the MO message. This is the value used by the
- * VVM server to identify the client. Certain VVM servers require a specific agreed
- * value for this field.
- * @param protocolVersion OMTP protocol version.
- * @param clientPrefix The client prefix requested to be used by the server in its MT messages.
- */
- public OmtpStandardMessageSender(SmsManager smsManager, short applicationPort,
- String destinationNumber, String clientType, String protocolVersion,
- String clientPrefix) {
- super(smsManager, applicationPort, destinationNumber);
- mClientType = clientType;
- mProtocolVersion = protocolVersion;
- mClientPrefix = clientPrefix;
- }
-
- // Activate message:
- // V1.1: Activate:pv=<value>;ct=<value>
- // V1.2: Activate:pv=<value>;ct=<value>;pt=<value>;<Clientprefix>
- // V1.3: Activate:pv=<value>;ct=<value>;pt=<value>;<Clientprefix>
- @Override
- public void requestVvmActivation(@Nullable PendingIntent sentIntent) {
- StringBuilder sb = new StringBuilder().append(OmtpConstants.ACTIVATE_REQUEST);
-
- appendProtocolVersionAndClientType(sb);
- if (TextUtils.equals(mProtocolVersion, OmtpConstants.PROTOCOL_VERSION1_2) ||
- TextUtils.equals(mProtocolVersion, OmtpConstants.PROTOCOL_VERSION1_3)) {
- appendApplicationPort(sb);
- appendClientPrefix(sb);
- }
-
- sendSms(sb.toString(), sentIntent);
- }
-
- // Deactivate message:
- // V1.1: Deactivate:pv=<value>;ct=<string>
- // V1.2: Deactivate:pv=<value>;ct=<string>
- // V1.3: Deactivate:pv=<value>;ct=<string>
- @Override
- public void requestVvmDeactivation(@Nullable PendingIntent sentIntent) {
- StringBuilder sb = new StringBuilder().append(OmtpConstants.DEACTIVATE_REQUEST);
- appendProtocolVersionAndClientType(sb);
-
- sendSms(sb.toString(), sentIntent);
- }
-
- // Status message:
- // V1.1: STATUS
- // V1.2: STATUS
- // V1.3: STATUS:pv=<value>;ct=<value>;pt=<value>;<Clientprefix>
- @Override
- public void requestVvmStatus(@Nullable PendingIntent sentIntent) {
- StringBuilder sb = new StringBuilder().append(OmtpConstants.STATUS_REQUEST);
-
- if (TextUtils.equals(mProtocolVersion, OmtpConstants.PROTOCOL_VERSION1_3)) {
- appendProtocolVersionAndClientType(sb);
- appendApplicationPort(sb);
- appendClientPrefix(sb);
- }
-
- sendSms(sb.toString(), sentIntent);
- }
-
- private void appendProtocolVersionAndClientType(StringBuilder sb) {
- sb.append(OmtpConstants.SMS_PREFIX_SEPARATOR);
- appendField(sb, OmtpConstants.PROTOCOL_VERSION, mProtocolVersion);
- sb.append(OmtpConstants.SMS_FIELD_SEPARATOR);
- appendField(sb, OmtpConstants.CLIENT_TYPE, mClientType);
- }
-
- private void appendApplicationPort(StringBuilder sb) {
- sb.append(OmtpConstants.SMS_FIELD_SEPARATOR);
- appendField(sb, OmtpConstants.APPLICATION_PORT, mApplicationPort);
- }
-
- private void appendClientPrefix(StringBuilder sb) {
- sb.append(OmtpConstants.SMS_FIELD_SEPARATOR);
- sb.append(mClientPrefix);
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sms/StatusMessage.java b/src/com/android/phone/vvm/omtp/sms/StatusMessage.java
deleted file mode 100644
index 65455d0..0000000
--- a/src/com/android/phone/vvm/omtp/sms/StatusMessage.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.sms;
-
-import android.os.Bundle;
-import android.telecom.Log;
-
-import com.android.phone.NeededForTesting;
-import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
-
-/**
- * Structured data representation of OMTP STATUS message.
- *
- * The getters will return null if the field was not set in the message body or it could not be
- * parsed.
- */
-public class StatusMessage {
- // NOTE: Following Status SMS fields are not yet parsed, as they do not seem
- // to be useful for initial omtp source implementation.
- // lang, g_len, vs_len, pw_len, pm, gm, vtc, vt
-
- private final String mProvisioningStatus;
- private final String mStatusReturnCode;
- private final String mSubscriptionUrl;
- private final String mServerAddress;
- private final String mTuiAccessNumber;
- private final String mClientSmsDestinationNumber;
- private final String mImapPort;
- private final String mImapUserName;
- private final String mImapPassword;
- private final String mSmtpPort;
- private final String mSmtpUserName;
- private final String mSmtpPassword;
- private final String mTuiPasswordLength;
-
- @Override
- public String toString() {
- return "StatusMessage [mProvisioningStatus=" + mProvisioningStatus
- + ", mStatusReturnCode=" + mStatusReturnCode
- + ", mSubscriptionUrl=" + mSubscriptionUrl
- + ", mServerAddress=" + mServerAddress
- + ", mTuiAccessNumber=" + mTuiAccessNumber
- + ", mClientSmsDestinationNumber=" + mClientSmsDestinationNumber
- + ", mImapPort=" + mImapPort
- + ", mImapUserName=" + mImapUserName
- + ", mImapPassword=" + Log.pii(mImapPassword)
- + ", mSmtpPort=" + mSmtpPort
- + ", mSmtpUserName=" + mSmtpUserName
- + ", mSmtpPassword=" + Log.pii(mSmtpPassword)
- + ", mTuiPasswordLength=" + mTuiPasswordLength + "]";
- }
-
- public StatusMessage(Bundle wrappedData) {
- mProvisioningStatus = unquote(getString(wrappedData, OmtpConstants.PROVISIONING_STATUS));
- mStatusReturnCode = getString(wrappedData, OmtpConstants.RETURN_CODE);
- mSubscriptionUrl = getString(wrappedData, OmtpConstants.SUBSCRIPTION_URL);
- mServerAddress = getString(wrappedData, OmtpConstants.SERVER_ADDRESS);
- mTuiAccessNumber = getString(wrappedData, OmtpConstants.TUI_ACCESS_NUMBER);
- mClientSmsDestinationNumber = getString(wrappedData,
- OmtpConstants.CLIENT_SMS_DESTINATION_NUMBER);
- mImapPort = getString(wrappedData, OmtpConstants.IMAP_PORT);
- mImapUserName = getString(wrappedData, OmtpConstants.IMAP_USER_NAME);
- mImapPassword = getString(wrappedData, OmtpConstants.IMAP_PASSWORD);
- mSmtpPort = getString(wrappedData, OmtpConstants.SMTP_PORT);
- mSmtpUserName = getString(wrappedData, OmtpConstants.SMTP_USER_NAME);
- mSmtpPassword = getString(wrappedData, OmtpConstants.SMTP_PASSWORD);
- mTuiPasswordLength = getString(wrappedData, OmtpConstants.TUI_PASSWORD_LENGTH);
- }
-
- private static String unquote(String string) {
- if (string.length() < 2) {
- return string;
- }
- if (string.startsWith("\"") && string.endsWith("\"")) {
- return string.substring(1, string.length() - 1);
- }
- return string;
- }
-
- /**
- * @return the subscriber's VVM provisioning status.
- */
- public String getProvisioningStatus() {
- return mProvisioningStatus;
- }
-
- /**
- * @return the return-code of the status SMS.
- */
- public String getReturnCode() {
- return mStatusReturnCode;
- }
-
- /**
- * @return the URL of the voicemail server. This is the URL to send the users to for subscribing
- * to the visual voicemail service.
- */
- @NeededForTesting
- public String getSubscriptionUrl() {
- return mSubscriptionUrl;
- }
-
- /**
- * @return the voicemail server address. Either server IP address or fully qualified domain
- * name.
- */
- public String getServerAddress() {
- return mServerAddress;
- }
-
- /**
- * @return the Telephony User Interface number to call to access voicemails directly from the
- * IVR.
- */
- @NeededForTesting
- public String getTuiAccessNumber() {
- return mTuiAccessNumber;
- }
-
- /**
- * @return the number to which client originated SMSes should be sent to.
- */
- @NeededForTesting
- public String getClientSmsDestinationNumber() {
- return mClientSmsDestinationNumber;
- }
-
- /**
- * @return the IMAP server port to talk to.
- */
- public String getImapPort() {
- return mImapPort;
- }
-
- /**
- * @return the IMAP user name to be used for authentication.
- */
- public String getImapUserName() {
- return mImapUserName;
- }
-
- /**
- * @return the IMAP password to be used for authentication.
- */
- public String getImapPassword() {
- return mImapPassword;
- }
-
- /**
- * @return the SMTP server port to talk to.
- */
- @NeededForTesting
- public String getSmtpPort() {
- return mSmtpPort;
- }
-
- /**
- * @return the SMTP user name to be used for SMTP authentication.
- */
- @NeededForTesting
- public String getSmtpUserName() {
- return mSmtpUserName;
- }
-
- /**
- * @return the SMTP password to be used for SMTP authentication.
- */
- @NeededForTesting
- public String getSmtpPassword() {
- return mSmtpPassword;
- }
-
- public String getTuiPasswordLength() {
- return mTuiPasswordLength;
- }
-
- private static String getString(Bundle bundle, String key) {
- String value = bundle.getString(key);
- if (value == null) {
- return "";
- }
- return value;
- }
-
- /**
- * Saves a StatusMessage to the {@link VisualVoicemailPreferences}. Not all fields are saved.
- */
- public VisualVoicemailPreferences.Editor putStatus(VisualVoicemailPreferences.Editor editor) {
- return editor
- .putString(OmtpConstants.IMAP_PORT, getImapPort())
- .putString(OmtpConstants.SERVER_ADDRESS, getServerAddress())
- .putString(OmtpConstants.IMAP_USER_NAME, getImapUserName())
- .putString(OmtpConstants.IMAP_PASSWORD, getImapPassword())
- .putString(OmtpConstants.TUI_PASSWORD_LENGTH, getTuiPasswordLength());
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java b/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
deleted file mode 100644
index adaa2f4..0000000
--- a/src/com/android/phone/vvm/omtp/sms/StatusSmsFetcher.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2015 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.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.telecom.PhoneAccountHandle;
-import android.telephony.SmsManager;
-import android.telephony.VisualVoicemailSms;
-
-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 com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
-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;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Intercepts a incoming STATUS SMS with a blocking call.
- */
-public class StatusSmsFetcher extends BroadcastReceiver implements Closeable {
-
- 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<>();
-
- private final Context mContext;
- private final int mSubId;
-
- public StatusSmsFetcher(Context context, int subId) {
- mContext = context;
- mSubId = subId;
- IntentFilter filter = new IntentFilter(VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED);
- filter.addAction(ACTION_REQUEST_SENT_INTENT);
- context.registerReceiver(this, filter);
- }
-
- @Override
- public void close() throws IOException {
- mContext.unregisterReceiver(this);
- }
-
- @WorkerThread
- @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;
- }
-
- VisualVoicemailSms sms = intent.getExtras()
- .getParcelable(VoicemailContract.EXTRA_VOICEMAIL_SMS);
- PhoneAccountHandle phoneAccountHandle = sms.getPhoneAccountHandle();
- int subId = PhoneAccountHandleConverter.toSubId(phoneAccountHandle);
- if (mSubId != subId) {
- return;
- }
- String eventType = sms.getPrefix();
-
- if (eventType.equals(OmtpConstants.STATUS_SMS_PREFIX)) {
- mFuture.complete(sms.getFields());
- return;
- }
-
- if (eventType.equals(OmtpConstants.SYNC_SMS_PREFIX)) {
- return;
- }
-
- VvmLog.i(TAG, "VVM SMS with event " + eventType
- + " received, attempting to translate to STATUS SMS");
- OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(context, subId);
- VisualVoicemailProtocol protocol = helper.getProtocol();
- if (protocol == null) {
- return;
- }
- Bundle translatedBundle = protocol.translateStatusSmsBundle(helper, eventType,
- sms.getFields());
-
- if (translatedBundle != null) {
- VvmLog.i(TAG, "Translated to STATUS SMS");
- 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/phone/vvm/omtp/sms/SyncMessage.java b/src/com/android/phone/vvm/omtp/sms/SyncMessage.java
deleted file mode 100644
index 632ff9e..0000000
--- a/src/com/android/phone/vvm/omtp/sms/SyncMessage.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.sms;
-
-import android.annotation.Nullable;
-import android.os.Bundle;
-
-import com.android.phone.NeededForTesting;
-import com.android.phone.vvm.omtp.OmtpConstants;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Locale;
-
-/**
- * Structured data representation of an OMTP SYNC message.
- *
- * Getters will return null if the field was not set in the message body or it could not be parsed.
- */
-public class SyncMessage {
- // Sync event that triggered this message.
- private final String mSyncTriggerEvent;
- // Total number of new messages on the server.
- private final int mNewMessageCount;
- // UID of the new message.
- private final String mMessageId;
- // Length of the message.
- private final int mMessageLength;
- // Content type (voice, video, fax...) of the new message.
- private final String mContentType;
- // Sender of the new message.
- private final String mSender;
- // Timestamp (in millis) of the new message.
- private final long mMsgTimeMillis;
-
- @Override
- public String toString() {
- return "SyncMessage [mSyncTriggerEvent=" + mSyncTriggerEvent
- + ", mNewMessageCount=" + mNewMessageCount
- + ", mMessageId=" + mMessageId
- + ", mMessageLength=" + mMessageLength
- + ", mContentType=" + mContentType
- + ", mSender=" + mSender
- + ", mMsgTimeMillis=" + mMsgTimeMillis + "]";
- }
-
- public SyncMessage(Bundle wrappedData) {
- mSyncTriggerEvent = getString(wrappedData, OmtpConstants.SYNC_TRIGGER_EVENT);
- mMessageId = getString(wrappedData, OmtpConstants.MESSAGE_UID);
- mMessageLength = getInt(wrappedData, OmtpConstants.MESSAGE_LENGTH);
- mContentType = getString(wrappedData, OmtpConstants.CONTENT_TYPE);
- mSender = getString(wrappedData, OmtpConstants.SENDER);
- mNewMessageCount = getInt(wrappedData, OmtpConstants.NUM_MESSAGE_COUNT);
- mMsgTimeMillis = parseTime(wrappedData.getString(OmtpConstants.TIME));
- }
-
- private static long parseTime(@Nullable String value) {
- if (value == null) {
- return 0L;
- }
- try {
- return new SimpleDateFormat(
- OmtpConstants.DATE_TIME_FORMAT, Locale.US)
- .parse(value).getTime();
- } catch (ParseException e) {
- return 0L;
- }
- }
- /**
- * @return the event that triggered the sync message. This is a mandatory field and must always
- * be set.
- */
- public String getSyncTriggerEvent() {
- return mSyncTriggerEvent;
- }
-
- /**
- * @return the number of new messages stored on the voicemail server.
- */
- @NeededForTesting
- public int getNewMessageCount() {
- return mNewMessageCount;
- }
-
- /**
- * @return the message ID of the new message.
- * <p>
- * Expected to be set only for
- * {@link com.android.phone.vvm.omtp.OmtpConstants#NEW_MESSAGE}
- */
- public String getId() {
- return mMessageId;
- }
-
- /**
- * @return the content type of the new message.
- * <p>
- * Expected to be set only for
- * {@link com.android.phone.vvm.omtp.OmtpConstants#NEW_MESSAGE}
- */
- @NeededForTesting
- public String getContentType() {
- return mContentType;
- }
-
- /**
- * @return the message length of the new message.
- * <p>
- * Expected to be set only for
- * {@link com.android.phone.vvm.omtp.OmtpConstants#NEW_MESSAGE}
- */
- public int getLength() {
- return mMessageLength;
- }
-
- /**
- * @return the sender's phone number of the new message specified as MSISDN.
- * <p>
- * Expected to be set only for
- * {@link com.android.phone.vvm.omtp.OmtpConstants#NEW_MESSAGE}
- */
- public String getSender() {
- return mSender;
- }
-
- /**
- * @return the timestamp as milliseconds for the new message.
- * <p>
- * Expected to be set only for
- * {@link com.android.phone.vvm.omtp.OmtpConstants#NEW_MESSAGE}
- */
- public long getTimestampMillis() {
- return mMsgTimeMillis;
- }
-
- private static int getInt(Bundle wrappedData, String key) {
- String value = wrappedData.getString(key);
- if (value == null) {
- return 0;
- }
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException e) {
- return 0;
- }
- }
-
- private static String getString(Bundle wrappedData, String key) {
- String value = wrappedData.getString(key);
- if (value == null) {
- return "";
- }
- return value;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/sms/Vvm3MessageSender.java b/src/com/android/phone/vvm/omtp/sms/Vvm3MessageSender.java
deleted file mode 100644
index dc2ea58..0000000
--- a/src/com/android/phone/vvm/omtp/sms/Vvm3MessageSender.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-package com.android.phone.vvm.omtp.sms;
-
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.telephony.SmsManager;
-
-public class Vvm3MessageSender extends OmtpMessageSender {
-
- /**
- * Creates a new instance of Vvm3MessageSender.
- *
- * @param smsManager SMS sending library. There is a different SmsManager for each SIM.
- * @param applicationPort If set to a value > 0 then a binary sms is sent to this port number.
- * Otherwise, a standard text SMS is sent.
- */
- public Vvm3MessageSender(SmsManager smsManager, short applicationPort,
- String destinationNumber) {
- super(smsManager, applicationPort, destinationNumber);
- }
-
- @Override
- public void requestVvmActivation(@Nullable PendingIntent sentIntent) {
- // Activation not supported for VVM3, send a status request instead.
- requestVvmStatus(sentIntent);
- }
-
- @Override
- public void requestVvmDeactivation(@Nullable PendingIntent sentIntent) {
- // Deactivation not supported for VVM3, do nothing
- }
-
-
- @Override
- public void requestVvmStatus(@Nullable PendingIntent sentIntent) {
- // Status message:
- // STATUS
- StringBuilder sb = new StringBuilder().append("STATUS");
- sendSms(sb.toString(), sentIntent);
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java
deleted file mode 100644
index 9b06462..0000000
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSourceManager.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.sync;
-
-import android.content.Context;
-import android.telecom.PhoneAccountHandle;
-import android.telephony.PhoneStateListener;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import com.android.internal.telephony.Phone;
-import com.android.phone.PhoneUtils;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.omtp.VvmPhoneStateListener;
-import java.util.Collections;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * A singleton class designed to remember the active OMTP visual voicemail sources. Because a
- * voicemail source is tied 1:1 to a phone account, the phone account handle is used as the key
- * for each voicemail source and the associated data.
- */
-public class OmtpVvmSourceManager {
- public static final String TAG = "OmtpVvmSourceManager";
-
- private static OmtpVvmSourceManager sInstance = new OmtpVvmSourceManager();
-
- private Context mContext;
- private SubscriptionManager mSubscriptionManager;
- private TelephonyManager mTelephonyManager;
- // Each phone account is associated with a phone state listener for updates to whether the
- // device is able to sync.
- private Set<PhoneAccountHandle> mActiveVvmSources;
- private Map<PhoneAccountHandle, PhoneStateListener> mPhoneStateListenerMap;
-
- /**
- * Private constructor. Instance should only be acquired through getInstance().
- */
- private OmtpVvmSourceManager() {}
-
- public static OmtpVvmSourceManager getInstance(Context context) {
- sInstance.setup(context);
- return sInstance;
- }
-
- /**
- * Set the context and system services so they do not need to be retrieved every time.
- * @param context The context to get the subscription and telephony manager for.
- */
- private void setup(Context context) {
- if (mContext == null) {
- mContext = context;
- mSubscriptionManager = SubscriptionManager.from(context);
- mTelephonyManager = (TelephonyManager)
- mContext.getSystemService(Context.TELEPHONY_SERVICE);
- mActiveVvmSources = Collections.newSetFromMap(
- new ConcurrentHashMap<PhoneAccountHandle, Boolean>(8, 0.9f, 1));
- mPhoneStateListenerMap =
- new ConcurrentHashMap<PhoneAccountHandle, PhoneStateListener>(8, 0.9f, 1);
- }
- }
-
- public void addSource(PhoneAccountHandle phoneAccount) {
- mActiveVvmSources.add(phoneAccount);
- }
-
- /**
- * When a voicemail source is removed, we don't always know which one was removed. Check the
- * list of registered phone accounts against the active subscriptions list and remove the
- * inactive sources.
- */
- public void removeInactiveSources() {
- for (PhoneAccountHandle phoneAccount : mActiveVvmSources) {
- if (!PhoneUtils.isPhoneAccountActive(mSubscriptionManager, phoneAccount)) {
- removeSource(phoneAccount);
- }
- }
-
- // Remove any orphaned phone state listeners as well.
- for (PhoneAccountHandle phoneAccount : mPhoneStateListenerMap.keySet()) {
- if (!PhoneUtils.isPhoneAccountActive(mSubscriptionManager, phoneAccount)) {
- removePhoneStateListener(phoneAccount);
- }
- }
- }
-
- public void removeSource(Phone phone) {
- removeSource(PhoneUtils.makePstnPhoneAccountHandle(phone));
- }
-
- public void removeSource(PhoneAccountHandle phoneAccount) {
- // TODO: should use OmtpVvmCarrierConfigHelper to handle the event. But currently it
- // couldn't handle events on removed SIMs
- VoicemailStatus.disable(mContext, phoneAccount);
- removePhoneStateListener(phoneAccount);
- mActiveVvmSources.remove(phoneAccount);
- }
-
- public void addPhoneStateListener(Phone phone) {
- addPhoneStateListener(PhoneUtils.makePstnPhoneAccountHandle(phone));
- }
-
- public void addPhoneStateListener(PhoneAccountHandle phoneAccount) {
- if (!mPhoneStateListenerMap.containsKey(phoneAccount)) {
- VvmPhoneStateListener phoneStateListener = new VvmPhoneStateListener(mContext,
- PhoneUtils.makePstnPhoneAccountHandle(phoneAccount.getId()));
- mPhoneStateListenerMap.put(phoneAccount, phoneStateListener);
- mTelephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
- }
- }
-
- public void removePhoneStateListener(PhoneAccountHandle phoneAccount) {
- PhoneStateListener phoneStateListener =
- mPhoneStateListenerMap.remove(phoneAccount);
- mTelephonyManager.listen(phoneStateListener, 0);
- }
-
- public Set<PhoneAccountHandle> getOmtpVvmSources() {
- return mActiveVvmSources;
- }
-
- /**
- * Check if a certain account is registered.
- *
- * @param phoneAccount The account to look for.
- * @return {@code true} if the account is in the list of registered OMTP voicemail sources.
- * {@code false} otherwise.
- */
- public boolean isVvmSourceRegistered(PhoneAccountHandle phoneAccount) {
- if (phoneAccount == null) {
- return false;
- }
-
- return mActiveVvmSources.contains(phoneAccount);
- }
-}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncReceiver.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncReceiver.java
deleted file mode 100644
index 41178eb..0000000
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncReceiver.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.sync;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.provider.VoicemailContract;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.TelecomManager;
-import com.android.phone.settings.VisualVoicemailSettingsUtil;
-import com.android.phone.vvm.omtp.ActivationTask;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-import java.util.List;
-
-public class OmtpVvmSyncReceiver extends BroadcastReceiver {
-
- private static final String TAG = "OmtpVvmSyncReceiver";
-
- @Override
- public void onReceive(final Context context, Intent intent) {
- if (VoicemailContract.ACTION_SYNC_VOICEMAIL.equals(intent.getAction())) {
- VvmLog.v(TAG, "Sync intent received");
- for (PhoneAccountHandle source : OmtpVvmSourceManager.getInstance(context)
- .getOmtpVvmSources()) {
- SyncTask.start(context, source, OmtpVvmSyncService.SYNC_FULL_SYNC);
- }
- activateUnactivatedAccounts(context);
- }
- }
-
- private static void activateUnactivatedAccounts(Context context) {
- List<PhoneAccountHandle> accounts =
- context.getSystemService(TelecomManager.class).getCallCapablePhoneAccounts();
- for (PhoneAccountHandle phoneAccount : accounts) {
- if (!VisualVoicemailSettingsUtil.isEnabled(context, phoneAccount)) {
- continue;
- }
- int subId = PhoneAccountHandleConverter.toSubId(phoneAccount);
- if (!OmtpVvmSourceManager.getInstance(context).isVvmSourceRegistered(phoneAccount)) {
- VvmLog.i(TAG, "Unactivated account " + phoneAccount + " found, activating");
- ActivationTask.start(context, subId, null);
- }
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
deleted file mode 100644
index 58797de..0000000
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.sync;
-
-import android.content.Context;
-import android.net.Network;
-import android.net.Uri;
-import android.provider.VoicemailContract;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.Voicemail;
-import android.text.TextUtils;
-import com.android.phone.Assert;
-import com.android.phone.PhoneUtils;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.settings.VisualVoicemailSettingsUtil;
-import com.android.phone.vvm.omtp.ActivationTask;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
-import com.android.phone.vvm.omtp.imap.ImapHelper;
-import com.android.phone.vvm.omtp.imap.ImapHelper.InitializingException;
-import com.android.phone.vvm.omtp.scheduling.BaseTask;
-import com.android.phone.vvm.omtp.sync.VvmNetworkRequest.NetworkWrapper;
-import com.android.phone.vvm.omtp.sync.VvmNetworkRequest.RequestFailedException;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Sync OMTP visual voicemail.
- */
-public class OmtpVvmSyncService {
-
- private static final String TAG = OmtpVvmSyncService.class.getSimpleName();
-
- /**
- * Signifies a sync with both uploading to the server and downloading from the server.
- */
- public static final String SYNC_FULL_SYNC = "full_sync";
- /**
- * Only upload to the server.
- */
- public static final String SYNC_UPLOAD_ONLY = "upload_only";
- /**
- * Only download from the server.
- */
- public static final String SYNC_DOWNLOAD_ONLY = "download_only";
- /**
- * Only download single voicemail transcription.
- */
- public static final String SYNC_DOWNLOAD_ONE_TRANSCRIPTION =
- "download_one_transcription";
-
- private final Context mContext;
-
- // Record the timestamp of the last full sync so that duplicate syncs can be reduced.
- private static final String LAST_FULL_SYNC_TIMESTAMP = "last_full_sync_timestamp";
- // Constant indicating that there has never been a full sync.
- public static final long NO_PRIOR_FULL_SYNC = -1;
-
- private VoicemailsQueryHelper mQueryHelper;
-
- public OmtpVvmSyncService(Context context) {
- mContext = context;
- mQueryHelper = new VoicemailsQueryHelper(mContext);
- }
-
- public void sync(BaseTask task, String action, PhoneAccountHandle phoneAccount,
- Voicemail voicemail, VoicemailStatus.Editor status) {
- Assert.isTrue(phoneAccount != null);
- VvmLog.v(TAG, "Sync requested: " + action + " - for account: " + phoneAccount);
- setupAndSendRequest(task, phoneAccount, voicemail, action, status);
- }
-
- private void setupAndSendRequest(BaseTask task, PhoneAccountHandle phoneAccount,
- Voicemail voicemail, String action, VoicemailStatus.Editor status) {
- if (!VisualVoicemailSettingsUtil.isEnabled(mContext, phoneAccount)) {
- VvmLog.v(TAG, "Sync requested for disabled account");
- return;
- }
- int subId = PhoneAccountHandleConverter.toSubId(phoneAccount);
- if (!OmtpVvmSourceManager.getInstance(mContext).isVvmSourceRegistered(phoneAccount)) {
- ActivationTask.start(mContext, subId, null);
- return;
- }
-
- OmtpVvmCarrierConfigHelper config = new OmtpVvmCarrierConfigHelper(mContext, subId);
- // DATA_IMAP_OPERATION_STARTED posting should not be deferred. This event clears all data
- // channel errors, which should happen when the task starts, not when it ends. It is the
- // "Sync in progress..." status.
- config.handleEvent(VoicemailStatus.edit(mContext, phoneAccount),
- OmtpEvents.DATA_IMAP_OPERATION_STARTED);
- try (NetworkWrapper network = VvmNetworkRequest.getNetwork(config, phoneAccount, status)) {
- if (network == null) {
- VvmLog.e(TAG, "unable to acquire network");
- task.fail();
- return;
- }
- doSync(task, network.get(), phoneAccount, voicemail, action, status);
- } catch (RequestFailedException e) {
- config.handleEvent(status, OmtpEvents.DATA_NO_CONNECTION_CELLULAR_REQUIRED);
- task.fail();
- }
- }
-
- private void doSync(BaseTask task, Network network, PhoneAccountHandle phoneAccount,
- Voicemail voicemail, String action, VoicemailStatus.Editor status) {
- try (ImapHelper imapHelper = new ImapHelper(mContext, phoneAccount, network, status)) {
- boolean success;
- if (voicemail == null) {
- success = syncAll(action, imapHelper, phoneAccount);
- } else {
- success = syncOne(imapHelper, voicemail, phoneAccount);
- }
- if (success) {
- // TODO: b/30569269 failure should interrupt all subsequent task via exceptions
- imapHelper.updateQuota();
- imapHelper.handleEvent(OmtpEvents.DATA_IMAP_OPERATION_COMPLETED);
- } else {
- task.fail();
- }
- } catch (InitializingException e) {
- VvmLog.w(TAG, "Can't retrieve Imap credentials.", e);
- return;
- }
- }
-
- private boolean syncAll(String action, ImapHelper imapHelper, PhoneAccountHandle account) {
- boolean uploadSuccess = true;
- boolean downloadSuccess = true;
-
- if (SYNC_FULL_SYNC.equals(action) || SYNC_UPLOAD_ONLY.equals(action)) {
- uploadSuccess = upload(imapHelper);
- }
- if (SYNC_FULL_SYNC.equals(action) || SYNC_DOWNLOAD_ONLY.equals(action)) {
- downloadSuccess = download(imapHelper, account);
- }
-
- VvmLog.v(TAG, "upload succeeded: [" + String.valueOf(uploadSuccess)
- + "] download succeeded: [" + String.valueOf(downloadSuccess) + "]");
-
- return uploadSuccess && downloadSuccess;
- }
-
- private boolean syncOne(ImapHelper imapHelper, Voicemail voicemail,
- PhoneAccountHandle account) {
- if (shouldPerformPrefetch(account, imapHelper)) {
- VoicemailFetchedCallback callback = new VoicemailFetchedCallback(mContext,
- voicemail.getUri(), account);
- imapHelper.fetchVoicemailPayload(callback, voicemail.getSourceData());
- }
-
- return imapHelper.fetchTranscription(
- new TranscriptionFetchedCallback(mContext, voicemail),
- voicemail.getSourceData());
- }
-
- private boolean upload(ImapHelper imapHelper) {
- List<Voicemail> readVoicemails = mQueryHelper.getReadVoicemails();
- List<Voicemail> deletedVoicemails = mQueryHelper.getDeletedVoicemails();
-
- boolean success = true;
-
- if (deletedVoicemails.size() > 0) {
- if (imapHelper.markMessagesAsDeleted(deletedVoicemails)) {
- // We want to delete selectively instead of all the voicemails for this provider
- // in case the state changed since the IMAP query was completed.
- mQueryHelper.deleteFromDatabase(deletedVoicemails);
- } else {
- success = false;
- }
- }
-
- if (readVoicemails.size() > 0) {
- if (imapHelper.markMessagesAsRead(readVoicemails)) {
- mQueryHelper.markCleanInDatabase(readVoicemails);
- } else {
- success = false;
- }
- }
-
- return success;
- }
-
- private boolean download(ImapHelper imapHelper, PhoneAccountHandle account) {
- List<Voicemail> serverVoicemails = imapHelper.fetchAllVoicemails();
- List<Voicemail> localVoicemails = mQueryHelper.getAllVoicemails();
-
- if (localVoicemails == null || serverVoicemails == null) {
- // Null value means the query failed.
- return false;
- }
-
- Map<String, Voicemail> remoteMap = buildMap(serverVoicemails);
-
- // Go through all the local voicemails and check if they are on the server.
- // They may be read or deleted on the server but not locally. Perform the
- // appropriate local operation if the status differs from the server. Remove
- // the messages that exist both locally and on the server to know which server
- // messages to insert locally.
- for (int i = 0; i < localVoicemails.size(); i++) {
- Voicemail localVoicemail = localVoicemails.get(i);
- Voicemail remoteVoicemail = remoteMap.remove(localVoicemail.getSourceData());
- if (remoteVoicemail == null) {
- mQueryHelper.deleteFromDatabase(localVoicemail);
- } else {
- if (remoteVoicemail.isRead() != localVoicemail.isRead()) {
- mQueryHelper.markReadInDatabase(localVoicemail);
- }
-
- if (!TextUtils.isEmpty(remoteVoicemail.getTranscription()) &&
- TextUtils.isEmpty(localVoicemail.getTranscription())) {
- mQueryHelper.updateWithTranscription(localVoicemail,
- remoteVoicemail.getTranscription());
- }
- }
- }
-
- // The leftover messages are messages that exist on the server but not locally.
- boolean prefetchEnabled = shouldPerformPrefetch(account, imapHelper);
- for (Voicemail remoteVoicemail : remoteMap.values()) {
- Uri uri = VoicemailContract.Voicemails.insert(mContext, remoteVoicemail);
- if (prefetchEnabled) {
- VoicemailFetchedCallback fetchedCallback =
- new VoicemailFetchedCallback(mContext, uri, account);
- imapHelper.fetchVoicemailPayload(fetchedCallback, remoteVoicemail.getSourceData());
- }
- }
-
- return true;
- }
-
- private boolean shouldPerformPrefetch(PhoneAccountHandle account, ImapHelper imapHelper) {
- OmtpVvmCarrierConfigHelper carrierConfigHelper = new OmtpVvmCarrierConfigHelper(
- mContext, PhoneUtils.getSubIdForPhoneAccountHandle(account));
- return carrierConfigHelper.isPrefetchEnabled() && !imapHelper.isRoaming();
- }
-
- /**
- * Builds a map from provider data to message for the given collection of voicemails.
- */
- private Map<String, Voicemail> buildMap(List<Voicemail> messages) {
- Map<String, Voicemail> map = new HashMap<String, Voicemail>();
- for (Voicemail message : messages) {
- map.put(message.getSourceData(), message);
- }
- return map;
- }
-
- public class TranscriptionFetchedCallback {
-
- private Context mContext;
- private Voicemail mVoicemail;
-
- public TranscriptionFetchedCallback(Context context, Voicemail voicemail) {
- mContext = context;
- mVoicemail = voicemail;
- }
-
- public void setVoicemailTranscription(String transcription) {
- VoicemailsQueryHelper queryHelper = new VoicemailsQueryHelper(mContext);
- queryHelper.updateWithTranscription(mVoicemail, transcription);
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/SyncOneTask.java b/src/com/android/phone/vvm/omtp/sync/SyncOneTask.java
deleted file mode 100644
index 510efc7..0000000
--- a/src/com/android/phone/vvm/omtp/sync/SyncOneTask.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone.vvm.omtp.sync;
-
-import android.content.Context;
-import android.content.Intent;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.Voicemail;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.omtp.scheduling.BaseTask;
-import com.android.phone.vvm.omtp.scheduling.RetryPolicy;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
-/**
- * Task to download a single voicemail from the server. This task is initiated by a SMS notifying
- * the new voicemail arrival, and ignores the duplicated tasks constraint.
- */
-public class SyncOneTask extends BaseTask {
-
- private static final int RETRY_TIMES = 2;
- private static final int RETRY_INTERVAL_MILLIS = 5_000;
-
- private static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle";
- private static final String EXTRA_SYNC_TYPE = "extra_sync_type";
- private static final String EXTRA_VOICEMAIL = "extra_voicemail";
-
- private PhoneAccountHandle mPhone;
- private String mSyncType;
- private Voicemail mVoicemail;
-
- public static void start(Context context, PhoneAccountHandle phone, Voicemail voicemail) {
- Intent intent = BaseTask
- .createIntent(context, SyncOneTask.class,
- PhoneAccountHandleConverter.toSubId(phone));
- intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phone);
- intent.putExtra(EXTRA_SYNC_TYPE, OmtpVvmSyncService.SYNC_DOWNLOAD_ONE_TRANSCRIPTION);
- intent.putExtra(EXTRA_VOICEMAIL, voicemail);
- context.startService(intent);
- }
-
- public SyncOneTask() {
- super(TASK_ALLOW_DUPLICATES);
- addPolicy(new RetryPolicy(RETRY_TIMES, RETRY_INTERVAL_MILLIS));
- }
-
- public void onCreate(Context context, Intent intent, int flags, int startId) {
- super.onCreate(context, intent, flags, startId);
- mPhone = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE);
- mSyncType = intent.getStringExtra(EXTRA_SYNC_TYPE);
- mVoicemail = intent.getParcelableExtra(EXTRA_VOICEMAIL);
- }
-
- @Override
- public void onExecuteInBackgroundThread() {
- OmtpVvmSyncService service = new OmtpVvmSyncService(getContext());
- service.sync(this, mSyncType, mPhone, mVoicemail,
- VoicemailStatus.edit(getContext(), mPhone));
- }
-
- @Override
- public Intent createRestartIntent() {
- Intent intent = super.createRestartIntent();
- intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, mPhone);
- intent.putExtra(EXTRA_SYNC_TYPE, mSyncType);
- intent.putExtra(EXTRA_VOICEMAIL, mVoicemail);
- return intent;
- }
-
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/SyncTask.java b/src/com/android/phone/vvm/omtp/sync/SyncTask.java
deleted file mode 100644
index 7374ee6..0000000
--- a/src/com/android/phone/vvm/omtp/sync/SyncTask.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.sync;
-
-import android.content.Context;
-import android.content.Intent;
-import android.telecom.PhoneAccountHandle;
-import com.android.phone.vvm.omtp.scheduling.BaseTask;
-import com.android.phone.vvm.omtp.scheduling.MinimalIntervalPolicy;
-import com.android.phone.vvm.omtp.scheduling.RetryPolicy;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
-/**
- * System initiated sync request.
- */
-public class SyncTask extends BaseTask {
-
- // Try sync for a total of 5 times, should take around 5 minutes before finally giving up.
- private static final int RETRY_TIMES = 4;
- private static final int RETRY_INTERVAL_MILLIS = 5_000;
- private static final int MINIMAL_INTERVAL_MILLIS = 60_000;
-
- private static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle";
- private static final String EXTRA_SYNC_TYPE = "extra_sync_type";
-
- private final RetryPolicy mRetryPolicy;
-
- private PhoneAccountHandle mPhone;
- private String mSyncType;
-
- public static void start(Context context, PhoneAccountHandle phone, String syncType) {
- Intent intent = BaseTask
- .createIntent(context, SyncTask.class, PhoneAccountHandleConverter.toSubId(phone));
- intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, phone);
- intent.putExtra(EXTRA_SYNC_TYPE, syncType);
- context.startService(intent);
- }
-
- public SyncTask() {
- super(TASK_SYNC);
- mRetryPolicy = new RetryPolicy(RETRY_TIMES, RETRY_INTERVAL_MILLIS);
- addPolicy(mRetryPolicy);
- addPolicy(new MinimalIntervalPolicy(MINIMAL_INTERVAL_MILLIS));
- }
-
- public void onCreate(Context context, Intent intent, int flags, int startId) {
- super.onCreate(context, intent, flags, startId);
- mPhone = intent.getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE);
- mSyncType = intent.getStringExtra(EXTRA_SYNC_TYPE);
- }
-
- @Override
- public void onExecuteInBackgroundThread() {
- OmtpVvmSyncService service = new OmtpVvmSyncService(getContext());
- service.sync(this, mSyncType, mPhone, null, mRetryPolicy.getVoicemailStatusEditor());
- }
-
- @Override
- public Intent createRestartIntent() {
- Intent intent = super.createRestartIntent();
- intent.putExtra(EXTRA_PHONE_ACCOUNT_HANDLE, mPhone);
- intent.putExtra(EXTRA_SYNC_TYPE, mSyncType);
- return intent;
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/UploadTask.java b/src/com/android/phone/vvm/omtp/sync/UploadTask.java
deleted file mode 100644
index 87c0a46..0000000
--- a/src/com/android/phone/vvm/omtp/sync/UploadTask.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.sync;
-
-import android.content.Context;
-import android.content.Intent;
-import android.telecom.PhoneAccountHandle;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.omtp.VvmLog;
-import com.android.phone.vvm.omtp.scheduling.BaseTask;
-import com.android.phone.vvm.omtp.scheduling.PostponePolicy;
-import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
-
-/**
- * Upload task triggered by database changes. Will wait until the database has been stable for
- * {@link #POSTPONE_MILLIS} to execute.
- */
-public class UploadTask extends BaseTask {
-
- private static final String TAG = "VvmUploadTask";
-
- private static final int POSTPONE_MILLIS = 5_000;
-
- public UploadTask() {
- super(TASK_UPLOAD);
- addPolicy(new PostponePolicy(POSTPONE_MILLIS));
- }
-
- public static void start(Context context, PhoneAccountHandle phoneAccountHandle) {
- Intent intent = BaseTask
- .createIntent(context, UploadTask.class,
- PhoneAccountHandleConverter.toSubId(phoneAccountHandle));
- context.startService(intent);
- }
-
- @Override
- public void onCreate(Context context, Intent intent, int flags, int startId) {
- super.onCreate(context, intent, flags, startId);
- }
-
- @Override
- public void onExecuteInBackgroundThread() {
- OmtpVvmSyncService service = new OmtpVvmSyncService(getContext());
-
- PhoneAccountHandle phoneAccountHandle = PhoneAccountHandleConverter.fromSubId(getSubId());
- if (phoneAccountHandle == null) {
- // This should never happen
- VvmLog.e(TAG, "null phone account for subId " + getSubId());
- return;
- }
- service.sync(this, OmtpVvmSyncService.SYNC_UPLOAD_ONLY,
- phoneAccountHandle, null,
- VoicemailStatus.edit(getContext(), phoneAccountHandle));
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java b/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java
deleted file mode 100644
index bc9e6e1..0000000
--- a/src/com/android/phone/vvm/omtp/sync/VoicemailProviderChangeReceiver.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.sync;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.provider.VoicemailContract;
-import android.telecom.PhoneAccountHandle;
-
-/**
- * Receives changes to the voicemail provider so they can be sent to the voicemail server.
- */
-public class VoicemailProviderChangeReceiver extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- boolean isSelfChanged = intent.getBooleanExtra(VoicemailContract.EXTRA_SELF_CHANGE, false);
- OmtpVvmSourceManager vvmSourceManager =
- OmtpVvmSourceManager.getInstance(context);
- if (vvmSourceManager.getOmtpVvmSources().size() > 0 && !isSelfChanged) {
- for (PhoneAccountHandle source : OmtpVvmSourceManager.getInstance(context)
- .getOmtpVvmSources()) {
- UploadTask.start(context, source);
- }
- }
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailStatusQueryHelper.java b/src/com/android/phone/vvm/omtp/sync/VoicemailStatusQueryHelper.java
deleted file mode 100644
index 66f3e9d..0000000
--- a/src/com/android/phone/vvm/omtp/sync/VoicemailStatusQueryHelper.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.sync;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.VoicemailContract;
-import android.provider.VoicemailContract.Status;
-import android.telecom.PhoneAccountHandle;
-
-/**
- * Construct queries to interact with the voicemail status table.
- */
-public class VoicemailStatusQueryHelper {
-
- final static String[] PROJECTION = new String[] {
- Status._ID, // 0
- Status.CONFIGURATION_STATE, // 1
- Status.NOTIFICATION_CHANNEL_STATE, // 2
- Status.SOURCE_PACKAGE // 3
- };
-
- public static final int _ID = 0;
- public static final int CONFIGURATION_STATE = 1;
- public static final int NOTIFICATION_CHANNEL_STATE = 2;
- public static final int SOURCE_PACKAGE = 3;
-
- private Context mContext;
- private ContentResolver mContentResolver;
- private Uri mSourceUri;
-
- public VoicemailStatusQueryHelper(Context context) {
- mContext = context;
- mContentResolver = context.getContentResolver();
- mSourceUri = VoicemailContract.Status.buildSourceUri(mContext.getPackageName());
- }
-
- /**
- * Check if the configuration state for the voicemail source is "ok", meaning that the
- * source is set up.
- *
- * @param phoneAccount The phone account for the voicemail source to check.
- * @return {@code true} if the voicemail source is configured, {@code} false otherwise,
- * including if the voicemail source is not registered in the table.
- */
- public boolean isVoicemailSourceConfigured(PhoneAccountHandle phoneAccount) {
- return isFieldEqualTo(phoneAccount, CONFIGURATION_STATE, Status.CONFIGURATION_STATE_OK);
- }
-
- /**
- * Check if the notifications channel of a voicemail source is active. That is, when a new
- * voicemail is available, if the server able to notify the device.
- *
- * @return {@code true} if notifications channel is active, {@code false} otherwise.
- */
- public boolean isNotificationsChannelActive(PhoneAccountHandle phoneAccount) {
- return isFieldEqualTo(phoneAccount, NOTIFICATION_CHANNEL_STATE,
- Status.NOTIFICATION_CHANNEL_STATE_OK);
- }
-
- /**
- * Check if a field for an entry in the status table is equal to a specific value.
- *
- * @param phoneAccount The phone account of the voicemail source to query for.
- * @param columnIndex The column index of the field in the returned query.
- * @param value The value to compare against.
- * @return {@code true} if the stored value is equal to the provided value. {@code false}
- * otherwise.
- */
- private boolean isFieldEqualTo(PhoneAccountHandle phoneAccount, int columnIndex, int value) {
- Cursor cursor = null;
- if (phoneAccount != null) {
- String phoneAccountComponentName = phoneAccount.getComponentName().flattenToString();
- String phoneAccountId = phoneAccount.getId();
- if (phoneAccountComponentName == null || phoneAccountId == null) {
- return false;
- }
- try {
- String whereClause =
- Status.PHONE_ACCOUNT_COMPONENT_NAME + "=? AND " +
- Status.PHONE_ACCOUNT_ID + "=? AND " + Status.SOURCE_PACKAGE + "=?";
- String[] whereArgs = { phoneAccountComponentName, phoneAccountId,
- mContext.getPackageName()};
- cursor = mContentResolver.query(
- mSourceUri, PROJECTION, whereClause, whereArgs, null);
- if (cursor != null && cursor.moveToFirst()) {
- return cursor.getInt(columnIndex) == value;
- }
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
- return false;
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java b/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
deleted file mode 100644
index 9906386..0000000
--- a/src/com/android/phone/vvm/omtp/sync/VoicemailsQueryHelper.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.sync;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.provider.VoicemailContract;
-import android.provider.VoicemailContract.Voicemails;
-import android.telecom.PhoneAccountHandle;
-import android.telecom.Voicemail;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Construct queries to interact with the voicemails table.
- */
-public class VoicemailsQueryHelper {
- final static String[] PROJECTION = new String[] {
- Voicemails._ID, // 0
- Voicemails.SOURCE_DATA, // 1
- Voicemails.IS_READ, // 2
- Voicemails.DELETED, // 3
- Voicemails.TRANSCRIPTION // 4
- };
-
- public static final int _ID = 0;
- public static final int SOURCE_DATA = 1;
- public static final int IS_READ = 2;
- public static final int DELETED = 3;
- public static final int TRANSCRIPTION = 4;
-
- final static String READ_SELECTION = Voicemails.DIRTY + "=1 AND "
- + Voicemails.DELETED + "!=1 AND " + Voicemails.IS_READ + "=1";
- final static String DELETED_SELECTION = Voicemails.DELETED + "=1";
-
- private Context mContext;
- private ContentResolver mContentResolver;
- private Uri mSourceUri;
-
- public VoicemailsQueryHelper(Context context) {
- mContext = context;
- mContentResolver = context.getContentResolver();
- mSourceUri = VoicemailContract.Voicemails.buildSourceUri(mContext.getPackageName());
- }
-
- /**
- * Get all the local read voicemails that have not been synced to the server.
- *
- * @return A list of read voicemails.
- */
- public List<Voicemail> getReadVoicemails() {
- return getLocalVoicemails(READ_SELECTION);
- }
-
- /**
- * Get all the locally deleted voicemails that have not been synced to the server.
- *
- * @return A list of deleted voicemails.
- */
- public List<Voicemail> getDeletedVoicemails() {
- return getLocalVoicemails(DELETED_SELECTION);
- }
-
- /**
- * Get all voicemails locally stored.
- *
- * @return A list of all locally stored voicemails.
- */
- public List<Voicemail> getAllVoicemails() {
- return getLocalVoicemails(null);
- }
-
- /**
- * Utility method to make queries to the voicemail database.
- *
- * @param selection A filter declaring which rows to return. {@code null} returns all rows.
- * @return A list of voicemails according to the selection statement.
- */
- private List<Voicemail> getLocalVoicemails(String selection) {
- Cursor cursor = mContentResolver.query(mSourceUri, PROJECTION, selection, null, null);
- if (cursor == null) {
- return null;
- }
- try {
- List<Voicemail> voicemails = new ArrayList<Voicemail>();
- while (cursor.moveToNext()) {
- final long id = cursor.getLong(_ID);
- final String sourceData = cursor.getString(SOURCE_DATA);
- final boolean isRead = cursor.getInt(IS_READ) == 1;
- final String transcription = cursor.getString(TRANSCRIPTION);
- Voicemail voicemail = Voicemail
- .createForUpdate(id, sourceData)
- .setIsRead(isRead)
- .setTranscription(transcription).build();
- voicemails.add(voicemail);
- }
- return voicemails;
- } finally {
- cursor.close();
- }
- }
-
- /**
- * Deletes a list of voicemails from the voicemail content provider.
- *
- * @param voicemails The list of voicemails to delete
- * @return The number of voicemails deleted
- */
- public int deleteFromDatabase(List<Voicemail> voicemails) {
- int count = voicemails.size();
- if (count == 0) {
- return 0;
- }
-
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < count; i++) {
- if (i > 0) {
- sb.append(",");
- }
- sb.append(voicemails.get(i).getId());
- }
-
- String selectionStatement = String.format(Voicemails._ID + " IN (%s)", sb.toString());
- return mContentResolver.delete(Voicemails.CONTENT_URI, selectionStatement, null);
- }
-
- /**
- * Utility method to delete a single voicemail.
- */
- public void deleteFromDatabase(Voicemail voicemail) {
- mContentResolver.delete(Voicemails.CONTENT_URI, Voicemails._ID + "=?",
- new String[] { Long.toString(voicemail.getId()) });
- }
-
- public int markReadInDatabase(List<Voicemail> voicemails) {
- int count = voicemails.size();
- for (int i = 0; i < count; i++) {
- markReadInDatabase(voicemails.get(i));
- }
- return count;
- }
-
- /**
- * Utility method to mark single message as read.
- */
- public void markReadInDatabase(Voicemail voicemail) {
- Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId());
- ContentValues contentValues = new ContentValues();
- contentValues.put(Voicemails.IS_READ, "1");
- mContentResolver.update(uri, contentValues, null, null);
- }
-
- /**
- * Sends an update command to the voicemail content provider for a list of voicemails. From the
- * view of the provider, since the updater is the owner of the entry, a blank "update" means
- * that the voicemail source is indicating that the server has up-to-date information on the
- * voicemail. This flips the "dirty" bit to "0".
- *
- * @param voicemails The list of voicemails to update
- * @return The number of voicemails updated
- */
- public int markCleanInDatabase(List<Voicemail> voicemails) {
- int count = voicemails.size();
- for (int i = 0; i < count; i++) {
- markCleanInDatabase(voicemails.get(i));
- }
- return count;
- }
-
- /**
- * Utility method to mark single message as clean.
- */
- public void markCleanInDatabase(Voicemail voicemail) {
- Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId());
- ContentValues contentValues = new ContentValues();
- mContentResolver.update(uri, contentValues, null, null);
- }
-
- /**
- * Utility method to add a transcription to the voicemail.
- */
- public void updateWithTranscription(Voicemail voicemail, String transcription) {
- Uri uri = ContentUris.withAppendedId(mSourceUri, voicemail.getId());
- ContentValues contentValues = new ContentValues();
- contentValues.put(Voicemails.TRANSCRIPTION, transcription);
- mContentResolver.update(uri, contentValues, null, null);
- }
-
- /**
- * Voicemail is unique if the tuple of (phone account component name, phone account id, source
- * data) is unique. If the phone account is missing, we also consider this unique since it's
- * simply an "unknown" account.
- * @param voicemail The voicemail to check if it is unique.
- * @return {@code true} if the voicemail is unique, {@code false} otherwise.
- */
- public boolean isVoicemailUnique(Voicemail voicemail) {
- Cursor cursor = null;
- PhoneAccountHandle phoneAccount = voicemail.getPhoneAccount();
- if (phoneAccount != null) {
- String phoneAccountComponentName = phoneAccount.getComponentName().flattenToString();
- String phoneAccountId = phoneAccount.getId();
- String sourceData = voicemail.getSourceData();
- if (phoneAccountComponentName == null || phoneAccountId == null || sourceData == null) {
- return true;
- }
- try {
- String whereClause =
- Voicemails.PHONE_ACCOUNT_COMPONENT_NAME + "=? AND " +
- Voicemails.PHONE_ACCOUNT_ID + "=? AND " + Voicemails.SOURCE_DATA + "=?";
- String[] whereArgs = { phoneAccountComponentName, phoneAccountId, sourceData };
- cursor = mContentResolver.query(
- mSourceUri, PROJECTION, whereClause, whereArgs, null);
- if (cursor.getCount() == 0) {
- return true;
- } else {
- return false;
- }
- }
- finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
- return true;
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequest.java b/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequest.java
deleted file mode 100644
index 3bdb45b..0000000
--- a/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequest.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.sync;
-
-import android.net.Network;
-import android.support.annotation.NonNull;
-import android.telecom.PhoneAccountHandle;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VvmLog;
-import java.io.Closeable;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
-/**
- * Class to retrieve a {@link Network} synchronously. {@link #getNetwork(OmtpVvmCarrierConfigHelper,
- * PhoneAccountHandle)} will block until a suitable network is retrieved or it has failed.
- */
-public class VvmNetworkRequest {
-
- private static final String TAG = "VvmNetworkRequest";
-
- /**
- * A wrapper around a Network returned by a {@link VvmNetworkRequestCallback}, which should be
- * closed once not needed anymore.
- */
- public static class NetworkWrapper implements Closeable {
-
- private final Network mNetwork;
- private final VvmNetworkRequestCallback mCallback;
-
- private NetworkWrapper(Network network, VvmNetworkRequestCallback callback) {
- mNetwork = network;
- mCallback = callback;
- }
-
- public Network get() {
- return mNetwork;
- }
-
- @Override
- public void close() {
- mCallback.releaseNetwork();
- }
- }
-
- public static class RequestFailedException extends Exception {
-
- private RequestFailedException(Throwable cause) {
- super(cause);
- }
- }
-
- @NonNull
- public static NetworkWrapper getNetwork(OmtpVvmCarrierConfigHelper config,
- PhoneAccountHandle handle, VoicemailStatus.Editor status) throws RequestFailedException {
- FutureNetworkRequestCallback callback = new FutureNetworkRequestCallback(config, handle,
- status);
- callback.requestNetwork();
- try {
- return callback.getFuture().get();
- } catch (InterruptedException | ExecutionException e) {
- callback.releaseNetwork();
- VvmLog.e(TAG, "can't get future network", e);
- throw new RequestFailedException(e);
- }
- }
-
- private static class FutureNetworkRequestCallback extends VvmNetworkRequestCallback {
-
- /**
- * {@link CompletableFuture#get()} will block until {@link CompletableFuture#
- * complete(Object) } has been called on the other thread.
- */
- private final CompletableFuture<NetworkWrapper> mFuture = new CompletableFuture<>();
-
- public FutureNetworkRequestCallback(OmtpVvmCarrierConfigHelper config,
- PhoneAccountHandle phoneAccount, VoicemailStatus.Editor status) {
- super(config, phoneAccount, status);
- }
-
- public Future<NetworkWrapper> getFuture() {
- return mFuture;
- }
-
- @Override
- public void onAvailable(Network network) {
- super.onAvailable(network);
- mFuture.complete(new NetworkWrapper(network, this));
- }
-
- @Override
- public void onFailed(String reason) {
- super.onFailed(reason);
- mFuture.complete(null);
- }
-
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequestCallback.java b/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequestCallback.java
deleted file mode 100644
index 787fdcd..0000000
--- a/src/com/android/phone/vvm/omtp/sync/VvmNetworkRequestCallback.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2015 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.vvm.omtp.sync;
-
-import android.annotation.CallSuper;
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.os.Handler;
-import android.os.Looper;
-import android.telecom.PhoneAccountHandle;
-import com.android.phone.PhoneUtils;
-import com.android.phone.VoicemailStatus;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.VvmLog;
-
-/**
- * Base class for network request call backs for visual voicemail syncing with the Imap server. This
- * handles retries and network requests.
- */
-public abstract class VvmNetworkRequestCallback extends ConnectivityManager.NetworkCallback {
-
- private static final String TAG = "VvmNetworkRequest";
-
- // Timeout used to call ConnectivityManager.requestNetwork
- private static final int NETWORK_REQUEST_TIMEOUT_MILLIS = 60 * 1000;
-
- public static final String NETWORK_REQUEST_FAILED_TIMEOUT = "timeout";
- public static final String NETWORK_REQUEST_FAILED_LOST = "lost";
-
- protected Context mContext;
- protected PhoneAccountHandle mPhoneAccount;
- protected NetworkRequest mNetworkRequest;
- private ConnectivityManager mConnectivityManager;
- private final OmtpVvmCarrierConfigHelper mCarrierConfigHelper;
- private final int mSubId;
- private final VoicemailStatus.Editor mStatus;
- private boolean mRequestSent = false;
- private boolean mResultReceived = false;
-
- public VvmNetworkRequestCallback(Context context, PhoneAccountHandle phoneAccount,
- VoicemailStatus.Editor status) {
- mContext = context;
- mPhoneAccount = phoneAccount;
- mSubId = PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount);
- mStatus = status;
- mCarrierConfigHelper = new OmtpVvmCarrierConfigHelper(context, mSubId);
- mNetworkRequest = createNetworkRequest();
- }
-
- public VvmNetworkRequestCallback(OmtpVvmCarrierConfigHelper config,
- PhoneAccountHandle phoneAccount, VoicemailStatus.Editor status) {
- mContext = config.getContext();
- mPhoneAccount = phoneAccount;
- mSubId = config.getSubId();
- mStatus = status;
- mCarrierConfigHelper = config;
- mNetworkRequest = createNetworkRequest();
- }
-
- public VoicemailStatus.Editor getVoicemailStatusEditor() {
- return mStatus;
- }
-
- /**
- * @return NetworkRequest for a proper transport type. Use only cellular network if the carrier
- * requires it. Otherwise use whatever available.
- */
- private NetworkRequest createNetworkRequest() {
-
- NetworkRequest.Builder builder = new NetworkRequest.Builder()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
-
- if (mCarrierConfigHelper.isCellularDataRequired()) {
- VvmLog.d(TAG, "Transport type: CELLULAR");
- builder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .setNetworkSpecifier(Integer.toString(mSubId));
- } else {
- VvmLog.d(TAG, "Transport type: ANY");
- }
- return builder.build();
- }
-
- public NetworkRequest getNetworkRequest() {
- return mNetworkRequest;
- }
-
- @Override
- @CallSuper
- public void onLost(Network network) {
- VvmLog.d(TAG, "onLost");
- mResultReceived = true;
- onFailed(NETWORK_REQUEST_FAILED_LOST);
- }
-
- @Override
- @CallSuper
- public void onAvailable(Network network) {
- super.onAvailable(network);
- mResultReceived = true;
- }
-
- @Override
- @CallSuper
- public void onUnavailable() {
- mResultReceived = true;
- onFailed(NETWORK_REQUEST_FAILED_TIMEOUT);
- }
-
- public void requestNetwork() {
- if (mRequestSent == true) {
- VvmLog.e(TAG, "requestNetwork() called twice");
- return;
- }
- mRequestSent = true;
- getConnectivityManager().requestNetwork(getNetworkRequest(), this);
- /**
- * Somehow requestNetwork() with timeout doesn't work, and it's a hidden method.
- * Implement our own timeout mechanism instead.
- */
- Handler handler = new Handler(Looper.getMainLooper());
- handler.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (mResultReceived == false) {
- onFailed(NETWORK_REQUEST_FAILED_TIMEOUT);
- }
- }
- }, NETWORK_REQUEST_TIMEOUT_MILLIS);
- }
-
- public void releaseNetwork() {
- VvmLog.d(TAG, "releaseNetwork");
- getConnectivityManager().unregisterNetworkCallback(this);
- }
-
- public ConnectivityManager getConnectivityManager() {
- if (mConnectivityManager == null) {
- mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- }
- return mConnectivityManager;
- }
-
- @CallSuper
- public void onFailed(String reason) {
- VvmLog.d(TAG, "onFailed: " + reason);
- if (mCarrierConfigHelper.isCellularDataRequired()) {
- mCarrierConfigHelper
- .handleEvent(mStatus, OmtpEvents.DATA_NO_CONNECTION_CELLULAR_REQUIRED);
- } else {
- mCarrierConfigHelper.handleEvent(mStatus, OmtpEvents.DATA_NO_CONNECTION);
- }
- releaseNetwork();
- }
-}
diff --git a/src/com/android/phone/vvm/omtp/utils/XmlUtils.java b/src/com/android/phone/vvm/omtp/utils/XmlUtils.java
deleted file mode 100644
index 4eeb5ce..0000000
--- a/src/com/android/phone/vvm/omtp/utils/XmlUtils.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone.vvm.omtp.utils;
-
-import android.util.ArrayMap;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-public class XmlUtils {
-
- public static final ArrayMap<String, ?> readThisArrayMapXml(XmlPullParser parser, String endTag,
- String[] name, ReadMapCallback callback)
- throws XmlPullParserException, java.io.IOException {
- ArrayMap<String, Object> map = new ArrayMap<>();
-
- int eventType = parser.getEventType();
- do {
- if (eventType == XmlPullParser.START_TAG) {
- Object val = readThisValueXml(parser, name, callback, true);
- map.put(name[0], val);
- } else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals(endTag)) {
- return map;
- }
- throw new XmlPullParserException(
- "Expected " + endTag + " end tag at: " + parser.getName());
- }
- eventType = parser.next();
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- throw new XmlPullParserException(
- "Document ended before " + endTag + " end tag");
- }
-
- /**
- * Read an ArrayList object from an XmlPullParser. The XML data could previously have been
- * generated by writeListXml(). The XmlPullParser must be positioned <em>after</em> the tag
- * that begins the list.
- *
- * @param parser The XmlPullParser from which to read the list data.
- * @param endTag Name of the tag that will end the list, usually "list".
- * @param name An array of one string, used to return the name attribute of the list's tag.
- * @return HashMap The newly generated list.
- */
- public static final ArrayList readThisListXml(XmlPullParser parser, String endTag,
- String[] name, ReadMapCallback callback, boolean arrayMap)
- throws XmlPullParserException, java.io.IOException {
- ArrayList list = new ArrayList();
-
- int eventType = parser.getEventType();
- do {
- if (eventType == XmlPullParser.START_TAG) {
- Object val = readThisValueXml(parser, name, callback, arrayMap);
- list.add(val);
- } else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals(endTag)) {
- return list;
- }
- throw new XmlPullParserException(
- "Expected " + endTag + " end tag at: " + parser.getName());
- }
- eventType = parser.next();
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- throw new XmlPullParserException(
- "Document ended before " + endTag + " end tag");
- }
-
- /**
- * Read a String[] object from an XmlPullParser. The XML data could previously have been
- * generated by writeStringArrayXml(). The XmlPullParser must be positioned <em>after</em> the
- * tag that begins the list.
- *
- * @param parser The XmlPullParser from which to read the list data.
- * @param endTag Name of the tag that will end the list, usually "string-array".
- * @param name An array of one string, used to return the name attribute of the list's tag.
- * @return Returns a newly generated String[].
- */
- public static String[] readThisStringArrayXml(XmlPullParser parser, String endTag,
- String[] name) throws XmlPullParserException, java.io.IOException {
-
- parser.next();
-
- List<String> array = new ArrayList<>();
-
- int eventType = parser.getEventType();
- do {
- if (eventType == XmlPullParser.START_TAG) {
- if (parser.getName().equals("item")) {
- try {
- array.add(parser.getAttributeValue(null, "value"));
- } catch (NullPointerException e) {
- throw new XmlPullParserException("Need value attribute in item");
- } catch (NumberFormatException e) {
- throw new XmlPullParserException("Not a number in value attribute in item");
- }
- } else {
- throw new XmlPullParserException("Expected item tag at: " + parser.getName());
- }
- } else if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals(endTag)) {
- return array.toArray(new String[0]);
- } else if (parser.getName().equals("item")) {
-
- } else {
- throw new XmlPullParserException("Expected " + endTag + " end tag at: " +
- parser.getName());
- }
- }
- eventType = parser.next();
- } while (eventType != XmlPullParser.END_DOCUMENT);
-
- throw new XmlPullParserException("Document ended before " + endTag + " end tag");
- }
-
- private static Object readThisValueXml(XmlPullParser parser, String[] name,
- ReadMapCallback callback, boolean arrayMap)
- throws XmlPullParserException, java.io.IOException {
- final String valueName = parser.getAttributeValue(null, "name");
- final String tagName = parser.getName();
-
- Object res;
-
- if (tagName.equals("null")) {
- res = null;
- } else if (tagName.equals("string")) {
- String value = "";
- int eventType;
- while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals("string")) {
- name[0] = valueName;
- return value;
- }
- throw new XmlPullParserException(
- "Unexpected end tag in <string>: " + parser.getName());
- } else if (eventType == XmlPullParser.TEXT) {
- value += parser.getText();
- } else if (eventType == XmlPullParser.START_TAG) {
- throw new XmlPullParserException(
- "Unexpected start tag in <string>: " + parser.getName());
- }
- }
- throw new XmlPullParserException(
- "Unexpected end of document in <string>");
- } else if ((res = readThisPrimitiveValueXml(parser, tagName)) != null) {
- // all work already done by readThisPrimitiveValueXml
- } else if (tagName.equals("string-array")) {
- res = readThisStringArrayXml(parser, "string-array", name);
- name[0] = valueName;
- return res;
- } else if (tagName.equals("list")) {
- parser.next();
- res = readThisListXml(parser, "list", name, callback, arrayMap);
- name[0] = valueName;
- return res;
- } else if (callback != null) {
- res = callback.readThisUnknownObjectXml(parser, tagName);
- name[0] = valueName;
- return res;
- } else {
- throw new XmlPullParserException("Unknown tag: " + tagName);
- }
-
- // Skip through to end tag.
- int eventType;
- while ((eventType = parser.next()) != XmlPullParser.END_DOCUMENT) {
- if (eventType == XmlPullParser.END_TAG) {
- if (parser.getName().equals(tagName)) {
- name[0] = valueName;
- return res;
- }
- throw new XmlPullParserException(
- "Unexpected end tag in <" + tagName + ">: " + parser.getName());
- } else if (eventType == XmlPullParser.TEXT) {
- throw new XmlPullParserException(
- "Unexpected text in <" + tagName + ">: " + parser.getName());
- } else if (eventType == XmlPullParser.START_TAG) {
- throw new XmlPullParserException(
- "Unexpected start tag in <" + tagName + ">: " + parser.getName());
- }
- }
- throw new XmlPullParserException(
- "Unexpected end of document in <" + tagName + ">");
- }
-
- private static final Object readThisPrimitiveValueXml(XmlPullParser parser, String tagName)
- throws XmlPullParserException, java.io.IOException {
- try {
- if (tagName.equals("int")) {
- return Integer.parseInt(parser.getAttributeValue(null, "value"));
- } else if (tagName.equals("long")) {
- return Long.valueOf(parser.getAttributeValue(null, "value"));
- } else if (tagName.equals("float")) {
- return Float.valueOf(parser.getAttributeValue(null, "value"));
- } else if (tagName.equals("double")) {
- return Double.valueOf(parser.getAttributeValue(null, "value"));
- } else if (tagName.equals("boolean")) {
- return Boolean.valueOf(parser.getAttributeValue(null, "value"));
- } else {
- return null;
- }
- } catch (NullPointerException e) {
- throw new XmlPullParserException("Need value attribute in <" + tagName + ">");
- } catch (NumberFormatException e) {
- throw new XmlPullParserException(
- "Not a number in value attribute in <" + tagName + ">");
- }
- }
-
- public interface ReadMapCallback {
-
- /**
- * Called from readThisMapXml when a START_TAG is not recognized. The input stream is
- * positioned within the start tag so that attributes can be read using in.getAttribute.
- *
- * @param in the XML input stream
- * @param tag the START_TAG that was not recognized.
- * @return the Object parsed from the stream which will be put into the map.
- * @throws XmlPullParserException if the START_TAG is not recognized.
- * @throws IOException on XmlPullParser serialization errors.
- */
- Object readThisUnknownObjectXml(XmlPullParser in, String tag)
- throws XmlPullParserException, IOException;
- }
-}
\ No newline at end of file
diff --git a/src/com/android/services/telephony/CdmaConnection.java b/src/com/android/services/telephony/CdmaConnection.java
index 29ccc6c..ffa9dbc 100644
--- a/src/com/android/services/telephony/CdmaConnection.java
+++ b/src/com/android/services/telephony/CdmaConnection.java
@@ -65,7 +65,6 @@
* {@code True} if the CDMA connection should allow mute.
*/
private boolean mAllowMute;
- private final boolean mIsOutgoing;
// Queue of pending short-DTMF characters.
private final Queue<Character> mDtmfQueue = new LinkedList<>();
private final EmergencyTonePlayer mEmergencyTonePlayer;
@@ -80,10 +79,9 @@
boolean allowMute,
boolean isOutgoing,
String telecomCallId) {
- super(connection, telecomCallId);
+ super(connection, telecomCallId, isOutgoing);
mEmergencyTonePlayer = emergencyTonePlayer;
mAllowMute = allowMute;
- mIsOutgoing = isOutgoing;
mIsCallWaiting = connection != null && connection.getState() == Call.State.WAITING;
boolean isImsCall = getOriginalConnection() instanceof ImsPhoneConnection;
// Start call waiting timer for CDMA waiting call.
diff --git a/src/com/android/services/telephony/RadioOnHelper.java b/src/com/android/services/telephony/EmergencyCallHelper.java
similarity index 73%
rename from src/com/android/services/telephony/RadioOnHelper.java
rename to src/com/android/services/telephony/EmergencyCallHelper.java
index 81a5b19..295f4f7 100644
--- a/src/com/android/services/telephony/RadioOnHelper.java
+++ b/src/com/android/services/telephony/EmergencyCallHelper.java
@@ -30,22 +30,21 @@
import java.util.List;
/**
- * Helper class that implements special behavior related to emergency calls or make phone calls when
- * radio is power off due to the device being on Bluetooth. Specifically, this class handles the
- * case of the user trying to dial an emergency number while the radio is off (i.e. the device is
- * in airplane mode) or a normal number while the radio is off (because of the device is on
- * Bluetooth), by forcibly turning the radio back on, waiting for it to come up, and then retrying
- * the call.
+ * Helper class that implements special behavior related to emergency calls. Specifically, this
+ * class handles the case of the user trying to dial an emergency number while the radio is off
+ * (i.e. the device is in airplane mode), by forcibly turning the radio back on, waiting for it to
+ * come up, and then retrying the emergency call.
*/
-public class RadioOnHelper implements RadioOnStateListener.Callback {
+public class EmergencyCallHelper implements EmergencyCallStateListener.Callback {
private final Context mContext;
- private RadioOnStateListener.Callback mCallback;
- private List<RadioOnStateListener> mListeners;
- private List<RadioOnStateListener> mInProgressListeners;
- private boolean mIsRadioOnCallingEnabled;
+ private EmergencyCallStateListener.Callback mCallback;
+ private List<EmergencyCallStateListener> mListeners;
+ private List<EmergencyCallStateListener> mInProgressListeners;
+ private boolean mIsEmergencyCallingEnabled;
- public RadioOnHelper(Context context) {
+
+ public EmergencyCallHelper(Context context) {
mContext = context;
mInProgressListeners = new ArrayList<>(2);
}
@@ -56,12 +55,12 @@
}
mListeners = new ArrayList<>(2);
for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
- mListeners.add(new RadioOnStateListener());
+ mListeners.add(new EmergencyCallStateListener());
}
}
/**
* Starts the "turn on radio" sequence. This is the (single) external API of the
- * RadioOnHelper class.
+ * EmergencyCallHelper class.
*
* This method kicks off the following sequence:
* - Power on the radio for each Phone
@@ -70,14 +69,14 @@
* - Finally, clean up any leftover state.
*
* This method is safe to call from any thread, since it simply posts a message to the
- * RadioOnHelper's handler (thus ensuring that the rest of the sequence is entirely
+ * EmergencyCallHelper's handler (thus ensuring that the rest of the sequence is entirely
* serialized, and runs on the main looper.)
*/
- public void enableRadioOnCalling(RadioOnStateListener.Callback callback) {
+ public void enableEmergencyCalling(EmergencyCallStateListener.Callback callback) {
setupListeners();
mCallback = callback;
mInProgressListeners.clear();
- mIsRadioOnCallingEnabled = false;
+ mIsEmergencyCallingEnabled = false;
for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
Phone phone = PhoneFactory.getPhone(i);
if (phone == null)
@@ -121,16 +120,11 @@
* Synchronization is not necessary.
*/
@Override
- public void onComplete(RadioOnStateListener listener, boolean isRadioReady) {
- mIsRadioOnCallingEnabled |= isRadioReady;
+ public void onComplete(EmergencyCallStateListener listener, boolean isRadioReady) {
+ mIsEmergencyCallingEnabled |= isRadioReady;
mInProgressListeners.remove(listener);
if (mCallback != null && mInProgressListeners.isEmpty()) {
- mCallback.onComplete(null, mIsRadioOnCallingEnabled);
+ mCallback.onComplete(null, mIsEmergencyCallingEnabled);
}
}
-
- @Override
- public boolean isOkToCall(Phone phone, int serviceState) {
- return (mCallback == null) ? false : mCallback.isOkToCall(phone, serviceState);
- }
}
diff --git a/src/com/android/services/telephony/RadioOnStateListener.java b/src/com/android/services/telephony/EmergencyCallStateListener.java
similarity index 92%
rename from src/com/android/services/telephony/RadioOnStateListener.java
rename to src/com/android/services/telephony/EmergencyCallStateListener.java
index 7bfa9c6..036872d 100644
--- a/src/com/android/services/telephony/RadioOnStateListener.java
+++ b/src/com/android/services/telephony/EmergencyCallStateListener.java
@@ -31,16 +31,15 @@
/**
* Helper class that listens to a Phone's radio state and sends a callback when the radio state of
- * that Phone is either "in service" or ("emergency calls only." if is emergency).
+ * that Phone is either "in service" or "emergency calls only."
*/
-public class RadioOnStateListener {
+public class EmergencyCallStateListener {
/**
- * Receives the result of the RadioOnStateListener's attempt to turn on the radio.
+ * Receives the result of the EmergencyCallStateListener's attempt to turn on the radio.
*/
interface Callback {
- void onComplete(RadioOnStateListener listener, boolean isRadioReady);
- boolean isOkToCall(Phone phone, int serviceState);
+ void onComplete(EmergencyCallStateListener listener, boolean isRadioReady);
}
// Number of times to retry the call, and time between retry attempts.
@@ -63,8 +62,8 @@
SomeArgs args = (SomeArgs) msg.obj;
try {
Phone phone = (Phone) args.arg1;
- RadioOnStateListener.Callback callback =
- (RadioOnStateListener.Callback) args.arg2;
+ EmergencyCallStateListener.Callback callback =
+ (EmergencyCallStateListener.Callback) args.arg2;
startSequenceInternal(phone, callback);
} finally {
args.recycle();
@@ -90,7 +89,7 @@
/**
* Starts the "wait for radio" sequence. This is the (single) external API of the
- * RadioOnStateListener class.
+ * EmergencyCallStateListener class.
*
* This method kicks off the following sequence:
* - Listen for the service state change event telling us the radio has come up.
@@ -99,7 +98,7 @@
* - Finally, clean up any leftover state.
*
* This method is safe to call from any thread, since it simply posts a message to the
- * RadioOnStateListener's handler (thus ensuring that the rest of the sequence is entirely
+ * EmergencyCallStateListener's handler (thus ensuring that the rest of the sequence is entirely
* serialized, and runs only on the handler thread.)
*/
public void waitForRadioOn(Phone phone, Callback callback) {
@@ -124,7 +123,7 @@
private void startSequenceInternal(Phone phone, Callback callback) {
Log.d(this, "startSequenceInternal: Phone " + phone.getPhoneId());
- // First of all, clean up any state left over from a prior RadioOn call sequence. This
+ // First of all, clean up any state left over from a prior emergency call sequence. This
// ensures that we'll behave sanely if another startTurnOnRadioSequence() comes in while
// we're already in the middle of the sequence.
cleanup();
@@ -141,7 +140,7 @@
/**
* Handles the SERVICE_STATE_CHANGED event. Normally this event tells us that the radio has
- * finally come up. In that case, it's now safe to actually place the RadioOn call.
+ * finally come up. In that case, it's now safe to actually place the emergency call.
*/
private void onServiceStateChanged(ServiceState state) {
Log.d(this, "onServiceStateChanged(), new state = %s, Phone = %s", state,
@@ -172,7 +171,8 @@
* UNAVAILABLE state, even if it is reporting the OUT_OF_SERVICE state.
*/
private boolean isOkToCall(int serviceState) {
- return (mCallback == null) ? false : mCallback.isOkToCall(mPhone, serviceState);
+ return (mPhone.getState() == PhoneConstants.State.OFFHOOK) ||
+ mPhone.getServiceStateTracker().isRadioOn();
}
/**
@@ -223,7 +223,7 @@
* - Clean up any extraneous handler messages (like retry timeouts) still in the queue
*
* Basically this method guarantees that there will be no more activity from the
- * RadioOnStateListener until someone kicks off the whole sequence again with another call
+ * EmergencyCallStateListener until someone kicks off the whole sequence again with another call
* to {@link #waitForRadioOn}
*
* TODO: Do the work for the comment below:
@@ -298,7 +298,7 @@
if (this == o) return true;
if (o == null || !getClass().equals(o.getClass())) return false;
- RadioOnStateListener that = (RadioOnStateListener) o;
+ EmergencyCallStateListener that = (EmergencyCallStateListener) o;
if (mNumRetriesSoFar != that.mNumRetriesSoFar) {
return false;
diff --git a/src/com/android/services/telephony/GsmConnection.java b/src/com/android/services/telephony/GsmConnection.java
index c480baa..ca547fa 100644
--- a/src/com/android/services/telephony/GsmConnection.java
+++ b/src/com/android/services/telephony/GsmConnection.java
@@ -22,8 +22,8 @@
* Manages a single phone call handled by GSM.
*/
final class GsmConnection extends TelephonyConnection {
- GsmConnection(Connection connection, String telecomCallId) {
- super(connection, telecomCallId);
+ GsmConnection(Connection connection, String telecomCallId, boolean isOutgoing) {
+ super(connection, telecomCallId, isOutgoing);
}
/**
@@ -36,7 +36,7 @@
@Override
public TelephonyConnection cloneConnection() {
GsmConnection gsmConnection = new GsmConnection(getOriginalConnection(),
- getTelecomCallId());
+ getTelecomCallId(), mIsOutgoing);
return gsmConnection;
}
diff --git a/src/com/android/services/telephony/ImsConference.java b/src/com/android/services/telephony/ImsConference.java
index 6c4fadc..603c3f4 100644
--- a/src/com/android/services/telephony/ImsConference.java
+++ b/src/com/android/services/telephony/ImsConference.java
@@ -131,17 +131,6 @@
}
/**
- * Handles destruction of the host connection; once the host connection has been
- * destroyed, cleans up the conference participant connection.
- *
- * @param connection The host connection.
- */
- @Override
- public void onDestroyed(android.telecom.Connection connection) {
- disconnectConferenceParticipants();
- }
-
- /**
* Handles changes to conference participant data as reported by the conference host
* connection.
*
@@ -215,7 +204,7 @@
/**
* The telephony connection service; used to add new participant connections to Telecom.
*/
- private TelephonyConnectionService mTelephonyConnectionService;
+ private TelephonyConnectionServiceProxy mTelephonyConnectionService;
/**
* The connection to the conference server which is hosting the conference.
@@ -232,6 +221,8 @@
*/
private Uri[] mConferenceHostAddress;
+ private TelecomAccountRegistry mTelecomAccountRegistry;
+
/**
* The known conference participant connections. The HashMap is keyed by a Pair containing
* the handle and endpoint Uris.
@@ -267,11 +258,14 @@
* @param conferenceHost The telephony connection hosting the conference.
* @param phoneAccountHandle The phone account handle associated with the conference.
*/
- public ImsConference(TelephonyConnectionService telephonyConnectionService,
+ public ImsConference(TelecomAccountRegistry telecomAccountRegistry,
+ TelephonyConnectionServiceProxy telephonyConnectionService,
TelephonyConnection conferenceHost, PhoneAccountHandle phoneAccountHandle) {
super(phoneAccountHandle);
+ mTelecomAccountRegistry = telecomAccountRegistry;
+
// Specify the connection time of the conference to be the connection time of the original
// connection.
long connectTime = conferenceHost.getOriginalConnection().getConnectTime();
@@ -411,6 +405,8 @@
return;
}
+ disconnectConferenceParticipants();
+
Call call = mConferenceHost.getCall();
if (call != null) {
try {
@@ -593,8 +589,7 @@
Phone imsPhone = mConferenceHost.getPhone();
mConferenceHostPhoneAccountHandle =
PhoneUtils.makePstnPhoneAccountHandle(imsPhone.getDefaultPhone());
- Uri hostAddress = TelecomAccountRegistry.getInstance(mTelephonyConnectionService)
- .getAddress(mConferenceHostPhoneAccountHandle);
+ Uri hostAddress = mTelecomAccountRegistry.getAddress(mConferenceHostPhoneAccountHandle);
ArrayList<Uri> hostAddresses = new ArrayList<>();
@@ -739,8 +734,9 @@
mConferenceParticipantConnections.put(new Pair<>(participant.getHandle(),
participant.getEndpoint()), connection);
}
+
mTelephonyConnectionService.addExistingConnection(mConferenceHostPhoneAccountHandle,
- connection);
+ connection, this);
addConnection(connection);
}
@@ -883,7 +879,8 @@
if (mConferenceHost.getPhone().getPhoneType() == PhoneConstants.PHONE_TYPE_GSM) {
Log.i(this,"handleOriginalConnectionChange : SRVCC to GSM");
- GsmConnection c = new GsmConnection(originalConnection, getTelecomCallId());
+ GsmConnection c = new GsmConnection(originalConnection, getTelecomCallId(),
+ mConferenceHost.isOutgoingCall());
// This is a newly created conference connection as a result of SRVCC
c.setConferenceSupported(true);
c.addCapability(Connection.CAPABILITY_CONFERENCE_HAS_NO_CHILDREN);
@@ -1014,4 +1011,47 @@
}
return PhoneGlobals.getInstance().getCarrierConfigForSubId(phone.getSubId());
}
+
+ /**
+ * @return {@code true} if the carrier associated with the conference requires that the maximum
+ * size of the conference is enforced, {@code false} otherwise.
+ */
+ public boolean isMaximumConferenceSizeEnforced() {
+ PersistableBundle b = getCarrierConfig();
+ // Return false if the CarrierConfig is unavailable
+ return b != null && b.getBoolean(
+ CarrierConfigManager.KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL);
+ }
+
+ /**
+ * @return The maximum size of a conference call where
+ * {@link #isMaximumConferenceSizeEnforced()} is true.
+ */
+ public int getMaximumConferenceSize() {
+ PersistableBundle b = getCarrierConfig();
+
+ // If there is no carrier config its really a problem, but we'll still define a sane limit
+ // of 5 so that we can still make a conference.
+ if (b == null) {
+ Log.w(this, "getMaximumConferenceSize - failed to get conference size");
+ return 5;
+ }
+ return b.getInt(CarrierConfigManager.KEY_IMS_CONFERENCE_SIZE_LIMIT_INT);
+ }
+
+ /**
+ * @return The number of participants in the conference.
+ */
+ public int getNumberOfParticipants() {
+ return mConferenceParticipantConnections.size();
+ }
+
+ /**
+ * @return {@code True} if the carrier enforces a maximum conference size, and the number of
+ * participants in the conference has reached the limit, {@code false} otherwise.
+ */
+ public boolean isFullConference() {
+ return isMaximumConferenceSizeEnforced()
+ && getNumberOfParticipants() >= getMaximumConferenceSize();
+ }
}
diff --git a/src/com/android/services/telephony/ImsConferenceController.java b/src/com/android/services/telephony/ImsConferenceController.java
index 4df6444..501808f 100644
--- a/src/com/android/services/telephony/ImsConferenceController.java
+++ b/src/com/android/services/telephony/ImsConferenceController.java
@@ -16,6 +16,7 @@
package com.android.services.telephony;
+import com.android.ims.ImsReasonInfo;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.phone.PhoneUtils;
@@ -91,7 +92,7 @@
/**
* The current {@link ConnectionService}.
*/
- private final TelephonyConnectionService mConnectionService;
+ private final TelephonyConnectionServiceProxy mConnectionService;
/**
* List of known {@link TelephonyConnection}s.
@@ -104,13 +105,17 @@
*/
private final ArrayList<ImsConference> mImsConferences = new ArrayList<>(1);
+ private TelecomAccountRegistry mTelecomAccountRegistry;
+
/**
* Creates a new instance of the Ims conference controller.
*
* @param connectionService The current connection service.
*/
- public ImsConferenceController(TelephonyConnectionService connectionService) {
+ public ImsConferenceController(TelecomAccountRegistry telecomAccountRegistry,
+ TelephonyConnectionServiceProxy connectionService) {
mConnectionService = connectionService;
+ mTelecomAccountRegistry = telecomAccountRegistry;
}
/**
@@ -241,8 +246,10 @@
case Connection.STATE_ACTIVE:
//fall through
case Connection.STATE_HOLDING:
- conferenceParticipantsSet.addAll(conference.getConnections());
- conferenceableSet.add(conference);
+ if (!conference.isFullConference()) {
+ conferenceParticipantsSet.addAll(conference.getConnections());
+ conferenceableSet.add(conference);
+ }
continue;
default:
break;
@@ -269,7 +276,14 @@
conferenceables.addAll(conferenceParticipantsSet);
((Connection) c).setConferenceables(conferenceables);
- } else if (c instanceof Conference) {
+ } else if (c instanceof ImsConference) {
+ ImsConference imsConference = (ImsConference) c;
+
+ // If the conference is full, don't allow anything to be conferenced with it.
+ if (imsConference.isFullConference()) {
+ imsConference.setConferenceableConnections(Collections.<Connection>emptyList());
+ }
+
// Remove all conferences from the set, since we can not conference a conference
// to another conference.
List<Connection> connections = conferenceableSet
@@ -278,7 +292,7 @@
.map(conferenceable -> (Connection) conferenceable)
.collect(Collectors.toList());
// Conference equivalent to setConferenceables that only accepts Connections
- ((Conference) c).setConferenceableConnections(connections);
+ imsConference.setConferenceableConnections(connections);
}
}
}
@@ -310,7 +324,6 @@
Iterator<TelephonyConnection> it = mTelephonyConnections.iterator();
while (it.hasNext()) {
TelephonyConnection connection = it.next();
-
if (connection.isImsConnection() && connection.getOriginalConnection() != null &&
connection.getOriginalConnection().isMultiparty()) {
@@ -357,8 +370,8 @@
PhoneUtils.makePstnPhoneAccountHandle(imsPhone.getDefaultPhone());
}
- ImsConference conference = new ImsConference(mConnectionService, conferenceHostConnection,
- phoneAccountHandle);
+ ImsConference conference = new ImsConference(mTelecomAccountRegistry, mConnectionService,
+ conferenceHostConnection, phoneAccountHandle);
conference.setState(conferenceHostConnection.getState());
conference.addListener(mConferenceListener);
conference.updateConferenceParticipantsAfterCreation();
@@ -370,7 +383,9 @@
// disconnect tone is not played.
connection.removeConnectionListener(mConnectionListener);
connection.clearOriginalConnection();
- connection.setDisconnected(new DisconnectCause(DisconnectCause.OTHER));
+ connection.setDisconnected(new DisconnectCause(DisconnectCause.OTHER,
+ android.telephony.DisconnectCause.toString(
+ android.telephony.DisconnectCause.IMS_MERGED_SUCCESSFULLY)));
connection.destroy();
mImsConferences.add(conference);
}
diff --git a/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java b/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
index eb6f7f6..e557919 100644
--- a/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
+++ b/src/com/android/services/telephony/PstnPhoneCapabilitiesNotifier.java
@@ -90,10 +90,10 @@
private void handleVideoCapabilitesChanged(AsyncResult ar) {
try {
boolean isVideoCapable = (Boolean) ar.result;
- Log.d(this, "handleVideoCapabilitesChanged. Video capability - " + isVideoCapable);
+ Log.i(this, "handleVideoCapabilitesChanged. Video capability - " + isVideoCapable);
mListener.onVideoCapabilitiesChanged(isVideoCapable);
} catch (Exception e) {
- Log.d(this, "handleVideoCapabilitesChanged. Exception=" + e);
+ Log.w(this, "handleVideoCapabilitesChanged. Exception=" + e);
}
}
diff --git a/src/com/android/services/telephony/TelecomAccountRegistry.java b/src/com/android/services/telephony/TelecomAccountRegistry.java
index bcc53b5..9cd89c2 100644
--- a/src/com/android/services/telephony/TelecomAccountRegistry.java
+++ b/src/com/android/services/telephony/TelecomAccountRegistry.java
@@ -183,18 +183,19 @@
}
mIsVideoCapable = mPhone.isVideoEnabled();
+ boolean isVideoEnabledByPlatform =
+ ImsManager.isVtEnabledByPlatform(mPhone.getContext());
if (!mIsPrimaryUser) {
Log.i(this, "Disabling video calling for secondary user.");
mIsVideoCapable = false;
+ isVideoEnabledByPlatform = false;
}
if (mIsVideoCapable) {
capabilities |= PhoneAccount.CAPABILITY_VIDEO_CALLING;
}
- boolean isVideoEnabledByPlatform =
- ImsManager.isVtEnabledByPlatform(mPhone.getContext());
if (isVideoEnabledByPlatform) {
capabilities |= PhoneAccount.CAPABILITY_SUPPORTS_VIDEO_CALLING;
}
diff --git a/src/com/android/services/telephony/TelephonyConferenceController.java b/src/com/android/services/telephony/TelephonyConferenceController.java
index 5d59e17..1386e19 100644
--- a/src/com/android/services/telephony/TelephonyConferenceController.java
+++ b/src/com/android/services/telephony/TelephonyConferenceController.java
@@ -68,13 +68,12 @@
/** The known connections. */
private final List<TelephonyConnection> mTelephonyConnections = new ArrayList<>();
- private final TelephonyConnectionService mConnectionService;
+ private final TelephonyConnectionServiceProxy mConnectionService;
private boolean mTriggerRecalculate = false;
- public TelephonyConferenceController(TelephonyConnectionService connectionService) {
+ public TelephonyConferenceController(TelephonyConnectionServiceProxy connectionService) {
mConnectionService = connectionService;
}
-
/** The TelephonyConference connection object. */
private TelephonyConference mTelephonyConference;
@@ -89,7 +88,6 @@
Log.w(this, "add - connection already tracked; connection=%s", connection);
return;
}
-
mTelephonyConnections.add(connection);
connection.addConnectionListener(mConnectionListener);
recalculate();
@@ -182,13 +180,11 @@
for (TelephonyConnection connection : mTelephonyConnections) {
com.android.internal.telephony.Connection radioConnection =
connection.getOriginalConnection();
-
if (radioConnection != null) {
Call.State state = radioConnection.getState();
Call call = radioConnection.getCall();
if ((state == Call.State.ACTIVE || state == Call.State.HOLDING) &&
(call != null && call.isMultiparty())) {
-
numGsmConnections++;
conferencedConnections.add(connection);
}
diff --git a/src/com/android/services/telephony/TelephonyConnection.java b/src/com/android/services/telephony/TelephonyConnection.java
index a403d1f..6aa4b97 100644
--- a/src/com/android/services/telephony/TelephonyConnection.java
+++ b/src/com/android/services/telephony/TelephonyConnection.java
@@ -500,13 +500,19 @@
private boolean mIsCdmaVoicePrivacyEnabled;
/**
+ * Indicates whether this call is an outgoing call.
+ */
+ protected final boolean mIsOutgoing;
+
+ /**
* Listeners to our TelephonyConnection specific callbacks
*/
private final Set<TelephonyConnectionListener> mTelephonyListeners = Collections.newSetFromMap(
new ConcurrentHashMap<TelephonyConnectionListener, Boolean>(8, 0.9f, 1));
protected TelephonyConnection(com.android.internal.telephony.Connection originalConnection,
- String callId) {
+ String callId, boolean isOutgoingCall) {
+ mIsOutgoing = isOutgoingCall;
setTelecomCallId(callId);
if (originalConnection != null) {
setOriginalConnection(originalConnection);
@@ -1554,6 +1560,13 @@
}
/**
+ * @return {@code true} if this is an outgoing call, {@code false} otherwise.
+ */
+ boolean isOutgoingCall() {
+ return mIsOutgoing;
+ }
+
+ /**
* Sets the current call audio quality. Used during rebuild of the properties
* to set or unset the {@link Connection#PROPERTY_HIGH_DEF_AUDIO} property.
*
diff --git a/src/com/android/services/telephony/TelephonyConnectionService.java b/src/com/android/services/telephony/TelephonyConnectionService.java
index 148759e..ac3e50a 100644
--- a/src/com/android/services/telephony/TelephonyConnectionService.java
+++ b/src/com/android/services/telephony/TelephonyConnectionService.java
@@ -41,6 +41,7 @@
import android.text.TextUtils;
import android.util.Pair;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Call;
import com.android.internal.telephony.CallStateException;
import com.android.internal.telephony.GsmCdmaPhone;
@@ -72,14 +73,52 @@
private static final Pattern CDMA_ACTIVATION_CODE_REGEX_PATTERN =
Pattern.compile("\\*228[0-9]{0,2}");
+ private final TelephonyConnectionServiceProxy mTelephonyConnectionServiceProxy =
+ new TelephonyConnectionServiceProxy() {
+ @Override
+ public Collection<Connection> getAllConnections() {
+ return TelephonyConnectionService.this.getAllConnections();
+ }
+ @Override
+ public void addConference(TelephonyConference mTelephonyConference) {
+ TelephonyConnectionService.this.addConference(mTelephonyConference);
+ }
+ @Override
+ public void addConference(ImsConference mImsConference) {
+ TelephonyConnectionService.this.addConference(mImsConference);
+ }
+ @Override
+ public void removeConnection(Connection connection) {
+ TelephonyConnectionService.this.removeConnection(connection);
+ }
+ @Override
+ public void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
+ Connection connection) {
+ TelephonyConnectionService.this
+ .addExistingConnection(phoneAccountHandle, connection);
+ }
+ @Override
+ public void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
+ Connection connection, Conference conference) {
+ TelephonyConnectionService.this
+ .addExistingConnection(phoneAccountHandle, connection, conference);
+ }
+ @Override
+ public void addConnectionToConferenceController(TelephonyConnection connection) {
+ TelephonyConnectionService.this.addConnectionToConferenceController(connection);
+ }
+ };
+
private final TelephonyConferenceController mTelephonyConferenceController =
- new TelephonyConferenceController(this);
+ new TelephonyConferenceController(mTelephonyConnectionServiceProxy);
private final CdmaConferenceController mCdmaConferenceController =
new CdmaConferenceController(this);
private final ImsConferenceController mImsConferenceController =
- new ImsConferenceController(this);
+ new ImsConferenceController(TelecomAccountRegistry.getInstance(this),
+ mTelephonyConnectionServiceProxy);
private ComponentName mExpectedComponentName = null;
+ private EmergencyCallHelper mEmergencyCallHelper;
private EmergencyTonePlayer mEmergencyTonePlayer;
// Contains one TelephonyConnection that has placed a call and a memory of which Phones it has
@@ -90,6 +129,105 @@
private Pair<WeakReference<TelephonyConnection>, List<Phone>> mEmergencyRetryCache;
/**
+ * Keeps track of the status of a SIM slot.
+ */
+ private static class SlotStatus {
+ public int slotId;
+ // RAT capabilities
+ public int capabilities;
+ // By default, we will assume that the slots are not locked.
+ public boolean isLocked = false;
+
+ public SlotStatus(int slotId, int capabilities) {
+ this.slotId = slotId;
+ this.capabilities = capabilities;
+ }
+ }
+
+ // SubscriptionManager Proxy interface for testing
+ public interface SubscriptionManagerProxy {
+ int getDefaultVoicePhoneId();
+ int getSimStateForSlotIdx(int slotId);
+ int getPhoneId(int subId);
+ }
+
+ private SubscriptionManagerProxy mSubscriptionManagerProxy = new SubscriptionManagerProxy() {
+ @Override
+ public int getDefaultVoicePhoneId() {
+ return SubscriptionManager.getDefaultVoicePhoneId();
+ }
+
+ @Override
+ public int getSimStateForSlotIdx(int slotId) {
+ return SubscriptionManager.getSimStateForSlotIndex(slotId);
+ }
+
+ @Override
+ public int getPhoneId(int subId) {
+ return SubscriptionManager.getPhoneId(subId);
+ }
+ };
+
+ // TelephonyManager Proxy interface for testing
+ public interface TelephonyManagerProxy {
+ int getPhoneCount();
+ boolean hasIccCard(int slotId);
+ }
+
+ private TelephonyManagerProxy mTelephonyManagerProxy = new TelephonyManagerProxy() {
+ private final TelephonyManager sTelephonyManager = TelephonyManager.getDefault();
+
+ @Override
+ public int getPhoneCount() {
+ return sTelephonyManager.getPhoneCount();
+ }
+
+ @Override
+ public boolean hasIccCard(int slotId) {
+ return sTelephonyManager.hasIccCard(slotId);
+ }
+ };
+
+ //PhoneFactory proxy interface for testing
+ public interface PhoneFactoryProxy {
+ Phone getPhone(int index);
+ Phone getDefaultPhone();
+ Phone[] getPhones();
+ }
+
+ private PhoneFactoryProxy mPhoneFactoryProxy = new PhoneFactoryProxy() {
+ @Override
+ public Phone getPhone(int index) {
+ return PhoneFactory.getPhone(index);
+ }
+
+ @Override
+ public Phone getDefaultPhone() {
+ return PhoneFactory.getDefaultPhone();
+ }
+
+ @Override
+ public Phone[] getPhones() {
+ return PhoneFactory.getPhones();
+ }
+ };
+
+ @VisibleForTesting
+ public void setSubscriptionManagerProxy(SubscriptionManagerProxy proxy) {
+ mSubscriptionManagerProxy = proxy;
+ }
+
+ @VisibleForTesting
+ public void setTelephonyManagerProxy(TelephonyManagerProxy proxy) {
+ mTelephonyManagerProxy = proxy;
+ }
+
+ @VisibleForTesting
+ public void setPhoneFactoryProxy(PhoneFactoryProxy proxy) {
+ mPhoneFactoryProxy = proxy;
+ }
+
+ /**
* A listener to actionable events specific to the TelephonyConnection.
*/
private final TelephonyConnection.TelephonyConnectionListener mTelephonyConnectionListener =
@@ -217,39 +355,73 @@
final boolean isEmergencyNumber =
PhoneNumberUtils.isLocalEmergencyNumber(this, numberToDial);
- if ((isEmergencyNumber && !isRadioOn()) || isRadioPowerDownOnBluetooth()) {
- final Uri resultHandle = handle;
+ final boolean isAirplaneModeOn = Settings.Global.getInt(getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) > 0;
+
+ if (isEmergencyNumber && (!isRadioOn() || isAirplaneModeOn)) {
+ final Uri emergencyHandle = handle;
// By default, Connection based on the default Phone, since we need to return to Telecom
// now.
- final Connection resultConnection = getTelephonyConnection(request, numberToDial,
- isEmergencyNumber, resultHandle, PhoneFactory.getDefaultPhone());
- RadioOnHelper radioOnHelper = new RadioOnHelper(this);
- radioOnHelper.enableRadioOnCalling(new RadioOnStateListener.Callback() {
+ final int defaultPhoneType = mPhoneFactoryProxy.getDefaultPhone().getPhoneType();
+ final Connection emergencyConnection = getTelephonyConnection(request, numberToDial,
+ isEmergencyNumber, emergencyHandle, mPhoneFactoryProxy.getDefaultPhone());
+ if (mEmergencyCallHelper == null) {
+ mEmergencyCallHelper = new EmergencyCallHelper(this);
+ }
+ mEmergencyCallHelper.enableEmergencyCalling(new EmergencyCallStateListener.Callback() {
@Override
- public void onComplete(RadioOnStateListener listener,
- boolean isRadioReady) {
- handleOnComplete(isRadioReady,
- isEmergencyNumber,
- resultConnection,
- request,
- numberToDial,
- resultHandle);
- }
-
- @Override
- public boolean isOkToCall(Phone phone, int serviceState) {
- if (isEmergencyNumber) {
- return (phone.getState() == PhoneConstants.State.OFFHOOK) ||
- phone.getServiceStateTracker().isRadioOn();
+ public void onComplete(EmergencyCallStateListener listener, boolean isRadioReady) {
+ // Make sure the Call has not already been canceled by the user.
+ if (emergencyConnection.getState() == Connection.STATE_DISCONNECTED) {
+ Log.i(this, "Emergency call disconnected before the outgoing call was " +
+ "placed. Skipping emergency call placement.");
+ return;
+ }
+ if (isRadioReady) {
+ // Get the right phone object since the radio has been turned on
+ // successfully.
+ final Phone phone = getPhoneForAccount(request.getAccountHandle(),
+ isEmergencyNumber);
+ // If the PhoneType of the Phone being used is different than the Default
+ // Phone, then we need create a new Connection using that PhoneType and
+ // replace it in Telecom.
+ if (phone.getPhoneType() != defaultPhoneType) {
+ 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!
+ if (repConnection instanceof TelephonyConnection) {
+ placeOutgoingConnection((TelephonyConnection) repConnection, phone,
+ request);
+ }
+ // Notify Telecom of the new Connection type.
+ // TODO: Switch out the underlying connection instead of creating a new
+ // one and causing UI Jank.
+ addExistingConnection(PhoneUtils.makePstnPhoneAccountHandle(phone),
+ repConnection);
+ // Remove the old connection from Telecom after.
+ emergencyConnection.setDisconnected(
+ DisconnectCauseUtil.toTelecomDisconnectCause(
+ android.telephony.DisconnectCause.OUTGOING_CANCELED,
+ "Reconnecting outgoing Emergency Call."));
+ emergencyConnection.destroy();
+ } else {
+ placeOutgoingConnection((TelephonyConnection) emergencyConnection,
+ phone, request);
+ }
} else {
- return (phone.getState() == PhoneConstants.State.OFFHOOK) ||
- serviceState == ServiceState.STATE_IN_SERVICE;
+ Log.w(this, "onCreateOutgoingConnection, failed to turn on radio");
+ emergencyConnection.setDisconnected(
+ DisconnectCauseUtil.toTelecomDisconnectCause(
+ android.telephony.DisconnectCause.POWER_OFF,
+ "Failed to turn on radio."));
+ emergencyConnection.destroy();
}
}
});
// Return the still unconnected GsmConnection and wait for the Radios to boot before
// connecting it to the underlying Phone.
- return resultConnection;
+ return emergencyConnection;
} else {
if (!canAddCall() && !isEmergencyNumber) {
Log.d(this, "onCreateOutgoingConnection, cannot add call .");
@@ -276,76 +448,6 @@
}
/**
- * Whether the cellular radio is power off because the device is on Bluetooth.
- */
- private boolean isRadioPowerDownOnBluetooth() {
- final Context context = getApplicationContext();
- final boolean allowed = context.getResources().getBoolean(
- R.bool.config_allowRadioPowerDownOnBluetooth);
- final int cellOn = Settings.Global.getInt(context.getContentResolver(),
- Settings.Global.CELL_ON,
- PhoneConstants.CELL_ON_FLAG);
- return (allowed && cellOn == PhoneConstants.CELL_ON_FLAG && !isRadioOn());
- }
-
- /**
- * Handle the onComplete callback of RadioOnStateListener.
- */
- private void handleOnComplete(boolean isRadioReady,
- boolean isEmergencyNumber,
- Connection originalConnection,
- ConnectionRequest request,
- String numberToDial,
- Uri handle) {
- // Make sure the Call has not already been canceled by the user.
- if (originalConnection.getState() == Connection.STATE_DISCONNECTED) {
- Log.i(this, "Emergency call disconnected before the outgoing call was " +
- "placed. Skipping emergency call placement.");
- return;
- }
- if (isRadioReady) {
- // Get the right phone object since the radio has been turned on
- // successfully.
- final Phone phone = getPhoneForAccount(request.getAccountHandle(),
- isEmergencyNumber);
- // If the PhoneType of the Phone being used is different than the Default
- // Phone, then we need create a new Connection using that PhoneType and
- // replace it in Telecom.
- if (phone.getPhoneType() != PhoneFactory.getDefaultPhone().getPhoneType()) {
- Connection repConnection = 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, just return!
- if (repConnection instanceof TelephonyConnection) {
- placeOutgoingConnection((TelephonyConnection) repConnection, phone,
- request);
- }
- // Notify Telecom of the new Connection type.
- // TODO: Switch out the underlying connection instead of creating a new
- // one and causing UI Jank.
- addExistingConnection(PhoneUtils.makePstnPhoneAccountHandle(phone),
- repConnection);
- // Remove the old connection from Telecom after.
- originalConnection.setDisconnected(
- DisconnectCauseUtil.toTelecomDisconnectCause(
- android.telephony.DisconnectCause.OUTGOING_CANCELED,
- "Reconnecting outgoing Emergency Call."));
- originalConnection.destroy();
- } else {
- placeOutgoingConnection((TelephonyConnection) originalConnection,
- phone, request);
- }
- } else {
- Log.w(this, "onCreateOutgoingConnection, failed to turn on radio");
- originalConnection.setDisconnected(
- DisconnectCauseUtil.toTelecomDisconnectCause(
- android.telephony.DisconnectCause.POWER_OFF,
- "Failed to turn on radio."));
- originalConnection.destroy();
- }
- }
-
- /**
* @return {@code true} if any other call is disabling the ability to add calls, {@code false}
* otherwise.
*/
@@ -368,7 +470,7 @@
if (context.getResources().getBoolean(R.bool.config_checkSimStateBeforeOutgoingCall)) {
// Check SIM card state before the outgoing call.
// Start the SIM unlock activity if PIN_REQUIRED.
- final Phone defaultPhone = PhoneFactory.getDefaultPhone();
+ final Phone defaultPhone = mPhoneFactoryProxy.getDefaultPhone();
final IccCard icc = defaultPhone.getIccCard();
IccCardConstants.State simState = IccCardConstants.State.UNKNOWN;
if (icc != null) {
@@ -449,10 +551,6 @@
"ServiceState.STATE_OUT_OF_SERVICE"));
}
case ServiceState.STATE_POWER_OFF:
- // Don't disconnect if radio is power off because the device is on Bluetooth.
- if (isRadioPowerDownOnBluetooth()) {
- break;
- }
return Connection.createFailedConnection(
DisconnectCauseUtil.toTelecomDisconnectCause(
android.telephony.DisconnectCause.POWER_OFF,
@@ -560,6 +658,21 @@
}
}
+ /**
+ * Called by the {@link ConnectionService} when a newly created {@link Connection} has been
+ * added to the {@link ConnectionService} and sent to Telecom. Here it is safe to send
+ * connection events.
+ *
+ * @param connection the {@link Connection}.
+ */
+ @Override
+ public void onCreateConnectionComplete(Connection connection) {
+ if (connection instanceof TelephonyConnection) {
+ TelephonyConnection telephonyConnection = (TelephonyConnection) connection;
+ maybeSendInternationalCallEvent(telephonyConnection);
+ }
+ }
+
@Override
public void triggerConferenceRecalculate() {
if (mTelephonyConferenceController.shouldRecalculate()) {
@@ -723,7 +836,7 @@
private boolean isRadioOn() {
boolean result = false;
- for (Phone phone : PhoneFactory.getPhones()) {
+ for (Phone phone : mPhoneFactoryProxy.getPhones()) {
result |= phone.isRadioOn();
}
return result;
@@ -731,7 +844,7 @@
private Pair<WeakReference<TelephonyConnection>, List<Phone>> makeCachedConnectionPhonePair(
TelephonyConnection c) {
- List<Phone> phones = new ArrayList<>(Arrays.asList(PhoneFactory.getPhones()));
+ List<Phone> phones = new ArrayList<>(Arrays.asList(mPhoneFactoryProxy.getPhones()));
return new Pair<>(new WeakReference<>(c), phones);
}
@@ -800,18 +913,6 @@
try {
if (phone != null) {
originalConnection = phone.dial(number, null, videoState, extras);
-
- if (phone instanceof GsmCdmaPhone) {
- GsmCdmaPhone gsmCdmaPhone = (GsmCdmaPhone) phone;
- if (gsmCdmaPhone.isNotificationOfWfcCallRequired(number)) {
- // Send connection event to InCall UI to inform the user of the fact they
- // are potentially placing an international call on WFC.
- Log.i(this, "placeOutgoingConnection - sending international call on WFC " +
- "confirmation event");
- connection.sendConnectionEvent(
- TelephonyManager.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC, null);
- }
- }
}
} catch (CallStateException e) {
Log.e(this, e, "placeOutgoingConnection, phone.dial exception: " + e);
@@ -861,7 +962,7 @@
TelephonyConnection returnConnection = null;
int phoneType = phone.getPhoneType();
if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
- returnConnection = new GsmConnection(originalConnection, telecomCallId);
+ returnConnection = new GsmConnection(originalConnection, telecomCallId, isOutgoing);
} else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
boolean allowsMute = allowsMute(phone);
returnConnection = new CdmaConnection(originalConnection, mEmergencyTonePlayer,
@@ -894,8 +995,8 @@
Phone chosenPhone = null;
int subId = PhoneUtils.getSubIdForPhoneAccountHandle(accountHandle);
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- int phoneId = SubscriptionManager.getPhoneId(subId);
- chosenPhone = PhoneFactory.getPhone(phoneId);
+ int phoneId = mSubscriptionManagerProxy.getPhoneId(subId);
+ chosenPhone = mPhoneFactoryProxy.getPhone(phoneId);
}
// If this is an emergency call and the phone we originally planned to make this call
// with is not in service or was invalid, try to find one that is in service, using the
@@ -916,89 +1017,120 @@
* 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 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)
+ * 3) If there is a PUK locked SIM, compare the SIMs that are not PUK locked. If all the SIMs
+ * are locked, skip to condition 4).
+ * 4) The Phone with more Capabilities.
+ * 5) The First Phone that has a SIM card in it (Starting from Slot 0...N)
+ * 6) The Default Phone (Currently set as Slot 0)
*/
- private Phone getFirstPhoneForEmergencyCall() {
+ @VisibleForTesting
+ public Phone getFirstPhoneForEmergencyCall() {
// 1)
- int phoneId = SubscriptionManager.getDefaultVoicePhoneId();
+ int phoneId = mSubscriptionManagerProxy.getDefaultVoicePhoneId();
if (phoneId != SubscriptionManager.INVALID_PHONE_INDEX) {
- Phone defaultPhone = PhoneFactory.getPhone(phoneId);
+ Phone defaultPhone = mPhoneFactoryProxy.getPhone(phoneId);
if (defaultPhone != null && isAvailableForEmergencyCalls(defaultPhone)) {
return defaultPhone;
}
}
Phone firstPhoneWithSim = null;
- int phoneCount = TelephonyManager.getDefault().getPhoneCount();
- List<Pair<Integer, Integer>> phoneNetworkType = new ArrayList<>(phoneCount);
+ int phoneCount = mTelephonyManagerProxy.getPhoneCount();
+ List<SlotStatus> phoneSlotStatus = new ArrayList<>(phoneCount);
for (int i = 0; i < phoneCount; i++) {
- Phone phone = PhoneFactory.getPhone(i);
- if (phone == null)
+ Phone phone = mPhoneFactoryProxy.getPhone(i);
+ if (phone == null) {
continue;
+ }
// 2)
if (isAvailableForEmergencyCalls(phone)) {
// the slot has the radio on & state is in service.
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)) {
+ // Store the RAF Capabilities for sorting later.
+ int radioAccessFamily = phone.getRadioAccessFamily();
+ SlotStatus status = new SlotStatus(i, radioAccessFamily);
+ phoneSlotStatus.add(status);
+ Log.i(this, "getFirstPhoneForEmergencyCall, RAF:" +
+ Integer.toHexString(radioAccessFamily) + " saved for Phone Id:" + i);
+ // 3)
+ // Report Slot's PIN/PUK lock status for sorting later.
+ int simState = mSubscriptionManagerProxy.getSimStateForSlotIdx(i);
+ if (simState == TelephonyManager.SIM_STATE_PIN_REQUIRED ||
+ simState == TelephonyManager.SIM_STATE_PUK_REQUIRED) {
+ status.isLocked = true;
+ }
+ // 5)
+ if (firstPhoneWithSim == null && mTelephonyManagerProxy.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.i(this, "getFirstPhoneForEmergencyCall, SIM card inserted, Phone Id:" + i);
firstPhoneWithSim = phone;
+ Log.i(this, "getFirstPhoneForEmergencyCall, SIM card inserted, Phone Id:" +
+ firstPhoneWithSim.getPhoneId());
}
}
- // 5)
- if (firstPhoneWithSim == null && phoneNetworkType.isEmpty()) {
- // No SIMs inserted, get the default.
+ // 6)
+ if (firstPhoneWithSim == null && phoneSlotStatus.isEmpty()) {
+ // No Phones available, get the default.
Log.i(this, "getFirstPhoneForEmergencyCall, return default phone");
- return PhoneFactory.getDefaultPhone();
+ return mPhoneFactoryProxy.getDefaultPhone();
} else {
- // 3)
+ // 4)
+ final int defaultPhoneId = mPhoneFactoryProxy.getDefaultPhone().getPhoneId();
final Phone firstOccupiedSlot = firstPhoneWithSim;
- if (!phoneNetworkType.isEmpty()) {
+ if (!phoneSlotStatus.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 (phoneSlotStatus.size() > 1) {
+ Collections.sort(phoneSlotStatus, (o1, o2) -> {
+ // First start by seeing if either of the phone slots are locked. If they
+ // are, then sort by non-locked SIM first. If they are both locked, sort
+ // by capability instead.
+ if (o1.isLocked && !o2.isLocked) {
+ return -1;
+ }
+ if (o2.isLocked && !o1.isLocked) {
+ return 1;
+ }
+ // sort by number of RadioAccessFamily Capabilities.
+ int compare = Integer.bitCount(o1.capabilities) -
+ Integer.bitCount(o2.capabilities);
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 = RadioAccessFamily.getHighestRafCapability(o1.capabilities) -
+ RadioAccessFamily.getHighestRafCapability(o2.capabilities);
+ if (compare == 0) {
+ if (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.slotId == firstOccupiedSlot.getPhoneId()) {
+ return 1;
+ } else if (o2.slotId == firstOccupiedSlot.getPhoneId()) {
+ return -1;
+ }
+ } else {
+ // No slots have SIMs detected in them, so weight the default
+ // Phone Id greater than the others.
+ if (o1.slotId == defaultPhoneId) {
+ return 1;
+ } else if (o2.slotId == defaultPhoneId) {
+ return -1;
+ }
}
- // Compare is still 0, return equal.
}
}
return compare;
});
}
- int mostCapablePhoneId = phoneNetworkType.get(phoneNetworkType.size()-1).first;
+ int mostCapablePhoneId = phoneSlotStatus.get(phoneSlotStatus.size() - 1).slotId;
Log.i(this, "getFirstPhoneForEmergencyCall, Using Phone Id: " + mostCapablePhoneId +
"with highest capability");
- return PhoneFactory.getPhone(mostCapablePhoneId);
+ return mPhoneFactoryProxy.getPhone(mostCapablePhoneId);
} else {
- // 4)
+ // 5)
return firstPhoneWithSim;
}
}
@@ -1116,4 +1248,30 @@
android.provider.Settings.Secure.PREFERRED_TTY_MODE,
TelecomManager.TTY_MODE_OFF) != TelecomManager.TTY_MODE_OFF);
}
+
+ /**
+ * For outgoing dialed calls, potentially send a ConnectionEvent if the user is on WFC and is
+ * dialing an international number.
+ * @param telephonyConnection The connection.
+ */
+ private void maybeSendInternationalCallEvent(TelephonyConnection telephonyConnection) {
+ if (telephonyConnection == null || telephonyConnection.getPhone() == null ||
+ telephonyConnection.getPhone().getDefaultPhone() == null) {
+ return;
+ }
+ Phone phone = telephonyConnection.getPhone().getDefaultPhone();
+ if (phone instanceof GsmCdmaPhone) {
+ GsmCdmaPhone gsmCdmaPhone = (GsmCdmaPhone) phone;
+ if (telephonyConnection.isOutgoingCall() &&
+ gsmCdmaPhone.isNotificationOfWfcCallRequired(
+ telephonyConnection.getOriginalConnection().getOrigDialString())) {
+ // Send connection event to InCall UI to inform the user of the fact they
+ // are potentially placing an international call on WFC.
+ Log.i(this, "placeOutgoingConnection - sending international call on WFC " +
+ "confirmation event");
+ telephonyConnection.sendConnectionEvent(
+ TelephonyManager.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC, null);
+ }
+ }
+ }
}
diff --git a/src/com/android/services/telephony/TelephonyConnectionServiceProxy.java b/src/com/android/services/telephony/TelephonyConnectionServiceProxy.java
new file mode 100644
index 0000000..1ced34a
--- /dev/null
+++ b/src/com/android/services/telephony/TelephonyConnectionServiceProxy.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.services.telephony;
+
+import android.telecom.Conference;
+import android.telecom.Connection;
+import android.telecom.PhoneAccountHandle;
+
+import java.util.Collection;
+
+/**
+ * TelephonyConnectionService Interface for testing purpose
+ */
+
+public interface TelephonyConnectionServiceProxy {
+ Collection<Connection> getAllConnections();
+ void addConference(TelephonyConference mTelephonyConference);
+ void addConference(ImsConference mImsConference);
+ void removeConnection(Connection connection);
+ void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
+ Connection connection);
+ void addExistingConnection(PhoneAccountHandle phoneAccountHandle,
+ Connection connection, Conference conference);
+ void addConnectionToConferenceController(TelephonyConnection connection);
+}
diff --git a/src/org/apache/commons/io/IOUtils.java b/src/org/apache/commons/io/IOUtils.java
deleted file mode 100644
index b414507..0000000
--- a/src/org/apache/commons/io/IOUtils.java
+++ /dev/null
@@ -1,1202 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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 org.apache.commons.io;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.CharArrayWriter;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.Reader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * General IO stream manipulation utilities.
- * <p>
- * This class provides static utility methods for input/output operations.
- * <ul>
- * <li>closeQuietly - these methods close a stream ignoring nulls and exceptions
- * <li>toXxx/read - these methods read data from a stream
- * <li>write - these methods write data to a stream
- * <li>copy - these methods copy all the data from one stream to another
- * <li>contentEquals - these methods compare the content of two streams
- * </ul>
- * <p>
- * The byte-to-char methods and char-to-byte methods involve a conversion step.
- * Two methods are provided in each case, one that uses the platform default
- * encoding and the other which allows you to specify an encoding. You are
- * encouraged to always specify an encoding because relying on the platform
- * default can lead to unexpected results, for example when moving from
- * development to production.
- * <p>
- * All the methods in this class that read a stream are buffered internally.
- * This means that there is no cause to use a <code>BufferedInputStream</code>
- * or <code>BufferedReader</code>. The default buffer size of 4K has been shown
- * to be efficient in tests.
- * <p>
- * Wherever possible, the methods in this class do <em>not</em> flush or close
- * the stream. This is to avoid making non-portable assumptions about the
- * streams' origin and further use. Thus the caller is still responsible for
- * closing streams after use.
- * <p>
- * Origin of code: Excalibur.
- *
- * @author Peter Donald
- * @author Jeff Turner
- * @author Matthew Hawthorne
- * @author Stephen Colebourne
- * @author Gareth Davis
- * @author Ian Springer
- * @author Niall Pemberton
- * @author Sandy McArthur
- * @version $Id: IOUtils.java 481854 2006-12-03 18:30:07Z scolebourne $
- */
-public class IOUtils {
- // NOTE: This class is focussed on InputStream, OutputStream, Reader and
- // Writer. Each method should take at least one of these as a parameter,
- // or return one of them.
-
- /**
- * The Unix directory separator character.
- */
- public static final char DIR_SEPARATOR_UNIX = '/';
- /**
- * The Windows directory separator character.
- */
- public static final char DIR_SEPARATOR_WINDOWS = '\\';
- /**
- * The system directory separator character.
- */
- public static final char DIR_SEPARATOR = File.separatorChar;
- /**
- * The Unix line separator string.
- */
- public static final String LINE_SEPARATOR_UNIX = "\n";
- /**
- * The Windows line separator string.
- */
- public static final String LINE_SEPARATOR_WINDOWS = "\r\n";
- /**
- * The system line separator string.
- */
- public static final String LINE_SEPARATOR;
- static {
- // avoid security issues
- StringWriter buf = new StringWriter(4);
- PrintWriter out = new PrintWriter(buf);
- out.println();
- LINE_SEPARATOR = buf.toString();
- }
-
- /**
- * The default buffer size to use.
- */
- private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
-
- /**
- * Instances should NOT be constructed in standard programming.
- */
- public IOUtils() {
- super();
- }
-
- //-----------------------------------------------------------------------
- /**
- * Unconditionally close an <code>Reader</code>.
- * <p>
- * Equivalent to {@link Reader#close()}, except any exceptions will be ignored.
- * This is typically used in finally blocks.
- *
- * @param input the Reader to close, may be null or already closed
- */
- public static void closeQuietly(Reader input) {
- try {
- if (input != null) {
- input.close();
- }
- } catch (IOException ioe) {
- // ignore
- }
- }
-
- /**
- * Unconditionally close a <code>Writer</code>.
- * <p>
- * Equivalent to {@link Writer#close()}, except any exceptions will be ignored.
- * This is typically used in finally blocks.
- *
- * @param output the Writer to close, may be null or already closed
- */
- public static void closeQuietly(Writer output) {
- try {
- if (output != null) {
- output.close();
- }
- } catch (IOException ioe) {
- // ignore
- }
- }
-
- /**
- * Unconditionally close an <code>InputStream</code>.
- * <p>
- * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
- * This is typically used in finally blocks.
- *
- * @param input the InputStream to close, may be null or already closed
- */
- public static void closeQuietly(InputStream input) {
- try {
- if (input != null) {
- input.close();
- }
- } catch (IOException ioe) {
- // ignore
- }
- }
-
- /**
- * Unconditionally close an <code>OutputStream</code>.
- * <p>
- * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored.
- * This is typically used in finally blocks.
- *
- * @param output the OutputStream to close, may be null or already closed
- */
- public static void closeQuietly(OutputStream output) {
- try {
- if (output != null) {
- output.close();
- }
- } catch (IOException ioe) {
- // ignore
- }
- }
-
- // read toByteArray
- //-----------------------------------------------------------------------
- /**
- * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- *
- * @param input the <code>InputStream</code> to read from
- * @return the requested byte array
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- */
- public static byte[] toByteArray(InputStream input) throws IOException {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- copy(input, output);
- return output.toByteArray();
- }
-
- /**
- * Get the contents of a <code>Reader</code> as a <code>byte[]</code>
- * using the default character encoding of the platform.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- *
- * @param input the <code>Reader</code> to read from
- * @return the requested byte array
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- */
- public static byte[] toByteArray(Reader input) throws IOException {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- copy(input, output);
- return output.toByteArray();
- }
-
- /**
- * Get the contents of a <code>Reader</code> as a <code>byte[]</code>
- * using the specified character encoding.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- *
- * @param input the <code>Reader</code> to read from
- * @param encoding the encoding to use, null means platform default
- * @return the requested byte array
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static byte[] toByteArray(Reader input, String encoding)
- throws IOException {
- ByteArrayOutputStream output = new ByteArrayOutputStream();
- copy(input, output, encoding);
- return output.toByteArray();
- }
-
- /**
- * Get the contents of a <code>String</code> as a <code>byte[]</code>
- * using the default character encoding of the platform.
- * <p>
- * This is the same as {@link String#getBytes()}.
- *
- * @param input the <code>String</code> to convert
- * @return the requested byte array
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs (never occurs)
- * @deprecated Use {@link String#getBytes()}
- */
- @Deprecated
- public static byte[] toByteArray(String input) throws IOException {
- return input.getBytes();
- }
-
- // read char[]
- //-----------------------------------------------------------------------
- /**
- * Get the contents of an <code>InputStream</code> as a character array
- * using the default character encoding of the platform.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- *
- * @param is the <code>InputStream</code> to read from
- * @return the requested character array
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static char[] toCharArray(InputStream is) throws IOException {
- CharArrayWriter output = new CharArrayWriter();
- copy(is, output);
- return output.toCharArray();
- }
-
- /**
- * Get the contents of an <code>InputStream</code> as a character array
- * using the specified character encoding.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- *
- * @param is the <code>InputStream</code> to read from
- * @param encoding the encoding to use, null means platform default
- * @return the requested character array
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static char[] toCharArray(InputStream is, String encoding)
- throws IOException {
- CharArrayWriter output = new CharArrayWriter();
- copy(is, output, encoding);
- return output.toCharArray();
- }
-
- /**
- * Get the contents of a <code>Reader</code> as a character array.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- *
- * @param input the <code>Reader</code> to read from
- * @return the requested character array
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static char[] toCharArray(Reader input) throws IOException {
- CharArrayWriter sw = new CharArrayWriter();
- copy(input, sw);
- return sw.toCharArray();
- }
-
- // read toString
- //-----------------------------------------------------------------------
- /**
- * Get the contents of an <code>InputStream</code> as a String
- * using the default character encoding of the platform.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- *
- * @param input the <code>InputStream</code> to read from
- * @return the requested String
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- */
- public static String toString(InputStream input) throws IOException {
- StringWriter sw = new StringWriter();
- copy(input, sw);
- return sw.toString();
- }
-
- /**
- * Get the contents of an <code>InputStream</code> as a String
- * using the specified character encoding.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- *
- * @param input the <code>InputStream</code> to read from
- * @param encoding the encoding to use, null means platform default
- * @return the requested String
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- */
- public static String toString(InputStream input, String encoding)
- throws IOException {
- StringWriter sw = new StringWriter();
- copy(input, sw, encoding);
- return sw.toString();
- }
-
- /**
- * Get the contents of a <code>Reader</code> as a String.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- *
- * @param input the <code>Reader</code> to read from
- * @return the requested String
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- */
- public static String toString(Reader input) throws IOException {
- StringWriter sw = new StringWriter();
- copy(input, sw);
- return sw.toString();
- }
-
- /**
- * Get the contents of a <code>byte[]</code> as a String
- * using the default character encoding of the platform.
- *
- * @param input the byte array to read from
- * @return the requested String
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs (never occurs)
- * @deprecated Use {@link String#String(byte[])}
- */
- @Deprecated
- public static String toString(byte[] input) throws IOException {
- return new String(input);
- }
-
- /**
- * Get the contents of a <code>byte[]</code> as a String
- * using the specified character encoding.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- *
- * @param input the byte array to read from
- * @param encoding the encoding to use, null means platform default
- * @return the requested String
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs (never occurs)
- * @deprecated Use {@link String#String(byte[],String)}
- */
- @Deprecated
- public static String toString(byte[] input, String encoding)
- throws IOException {
- if (encoding == null) {
- return new String(input);
- } else {
- return new String(input, encoding);
- }
- }
-
- // readLines
- //-----------------------------------------------------------------------
- /**
- * Get the contents of an <code>InputStream</code> as a list of Strings,
- * one entry per line, using the default character encoding of the platform.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- *
- * @param input the <code>InputStream</code> to read from, not null
- * @return the list of Strings, never null
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static List<String> readLines(InputStream input) throws IOException {
- InputStreamReader reader = new InputStreamReader(input);
- return readLines(reader);
- }
-
- /**
- * Get the contents of an <code>InputStream</code> as a list of Strings,
- * one entry per line, using the specified character encoding.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- *
- * @param input the <code>InputStream</code> to read from, not null
- * @param encoding the encoding to use, null means platform default
- * @return the list of Strings, never null
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static List<String> readLines(InputStream input, String encoding) throws IOException {
- if (encoding == null) {
- return readLines(input);
- } else {
- InputStreamReader reader = new InputStreamReader(input, encoding);
- return readLines(reader);
- }
- }
-
- /**
- * Get the contents of a <code>Reader</code> as a list of Strings,
- * one entry per line.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- *
- * @param input the <code>Reader</code> to read from, not null
- * @return the list of Strings, never null
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static List<String> readLines(Reader input) throws IOException {
- BufferedReader reader = new BufferedReader(input);
- List<String> list = new ArrayList<String>();
- String line = reader.readLine();
- while (line != null) {
- list.add(line);
- line = reader.readLine();
- }
- return list;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Convert the specified string to an input stream, encoded as bytes
- * using the default character encoding of the platform.
- *
- * @param input the string to convert
- * @return an input stream
- * @since Commons IO 1.1
- */
- public static InputStream toInputStream(String input) {
- byte[] bytes = input.getBytes();
- return new ByteArrayInputStream(bytes);
- }
-
- /**
- * Convert the specified string to an input stream, encoded as bytes
- * using the specified character encoding.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- *
- * @param input the string to convert
- * @param encoding the encoding to use, null means platform default
- * @throws IOException if the encoding is invalid
- * @return an input stream
- * @since Commons IO 1.1
- */
- public static InputStream toInputStream(String input, String encoding) throws IOException {
- byte[] bytes = encoding != null ? input.getBytes(encoding) : input.getBytes();
- return new ByteArrayInputStream(bytes);
- }
-
- // write byte[]
- //-----------------------------------------------------------------------
- /**
- * Writes bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
- *
- * @param data the byte array to write, do not modify during output,
- * null ignored
- * @param output the <code>OutputStream</code> to write to
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(byte[] data, OutputStream output)
- throws IOException {
- if (data != null) {
- output.write(data);
- }
- }
-
- /**
- * Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code>
- * using the default character encoding of the platform.
- * <p>
- * This method uses {@link String#String(byte[])}.
- *
- * @param data the byte array to write, do not modify during output,
- * null ignored
- * @param output the <code>Writer</code> to write to
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(byte[] data, Writer output) throws IOException {
- if (data != null) {
- output.write(new String(data));
- }
- }
-
- /**
- * Writes bytes from a <code>byte[]</code> to chars on a <code>Writer</code>
- * using the specified character encoding.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- * <p>
- * This method uses {@link String#String(byte[], String)}.
- *
- * @param data the byte array to write, do not modify during output,
- * null ignored
- * @param output the <code>Writer</code> to write to
- * @param encoding the encoding to use, null means platform default
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(byte[] data, Writer output, String encoding)
- throws IOException {
- if (data != null) {
- if (encoding == null) {
- write(data, output);
- } else {
- output.write(new String(data, encoding));
- }
- }
- }
-
- // write char[]
- //-----------------------------------------------------------------------
- /**
- * Writes chars from a <code>char[]</code> to a <code>Writer</code>
- * using the default character encoding of the platform.
- *
- * @param data the char array to write, do not modify during output,
- * null ignored
- * @param output the <code>Writer</code> to write to
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(char[] data, Writer output) throws IOException {
- if (data != null) {
- output.write(data);
- }
- }
-
- /**
- * Writes chars from a <code>char[]</code> to bytes on an
- * <code>OutputStream</code>.
- * <p>
- * This method uses {@link String#String(char[])} and
- * {@link String#getBytes()}.
- *
- * @param data the char array to write, do not modify during output,
- * null ignored
- * @param output the <code>OutputStream</code> to write to
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(char[] data, OutputStream output)
- throws IOException {
- if (data != null) {
- output.write(new String(data).getBytes());
- }
- }
-
- /**
- * Writes chars from a <code>char[]</code> to bytes on an
- * <code>OutputStream</code> using the specified character encoding.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- * <p>
- * This method uses {@link String#String(char[])} and
- * {@link String#getBytes(String)}.
- *
- * @param data the char array to write, do not modify during output,
- * null ignored
- * @param output the <code>OutputStream</code> to write to
- * @param encoding the encoding to use, null means platform default
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(char[] data, OutputStream output, String encoding)
- throws IOException {
- if (data != null) {
- if (encoding == null) {
- write(data, output);
- } else {
- output.write(new String(data).getBytes(encoding));
- }
- }
- }
-
- // write String
- //-----------------------------------------------------------------------
- /**
- * Writes chars from a <code>String</code> to a <code>Writer</code>.
- *
- * @param data the <code>String</code> to write, null ignored
- * @param output the <code>Writer</code> to write to
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(String data, Writer output) throws IOException {
- if (data != null) {
- output.write(data);
- }
- }
-
- /**
- * Writes chars from a <code>String</code> to bytes on an
- * <code>OutputStream</code> using the default character encoding of the
- * platform.
- * <p>
- * This method uses {@link String#getBytes()}.
- *
- * @param data the <code>String</code> to write, null ignored
- * @param output the <code>OutputStream</code> to write to
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(String data, OutputStream output)
- throws IOException {
- if (data != null) {
- output.write(data.getBytes());
- }
- }
-
- /**
- * Writes chars from a <code>String</code> to bytes on an
- * <code>OutputStream</code> using the specified character encoding.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- * <p>
- * This method uses {@link String#getBytes(String)}.
- *
- * @param data the <code>String</code> to write, null ignored
- * @param output the <code>OutputStream</code> to write to
- * @param encoding the encoding to use, null means platform default
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(String data, OutputStream output, String encoding)
- throws IOException {
- if (data != null) {
- if (encoding == null) {
- write(data, output);
- } else {
- output.write(data.getBytes(encoding));
- }
- }
- }
-
- // write StringBuffer
- //-----------------------------------------------------------------------
- /**
- * Writes chars from a <code>StringBuffer</code> to a <code>Writer</code>.
- *
- * @param data the <code>StringBuffer</code> to write, null ignored
- * @param output the <code>Writer</code> to write to
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(StringBuffer data, Writer output)
- throws IOException {
- if (data != null) {
- output.write(data.toString());
- }
- }
-
- /**
- * Writes chars from a <code>StringBuffer</code> to bytes on an
- * <code>OutputStream</code> using the default character encoding of the
- * platform.
- * <p>
- * This method uses {@link String#getBytes()}.
- *
- * @param data the <code>StringBuffer</code> to write, null ignored
- * @param output the <code>OutputStream</code> to write to
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(StringBuffer data, OutputStream output)
- throws IOException {
- if (data != null) {
- output.write(data.toString().getBytes());
- }
- }
-
- /**
- * Writes chars from a <code>StringBuffer</code> to bytes on an
- * <code>OutputStream</code> using the specified character encoding.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- * <p>
- * This method uses {@link String#getBytes(String)}.
- *
- * @param data the <code>StringBuffer</code> to write, null ignored
- * @param output the <code>OutputStream</code> to write to
- * @param encoding the encoding to use, null means platform default
- * @throws NullPointerException if output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void write(StringBuffer data, OutputStream output,
- String encoding) throws IOException {
- if (data != null) {
- if (encoding == null) {
- write(data, output);
- } else {
- output.write(data.toString().getBytes(encoding));
- }
- }
- }
-
- // writeLines
- //-----------------------------------------------------------------------
- /**
- * Writes the <code>toString()</code> value of each item in a collection to
- * an <code>OutputStream</code> line by line, using the default character
- * encoding of the platform and the specified line ending.
- *
- * @param lines the lines to write, null entries produce blank lines
- * @param lineEnding the line separator to use, null is system default
- * @param output the <code>OutputStream</code> to write to, not null, not closed
- * @throws NullPointerException if the output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void writeLines(Collection<Object> lines, String lineEnding,
- OutputStream output) throws IOException {
- if (lines == null) {
- return;
- }
- if (lineEnding == null) {
- lineEnding = LINE_SEPARATOR;
- }
- for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) {
- Object line = it.next();
- if (line != null) {
- output.write(line.toString().getBytes());
- }
- output.write(lineEnding.getBytes());
- }
- }
-
- /**
- * Writes the <code>toString()</code> value of each item in a collection to
- * an <code>OutputStream</code> line by line, using the specified character
- * encoding and the specified line ending.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- *
- * @param lines the lines to write, null entries produce blank lines
- * @param lineEnding the line separator to use, null is system default
- * @param output the <code>OutputStream</code> to write to, not null, not closed
- * @param encoding the encoding to use, null means platform default
- * @throws NullPointerException if the output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void writeLines(Collection<Object> lines, String lineEnding,
- OutputStream output, String encoding) throws IOException {
- if (encoding == null) {
- writeLines(lines, lineEnding, output);
- } else {
- if (lines == null) {
- return;
- }
- if (lineEnding == null) {
- lineEnding = LINE_SEPARATOR;
- }
- for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) {
- Object line = it.next();
- if (line != null) {
- output.write(line.toString().getBytes(encoding));
- }
- output.write(lineEnding.getBytes(encoding));
- }
- }
- }
-
- /**
- * Writes the <code>toString()</code> value of each item in a collection to
- * a <code>Writer</code> line by line, using the specified line ending.
- *
- * @param lines the lines to write, null entries produce blank lines
- * @param lineEnding the line separator to use, null is system default
- * @param writer the <code>Writer</code> to write to, not null, not closed
- * @throws NullPointerException if the input is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void writeLines(Collection<Object> lines, String lineEnding,
- Writer writer) throws IOException {
- if (lines == null) {
- return;
- }
- if (lineEnding == null) {
- lineEnding = LINE_SEPARATOR;
- }
- for (Iterator<Object> it = lines.iterator(); it.hasNext(); ) {
- Object line = it.next();
- if (line != null) {
- writer.write(line.toString());
- }
- writer.write(lineEnding);
- }
- }
-
- // copy from InputStream
- //-----------------------------------------------------------------------
- /**
- * Copy bytes from an <code>InputStream</code> to an
- * <code>OutputStream</code>.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- * <p>
- * Large streams (over 2GB) will return a bytes copied value of
- * <code>-1</code> after the copy has completed since the correct
- * number of bytes cannot be returned as an int. For large streams
- * use the <code>copyLarge(InputStream, OutputStream)</code> method.
- *
- * @param input the <code>InputStream</code> to read from
- * @param output the <code>OutputStream</code> to write to
- * @return the number of bytes copied
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @throws ArithmeticException if the byte count is too large
- * @since Commons IO 1.1
- */
- public static int copy(InputStream input, OutputStream output) throws IOException {
- long count = copyLarge(input, output);
- if (count > Integer.MAX_VALUE) {
- return -1;
- }
- return (int) count;
- }
-
- /**
- * Copy bytes from a large (over 2GB) <code>InputStream</code> to an
- * <code>OutputStream</code>.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- *
- * @param input the <code>InputStream</code> to read from
- * @param output the <code>OutputStream</code> to write to
- * @return the number of bytes copied
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.3
- */
- public static long copyLarge(InputStream input, OutputStream output)
- throws IOException {
- byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
- long count = 0;
- int n = 0;
- while (-1 != (n = input.read(buffer))) {
- output.write(buffer, 0, n);
- count += n;
- }
- return count;
- }
-
- /**
- * Copy bytes from an <code>InputStream</code> to chars on a
- * <code>Writer</code> using the default character encoding of the platform.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- * <p>
- * This method uses {@link InputStreamReader}.
- *
- * @param input the <code>InputStream</code> to read from
- * @param output the <code>Writer</code> to write to
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void copy(InputStream input, Writer output)
- throws IOException {
- InputStreamReader in = new InputStreamReader(input);
- copy(in, output);
- }
-
- /**
- * Copy bytes from an <code>InputStream</code> to chars on a
- * <code>Writer</code> using the specified character encoding.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedInputStream</code>.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- * <p>
- * This method uses {@link InputStreamReader}.
- *
- * @param input the <code>InputStream</code> to read from
- * @param output the <code>Writer</code> to write to
- * @param encoding the encoding to use, null means platform default
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void copy(InputStream input, Writer output, String encoding)
- throws IOException {
- if (encoding == null) {
- copy(input, output);
- } else {
- InputStreamReader in = new InputStreamReader(input, encoding);
- copy(in, output);
- }
- }
-
- // copy from Reader
- //-----------------------------------------------------------------------
- /**
- * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- * <p>
- * Large streams (over 2GB) will return a chars copied value of
- * <code>-1</code> after the copy has completed since the correct
- * number of chars cannot be returned as an int. For large streams
- * use the <code>copyLarge(Reader, Writer)</code> method.
- *
- * @param input the <code>Reader</code> to read from
- * @param output the <code>Writer</code> to write to
- * @return the number of characters copied
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @throws ArithmeticException if the character count is too large
- * @since Commons IO 1.1
- */
- public static int copy(Reader input, Writer output) throws IOException {
- long count = copyLarge(input, output);
- if (count > Integer.MAX_VALUE) {
- return -1;
- }
- return (int) count;
- }
-
- /**
- * Copy chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- *
- * @param input the <code>Reader</code> to read from
- * @param output the <code>Writer</code> to write to
- * @return the number of characters copied
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.3
- */
- public static long copyLarge(Reader input, Writer output) throws IOException {
- char[] buffer = new char[DEFAULT_BUFFER_SIZE];
- long count = 0;
- int n = 0;
- while (-1 != (n = input.read(buffer))) {
- output.write(buffer, 0, n);
- count += n;
- }
- return count;
- }
-
- /**
- * Copy chars from a <code>Reader</code> to bytes on an
- * <code>OutputStream</code> using the default character encoding of the
- * platform, and calling flush.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- * <p>
- * Due to the implementation of OutputStreamWriter, this method performs a
- * flush.
- * <p>
- * This method uses {@link OutputStreamWriter}.
- *
- * @param input the <code>Reader</code> to read from
- * @param output the <code>OutputStream</code> to write to
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void copy(Reader input, OutputStream output)
- throws IOException {
- OutputStreamWriter out = new OutputStreamWriter(output);
- copy(input, out);
- // XXX Unless anyone is planning on rewriting OutputStreamWriter, we
- // have to flush here.
- out.flush();
- }
-
- /**
- * Copy chars from a <code>Reader</code> to bytes on an
- * <code>OutputStream</code> using the specified character encoding, and
- * calling flush.
- * <p>
- * This method buffers the input internally, so there is no need to use a
- * <code>BufferedReader</code>.
- * <p>
- * Character encoding names can be found at
- * <a href="http://www.iana.org/assignments/character-sets">IANA</a>.
- * <p>
- * Due to the implementation of OutputStreamWriter, this method performs a
- * flush.
- * <p>
- * This method uses {@link OutputStreamWriter}.
- *
- * @param input the <code>Reader</code> to read from
- * @param output the <code>OutputStream</code> to write to
- * @param encoding the encoding to use, null means platform default
- * @throws NullPointerException if the input or output is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static void copy(Reader input, OutputStream output, String encoding)
- throws IOException {
- if (encoding == null) {
- copy(input, output);
- } else {
- OutputStreamWriter out = new OutputStreamWriter(output, encoding);
- copy(input, out);
- // XXX Unless anyone is planning on rewriting OutputStreamWriter,
- // we have to flush here.
- out.flush();
- }
- }
-
- // content equals
- //-----------------------------------------------------------------------
- /**
- * Compare the contents of two Streams to determine if they are equal or
- * not.
- * <p>
- * This method buffers the input internally using
- * <code>BufferedInputStream</code> if they are not already buffered.
- *
- * @param input1 the first stream
- * @param input2 the second stream
- * @return true if the content of the streams are equal or they both don't
- * exist, false otherwise
- * @throws NullPointerException if either input is null
- * @throws IOException if an I/O error occurs
- */
- public static boolean contentEquals(InputStream input1, InputStream input2)
- throws IOException {
- if (!(input1 instanceof BufferedInputStream)) {
- input1 = new BufferedInputStream(input1);
- }
- if (!(input2 instanceof BufferedInputStream)) {
- input2 = new BufferedInputStream(input2);
- }
-
- int ch = input1.read();
- while (-1 != ch) {
- int ch2 = input2.read();
- if (ch != ch2) {
- return false;
- }
- ch = input1.read();
- }
-
- int ch2 = input2.read();
- return (ch2 == -1);
- }
-
- /**
- * Compare the contents of two Readers to determine if they are equal or
- * not.
- * <p>
- * This method buffers the input internally using
- * <code>BufferedReader</code> if they are not already buffered.
- *
- * @param input1 the first reader
- * @param input2 the second reader
- * @return true if the content of the readers are equal or they both don't
- * exist, false otherwise
- * @throws NullPointerException if either input is null
- * @throws IOException if an I/O error occurs
- * @since Commons IO 1.1
- */
- public static boolean contentEquals(Reader input1, Reader input2)
- throws IOException {
- if (!(input1 instanceof BufferedReader)) {
- input1 = new BufferedReader(input1);
- }
- if (!(input2 instanceof BufferedReader)) {
- input2 = new BufferedReader(input2);
- }
-
- int ch = input1.read();
- while (-1 != ch) {
- int ch2 = input2.read();
- if (ch != ch2) {
- return false;
- }
- ch = input1.read();
- }
-
- int ch2 = input2.read();
- return (ch2 == -1);
- }
-
-}
diff --git a/src/org/apache/james/mime4j/BodyDescriptor.java b/src/org/apache/james/mime4j/BodyDescriptor.java
deleted file mode 100644
index 867c43d..0000000
--- a/src/org/apache/james/mime4j/BodyDescriptor.java
+++ /dev/null
@@ -1,392 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Encapsulates the values of the MIME-specific header fields
- * (which starts with <code>Content-</code>).
- *
- *
- * @version $Id: BodyDescriptor.java,v 1.4 2005/02/11 10:08:37 ntherning Exp $
- */
-public class BodyDescriptor {
- private static Log log = LogFactory.getLog(BodyDescriptor.class);
-
- private String mimeType = "text/plain";
- private String boundary = null;
- private String charset = "us-ascii";
- private String transferEncoding = "7bit";
- private Map<String, String> parameters = new HashMap<String, String>();
- private boolean contentTypeSet = false;
- private boolean contentTransferEncSet = false;
-
- /**
- * Creates a new root <code>BodyDescriptor</code> instance.
- */
- public BodyDescriptor() {
- this(null);
- }
-
- /**
- * Creates a new <code>BodyDescriptor</code> instance.
- *
- * @param parent the descriptor of the parent or <code>null</code> if this
- * is the root descriptor.
- */
- public BodyDescriptor(BodyDescriptor parent) {
- if (parent != null && parent.isMimeType("multipart/digest")) {
- mimeType = "message/rfc822";
- } else {
- mimeType = "text/plain";
- }
- }
-
- /**
- * Should be called for each <code>Content-</code> header field of
- * a MIME message or part.
- *
- * @param name the field name.
- * @param value the field value.
- */
- public void addField(String name, String value) {
-
- name = name.trim().toLowerCase();
-
- if (name.equals("content-transfer-encoding") && !contentTransferEncSet) {
- contentTransferEncSet = true;
-
- value = value.trim().toLowerCase();
- if (value.length() > 0) {
- transferEncoding = value;
- }
-
- } else if (name.equals("content-type") && !contentTypeSet) {
- contentTypeSet = true;
-
- value = value.trim();
-
- /*
- * Unfold Content-Type value
- */
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < value.length(); i++) {
- char c = value.charAt(i);
- if (c == '\r' || c == '\n') {
- continue;
- }
- sb.append(c);
- }
-
- Map<String, String> params = getHeaderParams(sb.toString());
-
- String main = params.get("");
- if (main != null) {
- main = main.toLowerCase().trim();
- int index = main.indexOf('/');
- boolean valid = false;
- if (index != -1) {
- String type = main.substring(0, index).trim();
- String subtype = main.substring(index + 1).trim();
- if (type.length() > 0 && subtype.length() > 0) {
- main = type + "/" + subtype;
- valid = true;
- }
- }
-
- if (!valid) {
- main = null;
- }
- }
- String b = params.get("boundary");
-
- if (main != null
- && ((main.startsWith("multipart/") && b != null)
- || !main.startsWith("multipart/"))) {
-
- mimeType = main;
- }
-
- if (isMultipart()) {
- boundary = b;
- }
-
- String c = params.get("charset");
- if (c != null) {
- c = c.trim();
- if (c.length() > 0) {
- charset = c.toLowerCase();
- }
- }
-
- /*
- * Add all other parameters to parameters.
- */
- parameters.putAll(params);
- parameters.remove("");
- parameters.remove("boundary");
- parameters.remove("charset");
- }
- }
-
- private Map<String, String> getHeaderParams(String headerValue) {
- Map<String, String> result = new HashMap<String, String>();
-
- // split main value and parameters
- String main;
- String rest;
- if (headerValue.indexOf(";") == -1) {
- main = headerValue;
- rest = null;
- } else {
- main = headerValue.substring(0, headerValue.indexOf(";"));
- rest = headerValue.substring(main.length() + 1);
- }
-
- result.put("", main);
- if (rest != null) {
- char[] chars = rest.toCharArray();
- StringBuffer paramName = new StringBuffer();
- StringBuffer paramValue = new StringBuffer();
-
- final byte READY_FOR_NAME = 0;
- final byte IN_NAME = 1;
- final byte READY_FOR_VALUE = 2;
- final byte IN_VALUE = 3;
- final byte IN_QUOTED_VALUE = 4;
- final byte VALUE_DONE = 5;
- final byte ERROR = 99;
-
- byte state = READY_FOR_NAME;
- boolean escaped = false;
- for (int i = 0; i < chars.length; i++) {
- char c = chars[i];
-
- switch (state) {
- case ERROR:
- if (c == ';')
- state = READY_FOR_NAME;
- break;
-
- case READY_FOR_NAME:
- if (c == '=') {
- log.error("Expected header param name, got '='");
- state = ERROR;
- break;
- }
-
- paramName = new StringBuffer();
- paramValue = new StringBuffer();
-
- state = IN_NAME;
- // $FALL-THROUGH$
-
- case IN_NAME:
- if (c == '=') {
- if (paramName.length() == 0)
- state = ERROR;
- else
- state = READY_FOR_VALUE;
- break;
- }
-
- // not '='... just add to name
- paramName.append(c);
- break;
-
- case READY_FOR_VALUE:
- boolean fallThrough = false;
- switch (c) {
- case ' ':
- case '\t':
- break; // ignore spaces, especially before '"'
-
- case '"':
- state = IN_QUOTED_VALUE;
- break;
-
- default:
- state = IN_VALUE;
- fallThrough = true;
- break;
- }
- if (!fallThrough)
- break;
-
- // $FALL-THROUGH$
-
- case IN_VALUE:
- fallThrough = false;
- switch (c) {
- case ';':
- case ' ':
- case '\t':
- result.put(
- paramName.toString().trim().toLowerCase(),
- paramValue.toString().trim());
- state = VALUE_DONE;
- fallThrough = true;
- break;
- default:
- paramValue.append(c);
- break;
- }
- if (!fallThrough)
- break;
-
- // $FALL-THROUGH$
-
- case VALUE_DONE:
- switch (c) {
- case ';':
- state = READY_FOR_NAME;
- break;
-
- case ' ':
- case '\t':
- break;
-
- default:
- state = ERROR;
- break;
- }
- break;
-
- case IN_QUOTED_VALUE:
- switch (c) {
- case '"':
- if (!escaped) {
- // don't trim quoted strings; the spaces could be intentional.
- result.put(
- paramName.toString().trim().toLowerCase(),
- paramValue.toString());
- state = VALUE_DONE;
- } else {
- escaped = false;
- paramValue.append(c);
- }
- break;
-
- case '\\':
- if (escaped) {
- paramValue.append('\\');
- }
- escaped = !escaped;
- break;
-
- default:
- if (escaped) {
- paramValue.append('\\');
- }
- escaped = false;
- paramValue.append(c);
- break;
- }
- break;
-
- }
- }
-
- // done looping. check if anything is left over.
- if (state == IN_VALUE) {
- result.put(
- paramName.toString().trim().toLowerCase(),
- paramValue.toString().trim());
- }
- }
-
- return result;
- }
-
-
- public boolean isMimeType(String mimeType) {
- return this.mimeType.equals(mimeType.toLowerCase());
- }
-
- /**
- * Return true if the BodyDescriptor belongs to a message
- */
- public boolean isMessage() {
- return mimeType.equals("message/rfc822");
- }
-
- /**
- * Return true if the BodyDescripotro belongs to a multipart
- */
- public boolean isMultipart() {
- return mimeType.startsWith("multipart/");
- }
-
- /**
- * Return the MimeType
- */
- public String getMimeType() {
- return mimeType;
- }
-
- /**
- * Return the boundary
- */
- public String getBoundary() {
- return boundary;
- }
-
- /**
- * Return the charset
- */
- public String getCharset() {
- return charset;
- }
-
- /**
- * Return all parameters for the BodyDescriptor
- */
- public Map<String, String> getParameters() {
- return parameters;
- }
-
- /**
- * Return the TransferEncoding
- */
- public String getTransferEncoding() {
- return transferEncoding;
- }
-
- /**
- * Return true if it's base64 encoded
- */
- public boolean isBase64Encoded() {
- return "base64".equals(transferEncoding);
- }
-
- /**
- * Return true if it's quoted-printable
- */
- public boolean isQuotedPrintableEncoded() {
- return "quoted-printable".equals(transferEncoding);
- }
-
- @Override
- public String toString() {
- return mimeType;
- }
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/CloseShieldInputStream.java b/src/org/apache/james/mime4j/CloseShieldInputStream.java
deleted file mode 100644
index d9f3b07..0000000
--- a/src/org/apache/james/mime4j/CloseShieldInputStream.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j;
-
-import java.io.InputStream;
-import java.io.IOException;
-
-/**
- * InputStream that shields its underlying input stream from
- * being closed.
- *
- *
- * @version $Id: CloseShieldInputStream.java,v 1.2 2004/10/02 12:41:10 ntherning Exp $
- */
-public class CloseShieldInputStream extends InputStream {
-
- /**
- * Underlying InputStream
- */
- private InputStream is;
-
- public CloseShieldInputStream(InputStream is) {
- this.is = is;
- }
-
- public InputStream getUnderlyingStream() {
- return is;
- }
-
- /**
- * @see java.io.InputStream#read()
- */
- public int read() throws IOException {
- checkIfClosed();
- return is.read();
- }
-
- /**
- * @see java.io.InputStream#available()
- */
- public int available() throws IOException {
- checkIfClosed();
- return is.available();
- }
-
-
- /**
- * Set the underlying InputStream to null
- */
- public void close() throws IOException {
- is = null;
- }
-
- /**
- * @see java.io.FilterInputStream#reset()
- */
- public synchronized void reset() throws IOException {
- checkIfClosed();
- is.reset();
- }
-
- /**
- * @see java.io.FilterInputStream#markSupported()
- */
- public boolean markSupported() {
- if (is == null)
- return false;
- return is.markSupported();
- }
-
- /**
- * @see java.io.FilterInputStream#mark(int)
- */
- public synchronized void mark(int readlimit) {
- if (is != null)
- is.mark(readlimit);
- }
-
- /**
- * @see java.io.FilterInputStream#skip(long)
- */
- public long skip(long n) throws IOException {
- checkIfClosed();
- return is.skip(n);
- }
-
- /**
- * @see java.io.FilterInputStream#read(byte[])
- */
- public int read(byte b[]) throws IOException {
- checkIfClosed();
- return is.read(b);
- }
-
- /**
- * @see java.io.FilterInputStream#read(byte[], int, int)
- */
- public int read(byte b[], int off, int len) throws IOException {
- checkIfClosed();
- return is.read(b, off, len);
- }
-
- /**
- * Check if the underlying InputStream is null. If so throw an Exception
- *
- * @throws IOException if the underlying InputStream is null
- */
- private void checkIfClosed() throws IOException {
- if (is == null)
- throw new IOException("Stream is closed");
- }
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/ContentHandler.java b/src/org/apache/james/mime4j/ContentHandler.java
deleted file mode 100644
index b437e73..0000000
--- a/src/org/apache/james/mime4j/ContentHandler.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * <p>
- * Receives notifications of the content of a plain RFC822 or MIME message.
- * Implement this interface and register an instance of that implementation
- * with a <code>MimeStreamParser</code> instance using its
- * {@link org.apache.james.mime4j.MimeStreamParser#setContentHandler(ContentHandler)}
- * method. The parser uses the <code>ContentHandler</code> instance to report
- * basic message-related events like the start and end of the body of a
- * part in a multipart MIME entity.
- * </p>
- * <p>
- * Events will be generated in the order the corresponding elements occur in
- * the message stream parsed by the parser. E.g.:
- * <pre>
- * startMessage()
- * startHeader()
- * field(...)
- * field(...)
- * ...
- * endHeader()
- * startMultipart()
- * preamble(...)
- * startBodyPart()
- * startHeader()
- * field(...)
- * field(...)
- * ...
- * endHeader()
- * body()
- * endBodyPart()
- * startBodyPart()
- * startHeader()
- * field(...)
- * field(...)
- * ...
- * endHeader()
- * body()
- * endBodyPart()
- * epilogue(...)
- * endMultipart()
- * endMessage()
- * </pre>
- * The above shows an example of a MIME message consisting of a multipart
- * body containing two body parts.
- * </p>
- * <p>
- * See MIME RFCs 2045-2049 for more information on the structure of MIME
- * messages and RFC 822 and 2822 for the general structure of Internet mail
- * messages.
- * </p>
- *
- *
- * @version $Id: ContentHandler.java,v 1.3 2004/10/02 12:41:10 ntherning Exp $
- */
-public interface ContentHandler {
- /**
- * Called when a new message starts (a top level message or an embedded
- * rfc822 message).
- */
- void startMessage();
-
- /**
- * Called when a message ends.
- */
- void endMessage();
-
- /**
- * Called when a new body part starts inside a
- * <code>multipart/*</code> entity.
- */
- void startBodyPart();
-
- /**
- * Called when a body part ends.
- */
- void endBodyPart();
-
- /**
- * Called when a header (of a message or body part) is about to be parsed.
- */
- void startHeader();
-
- /**
- * Called for each field of a header.
- *
- * @param fieldData the raw contents of the field
- * (<code>Field-Name: field value</code>). The value will not be
- * unfolded.
- */
- void field(String fieldData);
-
- /**
- * Called when there are no more header fields in a message or body part.
- */
- void endHeader();
-
- /**
- * Called for the preamble (whatever comes before the first body part)
- * of a <code>multipart/*</code> entity.
- *
- * @param is used to get the contents of the preamble.
- * @throws IOException should be thrown on I/O errors.
- */
- void preamble(InputStream is) throws IOException;
-
- /**
- * Called for the epilogue (whatever comes after the final body part)
- * of a <code>multipart/*</code> entity.
- *
- * @param is used to get the contents of the epilogue.
- * @throws IOException should be thrown on I/O errors.
- */
- void epilogue(InputStream is) throws IOException;
-
- /**
- * Called when the body of a multipart entity is about to be parsed.
- *
- * @param bd encapsulates the values (either read from the
- * message stream or, if not present, determined implictly
- * as described in the
- * MIME rfc:s) of the <code>Content-Type</code> and
- * <code>Content-Transfer-Encoding</code> header fields.
- */
- void startMultipart(BodyDescriptor bd);
-
- /**
- * Called when the body of an entity has been parsed.
- */
- void endMultipart();
-
- /**
- * Called when the body of a discrete (non-multipart) entity is about to
- * be parsed.
- *
- * @param bd see {@link #startMultipart(BodyDescriptor)}
- * @param is the contents of the body. NOTE: this is the raw body contents
- * - it will not be decoded if encoded. The <code>bd</code>
- * parameter should be used to determine how the stream data
- * should be decoded.
- * @throws IOException should be thrown on I/O errors.
- */
- void body(BodyDescriptor bd, InputStream is) throws IOException;
-
- /**
- * Called when a new entity (message or body part) starts and the
- * parser is in <code>raw</code> mode.
- *
- * @param is the raw contents of the entity.
- * @throws IOException should be thrown on I/O errors.
- * @see MimeStreamParser#setRaw(boolean)
- */
- void raw(InputStream is) throws IOException;
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/EOLConvertingInputStream.java b/src/org/apache/james/mime4j/EOLConvertingInputStream.java
deleted file mode 100644
index d6ef706..0000000
--- a/src/org/apache/james/mime4j/EOLConvertingInputStream.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PushbackInputStream;
-
-/**
- * InputStream which converts <code>\r</code>
- * bytes not followed by <code>\n</code> and <code>\n</code> not
- * preceded by <code>\r</code> to <code>\r\n</code>.
- *
- *
- * @version $Id: EOLConvertingInputStream.java,v 1.4 2004/11/29 13:15:42 ntherning Exp $
- */
-public class EOLConvertingInputStream extends InputStream {
- /** Converts single '\r' to '\r\n' */
- public static final int CONVERT_CR = 1;
- /** Converts single '\n' to '\r\n' */
- public static final int CONVERT_LF = 2;
- /** Converts single '\r' and '\n' to '\r\n' */
- public static final int CONVERT_BOTH = 3;
-
- private PushbackInputStream in = null;
- private int previous = 0;
- private int flags = CONVERT_BOTH;
- private int size = 0;
- private int pos = 0;
- private int nextTenPctPos;
- private int tenPctSize;
- private Callback callback;
-
- public interface Callback {
- public void report(int bytesRead);
- }
-
- /**
- * Creates a new <code>EOLConvertingInputStream</code>
- * instance converting bytes in the given <code>InputStream</code>.
- * The flag <code>CONVERT_BOTH</code> is the default.
- *
- * @param in the <code>InputStream</code> to read from.
- */
- public EOLConvertingInputStream(InputStream _in) {
- super();
- in = new PushbackInputStream(_in, 2);
- }
-
- /**
- * Creates a new <code>EOLConvertingInputStream</code>
- * instance converting bytes in the given <code>InputStream</code>.
- *
- * @param _in the <code>InputStream</code> to read from.
- * @param _size the size of the input stream (need not be exact)
- * @param _callback a callback reporting when each 10% of stream's size is reached
- */
- public EOLConvertingInputStream(InputStream _in, int _size, Callback _callback) {
- this(_in);
- size = _size;
- tenPctSize = size / 10;
- nextTenPctPos = tenPctSize;
- callback = _callback;
- }
-
- /**
- * Closes the underlying stream.
- *
- * @throws IOException on I/O errors.
- */
- public void close() throws IOException {
- in.close();
- }
-
- private int readByte() throws IOException {
- int b = in.read();
- if (b != -1) {
- if (callback != null && pos++ == nextTenPctPos) {
- nextTenPctPos += tenPctSize;
- if (callback != null) {
- callback.report(pos);
- }
- }
- }
- return b;
- }
-
- private void unreadByte(int c) throws IOException {
- in.unread(c);
- pos--;
- }
-
- /**
- * @see java.io.InputStream#read()
- */
- public int read() throws IOException {
- int b = readByte();
-
- if (b == -1) {
- pos = size;
- return -1;
- }
-
- if ((flags & CONVERT_CR) != 0 && b == '\r') {
- int c = readByte();
- if (c != -1) {
- unreadByte(c);
- }
- if (c != '\n') {
- unreadByte('\n');
- }
- } else if ((flags & CONVERT_LF) != 0 && b == '\n' && previous != '\r') {
- b = '\r';
- unreadByte('\n');
- }
-
- previous = b;
-
- return b;
- }
-
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/Log.java b/src/org/apache/james/mime4j/Log.java
deleted file mode 100644
index 5eeead5..0000000
--- a/src/org/apache/james/mime4j/Log.java
+++ /dev/null
@@ -1,114 +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 org.apache.james.mime4j;
-
-/**
- * Empty stub for the apache logging library.
- */
-public class Log {
- private static final String LOG_TAG = "Email Log";
-
- public Log(Class mClazz) {
- }
-
- public boolean isDebugEnabled() {
- return false;
- }
-
- public boolean isErrorEnabled() {
- return true;
- }
-
- public boolean isFatalEnabled() {
- return true;
- }
-
- public boolean isInfoEnabled() {
- return false;
- }
-
- public boolean isTraceEnabled() {
- return false;
- }
-
- public boolean isWarnEnabled() {
- return true;
- }
-
- public void trace(Object message) {
- if (!isTraceEnabled()) return;
- android.util.Log.v(LOG_TAG, toString(message, null));
- }
-
- public void trace(Object message, Throwable t) {
- if (!isTraceEnabled()) return;
- android.util.Log.v(LOG_TAG, toString(message, t));
- }
-
- public void debug(Object message) {
- if (!isDebugEnabled()) return;
- android.util.Log.d(LOG_TAG, toString(message, null));
- }
-
- public void debug(Object message, Throwable t) {
- if (!isDebugEnabled()) return;
- android.util.Log.d(LOG_TAG, toString(message, t));
- }
-
- public void info(Object message) {
- if (!isInfoEnabled()) return;
- android.util.Log.i(LOG_TAG, toString(message, null));
- }
-
- public void info(Object message, Throwable t) {
- if (!isInfoEnabled()) return;
- android.util.Log.i(LOG_TAG, toString(message, t));
- }
-
- public void warn(Object message) {
- android.util.Log.w(LOG_TAG, toString(message, null));
- }
-
- public void warn(Object message, Throwable t) {
- android.util.Log.w(LOG_TAG, toString(message, t));
- }
-
- public void error(Object message) {
- android.util.Log.e(LOG_TAG, toString(message, null));
- }
-
- public void error(Object message, Throwable t) {
- android.util.Log.e(LOG_TAG, toString(message, t));
- }
-
- public void fatal(Object message) {
- android.util.Log.e(LOG_TAG, toString(message, null));
- }
-
- public void fatal(Object message, Throwable t) {
- android.util.Log.e(LOG_TAG, toString(message, t));
- }
-
- private static String toString(Object o, Throwable t) {
- String m = (o == null) ? "(null)" : o.toString();
- if (t == null) {
- return m;
- } else {
- return m + " " + t.getMessage();
- }
- }
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/LogFactory.java b/src/org/apache/james/mime4j/LogFactory.java
deleted file mode 100644
index ed6e3de..0000000
--- a/src/org/apache/james/mime4j/LogFactory.java
+++ /dev/null
@@ -1,29 +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 org.apache.james.mime4j;
-
-/**
- * Empty stub for the apache logging library.
- */
-public final class LogFactory {
- private LogFactory() {
- }
-
- public static Log getLog(Class clazz) {
- return new Log(clazz);
- }
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/MimeBoundaryInputStream.java b/src/org/apache/james/mime4j/MimeBoundaryInputStream.java
deleted file mode 100644
index c6d6f24..0000000
--- a/src/org/apache/james/mime4j/MimeBoundaryInputStream.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PushbackInputStream;
-
-/**
- * Stream that constrains itself to a single MIME body part.
- * After the stream ends (i.e. read() returns -1) {@link #hasMoreParts()}
- * can be used to determine if a final boundary has been seen or not.
- * If {@link #parentEOF()} is <code>true</code> an unexpected end of stream
- * has been detected in the parent stream.
- *
- *
- *
- * @version $Id: MimeBoundaryInputStream.java,v 1.2 2004/11/29 13:15:42 ntherning Exp $
- */
-public class MimeBoundaryInputStream extends InputStream {
-
- private PushbackInputStream s = null;
- private byte[] boundary = null;
- private boolean first = true;
- private boolean eof = false;
- private boolean parenteof = false;
- private boolean moreParts = true;
-
- /**
- * Creates a new MimeBoundaryInputStream.
- * @param s The underlying stream.
- * @param boundary Boundary string (not including leading hyphens).
- */
- public MimeBoundaryInputStream(InputStream s, String boundary)
- throws IOException {
-
- this.s = new PushbackInputStream(s, boundary.length() + 4);
-
- boundary = "--" + boundary;
- this.boundary = new byte[boundary.length()];
- for (int i = 0; i < this.boundary.length; i++) {
- this.boundary[i] = (byte) boundary.charAt(i);
- }
-
- /*
- * By reading one byte we will update moreParts to be as expected
- * before any bytes have been read.
- */
- int b = read();
- if (b != -1) {
- this.s.unread(b);
- }
- }
-
- /**
- * Closes the underlying stream.
- *
- * @throws IOException on I/O errors.
- */
- public void close() throws IOException {
- s.close();
- }
-
- /**
- * Determines if the underlying stream has more parts (this stream has
- * not seen an end boundary).
- *
- * @return <code>true</code> if there are more parts in the underlying
- * stream, <code>false</code> otherwise.
- */
- public boolean hasMoreParts() {
- return moreParts;
- }
-
- /**
- * Determines if the parent stream has reached EOF
- *
- * @return <code>true</code> if EOF has been reached for the parent stream,
- * <code>false</code> otherwise.
- */
- public boolean parentEOF() {
- return parenteof;
- }
-
- /**
- * Consumes all unread bytes of this stream. After a call to this method
- * this stream will have reached EOF.
- *
- * @throws IOException on I/O errors.
- */
- public void consume() throws IOException {
- while (read() != -1) {
- }
- }
-
- /**
- * @see java.io.InputStream#read()
- */
- public int read() throws IOException {
- if (eof) {
- return -1;
- }
-
- if (first) {
- first = false;
- if (matchBoundary()) {
- return -1;
- }
- }
-
- int b1 = s.read();
- int b2 = s.read();
-
- if (b1 == '\r' && b2 == '\n') {
- if (matchBoundary()) {
- return -1;
- }
- }
-
- if (b2 != -1) {
- s.unread(b2);
- }
-
- parenteof = b1 == -1;
- eof = parenteof;
-
- return b1;
- }
-
- private boolean matchBoundary() throws IOException {
-
- for (int i = 0; i < boundary.length; i++) {
- int b = s.read();
- if (b != boundary[i]) {
- if (b != -1) {
- s.unread(b);
- }
- for (int j = i - 1; j >= 0; j--) {
- s.unread(boundary[j]);
- }
- return false;
- }
- }
-
- /*
- * We have a match. Is it an end boundary?
- */
- int prev = s.read();
- int curr = s.read();
- moreParts = !(prev == '-' && curr == '-');
- do {
- if (curr == '\n' && prev == '\r') {
- break;
- }
- prev = curr;
- } while ((curr = s.read()) != -1);
-
- if (curr == -1) {
- moreParts = false;
- parenteof = true;
- }
-
- eof = true;
-
- return true;
- }
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/MimeStreamParser.java b/src/org/apache/james/mime4j/MimeStreamParser.java
deleted file mode 100644
index a8aad5a..0000000
--- a/src/org/apache/james/mime4j/MimeStreamParser.java
+++ /dev/null
@@ -1,324 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j;
-
-import org.apache.james.mime4j.decoder.Base64InputStream;
-import org.apache.james.mime4j.decoder.QuotedPrintableInputStream;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.BitSet;
-import java.util.LinkedList;
-
-/**
- * <p>
- * Parses MIME (or RFC822) message streams of bytes or characters and reports
- * parsing events to a <code>ContentHandler</code> instance.
- * </p>
- * <p>
- * Typical usage:<br/>
- * <pre>
- * ContentHandler handler = new MyHandler();
- * MimeStreamParser parser = new MimeStreamParser();
- * parser.setContentHandler(handler);
- * parser.parse(new BufferedInputStream(new FileInputStream("mime.msg")));
- * </pre>
- * <strong>NOTE:</strong> All lines must end with CRLF
- * (<code>\r\n</code>). If you are unsure of the line endings in your stream
- * you should wrap it in a {@link org.apache.james.mime4j.EOLConvertingInputStream} instance.
- *
- *
- * @version $Id: MimeStreamParser.java,v 1.8 2005/02/11 10:12:02 ntherning Exp $
- */
-public class MimeStreamParser {
- private static final Log log = LogFactory.getLog(MimeStreamParser.class);
-
- private static BitSet fieldChars = null;
-
- private RootInputStream rootStream = null;
- private LinkedList<BodyDescriptor> bodyDescriptors = new LinkedList<BodyDescriptor>();
- private ContentHandler handler = null;
- private boolean raw = false;
- private boolean prematureEof = false;
-
- static {
- fieldChars = new BitSet();
- for (int i = 0x21; i <= 0x39; i++) {
- fieldChars.set(i);
- }
- for (int i = 0x3b; i <= 0x7e; i++) {
- fieldChars.set(i);
- }
- }
-
- /**
- * Creates a new <code>MimeStreamParser</code> instance.
- */
- public MimeStreamParser() {
- }
-
- /**
- * Parses a stream of bytes containing a MIME message.
- *
- * @param is the stream to parse.
- * @throws IOException on I/O errors.
- */
- public void parse(InputStream is) throws IOException {
- rootStream = new RootInputStream(is);
- parseMessage(rootStream);
- }
-
- /**
- * Determines if this parser is currently in raw mode.
- *
- * @return <code>true</code> if in raw mode, <code>false</code>
- * otherwise.
- * @see #setRaw(boolean)
- */
- public boolean isRaw() {
- return raw;
- }
-
- /**
- * Enables or disables raw mode. In raw mode all future entities
- * (messages or body parts) in the stream will be reported to the
- * {@link ContentHandler#raw(InputStream)} handler method only.
- * The stream will contain the entire unparsed entity contents
- * including header fields and whatever is in the body.
- *
- * @param raw <code>true</code> enables raw mode, <code>false</code>
- * disables it.
- */
- public void setRaw(boolean raw) {
- this.raw = raw;
- }
-
- /**
- * Finishes the parsing and stops reading lines.
- * NOTE: No more lines will be parsed but the parser
- * will still call
- * {@link ContentHandler#endMultipart()},
- * {@link ContentHandler#endBodyPart()},
- * {@link ContentHandler#endMessage()}, etc to match previous calls
- * to
- * {@link ContentHandler#startMultipart(BodyDescriptor)},
- * {@link ContentHandler#startBodyPart()},
- * {@link ContentHandler#startMessage()}, etc.
- */
- public void stop() {
- rootStream.truncate();
- }
-
- /**
- * Parses an entity which consists of a header followed by a body containing
- * arbitrary data, body parts or an embedded message.
- *
- * @param is the stream to parse.
- * @throws IOException on I/O errors.
- */
- private void parseEntity(InputStream is) throws IOException {
- BodyDescriptor bd = parseHeader(is);
-
- if (bd.isMultipart()) {
- bodyDescriptors.addFirst(bd);
-
- handler.startMultipart(bd);
-
- MimeBoundaryInputStream tempIs =
- new MimeBoundaryInputStream(is, bd.getBoundary());
- handler.preamble(new CloseShieldInputStream(tempIs));
- tempIs.consume();
-
- while (tempIs.hasMoreParts()) {
- tempIs = new MimeBoundaryInputStream(is, bd.getBoundary());
- parseBodyPart(tempIs);
- tempIs.consume();
- if (tempIs.parentEOF()) {
- prematureEof = true;
-// if (log.isWarnEnabled()) {
-// log.warn("Line " + rootStream.getLineNumber()
-// + ": Body part ended prematurely. "
-// + "Higher level boundary detected or "
-// + "EOF reached.");
-// }
- break;
- }
- }
-
- handler.epilogue(new CloseShieldInputStream(is));
-
- handler.endMultipart();
-
- bodyDescriptors.removeFirst();
-
- } else if (bd.isMessage()) {
- if (bd.isBase64Encoded()) {
- log.warn("base64 encoded message/rfc822 detected");
- is = new EOLConvertingInputStream(
- new Base64InputStream(is));
- } else if (bd.isQuotedPrintableEncoded()) {
- log.warn("quoted-printable encoded message/rfc822 detected");
- is = new EOLConvertingInputStream(
- new QuotedPrintableInputStream(is));
- }
- bodyDescriptors.addFirst(bd);
- parseMessage(is);
- bodyDescriptors.removeFirst();
- } else {
- handler.body(bd, new CloseShieldInputStream(is));
- }
-
- /*
- * Make sure the stream has been consumed.
- */
- while (is.read() != -1) {
- }
- }
-
- private void parseMessage(InputStream is) throws IOException {
- if (raw) {
- handler.raw(new CloseShieldInputStream(is));
- } else {
- handler.startMessage();
- parseEntity(is);
- handler.endMessage();
- }
- }
-
- public boolean getPrematureEof() {
- return prematureEof;
- }
-
- private void parseBodyPart(InputStream is) throws IOException {
- if (raw) {
- handler.raw(new CloseShieldInputStream(is));
- } else {
- handler.startBodyPart();
- parseEntity(is);
- handler.endBodyPart();
- }
- }
-
- /**
- * Parses a header.
- *
- * @param is the stream to parse.
- * @return a <code>BodyDescriptor</code> describing the body following
- * the header.
- */
- private BodyDescriptor parseHeader(InputStream is) throws IOException {
- BodyDescriptor bd = new BodyDescriptor(bodyDescriptors.isEmpty()
- ? null : (BodyDescriptor) bodyDescriptors.getFirst());
-
- handler.startHeader();
-
- int lineNumber = rootStream.getLineNumber();
-
- StringBuffer sb = new StringBuffer();
- int curr = 0;
- int prev = 0;
- while ((curr = is.read()) != -1) {
- if (curr == '\n' && (prev == '\n' || prev == 0)) {
- /*
- * [\r]\n[\r]\n or an immediate \r\n have been seen.
- */
- sb.deleteCharAt(sb.length() - 1);
- break;
- }
- sb.append((char) curr);
- prev = curr == '\r' ? prev : curr;
- }
-
-// if (curr == -1 && log.isWarnEnabled()) {
-// log.warn("Line " + rootStream.getLineNumber()
-// + ": Unexpected end of headers detected. "
-// + "Boundary detected in header or EOF reached.");
-// }
-
- int start = 0;
- int pos = 0;
- int startLineNumber = lineNumber;
- while (pos < sb.length()) {
- while (pos < sb.length() && sb.charAt(pos) != '\r') {
- pos++;
- }
- if (pos < sb.length() - 1 && sb.charAt(pos + 1) != '\n') {
- pos++;
- continue;
- }
-
- if (pos >= sb.length() - 2 || fieldChars.get(sb.charAt(pos + 2))) {
-
- /*
- * field should be the complete field data excluding the
- * trailing \r\n.
- */
- String field = sb.substring(start, pos);
- start = pos + 2;
-
- /*
- * Check for a valid field.
- */
- int index = field.indexOf(':');
- boolean valid = false;
- if (index != -1 && fieldChars.get(field.charAt(0))) {
- valid = true;
- String fieldName = field.substring(0, index).trim();
- for (int i = 0; i < fieldName.length(); i++) {
- if (!fieldChars.get(fieldName.charAt(i))) {
- valid = false;
- break;
- }
- }
-
- if (valid) {
- handler.field(field);
- bd.addField(fieldName, field.substring(index + 1));
- }
- }
-
- if (!valid && log.isWarnEnabled()) {
- log.warn("Line " + startLineNumber
- + ": Ignoring invalid field: '" + field.trim() + "'");
- }
-
- startLineNumber = lineNumber;
- }
-
- pos += 2;
- lineNumber++;
- }
-
- handler.endHeader();
-
- return bd;
- }
-
- /**
- * Sets the <code>ContentHandler</code> to use when reporting
- * parsing events.
- *
- * @param h the <code>ContentHandler</code>.
- */
- public void setContentHandler(ContentHandler h) {
- this.handler = h;
- }
-
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/RootInputStream.java b/src/org/apache/james/mime4j/RootInputStream.java
deleted file mode 100644
index cc8b241..0000000
--- a/src/org/apache/james/mime4j/RootInputStream.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * <code>InputStream</code> used by the parser to wrap the original user
- * supplied stream. This stream keeps track of the current line number and
- * can also be truncated. When truncated the stream will appear to have
- * reached end of file. This is used by the parser's
- * {@link org.apache.james.mime4j.MimeStreamParser#stop()} method.
- *
- *
- * @version $Id: RootInputStream.java,v 1.2 2004/10/02 12:41:10 ntherning Exp $
- */
-class RootInputStream extends InputStream {
- private InputStream is = null;
- private int lineNumber = 1;
- private int prev = -1;
- private boolean truncated = false;
-
- /**
- * Creates a new <code>RootInputStream</code>.
- *
- * @param in the stream to read from.
- */
- public RootInputStream(InputStream is) {
- this.is = is;
- }
-
- /**
- * Gets the current line number starting at 1
- * (the number of <code>\r\n</code> read so far plus 1).
- *
- * @return the current line number.
- */
- public int getLineNumber() {
- return lineNumber;
- }
-
- /**
- * Truncates this <code>InputStream</code>. After this call any
- * call to {@link #read()}, {@link #read(byte[]) or
- * {@link #read(byte[], int, int)} will return
- * -1 as if end-of-file had been reached.
- */
- public void truncate() {
- this.truncated = true;
- }
-
- /**
- * @see java.io.InputStream#read()
- */
- public int read() throws IOException {
- if (truncated) {
- return -1;
- }
-
- int b = is.read();
- if (prev == '\r' && b == '\n') {
- lineNumber++;
- }
- prev = b;
- return b;
- }
-
- /**
- *
- * @see java.io.InputStream#read(byte[], int, int)
- */
- public int read(byte[] b, int off, int len) throws IOException {
- if (truncated) {
- return -1;
- }
-
- int n = is.read(b, off, len);
- for (int i = off; i < off + n; i++) {
- if (prev == '\r' && b[i] == '\n') {
- lineNumber++;
- }
- prev = b[i];
- }
- return n;
- }
-
- /**
- * @see java.io.InputStream#read(byte[])
- */
- public int read(byte[] b) throws IOException {
- return read(b, 0, b.length);
- }
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/codec/EncoderUtil.java b/src/org/apache/james/mime4j/codec/EncoderUtil.java
deleted file mode 100644
index 6841bc9..0000000
--- a/src/org/apache/james/mime4j/codec/EncoderUtil.java
+++ /dev/null
@@ -1,630 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.codec;
-
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.BitSet;
-import java.util.Locale;
-
-import org.apache.james.mime4j.util.CharsetUtil;
-
-/**
- * ANDROID: THIS CLASS IS COPIED FROM A NEWER VERSION OF MIME4J
- */
-
-/**
- * Static methods for encoding header field values. This includes encoded-words
- * as defined in <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC 2047</a>
- * or display-names of an e-mail address, for example.
- *
- */
-public class EncoderUtil {
-
- // This array is a lookup table that translates 6-bit positive integer index
- // values into their "Base64 Alphabet" equivalents as specified in Table 1
- // of RFC 2045.
- // ANDROID: THIS TABLE IS COPIED FROM BASE64OUTPUTSTREAM
- static final byte[] BASE64_TABLE = { 'A', 'B', 'C', 'D', 'E', 'F',
- 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
- 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
- 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
- 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
- '6', '7', '8', '9', '+', '/' };
-
- // Byte used to pad output.
- private static final byte BASE64_PAD = '=';
-
- private static final BitSet Q_REGULAR_CHARS = initChars("=_?");
-
- private static final BitSet Q_RESTRICTED_CHARS = initChars("=_?\"#$%&'(),.:;<>@[\\]^`{|}~");
-
- private static final int MAX_USED_CHARACTERS = 50;
-
- private static final String ENC_WORD_PREFIX = "=?";
- private static final String ENC_WORD_SUFFIX = "?=";
-
- private static final int ENCODED_WORD_MAX_LENGTH = 75; // RFC 2047
-
- private static final BitSet TOKEN_CHARS = initChars("()<>@,;:\\\"/[]?=");
-
- private static final BitSet ATEXT_CHARS = initChars("()<>@.,;:\\\"[]");
-
- private static BitSet initChars(String specials) {
- BitSet bs = new BitSet(128);
- for (char ch = 33; ch < 127; ch++) {
- if (specials.indexOf(ch) == -1) {
- bs.set(ch);
- }
- }
- return bs;
- }
-
- /**
- * Selects one of the two encodings specified in RFC 2047.
- */
- public enum Encoding {
- /** The B encoding (identical to base64 defined in RFC 2045). */
- B,
- /** The Q encoding (similar to quoted-printable defined in RFC 2045). */
- Q
- }
-
- /**
- * Indicates the intended usage of an encoded word.
- */
- public enum Usage {
- /**
- * Encoded word is used to replace a 'text' token in any Subject or
- * Comments header field.
- */
- TEXT_TOKEN,
- /**
- * Encoded word is used to replace a 'word' entity within a 'phrase',
- * for example, one that precedes an address in a From, To, or Cc
- * header.
- */
- WORD_ENTITY
- }
-
- private EncoderUtil() {
- }
-
- /**
- * Encodes the display-name portion of an address. See <a
- * href='http://www.faqs.org/rfcs/rfc5322.html'>RFC 5322</a> section 3.4
- * and <a href='http://www.faqs.org/rfcs/rfc2047.html'>RFC 2047</a> section
- * 5.3. The specified string should not be folded.
- *
- * @param displayName
- * display-name to encode.
- * @return encoded display-name.
- */
- public static String encodeAddressDisplayName(String displayName) {
- // display-name = phrase
- // phrase = 1*( encoded-word / word )
- // word = atom / quoted-string
- // atom = [CFWS] 1*atext [CFWS]
- // CFWS = comment or folding white space
-
- if (isAtomPhrase(displayName)) {
- return displayName;
- } else if (hasToBeEncoded(displayName, 0)) {
- return encodeEncodedWord(displayName, Usage.WORD_ENTITY);
- } else {
- return quote(displayName);
- }
- }
-
- /**
- * Encodes the local part of an address specification as described in RFC
- * 5322 section 3.4.1. Leading and trailing CFWS should have been removed
- * before calling this method. The specified string should not contain any
- * illegal (control or non-ASCII) characters.
- *
- * @param localPart
- * the local part to encode
- * @return the encoded local part.
- */
- public static String encodeAddressLocalPart(String localPart) {
- // local-part = dot-atom / quoted-string
- // dot-atom = [CFWS] dot-atom-text [CFWS]
- // CFWS = comment or folding white space
-
- if (isDotAtomText(localPart)) {
- return localPart;
- } else {
- return quote(localPart);
- }
- }
-
- /**
- * Encodes the specified strings into a header parameter as described in RFC
- * 2045 section 5.1 and RFC 2183 section 2. The specified strings should not
- * contain any illegal (control or non-ASCII) characters.
- *
- * @param name
- * parameter name.
- * @param value
- * parameter value.
- * @return encoded result.
- */
- public static String encodeHeaderParameter(String name, String value) {
- name = name.toLowerCase(Locale.US);
-
- // value := token / quoted-string
- if (isToken(value)) {
- return name + "=" + value;
- } else {
- return name + "=" + quote(value);
- }
- }
-
- /**
- * Shortcut method that encodes the specified text into an encoded-word if
- * the text has to be encoded.
- *
- * @param text
- * text to encode.
- * @param usage
- * whether the encoded-word is to be used to replace a text token
- * or a word entity (see RFC 822).
- * @param usedCharacters
- * number of characters already used up (<code>0 <= usedCharacters <= 50</code>).
- * @return the specified text if encoding is not necessary or an encoded
- * word or a sequence of encoded words otherwise.
- */
- public static String encodeIfNecessary(String text, Usage usage,
- int usedCharacters) {
- if (hasToBeEncoded(text, usedCharacters))
- return encodeEncodedWord(text, usage, usedCharacters);
- else
- return text;
- }
-
- /**
- * Determines if the specified string has to encoded into an encoded-word.
- * Returns <code>true</code> if the text contains characters that don't
- * fall into the printable ASCII character set or if the text contains a
- * 'word' (sequence of non-whitespace characters) longer than 77 characters
- * (including characters already used up in the line).
- *
- * @param text
- * text to analyze.
- * @param usedCharacters
- * number of characters already used up (<code>0 <= usedCharacters <= 50</code>).
- * @return <code>true</code> if the specified text has to be encoded into
- * an encoded-word, <code>false</code> otherwise.
- */
- public static boolean hasToBeEncoded(String text, int usedCharacters) {
- if (text == null)
- throw new IllegalArgumentException();
- if (usedCharacters < 0 || usedCharacters > MAX_USED_CHARACTERS)
- throw new IllegalArgumentException();
-
- int nonWhiteSpaceCount = usedCharacters;
-
- for (int idx = 0; idx < text.length(); idx++) {
- char ch = text.charAt(idx);
- if (ch == '\t' || ch == ' ') {
- nonWhiteSpaceCount = 0;
- } else {
- nonWhiteSpaceCount++;
- if (nonWhiteSpaceCount > 77) {
- // Line cannot be folded into multiple lines with no more
- // than 78 characters each. Encoding as encoded-words makes
- // that possible. One character has to be reserved for
- // folding white space; that leaves 77 characters.
- return true;
- }
-
- if (ch < 32 || ch >= 127) {
- // non-printable ascii character has to be encoded
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Encodes the specified text into an encoded word or a sequence of encoded
- * words separated by space. The text is separated into a sequence of
- * encoded words if it does not fit in a single one.
- * <p>
- * The charset to encode the specified text into a byte array and the
- * encoding to use for the encoded-word are detected automatically.
- * <p>
- * This method assumes that zero characters have already been used up in the
- * current line.
- *
- * @param text
- * text to encode.
- * @param usage
- * whether the encoded-word is to be used to replace a text token
- * or a word entity (see RFC 822).
- * @return the encoded word (or sequence of encoded words if the given text
- * does not fit in a single encoded word).
- * @see #hasToBeEncoded(String, int)
- */
- public static String encodeEncodedWord(String text, Usage usage) {
- return encodeEncodedWord(text, usage, 0, null, null);
- }
-
- /**
- * Encodes the specified text into an encoded word or a sequence of encoded
- * words separated by space. The text is separated into a sequence of
- * encoded words if it does not fit in a single one.
- * <p>
- * The charset to encode the specified text into a byte array and the
- * encoding to use for the encoded-word are detected automatically.
- *
- * @param text
- * text to encode.
- * @param usage
- * whether the encoded-word is to be used to replace a text token
- * or a word entity (see RFC 822).
- * @param usedCharacters
- * number of characters already used up (<code>0 <= usedCharacters <= 50</code>).
- * @return the encoded word (or sequence of encoded words if the given text
- * does not fit in a single encoded word).
- * @see #hasToBeEncoded(String, int)
- */
- public static String encodeEncodedWord(String text, Usage usage,
- int usedCharacters) {
- return encodeEncodedWord(text, usage, usedCharacters, null, null);
- }
-
- /**
- * Encodes the specified text into an encoded word or a sequence of encoded
- * words separated by space. The text is separated into a sequence of
- * encoded words if it does not fit in a single one.
- *
- * @param text
- * text to encode.
- * @param usage
- * whether the encoded-word is to be used to replace a text token
- * or a word entity (see RFC 822).
- * @param usedCharacters
- * number of characters already used up (<code>0 <= usedCharacters <= 50</code>).
- * @param charset
- * the Java charset that should be used to encode the specified
- * string into a byte array. A suitable charset is detected
- * automatically if this parameter is <code>null</code>.
- * @param encoding
- * the encoding to use for the encoded-word (either B or Q). A
- * suitable encoding is automatically chosen if this parameter is
- * <code>null</code>.
- * @return the encoded word (or sequence of encoded words if the given text
- * does not fit in a single encoded word).
- * @see #hasToBeEncoded(String, int)
- */
- public static String encodeEncodedWord(String text, Usage usage,
- int usedCharacters, Charset charset, Encoding encoding) {
- if (text == null)
- throw new IllegalArgumentException();
- if (usedCharacters < 0 || usedCharacters > MAX_USED_CHARACTERS)
- throw new IllegalArgumentException();
-
- if (charset == null)
- charset = determineCharset(text);
-
- String mimeCharset = CharsetUtil.toMimeCharset(charset.name());
- if (mimeCharset == null) {
- // cannot happen if charset was originally null
- throw new IllegalArgumentException("Unsupported charset");
- }
-
- byte[] bytes = encode(text, charset);
-
- if (encoding == null)
- encoding = determineEncoding(bytes, usage);
-
- if (encoding == Encoding.B) {
- String prefix = ENC_WORD_PREFIX + mimeCharset + "?B?";
- return encodeB(prefix, text, usedCharacters, charset, bytes);
- } else {
- String prefix = ENC_WORD_PREFIX + mimeCharset + "?Q?";
- return encodeQ(prefix, text, usage, usedCharacters, charset, bytes);
- }
- }
-
- /**
- * Encodes the specified byte array using the B encoding defined in RFC
- * 2047.
- *
- * @param bytes
- * byte array to encode.
- * @return encoded string.
- */
- public static String encodeB(byte[] bytes) {
- StringBuilder sb = new StringBuilder();
-
- int idx = 0;
- final int end = bytes.length;
- for (; idx < end - 2; idx += 3) {
- int data = (bytes[idx] & 0xff) << 16 | (bytes[idx + 1] & 0xff) << 8
- | bytes[idx + 2] & 0xff;
- sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]);
- sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]);
- sb.append((char) BASE64_TABLE[data >> 6 & 0x3f]);
- sb.append((char) BASE64_TABLE[data & 0x3f]);
- }
-
- if (idx == end - 2) {
- int data = (bytes[idx] & 0xff) << 16 | (bytes[idx + 1] & 0xff) << 8;
- sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]);
- sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]);
- sb.append((char) BASE64_TABLE[data >> 6 & 0x3f]);
- sb.append((char) BASE64_PAD);
-
- } else if (idx == end - 1) {
- int data = (bytes[idx] & 0xff) << 16;
- sb.append((char) BASE64_TABLE[data >> 18 & 0x3f]);
- sb.append((char) BASE64_TABLE[data >> 12 & 0x3f]);
- sb.append((char) BASE64_PAD);
- sb.append((char) BASE64_PAD);
- }
-
- return sb.toString();
- }
-
- /**
- * Encodes the specified byte array using the Q encoding defined in RFC
- * 2047.
- *
- * @param bytes
- * byte array to encode.
- * @param usage
- * whether the encoded-word is to be used to replace a text token
- * or a word entity (see RFC 822).
- * @return encoded string.
- */
- public static String encodeQ(byte[] bytes, Usage usage) {
- BitSet qChars = usage == Usage.TEXT_TOKEN ? Q_REGULAR_CHARS
- : Q_RESTRICTED_CHARS;
-
- StringBuilder sb = new StringBuilder();
-
- final int end = bytes.length;
- for (int idx = 0; idx < end; idx++) {
- int v = bytes[idx] & 0xff;
- if (v == 32) {
- sb.append('_');
- } else if (!qChars.get(v)) {
- sb.append('=');
- sb.append(hexDigit(v >>> 4));
- sb.append(hexDigit(v & 0xf));
- } else {
- sb.append((char) v);
- }
- }
-
- return sb.toString();
- }
-
- /**
- * Tests whether the specified string is a token as defined in RFC 2045
- * section 5.1.
- *
- * @param str
- * string to test.
- * @return <code>true</code> if the specified string is a RFC 2045 token,
- * <code>false</code> otherwise.
- */
- public static boolean isToken(String str) {
- // token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, or tspecials>
- // tspecials := "(" / ")" / "<" / ">" / "@" / "," / ";" / ":" / "\" /
- // <"> / "/" / "[" / "]" / "?" / "="
- // CTL := 0.- 31., 127.
-
- final int length = str.length();
- if (length == 0)
- return false;
-
- for (int idx = 0; idx < length; idx++) {
- char ch = str.charAt(idx);
- if (!TOKEN_CHARS.get(ch))
- return false;
- }
-
- return true;
- }
-
- private static boolean isAtomPhrase(String str) {
- // atom = [CFWS] 1*atext [CFWS]
-
- boolean containsAText = false;
-
- final int length = str.length();
- for (int idx = 0; idx < length; idx++) {
- char ch = str.charAt(idx);
- if (ATEXT_CHARS.get(ch)) {
- containsAText = true;
- } else if (!CharsetUtil.isWhitespace(ch)) {
- return false;
- }
- }
-
- return containsAText;
- }
-
- // RFC 5322 section 3.2.3
- private static boolean isDotAtomText(String str) {
- // dot-atom-text = 1*atext *("." 1*atext)
- // atext = ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" /
- // "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~"
-
- char prev = '.';
-
- final int length = str.length();
- if (length == 0)
- return false;
-
- for (int idx = 0; idx < length; idx++) {
- char ch = str.charAt(idx);
-
- if (ch == '.') {
- if (prev == '.' || idx == length - 1)
- return false;
- } else {
- if (!ATEXT_CHARS.get(ch))
- return false;
- }
-
- prev = ch;
- }
-
- return true;
- }
-
- // RFC 5322 section 3.2.4
- private static String quote(String str) {
- // quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS]
- // qcontent = qtext / quoted-pair
- // qtext = %d33 / %d35-91 / %d93-126
- // quoted-pair = ("\" (VCHAR / WSP))
- // VCHAR = %x21-7E
- // DQUOTE = %x22
-
- String escaped = str.replaceAll("[\\\\\"]", "\\\\$0");
- return "\"" + escaped + "\"";
- }
-
- private static String encodeB(String prefix, String text,
- int usedCharacters, Charset charset, byte[] bytes) {
- int encodedLength = bEncodedLength(bytes);
-
- int totalLength = prefix.length() + encodedLength
- + ENC_WORD_SUFFIX.length();
- if (totalLength <= ENCODED_WORD_MAX_LENGTH - usedCharacters) {
- return prefix + encodeB(bytes) + ENC_WORD_SUFFIX;
- } else {
- int splitOffset = text.offsetByCodePoints(text.length() / 2, -1);
-
- String part1 = text.substring(0, splitOffset);
- byte[] bytes1 = encode(part1, charset);
- String word1 = encodeB(prefix, part1, usedCharacters, charset,
- bytes1);
-
- String part2 = text.substring(splitOffset);
- byte[] bytes2 = encode(part2, charset);
- String word2 = encodeB(prefix, part2, 0, charset, bytes2);
-
- return word1 + " " + word2;
- }
- }
-
- private static int bEncodedLength(byte[] bytes) {
- return (bytes.length + 2) / 3 * 4;
- }
-
- private static String encodeQ(String prefix, String text, Usage usage,
- int usedCharacters, Charset charset, byte[] bytes) {
- int encodedLength = qEncodedLength(bytes, usage);
-
- int totalLength = prefix.length() + encodedLength
- + ENC_WORD_SUFFIX.length();
- if (totalLength <= ENCODED_WORD_MAX_LENGTH - usedCharacters) {
- return prefix + encodeQ(bytes, usage) + ENC_WORD_SUFFIX;
- } else {
- int splitOffset = text.offsetByCodePoints(text.length() / 2, -1);
-
- String part1 = text.substring(0, splitOffset);
- byte[] bytes1 = encode(part1, charset);
- String word1 = encodeQ(prefix, part1, usage, usedCharacters,
- charset, bytes1);
-
- String part2 = text.substring(splitOffset);
- byte[] bytes2 = encode(part2, charset);
- String word2 = encodeQ(prefix, part2, usage, 0, charset, bytes2);
-
- return word1 + " " + word2;
- }
- }
-
- private static int qEncodedLength(byte[] bytes, Usage usage) {
- BitSet qChars = usage == Usage.TEXT_TOKEN ? Q_REGULAR_CHARS
- : Q_RESTRICTED_CHARS;
-
- int count = 0;
-
- for (int idx = 0; idx < bytes.length; idx++) {
- int v = bytes[idx] & 0xff;
- if (v == 32) {
- count++;
- } else if (!qChars.get(v)) {
- count += 3;
- } else {
- count++;
- }
- }
-
- return count;
- }
-
- private static byte[] encode(String text, Charset charset) {
- ByteBuffer buffer = charset.encode(text);
- byte[] bytes = new byte[buffer.limit()];
- buffer.get(bytes);
- return bytes;
- }
-
- private static Charset determineCharset(String text) {
- // it is an important property of iso-8859-1 that it directly maps
- // unicode code points 0000 to 00ff to byte values 00 to ff.
- boolean ascii = true;
- final int len = text.length();
- for (int index = 0; index < len; index++) {
- char ch = text.charAt(index);
- if (ch > 0xff) {
- return CharsetUtil.UTF_8;
- }
- if (ch > 0x7f) {
- ascii = false;
- }
- }
- return ascii ? CharsetUtil.US_ASCII : CharsetUtil.ISO_8859_1;
- }
-
- private static Encoding determineEncoding(byte[] bytes, Usage usage) {
- if (bytes.length == 0)
- return Encoding.Q;
-
- BitSet qChars = usage == Usage.TEXT_TOKEN ? Q_REGULAR_CHARS
- : Q_RESTRICTED_CHARS;
-
- int qEncoded = 0;
- for (int i = 0; i < bytes.length; i++) {
- int v = bytes[i] & 0xff;
- if (v != 32 && !qChars.get(v)) {
- qEncoded++;
- }
- }
-
- int percentage = qEncoded * 100 / bytes.length;
- return percentage > 30 ? Encoding.B : Encoding.Q;
- }
-
- private static char hexDigit(int i) {
- return i < 10 ? (char) (i + '0') : (char) (i - 10 + 'A');
- }
-}
diff --git a/src/org/apache/james/mime4j/decoder/Base64InputStream.java b/src/org/apache/james/mime4j/decoder/Base64InputStream.java
deleted file mode 100644
index 77f5d7d..0000000
--- a/src/org/apache/james/mime4j/decoder/Base64InputStream.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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. *
- ****************************************************************/
-
-/**
- * Modified to improve efficiency by Android 21-Aug-2009
- */
-
-package org.apache.james.mime4j.decoder;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Performs Base-64 decoding on an underlying stream.
- *
- *
- * @version $Id: Base64InputStream.java,v 1.3 2004/11/29 13:15:47 ntherning Exp $
- */
-public class Base64InputStream extends InputStream {
- private final InputStream s;
- private int outCount = 0;
- private int outIndex = 0;
- private final int[] outputBuffer = new int[3];
- private final byte[] inputBuffer = new byte[4];
- private boolean done = false;
-
- public Base64InputStream(InputStream s) {
- this.s = s;
- }
-
- /**
- * Closes the underlying stream.
- *
- * @throws IOException on I/O errors.
- */
- @Override
- public void close() throws IOException {
- s.close();
- }
-
- @Override
- public int read() throws IOException {
- if (outIndex == outCount) {
- fillBuffer();
- if (outIndex == outCount) {
- return -1;
- }
- }
-
- return outputBuffer[outIndex++];
- }
-
- /**
- * Retrieve data from the underlying stream, decode it,
- * and put the results in the byteq.
- * @throws IOException
- */
- private void fillBuffer() throws IOException {
- outCount = 0;
- outIndex = 0;
- int inCount = 0;
-
- int i;
- // "done" is needed for the two successive '=' at the end
- while (!done) {
- switch (i = s.read()) {
- case -1:
- // No more input - just return, let outputBuffer drain out, and be done
- return;
- case '=':
- // once we meet the first '=', avoid reading the second '='
- done = true;
- decodeAndEnqueue(inCount);
- return;
- default:
- byte sX = TRANSLATION[i];
- if (sX < 0) continue;
- inputBuffer[inCount++] = sX;
- if (inCount == 4) {
- decodeAndEnqueue(inCount);
- return;
- }
- break;
- }
- }
- }
-
- private void decodeAndEnqueue(int len) {
- int accum = 0;
- accum |= inputBuffer[0] << 18;
- accum |= inputBuffer[1] << 12;
- accum |= inputBuffer[2] << 6;
- accum |= inputBuffer[3];
-
- // There's a bit of duplicated code here because we want to have straight-through operation
- // for the most common case of len==4
- if (len == 4) {
- outputBuffer[0] = (accum >> 16) & 0xFF;
- outputBuffer[1] = (accum >> 8) & 0xFF;
- outputBuffer[2] = (accum) & 0xFF;
- outCount = 3;
- return;
- } else if (len == 3) {
- outputBuffer[0] = (accum >> 16) & 0xFF;
- outputBuffer[1] = (accum >> 8) & 0xFF;
- outCount = 2;
- return;
- } else { // len == 2
- outputBuffer[0] = (accum >> 16) & 0xFF;
- outCount = 1;
- return;
- }
- }
-
- private static byte[] TRANSLATION = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */
- -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */
- 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */
- -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */
- 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xA0 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xB0 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xC0 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xD0 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xE0 */
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xF0 */
- };
-
-
-}
diff --git a/src/org/apache/james/mime4j/decoder/ByteQueue.java b/src/org/apache/james/mime4j/decoder/ByteQueue.java
deleted file mode 100644
index 6d7ccef..0000000
--- a/src/org/apache/james/mime4j/decoder/ByteQueue.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.decoder;
-
-import java.util.Iterator;
-
-public class ByteQueue {
-
- private UnboundedFifoByteBuffer buf;
- private int initialCapacity = -1;
-
- public ByteQueue() {
- buf = new UnboundedFifoByteBuffer();
- }
-
- public ByteQueue(int initialCapacity) {
- buf = new UnboundedFifoByteBuffer(initialCapacity);
- this.initialCapacity = initialCapacity;
- }
-
- public void enqueue(byte b) {
- buf.add(b);
- }
-
- public byte dequeue() {
- return buf.remove();
- }
-
- public int count() {
- return buf.size();
- }
-
- public void clear() {
- if (initialCapacity != -1)
- buf = new UnboundedFifoByteBuffer(initialCapacity);
- else
- buf = new UnboundedFifoByteBuffer();
- }
-
- public Iterator iterator() {
- return buf.iterator();
- }
-
-
-}
diff --git a/src/org/apache/james/mime4j/decoder/DecoderUtil.java b/src/org/apache/james/mime4j/decoder/DecoderUtil.java
deleted file mode 100644
index 48fe07d..0000000
--- a/src/org/apache/james/mime4j/decoder/DecoderUtil.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.decoder;
-
-//BEGIN android-changed: Stubbing out logging
-import org.apache.james.mime4j.Log;
-import org.apache.james.mime4j.LogFactory;
-//END android-changed
-import org.apache.james.mime4j.util.CharsetUtil;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-
-/**
- * Static methods for decoding strings, byte arrays and encoded words.
- *
- *
- * @version $Id: DecoderUtil.java,v 1.3 2005/02/07 15:33:59 ntherning Exp $
- */
-public class DecoderUtil {
- private static Log log = LogFactory.getLog(DecoderUtil.class);
-
- /**
- * Decodes a string containing quoted-printable encoded data.
- *
- * @param s the string to decode.
- * @return the decoded bytes.
- */
- public static byte[] decodeBaseQuotedPrintable(String s) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- try {
- byte[] bytes = s.getBytes("US-ASCII");
-
- QuotedPrintableInputStream is = new QuotedPrintableInputStream(
- new ByteArrayInputStream(bytes));
-
- int b = 0;
- while ((b = is.read()) != -1) {
- baos.write(b);
- }
- } catch (IOException e) {
- /*
- * This should never happen!
- */
- log.error(e);
- }
-
- return baos.toByteArray();
- }
-
- /**
- * Decodes a string containing base64 encoded data.
- *
- * @param s the string to decode.
- * @return the decoded bytes.
- */
- public static byte[] decodeBase64(String s) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- try {
- byte[] bytes = s.getBytes("US-ASCII");
-
- Base64InputStream is = new Base64InputStream(
- new ByteArrayInputStream(bytes));
-
- int b = 0;
- while ((b = is.read()) != -1) {
- baos.write(b);
- }
- } catch (IOException e) {
- /*
- * This should never happen!
- */
- log.error(e);
- }
-
- return baos.toByteArray();
- }
-
- /**
- * Decodes an encoded word encoded with the 'B' encoding (described in
- * RFC 2047) found in a header field body.
- *
- * @param encodedWord the encoded word to decode.
- * @param charset the Java charset to use.
- * @return the decoded string.
- * @throws UnsupportedEncodingException if the given Java charset isn't
- * supported.
- */
- public static String decodeB(String encodedWord, String charset)
- throws UnsupportedEncodingException {
-
- return new String(decodeBase64(encodedWord), charset);
- }
-
- /**
- * Decodes an encoded word encoded with the 'Q' encoding (described in
- * RFC 2047) found in a header field body.
- *
- * @param encodedWord the encoded word to decode.
- * @param charset the Java charset to use.
- * @return the decoded string.
- * @throws UnsupportedEncodingException if the given Java charset isn't
- * supported.
- */
- public static String decodeQ(String encodedWord, String charset)
- throws UnsupportedEncodingException {
-
- /*
- * Replace _ with =20
- */
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < encodedWord.length(); i++) {
- char c = encodedWord.charAt(i);
- if (c == '_') {
- sb.append("=20");
- } else {
- sb.append(c);
- }
- }
-
- return new String(decodeBaseQuotedPrintable(sb.toString()), charset);
- }
-
- /**
- * Decodes a string containing encoded words as defined by RFC 2047.
- * Encoded words in have the form
- * =?charset?enc?Encoded word?= where enc is either 'Q' or 'q' for
- * quoted-printable and 'B' or 'b' for Base64.
- *
- * ANDROID: COPIED FROM A NEWER VERSION OF MIME4J
- *
- * @param body the string to decode.
- * @return the decoded string.
- */
- public static String decodeEncodedWords(String body) {
-
- // ANDROID: Most strings will not include "=?" so a quick test can prevent unneeded
- // object creation. This could also be handled via lazy creation of the StringBuilder.
- if (body.indexOf("=?") == -1) {
- return body;
- }
-
- int previousEnd = 0;
- boolean previousWasEncoded = false;
-
- StringBuilder sb = new StringBuilder();
-
- while (true) {
- int begin = body.indexOf("=?", previousEnd);
-
- // ANDROID: The mime4j original version has an error here. It gets confused if
- // the encoded string begins with an '=' (just after "?Q?"). This patch seeks forward
- // to find the two '?' in the "header", before looking for the final "?=".
- if (begin == -1) {
- break;
- }
- int qm1 = body.indexOf('?', begin + 2);
- if (qm1 == -1) {
- break;
- }
- int qm2 = body.indexOf('?', qm1 + 1);
- if (qm2 == -1) {
- break;
- }
- int end = body.indexOf("?=", qm2 + 1);
- if (end == -1) {
- break;
- }
- end += 2;
-
- String sep = body.substring(previousEnd, begin);
-
- String decoded = decodeEncodedWord(body, begin, end);
- if (decoded == null) {
- sb.append(sep);
- sb.append(body.substring(begin, end));
- } else {
- if (!previousWasEncoded || !CharsetUtil.isWhitespace(sep)) {
- sb.append(sep);
- }
- sb.append(decoded);
- }
-
- previousEnd = end;
- previousWasEncoded = decoded != null;
- }
-
- if (previousEnd == 0)
- return body;
-
- sb.append(body.substring(previousEnd));
- return sb.toString();
- }
-
- // return null on error. Begin is index of '=?' in body.
- public static String decodeEncodedWord(String body, int begin, int end) {
- // Skip the '?=' chars in body and scan forward from there for next '?'
- int qm1 = body.indexOf('?', begin + 2);
- if (qm1 == -1 || qm1 == end - 2)
- return null;
-
- int qm2 = body.indexOf('?', qm1 + 1);
- if (qm2 == -1 || qm2 == end - 2)
- return null;
-
- String mimeCharset = body.substring(begin + 2, qm1);
- String encoding = body.substring(qm1 + 1, qm2);
- String encodedText = body.substring(qm2 + 1, end - 2);
-
- String charset = CharsetUtil.toJavaCharset(mimeCharset);
- if (charset == null) {
- if (log.isWarnEnabled()) {
- log.warn("MIME charset '" + mimeCharset + "' in encoded word '"
- + body.substring(begin, end) + "' doesn't have a "
- + "corresponding Java charset");
- }
- return null;
- } else if (!CharsetUtil.isDecodingSupported(charset)) {
- if (log.isWarnEnabled()) {
- log.warn("Current JDK doesn't support decoding of charset '"
- + charset + "' (MIME charset '" + mimeCharset
- + "' in encoded word '" + body.substring(begin, end)
- + "')");
- }
- return null;
- }
-
- if (encodedText.length() == 0) {
- if (log.isWarnEnabled()) {
- log.warn("Missing encoded text in encoded word: '"
- + body.substring(begin, end) + "'");
- }
- return null;
- }
-
- try {
- if (encoding.equalsIgnoreCase("Q")) {
- return DecoderUtil.decodeQ(encodedText, charset);
- } else if (encoding.equalsIgnoreCase("B")) {
- return DecoderUtil.decodeB(encodedText, charset);
- } else {
- if (log.isWarnEnabled()) {
- log.warn("Warning: Unknown encoding in encoded word '"
- + body.substring(begin, end) + "'");
- }
- return null;
- }
- } catch (UnsupportedEncodingException e) {
- // should not happen because of isDecodingSupported check above
- if (log.isWarnEnabled()) {
- log.warn("Unsupported encoding in encoded word '"
- + body.substring(begin, end) + "'", e);
- }
- return null;
- } catch (RuntimeException e) {
- if (log.isWarnEnabled()) {
- log.warn("Could not decode encoded word '"
- + body.substring(begin, end) + "'", e);
- }
- return null;
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java b/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java
deleted file mode 100644
index e43f398..0000000
--- a/src/org/apache/james/mime4j/decoder/QuotedPrintableInputStream.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.decoder;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-//BEGIN android-changed: Stubbing out logging
-import org.apache.james.mime4j.Log;
-import org.apache.james.mime4j.LogFactory;
-//END android-changed
-
-/**
- * Performs Quoted-Printable decoding on an underlying stream.
- *
- *
- *
- * @version $Id: QuotedPrintableInputStream.java,v 1.3 2004/11/29 13:15:47 ntherning Exp $
- */
-public class QuotedPrintableInputStream extends InputStream {
- private static Log log = LogFactory.getLog(QuotedPrintableInputStream.class);
-
- private InputStream stream;
- ByteQueue byteq = new ByteQueue();
- ByteQueue pushbackq = new ByteQueue();
- private byte state = 0;
-
- public QuotedPrintableInputStream(InputStream stream) {
- this.stream = stream;
- }
-
- /**
- * Closes the underlying stream.
- *
- * @throws IOException on I/O errors.
- */
- public void close() throws IOException {
- stream.close();
- }
-
- public int read() throws IOException {
- fillBuffer();
- if (byteq.count() == 0)
- return -1;
- else {
- byte val = byteq.dequeue();
- if (val >= 0)
- return val;
- else
- return val & 0xFF;
- }
- }
-
- /**
- * Pulls bytes out of the underlying stream and places them in the
- * pushback queue. This is necessary (vs. reading from the
- * underlying stream directly) to detect and filter out "transport
- * padding" whitespace, i.e., all whitespace that appears immediately
- * before a CRLF.
- *
- * @throws IOException Underlying stream threw IOException.
- */
- private void populatePushbackQueue() throws IOException {
- //Debug.verify(pushbackq.count() == 0, "PopulatePushbackQueue called when pushback queue was not empty!");
-
- if (pushbackq.count() != 0)
- return;
-
- while (true) {
- int i = stream.read();
- switch (i) {
- case -1:
- // stream is done
- pushbackq.clear(); // discard any whitespace preceding EOF
- return;
- case ' ':
- case '\t':
- pushbackq.enqueue((byte)i);
- break;
- case '\r':
- case '\n':
- pushbackq.clear(); // discard any whitespace preceding EOL
- pushbackq.enqueue((byte)i);
- return;
- default:
- pushbackq.enqueue((byte)i);
- return;
- }
- }
- }
-
- /**
- * Causes the pushback queue to get populated if it is empty, then
- * consumes and decodes bytes out of it until one or more bytes are
- * in the byte queue. This decoding step performs the actual QP
- * decoding.
- *
- * @throws IOException Underlying stream threw IOException.
- */
- private void fillBuffer() throws IOException {
- byte msdChar = 0; // first digit of escaped num
- while (byteq.count() == 0) {
- if (pushbackq.count() == 0) {
- populatePushbackQueue();
- if (pushbackq.count() == 0)
- return;
- }
-
- byte b = (byte)pushbackq.dequeue();
-
- switch (state) {
- case 0: // start state, no bytes pending
- if (b != '=') {
- byteq.enqueue(b);
- break; // state remains 0
- } else {
- state = 1;
- break;
- }
- case 1: // encountered "=" so far
- if (b == '\r') {
- state = 2;
- break;
- } else if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) {
- state = 3;
- msdChar = b; // save until next digit encountered
- break;
- } else if (b == '=') {
- /*
- * Special case when == is encountered.
- * Emit one = and stay in this state.
- */
- if (log.isWarnEnabled()) {
- log.warn("Malformed MIME; got ==");
- }
- byteq.enqueue((byte)'=');
- break;
- } else {
- if (log.isWarnEnabled()) {
- log.warn("Malformed MIME; expected \\r or "
- + "[0-9A-Z], got " + b);
- }
- state = 0;
- byteq.enqueue((byte)'=');
- byteq.enqueue(b);
- break;
- }
- case 2: // encountered "=\r" so far
- if (b == '\n') {
- state = 0;
- break;
- } else {
- if (log.isWarnEnabled()) {
- log.warn("Malformed MIME; expected "
- + (int)'\n' + ", got " + b);
- }
- state = 0;
- byteq.enqueue((byte)'=');
- byteq.enqueue((byte)'\r');
- byteq.enqueue(b);
- break;
- }
- case 3: // encountered =<digit> so far; expecting another <digit> to complete the octet
- if ((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f')) {
- byte msd = asciiCharToNumericValue(msdChar);
- byte low = asciiCharToNumericValue(b);
- state = 0;
- byteq.enqueue((byte)((msd << 4) | low));
- break;
- } else {
- if (log.isWarnEnabled()) {
- log.warn("Malformed MIME; expected "
- + "[0-9A-Z], got " + b);
- }
- state = 0;
- byteq.enqueue((byte)'=');
- byteq.enqueue(msdChar);
- byteq.enqueue(b);
- break;
- }
- default: // should never happen
- log.error("Illegal state: " + state);
- state = 0;
- byteq.enqueue(b);
- break;
- }
- }
- }
-
- /**
- * Converts '0' => 0, 'A' => 10, etc.
- * @param c ASCII character value.
- * @return Numeric value of hexadecimal character.
- */
- private byte asciiCharToNumericValue(byte c) {
- if (c >= '0' && c <= '9') {
- return (byte)(c - '0');
- } else if (c >= 'A' && c <= 'Z') {
- return (byte)(0xA + (c - 'A'));
- } else if (c >= 'a' && c <= 'z') {
- return (byte)(0xA + (c - 'a'));
- } else {
- /*
- * This should never happen since all calls to this method
- * are preceded by a check that c is in [0-9A-Za-z]
- */
- throw new IllegalArgumentException((char) c
- + " is not a hexadecimal digit");
- }
- }
-
-}
diff --git a/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java b/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java
deleted file mode 100644
index f01194f..0000000
--- a/src/org/apache/james/mime4j/decoder/UnboundedFifoByteBuffer.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.decoder;
-
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-
-/**
- * UnboundedFifoByteBuffer is a very efficient buffer implementation.
- * According to performance testing, it exhibits a constant access time, but it
- * also outperforms ArrayList when used for the same purpose.
- * <p>
- * The removal order of an <code>UnboundedFifoByteBuffer</code> is based on the insertion
- * order; elements are removed in the same order in which they were added.
- * The iteration order is the same as the removal order.
- * <p>
- * The {@link #remove()} and {@link #get()} operations perform in constant time.
- * The {@link #add(Object)} operation performs in amortized constant time. All
- * other operations perform in linear time or worse.
- * <p>
- * Note that this implementation is not synchronized. The following can be
- * used to provide synchronized access to your <code>UnboundedFifoByteBuffer</code>:
- * <pre>
- * Buffer fifo = BufferUtils.synchronizedBuffer(new UnboundedFifoByteBuffer());
- * </pre>
- * <p>
- * This buffer prevents null objects from being added.
- *
- * @since Commons Collections 3.0 (previously in main package v2.1)
- * @version $Revision: 1.1 $ $Date: 2004/08/24 06:52:02 $
- *
- *
- *
- *
- *
- *
- */
-class UnboundedFifoByteBuffer {
-
- protected byte[] buffer;
- protected int head;
- protected int tail;
-
- /**
- * Constructs an UnboundedFifoByteBuffer with the default number of elements.
- * It is exactly the same as performing the following:
- *
- * <pre>
- * new UnboundedFifoByteBuffer(32);
- * </pre>
- */
- public UnboundedFifoByteBuffer() {
- this(32);
- }
-
- /**
- * Constructs an UnboundedFifoByteBuffer with the specified number of elements.
- * The integer must be a positive integer.
- *
- * @param initialSize the initial size of the buffer
- * @throws IllegalArgumentException if the size is less than 1
- */
- public UnboundedFifoByteBuffer(int initialSize) {
- if (initialSize <= 0) {
- throw new IllegalArgumentException("The size must be greater than 0");
- }
- buffer = new byte[initialSize + 1];
- head = 0;
- tail = 0;
- }
-
- /**
- * Returns the number of elements stored in the buffer.
- *
- * @return this buffer's size
- */
- public int size() {
- int size = 0;
-
- if (tail < head) {
- size = buffer.length - head + tail;
- } else {
- size = tail - head;
- }
-
- return size;
- }
-
- /**
- * Returns true if this buffer is empty; false otherwise.
- *
- * @return true if this buffer is empty
- */
- public boolean isEmpty() {
- return (size() == 0);
- }
-
- /**
- * Adds the given element to this buffer.
- *
- * @param b the byte to add
- * @return true, always
- */
- public boolean add(final byte b) {
-
- if (size() + 1 >= buffer.length) {
- byte[] tmp = new byte[((buffer.length - 1) * 2) + 1];
-
- int j = 0;
- for (int i = head; i != tail;) {
- tmp[j] = buffer[i];
- buffer[i] = 0;
-
- j++;
- i++;
- if (i == buffer.length) {
- i = 0;
- }
- }
-
- buffer = tmp;
- head = 0;
- tail = j;
- }
-
- buffer[tail] = b;
- tail++;
- if (tail >= buffer.length) {
- tail = 0;
- }
- return true;
- }
-
- /**
- * Returns the next object in the buffer.
- *
- * @return the next object in the buffer
- * @throws BufferUnderflowException if this buffer is empty
- */
- public byte get() {
- if (isEmpty()) {
- throw new IllegalStateException("The buffer is already empty");
- }
-
- return buffer[head];
- }
-
- /**
- * Removes the next object from the buffer
- *
- * @return the removed object
- * @throws BufferUnderflowException if this buffer is empty
- */
- public byte remove() {
- if (isEmpty()) {
- throw new IllegalStateException("The buffer is already empty");
- }
-
- byte element = buffer[head];
-
- head++;
- if (head >= buffer.length) {
- head = 0;
- }
-
- return element;
- }
-
- /**
- * Increments the internal index.
- *
- * @param index the index to increment
- * @return the updated index
- */
- private int increment(int index) {
- index++;
- if (index >= buffer.length) {
- index = 0;
- }
- return index;
- }
-
- /**
- * Decrements the internal index.
- *
- * @param index the index to decrement
- * @return the updated index
- */
- private int decrement(int index) {
- index--;
- if (index < 0) {
- index = buffer.length - 1;
- }
- return index;
- }
-
- /**
- * Returns an iterator over this buffer's elements.
- *
- * @return an iterator over this buffer's elements
- */
- public Iterator iterator() {
- return new Iterator() {
-
- private int index = head;
- private int lastReturnedIndex = -1;
-
- public boolean hasNext() {
- return index != tail;
-
- }
-
- public Object next() {
- if (!hasNext()) {
- throw new NoSuchElementException();
- }
- lastReturnedIndex = index;
- index = increment(index);
- return new Byte(buffer[lastReturnedIndex]);
- }
-
- public void remove() {
- if (lastReturnedIndex == -1) {
- throw new IllegalStateException();
- }
-
- // First element can be removed quickly
- if (lastReturnedIndex == head) {
- UnboundedFifoByteBuffer.this.remove();
- lastReturnedIndex = -1;
- return;
- }
-
- // Other elements require us to shift the subsequent elements
- int i = lastReturnedIndex + 1;
- while (i != tail) {
- if (i >= buffer.length) {
- buffer[i - 1] = buffer[0];
- i = 0;
- } else {
- buffer[i - 1] = buffer[i];
- i++;
- }
- }
-
- lastReturnedIndex = -1;
- tail = decrement(tail);
- buffer[tail] = 0;
- index = decrement(index);
- }
-
- };
- }
-
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/field/AddressListField.java b/src/org/apache/james/mime4j/field/AddressListField.java
deleted file mode 100644
index df9f398..0000000
--- a/src/org/apache/james/mime4j/field/AddressListField.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field;
-
-//BEGIN android-changed: Stubbing out logging
-import org.apache.james.mime4j.Log;
-import org.apache.james.mime4j.LogFactory;
-//END android-changed
-import org.apache.james.mime4j.field.address.AddressList;
-import org.apache.james.mime4j.field.address.parser.ParseException;
-
-public class AddressListField extends Field {
- private AddressList addressList;
- private ParseException parseException;
-
- protected AddressListField(String name, String body, String raw, AddressList addressList, ParseException parseException) {
- super(name, body, raw);
- this.addressList = addressList;
- this.parseException = parseException;
- }
-
- public AddressList getAddressList() {
- return addressList;
- }
-
- public ParseException getParseException() {
- return parseException;
- }
-
- public static class Parser implements FieldParser {
- private static Log log = LogFactory.getLog(Parser.class);
-
- public Field parse(final String name, final String body, final String raw) {
- AddressList addressList = null;
- ParseException parseException = null;
- try {
- addressList = AddressList.parse(body);
- }
- catch (ParseException e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = e;
- }
- return new AddressListField(name, body, raw, addressList, parseException);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java b/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java
deleted file mode 100644
index 73d8d23..0000000
--- a/src/org/apache/james/mime4j/field/ContentTransferEncodingField.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field;
-
-
-
-/**
- * Represents a <code>Content-Transfer-Encoding</code> field.
- *
- *
- * @version $Id: ContentTransferEncodingField.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $
- */
-public class ContentTransferEncodingField extends Field {
- /**
- * The <code>7bit</code> encoding.
- */
- public static final String ENC_7BIT = "7bit";
- /**
- * The <code>8bit</code> encoding.
- */
- public static final String ENC_8BIT = "8bit";
- /**
- * The <code>binary</code> encoding.
- */
- public static final String ENC_BINARY = "binary";
- /**
- * The <code>quoted-printable</code> encoding.
- */
- public static final String ENC_QUOTED_PRINTABLE = "quoted-printable";
- /**
- * The <code>base64</code> encoding.
- */
- public static final String ENC_BASE64 = "base64";
-
- private String encoding;
-
- protected ContentTransferEncodingField(String name, String body, String raw, String encoding) {
- super(name, body, raw);
- this.encoding = encoding;
- }
-
- /**
- * Gets the encoding defined in this field.
- *
- * @return the encoding or an empty string if not set.
- */
- public String getEncoding() {
- return encoding;
- }
-
- /**
- * Gets the encoding of the given field if. Returns the default
- * <code>7bit</code> if not set or if
- * <code>f</code> is <code>null</code>.
- *
- * @return the encoding.
- */
- public static String getEncoding(ContentTransferEncodingField f) {
- if (f != null && f.getEncoding().length() != 0) {
- return f.getEncoding();
- }
- return ENC_7BIT;
- }
-
- public static class Parser implements FieldParser {
- public Field parse(final String name, final String body, final String raw) {
- final String encoding = body.trim().toLowerCase();
- return new ContentTransferEncodingField(name, body, raw, encoding);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/ContentTypeField.java b/src/org/apache/james/mime4j/field/ContentTypeField.java
deleted file mode 100644
index ad9f7f9..0000000
--- a/src/org/apache/james/mime4j/field/ContentTypeField.java
+++ /dev/null
@@ -1,259 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field;
-
-import java.io.StringReader;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-//BEGIN android-changed: Stubbing out logging
-import org.apache.james.mime4j.Log;
-import org.apache.james.mime4j.LogFactory;
-//END android-changed
-import org.apache.james.mime4j.field.contenttype.parser.ContentTypeParser;
-import org.apache.james.mime4j.field.contenttype.parser.ParseException;
-import org.apache.james.mime4j.field.contenttype.parser.TokenMgrError;
-
-/**
- * Represents a <code>Content-Type</code> field.
- *
- * <p>TODO: Remove dependency on Java 1.4 regexps</p>
- *
- *
- * @version $Id: ContentTypeField.java,v 1.6 2005/01/27 14:16:31 ntherning Exp $
- */
-public class ContentTypeField extends Field {
-
- /**
- * The prefix of all <code>multipart</code> MIME types.
- */
- public static final String TYPE_MULTIPART_PREFIX = "multipart/";
- /**
- * The <code>multipart/digest</code> MIME type.
- */
- public static final String TYPE_MULTIPART_DIGEST = "multipart/digest";
- /**
- * The <code>text/plain</code> MIME type.
- */
- public static final String TYPE_TEXT_PLAIN = "text/plain";
- /**
- * The <code>message/rfc822</code> MIME type.
- */
- public static final String TYPE_MESSAGE_RFC822 = "message/rfc822";
- /**
- * The name of the <code>boundary</code> parameter.
- */
- public static final String PARAM_BOUNDARY = "boundary";
- /**
- * The name of the <code>charset</code> parameter.
- */
- public static final String PARAM_CHARSET = "charset";
-
- private String mimeType = "";
- private Map<String, String> parameters = null;
- private ParseException parseException;
-
- protected ContentTypeField(String name, String body, String raw, String mimeType, Map<String, String> parameters, ParseException parseException) {
- super(name, body, raw);
- this.mimeType = mimeType;
- this.parameters = parameters;
- this.parseException = parseException;
- }
-
- /**
- * Gets the exception that was raised during parsing of
- * the field value, if any; otherwise, null.
- */
- public ParseException getParseException() {
- return parseException;
- }
-
- /**
- * Gets the MIME type defined in this Content-Type field.
- *
- * @return the MIME type or an empty string if not set.
- */
- public String getMimeType() {
- return mimeType;
- }
-
- /**
- * Gets the MIME type defined in the child's
- * Content-Type field or derives a MIME type from the parent
- * if child is <code>null</code> or hasn't got a MIME type value set.
- * If child's MIME type is multipart but no boundary
- * has been set the MIME type of child will be derived from
- * the parent.
- *
- * @param child the child.
- * @param parent the parent.
- * @return the MIME type.
- */
- public static String getMimeType(ContentTypeField child,
- ContentTypeField parent) {
-
- if (child == null || child.getMimeType().length() == 0
- || child.isMultipart() && child.getBoundary() == null) {
-
- if (parent != null && parent.isMimeType(TYPE_MULTIPART_DIGEST)) {
- return TYPE_MESSAGE_RFC822;
- } else {
- return TYPE_TEXT_PLAIN;
- }
- }
-
- return child.getMimeType();
- }
-
- /**
- * Gets the value of a parameter. Parameter names are case-insensitive.
- *
- * @param name the name of the parameter to get.
- * @return the parameter value or <code>null</code> if not set.
- */
- public String getParameter(String name) {
- return parameters != null
- ? parameters.get(name.toLowerCase())
- : null;
- }
-
- /**
- * Gets all parameters.
- *
- * @return the parameters.
- */
- public Map<String, String> getParameters() {
- if (parameters != null) {
- return Collections.unmodifiableMap(parameters);
- }
- return Collections.emptyMap();
- }
-
- /**
- * Gets the value of the <code>boundary</code> parameter if set.
- *
- * @return the <code>boundary</code> parameter value or <code>null</code>
- * if not set.
- */
- public String getBoundary() {
- return getParameter(PARAM_BOUNDARY);
- }
-
- /**
- * Gets the value of the <code>charset</code> parameter if set.
- *
- * @return the <code>charset</code> parameter value or <code>null</code>
- * if not set.
- */
- public String getCharset() {
- return getParameter(PARAM_CHARSET);
- }
-
- /**
- * Gets the value of the <code>charset</code> parameter if set for the
- * given field. Returns the default <code>us-ascii</code> if not set or if
- * <code>f</code> is <code>null</code>.
- *
- * @return the <code>charset</code> parameter value.
- */
- public static String getCharset(ContentTypeField f) {
- if (f != null) {
- if (f.getCharset() != null && f.getCharset().length() > 0) {
- return f.getCharset();
- }
- }
- return "us-ascii";
- }
-
- /**
- * Determines if the MIME type of this field matches the given one.
- *
- * @param mimeType the MIME type to match against.
- * @return <code>true</code> if the MIME type of this field matches,
- * <code>false</code> otherwise.
- */
- public boolean isMimeType(String mimeType) {
- return this.mimeType.equalsIgnoreCase(mimeType);
- }
-
- /**
- * Determines if the MIME type of this field is <code>multipart/*</code>.
- *
- * @return <code>true</code> if this field is has a <code>multipart/*</code>
- * MIME type, <code>false</code> otherwise.
- */
- public boolean isMultipart() {
- return mimeType.startsWith(TYPE_MULTIPART_PREFIX);
- }
-
- public static class Parser implements FieldParser {
- private static Log log = LogFactory.getLog(Parser.class);
-
- public Field parse(final String name, final String body, final String raw) {
- ParseException parseException = null;
- String mimeType = "";
- Map<String, String> parameters = null;
-
- ContentTypeParser parser = new ContentTypeParser(new StringReader(body));
- try {
- parser.parseAll();
- }
- catch (ParseException e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = e;
- }
- catch (TokenMgrError e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = new ParseException(e.getMessage());
- }
-
- try {
- final String type = parser.getType();
- final String subType = parser.getSubType();
-
- if (type != null && subType != null) {
- mimeType = (type + "/" + parser.getSubType()).toLowerCase();
-
- ArrayList<String> paramNames = parser.getParamNames();
- ArrayList<String> paramValues = parser.getParamValues();
-
- if (paramNames != null && paramValues != null) {
- for (int i = 0; i < paramNames.size() && i < paramValues.size(); i++) {
- if (parameters == null)
- parameters = new HashMap<String, String>((int)(paramNames.size() * 1.3 + 1));
- String paramName = paramNames.get(i).toLowerCase();
- String paramValue = paramValues.get(i);
- parameters.put(paramName, paramValue);
- }
- }
- }
- }
- catch (NullPointerException npe) {
- }
- return new ContentTypeField(name, body, raw, mimeType, parameters, parseException);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/DateTimeField.java b/src/org/apache/james/mime4j/field/DateTimeField.java
deleted file mode 100644
index 5215534..0000000
--- a/src/org/apache/james/mime4j/field/DateTimeField.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field;
-
-//BEGIN android-changed: Stubbing out logging
-
-import com.android.phone.common.mail.utils.LogUtils;
-
-import org.apache.james.mime4j.Log;
-import org.apache.james.mime4j.LogFactory;
-//END
-import org.apache.james.mime4j.field.datetime.DateTime;
-import org.apache.james.mime4j.field.datetime.parser.ParseException;
-
-import java.util.Date;
-
-public class DateTimeField extends Field {
- private Date date;
- private ParseException parseException;
-
- protected DateTimeField(String name, String body, String raw, Date date, ParseException parseException) {
- super(name, body, raw);
- this.date = date;
- this.parseException = parseException;
- }
-
- public Date getDate() {
- return date;
- }
-
- public ParseException getParseException() {
- return parseException;
- }
-
- public static class Parser implements FieldParser {
- private static Log log = LogFactory.getLog(Parser.class);
-
- public Field parse(final String name, String body, final String raw) {
- Date date = null;
- ParseException parseException = null;
- //BEGIN android-changed
- body = LogUtils.cleanUpMimeDate(body);
- //END android-changed
- try {
- date = DateTime.parse(body).getDate();
- }
- catch (ParseException e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = e;
- }
- return new DateTimeField(name, body, raw, date, parseException);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/DefaultFieldParser.java b/src/org/apache/james/mime4j/field/DefaultFieldParser.java
deleted file mode 100644
index 3695afe..0000000
--- a/src/org/apache/james/mime4j/field/DefaultFieldParser.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2006 the mime4j 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 org.apache.james.mime4j.field;
-
-public class DefaultFieldParser extends DelegatingFieldParser {
-
- public DefaultFieldParser() {
- setFieldParser(Field.CONTENT_TRANSFER_ENCODING, new ContentTransferEncodingField.Parser());
- setFieldParser(Field.CONTENT_TYPE, new ContentTypeField.Parser());
-
- final DateTimeField.Parser dateTimeParser = new DateTimeField.Parser();
- setFieldParser(Field.DATE, dateTimeParser);
- setFieldParser(Field.RESENT_DATE, dateTimeParser);
-
- final MailboxListField.Parser mailboxListParser = new MailboxListField.Parser();
- setFieldParser(Field.FROM, mailboxListParser);
- setFieldParser(Field.RESENT_FROM, mailboxListParser);
-
- final MailboxField.Parser mailboxParser = new MailboxField.Parser();
- setFieldParser(Field.SENDER, mailboxParser);
- setFieldParser(Field.RESENT_SENDER, mailboxParser);
-
- final AddressListField.Parser addressListParser = new AddressListField.Parser();
- setFieldParser(Field.TO, addressListParser);
- setFieldParser(Field.RESENT_TO, addressListParser);
- setFieldParser(Field.CC, addressListParser);
- setFieldParser(Field.RESENT_CC, addressListParser);
- setFieldParser(Field.BCC, addressListParser);
- setFieldParser(Field.RESENT_BCC, addressListParser);
- setFieldParser(Field.REPLY_TO, addressListParser);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/DelegatingFieldParser.java b/src/org/apache/james/mime4j/field/DelegatingFieldParser.java
deleted file mode 100644
index 32b69ec..0000000
--- a/src/org/apache/james/mime4j/field/DelegatingFieldParser.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2006 the mime4j 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 org.apache.james.mime4j.field;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class DelegatingFieldParser implements FieldParser {
-
- private Map<String, FieldParser> parsers = new HashMap<String, FieldParser>();
- private FieldParser defaultParser = new UnstructuredField.Parser();
-
- /**
- * Sets the parser used for the field named <code>name</code>.
- * @param name the name of the field
- * @param parser the parser for fields named <code>name</code>
- */
- public void setFieldParser(final String name, final FieldParser parser) {
- parsers.put(name.toLowerCase(), parser);
- }
-
- public FieldParser getParser(final String name) {
- final FieldParser field = parsers.get(name.toLowerCase());
- if(field==null) {
- return defaultParser;
- }
- return field;
- }
-
- public Field parse(final String name, final String body, final String raw) {
- final FieldParser parser = getParser(name);
- return parser.parse(name, body, raw);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/Field.java b/src/org/apache/james/mime4j/field/Field.java
deleted file mode 100644
index 4dea5c5..0000000
--- a/src/org/apache/james/mime4j/field/Field.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * The base class of all field classes.
- *
- *
- * @version $Id: Field.java,v 1.6 2004/10/25 07:26:46 ntherning Exp $
- */
-public abstract class Field {
- public static final String SENDER = "Sender";
- public static final String FROM = "From";
- public static final String TO = "To";
- public static final String CC = "Cc";
- public static final String BCC = "Bcc";
- public static final String REPLY_TO = "Reply-To";
- public static final String RESENT_SENDER = "Resent-Sender";
- public static final String RESENT_FROM = "Resent-From";
- public static final String RESENT_TO = "Resent-To";
- public static final String RESENT_CC = "Resent-Cc";
- public static final String RESENT_BCC = "Resent-Bcc";
-
- public static final String DATE = "Date";
- public static final String RESENT_DATE = "Resent-Date";
-
- public static final String SUBJECT = "Subject";
- public static final String CONTENT_TYPE = "Content-Type";
- public static final String CONTENT_TRANSFER_ENCODING =
- "Content-Transfer-Encoding";
-
- private static final String FIELD_NAME_PATTERN =
- "^([\\x21-\\x39\\x3b-\\x7e]+)[ \t]*:";
- private static final Pattern fieldNamePattern =
- Pattern.compile(FIELD_NAME_PATTERN);
-
- private static final DefaultFieldParser parser = new DefaultFieldParser();
-
- private final String name;
- private final String body;
- private final String raw;
-
- protected Field(final String name, final String body, final String raw) {
- this.name = name;
- this.body = body;
- this.raw = raw;
- }
-
- /**
- * Parses the given string and returns an instance of the
- * <code>Field</code> class. The type of the class returned depends on
- * the field name:
- * <table>
- * <tr>
- * <td><em>Field name</em></td><td><em>Class returned</em></td>
- * <td>Content-Type</td><td>org.apache.james.mime4j.field.ContentTypeField</td>
- * <td>other</td><td>org.apache.james.mime4j.field.UnstructuredField</td>
- * </tr>
- * </table>
- *
- * @param s the string to parse.
- * @return a <code>Field</code> instance.
- * @throws IllegalArgumentException on parse errors.
- */
- public static Field parse(final String raw) {
-
- /*
- * Unfold the field.
- */
- final String unfolded = raw.replaceAll("\r|\n", "");
-
- /*
- * Split into name and value.
- */
- final Matcher fieldMatcher = fieldNamePattern.matcher(unfolded);
- if (!fieldMatcher.find()) {
- throw new IllegalArgumentException("Invalid field in string");
- }
- final String name = fieldMatcher.group(1);
-
- String body = unfolded.substring(fieldMatcher.end());
- if (body.length() > 0 && body.charAt(0) == ' ') {
- body = body.substring(1);
- }
-
- return parser.parse(name, body, raw);
- }
-
- /**
- * Gets the default parser used to parse fields.
- * @return the default field parser
- */
- public static DefaultFieldParser getParser() {
- return parser;
- }
-
- /**
- * Gets the name of the field (<code>Subject</code>,
- * <code>From</code>, etc).
- *
- * @return the field name.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Gets the original raw field string.
- *
- * @return the original raw field string.
- */
- public String getRaw() {
- return raw;
- }
-
- /**
- * Gets the unfolded, unparsed and possibly encoded (see RFC 2047) field
- * body string.
- *
- * @return the unfolded unparsed field body string.
- */
- public String getBody() {
- return body;
- }
-
- /**
- * Determines if this is a <code>Content-Type</code> field.
- *
- * @return <code>true</code> if this is a <code>Content-Type</code> field,
- * <code>false</code> otherwise.
- */
- public boolean isContentType() {
- return CONTENT_TYPE.equalsIgnoreCase(name);
- }
-
- /**
- * Determines if this is a <code>Subject</code> field.
- *
- * @return <code>true</code> if this is a <code>Subject</code> field,
- * <code>false</code> otherwise.
- */
- public boolean isSubject() {
- return SUBJECT.equalsIgnoreCase(name);
- }
-
- /**
- * Determines if this is a <code>From</code> field.
- *
- * @return <code>true</code> if this is a <code>From</code> field,
- * <code>false</code> otherwise.
- */
- public boolean isFrom() {
- return FROM.equalsIgnoreCase(name);
- }
-
- /**
- * Determines if this is a <code>To</code> field.
- *
- * @return <code>true</code> if this is a <code>To</code> field,
- * <code>false</code> otherwise.
- */
- public boolean isTo() {
- return TO.equalsIgnoreCase(name);
- }
-
- /**
- * @see #getRaw()
- */
- public String toString() {
- return raw;
- }
-}
diff --git a/src/org/apache/james/mime4j/field/FieldParser.java b/src/org/apache/james/mime4j/field/FieldParser.java
deleted file mode 100644
index 78aaf13..0000000
--- a/src/org/apache/james/mime4j/field/FieldParser.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2006 the mime4j 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 org.apache.james.mime4j.field;
-
-public interface FieldParser {
-
- Field parse(final String name, final String body, final String raw);
-}
diff --git a/src/org/apache/james/mime4j/field/MailboxField.java b/src/org/apache/james/mime4j/field/MailboxField.java
deleted file mode 100644
index f159800..0000000
--- a/src/org/apache/james/mime4j/field/MailboxField.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field;
-
-//BEGIN android-changed: Stubbing out logging
-import org.apache.james.mime4j.Log;
-import org.apache.james.mime4j.LogFactory;
-//END android-changed
-import org.apache.james.mime4j.field.address.AddressList;
-import org.apache.james.mime4j.field.address.Mailbox;
-import org.apache.james.mime4j.field.address.MailboxList;
-import org.apache.james.mime4j.field.address.parser.ParseException;
-
-public class MailboxField extends Field {
- private final Mailbox mailbox;
- private final ParseException parseException;
-
- protected MailboxField(final String name, final String body, final String raw, final Mailbox mailbox, final ParseException parseException) {
- super(name, body, raw);
- this.mailbox = mailbox;
- this.parseException = parseException;
- }
-
- public Mailbox getMailbox() {
- return mailbox;
- }
-
- public ParseException getParseException() {
- return parseException;
- }
-
- public static class Parser implements FieldParser {
- private static Log log = LogFactory.getLog(Parser.class);
-
- public Field parse(final String name, final String body, final String raw) {
- Mailbox mailbox = null;
- ParseException parseException = null;
- try {
- MailboxList mailboxList = AddressList.parse(body).flatten();
- if (mailboxList.size() > 0) {
- mailbox = mailboxList.get(0);
- }
- }
- catch (ParseException e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = e;
- }
- return new MailboxField(name, body, raw, mailbox, parseException);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/MailboxListField.java b/src/org/apache/james/mime4j/field/MailboxListField.java
deleted file mode 100644
index 23378d4..0000000
--- a/src/org/apache/james/mime4j/field/MailboxListField.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field;
-
-//BEGIN android-changed: Stubbing out logging
-import org.apache.james.mime4j.Log;
-import org.apache.james.mime4j.LogFactory;
-//END android-changed
-import org.apache.james.mime4j.field.address.AddressList;
-import org.apache.james.mime4j.field.address.MailboxList;
-import org.apache.james.mime4j.field.address.parser.ParseException;
-
-public class MailboxListField extends Field {
-
- private MailboxList mailboxList;
- private ParseException parseException;
-
- protected MailboxListField(final String name, final String body, final String raw, final MailboxList mailboxList, final ParseException parseException) {
- super(name, body, raw);
- this.mailboxList = mailboxList;
- this.parseException = parseException;
- }
-
- public MailboxList getMailboxList() {
- return mailboxList;
- }
-
- public ParseException getParseException() {
- return parseException;
- }
-
- public static class Parser implements FieldParser {
- private static Log log = LogFactory.getLog(Parser.class);
-
- public Field parse(final String name, final String body, final String raw) {
- MailboxList mailboxList = null;
- ParseException parseException = null;
- try {
- mailboxList = AddressList.parse(body).flatten();
- }
- catch (ParseException e) {
- if (log.isDebugEnabled()) {
- log.debug("Parsing value '" + body + "': "+ e.getMessage());
- }
- parseException = e;
- }
- return new MailboxListField(name, body, raw, mailboxList, parseException);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/UnstructuredField.java b/src/org/apache/james/mime4j/field/UnstructuredField.java
deleted file mode 100644
index 6084e44..0000000
--- a/src/org/apache/james/mime4j/field/UnstructuredField.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field;
-
-import org.apache.james.mime4j.decoder.DecoderUtil;
-
-
-/**
- * Simple unstructured field such as <code>Subject</code>.
- *
- *
- * @version $Id: UnstructuredField.java,v 1.3 2004/10/25 07:26:46 ntherning Exp $
- */
-public class UnstructuredField extends Field {
- private String value;
-
- protected UnstructuredField(String name, String body, String raw, String value) {
- super(name, body, raw);
- this.value = value;
- }
-
- public String getValue() {
- return value;
- }
-
- public static class Parser implements FieldParser {
- public Field parse(final String name, final String body, final String raw) {
- final String value = DecoderUtil.decodeEncodedWords(body);
- return new UnstructuredField(name, body, raw, value);
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/Address.java b/src/org/apache/james/mime4j/field/address/Address.java
deleted file mode 100644
index 3e24e91..0000000
--- a/src/org/apache/james/mime4j/field/address/Address.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field.address;
-
-import java.util.ArrayList;
-
-/**
- * The abstract base for classes that represent RFC2822 addresses.
- * This includes groups and mailboxes.
- *
- * Currently, no public methods are introduced on this class.
- *
- *
- */
-public abstract class Address {
-
- /**
- * Adds any mailboxes represented by this address
- * into the given ArrayList. Note that this method
- * has default (package) access, so a doAddMailboxesTo
- * method is needed to allow the behavior to be
- * overridden by subclasses.
- */
- final void addMailboxesTo(ArrayList<Address> results) {
- doAddMailboxesTo(results);
- }
-
- /**
- * Adds any mailboxes represented by this address
- * into the given ArrayList. Must be overridden by
- * concrete subclasses.
- */
- protected abstract void doAddMailboxesTo(ArrayList<Address> results);
-
-}
diff --git a/src/org/apache/james/mime4j/field/address/AddressList.java b/src/org/apache/james/mime4j/field/address/AddressList.java
deleted file mode 100644
index 1829e79..0000000
--- a/src/org/apache/james/mime4j/field/address/AddressList.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field.address;
-
-import org.apache.james.mime4j.field.address.parser.AddressListParser;
-import org.apache.james.mime4j.field.address.parser.ParseException;
-
-import java.io.StringReader;
-import java.util.ArrayList;
-
-/**
- * An immutable, random-access list of Address objects.
- *
- *
- */
-public class AddressList {
-
- private ArrayList<Address> addresses;
-
- /**
- * @param addresses An ArrayList that contains only Address objects.
- * @param dontCopy true iff it is not possible for the addresses ArrayList to be modified by someone else.
- */
- public AddressList(ArrayList<Address> addresses, boolean dontCopy) {
- if (addresses != null)
- this.addresses = (dontCopy ? addresses : new ArrayList<Address>(addresses));
- else
- this.addresses = new ArrayList<Address>(0);
- }
-
- /**
- * The number of elements in this list.
- */
- public int size() {
- return addresses.size();
- }
-
- /**
- * Gets an address.
- */
- public Address get(int index) {
- if (0 > index || size() <= index)
- throw new IndexOutOfBoundsException();
- return addresses.get(index);
- }
-
- /**
- * Returns a flat list of all mailboxes represented
- * in this address list. Use this if you don't care
- * about grouping.
- */
- public MailboxList flatten() {
- // in the common case, all addresses are mailboxes
- boolean groupDetected = false;
- for (int i = 0; i < size(); i++) {
- if (!(get(i) instanceof Mailbox)) {
- groupDetected = true;
- break;
- }
- }
-
- if (!groupDetected)
- return new MailboxList(addresses, true);
-
- ArrayList<Address> results = new ArrayList<Address>();
- for (int i = 0; i < size(); i++) {
- Address addr = get(i);
- addr.addMailboxesTo(results);
- }
-
- // copy-on-construct this time, because subclasses
- // could have held onto a reference to the results
- return new MailboxList(results, false);
- }
-
- /**
- * Dumps a representation of this address list to
- * stdout, for debugging purposes.
- */
- public void print() {
- for (int i = 0; i < size(); i++) {
- Address addr = get(i);
- System.out.println(addr.toString());
- }
- }
-
- /**
- * Parse the address list string, such as the value
- * of a From, To, Cc, Bcc, Sender, or Reply-To
- * header.
- *
- * The string MUST be unfolded already.
- */
- public static AddressList parse(String rawAddressList) throws ParseException {
- AddressListParser parser = new AddressListParser(new StringReader(rawAddressList));
- return Builder.getInstance().buildAddressList(parser.parse());
- }
-
- /**
- * Test console.
- */
- public static void main(String[] args) throws Exception {
- java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
- while (true) {
- try {
- System.out.print("> ");
- String line = reader.readLine();
- if (line.length() == 0 || line.toLowerCase().equals("exit") || line.toLowerCase().equals("quit")) {
- System.out.println("Goodbye.");
- return;
- }
- AddressList list = parse(line);
- list.print();
- }
- catch(Exception e) {
- e.printStackTrace();
- Thread.sleep(300);
- }
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/Builder.java b/src/org/apache/james/mime4j/field/address/Builder.java
deleted file mode 100644
index 3bcd15b..0000000
--- a/src/org/apache/james/mime4j/field/address/Builder.java
+++ /dev/null
@@ -1,243 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field.address;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-
-import org.apache.james.mime4j.decoder.DecoderUtil;
-import org.apache.james.mime4j.field.address.parser.ASTaddr_spec;
-import org.apache.james.mime4j.field.address.parser.ASTaddress;
-import org.apache.james.mime4j.field.address.parser.ASTaddress_list;
-import org.apache.james.mime4j.field.address.parser.ASTangle_addr;
-import org.apache.james.mime4j.field.address.parser.ASTdomain;
-import org.apache.james.mime4j.field.address.parser.ASTgroup_body;
-import org.apache.james.mime4j.field.address.parser.ASTlocal_part;
-import org.apache.james.mime4j.field.address.parser.ASTmailbox;
-import org.apache.james.mime4j.field.address.parser.ASTname_addr;
-import org.apache.james.mime4j.field.address.parser.ASTphrase;
-import org.apache.james.mime4j.field.address.parser.ASTroute;
-import org.apache.james.mime4j.field.address.parser.Node;
-import org.apache.james.mime4j.field.address.parser.SimpleNode;
-import org.apache.james.mime4j.field.address.parser.Token;
-
-/**
- * Transforms the JJTree-generated abstract syntax tree
- * into a graph of org.apache.james.mime4j.field.address objects.
- *
- *
- */
-class Builder {
-
- private static Builder singleton = new Builder();
-
- public static Builder getInstance() {
- return singleton;
- }
-
-
-
- public AddressList buildAddressList(ASTaddress_list node) {
- ArrayList<Address> list = new ArrayList<Address>();
- for (int i = 0; i < node.jjtGetNumChildren(); i++) {
- ASTaddress childNode = (ASTaddress) node.jjtGetChild(i);
- Address address = buildAddress(childNode);
- list.add(address);
- }
- return new AddressList(list, true);
- }
-
- private Address buildAddress(ASTaddress node) {
- ChildNodeIterator it = new ChildNodeIterator(node);
- Node n = it.nextNode();
- if (n instanceof ASTaddr_spec) {
- return buildAddrSpec((ASTaddr_spec)n);
- }
- else if (n instanceof ASTangle_addr) {
- return buildAngleAddr((ASTangle_addr)n);
- }
- else if (n instanceof ASTphrase) {
- String name = buildString((ASTphrase)n, false);
- Node n2 = it.nextNode();
- if (n2 instanceof ASTgroup_body) {
- return new Group(name, buildGroupBody((ASTgroup_body)n2));
- }
- else if (n2 instanceof ASTangle_addr) {
- name = DecoderUtil.decodeEncodedWords(name);
- return new NamedMailbox(name, buildAngleAddr((ASTangle_addr)n2));
- }
- else {
- throw new IllegalStateException();
- }
- }
- else {
- throw new IllegalStateException();
- }
- }
-
-
-
- private MailboxList buildGroupBody(ASTgroup_body node) {
- ArrayList<Address> results = new ArrayList<Address>();
- ChildNodeIterator it = new ChildNodeIterator(node);
- while (it.hasNext()) {
- Node n = it.nextNode();
- if (n instanceof ASTmailbox)
- results.add(buildMailbox((ASTmailbox)n));
- else
- throw new IllegalStateException();
- }
- return new MailboxList(results, true);
- }
-
- private Mailbox buildMailbox(ASTmailbox node) {
- ChildNodeIterator it = new ChildNodeIterator(node);
- Node n = it.nextNode();
- if (n instanceof ASTaddr_spec) {
- return buildAddrSpec((ASTaddr_spec)n);
- }
- else if (n instanceof ASTangle_addr) {
- return buildAngleAddr((ASTangle_addr)n);
- }
- else if (n instanceof ASTname_addr) {
- return buildNameAddr((ASTname_addr)n);
- }
- else {
- throw new IllegalStateException();
- }
- }
-
- private NamedMailbox buildNameAddr(ASTname_addr node) {
- ChildNodeIterator it = new ChildNodeIterator(node);
- Node n = it.nextNode();
- String name;
- if (n instanceof ASTphrase) {
- name = buildString((ASTphrase)n, false);
- }
- else {
- throw new IllegalStateException();
- }
-
- n = it.nextNode();
- if (n instanceof ASTangle_addr) {
- name = DecoderUtil.decodeEncodedWords(name);
- return new NamedMailbox(name, buildAngleAddr((ASTangle_addr) n));
- }
- else {
- throw new IllegalStateException();
- }
- }
-
- private Mailbox buildAngleAddr(ASTangle_addr node) {
- ChildNodeIterator it = new ChildNodeIterator(node);
- DomainList route = null;
- Node n = it.nextNode();
- if (n instanceof ASTroute) {
- route = buildRoute((ASTroute)n);
- n = it.nextNode();
- }
- else if (n instanceof ASTaddr_spec)
- ; // do nothing
- else
- throw new IllegalStateException();
-
- if (n instanceof ASTaddr_spec)
- return buildAddrSpec(route, (ASTaddr_spec)n);
- else
- throw new IllegalStateException();
- }
-
- private DomainList buildRoute(ASTroute node) {
- ArrayList<String> results = new ArrayList<String>(node.jjtGetNumChildren());
- ChildNodeIterator it = new ChildNodeIterator(node);
- while (it.hasNext()) {
- Node n = it.nextNode();
- if (n instanceof ASTdomain)
- results.add(buildString((ASTdomain)n, true));
- else
- throw new IllegalStateException();
- }
- return new DomainList(results, true);
- }
-
- private Mailbox buildAddrSpec(ASTaddr_spec node) {
- return buildAddrSpec(null, node);
- }
- private Mailbox buildAddrSpec(DomainList route, ASTaddr_spec node) {
- ChildNodeIterator it = new ChildNodeIterator(node);
- String localPart = buildString((ASTlocal_part)it.nextNode(), true);
- String domain = buildString((ASTdomain)it.nextNode(), true);
- return new Mailbox(route, localPart, domain);
- }
-
-
- private String buildString(SimpleNode node, boolean stripSpaces) {
- Token head = node.firstToken;
- Token tail = node.lastToken;
- StringBuffer out = new StringBuffer();
-
- while (head != tail) {
- out.append(head.image);
- head = head.next;
- if (!stripSpaces)
- addSpecials(out, head.specialToken);
- }
- out.append(tail.image);
-
- return out.toString();
- }
-
- private void addSpecials(StringBuffer out, Token specialToken) {
- if (specialToken != null) {
- addSpecials(out, specialToken.specialToken);
- out.append(specialToken.image);
- }
- }
-
- private static class ChildNodeIterator implements Iterator<Node> {
-
- private SimpleNode simpleNode;
- private int index;
- private int len;
-
- public ChildNodeIterator(SimpleNode simpleNode) {
- this.simpleNode = simpleNode;
- this.len = simpleNode.jjtGetNumChildren();
- this.index = 0;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
-
- public boolean hasNext() {
- return index < len;
- }
-
- public Node next() {
- return nextNode();
- }
-
- public Node nextNode() {
- return simpleNode.jjtGetChild(index++);
- }
-
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/DomainList.java b/src/org/apache/james/mime4j/field/address/DomainList.java
deleted file mode 100644
index 49b0f3b..0000000
--- a/src/org/apache/james/mime4j/field/address/DomainList.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field.address;
-
-import java.util.ArrayList;
-
-/**
- * An immutable, random-access list of Strings (that
- * are supposedly domain names or domain literals).
- *
- *
- */
-public class DomainList {
- private ArrayList<String> domains;
-
- /**
- * @param domains An ArrayList that contains only String objects.
- * @param dontCopy true iff it is not possible for the domains ArrayList to be modified by someone else.
- */
- public DomainList(ArrayList<String> domains, boolean dontCopy) {
- if (domains != null)
- this.domains = (dontCopy ? domains : new ArrayList<String>(domains));
- else
- this.domains = new ArrayList<String>(0);
- }
-
- /**
- * The number of elements in this list.
- */
- public int size() {
- return domains.size();
- }
-
- /**
- * Gets the domain name or domain literal at the
- * specified index.
- * @throws IndexOutOfBoundsException If index is < 0 or >= size().
- */
- public String get(int index) {
- if (0 > index || size() <= index)
- throw new IndexOutOfBoundsException();
- return domains.get(index);
- }
-
- /**
- * Returns the list of domains formatted as a route
- * string (not including the trailing ':').
- */
- public String toRouteString() {
- StringBuffer out = new StringBuffer();
- for (int i = 0; i < domains.size(); i++) {
- out.append("@");
- out.append(get(i));
- if (i + 1 < domains.size())
- out.append(",");
- }
- return out.toString();
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/Group.java b/src/org/apache/james/mime4j/field/address/Group.java
deleted file mode 100644
index c0ab7f7..0000000
--- a/src/org/apache/james/mime4j/field/address/Group.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field.address;
-
-import java.util.ArrayList;
-
-/**
- * A named group of zero or more mailboxes.
- *
- *
- */
-public class Group extends Address {
- private String name;
- private MailboxList mailboxList;
-
- /**
- * @param name The group name.
- * @param mailboxes The mailboxes in this group.
- */
- public Group(String name, MailboxList mailboxes) {
- this.name = name;
- this.mailboxList = mailboxes;
- }
-
- /**
- * Returns the group name.
- */
- public String getName() {
- return name;
- }
-
- /**
- * Returns the mailboxes in this group.
- */
- public MailboxList getMailboxes() {
- return mailboxList;
- }
-
- @Override
- public String toString() {
- StringBuffer buf = new StringBuffer();
- buf.append(name);
- buf.append(":");
- for (int i = 0; i < mailboxList.size(); i++) {
- buf.append(mailboxList.get(i).toString());
- if (i + 1 < mailboxList.size())
- buf.append(",");
- }
- buf.append(";");
- return buf.toString();
- }
-
- @Override
- protected void doAddMailboxesTo(ArrayList<Address> results) {
- for (int i = 0; i < mailboxList.size(); i++)
- results.add(mailboxList.get(i));
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/Mailbox.java b/src/org/apache/james/mime4j/field/address/Mailbox.java
deleted file mode 100644
index 25f2548..0000000
--- a/src/org/apache/james/mime4j/field/address/Mailbox.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field.address;
-
-import java.util.ArrayList;
-
-/**
- * Represents a single e-mail address.
- *
- *
- */
-public class Mailbox extends Address {
- private DomainList route;
- private String localPart;
- private String domain;
-
- /**
- * Creates a mailbox without a route. Routes are obsolete.
- * @param localPart The part of the e-mail address to the left of the "@".
- * @param domain The part of the e-mail address to the right of the "@".
- */
- public Mailbox(String localPart, String domain) {
- this(null, localPart, domain);
- }
-
- /**
- * Creates a mailbox with a route. Routes are obsolete.
- * @param route The zero or more domains that make up the route. Can be null.
- * @param localPart The part of the e-mail address to the left of the "@".
- * @param domain The part of the e-mail address to the right of the "@".
- */
- public Mailbox(DomainList route, String localPart, String domain) {
- this.route = route;
- this.localPart = localPart;
- this.domain = domain;
- }
-
- /**
- * Returns the route list.
- */
- public DomainList getRoute() {
- return route;
- }
-
- /**
- * Returns the left part of the e-mail address
- * (before "@").
- */
- public String getLocalPart() {
- return localPart;
- }
-
- /**
- * Returns the right part of the e-mail address
- * (after "@").
- */
- public String getDomain() {
- return domain;
- }
-
- /**
- * Formats the address as a string, not including
- * the route.
- *
- * @see #getAddressString(boolean)
- */
- public String getAddressString() {
- return getAddressString(false);
- }
-
- /**
- * Note that this value may not be usable
- * for transport purposes, only display purposes.
- *
- * For example, if the unparsed address was
- *
- * <"Joe Cheng"@joecheng.com>
- *
- * this method would return
- *
- * <Joe Cheng@joecheng.com>
- *
- * which is not valid for transport; the local part
- * would need to be re-quoted.
- *
- * @param includeRoute true if the route should be included if it exists.
- */
- public String getAddressString(boolean includeRoute) {
- return "<" + (!includeRoute || route == null ? "" : route.toRouteString() + ":")
- + localPart
- + (domain == null ? "" : "@")
- + domain + ">";
- }
-
- @Override
- protected final void doAddMailboxesTo(ArrayList<Address> results) {
- results.add(this);
- }
-
- @Override
- public String toString() {
- return getAddressString();
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/MailboxList.java b/src/org/apache/james/mime4j/field/address/MailboxList.java
deleted file mode 100644
index 2c9efb3..0000000
--- a/src/org/apache/james/mime4j/field/address/MailboxList.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field.address;
-
-import java.util.ArrayList;
-
-/**
- * An immutable, random-access list of Mailbox objects.
- *
- *
- */
-public class MailboxList {
-
- private ArrayList<Address> mailboxes;
-
- /**
- * @param mailboxes An ArrayList that contains only Mailbox objects.
- * @param dontCopy true iff it is not possible for the mailboxes ArrayList to be modified by someone else.
- */
- public MailboxList(ArrayList<Address> mailboxes, boolean dontCopy) {
- if (mailboxes != null)
- this.mailboxes = (dontCopy ? mailboxes : new ArrayList<Address>(mailboxes));
- else
- this.mailboxes = new ArrayList<Address>(0);
- }
-
- /**
- * The number of elements in this list.
- */
- public int size() {
- return mailboxes.size();
- }
-
- /**
- * Gets an address.
- */
- public Mailbox get(int index) {
- if (0 > index || size() <= index)
- throw new IndexOutOfBoundsException();
- return (Mailbox)mailboxes.get(index);
- }
-
- /**
- * Dumps a representation of this mailbox list to
- * stdout, for debugging purposes.
- */
- public void print() {
- for (int i = 0; i < size(); i++) {
- Mailbox mailbox = get(i);
- System.out.println(mailbox.toString());
- }
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/address/NamedMailbox.java b/src/org/apache/james/mime4j/field/address/NamedMailbox.java
deleted file mode 100644
index 4b83060..0000000
--- a/src/org/apache/james/mime4j/field/address/NamedMailbox.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field.address;
-
-/**
- * A Mailbox that has a name/description.
- *
- *
- */
-public class NamedMailbox extends Mailbox {
- private String name;
-
- /**
- * @see Mailbox#Mailbox(String, String)
- */
- public NamedMailbox(String name, String localPart, String domain) {
- super(localPart, domain);
- this.name = name;
- }
-
- /**
- * @see Mailbox#Mailbox(DomainList, String, String)
- */
- public NamedMailbox(String name, DomainList route, String localPart, String domain) {
- super(route, localPart, domain);
- this.name = name;
- }
-
- /**
- * Creates a named mailbox based on an unnamed mailbox.
- */
- public NamedMailbox(String name, Mailbox baseMailbox) {
- super(baseMailbox.getRoute(), baseMailbox.getLocalPart(), baseMailbox.getDomain());
- this.name = name;
- }
-
- /**
- * Returns the name of the mailbox.
- */
- public String getName() {
- return this.name;
- }
-
- /**
- * Same features (or problems) as Mailbox.getAddressString(boolean),
- * only more so.
- *
- * @see Mailbox#getAddressString(boolean)
- */
- @Override
- public String getAddressString(boolean includeRoute) {
- return (name == null ? "" : name + " ") + super.getAddressString(includeRoute);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java b/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java
deleted file mode 100644
index 4d56d00..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTaddr_spec.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTaddr_spec.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTaddr_spec extends SimpleNode {
- public ASTaddr_spec(int id) {
- super(id);
- }
-
- public ASTaddr_spec(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java b/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java
deleted file mode 100644
index 47bdeda..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTaddress.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTaddress.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTaddress extends SimpleNode {
- public ASTaddress(int id) {
- super(id);
- }
-
- public ASTaddress(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java b/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java
deleted file mode 100644
index 737840e..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTaddress_list.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTaddress_list.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTaddress_list extends SimpleNode {
- public ASTaddress_list(int id) {
- super(id);
- }
-
- public ASTaddress_list(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java b/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java
deleted file mode 100644
index 8cb8f42..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTangle_addr.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTangle_addr.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTangle_addr extends SimpleNode {
- public ASTangle_addr(int id) {
- super(id);
- }
-
- public ASTangle_addr(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java b/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java
deleted file mode 100644
index b526643..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTdomain.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTdomain.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTdomain extends SimpleNode {
- public ASTdomain(int id) {
- super(id);
- }
-
- public ASTdomain(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java b/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java
deleted file mode 100644
index f6017b9..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTgroup_body.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTgroup_body.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTgroup_body extends SimpleNode {
- public ASTgroup_body(int id) {
- super(id);
- }
-
- public ASTgroup_body(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java b/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java
deleted file mode 100644
index 5c244fa..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTlocal_part.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTlocal_part.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTlocal_part extends SimpleNode {
- public ASTlocal_part(int id) {
- super(id);
- }
-
- public ASTlocal_part(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java b/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java
deleted file mode 100644
index aeb469d..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTmailbox.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTmailbox.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTmailbox extends SimpleNode {
- public ASTmailbox(int id) {
- super(id);
- }
-
- public ASTmailbox(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java b/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java
deleted file mode 100644
index 846c731..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTname_addr.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTname_addr.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTname_addr extends SimpleNode {
- public ASTname_addr(int id) {
- super(id);
- }
-
- public ASTname_addr(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java b/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java
deleted file mode 100644
index 7d711c5..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTphrase.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTphrase.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTphrase extends SimpleNode {
- public ASTphrase(int id) {
- super(id);
- }
-
- public ASTphrase(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ASTroute.java b/src/org/apache/james/mime4j/field/address/parser/ASTroute.java
deleted file mode 100644
index 54ea115..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ASTroute.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. ASTroute.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class ASTroute extends SimpleNode {
- public ASTroute(int id) {
- super(id);
- }
-
- public ASTroute(AddressListParser p, int id) {
- super(p, id);
- }
-
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java
deleted file mode 100644
index 8094df0..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.java
+++ /dev/null
@@ -1,977 +0,0 @@
-/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParser.java */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.address.parser;
-
-public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeConstants, AddressListParserConstants {/*@bgen(jjtree)*/
- protected JJTAddressListParserState jjtree = new JJTAddressListParserState();public static void main(String args[]) throws ParseException {
- while (true) {
- try {
- AddressListParser parser = new AddressListParser(System.in);
- parser.parseLine();
- ((SimpleNode)parser.jjtree.rootNode()).dump("> ");
- } catch (Exception x) {
- x.printStackTrace();
- return;
- }
- }
- }
-
- private static void log(String msg) {
- System.out.print(msg);
- }
-
- public ASTaddress_list parse() throws ParseException {
- try {
- parseAll();
- return (ASTaddress_list)jjtree.rootNode();
- } catch (TokenMgrError tme) {
- throw new ParseException(tme.getMessage());
- }
- }
-
-
- void jjtreeOpenNodeScope(Node n) {
- ((SimpleNode)n).firstToken = getToken(1);
- }
-
- void jjtreeCloseNodeScope(Node n) {
- ((SimpleNode)n).lastToken = getToken(0);
- }
-
- final public void parseLine() throws ParseException {
- address_list();
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 1:
- jj_consume_token(1);
- break;
- default:
- jj_la1[0] = jj_gen;
- ;
- }
- jj_consume_token(2);
- }
-
- final public void parseAll() throws ParseException {
- address_list();
- jj_consume_token(0);
- }
-
- final public void address_list() throws ParseException {
- /*@bgen(jjtree) address_list */
- ASTaddress_list jjtn000 = new ASTaddress_list(JJTADDRESS_LIST);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
- try {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 6:
- case DOTATOM:
- case QUOTEDSTRING:
- address();
- break;
- default:
- jj_la1[1] = jj_gen;
- ;
- }
- label_1:
- while (true) {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 3:
- ;
- break;
- default:
- jj_la1[2] = jj_gen;
- break label_1;
- }
- jj_consume_token(3);
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 6:
- case DOTATOM:
- case QUOTEDSTRING:
- address();
- break;
- default:
- jj_la1[3] = jj_gen;
- ;
- }
- }
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- {if (true) throw (RuntimeException)jjte000;}
- }
- if (jjte000 instanceof ParseException) {
- {if (true) throw (ParseException)jjte000;}
- }
- {if (true) throw (Error)jjte000;}
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final public void address() throws ParseException {
- /*@bgen(jjtree) address */
- ASTaddress jjtn000 = new ASTaddress(JJTADDRESS);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
- try {
- if (jj_2_1(2147483647)) {
- addr_spec();
- } else {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 6:
- angle_addr();
- break;
- case DOTATOM:
- case QUOTEDSTRING:
- phrase();
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 4:
- group_body();
- break;
- case 6:
- angle_addr();
- break;
- default:
- jj_la1[4] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- break;
- default:
- jj_la1[5] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- {if (true) throw (RuntimeException)jjte000;}
- }
- if (jjte000 instanceof ParseException) {
- {if (true) throw (ParseException)jjte000;}
- }
- {if (true) throw (Error)jjte000;}
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final public void mailbox() throws ParseException {
- /*@bgen(jjtree) mailbox */
- ASTmailbox jjtn000 = new ASTmailbox(JJTMAILBOX);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
- try {
- if (jj_2_2(2147483647)) {
- addr_spec();
- } else {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 6:
- angle_addr();
- break;
- case DOTATOM:
- case QUOTEDSTRING:
- name_addr();
- break;
- default:
- jj_la1[6] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- {if (true) throw (RuntimeException)jjte000;}
- }
- if (jjte000 instanceof ParseException) {
- {if (true) throw (ParseException)jjte000;}
- }
- {if (true) throw (Error)jjte000;}
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final public void name_addr() throws ParseException {
- /*@bgen(jjtree) name_addr */
- ASTname_addr jjtn000 = new ASTname_addr(JJTNAME_ADDR);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
- try {
- phrase();
- angle_addr();
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- {if (true) throw (RuntimeException)jjte000;}
- }
- if (jjte000 instanceof ParseException) {
- {if (true) throw (ParseException)jjte000;}
- }
- {if (true) throw (Error)jjte000;}
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final public void group_body() throws ParseException {
- /*@bgen(jjtree) group_body */
- ASTgroup_body jjtn000 = new ASTgroup_body(JJTGROUP_BODY);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
- try {
- jj_consume_token(4);
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 6:
- case DOTATOM:
- case QUOTEDSTRING:
- mailbox();
- break;
- default:
- jj_la1[7] = jj_gen;
- ;
- }
- label_2:
- while (true) {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 3:
- ;
- break;
- default:
- jj_la1[8] = jj_gen;
- break label_2;
- }
- jj_consume_token(3);
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 6:
- case DOTATOM:
- case QUOTEDSTRING:
- mailbox();
- break;
- default:
- jj_la1[9] = jj_gen;
- ;
- }
- }
- jj_consume_token(5);
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- {if (true) throw (RuntimeException)jjte000;}
- }
- if (jjte000 instanceof ParseException) {
- {if (true) throw (ParseException)jjte000;}
- }
- {if (true) throw (Error)jjte000;}
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final public void angle_addr() throws ParseException {
- /*@bgen(jjtree) angle_addr */
- ASTangle_addr jjtn000 = new ASTangle_addr(JJTANGLE_ADDR);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
- try {
- jj_consume_token(6);
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 8:
- route();
- break;
- default:
- jj_la1[10] = jj_gen;
- ;
- }
- addr_spec();
- jj_consume_token(7);
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- {if (true) throw (RuntimeException)jjte000;}
- }
- if (jjte000 instanceof ParseException) {
- {if (true) throw (ParseException)jjte000;}
- }
- {if (true) throw (Error)jjte000;}
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final public void route() throws ParseException {
- /*@bgen(jjtree) route */
- ASTroute jjtn000 = new ASTroute(JJTROUTE);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
- try {
- jj_consume_token(8);
- domain();
- label_3:
- while (true) {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 3:
- case 8:
- ;
- break;
- default:
- jj_la1[11] = jj_gen;
- break label_3;
- }
- label_4:
- while (true) {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 3:
- ;
- break;
- default:
- jj_la1[12] = jj_gen;
- break label_4;
- }
- jj_consume_token(3);
- }
- jj_consume_token(8);
- domain();
- }
- jj_consume_token(4);
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- {if (true) throw (RuntimeException)jjte000;}
- }
- if (jjte000 instanceof ParseException) {
- {if (true) throw (ParseException)jjte000;}
- }
- {if (true) throw (Error)jjte000;}
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final public void phrase() throws ParseException {
- /*@bgen(jjtree) phrase */
- ASTphrase jjtn000 = new ASTphrase(JJTPHRASE);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
- try {
- label_5:
- while (true) {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case DOTATOM:
- jj_consume_token(DOTATOM);
- break;
- case QUOTEDSTRING:
- jj_consume_token(QUOTEDSTRING);
- break;
- default:
- jj_la1[13] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case DOTATOM:
- case QUOTEDSTRING:
- ;
- break;
- default:
- jj_la1[14] = jj_gen;
- break label_5;
- }
- }
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final public void addr_spec() throws ParseException {
- /*@bgen(jjtree) addr_spec */
- ASTaddr_spec jjtn000 = new ASTaddr_spec(JJTADDR_SPEC);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
- try {
- local_part();
- jj_consume_token(8);
- domain();
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- {if (true) throw (RuntimeException)jjte000;}
- }
- if (jjte000 instanceof ParseException) {
- {if (true) throw (ParseException)jjte000;}
- }
- {if (true) throw (Error)jjte000;}
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final public void local_part() throws ParseException {
- /*@bgen(jjtree) local_part */
- ASTlocal_part jjtn000 = new ASTlocal_part(JJTLOCAL_PART);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);Token t;
- try {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case DOTATOM:
- t = jj_consume_token(DOTATOM);
- break;
- case QUOTEDSTRING:
- t = jj_consume_token(QUOTEDSTRING);
- break;
- default:
- jj_la1[15] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- label_6:
- while (true) {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 9:
- case DOTATOM:
- case QUOTEDSTRING:
- ;
- break;
- default:
- jj_la1[16] = jj_gen;
- break label_6;
- }
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 9:
- t = jj_consume_token(9);
- break;
- default:
- jj_la1[17] = jj_gen;
- ;
- }
- if (t.image.charAt(t.image.length() - 1) != '.' || t.kind == AddressListParserConstants.QUOTEDSTRING)
- {if (true) throw new ParseException("Words in local part must be separated by '.'");}
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case DOTATOM:
- t = jj_consume_token(DOTATOM);
- break;
- case QUOTEDSTRING:
- t = jj_consume_token(QUOTEDSTRING);
- break;
- default:
- jj_la1[18] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- }
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final public void domain() throws ParseException {
- /*@bgen(jjtree) domain */
- ASTdomain jjtn000 = new ASTdomain(JJTDOMAIN);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);Token t;
- try {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case DOTATOM:
- t = jj_consume_token(DOTATOM);
- label_7:
- while (true) {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 9:
- case DOTATOM:
- ;
- break;
- default:
- jj_la1[19] = jj_gen;
- break label_7;
- }
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 9:
- t = jj_consume_token(9);
- break;
- default:
- jj_la1[20] = jj_gen;
- ;
- }
- if (t.image.charAt(t.image.length() - 1) != '.')
- {if (true) throw new ParseException("Atoms in domain names must be separated by '.'");}
- t = jj_consume_token(DOTATOM);
- }
- break;
- case DOMAINLITERAL:
- jj_consume_token(DOMAINLITERAL);
- break;
- default:
- jj_la1[21] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
- }
-
- final private boolean jj_2_1(int xla) {
- jj_la = xla; jj_lastpos = jj_scanpos = token;
- try { return !jj_3_1(); }
- catch(LookaheadSuccess ls) { return true; }
- finally { jj_save(0, xla); }
- }
-
- final private boolean jj_2_2(int xla) {
- jj_la = xla; jj_lastpos = jj_scanpos = token;
- try { return !jj_3_2(); }
- catch(LookaheadSuccess ls) { return true; }
- finally { jj_save(1, xla); }
- }
-
- final private boolean jj_3R_11() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_scan_token(9)) jj_scanpos = xsp;
- xsp = jj_scanpos;
- if (jj_scan_token(14)) {
- jj_scanpos = xsp;
- if (jj_scan_token(31)) return true;
- }
- return false;
- }
-
- final private boolean jj_3R_13() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_scan_token(9)) jj_scanpos = xsp;
- if (jj_scan_token(DOTATOM)) return true;
- return false;
- }
-
- final private boolean jj_3R_8() {
- if (jj_3R_9()) return true;
- if (jj_scan_token(8)) return true;
- if (jj_3R_10()) return true;
- return false;
- }
-
- final private boolean jj_3_1() {
- if (jj_3R_8()) return true;
- return false;
- }
-
- final private boolean jj_3R_12() {
- if (jj_scan_token(DOTATOM)) return true;
- Token xsp;
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_13()) { jj_scanpos = xsp; break; }
- }
- return false;
- }
-
- final private boolean jj_3R_10() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3R_12()) {
- jj_scanpos = xsp;
- if (jj_scan_token(18)) return true;
- }
- return false;
- }
-
- final private boolean jj_3_2() {
- if (jj_3R_8()) return true;
- return false;
- }
-
- final private boolean jj_3R_9() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_scan_token(14)) {
- jj_scanpos = xsp;
- if (jj_scan_token(31)) return true;
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_11()) { jj_scanpos = xsp; break; }
- }
- return false;
- }
-
- public AddressListParserTokenManager token_source;
- SimpleCharStream jj_input_stream;
- public Token token, jj_nt;
- private int jj_ntk;
- private Token jj_scanpos, jj_lastpos;
- private int jj_la;
- public boolean lookingAhead = false;
- private boolean jj_semLA;
- private int jj_gen;
- final private int[] jj_la1 = new int[22];
- static private int[] jj_la1_0;
- static private int[] jj_la1_1;
- static {
- jj_la1_0();
- jj_la1_1();
- }
- private static void jj_la1_0() {
- jj_la1_0 = new int[] {0x2,0x80004040,0x8,0x80004040,0x50,0x80004040,0x80004040,0x80004040,0x8,0x80004040,0x100,0x108,0x8,0x80004000,0x80004000,0x80004000,0x80004200,0x200,0x80004000,0x4200,0x200,0x44000,};
- }
- private static void jj_la1_1() {
- jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,};
- }
- final private JJCalls[] jj_2_rtns = new JJCalls[2];
- private boolean jj_rescan = false;
- private int jj_gc = 0;
-
- public AddressListParser(java.io.InputStream stream) {
- this(stream, null);
- }
- public AddressListParser(java.io.InputStream stream, String encoding) {
- try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
- token_source = new AddressListParserTokenManager(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 22; i++) jj_la1[i] = -1;
- for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
- }
-
- public void ReInit(java.io.InputStream stream) {
- ReInit(stream, null);
- }
- public void ReInit(java.io.InputStream stream, String encoding) {
- try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
- token_source.ReInit(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jjtree.reset();
- jj_gen = 0;
- for (int i = 0; i < 22; i++) jj_la1[i] = -1;
- for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
- }
-
- public AddressListParser(java.io.Reader stream) {
- jj_input_stream = new SimpleCharStream(stream, 1, 1);
- token_source = new AddressListParserTokenManager(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 22; i++) jj_la1[i] = -1;
- for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
- }
-
- public void ReInit(java.io.Reader stream) {
- jj_input_stream.ReInit(stream, 1, 1);
- token_source.ReInit(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jjtree.reset();
- jj_gen = 0;
- for (int i = 0; i < 22; i++) jj_la1[i] = -1;
- for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
- }
-
- public AddressListParser(AddressListParserTokenManager tm) {
- token_source = tm;
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 22; i++) jj_la1[i] = -1;
- for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
- }
-
- public void ReInit(AddressListParserTokenManager tm) {
- token_source = tm;
- token = new Token();
- jj_ntk = -1;
- jjtree.reset();
- jj_gen = 0;
- for (int i = 0; i < 22; i++) jj_la1[i] = -1;
- for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls();
- }
-
- final private Token jj_consume_token(int kind) throws ParseException {
- Token oldToken;
- if ((oldToken = token).next != null) token = token.next;
- else token = token.next = token_source.getNextToken();
- jj_ntk = -1;
- if (token.kind == kind) {
- jj_gen++;
- if (++jj_gc > 100) {
- jj_gc = 0;
- for (int i = 0; i < jj_2_rtns.length; i++) {
- JJCalls c = jj_2_rtns[i];
- while (c != null) {
- if (c.gen < jj_gen) c.first = null;
- c = c.next;
- }
- }
- }
- return token;
- }
- token = oldToken;
- jj_kind = kind;
- throw generateParseException();
- }
-
- static private final class LookaheadSuccess extends java.lang.Error { }
- final private LookaheadSuccess jj_ls = new LookaheadSuccess();
- final private boolean jj_scan_token(int kind) {
- if (jj_scanpos == jj_lastpos) {
- jj_la--;
- if (jj_scanpos.next == null) {
- jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken();
- } else {
- jj_lastpos = jj_scanpos = jj_scanpos.next;
- }
- } else {
- jj_scanpos = jj_scanpos.next;
- }
- if (jj_rescan) {
- int i = 0; Token tok = token;
- while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; }
- if (tok != null) jj_add_error_token(kind, i);
- }
- if (jj_scanpos.kind != kind) return true;
- if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls;
- return false;
- }
-
- final public Token getNextToken() {
- if (token.next != null) token = token.next;
- else token = token.next = token_source.getNextToken();
- jj_ntk = -1;
- jj_gen++;
- return token;
- }
-
- final public Token getToken(int index) {
- Token t = lookingAhead ? jj_scanpos : token;
- for (int i = 0; i < index; i++) {
- if (t.next != null) t = t.next;
- else t = t.next = token_source.getNextToken();
- }
- return t;
- }
-
- final private int jj_ntk() {
- if ((jj_nt=token.next) == null)
- return (jj_ntk = (token.next=token_source.getNextToken()).kind);
- else
- return (jj_ntk = jj_nt.kind);
- }
-
- private java.util.Vector<int[]> jj_expentries = new java.util.Vector<int[]>();
- private int[] jj_expentry;
- private int jj_kind = -1;
- private int[] jj_lasttokens = new int[100];
- private int jj_endpos;
-
- private void jj_add_error_token(int kind, int pos) {
- if (pos >= 100) return;
- if (pos == jj_endpos + 1) {
- jj_lasttokens[jj_endpos++] = kind;
- } else if (jj_endpos != 0) {
- jj_expentry = new int[jj_endpos];
- for (int i = 0; i < jj_endpos; i++) {
- jj_expentry[i] = jj_lasttokens[i];
- }
- boolean exists = false;
- for (java.util.Enumeration<int[]> e = jj_expentries.elements(); e.hasMoreElements();) {
- int[] oldentry = e.nextElement();
- if (oldentry.length == jj_expentry.length) {
- exists = true;
- for (int i = 0; i < jj_expentry.length; i++) {
- if (oldentry[i] != jj_expentry[i]) {
- exists = false;
- break;
- }
- }
- if (exists) break;
- }
- }
- if (!exists) jj_expentries.addElement(jj_expentry);
- if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind;
- }
- }
-
- public ParseException generateParseException() {
- jj_expentries.removeAllElements();
- boolean[] la1tokens = new boolean[34];
- for (int i = 0; i < 34; i++) {
- la1tokens[i] = false;
- }
- if (jj_kind >= 0) {
- la1tokens[jj_kind] = true;
- jj_kind = -1;
- }
- for (int i = 0; i < 22; i++) {
- if (jj_la1[i] == jj_gen) {
- for (int j = 0; j < 32; j++) {
- if ((jj_la1_0[i] & (1<<j)) != 0) {
- la1tokens[j] = true;
- }
- if ((jj_la1_1[i] & (1<<j)) != 0) {
- la1tokens[32+j] = true;
- }
- }
- }
- }
- for (int i = 0; i < 34; i++) {
- if (la1tokens[i]) {
- jj_expentry = new int[1];
- jj_expentry[0] = i;
- jj_expentries.addElement(jj_expentry);
- }
- }
- jj_endpos = 0;
- jj_rescan_token();
- jj_add_error_token(0, 0);
- int[][] exptokseq = new int[jj_expentries.size()][];
- for (int i = 0; i < jj_expentries.size(); i++) {
- exptokseq[i] = jj_expentries.elementAt(i);
- }
- return new ParseException(token, exptokseq, tokenImage);
- }
-
- final public void enable_tracing() {
- }
-
- final public void disable_tracing() {
- }
-
- final private void jj_rescan_token() {
- jj_rescan = true;
- for (int i = 0; i < 2; i++) {
- try {
- JJCalls p = jj_2_rtns[i];
- do {
- if (p.gen > jj_gen) {
- jj_la = p.arg; jj_lastpos = jj_scanpos = p.first;
- switch (i) {
- case 0: jj_3_1(); break;
- case 1: jj_3_2(); break;
- }
- }
- p = p.next;
- } while (p != null);
- } catch(LookaheadSuccess ls) { }
- }
- jj_rescan = false;
- }
-
- final private void jj_save(int index, int xla) {
- JJCalls p = jj_2_rtns[index];
- while (p.gen > jj_gen) {
- if (p.next == null) { p = p.next = new JJCalls(); break; }
- p = p.next;
- }
- p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla;
- }
-
- static final class JJCalls {
- int gen;
- Token first;
- int arg;
- JJCalls next;
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj b/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj
deleted file mode 100644
index c14277b..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParser.jj
+++ /dev/null
@@ -1,595 +0,0 @@
-/*@bgen(jjtree) Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParser.jj */
-/*@egen*//****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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. *
- ****************************************************************/
-
-
-/**
- * RFC2822 address list parser.
- *
- * Created 9/17/2004
- * by Joe Cheng <code@joecheng.com>
- */
-
-options {
- STATIC=false;
- LOOKAHEAD=1;
- //DEBUG_PARSER=true;
- //DEBUG_TOKEN_MANAGER=true;
-}
-
-PARSER_BEGIN(AddressListParser)
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.address.parser;
-
-public class AddressListParser/*@bgen(jjtree)*/implements AddressListParserTreeConstants/*@egen*/ {/*@bgen(jjtree)*/
- protected JJTAddressListParserState jjtree = new JJTAddressListParserState();
-
-/*@egen*/
- public static void main(String args[]) throws ParseException {
- while (true) {
- try {
- AddressListParser parser = new AddressListParser(System.in);
- parser.parseLine();
- ((SimpleNode)parser.jjtree.rootNode()).dump("> ");
- } catch (Exception x) {
- x.printStackTrace();
- return;
- }
- }
- }
-
- private static void log(String msg) {
- System.out.print(msg);
- }
-
- public ASTaddress_list parse() throws ParseException {
- try {
- parseAll();
- return (ASTaddress_list)jjtree.rootNode();
- } catch (TokenMgrError tme) {
- throw new ParseException(tme.getMessage());
- }
- }
-
-
- void jjtreeOpenNodeScope(Node n) {
- ((SimpleNode)n).firstToken = getToken(1);
- }
-
- void jjtreeCloseNodeScope(Node n) {
- ((SimpleNode)n).lastToken = getToken(0);
- }
-}
-
-PARSER_END(AddressListParser)
-
-void parseLine() :
-{}
-{
- address_list() ["\r"] "\n"
-}
-
-void parseAll() :
-{}
-{
- address_list() <EOF>
-}
-
-void address_list() :
-{/*@bgen(jjtree) address_list */
- ASTaddress_list jjtn000 = new ASTaddress_list(JJTADDRESS_LIST);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) address_list */
- try {
-/*@egen*/
- [ address() ]
- (
- ","
- [ address() ]
- )*/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void address() :
-{/*@bgen(jjtree) address */
- ASTaddress jjtn000 = new ASTaddress(JJTADDRESS);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) address */
- try {
-/*@egen*/
- LOOKAHEAD(2147483647)
- addr_spec()
-| angle_addr()
-| ( phrase() (group_body() | angle_addr()) )/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void mailbox() :
-{/*@bgen(jjtree) mailbox */
- ASTmailbox jjtn000 = new ASTmailbox(JJTMAILBOX);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) mailbox */
- try {
-/*@egen*/
- LOOKAHEAD(2147483647)
- addr_spec()
-| angle_addr()
-| name_addr()/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void name_addr() :
-{/*@bgen(jjtree) name_addr */
- ASTname_addr jjtn000 = new ASTname_addr(JJTNAME_ADDR);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) name_addr */
- try {
-/*@egen*/
- phrase() angle_addr()/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void group_body() :
-{/*@bgen(jjtree) group_body */
- ASTgroup_body jjtn000 = new ASTgroup_body(JJTGROUP_BODY);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) group_body */
- try {
-/*@egen*/
- ":"
- [ mailbox() ]
- (
- ","
- [ mailbox() ]
- )*
- ";"/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void angle_addr() :
-{/*@bgen(jjtree) angle_addr */
- ASTangle_addr jjtn000 = new ASTangle_addr(JJTANGLE_ADDR);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) angle_addr */
- try {
-/*@egen*/
- "<" [ route() ] addr_spec() ">"/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void route() :
-{/*@bgen(jjtree) route */
- ASTroute jjtn000 = new ASTroute(JJTROUTE);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) route */
- try {
-/*@egen*/
- "@" domain() ( (",")* "@" domain() )* ":"/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void phrase() :
-{/*@bgen(jjtree) phrase */
- ASTphrase jjtn000 = new ASTphrase(JJTPHRASE);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) phrase */
-try {
-/*@egen*/
-( <DOTATOM>
-| <QUOTEDSTRING>
-)+/*@bgen(jjtree)*/
-} finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
-}
-/*@egen*/
-}
-
-void addr_spec() :
-{/*@bgen(jjtree) addr_spec */
- ASTaddr_spec jjtn000 = new ASTaddr_spec(JJTADDR_SPEC);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/}
-{/*@bgen(jjtree) addr_spec */
- try {
-/*@egen*/
- ( local_part() "@" domain() )/*@bgen(jjtree)*/
- } catch (Throwable jjte000) {
- if (jjtc000) {
- jjtree.clearNodeScope(jjtn000);
- jjtc000 = false;
- } else {
- jjtree.popNode();
- }
- if (jjte000 instanceof RuntimeException) {
- throw (RuntimeException)jjte000;
- }
- if (jjte000 instanceof ParseException) {
- throw (ParseException)jjte000;
- }
- throw (Error)jjte000;
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void local_part() :
-{/*@bgen(jjtree) local_part */
- ASTlocal_part jjtn000 = new ASTlocal_part(JJTLOCAL_PART);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/ Token t; }
-{/*@bgen(jjtree) local_part */
- try {
-/*@egen*/
- ( t=<DOTATOM> | t=<QUOTEDSTRING> )
- ( [t="."]
- {
- if (t.image.charAt(t.image.length() - 1) != '.' || t.kind == AddressListParserConstants.QUOTEDSTRING)
- throw new ParseException("Words in local part must be separated by '.'");
- }
- ( t=<DOTATOM> | t=<QUOTEDSTRING> )
- )*/*@bgen(jjtree)*/
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-void domain() :
-{/*@bgen(jjtree) domain */
- ASTdomain jjtn000 = new ASTdomain(JJTDOMAIN);
- boolean jjtc000 = true;
- jjtree.openNodeScope(jjtn000);
- jjtreeOpenNodeScope(jjtn000);
-/*@egen*/ Token t; }
-{/*@bgen(jjtree) domain */
- try {
-/*@egen*/
- ( t=<DOTATOM>
- ( [t="."]
- {
- if (t.image.charAt(t.image.length() - 1) != '.')
- throw new ParseException("Atoms in domain names must be separated by '.'");
- }
- t=<DOTATOM>
- )*
- )
-| <DOMAINLITERAL>/*@bgen(jjtree)*/
- } finally {
- if (jjtc000) {
- jjtree.closeNodeScope(jjtn000, true);
- jjtreeCloseNodeScope(jjtn000);
- }
- }
-/*@egen*/
-}
-
-SPECIAL_TOKEN :
-{
- < WS: ( [" ", "\t"] )+ >
-}
-
-TOKEN :
-{
- < #ALPHA: ["a" - "z", "A" - "Z"] >
-| < #DIGIT: ["0" - "9"] >
-| < #ATEXT: ( <ALPHA> | <DIGIT>
- | "!" | "#" | "$" | "%"
- | "&" | "'" | "*" | "+"
- | "-" | "/" | "=" | "?"
- | "^" | "_" | "`" | "{"
- | "|" | "}" | "~"
- )>
-| < DOTATOM: <ATEXT> ( <ATEXT> | "." )* >
-}
-
-TOKEN_MGR_DECLS :
-{
- // Keeps track of how many levels of comment nesting
- // we've encountered. This is only used when the 2nd
- // level is reached, for example ((this)), not (this).
- // This is because the outermost level must be treated
- // specially anyway, because the outermost ")" has a
- // different token type than inner ")" instances.
- static int commentNest;
-}
-
-MORE :
-{
- // domain literal
- "[" : INDOMAINLITERAL
-}
-
-<INDOMAINLITERAL>
-MORE :
-{
- < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
-| < ~["[", "]", "\\"] >
-}
-
-<INDOMAINLITERAL>
-TOKEN :
-{
- < DOMAINLITERAL: "]" > { matchedToken.image = image.toString(); }: DEFAULT
-}
-
-MORE :
-{
- // starts a comment
- "(" : INCOMMENT
-}
-
-<INCOMMENT>
-SKIP :
-{
- // ends a comment
- < COMMENT: ")" > : DEFAULT
- // if this is ever changed to not be a SKIP, need
- // to make sure matchedToken.token = token.toString()
- // is called.
-}
-
-<INCOMMENT>
-MORE :
-{
- < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
-| "(" { commentNest = 1; } : NESTED_COMMENT
-| < <ANY>>
-}
-
-<NESTED_COMMENT>
-MORE :
-{
- < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
-| "(" { ++commentNest; }
-| ")" { --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT); }
-| < <ANY>>
-}
-
-
-// QUOTED STRINGS
-
-MORE :
-{
- "\"" { image.deleteCharAt(image.length() - 1); } : INQUOTEDSTRING
-}
-
-<INQUOTEDSTRING>
-MORE :
-{
- < <QUOTEDPAIR>> { image.deleteCharAt(image.length() - 2); }
-| < (~["\"", "\\"])+ >
-}
-
-<INQUOTEDSTRING>
-TOKEN :
-{
- < QUOTEDSTRING: "\"" > { matchedToken.image = image.substring(0, image.length() - 1); } : DEFAULT
-}
-
-// GLOBALS
-
-<*>
-TOKEN :
-{
- < #QUOTEDPAIR: "\\" <ANY> >
-| < #ANY: ~[] >
-}
-
-// ERROR!
-/*
-
-<*>
-TOKEN :
-{
- < UNEXPECTED_CHAR: <ANY> >
-}
-
-*/
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java
deleted file mode 100644
index 006a082..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserConstants.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParserConstants.java */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.address.parser;
-
-public interface AddressListParserConstants {
-
- int EOF = 0;
- int WS = 10;
- int ALPHA = 11;
- int DIGIT = 12;
- int ATEXT = 13;
- int DOTATOM = 14;
- int DOMAINLITERAL = 18;
- int COMMENT = 20;
- int QUOTEDSTRING = 31;
- int QUOTEDPAIR = 32;
- int ANY = 33;
-
- int DEFAULT = 0;
- int INDOMAINLITERAL = 1;
- int INCOMMENT = 2;
- int NESTED_COMMENT = 3;
- int INQUOTEDSTRING = 4;
-
- String[] tokenImage = {
- "<EOF>",
- "\"\\r\"",
- "\"\\n\"",
- "\",\"",
- "\":\"",
- "\";\"",
- "\"<\"",
- "\">\"",
- "\"@\"",
- "\".\"",
- "<WS>",
- "<ALPHA>",
- "<DIGIT>",
- "<ATEXT>",
- "<DOTATOM>",
- "\"[\"",
- "<token of kind 16>",
- "<token of kind 17>",
- "\"]\"",
- "\"(\"",
- "\")\"",
- "<token of kind 21>",
- "\"(\"",
- "<token of kind 23>",
- "<token of kind 24>",
- "\"(\"",
- "\")\"",
- "<token of kind 27>",
- "\"\\\"\"",
- "<token of kind 29>",
- "<token of kind 30>",
- "\"\\\"\"",
- "<QUOTEDPAIR>",
- "<ANY>",
- };
-
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java
deleted file mode 100644
index d2dd88d..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTokenManager.java
+++ /dev/null
@@ -1,1009 +0,0 @@
-/* Generated By:JJTree&JavaCC: Do not edit this line. AddressListParserTokenManager.java */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.address.parser;
-
-public class AddressListParserTokenManager implements AddressListParserConstants
-{
- // Keeps track of how many levels of comment nesting
- // we've encountered. This is only used when the 2nd
- // level is reached, for example ((this)), not (this).
- // This is because the outermost level must be treated
- // specially anyway, because the outermost ")" has a
- // different token type than inner ")" instances.
- static int commentNest;
- public java.io.PrintStream debugStream = System.out;
- public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
-private final int jjStopStringLiteralDfa_0(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_0(int pos, long active0)
-{
- return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
-}
-private final int jjStopAtPos(int pos, int kind)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- return pos + 1;
-}
-private final int jjStartNfaWithStates_0(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_0(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_0()
-{
- switch(curChar)
- {
- case 10:
- return jjStopAtPos(0, 2);
- case 13:
- return jjStopAtPos(0, 1);
- case 34:
- return jjStopAtPos(0, 28);
- case 40:
- return jjStopAtPos(0, 19);
- case 44:
- return jjStopAtPos(0, 3);
- case 46:
- return jjStopAtPos(0, 9);
- case 58:
- return jjStopAtPos(0, 4);
- case 59:
- return jjStopAtPos(0, 5);
- case 60:
- return jjStopAtPos(0, 6);
- case 62:
- return jjStopAtPos(0, 7);
- case 64:
- return jjStopAtPos(0, 8);
- case 91:
- return jjStopAtPos(0, 15);
- default :
- return jjMoveNfa_0(1, 0);
- }
-}
-private final void jjCheckNAdd(int state)
-{
- if (jjrounds[state] != jjround)
- {
- jjstateSet[jjnewStateCnt++] = state;
- jjrounds[state] = jjround;
- }
-}
-private final void jjAddStates(int start, int end)
-{
- do {
- jjstateSet[jjnewStateCnt++] = jjnextStates[start];
- } while (start++ != end);
-}
-private final void jjCheckNAddTwoStates(int state1, int state2)
-{
- jjCheckNAdd(state1);
- jjCheckNAdd(state2);
-}
-private final void jjCheckNAddStates(int start, int end)
-{
- do {
- jjCheckNAdd(jjnextStates[start]);
- } while (start++ != end);
-}
-private final void jjCheckNAddStates(int start)
-{
- jjCheckNAdd(jjnextStates[start]);
- jjCheckNAdd(jjnextStates[start + 1]);
-}
-private final int jjMoveNfa_0(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 1:
- if ((0xa3ffacfa00000000L & l) != 0L)
- {
- if (kind > 14)
- kind = 14;
- jjCheckNAdd(2);
- }
- else if ((0x100000200L & l) != 0L)
- {
- if (kind > 10)
- kind = 10;
- jjCheckNAdd(0);
- }
- break;
- case 0:
- if ((0x100000200L & l) == 0L)
- break;
- kind = 10;
- jjCheckNAdd(0);
- break;
- case 2:
- if ((0xa3ffecfa00000000L & l) == 0L)
- break;
- if (kind > 14)
- kind = 14;
- jjCheckNAdd(2);
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 1:
- case 2:
- if ((0x7fffffffc7fffffeL & l) == 0L)
- break;
- if (kind > 14)
- kind = 14;
- jjCheckNAdd(2);
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-private final int jjStopStringLiteralDfa_2(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_2(int pos, long active0)
-{
- return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1);
-}
-private final int jjStartNfaWithStates_2(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_2(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_2()
-{
- switch(curChar)
- {
- case 40:
- return jjStopAtPos(0, 22);
- case 41:
- return jjStopAtPos(0, 20);
- default :
- return jjMoveNfa_2(0, 0);
- }
-}
-static final long[] jjbitVec0 = {
- 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
-};
-private final int jjMoveNfa_2(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 23)
- kind = 23;
- break;
- case 1:
- if (kind > 21)
- kind = 21;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 23)
- kind = 23;
- if (curChar == 92)
- jjstateSet[jjnewStateCnt++] = 1;
- break;
- case 1:
- if (kind > 21)
- kind = 21;
- break;
- case 2:
- if (kind > 23)
- kind = 23;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 23)
- kind = 23;
- break;
- case 1:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 21)
- kind = 21;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-private final int jjStopStringLiteralDfa_4(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_4(int pos, long active0)
-{
- return jjMoveNfa_4(jjStopStringLiteralDfa_4(pos, active0), pos + 1);
-}
-private final int jjStartNfaWithStates_4(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_4(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_4()
-{
- switch(curChar)
- {
- case 34:
- return jjStopAtPos(0, 31);
- default :
- return jjMoveNfa_4(0, 0);
- }
-}
-private final int jjMoveNfa_4(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- case 2:
- if ((0xfffffffbffffffffL & l) == 0L)
- break;
- if (kind > 30)
- kind = 30;
- jjCheckNAdd(2);
- break;
- case 1:
- if (kind > 29)
- kind = 29;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((0xffffffffefffffffL & l) != 0L)
- {
- if (kind > 30)
- kind = 30;
- jjCheckNAdd(2);
- }
- else if (curChar == 92)
- jjstateSet[jjnewStateCnt++] = 1;
- break;
- case 1:
- if (kind > 29)
- kind = 29;
- break;
- case 2:
- if ((0xffffffffefffffffL & l) == 0L)
- break;
- if (kind > 30)
- kind = 30;
- jjCheckNAdd(2);
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- case 2:
- if ((jjbitVec0[i2] & l2) == 0L)
- break;
- if (kind > 30)
- kind = 30;
- jjCheckNAdd(2);
- break;
- case 1:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 29)
- kind = 29;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-private final int jjStopStringLiteralDfa_3(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_3(int pos, long active0)
-{
- return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1);
-}
-private final int jjStartNfaWithStates_3(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_3(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_3()
-{
- switch(curChar)
- {
- case 40:
- return jjStopAtPos(0, 25);
- case 41:
- return jjStopAtPos(0, 26);
- default :
- return jjMoveNfa_3(0, 0);
- }
-}
-private final int jjMoveNfa_3(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 27)
- kind = 27;
- break;
- case 1:
- if (kind > 24)
- kind = 24;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 27)
- kind = 27;
- if (curChar == 92)
- jjstateSet[jjnewStateCnt++] = 1;
- break;
- case 1:
- if (kind > 24)
- kind = 24;
- break;
- case 2:
- if (kind > 27)
- kind = 27;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 27)
- kind = 27;
- break;
- case 1:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 24)
- kind = 24;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-private final int jjStopStringLiteralDfa_1(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_1(int pos, long active0)
-{
- return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1);
-}
-private final int jjStartNfaWithStates_1(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_1(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_1()
-{
- switch(curChar)
- {
- case 93:
- return jjStopAtPos(0, 18);
- default :
- return jjMoveNfa_1(0, 0);
- }
-}
-private final int jjMoveNfa_1(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 17)
- kind = 17;
- break;
- case 1:
- if (kind > 16)
- kind = 16;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((0xffffffffc7ffffffL & l) != 0L)
- {
- if (kind > 17)
- kind = 17;
- }
- else if (curChar == 92)
- jjstateSet[jjnewStateCnt++] = 1;
- break;
- case 1:
- if (kind > 16)
- kind = 16;
- break;
- case 2:
- if ((0xffffffffc7ffffffL & l) != 0L && kind > 17)
- kind = 17;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 17)
- kind = 17;
- break;
- case 1:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 16)
- kind = 16;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-static final int[] jjnextStates = {
-};
-public static final String[] jjstrLiteralImages = {
-"", "\15", "\12", "\54", "\72", "\73", "\74", "\76", "\100", "\56", null, null,
-null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-null, null, null, null, null, null, null, null, };
-public static final String[] lexStateNames = {
- "DEFAULT",
- "INDOMAINLITERAL",
- "INCOMMENT",
- "NESTED_COMMENT",
- "INQUOTEDSTRING",
-};
-public static final int[] jjnewLexState = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, -1, -1, 0, 2, 0, -1, 3, -1, -1,
- -1, -1, -1, 4, -1, -1, 0, -1, -1,
-};
-static final long[] jjtoToken = {
- 0x800443ffL,
-};
-static final long[] jjtoSkip = {
- 0x100400L,
-};
-static final long[] jjtoSpecial = {
- 0x400L,
-};
-static final long[] jjtoMore = {
- 0x7feb8000L,
-};
-protected SimpleCharStream input_stream;
-private final int[] jjrounds = new int[3];
-private final int[] jjstateSet = new int[6];
-StringBuffer image;
-int jjimageLen;
-int lengthOfMatch;
-protected char curChar;
-public AddressListParserTokenManager(SimpleCharStream stream){
- if (SimpleCharStream.staticFlag)
- throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
- input_stream = stream;
-}
-public AddressListParserTokenManager(SimpleCharStream stream, int lexState){
- this(stream);
- SwitchTo(lexState);
-}
-public void ReInit(SimpleCharStream stream)
-{
- jjmatchedPos = jjnewStateCnt = 0;
- curLexState = defaultLexState;
- input_stream = stream;
- ReInitRounds();
-}
-private final void ReInitRounds()
-{
- int i;
- jjround = 0x80000001;
- for (i = 3; i-- > 0;)
- jjrounds[i] = 0x80000000;
-}
-public void ReInit(SimpleCharStream stream, int lexState)
-{
- ReInit(stream);
- SwitchTo(lexState);
-}
-public void SwitchTo(int lexState)
-{
- if (lexState >= 5 || lexState < 0)
- throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
- else
- curLexState = lexState;
-}
-
-protected Token jjFillToken()
-{
- Token t = Token.newToken(jjmatchedKind);
- t.kind = jjmatchedKind;
- String im = jjstrLiteralImages[jjmatchedKind];
- t.image = (im == null) ? input_stream.GetImage() : im;
- t.beginLine = input_stream.getBeginLine();
- t.beginColumn = input_stream.getBeginColumn();
- t.endLine = input_stream.getEndLine();
- t.endColumn = input_stream.getEndColumn();
- return t;
-}
-
-int curLexState = 0;
-int defaultLexState = 0;
-int jjnewStateCnt;
-int jjround;
-int jjmatchedPos;
-int jjmatchedKind;
-
-public Token getNextToken()
-{
- int kind;
- Token specialToken = null;
- Token matchedToken;
- int curPos = 0;
-
- EOFLoop :
- for (;;)
- {
- try
- {
- curChar = input_stream.BeginToken();
- }
- catch(java.io.IOException e)
- {
- jjmatchedKind = 0;
- matchedToken = jjFillToken();
- matchedToken.specialToken = specialToken;
- return matchedToken;
- }
- image = null;
- jjimageLen = 0;
-
- for (;;)
- {
- switch(curLexState)
- {
- case 0:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_0();
- break;
- case 1:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_1();
- break;
- case 2:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_2();
- break;
- case 3:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_3();
- break;
- case 4:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_4();
- break;
- }
- if (jjmatchedKind != 0x7fffffff)
- {
- if (jjmatchedPos + 1 < curPos)
- input_stream.backup(curPos - jjmatchedPos - 1);
- if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
- {
- matchedToken = jjFillToken();
- matchedToken.specialToken = specialToken;
- TokenLexicalActions(matchedToken);
- if (jjnewLexState[jjmatchedKind] != -1)
- curLexState = jjnewLexState[jjmatchedKind];
- return matchedToken;
- }
- else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
- {
- if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
- {
- matchedToken = jjFillToken();
- if (specialToken == null)
- specialToken = matchedToken;
- else
- {
- matchedToken.specialToken = specialToken;
- specialToken = (specialToken.next = matchedToken);
- }
- }
- if (jjnewLexState[jjmatchedKind] != -1)
- curLexState = jjnewLexState[jjmatchedKind];
- continue EOFLoop;
- }
- MoreLexicalActions();
- if (jjnewLexState[jjmatchedKind] != -1)
- curLexState = jjnewLexState[jjmatchedKind];
- curPos = 0;
- jjmatchedKind = 0x7fffffff;
- try {
- curChar = input_stream.readChar();
- continue;
- }
- catch (java.io.IOException e1) { }
- }
- int error_line = input_stream.getEndLine();
- int error_column = input_stream.getEndColumn();
- String error_after = null;
- boolean EOFSeen = false;
- try { input_stream.readChar(); input_stream.backup(1); }
- catch (java.io.IOException e1) {
- EOFSeen = true;
- error_after = curPos <= 1 ? "" : input_stream.GetImage();
- if (curChar == '\n' || curChar == '\r') {
- error_line++;
- error_column = 0;
- }
- else
- error_column++;
- }
- if (!EOFSeen) {
- input_stream.backup(1);
- error_after = curPos <= 1 ? "" : input_stream.GetImage();
- }
- throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
- }
- }
-}
-
-void MoreLexicalActions()
-{
- jjimageLen += (lengthOfMatch = jjmatchedPos + 1);
- switch(jjmatchedKind)
- {
- case 16 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 2);
- break;
- case 21 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 2);
- break;
- case 22 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- commentNest = 1;
- break;
- case 24 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 2);
- break;
- case 25 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- ++commentNest;
- break;
- case 26 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT);
- break;
- case 28 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 1);
- break;
- case 29 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 2);
- break;
- default :
- break;
- }
-}
-void TokenLexicalActions(Token matchedToken)
-{
- switch(jjmatchedKind)
- {
- case 18 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
- matchedToken.image = image.toString();
- break;
- case 31 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
- matchedToken.image = image.substring(0, image.length() - 1);
- break;
- default :
- break;
- }
-}
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java
deleted file mode 100644
index 5987f19..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParserTreeConstants.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public interface AddressListParserTreeConstants
-{
- public int JJTVOID = 0;
- public int JJTADDRESS_LIST = 1;
- public int JJTADDRESS = 2;
- public int JJTMAILBOX = 3;
- public int JJTNAME_ADDR = 4;
- public int JJTGROUP_BODY = 5;
- public int JJTANGLE_ADDR = 6;
- public int JJTROUTE = 7;
- public int JJTPHRASE = 8;
- public int JJTADDR_SPEC = 9;
- public int JJTLOCAL_PART = 10;
- public int JJTDOMAIN = 11;
-
-
- public String[] jjtNodeName = {
- "void",
- "address_list",
- "address",
- "mailbox",
- "name_addr",
- "group_body",
- "angle_addr",
- "route",
- "phrase",
- "addr_spec",
- "local_part",
- "domain",
- };
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java b/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java
deleted file mode 100644
index 8ec2fe7..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/AddressListParserVisitor.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public interface AddressListParserVisitor
-{
- public Object visit(SimpleNode node, Object data);
- public Object visit(ASTaddress_list node, Object data);
- public Object visit(ASTaddress node, Object data);
- public Object visit(ASTmailbox node, Object data);
- public Object visit(ASTname_addr node, Object data);
- public Object visit(ASTgroup_body node, Object data);
- public Object visit(ASTangle_addr node, Object data);
- public Object visit(ASTroute node, Object data);
- public Object visit(ASTphrase node, Object data);
- public Object visit(ASTaddr_spec node, Object data);
- public Object visit(ASTlocal_part node, Object data);
- public Object visit(ASTdomain node, Object data);
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/BaseNode.java b/src/org/apache/james/mime4j/field/address/parser/BaseNode.java
deleted file mode 100644
index 7809746..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/BaseNode.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field.address.parser;
-
-import org.apache.james.mime4j.field.address.parser.Node;
-import org.apache.james.mime4j.field.address.parser.Token;
-
-public abstract class BaseNode implements Node {
-
- public Token firstToken;
- public Token lastToken;
-
-}
\ No newline at end of file
diff --git a/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java b/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java
deleted file mode 100644
index 08b5c5b..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. /Users/jason/Projects/apache-mime4j-0.3/target/generated-sources/jjtree/org/apache/james/mime4j/field/address/parser/JJTAddressListParserState.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-class JJTAddressListParserState {
- private java.util.Stack<Node> nodes;
- private java.util.Stack<Integer> marks;
-
- private int sp; // number of nodes on stack
- private int mk; // current mark
- private boolean node_created;
-
- JJTAddressListParserState() {
- nodes = new java.util.Stack<Node>();
- marks = new java.util.Stack<Integer>();
- sp = 0;
- mk = 0;
- }
-
- /* Determines whether the current node was actually closed and
- pushed. This should only be called in the final user action of a
- node scope. */
- boolean nodeCreated() {
- return node_created;
- }
-
- /* Call this to reinitialize the node stack. It is called
- automatically by the parser's ReInit() method. */
- void reset() {
- nodes.removeAllElements();
- marks.removeAllElements();
- sp = 0;
- mk = 0;
- }
-
- /* Returns the root node of the AST. It only makes sense to call
- this after a successful parse. */
- Node rootNode() {
- return nodes.elementAt(0);
- }
-
- /* Pushes a node on to the stack. */
- void pushNode(Node n) {
- nodes.push(n);
- ++sp;
- }
-
- /* Returns the node on the top of the stack, and remove it from the
- stack. */
- Node popNode() {
- if (--sp < mk) {
- mk = marks.pop().intValue();
- }
- return nodes.pop();
- }
-
- /* Returns the node currently on the top of the stack. */
- Node peekNode() {
- return nodes.peek();
- }
-
- /* Returns the number of children on the stack in the current node
- scope. */
- int nodeArity() {
- return sp - mk;
- }
-
-
- void clearNodeScope(Node n) {
- while (sp > mk) {
- popNode();
- }
- mk = marks.pop().intValue();
- }
-
-
- void openNodeScope(Node n) {
- marks.push(new Integer(mk));
- mk = sp;
- n.jjtOpen();
- }
-
-
- /* A definite node is constructed from a specified number of
- children. That number of nodes are popped from the stack and
- made the children of the definite node. Then the definite node
- is pushed on to the stack. */
- void closeNodeScope(Node n, int num) {
- mk = marks.pop().intValue();
- while (num-- > 0) {
- Node c = popNode();
- c.jjtSetParent(n);
- n.jjtAddChild(c, num);
- }
- n.jjtClose();
- pushNode(n);
- node_created = true;
- }
-
-
- /* A conditional node is constructed if its condition is true. All
- the nodes that have been pushed since the node was opened are
- made children of the the conditional node, which is then pushed
- on to the stack. If the condition is false the node is not
- constructed and they are left on the stack. */
- void closeNodeScope(Node n, boolean condition) {
- if (condition) {
- int a = nodeArity();
- mk = marks.pop().intValue();
- while (a-- > 0) {
- Node c = popNode();
- c.jjtSetParent(n);
- n.jjtAddChild(c, a);
- }
- n.jjtClose();
- pushNode(n);
- node_created = true;
- } else {
- mk = marks.pop().intValue();
- node_created = false;
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/Node.java b/src/org/apache/james/mime4j/field/address/parser/Node.java
deleted file mode 100644
index 1588920..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/Node.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. Node.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-/* All AST nodes must implement this interface. It provides basic
- machinery for constructing the parent and child relationships
- between nodes. */
-
-public interface Node {
-
- /** This method is called after the node has been made the current
- node. It indicates that child nodes can now be added to it. */
- public void jjtOpen();
-
- /** This method is called after all the child nodes have been
- added. */
- public void jjtClose();
-
- /** This pair of methods are used to inform the node of its
- parent. */
- public void jjtSetParent(Node n);
- public Node jjtGetParent();
-
- /** This method tells the node to add its argument to the node's
- list of children. */
- public void jjtAddChild(Node n, int i);
-
- /** This method returns a child node. The children are numbered
- from zero, left to right. */
- public Node jjtGetChild(int i);
-
- /** Return the number of children the node has. */
- public int jjtGetNumChildren();
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data);
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/ParseException.java b/src/org/apache/james/mime4j/field/address/parser/ParseException.java
deleted file mode 100644
index e20146f..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/ParseException.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.address.parser;
-
-/**
- * This exception is thrown when parse errors are encountered.
- * You can explicitly create objects of this exception type by
- * calling the method generateParseException in the generated
- * parser.
- *
- * You can modify this class to customize your error reporting
- * mechanisms so long as you retain the public fields.
- */
-public class ParseException extends Exception {
-
- /**
- * This constructor is used by the method "generateParseException"
- * in the generated parser. Calling this constructor generates
- * a new object of this type with the fields "currentToken",
- * "expectedTokenSequences", and "tokenImage" set. The boolean
- * flag "specialConstructor" is also set to true to indicate that
- * this constructor was used to create this object.
- * This constructor calls its super class with the empty string
- * to force the "toString" method of parent class "Throwable" to
- * print the error message in the form:
- * ParseException: <result of getMessage>
- */
- public ParseException(Token currentTokenVal,
- int[][] expectedTokenSequencesVal,
- String[] tokenImageVal
- )
- {
- super("");
- specialConstructor = true;
- currentToken = currentTokenVal;
- expectedTokenSequences = expectedTokenSequencesVal;
- tokenImage = tokenImageVal;
- }
-
- /**
- * The following constructors are for use by you for whatever
- * purpose you can think of. Constructing the exception in this
- * manner makes the exception behave in the normal way - i.e., as
- * documented in the class "Throwable". The fields "errorToken",
- * "expectedTokenSequences", and "tokenImage" do not contain
- * relevant information. The JavaCC generated code does not use
- * these constructors.
- */
-
- public ParseException() {
- super();
- specialConstructor = false;
- }
-
- public ParseException(String message) {
- super(message);
- specialConstructor = false;
- }
-
- /**
- * This variable determines which constructor was used to create
- * this object and thereby affects the semantics of the
- * "getMessage" method (see below).
- */
- protected boolean specialConstructor;
-
- /**
- * This is the last token that has been consumed successfully. If
- * this object has been created due to a parse error, the token
- * followng this token will (therefore) be the first error token.
- */
- public Token currentToken;
-
- /**
- * Each entry in this array is an array of integers. Each array
- * of integers represents a sequence of tokens (by their ordinal
- * values) that is expected at this point of the parse.
- */
- public int[][] expectedTokenSequences;
-
- /**
- * This is a reference to the "tokenImage" array of the generated
- * parser within which the parse error occurred. This array is
- * defined in the generated ...Constants interface.
- */
- public String[] tokenImage;
-
- /**
- * This method has the standard behavior when this object has been
- * created using the standard constructors. Otherwise, it uses
- * "currentToken" and "expectedTokenSequences" to generate a parse
- * error message and returns it. If this object has been created
- * due to a parse error, and you do not catch it (it gets thrown
- * from the parser), then this method is called during the printing
- * of the final stack trace, and hence the correct error message
- * gets displayed.
- */
- public String getMessage() {
- if (!specialConstructor) {
- return super.getMessage();
- }
- StringBuffer expected = new StringBuffer();
- int maxSize = 0;
- for (int i = 0; i < expectedTokenSequences.length; i++) {
- if (maxSize < expectedTokenSequences[i].length) {
- maxSize = expectedTokenSequences[i].length;
- }
- for (int j = 0; j < expectedTokenSequences[i].length; j++) {
- expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
- }
- if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
- expected.append("...");
- }
- expected.append(eol).append(" ");
- }
- String retval = "Encountered \"";
- Token tok = currentToken.next;
- for (int i = 0; i < maxSize; i++) {
- if (i != 0) retval += " ";
- if (tok.kind == 0) {
- retval += tokenImage[0];
- break;
- }
- retval += add_escapes(tok.image);
- tok = tok.next;
- }
- retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
- retval += "." + eol;
- if (expectedTokenSequences.length == 1) {
- retval += "Was expecting:" + eol + " ";
- } else {
- retval += "Was expecting one of:" + eol + " ";
- }
- retval += expected.toString();
- return retval;
- }
-
- /**
- * The end of line string for this machine.
- */
- protected String eol = System.getProperty("line.separator", "\n");
-
- /**
- * Used to convert raw characters to their escaped version
- * when these raw version cannot be used as part of an ASCII
- * string literal.
- */
- protected String add_escapes(String str) {
- StringBuffer retval = new StringBuffer();
- char ch;
- for (int i = 0; i < str.length(); i++) {
- switch (str.charAt(i))
- {
- case 0 :
- continue;
- case '\b':
- retval.append("\\b");
- continue;
- case '\t':
- retval.append("\\t");
- continue;
- case '\n':
- retval.append("\\n");
- continue;
- case '\f':
- retval.append("\\f");
- continue;
- case '\r':
- retval.append("\\r");
- continue;
- case '\"':
- retval.append("\\\"");
- continue;
- case '\'':
- retval.append("\\\'");
- continue;
- case '\\':
- retval.append("\\\\");
- continue;
- default:
- if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
- String s = "0000" + Integer.toString(ch, 16);
- retval.append("\\u" + s.substring(s.length() - 4, s.length()));
- } else {
- retval.append(ch);
- }
- continue;
- }
- }
- return retval.toString();
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java
deleted file mode 100644
index c9ba0b4..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/SimpleCharStream.java
+++ /dev/null
@@ -1,454 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.address.parser;
-
-/**
- * An implementation of interface CharStream, where the stream is assumed to
- * contain only ASCII characters (without unicode processing).
- */
-
-public class SimpleCharStream
-{
- public static final boolean staticFlag = false;
- int bufsize;
- int available;
- int tokenBegin;
- public int bufpos = -1;
- protected int bufline[];
- protected int bufcolumn[];
-
- protected int column = 0;
- protected int line = 1;
-
- protected boolean prevCharIsCR = false;
- protected boolean prevCharIsLF = false;
-
- protected java.io.Reader inputStream;
-
- protected char[] buffer;
- protected int maxNextCharInd = 0;
- protected int inBuf = 0;
- protected int tabSize = 8;
-
- protected void setTabSize(int i) { tabSize = i; }
- protected int getTabSize(int i) { return tabSize; }
-
-
- protected void ExpandBuff(boolean wrapAround)
- {
- char[] newbuffer = new char[bufsize + 2048];
- int newbufline[] = new int[bufsize + 2048];
- int newbufcolumn[] = new int[bufsize + 2048];
-
- try
- {
- if (wrapAround)
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- System.arraycopy(buffer, 0, newbuffer,
- bufsize - tokenBegin, bufpos);
- buffer = newbuffer;
-
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
- bufline = newbufline;
-
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
- bufcolumn = newbufcolumn;
-
- maxNextCharInd = (bufpos += (bufsize - tokenBegin));
- }
- else
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- buffer = newbuffer;
-
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- bufline = newbufline;
-
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- bufcolumn = newbufcolumn;
-
- maxNextCharInd = (bufpos -= tokenBegin);
- }
- }
- catch (Throwable t)
- {
- throw new Error(t.getMessage());
- }
-
-
- bufsize += 2048;
- available = bufsize;
- tokenBegin = 0;
- }
-
- protected void FillBuff() throws java.io.IOException
- {
- if (maxNextCharInd == available)
- {
- if (available == bufsize)
- {
- if (tokenBegin > 2048)
- {
- bufpos = maxNextCharInd = 0;
- available = tokenBegin;
- }
- else if (tokenBegin < 0)
- bufpos = maxNextCharInd = 0;
- else
- ExpandBuff(false);
- }
- else if (available > tokenBegin)
- available = bufsize;
- else if ((tokenBegin - available) < 2048)
- ExpandBuff(true);
- else
- available = tokenBegin;
- }
-
- int i;
- try {
- if ((i = inputStream.read(buffer, maxNextCharInd,
- available - maxNextCharInd)) == -1)
- {
- inputStream.close();
- throw new java.io.IOException();
- }
- else
- maxNextCharInd += i;
- return;
- }
- catch(java.io.IOException e) {
- --bufpos;
- backup(0);
- if (tokenBegin == -1)
- tokenBegin = bufpos;
- throw e;
- }
- }
-
- public char BeginToken() throws java.io.IOException
- {
- tokenBegin = -1;
- char c = readChar();
- tokenBegin = bufpos;
-
- return c;
- }
-
- protected void UpdateLineColumn(char c)
- {
- column++;
-
- if (prevCharIsLF)
- {
- prevCharIsLF = false;
- line += (column = 1);
- }
- else if (prevCharIsCR)
- {
- prevCharIsCR = false;
- if (c == '\n')
- {
- prevCharIsLF = true;
- }
- else
- line += (column = 1);
- }
-
- switch (c)
- {
- case '\r' :
- prevCharIsCR = true;
- break;
- case '\n' :
- prevCharIsLF = true;
- break;
- case '\t' :
- column--;
- column += (tabSize - (column % tabSize));
- break;
- default :
- break;
- }
-
- bufline[bufpos] = line;
- bufcolumn[bufpos] = column;
- }
-
- public char readChar() throws java.io.IOException
- {
- if (inBuf > 0)
- {
- --inBuf;
-
- if (++bufpos == bufsize)
- bufpos = 0;
-
- return buffer[bufpos];
- }
-
- if (++bufpos >= maxNextCharInd)
- FillBuff();
-
- char c = buffer[bufpos];
-
- UpdateLineColumn(c);
- return (c);
- }
-
- /**
- * @deprecated
- * @see #getEndColumn
- */
- @Deprecated
- public int getColumn() {
- return bufcolumn[bufpos];
- }
-
- /**
- * @deprecated
- * @see #getEndLine
- */
- @Deprecated
- public int getLine() {
- return bufline[bufpos];
- }
-
- public int getEndColumn() {
- return bufcolumn[bufpos];
- }
-
- public int getEndLine() {
- return bufline[bufpos];
- }
-
- public int getBeginColumn() {
- return bufcolumn[tokenBegin];
- }
-
- public int getBeginLine() {
- return bufline[tokenBegin];
- }
-
- public void backup(int amount) {
-
- inBuf += amount;
- if ((bufpos -= amount) < 0)
- bufpos += bufsize;
- }
-
- public SimpleCharStream(java.io.Reader dstream, int startline,
- int startcolumn, int buffersize)
- {
- inputStream = dstream;
- line = startline;
- column = startcolumn - 1;
-
- available = bufsize = buffersize;
- buffer = new char[buffersize];
- bufline = new int[buffersize];
- bufcolumn = new int[buffersize];
- }
-
- public SimpleCharStream(java.io.Reader dstream, int startline,
- int startcolumn)
- {
- this(dstream, startline, startcolumn, 4096);
- }
-
- public SimpleCharStream(java.io.Reader dstream)
- {
- this(dstream, 1, 1, 4096);
- }
- public void ReInit(java.io.Reader dstream, int startline,
- int startcolumn, int buffersize)
- {
- inputStream = dstream;
- line = startline;
- column = startcolumn - 1;
-
- if (buffer == null || buffersize != buffer.length)
- {
- available = bufsize = buffersize;
- buffer = new char[buffersize];
- bufline = new int[buffersize];
- bufcolumn = new int[buffersize];
- }
- prevCharIsLF = prevCharIsCR = false;
- tokenBegin = inBuf = maxNextCharInd = 0;
- bufpos = -1;
- }
-
- public void ReInit(java.io.Reader dstream, int startline,
- int startcolumn)
- {
- ReInit(dstream, startline, startcolumn, 4096);
- }
-
- public void ReInit(java.io.Reader dstream)
- {
- ReInit(dstream, 1, 1, 4096);
- }
- public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
- {
- this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, int startline,
- int startcolumn, int buffersize)
- {
- this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn) throws java.io.UnsupportedEncodingException
- {
- this(dstream, encoding, startline, startcolumn, 4096);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, int startline,
- int startcolumn)
- {
- this(dstream, startline, startcolumn, 4096);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
- {
- this(dstream, encoding, 1, 1, 4096);
- }
-
- public SimpleCharStream(java.io.InputStream dstream)
- {
- this(dstream, 1, 1, 4096);
- }
-
- public void ReInit(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
- {
- ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
- }
-
- public void ReInit(java.io.InputStream dstream, int startline,
- int startcolumn, int buffersize)
- {
- ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
- }
-
- public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
- {
- ReInit(dstream, encoding, 1, 1, 4096);
- }
-
- public void ReInit(java.io.InputStream dstream)
- {
- ReInit(dstream, 1, 1, 4096);
- }
- public void ReInit(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn) throws java.io.UnsupportedEncodingException
- {
- ReInit(dstream, encoding, startline, startcolumn, 4096);
- }
- public void ReInit(java.io.InputStream dstream, int startline,
- int startcolumn)
- {
- ReInit(dstream, startline, startcolumn, 4096);
- }
- public String GetImage()
- {
- if (bufpos >= tokenBegin)
- return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
- else
- return new String(buffer, tokenBegin, bufsize - tokenBegin) +
- new String(buffer, 0, bufpos + 1);
- }
-
- public char[] GetSuffix(int len)
- {
- char[] ret = new char[len];
-
- if ((bufpos + 1) >= len)
- System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
- else
- {
- System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
- len - bufpos - 1);
- System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
- }
-
- return ret;
- }
-
- public void Done()
- {
- buffer = null;
- bufline = null;
- bufcolumn = null;
- }
-
- /**
- * Method to adjust line and column numbers for the start of a token.
- */
- public void adjustBeginLineColumn(int newLine, int newCol)
- {
- int start = tokenBegin;
- int len;
-
- if (bufpos >= tokenBegin)
- {
- len = bufpos - tokenBegin + inBuf + 1;
- }
- else
- {
- len = bufsize - tokenBegin + bufpos + 1 + inBuf;
- }
-
- int i = 0, j = 0, k = 0;
- int nextColDiff = 0, columnDiff = 0;
-
- while (i < len &&
- bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
- {
- bufline[j] = newLine;
- nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
- bufcolumn[j] = newCol + columnDiff;
- columnDiff = nextColDiff;
- i++;
- }
-
- if (i < len)
- {
- bufline[j] = newLine++;
- bufcolumn[j] = newCol + columnDiff;
-
- while (i++ < len)
- {
- if (bufline[j = start % bufsize] != bufline[++start % bufsize])
- bufline[j] = newLine++;
- else
- bufline[j] = newLine;
- }
- }
-
- line = bufline[j];
- column = bufcolumn[j];
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java b/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java
deleted file mode 100644
index 9bf537e..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/SimpleNode.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/* Generated By:JJTree: Do not edit this line. SimpleNode.java */
-
-package org.apache.james.mime4j.field.address.parser;
-
-public class SimpleNode extends org.apache.james.mime4j.field.address.parser.BaseNode implements Node {
- protected Node parent;
- protected Node[] children;
- protected int id;
- protected AddressListParser parser;
-
- public SimpleNode(int i) {
- id = i;
- }
-
- public SimpleNode(AddressListParser p, int i) {
- this(i);
- parser = p;
- }
-
- public void jjtOpen() {
- }
-
- public void jjtClose() {
- }
-
- public void jjtSetParent(Node n) { parent = n; }
- public Node jjtGetParent() { return parent; }
-
- public void jjtAddChild(Node n, int i) {
- if (children == null) {
- children = new Node[i + 1];
- } else if (i >= children.length) {
- Node c[] = new Node[i + 1];
- System.arraycopy(children, 0, c, 0, children.length);
- children = c;
- }
- children[i] = n;
- }
-
- public Node jjtGetChild(int i) {
- return children[i];
- }
-
- public int jjtGetNumChildren() {
- return (children == null) ? 0 : children.length;
- }
-
- /** Accept the visitor. **/
- public Object jjtAccept(AddressListParserVisitor visitor, Object data) {
- return visitor.visit(this, data);
- }
-
- /** Accept the visitor. **/
- public Object childrenAccept(AddressListParserVisitor visitor, Object data) {
- if (children != null) {
- for (int i = 0; i < children.length; ++i) {
- children[i].jjtAccept(visitor, data);
- }
- }
- return data;
- }
-
- /* You can override these two methods in subclasses of SimpleNode to
- customize the way the node appears when the tree is dumped. If
- your output uses more than one line you should override
- toString(String), otherwise overriding toString() is probably all
- you need to do. */
-
- public String toString() { return AddressListParserTreeConstants.jjtNodeName[id]; }
- public String toString(String prefix) { return prefix + toString(); }
-
- /* Override this method if you want to customize how the node dumps
- out its children. */
-
- public void dump(String prefix) {
- System.out.println(toString(prefix));
- if (children != null) {
- for (int i = 0; i < children.length; ++i) {
- SimpleNode n = (SimpleNode)children[i];
- if (n != null) {
- n.dump(prefix + " ");
- }
- }
- }
- }
-}
-
diff --git a/src/org/apache/james/mime4j/field/address/parser/Token.java b/src/org/apache/james/mime4j/field/address/parser/Token.java
deleted file mode 100644
index 2382e8e..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/Token.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.address.parser;
-
-/**
- * Describes the input token stream.
- */
-
-public class Token {
-
- /**
- * An integer that describes the kind of this token. This numbering
- * system is determined by JavaCCParser, and a table of these numbers is
- * stored in the file ...Constants.java.
- */
- public int kind;
-
- /**
- * beginLine and beginColumn describe the position of the first character
- * of this token; endLine and endColumn describe the position of the
- * last character of this token.
- */
- public int beginLine, beginColumn, endLine, endColumn;
-
- /**
- * The string image of the token.
- */
- public String image;
-
- /**
- * A reference to the next regular (non-special) token from the input
- * stream. If this is the last token from the input stream, or if the
- * token manager has not read tokens beyond this one, this field is
- * set to null. This is true only if this token is also a regular
- * token. Otherwise, see below for a description of the contents of
- * this field.
- */
- public Token next;
-
- /**
- * This field is used to access special tokens that occur prior to this
- * token, but after the immediately preceding regular (non-special) token.
- * If there are no such special tokens, this field is set to null.
- * When there are more than one such special token, this field refers
- * to the last of these special tokens, which in turn refers to the next
- * previous special token through its specialToken field, and so on
- * until the first special token (whose specialToken field is null).
- * The next fields of special tokens refer to other special tokens that
- * immediately follow it (without an intervening regular token). If there
- * is no such token, this field is null.
- */
- public Token specialToken;
-
- /**
- * Returns the image.
- */
- public String toString()
- {
- return image;
- }
-
- /**
- * Returns a new Token object, by default. However, if you want, you
- * can create and return subclass objects based on the value of ofKind.
- * Simply add the cases to the switch for all those special cases.
- * For example, if you have a subclass of Token called IDToken that
- * you want to create if ofKind is ID, simlpy add something like :
- *
- * case MyParserConstants.ID : return new IDToken();
- *
- * to the following switch statement. Then you can cast matchedToken
- * variable to the appropriate type and use it in your lexical actions.
- */
- public static final Token newToken(int ofKind)
- {
- switch(ofKind)
- {
- default : return new Token();
- }
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java
deleted file mode 100644
index 0299c85..0000000
--- a/src/org/apache/james/mime4j/field/address/parser/TokenMgrError.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.address.parser;
-
-public class TokenMgrError extends Error
-{
- /*
- * Ordinals for various reasons why an Error of this type can be thrown.
- */
-
- /**
- * Lexical error occured.
- */
- static final int LEXICAL_ERROR = 0;
-
- /**
- * An attempt wass made to create a second instance of a static token manager.
- */
- static final int STATIC_LEXER_ERROR = 1;
-
- /**
- * Tried to change to an invalid lexical state.
- */
- static final int INVALID_LEXICAL_STATE = 2;
-
- /**
- * Detected (and bailed out of) an infinite loop in the token manager.
- */
- static final int LOOP_DETECTED = 3;
-
- /**
- * Indicates the reason why the exception is thrown. It will have
- * one of the above 4 values.
- */
- int errorCode;
-
- /**
- * Replaces unprintable characters by their espaced (or unicode escaped)
- * equivalents in the given string
- */
- protected static final String addEscapes(String str) {
- StringBuffer retval = new StringBuffer();
- char ch;
- for (int i = 0; i < str.length(); i++) {
- switch (str.charAt(i))
- {
- case 0 :
- continue;
- case '\b':
- retval.append("\\b");
- continue;
- case '\t':
- retval.append("\\t");
- continue;
- case '\n':
- retval.append("\\n");
- continue;
- case '\f':
- retval.append("\\f");
- continue;
- case '\r':
- retval.append("\\r");
- continue;
- case '\"':
- retval.append("\\\"");
- continue;
- case '\'':
- retval.append("\\\'");
- continue;
- case '\\':
- retval.append("\\\\");
- continue;
- default:
- if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
- String s = "0000" + Integer.toString(ch, 16);
- retval.append("\\u" + s.substring(s.length() - 4, s.length()));
- } else {
- retval.append(ch);
- }
- continue;
- }
- }
- return retval.toString();
- }
-
- /**
- * Returns a detailed message for the Error when it is thrown by the
- * token manager to indicate a lexical error.
- * Parameters :
- * EOFSeen : indicates if EOF caused the lexicl error
- * curLexState : lexical state in which this error occured
- * errorLine : line number when the error occured
- * errorColumn : column number when the error occured
- * errorAfter : prefix that was seen before this error occured
- * curchar : the offending character
- * Note: You can customize the lexical error message by modifying this method.
- */
- protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
- return("Lexical error at line " +
- errorLine + ", column " +
- errorColumn + ". Encountered: " +
- (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
- "after : \"" + addEscapes(errorAfter) + "\"");
- }
-
- /**
- * You can also modify the body of this method to customize your error messages.
- * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
- * of end-users concern, so you can return something like :
- *
- * "Internal Error : Please file a bug report .... "
- *
- * from this method for such cases in the release version of your parser.
- */
- public String getMessage() {
- return super.getMessage();
- }
-
- /*
- * Constructors of various flavors follow.
- */
-
- public TokenMgrError() {
- }
-
- public TokenMgrError(String message, int reason) {
- super(message);
- errorCode = reason;
- }
-
- public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
- this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java
deleted file mode 100644
index cacf3af..0000000
--- a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParser.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. ContentTypeParser.java */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.contenttype.parser;
-
-import java.util.ArrayList;
-import java.util.Vector;
-
-public class ContentTypeParser implements ContentTypeParserConstants {
-
- private String type;
- private String subtype;
- private ArrayList<String> paramNames = new ArrayList<String>();
- private ArrayList<String> paramValues = new ArrayList<String>();
-
- public String getType() { return type; }
- public String getSubType() { return subtype; }
- public ArrayList<String> getParamNames() { return paramNames; }
- public ArrayList<String> getParamValues() { return paramValues; }
-
- public static void main(String args[]) throws ParseException {
- while (true) {
- try {
- ContentTypeParser parser = new ContentTypeParser(System.in);
- parser.parseLine();
- } catch (Exception x) {
- x.printStackTrace();
- return;
- }
- }
- }
-
- final public void parseLine() throws ParseException {
- parse();
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 1:
- jj_consume_token(1);
- break;
- default:
- jj_la1[0] = jj_gen;
- ;
- }
- jj_consume_token(2);
- }
-
- final public void parseAll() throws ParseException {
- parse();
- jj_consume_token(0);
- }
-
- final public void parse() throws ParseException {
- Token type;
- Token subtype;
- type = jj_consume_token(ATOKEN);
- jj_consume_token(3);
- subtype = jj_consume_token(ATOKEN);
- this.type = type.image;
- this.subtype = subtype.image;
- label_1:
- while (true) {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 4:
- ;
- break;
- default:
- jj_la1[1] = jj_gen;
- break label_1;
- }
- jj_consume_token(4);
- parameter();
- }
- }
-
- final public void parameter() throws ParseException {
- Token attrib;
- String val;
- attrib = jj_consume_token(ATOKEN);
- jj_consume_token(5);
- val = value();
- paramNames.add(attrib.image);
- paramValues.add(val);
- }
-
- final public String value() throws ParseException {
- Token t;
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case ATOKEN:
- t = jj_consume_token(ATOKEN);
- break;
- case QUOTEDSTRING:
- t = jj_consume_token(QUOTEDSTRING);
- break;
- default:
- jj_la1[2] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- {if (true) return t.image;}
- throw new Error("Missing return statement in function");
- }
-
- public ContentTypeParserTokenManager token_source;
- SimpleCharStream jj_input_stream;
- public Token token, jj_nt;
- private int jj_ntk;
- private int jj_gen;
- final private int[] jj_la1 = new int[3];
- static private int[] jj_la1_0;
- static {
- jj_la1_0();
- }
- private static void jj_la1_0() {
- jj_la1_0 = new int[] {0x2,0x10,0x280000,};
- }
-
- public ContentTypeParser(java.io.InputStream stream) {
- this(stream, null);
- }
- public ContentTypeParser(java.io.InputStream stream, String encoding) {
- try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
- token_source = new ContentTypeParserTokenManager(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 3; i++) jj_la1[i] = -1;
- }
-
- public void ReInit(java.io.InputStream stream) {
- ReInit(stream, null);
- }
- public void ReInit(java.io.InputStream stream, String encoding) {
- try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
- token_source.ReInit(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 3; i++) jj_la1[i] = -1;
- }
-
- public ContentTypeParser(java.io.Reader stream) {
- jj_input_stream = new SimpleCharStream(stream, 1, 1);
- token_source = new ContentTypeParserTokenManager(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 3; i++) jj_la1[i] = -1;
- }
-
- public void ReInit(java.io.Reader stream) {
- jj_input_stream.ReInit(stream, 1, 1);
- token_source.ReInit(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 3; i++) jj_la1[i] = -1;
- }
-
- public ContentTypeParser(ContentTypeParserTokenManager tm) {
- token_source = tm;
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 3; i++) jj_la1[i] = -1;
- }
-
- public void ReInit(ContentTypeParserTokenManager tm) {
- token_source = tm;
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 3; i++) jj_la1[i] = -1;
- }
-
- final private Token jj_consume_token(int kind) throws ParseException {
- Token oldToken;
- if ((oldToken = token).next != null) token = token.next;
- else token = token.next = token_source.getNextToken();
- jj_ntk = -1;
- if (token.kind == kind) {
- jj_gen++;
- return token;
- }
- token = oldToken;
- jj_kind = kind;
- throw generateParseException();
- }
-
- final public Token getNextToken() {
- if (token.next != null) token = token.next;
- else token = token.next = token_source.getNextToken();
- jj_ntk = -1;
- jj_gen++;
- return token;
- }
-
- final public Token getToken(int index) {
- Token t = token;
- for (int i = 0; i < index; i++) {
- if (t.next != null) t = t.next;
- else t = t.next = token_source.getNextToken();
- }
- return t;
- }
-
- final private int jj_ntk() {
- if ((jj_nt=token.next) == null)
- return (jj_ntk = (token.next=token_source.getNextToken()).kind);
- else
- return (jj_ntk = jj_nt.kind);
- }
-
- private Vector<int[]> jj_expentries = new Vector<int[]>();
- private int[] jj_expentry;
- private int jj_kind = -1;
-
- public ParseException generateParseException() {
- jj_expentries.removeAllElements();
- boolean[] la1tokens = new boolean[24];
- for (int i = 0; i < 24; i++) {
- la1tokens[i] = false;
- }
- if (jj_kind >= 0) {
- la1tokens[jj_kind] = true;
- jj_kind = -1;
- }
- for (int i = 0; i < 3; i++) {
- if (jj_la1[i] == jj_gen) {
- for (int j = 0; j < 32; j++) {
- if ((jj_la1_0[i] & (1<<j)) != 0) {
- la1tokens[j] = true;
- }
- }
- }
- }
- for (int i = 0; i < 24; i++) {
- if (la1tokens[i]) {
- jj_expentry = new int[1];
- jj_expentry[0] = i;
- jj_expentries.addElement(jj_expentry);
- }
- }
- int[][] exptokseq = new int[jj_expentries.size()][];
- for (int i = 0; i < jj_expentries.size(); i++) {
- exptokseq[i] = jj_expentries.elementAt(i);
- }
- return new ParseException(token, exptokseq, tokenImage);
- }
-
- final public void enable_tracing() {
- }
-
- final public void disable_tracing() {
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java
deleted file mode 100644
index d933d80..0000000
--- a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserConstants.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. ContentTypeParserConstants.java */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.contenttype.parser;
-
-public interface ContentTypeParserConstants {
-
- int EOF = 0;
- int WS = 6;
- int COMMENT = 8;
- int QUOTEDSTRING = 19;
- int DIGITS = 20;
- int ATOKEN = 21;
- int QUOTEDPAIR = 22;
- int ANY = 23;
-
- int DEFAULT = 0;
- int INCOMMENT = 1;
- int NESTED_COMMENT = 2;
- int INQUOTEDSTRING = 3;
-
- String[] tokenImage = {
- "<EOF>",
- "\"\\r\"",
- "\"\\n\"",
- "\"/\"",
- "\";\"",
- "\"=\"",
- "<WS>",
- "\"(\"",
- "\")\"",
- "<token of kind 9>",
- "\"(\"",
- "<token of kind 11>",
- "<token of kind 12>",
- "\"(\"",
- "\")\"",
- "<token of kind 15>",
- "\"\\\"\"",
- "<token of kind 17>",
- "<token of kind 18>",
- "\"\\\"\"",
- "<DIGITS>",
- "<ATOKEN>",
- "<QUOTEDPAIR>",
- "<ANY>",
- };
-
-}
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java b/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java
deleted file mode 100644
index 25b7aba..0000000
--- a/src/org/apache/james/mime4j/field/contenttype/parser/ContentTypeParserTokenManager.java
+++ /dev/null
@@ -1,877 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. ContentTypeParserTokenManager.java */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.contenttype.parser;
-import java.util.ArrayList;
-
-public class ContentTypeParserTokenManager implements ContentTypeParserConstants
-{
- // Keeps track of how many levels of comment nesting
- // we've encountered. This is only used when the 2nd
- // level is reached, for example ((this)), not (this).
- // This is because the outermost level must be treated
- // specially anyway, because the outermost ")" has a
- // different token type than inner ")" instances.
- static int commentNest;
- public java.io.PrintStream debugStream = System.out;
- public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
-private final int jjStopStringLiteralDfa_0(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_0(int pos, long active0)
-{
- return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
-}
-private final int jjStopAtPos(int pos, int kind)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- return pos + 1;
-}
-private final int jjStartNfaWithStates_0(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_0(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_0()
-{
- switch(curChar)
- {
- case 10:
- return jjStartNfaWithStates_0(0, 2, 2);
- case 13:
- return jjStartNfaWithStates_0(0, 1, 2);
- case 34:
- return jjStopAtPos(0, 16);
- case 40:
- return jjStopAtPos(0, 7);
- case 47:
- return jjStopAtPos(0, 3);
- case 59:
- return jjStopAtPos(0, 4);
- case 61:
- return jjStopAtPos(0, 5);
- default :
- return jjMoveNfa_0(3, 0);
- }
-}
-private final void jjCheckNAdd(int state)
-{
- if (jjrounds[state] != jjround)
- {
- jjstateSet[jjnewStateCnt++] = state;
- jjrounds[state] = jjround;
- }
-}
-private final void jjAddStates(int start, int end)
-{
- do {
- jjstateSet[jjnewStateCnt++] = jjnextStates[start];
- } while (start++ != end);
-}
-private final void jjCheckNAddTwoStates(int state1, int state2)
-{
- jjCheckNAdd(state1);
- jjCheckNAdd(state2);
-}
-private final void jjCheckNAddStates(int start, int end)
-{
- do {
- jjCheckNAdd(jjnextStates[start]);
- } while (start++ != end);
-}
-private final void jjCheckNAddStates(int start)
-{
- jjCheckNAdd(jjnextStates[start]);
- jjCheckNAdd(jjnextStates[start + 1]);
-}
-static final long[] jjbitVec0 = {
- 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
-};
-private final int jjMoveNfa_0(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 3:
- if ((0x3ff6cfafffffdffL & l) != 0L)
- {
- if (kind > 21)
- kind = 21;
- jjCheckNAdd(2);
- }
- else if ((0x100000200L & l) != 0L)
- {
- if (kind > 6)
- kind = 6;
- jjCheckNAdd(0);
- }
- if ((0x3ff000000000000L & l) != 0L)
- {
- if (kind > 20)
- kind = 20;
- jjCheckNAdd(1);
- }
- break;
- case 0:
- if ((0x100000200L & l) == 0L)
- break;
- kind = 6;
- jjCheckNAdd(0);
- break;
- case 1:
- if ((0x3ff000000000000L & l) == 0L)
- break;
- if (kind > 20)
- kind = 20;
- jjCheckNAdd(1);
- break;
- case 2:
- if ((0x3ff6cfafffffdffL & l) == 0L)
- break;
- if (kind > 21)
- kind = 21;
- jjCheckNAdd(2);
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 3:
- case 2:
- if ((0xffffffffc7fffffeL & l) == 0L)
- break;
- kind = 21;
- jjCheckNAdd(2);
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 3:
- case 2:
- if ((jjbitVec0[i2] & l2) == 0L)
- break;
- if (kind > 21)
- kind = 21;
- jjCheckNAdd(2);
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-private final int jjStopStringLiteralDfa_1(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_1(int pos, long active0)
-{
- return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1);
-}
-private final int jjStartNfaWithStates_1(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_1(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_1()
-{
- switch(curChar)
- {
- case 40:
- return jjStopAtPos(0, 10);
- case 41:
- return jjStopAtPos(0, 8);
- default :
- return jjMoveNfa_1(0, 0);
- }
-}
-private final int jjMoveNfa_1(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 11)
- kind = 11;
- break;
- case 1:
- if (kind > 9)
- kind = 9;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 11)
- kind = 11;
- if (curChar == 92)
- jjstateSet[jjnewStateCnt++] = 1;
- break;
- case 1:
- if (kind > 9)
- kind = 9;
- break;
- case 2:
- if (kind > 11)
- kind = 11;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 11)
- kind = 11;
- break;
- case 1:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 9)
- kind = 9;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-private final int jjStopStringLiteralDfa_3(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_3(int pos, long active0)
-{
- return jjMoveNfa_3(jjStopStringLiteralDfa_3(pos, active0), pos + 1);
-}
-private final int jjStartNfaWithStates_3(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_3(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_3()
-{
- switch(curChar)
- {
- case 34:
- return jjStopAtPos(0, 19);
- default :
- return jjMoveNfa_3(0, 0);
- }
-}
-private final int jjMoveNfa_3(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- case 2:
- if ((0xfffffffbffffffffL & l) == 0L)
- break;
- if (kind > 18)
- kind = 18;
- jjCheckNAdd(2);
- break;
- case 1:
- if (kind > 17)
- kind = 17;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((0xffffffffefffffffL & l) != 0L)
- {
- if (kind > 18)
- kind = 18;
- jjCheckNAdd(2);
- }
- else if (curChar == 92)
- jjstateSet[jjnewStateCnt++] = 1;
- break;
- case 1:
- if (kind > 17)
- kind = 17;
- break;
- case 2:
- if ((0xffffffffefffffffL & l) == 0L)
- break;
- if (kind > 18)
- kind = 18;
- jjCheckNAdd(2);
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- case 2:
- if ((jjbitVec0[i2] & l2) == 0L)
- break;
- if (kind > 18)
- kind = 18;
- jjCheckNAdd(2);
- break;
- case 1:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 17)
- kind = 17;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-private final int jjStopStringLiteralDfa_2(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_2(int pos, long active0)
-{
- return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1);
-}
-private final int jjStartNfaWithStates_2(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_2(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_2()
-{
- switch(curChar)
- {
- case 40:
- return jjStopAtPos(0, 13);
- case 41:
- return jjStopAtPos(0, 14);
- default :
- return jjMoveNfa_2(0, 0);
- }
-}
-private final int jjMoveNfa_2(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 15)
- kind = 15;
- break;
- case 1:
- if (kind > 12)
- kind = 12;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 15)
- kind = 15;
- if (curChar == 92)
- jjstateSet[jjnewStateCnt++] = 1;
- break;
- case 1:
- if (kind > 12)
- kind = 12;
- break;
- case 2:
- if (kind > 15)
- kind = 15;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 15)
- kind = 15;
- break;
- case 1:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 12)
- kind = 12;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-static final int[] jjnextStates = {
-};
-public static final String[] jjstrLiteralImages = {
-"", "\15", "\12", "\57", "\73", "\75", null, null, null, null, null, null,
-null, null, null, null, null, null, null, null, null, null, null, null, };
-public static final String[] lexStateNames = {
- "DEFAULT",
- "INCOMMENT",
- "NESTED_COMMENT",
- "INQUOTEDSTRING",
-};
-public static final int[] jjnewLexState = {
- -1, -1, -1, -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, 3, -1, -1, 0, -1, -1, -1, -1,
-};
-static final long[] jjtoToken = {
- 0x38003fL,
-};
-static final long[] jjtoSkip = {
- 0x140L,
-};
-static final long[] jjtoSpecial = {
- 0x40L,
-};
-static final long[] jjtoMore = {
- 0x7fe80L,
-};
-protected SimpleCharStream input_stream;
-private final int[] jjrounds = new int[3];
-private final int[] jjstateSet = new int[6];
-StringBuffer image;
-int jjimageLen;
-int lengthOfMatch;
-protected char curChar;
-public ContentTypeParserTokenManager(SimpleCharStream stream){
- if (SimpleCharStream.staticFlag)
- throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
- input_stream = stream;
-}
-public ContentTypeParserTokenManager(SimpleCharStream stream, int lexState){
- this(stream);
- SwitchTo(lexState);
-}
-public void ReInit(SimpleCharStream stream)
-{
- jjmatchedPos = jjnewStateCnt = 0;
- curLexState = defaultLexState;
- input_stream = stream;
- ReInitRounds();
-}
-private final void ReInitRounds()
-{
- int i;
- jjround = 0x80000001;
- for (i = 3; i-- > 0;)
- jjrounds[i] = 0x80000000;
-}
-public void ReInit(SimpleCharStream stream, int lexState)
-{
- ReInit(stream);
- SwitchTo(lexState);
-}
-public void SwitchTo(int lexState)
-{
- if (lexState >= 4 || lexState < 0)
- throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
- else
- curLexState = lexState;
-}
-
-protected Token jjFillToken()
-{
- Token t = Token.newToken(jjmatchedKind);
- t.kind = jjmatchedKind;
- String im = jjstrLiteralImages[jjmatchedKind];
- t.image = (im == null) ? input_stream.GetImage() : im;
- t.beginLine = input_stream.getBeginLine();
- t.beginColumn = input_stream.getBeginColumn();
- t.endLine = input_stream.getEndLine();
- t.endColumn = input_stream.getEndColumn();
- return t;
-}
-
-int curLexState = 0;
-int defaultLexState = 0;
-int jjnewStateCnt;
-int jjround;
-int jjmatchedPos;
-int jjmatchedKind;
-
-public Token getNextToken()
-{
- int kind;
- Token specialToken = null;
- Token matchedToken;
- int curPos = 0;
-
- EOFLoop :
- for (;;)
- {
- try
- {
- curChar = input_stream.BeginToken();
- }
- catch(java.io.IOException e)
- {
- jjmatchedKind = 0;
- matchedToken = jjFillToken();
- matchedToken.specialToken = specialToken;
- return matchedToken;
- }
- image = null;
- jjimageLen = 0;
-
- for (;;)
- {
- switch(curLexState)
- {
- case 0:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_0();
- break;
- case 1:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_1();
- break;
- case 2:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_2();
- break;
- case 3:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_3();
- break;
- }
- if (jjmatchedKind != 0x7fffffff)
- {
- if (jjmatchedPos + 1 < curPos)
- input_stream.backup(curPos - jjmatchedPos - 1);
- if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
- {
- matchedToken = jjFillToken();
- matchedToken.specialToken = specialToken;
- TokenLexicalActions(matchedToken);
- if (jjnewLexState[jjmatchedKind] != -1)
- curLexState = jjnewLexState[jjmatchedKind];
- return matchedToken;
- }
- else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
- {
- if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
- {
- matchedToken = jjFillToken();
- if (specialToken == null)
- specialToken = matchedToken;
- else
- {
- matchedToken.specialToken = specialToken;
- specialToken = (specialToken.next = matchedToken);
- }
- }
- if (jjnewLexState[jjmatchedKind] != -1)
- curLexState = jjnewLexState[jjmatchedKind];
- continue EOFLoop;
- }
- MoreLexicalActions();
- if (jjnewLexState[jjmatchedKind] != -1)
- curLexState = jjnewLexState[jjmatchedKind];
- curPos = 0;
- jjmatchedKind = 0x7fffffff;
- try {
- curChar = input_stream.readChar();
- continue;
- }
- catch (java.io.IOException e1) { }
- }
- int error_line = input_stream.getEndLine();
- int error_column = input_stream.getEndColumn();
- String error_after = null;
- boolean EOFSeen = false;
- try { input_stream.readChar(); input_stream.backup(1); }
- catch (java.io.IOException e1) {
- EOFSeen = true;
- error_after = curPos <= 1 ? "" : input_stream.GetImage();
- if (curChar == '\n' || curChar == '\r') {
- error_line++;
- error_column = 0;
- }
- else
- error_column++;
- }
- if (!EOFSeen) {
- input_stream.backup(1);
- error_after = curPos <= 1 ? "" : input_stream.GetImage();
- }
- throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
- }
- }
-}
-
-void MoreLexicalActions()
-{
- jjimageLen += (lengthOfMatch = jjmatchedPos + 1);
- switch(jjmatchedKind)
- {
- case 9 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 2);
- break;
- case 10 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- commentNest = 1;
- break;
- case 12 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 2);
- break;
- case 13 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- ++commentNest;
- break;
- case 14 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT);
- break;
- case 16 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 1);
- break;
- case 17 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 2);
- break;
- default :
- break;
- }
-}
-void TokenLexicalActions(Token matchedToken)
-{
- switch(jjmatchedKind)
- {
- case 19 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
- matchedToken.image = image.substring(0, image.length() - 1);
- break;
- default :
- break;
- }
-}
-}
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java b/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java
deleted file mode 100644
index d9b69b2..0000000
--- a/src/org/apache/james/mime4j/field/contenttype/parser/ParseException.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.contenttype.parser;
-
-/**
- * This exception is thrown when parse errors are encountered.
- * You can explicitly create objects of this exception type by
- * calling the method generateParseException in the generated
- * parser.
- *
- * You can modify this class to customize your error reporting
- * mechanisms so long as you retain the public fields.
- */
-public class ParseException extends Exception {
-
- /**
- * This constructor is used by the method "generateParseException"
- * in the generated parser. Calling this constructor generates
- * a new object of this type with the fields "currentToken",
- * "expectedTokenSequences", and "tokenImage" set. The boolean
- * flag "specialConstructor" is also set to true to indicate that
- * this constructor was used to create this object.
- * This constructor calls its super class with the empty string
- * to force the "toString" method of parent class "Throwable" to
- * print the error message in the form:
- * ParseException: <result of getMessage>
- */
- public ParseException(Token currentTokenVal,
- int[][] expectedTokenSequencesVal,
- String[] tokenImageVal
- )
- {
- super("");
- specialConstructor = true;
- currentToken = currentTokenVal;
- expectedTokenSequences = expectedTokenSequencesVal;
- tokenImage = tokenImageVal;
- }
-
- /**
- * The following constructors are for use by you for whatever
- * purpose you can think of. Constructing the exception in this
- * manner makes the exception behave in the normal way - i.e., as
- * documented in the class "Throwable". The fields "errorToken",
- * "expectedTokenSequences", and "tokenImage" do not contain
- * relevant information. The JavaCC generated code does not use
- * these constructors.
- */
-
- public ParseException() {
- super();
- specialConstructor = false;
- }
-
- public ParseException(String message) {
- super(message);
- specialConstructor = false;
- }
-
- /**
- * This variable determines which constructor was used to create
- * this object and thereby affects the semantics of the
- * "getMessage" method (see below).
- */
- protected boolean specialConstructor;
-
- /**
- * This is the last token that has been consumed successfully. If
- * this object has been created due to a parse error, the token
- * followng this token will (therefore) be the first error token.
- */
- public Token currentToken;
-
- /**
- * Each entry in this array is an array of integers. Each array
- * of integers represents a sequence of tokens (by their ordinal
- * values) that is expected at this point of the parse.
- */
- public int[][] expectedTokenSequences;
-
- /**
- * This is a reference to the "tokenImage" array of the generated
- * parser within which the parse error occurred. This array is
- * defined in the generated ...Constants interface.
- */
- public String[] tokenImage;
-
- /**
- * This method has the standard behavior when this object has been
- * created using the standard constructors. Otherwise, it uses
- * "currentToken" and "expectedTokenSequences" to generate a parse
- * error message and returns it. If this object has been created
- * due to a parse error, and you do not catch it (it gets thrown
- * from the parser), then this method is called during the printing
- * of the final stack trace, and hence the correct error message
- * gets displayed.
- */
- public String getMessage() {
- if (!specialConstructor) {
- return super.getMessage();
- }
- StringBuffer expected = new StringBuffer();
- int maxSize = 0;
- for (int i = 0; i < expectedTokenSequences.length; i++) {
- if (maxSize < expectedTokenSequences[i].length) {
- maxSize = expectedTokenSequences[i].length;
- }
- for (int j = 0; j < expectedTokenSequences[i].length; j++) {
- expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
- }
- if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
- expected.append("...");
- }
- expected.append(eol).append(" ");
- }
- String retval = "Encountered \"";
- Token tok = currentToken.next;
- for (int i = 0; i < maxSize; i++) {
- if (i != 0) retval += " ";
- if (tok.kind == 0) {
- retval += tokenImage[0];
- break;
- }
- retval += add_escapes(tok.image);
- tok = tok.next;
- }
- retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
- retval += "." + eol;
- if (expectedTokenSequences.length == 1) {
- retval += "Was expecting:" + eol + " ";
- } else {
- retval += "Was expecting one of:" + eol + " ";
- }
- retval += expected.toString();
- return retval;
- }
-
- /**
- * The end of line string for this machine.
- */
- protected String eol = System.getProperty("line.separator", "\n");
-
- /**
- * Used to convert raw characters to their escaped version
- * when these raw version cannot be used as part of an ASCII
- * string literal.
- */
- protected String add_escapes(String str) {
- StringBuffer retval = new StringBuffer();
- char ch;
- for (int i = 0; i < str.length(); i++) {
- switch (str.charAt(i))
- {
- case 0 :
- continue;
- case '\b':
- retval.append("\\b");
- continue;
- case '\t':
- retval.append("\\t");
- continue;
- case '\n':
- retval.append("\\n");
- continue;
- case '\f':
- retval.append("\\f");
- continue;
- case '\r':
- retval.append("\\r");
- continue;
- case '\"':
- retval.append("\\\"");
- continue;
- case '\'':
- retval.append("\\\'");
- continue;
- case '\\':
- retval.append("\\\\");
- continue;
- default:
- if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
- String s = "0000" + Integer.toString(ch, 16);
- retval.append("\\u" + s.substring(s.length() - 4, s.length()));
- } else {
- retval.append(ch);
- }
- continue;
- }
- }
- return retval.toString();
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java
deleted file mode 100644
index ae035b7..0000000
--- a/src/org/apache/james/mime4j/field/contenttype/parser/SimpleCharStream.java
+++ /dev/null
@@ -1,454 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.contenttype.parser;
-
-/**
- * An implementation of interface CharStream, where the stream is assumed to
- * contain only ASCII characters (without unicode processing).
- */
-
-public class SimpleCharStream
-{
- public static final boolean staticFlag = false;
- int bufsize;
- int available;
- int tokenBegin;
- public int bufpos = -1;
- protected int bufline[];
- protected int bufcolumn[];
-
- protected int column = 0;
- protected int line = 1;
-
- protected boolean prevCharIsCR = false;
- protected boolean prevCharIsLF = false;
-
- protected java.io.Reader inputStream;
-
- protected char[] buffer;
- protected int maxNextCharInd = 0;
- protected int inBuf = 0;
- protected int tabSize = 8;
-
- protected void setTabSize(int i) { tabSize = i; }
- protected int getTabSize(int i) { return tabSize; }
-
-
- protected void ExpandBuff(boolean wrapAround)
- {
- char[] newbuffer = new char[bufsize + 2048];
- int newbufline[] = new int[bufsize + 2048];
- int newbufcolumn[] = new int[bufsize + 2048];
-
- try
- {
- if (wrapAround)
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- System.arraycopy(buffer, 0, newbuffer,
- bufsize - tokenBegin, bufpos);
- buffer = newbuffer;
-
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
- bufline = newbufline;
-
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
- bufcolumn = newbufcolumn;
-
- maxNextCharInd = (bufpos += (bufsize - tokenBegin));
- }
- else
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- buffer = newbuffer;
-
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- bufline = newbufline;
-
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- bufcolumn = newbufcolumn;
-
- maxNextCharInd = (bufpos -= tokenBegin);
- }
- }
- catch (Throwable t)
- {
- throw new Error(t.getMessage());
- }
-
-
- bufsize += 2048;
- available = bufsize;
- tokenBegin = 0;
- }
-
- protected void FillBuff() throws java.io.IOException
- {
- if (maxNextCharInd == available)
- {
- if (available == bufsize)
- {
- if (tokenBegin > 2048)
- {
- bufpos = maxNextCharInd = 0;
- available = tokenBegin;
- }
- else if (tokenBegin < 0)
- bufpos = maxNextCharInd = 0;
- else
- ExpandBuff(false);
- }
- else if (available > tokenBegin)
- available = bufsize;
- else if ((tokenBegin - available) < 2048)
- ExpandBuff(true);
- else
- available = tokenBegin;
- }
-
- int i;
- try {
- if ((i = inputStream.read(buffer, maxNextCharInd,
- available - maxNextCharInd)) == -1)
- {
- inputStream.close();
- throw new java.io.IOException();
- }
- else
- maxNextCharInd += i;
- return;
- }
- catch(java.io.IOException e) {
- --bufpos;
- backup(0);
- if (tokenBegin == -1)
- tokenBegin = bufpos;
- throw e;
- }
- }
-
- public char BeginToken() throws java.io.IOException
- {
- tokenBegin = -1;
- char c = readChar();
- tokenBegin = bufpos;
-
- return c;
- }
-
- protected void UpdateLineColumn(char c)
- {
- column++;
-
- if (prevCharIsLF)
- {
- prevCharIsLF = false;
- line += (column = 1);
- }
- else if (prevCharIsCR)
- {
- prevCharIsCR = false;
- if (c == '\n')
- {
- prevCharIsLF = true;
- }
- else
- line += (column = 1);
- }
-
- switch (c)
- {
- case '\r' :
- prevCharIsCR = true;
- break;
- case '\n' :
- prevCharIsLF = true;
- break;
- case '\t' :
- column--;
- column += (tabSize - (column % tabSize));
- break;
- default :
- break;
- }
-
- bufline[bufpos] = line;
- bufcolumn[bufpos] = column;
- }
-
- public char readChar() throws java.io.IOException
- {
- if (inBuf > 0)
- {
- --inBuf;
-
- if (++bufpos == bufsize)
- bufpos = 0;
-
- return buffer[bufpos];
- }
-
- if (++bufpos >= maxNextCharInd)
- FillBuff();
-
- char c = buffer[bufpos];
-
- UpdateLineColumn(c);
- return (c);
- }
-
- /**
- * @deprecated
- * @see #getEndColumn
- */
- @Deprecated
- public int getColumn() {
- return bufcolumn[bufpos];
- }
-
- /**
- * @deprecated
- * @see #getEndLine
- */
- @Deprecated
- public int getLine() {
- return bufline[bufpos];
- }
-
- public int getEndColumn() {
- return bufcolumn[bufpos];
- }
-
- public int getEndLine() {
- return bufline[bufpos];
- }
-
- public int getBeginColumn() {
- return bufcolumn[tokenBegin];
- }
-
- public int getBeginLine() {
- return bufline[tokenBegin];
- }
-
- public void backup(int amount) {
-
- inBuf += amount;
- if ((bufpos -= amount) < 0)
- bufpos += bufsize;
- }
-
- public SimpleCharStream(java.io.Reader dstream, int startline,
- int startcolumn, int buffersize)
- {
- inputStream = dstream;
- line = startline;
- column = startcolumn - 1;
-
- available = bufsize = buffersize;
- buffer = new char[buffersize];
- bufline = new int[buffersize];
- bufcolumn = new int[buffersize];
- }
-
- public SimpleCharStream(java.io.Reader dstream, int startline,
- int startcolumn)
- {
- this(dstream, startline, startcolumn, 4096);
- }
-
- public SimpleCharStream(java.io.Reader dstream)
- {
- this(dstream, 1, 1, 4096);
- }
- public void ReInit(java.io.Reader dstream, int startline,
- int startcolumn, int buffersize)
- {
- inputStream = dstream;
- line = startline;
- column = startcolumn - 1;
-
- if (buffer == null || buffersize != buffer.length)
- {
- available = bufsize = buffersize;
- buffer = new char[buffersize];
- bufline = new int[buffersize];
- bufcolumn = new int[buffersize];
- }
- prevCharIsLF = prevCharIsCR = false;
- tokenBegin = inBuf = maxNextCharInd = 0;
- bufpos = -1;
- }
-
- public void ReInit(java.io.Reader dstream, int startline,
- int startcolumn)
- {
- ReInit(dstream, startline, startcolumn, 4096);
- }
-
- public void ReInit(java.io.Reader dstream)
- {
- ReInit(dstream, 1, 1, 4096);
- }
- public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
- {
- this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, int startline,
- int startcolumn, int buffersize)
- {
- this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn) throws java.io.UnsupportedEncodingException
- {
- this(dstream, encoding, startline, startcolumn, 4096);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, int startline,
- int startcolumn)
- {
- this(dstream, startline, startcolumn, 4096);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
- {
- this(dstream, encoding, 1, 1, 4096);
- }
-
- public SimpleCharStream(java.io.InputStream dstream)
- {
- this(dstream, 1, 1, 4096);
- }
-
- public void ReInit(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
- {
- ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
- }
-
- public void ReInit(java.io.InputStream dstream, int startline,
- int startcolumn, int buffersize)
- {
- ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
- }
-
- public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
- {
- ReInit(dstream, encoding, 1, 1, 4096);
- }
-
- public void ReInit(java.io.InputStream dstream)
- {
- ReInit(dstream, 1, 1, 4096);
- }
- public void ReInit(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn) throws java.io.UnsupportedEncodingException
- {
- ReInit(dstream, encoding, startline, startcolumn, 4096);
- }
- public void ReInit(java.io.InputStream dstream, int startline,
- int startcolumn)
- {
- ReInit(dstream, startline, startcolumn, 4096);
- }
- public String GetImage()
- {
- if (bufpos >= tokenBegin)
- return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
- else
- return new String(buffer, tokenBegin, bufsize - tokenBegin) +
- new String(buffer, 0, bufpos + 1);
- }
-
- public char[] GetSuffix(int len)
- {
- char[] ret = new char[len];
-
- if ((bufpos + 1) >= len)
- System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
- else
- {
- System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
- len - bufpos - 1);
- System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
- }
-
- return ret;
- }
-
- public void Done()
- {
- buffer = null;
- bufline = null;
- bufcolumn = null;
- }
-
- /**
- * Method to adjust line and column numbers for the start of a token.
- */
- public void adjustBeginLineColumn(int newLine, int newCol)
- {
- int start = tokenBegin;
- int len;
-
- if (bufpos >= tokenBegin)
- {
- len = bufpos - tokenBegin + inBuf + 1;
- }
- else
- {
- len = bufsize - tokenBegin + bufpos + 1 + inBuf;
- }
-
- int i = 0, j = 0, k = 0;
- int nextColDiff = 0, columnDiff = 0;
-
- while (i < len &&
- bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
- {
- bufline[j] = newLine;
- nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
- bufcolumn[j] = newCol + columnDiff;
- columnDiff = nextColDiff;
- i++;
- }
-
- if (i < len)
- {
- bufline[j] = newLine++;
- bufcolumn[j] = newCol + columnDiff;
-
- while (i++ < len)
- {
- if (bufline[j = start % bufsize] != bufline[++start % bufsize])
- bufline[j] = newLine++;
- else
- bufline[j] = newLine;
- }
- }
-
- line = bufline[j];
- column = bufcolumn[j];
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/Token.java b/src/org/apache/james/mime4j/field/contenttype/parser/Token.java
deleted file mode 100644
index 34e65ee..0000000
--- a/src/org/apache/james/mime4j/field/contenttype/parser/Token.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.contenttype.parser;
-
-/**
- * Describes the input token stream.
- */
-
-public class Token {
-
- /**
- * An integer that describes the kind of this token. This numbering
- * system is determined by JavaCCParser, and a table of these numbers is
- * stored in the file ...Constants.java.
- */
- public int kind;
-
- /**
- * beginLine and beginColumn describe the position of the first character
- * of this token; endLine and endColumn describe the position of the
- * last character of this token.
- */
- public int beginLine, beginColumn, endLine, endColumn;
-
- /**
- * The string image of the token.
- */
- public String image;
-
- /**
- * A reference to the next regular (non-special) token from the input
- * stream. If this is the last token from the input stream, or if the
- * token manager has not read tokens beyond this one, this field is
- * set to null. This is true only if this token is also a regular
- * token. Otherwise, see below for a description of the contents of
- * this field.
- */
- public Token next;
-
- /**
- * This field is used to access special tokens that occur prior to this
- * token, but after the immediately preceding regular (non-special) token.
- * If there are no such special tokens, this field is set to null.
- * When there are more than one such special token, this field refers
- * to the last of these special tokens, which in turn refers to the next
- * previous special token through its specialToken field, and so on
- * until the first special token (whose specialToken field is null).
- * The next fields of special tokens refer to other special tokens that
- * immediately follow it (without an intervening regular token). If there
- * is no such token, this field is null.
- */
- public Token specialToken;
-
- /**
- * Returns the image.
- */
- public String toString()
- {
- return image;
- }
-
- /**
- * Returns a new Token object, by default. However, if you want, you
- * can create and return subclass objects based on the value of ofKind.
- * Simply add the cases to the switch for all those special cases.
- * For example, if you have a subclass of Token called IDToken that
- * you want to create if ofKind is ID, simlpy add something like :
- *
- * case MyParserConstants.ID : return new IDToken();
- *
- * to the following switch statement. Then you can cast matchedToken
- * variable to the appropriate type and use it in your lexical actions.
- */
- public static final Token newToken(int ofKind)
- {
- switch(ofKind)
- {
- default : return new Token();
- }
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java
deleted file mode 100644
index ea5a782..0000000
--- a/src/org/apache/james/mime4j/field/contenttype/parser/TokenMgrError.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.contenttype.parser;
-
-public class TokenMgrError extends Error
-{
- /*
- * Ordinals for various reasons why an Error of this type can be thrown.
- */
-
- /**
- * Lexical error occured.
- */
- static final int LEXICAL_ERROR = 0;
-
- /**
- * An attempt wass made to create a second instance of a static token manager.
- */
- static final int STATIC_LEXER_ERROR = 1;
-
- /**
- * Tried to change to an invalid lexical state.
- */
- static final int INVALID_LEXICAL_STATE = 2;
-
- /**
- * Detected (and bailed out of) an infinite loop in the token manager.
- */
- static final int LOOP_DETECTED = 3;
-
- /**
- * Indicates the reason why the exception is thrown. It will have
- * one of the above 4 values.
- */
- int errorCode;
-
- /**
- * Replaces unprintable characters by their espaced (or unicode escaped)
- * equivalents in the given string
- */
- protected static final String addEscapes(String str) {
- StringBuffer retval = new StringBuffer();
- char ch;
- for (int i = 0; i < str.length(); i++) {
- switch (str.charAt(i))
- {
- case 0 :
- continue;
- case '\b':
- retval.append("\\b");
- continue;
- case '\t':
- retval.append("\\t");
- continue;
- case '\n':
- retval.append("\\n");
- continue;
- case '\f':
- retval.append("\\f");
- continue;
- case '\r':
- retval.append("\\r");
- continue;
- case '\"':
- retval.append("\\\"");
- continue;
- case '\'':
- retval.append("\\\'");
- continue;
- case '\\':
- retval.append("\\\\");
- continue;
- default:
- if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
- String s = "0000" + Integer.toString(ch, 16);
- retval.append("\\u" + s.substring(s.length() - 4, s.length()));
- } else {
- retval.append(ch);
- }
- continue;
- }
- }
- return retval.toString();
- }
-
- /**
- * Returns a detailed message for the Error when it is thrown by the
- * token manager to indicate a lexical error.
- * Parameters :
- * EOFSeen : indicates if EOF caused the lexicl error
- * curLexState : lexical state in which this error occured
- * errorLine : line number when the error occured
- * errorColumn : column number when the error occured
- * errorAfter : prefix that was seen before this error occured
- * curchar : the offending character
- * Note: You can customize the lexical error message by modifying this method.
- */
- protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
- return("Lexical error at line " +
- errorLine + ", column " +
- errorColumn + ". Encountered: " +
- (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
- "after : \"" + addEscapes(errorAfter) + "\"");
- }
-
- /**
- * You can also modify the body of this method to customize your error messages.
- * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
- * of end-users concern, so you can return something like :
- *
- * "Internal Error : Please file a bug report .... "
- *
- * from this method for such cases in the release version of your parser.
- */
- public String getMessage() {
- return super.getMessage();
- }
-
- /*
- * Constructors of various flavors follow.
- */
-
- public TokenMgrError() {
- }
-
- public TokenMgrError(String message, int reason) {
- super(message);
- errorCode = reason;
- }
-
- public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
- this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
- }
-}
diff --git a/src/org/apache/james/mime4j/field/datetime/DateTime.java b/src/org/apache/james/mime4j/field/datetime/DateTime.java
deleted file mode 100644
index 506ff54..0000000
--- a/src/org/apache/james/mime4j/field/datetime/DateTime.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.field.datetime;
-
-import org.apache.james.mime4j.field.datetime.parser.DateTimeParser;
-import org.apache.james.mime4j.field.datetime.parser.ParseException;
-import org.apache.james.mime4j.field.datetime.parser.TokenMgrError;
-
-import java.util.Date;
-import java.util.Calendar;
-import java.util.TimeZone;
-import java.util.GregorianCalendar;
-import java.io.StringReader;
-
-public class DateTime {
- private final Date date;
- private final int year;
- private final int month;
- private final int day;
- private final int hour;
- private final int minute;
- private final int second;
- private final int timeZone;
-
- public DateTime(String yearString, int month, int day, int hour, int minute, int second, int timeZone) {
- this.year = convertToYear(yearString);
- this.date = convertToDate(year, month, day, hour, minute, second, timeZone);
- this.month = month;
- this.day = day;
- this.hour = hour;
- this.minute = minute;
- this.second = second;
- this.timeZone = timeZone;
- }
-
- private int convertToYear(String yearString) {
- int year = Integer.parseInt(yearString);
- switch (yearString.length()) {
- case 1:
- case 2:
- if (year >= 0 && year < 50)
- return 2000 + year;
- else
- return 1900 + year;
- case 3:
- return 1900 + year;
- default:
- return year;
- }
- }
-
- public static Date convertToDate(int year, int month, int day, int hour, int minute, int second, int timeZone) {
- Calendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT+0"));
- c.set(year, month - 1, day, hour, minute, second);
- c.set(Calendar.MILLISECOND, 0);
-
- if (timeZone != Integer.MIN_VALUE) {
- int minutes = ((timeZone / 100) * 60) + timeZone % 100;
- c.add(Calendar.MINUTE, -1 * minutes);
- }
-
- return c.getTime();
- }
-
- public Date getDate() {
- return date;
- }
-
- public int getYear() {
- return year;
- }
-
- public int getMonth() {
- return month;
- }
-
- public int getDay() {
- return day;
- }
-
- public int getHour() {
- return hour;
- }
-
- public int getMinute() {
- return minute;
- }
-
- public int getSecond() {
- return second;
- }
-
- public int getTimeZone() {
- return timeZone;
- }
-
- public void print() {
- System.out.println(getYear() + " " + getMonth() + " " + getDay() + "; " + getHour() + " " + getMinute() + " " + getSecond() + " " + getTimeZone());
- }
-
-
- public static DateTime parse(String dateString) throws ParseException {
- try {
- return new DateTimeParser(new StringReader(dateString)).parseAll();
- }
- catch (TokenMgrError err) {
- throw new ParseException(err.getMessage());
- }
- }
-}
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java
deleted file mode 100644
index 43edebb..0000000
--- a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParser.java
+++ /dev/null
@@ -1,570 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. DateTimeParser.java */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.datetime.parser;
-
-import org.apache.james.mime4j.field.datetime.DateTime;
-
-import java.util.Vector;
-
-public class DateTimeParser implements DateTimeParserConstants {
- private static final boolean ignoreMilitaryZoneOffset = true;
-
- public static void main(String args[]) throws ParseException {
- while (true) {
- try {
- DateTimeParser parser = new DateTimeParser(System.in);
- parser.parseLine();
- } catch (Exception x) {
- x.printStackTrace();
- return;
- }
- }
- }
-
- private static int parseDigits(Token token) {
- return Integer.parseInt(token.image, 10);
- }
-
- private static int getMilitaryZoneOffset(char c) {
- if (ignoreMilitaryZoneOffset)
- return 0;
-
- c = Character.toUpperCase(c);
-
- switch (c) {
- case 'A': return 1;
- case 'B': return 2;
- case 'C': return 3;
- case 'D': return 4;
- case 'E': return 5;
- case 'F': return 6;
- case 'G': return 7;
- case 'H': return 8;
- case 'I': return 9;
- case 'K': return 10;
- case 'L': return 11;
- case 'M': return 12;
-
- case 'N': return -1;
- case 'O': return -2;
- case 'P': return -3;
- case 'Q': return -4;
- case 'R': return -5;
- case 'S': return -6;
- case 'T': return -7;
- case 'U': return -8;
- case 'V': return -9;
- case 'W': return -10;
- case 'X': return -11;
- case 'Y': return -12;
-
- case 'Z': return 0;
- default: return 0;
- }
- }
-
- private static class Time {
- private int hour;
- private int minute;
- private int second;
- private int zone;
-
- public Time(int hour, int minute, int second, int zone) {
- this.hour = hour;
- this.minute = minute;
- this.second = second;
- this.zone = zone;
- }
-
- public int getHour() { return hour; }
- public int getMinute() { return minute; }
- public int getSecond() { return second; }
- public int getZone() { return zone; }
- }
-
- private static class Date {
- private String year;
- private int month;
- private int day;
-
- public Date(String year, int month, int day) {
- this.year = year;
- this.month = month;
- this.day = day;
- }
-
- public String getYear() { return year; }
- public int getMonth() { return month; }
- public int getDay() { return day; }
- }
-
- final public DateTime parseLine() throws ParseException {
- DateTime dt;
- dt = date_time();
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 1:
- jj_consume_token(1);
- break;
- default:
- jj_la1[0] = jj_gen;
- ;
- }
- jj_consume_token(2);
- {if (true) return dt;}
- throw new Error("Missing return statement in function");
- }
-
- final public DateTime parseAll() throws ParseException {
- DateTime dt;
- dt = date_time();
- jj_consume_token(0);
- {if (true) return dt;}
- throw new Error("Missing return statement in function");
- }
-
- final public DateTime date_time() throws ParseException {
- Date d; Time t;
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 4:
- case 5:
- case 6:
- case 7:
- case 8:
- case 9:
- case 10:
- day_of_week();
- jj_consume_token(3);
- break;
- default:
- jj_la1[1] = jj_gen;
- ;
- }
- d = date();
- t = time();
- {if (true) return new DateTime(
- d.getYear(),
- d.getMonth(),
- d.getDay(),
- t.getHour(),
- t.getMinute(),
- t.getSecond(),
- t.getZone());} // time zone offset
-
- throw new Error("Missing return statement in function");
- }
-
- final public String day_of_week() throws ParseException {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 4:
- jj_consume_token(4);
- break;
- case 5:
- jj_consume_token(5);
- break;
- case 6:
- jj_consume_token(6);
- break;
- case 7:
- jj_consume_token(7);
- break;
- case 8:
- jj_consume_token(8);
- break;
- case 9:
- jj_consume_token(9);
- break;
- case 10:
- jj_consume_token(10);
- break;
- default:
- jj_la1[2] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- {if (true) return token.image;}
- throw new Error("Missing return statement in function");
- }
-
- final public Date date() throws ParseException {
- int d, m; String y;
- d = day();
- m = month();
- y = year();
- {if (true) return new Date(y, m, d);}
- throw new Error("Missing return statement in function");
- }
-
- final public int day() throws ParseException {
- Token t;
- t = jj_consume_token(DIGITS);
- {if (true) return parseDigits(t);}
- throw new Error("Missing return statement in function");
- }
-
- final public int month() throws ParseException {
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 11:
- jj_consume_token(11);
- {if (true) return 1;}
- break;
- case 12:
- jj_consume_token(12);
- {if (true) return 2;}
- break;
- case 13:
- jj_consume_token(13);
- {if (true) return 3;}
- break;
- case 14:
- jj_consume_token(14);
- {if (true) return 4;}
- break;
- case 15:
- jj_consume_token(15);
- {if (true) return 5;}
- break;
- case 16:
- jj_consume_token(16);
- {if (true) return 6;}
- break;
- case 17:
- jj_consume_token(17);
- {if (true) return 7;}
- break;
- case 18:
- jj_consume_token(18);
- {if (true) return 8;}
- break;
- case 19:
- jj_consume_token(19);
- {if (true) return 9;}
- break;
- case 20:
- jj_consume_token(20);
- {if (true) return 10;}
- break;
- case 21:
- jj_consume_token(21);
- {if (true) return 11;}
- break;
- case 22:
- jj_consume_token(22);
- {if (true) return 12;}
- break;
- default:
- jj_la1[3] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- throw new Error("Missing return statement in function");
- }
-
- final public String year() throws ParseException {
- Token t;
- t = jj_consume_token(DIGITS);
- {if (true) return t.image;}
- throw new Error("Missing return statement in function");
- }
-
- final public Time time() throws ParseException {
- int h, m, s=0, z;
- h = hour();
- jj_consume_token(23);
- m = minute();
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 23:
- jj_consume_token(23);
- s = second();
- break;
- default:
- jj_la1[4] = jj_gen;
- ;
- }
- z = zone();
- {if (true) return new Time(h, m, s, z);}
- throw new Error("Missing return statement in function");
- }
-
- final public int hour() throws ParseException {
- Token t;
- t = jj_consume_token(DIGITS);
- {if (true) return parseDigits(t);}
- throw new Error("Missing return statement in function");
- }
-
- final public int minute() throws ParseException {
- Token t;
- t = jj_consume_token(DIGITS);
- {if (true) return parseDigits(t);}
- throw new Error("Missing return statement in function");
- }
-
- final public int second() throws ParseException {
- Token t;
- t = jj_consume_token(DIGITS);
- {if (true) return parseDigits(t);}
- throw new Error("Missing return statement in function");
- }
-
- final public int zone() throws ParseException {
- Token t, u; int z;
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case OFFSETDIR:
- t = jj_consume_token(OFFSETDIR);
- u = jj_consume_token(DIGITS);
- z=parseDigits(u)*(t.image.equals("-") ? -1 : 1);
- break;
- case 25:
- case 26:
- case 27:
- case 28:
- case 29:
- case 30:
- case 31:
- case 32:
- case 33:
- case 34:
- case MILITARY_ZONE:
- z = obs_zone();
- break;
- default:
- jj_la1[5] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- {if (true) return z;}
- throw new Error("Missing return statement in function");
- }
-
- final public int obs_zone() throws ParseException {
- Token t; int z;
- switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
- case 25:
- jj_consume_token(25);
- z=0;
- break;
- case 26:
- jj_consume_token(26);
- z=0;
- break;
- case 27:
- jj_consume_token(27);
- z=-5;
- break;
- case 28:
- jj_consume_token(28);
- z=-4;
- break;
- case 29:
- jj_consume_token(29);
- z=-6;
- break;
- case 30:
- jj_consume_token(30);
- z=-5;
- break;
- case 31:
- jj_consume_token(31);
- z=-7;
- break;
- case 32:
- jj_consume_token(32);
- z=-6;
- break;
- case 33:
- jj_consume_token(33);
- z=-8;
- break;
- case 34:
- jj_consume_token(34);
- z=-7;
- break;
- case MILITARY_ZONE:
- t = jj_consume_token(MILITARY_ZONE);
- z=getMilitaryZoneOffset(t.image.charAt(0));
- break;
- default:
- jj_la1[6] = jj_gen;
- jj_consume_token(-1);
- throw new ParseException();
- }
- {if (true) return z * 100;}
- throw new Error("Missing return statement in function");
- }
-
- public DateTimeParserTokenManager token_source;
- SimpleCharStream jj_input_stream;
- public Token token, jj_nt;
- private int jj_ntk;
- private int jj_gen;
- final private int[] jj_la1 = new int[7];
- static private int[] jj_la1_0;
- static private int[] jj_la1_1;
- static {
- jj_la1_0();
- jj_la1_1();
- }
- private static void jj_la1_0() {
- jj_la1_0 = new int[] {0x2,0x7f0,0x7f0,0x7ff800,0x800000,0xff000000,0xfe000000,};
- }
- private static void jj_la1_1() {
- jj_la1_1 = new int[] {0x0,0x0,0x0,0x0,0x0,0xf,0xf,};
- }
-
- public DateTimeParser(java.io.InputStream stream) {
- this(stream, null);
- }
- public DateTimeParser(java.io.InputStream stream, String encoding) {
- try { jj_input_stream = new SimpleCharStream(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
- token_source = new DateTimeParserTokenManager(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 7; i++) jj_la1[i] = -1;
- }
-
- public void ReInit(java.io.InputStream stream) {
- ReInit(stream, null);
- }
- public void ReInit(java.io.InputStream stream, String encoding) {
- try { jj_input_stream.ReInit(stream, encoding, 1, 1); } catch(java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); }
- token_source.ReInit(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 7; i++) jj_la1[i] = -1;
- }
-
- public DateTimeParser(java.io.Reader stream) {
- jj_input_stream = new SimpleCharStream(stream, 1, 1);
- token_source = new DateTimeParserTokenManager(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 7; i++) jj_la1[i] = -1;
- }
-
- public void ReInit(java.io.Reader stream) {
- jj_input_stream.ReInit(stream, 1, 1);
- token_source.ReInit(jj_input_stream);
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 7; i++) jj_la1[i] = -1;
- }
-
- public DateTimeParser(DateTimeParserTokenManager tm) {
- token_source = tm;
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 7; i++) jj_la1[i] = -1;
- }
-
- public void ReInit(DateTimeParserTokenManager tm) {
- token_source = tm;
- token = new Token();
- jj_ntk = -1;
- jj_gen = 0;
- for (int i = 0; i < 7; i++) jj_la1[i] = -1;
- }
-
- final private Token jj_consume_token(int kind) throws ParseException {
- Token oldToken;
- if ((oldToken = token).next != null) token = token.next;
- else token = token.next = token_source.getNextToken();
- jj_ntk = -1;
- if (token.kind == kind) {
- jj_gen++;
- return token;
- }
- token = oldToken;
- jj_kind = kind;
- throw generateParseException();
- }
-
- final public Token getNextToken() {
- if (token.next != null) token = token.next;
- else token = token.next = token_source.getNextToken();
- jj_ntk = -1;
- jj_gen++;
- return token;
- }
-
- final public Token getToken(int index) {
- Token t = token;
- for (int i = 0; i < index; i++) {
- if (t.next != null) t = t.next;
- else t = t.next = token_source.getNextToken();
- }
- return t;
- }
-
- final private int jj_ntk() {
- if ((jj_nt=token.next) == null)
- return (jj_ntk = (token.next=token_source.getNextToken()).kind);
- else
- return (jj_ntk = jj_nt.kind);
- }
-
- private Vector<int[]> jj_expentries = new Vector<int[]>();
- private int[] jj_expentry;
- private int jj_kind = -1;
-
- public ParseException generateParseException() {
- jj_expentries.removeAllElements();
- boolean[] la1tokens = new boolean[49];
- for (int i = 0; i < 49; i++) {
- la1tokens[i] = false;
- }
- if (jj_kind >= 0) {
- la1tokens[jj_kind] = true;
- jj_kind = -1;
- }
- for (int i = 0; i < 7; i++) {
- if (jj_la1[i] == jj_gen) {
- for (int j = 0; j < 32; j++) {
- if ((jj_la1_0[i] & (1<<j)) != 0) {
- la1tokens[j] = true;
- }
- if ((jj_la1_1[i] & (1<<j)) != 0) {
- la1tokens[32+j] = true;
- }
- }
- }
- }
- for (int i = 0; i < 49; i++) {
- if (la1tokens[i]) {
- jj_expentry = new int[1];
- jj_expentry[0] = i;
- jj_expentries.addElement(jj_expentry);
- }
- }
- int[][] exptokseq = new int[jj_expentries.size()][];
- for (int i = 0; i < jj_expentries.size(); i++) {
- exptokseq[i] = jj_expentries.elementAt(i);
- }
- return new ParseException(token, exptokseq, tokenImage);
- }
-
- final public void enable_tracing() {
- }
-
- final public void disable_tracing() {
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java
deleted file mode 100644
index 2c203db..0000000
--- a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserConstants.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. DateTimeParserConstants.java */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.datetime.parser;
-
-public interface DateTimeParserConstants {
-
- int EOF = 0;
- int OFFSETDIR = 24;
- int MILITARY_ZONE = 35;
- int WS = 36;
- int COMMENT = 38;
- int DIGITS = 46;
- int QUOTEDPAIR = 47;
- int ANY = 48;
-
- int DEFAULT = 0;
- int INCOMMENT = 1;
- int NESTED_COMMENT = 2;
-
- String[] tokenImage = {
- "<EOF>",
- "\"\\r\"",
- "\"\\n\"",
- "\",\"",
- "\"Mon\"",
- "\"Tue\"",
- "\"Wed\"",
- "\"Thu\"",
- "\"Fri\"",
- "\"Sat\"",
- "\"Sun\"",
- "\"Jan\"",
- "\"Feb\"",
- "\"Mar\"",
- "\"Apr\"",
- "\"May\"",
- "\"Jun\"",
- "\"Jul\"",
- "\"Aug\"",
- "\"Sep\"",
- "\"Oct\"",
- "\"Nov\"",
- "\"Dec\"",
- "\":\"",
- "<OFFSETDIR>",
- "\"UT\"",
- "\"GMT\"",
- "\"EST\"",
- "\"EDT\"",
- "\"CST\"",
- "\"CDT\"",
- "\"MST\"",
- "\"MDT\"",
- "\"PST\"",
- "\"PDT\"",
- "<MILITARY_ZONE>",
- "<WS>",
- "\"(\"",
- "\")\"",
- "<token of kind 39>",
- "\"(\"",
- "<token of kind 41>",
- "<token of kind 42>",
- "\"(\"",
- "\")\"",
- "<token of kind 45>",
- "<DIGITS>",
- "<QUOTEDPAIR>",
- "<ANY>",
- };
-
-}
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java b/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java
deleted file mode 100644
index 4b2d2fd..0000000
--- a/src/org/apache/james/mime4j/field/datetime/parser/DateTimeParserTokenManager.java
+++ /dev/null
@@ -1,882 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. DateTimeParserTokenManager.java */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.datetime.parser;
-import org.apache.james.mime4j.field.datetime.DateTime;
-import java.util.Calendar;
-
-public class DateTimeParserTokenManager implements DateTimeParserConstants
-{
- // Keeps track of how many levels of comment nesting
- // we've encountered. This is only used when the 2nd
- // level is reached, for example ((this)), not (this).
- // This is because the outermost level must be treated
- // specially anyway, because the outermost ")" has a
- // different token type than inner ")" instances.
- static int commentNest;
- public java.io.PrintStream debugStream = System.out;
- public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; }
-private final int jjStopStringLiteralDfa_0(int pos, long active0)
-{
- switch (pos)
- {
- case 0:
- if ((active0 & 0x7fe7cf7f0L) != 0L)
- {
- jjmatchedKind = 35;
- return -1;
- }
- return -1;
- case 1:
- if ((active0 & 0x7fe7cf7f0L) != 0L)
- {
- if (jjmatchedPos == 0)
- {
- jjmatchedKind = 35;
- jjmatchedPos = 0;
- }
- return -1;
- }
- return -1;
- default :
- return -1;
- }
-}
-private final int jjStartNfa_0(int pos, long active0)
-{
- return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1);
-}
-private final int jjStopAtPos(int pos, int kind)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- return pos + 1;
-}
-private final int jjStartNfaWithStates_0(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_0(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_0()
-{
- switch(curChar)
- {
- case 10:
- return jjStopAtPos(0, 2);
- case 13:
- return jjStopAtPos(0, 1);
- case 40:
- return jjStopAtPos(0, 37);
- case 44:
- return jjStopAtPos(0, 3);
- case 58:
- return jjStopAtPos(0, 23);
- case 65:
- return jjMoveStringLiteralDfa1_0(0x44000L);
- case 67:
- return jjMoveStringLiteralDfa1_0(0x60000000L);
- case 68:
- return jjMoveStringLiteralDfa1_0(0x400000L);
- case 69:
- return jjMoveStringLiteralDfa1_0(0x18000000L);
- case 70:
- return jjMoveStringLiteralDfa1_0(0x1100L);
- case 71:
- return jjMoveStringLiteralDfa1_0(0x4000000L);
- case 74:
- return jjMoveStringLiteralDfa1_0(0x30800L);
- case 77:
- return jjMoveStringLiteralDfa1_0(0x18000a010L);
- case 78:
- return jjMoveStringLiteralDfa1_0(0x200000L);
- case 79:
- return jjMoveStringLiteralDfa1_0(0x100000L);
- case 80:
- return jjMoveStringLiteralDfa1_0(0x600000000L);
- case 83:
- return jjMoveStringLiteralDfa1_0(0x80600L);
- case 84:
- return jjMoveStringLiteralDfa1_0(0xa0L);
- case 85:
- return jjMoveStringLiteralDfa1_0(0x2000000L);
- case 87:
- return jjMoveStringLiteralDfa1_0(0x40L);
- default :
- return jjMoveNfa_0(0, 0);
- }
-}
-private final int jjMoveStringLiteralDfa1_0(long active0)
-{
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) {
- jjStopStringLiteralDfa_0(0, active0);
- return 1;
- }
- switch(curChar)
- {
- case 68:
- return jjMoveStringLiteralDfa2_0(active0, 0x550000000L);
- case 77:
- return jjMoveStringLiteralDfa2_0(active0, 0x4000000L);
- case 83:
- return jjMoveStringLiteralDfa2_0(active0, 0x2a8000000L);
- case 84:
- if ((active0 & 0x2000000L) != 0L)
- return jjStopAtPos(1, 25);
- break;
- case 97:
- return jjMoveStringLiteralDfa2_0(active0, 0xaa00L);
- case 99:
- return jjMoveStringLiteralDfa2_0(active0, 0x100000L);
- case 101:
- return jjMoveStringLiteralDfa2_0(active0, 0x481040L);
- case 104:
- return jjMoveStringLiteralDfa2_0(active0, 0x80L);
- case 111:
- return jjMoveStringLiteralDfa2_0(active0, 0x200010L);
- case 112:
- return jjMoveStringLiteralDfa2_0(active0, 0x4000L);
- case 114:
- return jjMoveStringLiteralDfa2_0(active0, 0x100L);
- case 117:
- return jjMoveStringLiteralDfa2_0(active0, 0x70420L);
- default :
- break;
- }
- return jjStartNfa_0(0, active0);
-}
-private final int jjMoveStringLiteralDfa2_0(long old0, long active0)
-{
- if (((active0 &= old0)) == 0L)
- return jjStartNfa_0(0, old0);
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) {
- jjStopStringLiteralDfa_0(1, active0);
- return 2;
- }
- switch(curChar)
- {
- case 84:
- if ((active0 & 0x4000000L) != 0L)
- return jjStopAtPos(2, 26);
- else if ((active0 & 0x8000000L) != 0L)
- return jjStopAtPos(2, 27);
- else if ((active0 & 0x10000000L) != 0L)
- return jjStopAtPos(2, 28);
- else if ((active0 & 0x20000000L) != 0L)
- return jjStopAtPos(2, 29);
- else if ((active0 & 0x40000000L) != 0L)
- return jjStopAtPos(2, 30);
- else if ((active0 & 0x80000000L) != 0L)
- return jjStopAtPos(2, 31);
- else if ((active0 & 0x100000000L) != 0L)
- return jjStopAtPos(2, 32);
- else if ((active0 & 0x200000000L) != 0L)
- return jjStopAtPos(2, 33);
- else if ((active0 & 0x400000000L) != 0L)
- return jjStopAtPos(2, 34);
- break;
- case 98:
- if ((active0 & 0x1000L) != 0L)
- return jjStopAtPos(2, 12);
- break;
- case 99:
- if ((active0 & 0x400000L) != 0L)
- return jjStopAtPos(2, 22);
- break;
- case 100:
- if ((active0 & 0x40L) != 0L)
- return jjStopAtPos(2, 6);
- break;
- case 101:
- if ((active0 & 0x20L) != 0L)
- return jjStopAtPos(2, 5);
- break;
- case 103:
- if ((active0 & 0x40000L) != 0L)
- return jjStopAtPos(2, 18);
- break;
- case 105:
- if ((active0 & 0x100L) != 0L)
- return jjStopAtPos(2, 8);
- break;
- case 108:
- if ((active0 & 0x20000L) != 0L)
- return jjStopAtPos(2, 17);
- break;
- case 110:
- if ((active0 & 0x10L) != 0L)
- return jjStopAtPos(2, 4);
- else if ((active0 & 0x400L) != 0L)
- return jjStopAtPos(2, 10);
- else if ((active0 & 0x800L) != 0L)
- return jjStopAtPos(2, 11);
- else if ((active0 & 0x10000L) != 0L)
- return jjStopAtPos(2, 16);
- break;
- case 112:
- if ((active0 & 0x80000L) != 0L)
- return jjStopAtPos(2, 19);
- break;
- case 114:
- if ((active0 & 0x2000L) != 0L)
- return jjStopAtPos(2, 13);
- else if ((active0 & 0x4000L) != 0L)
- return jjStopAtPos(2, 14);
- break;
- case 116:
- if ((active0 & 0x200L) != 0L)
- return jjStopAtPos(2, 9);
- else if ((active0 & 0x100000L) != 0L)
- return jjStopAtPos(2, 20);
- break;
- case 117:
- if ((active0 & 0x80L) != 0L)
- return jjStopAtPos(2, 7);
- break;
- case 118:
- if ((active0 & 0x200000L) != 0L)
- return jjStopAtPos(2, 21);
- break;
- case 121:
- if ((active0 & 0x8000L) != 0L)
- return jjStopAtPos(2, 15);
- break;
- default :
- break;
- }
- return jjStartNfa_0(1, active0);
-}
-private final void jjCheckNAdd(int state)
-{
- if (jjrounds[state] != jjround)
- {
- jjstateSet[jjnewStateCnt++] = state;
- jjrounds[state] = jjround;
- }
-}
-private final void jjAddStates(int start, int end)
-{
- do {
- jjstateSet[jjnewStateCnt++] = jjnextStates[start];
- } while (start++ != end);
-}
-private final void jjCheckNAddTwoStates(int state1, int state2)
-{
- jjCheckNAdd(state1);
- jjCheckNAdd(state2);
-}
-private final void jjCheckNAddStates(int start, int end)
-{
- do {
- jjCheckNAdd(jjnextStates[start]);
- } while (start++ != end);
-}
-private final void jjCheckNAddStates(int start)
-{
- jjCheckNAdd(jjnextStates[start]);
- jjCheckNAdd(jjnextStates[start + 1]);
-}
-private final int jjMoveNfa_0(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 4;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((0x3ff000000000000L & l) != 0L)
- {
- if (kind > 46)
- kind = 46;
- jjCheckNAdd(3);
- }
- else if ((0x100000200L & l) != 0L)
- {
- if (kind > 36)
- kind = 36;
- jjCheckNAdd(2);
- }
- else if ((0x280000000000L & l) != 0L)
- {
- if (kind > 24)
- kind = 24;
- }
- break;
- case 2:
- if ((0x100000200L & l) == 0L)
- break;
- kind = 36;
- jjCheckNAdd(2);
- break;
- case 3:
- if ((0x3ff000000000000L & l) == 0L)
- break;
- kind = 46;
- jjCheckNAdd(3);
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((0x7fffbfe07fffbfeL & l) != 0L)
- kind = 35;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 4 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-private final int jjStopStringLiteralDfa_1(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_1(int pos, long active0)
-{
- return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1);
-}
-private final int jjStartNfaWithStates_1(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_1(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_1()
-{
- switch(curChar)
- {
- case 40:
- return jjStopAtPos(0, 40);
- case 41:
- return jjStopAtPos(0, 38);
- default :
- return jjMoveNfa_1(0, 0);
- }
-}
-static final long[] jjbitVec0 = {
- 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL
-};
-private final int jjMoveNfa_1(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 41)
- kind = 41;
- break;
- case 1:
- if (kind > 39)
- kind = 39;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 41)
- kind = 41;
- if (curChar == 92)
- jjstateSet[jjnewStateCnt++] = 1;
- break;
- case 1:
- if (kind > 39)
- kind = 39;
- break;
- case 2:
- if (kind > 41)
- kind = 41;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 41)
- kind = 41;
- break;
- case 1:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 39)
- kind = 39;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-private final int jjStopStringLiteralDfa_2(int pos, long active0)
-{
- switch (pos)
- {
- default :
- return -1;
- }
-}
-private final int jjStartNfa_2(int pos, long active0)
-{
- return jjMoveNfa_2(jjStopStringLiteralDfa_2(pos, active0), pos + 1);
-}
-private final int jjStartNfaWithStates_2(int pos, int kind, int state)
-{
- jjmatchedKind = kind;
- jjmatchedPos = pos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return pos + 1; }
- return jjMoveNfa_2(state, pos + 1);
-}
-private final int jjMoveStringLiteralDfa0_2()
-{
- switch(curChar)
- {
- case 40:
- return jjStopAtPos(0, 43);
- case 41:
- return jjStopAtPos(0, 44);
- default :
- return jjMoveNfa_2(0, 0);
- }
-}
-private final int jjMoveNfa_2(int startState, int curPos)
-{
- int[] nextStates;
- int startsAt = 0;
- jjnewStateCnt = 3;
- int i = 1;
- jjstateSet[0] = startState;
- int j, kind = 0x7fffffff;
- for (;;)
- {
- if (++jjround == 0x7fffffff)
- ReInitRounds();
- if (curChar < 64)
- {
- long l = 1L << curChar;
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 45)
- kind = 45;
- break;
- case 1:
- if (kind > 42)
- kind = 42;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else if (curChar < 128)
- {
- long l = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if (kind > 45)
- kind = 45;
- if (curChar == 92)
- jjstateSet[jjnewStateCnt++] = 1;
- break;
- case 1:
- if (kind > 42)
- kind = 42;
- break;
- case 2:
- if (kind > 45)
- kind = 45;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- else
- {
- int i2 = (curChar & 0xff) >> 6;
- long l2 = 1L << (curChar & 077);
- MatchLoop: do
- {
- switch(jjstateSet[--i])
- {
- case 0:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 45)
- kind = 45;
- break;
- case 1:
- if ((jjbitVec0[i2] & l2) != 0L && kind > 42)
- kind = 42;
- break;
- default : break;
- }
- } while(i != startsAt);
- }
- if (kind != 0x7fffffff)
- {
- jjmatchedKind = kind;
- jjmatchedPos = curPos;
- kind = 0x7fffffff;
- }
- ++curPos;
- if ((i = jjnewStateCnt) == (startsAt = 3 - (jjnewStateCnt = startsAt)))
- return curPos;
- try { curChar = input_stream.readChar(); }
- catch(java.io.IOException e) { return curPos; }
- }
-}
-static final int[] jjnextStates = {
-};
-public static final String[] jjstrLiteralImages = {
-"", "\15", "\12", "\54", "\115\157\156", "\124\165\145", "\127\145\144",
-"\124\150\165", "\106\162\151", "\123\141\164", "\123\165\156", "\112\141\156",
-"\106\145\142", "\115\141\162", "\101\160\162", "\115\141\171", "\112\165\156",
-"\112\165\154", "\101\165\147", "\123\145\160", "\117\143\164", "\116\157\166",
-"\104\145\143", "\72", null, "\125\124", "\107\115\124", "\105\123\124", "\105\104\124",
-"\103\123\124", "\103\104\124", "\115\123\124", "\115\104\124", "\120\123\124",
-"\120\104\124", null, null, null, null, null, null, null, null, null, null, null, null, null,
-null, };
-public static final String[] lexStateNames = {
- "DEFAULT",
- "INCOMMENT",
- "NESTED_COMMENT",
-};
-public static final int[] jjnewLexState = {
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 0, -1, 2, -1, -1, -1, -1, -1, -1, -1, -1,
-};
-static final long[] jjtoToken = {
- 0x400fffffffffL,
-};
-static final long[] jjtoSkip = {
- 0x5000000000L,
-};
-static final long[] jjtoSpecial = {
- 0x1000000000L,
-};
-static final long[] jjtoMore = {
- 0x3fa000000000L,
-};
-protected SimpleCharStream input_stream;
-private final int[] jjrounds = new int[4];
-private final int[] jjstateSet = new int[8];
-StringBuffer image;
-int jjimageLen;
-int lengthOfMatch;
-protected char curChar;
-public DateTimeParserTokenManager(SimpleCharStream stream){
- if (SimpleCharStream.staticFlag)
- throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer.");
- input_stream = stream;
-}
-public DateTimeParserTokenManager(SimpleCharStream stream, int lexState){
- this(stream);
- SwitchTo(lexState);
-}
-public void ReInit(SimpleCharStream stream)
-{
- jjmatchedPos = jjnewStateCnt = 0;
- curLexState = defaultLexState;
- input_stream = stream;
- ReInitRounds();
-}
-private final void ReInitRounds()
-{
- int i;
- jjround = 0x80000001;
- for (i = 4; i-- > 0;)
- jjrounds[i] = 0x80000000;
-}
-public void ReInit(SimpleCharStream stream, int lexState)
-{
- ReInit(stream);
- SwitchTo(lexState);
-}
-public void SwitchTo(int lexState)
-{
- if (lexState >= 3 || lexState < 0)
- throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE);
- else
- curLexState = lexState;
-}
-
-protected Token jjFillToken()
-{
- Token t = Token.newToken(jjmatchedKind);
- t.kind = jjmatchedKind;
- String im = jjstrLiteralImages[jjmatchedKind];
- t.image = (im == null) ? input_stream.GetImage() : im;
- t.beginLine = input_stream.getBeginLine();
- t.beginColumn = input_stream.getBeginColumn();
- t.endLine = input_stream.getEndLine();
- t.endColumn = input_stream.getEndColumn();
- return t;
-}
-
-int curLexState = 0;
-int defaultLexState = 0;
-int jjnewStateCnt;
-int jjround;
-int jjmatchedPos;
-int jjmatchedKind;
-
-public Token getNextToken()
-{
- int kind;
- Token specialToken = null;
- Token matchedToken;
- int curPos = 0;
-
- EOFLoop :
- for (;;)
- {
- try
- {
- curChar = input_stream.BeginToken();
- }
- catch(java.io.IOException e)
- {
- jjmatchedKind = 0;
- matchedToken = jjFillToken();
- matchedToken.specialToken = specialToken;
- return matchedToken;
- }
- image = null;
- jjimageLen = 0;
-
- for (;;)
- {
- switch(curLexState)
- {
- case 0:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_0();
- break;
- case 1:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_1();
- break;
- case 2:
- jjmatchedKind = 0x7fffffff;
- jjmatchedPos = 0;
- curPos = jjMoveStringLiteralDfa0_2();
- break;
- }
- if (jjmatchedKind != 0x7fffffff)
- {
- if (jjmatchedPos + 1 < curPos)
- input_stream.backup(curPos - jjmatchedPos - 1);
- if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
- {
- matchedToken = jjFillToken();
- matchedToken.specialToken = specialToken;
- if (jjnewLexState[jjmatchedKind] != -1)
- curLexState = jjnewLexState[jjmatchedKind];
- return matchedToken;
- }
- else if ((jjtoSkip[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
- {
- if ((jjtoSpecial[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L)
- {
- matchedToken = jjFillToken();
- if (specialToken == null)
- specialToken = matchedToken;
- else
- {
- matchedToken.specialToken = specialToken;
- specialToken = (specialToken.next = matchedToken);
- }
- }
- if (jjnewLexState[jjmatchedKind] != -1)
- curLexState = jjnewLexState[jjmatchedKind];
- continue EOFLoop;
- }
- MoreLexicalActions();
- if (jjnewLexState[jjmatchedKind] != -1)
- curLexState = jjnewLexState[jjmatchedKind];
- curPos = 0;
- jjmatchedKind = 0x7fffffff;
- try {
- curChar = input_stream.readChar();
- continue;
- }
- catch (java.io.IOException e1) { }
- }
- int error_line = input_stream.getEndLine();
- int error_column = input_stream.getEndColumn();
- String error_after = null;
- boolean EOFSeen = false;
- try { input_stream.readChar(); input_stream.backup(1); }
- catch (java.io.IOException e1) {
- EOFSeen = true;
- error_after = curPos <= 1 ? "" : input_stream.GetImage();
- if (curChar == '\n' || curChar == '\r') {
- error_line++;
- error_column = 0;
- }
- else
- error_column++;
- }
- if (!EOFSeen) {
- input_stream.backup(1);
- error_after = curPos <= 1 ? "" : input_stream.GetImage();
- }
- throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR);
- }
- }
-}
-
-void MoreLexicalActions()
-{
- jjimageLen += (lengthOfMatch = jjmatchedPos + 1);
- switch(jjmatchedKind)
- {
- case 39 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 2);
- break;
- case 40 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- commentNest = 1;
- break;
- case 42 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- image.deleteCharAt(image.length() - 2);
- break;
- case 43 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- ++commentNest;
- break;
- case 44 :
- if (image == null)
- image = new StringBuffer();
- image.append(input_stream.GetSuffix(jjimageLen));
- jjimageLen = 0;
- --commentNest; if (commentNest == 0) SwitchTo(INCOMMENT);
- break;
- default :
- break;
- }
-}
-}
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java b/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java
deleted file mode 100644
index 13b3ff0..0000000
--- a/src/org/apache/james/mime4j/field/datetime/parser/ParseException.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.datetime.parser;
-
-/**
- * This exception is thrown when parse errors are encountered.
- * You can explicitly create objects of this exception type by
- * calling the method generateParseException in the generated
- * parser.
- *
- * You can modify this class to customize your error reporting
- * mechanisms so long as you retain the public fields.
- */
-public class ParseException extends Exception {
-
- /**
- * This constructor is used by the method "generateParseException"
- * in the generated parser. Calling this constructor generates
- * a new object of this type with the fields "currentToken",
- * "expectedTokenSequences", and "tokenImage" set. The boolean
- * flag "specialConstructor" is also set to true to indicate that
- * this constructor was used to create this object.
- * This constructor calls its super class with the empty string
- * to force the "toString" method of parent class "Throwable" to
- * print the error message in the form:
- * ParseException: <result of getMessage>
- */
- public ParseException(Token currentTokenVal,
- int[][] expectedTokenSequencesVal,
- String[] tokenImageVal
- )
- {
- super("");
- specialConstructor = true;
- currentToken = currentTokenVal;
- expectedTokenSequences = expectedTokenSequencesVal;
- tokenImage = tokenImageVal;
- }
-
- /**
- * The following constructors are for use by you for whatever
- * purpose you can think of. Constructing the exception in this
- * manner makes the exception behave in the normal way - i.e., as
- * documented in the class "Throwable". The fields "errorToken",
- * "expectedTokenSequences", and "tokenImage" do not contain
- * relevant information. The JavaCC generated code does not use
- * these constructors.
- */
-
- public ParseException() {
- super();
- specialConstructor = false;
- }
-
- public ParseException(String message) {
- super(message);
- specialConstructor = false;
- }
-
- /**
- * This variable determines which constructor was used to create
- * this object and thereby affects the semantics of the
- * "getMessage" method (see below).
- */
- protected boolean specialConstructor;
-
- /**
- * This is the last token that has been consumed successfully. If
- * this object has been created due to a parse error, the token
- * followng this token will (therefore) be the first error token.
- */
- public Token currentToken;
-
- /**
- * Each entry in this array is an array of integers. Each array
- * of integers represents a sequence of tokens (by their ordinal
- * values) that is expected at this point of the parse.
- */
- public int[][] expectedTokenSequences;
-
- /**
- * This is a reference to the "tokenImage" array of the generated
- * parser within which the parse error occurred. This array is
- * defined in the generated ...Constants interface.
- */
- public String[] tokenImage;
-
- /**
- * This method has the standard behavior when this object has been
- * created using the standard constructors. Otherwise, it uses
- * "currentToken" and "expectedTokenSequences" to generate a parse
- * error message and returns it. If this object has been created
- * due to a parse error, and you do not catch it (it gets thrown
- * from the parser), then this method is called during the printing
- * of the final stack trace, and hence the correct error message
- * gets displayed.
- */
- public String getMessage() {
- if (!specialConstructor) {
- return super.getMessage();
- }
- StringBuffer expected = new StringBuffer();
- int maxSize = 0;
- for (int i = 0; i < expectedTokenSequences.length; i++) {
- if (maxSize < expectedTokenSequences[i].length) {
- maxSize = expectedTokenSequences[i].length;
- }
- for (int j = 0; j < expectedTokenSequences[i].length; j++) {
- expected.append(tokenImage[expectedTokenSequences[i][j]]).append(" ");
- }
- if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) {
- expected.append("...");
- }
- expected.append(eol).append(" ");
- }
- String retval = "Encountered \"";
- Token tok = currentToken.next;
- for (int i = 0; i < maxSize; i++) {
- if (i != 0) retval += " ";
- if (tok.kind == 0) {
- retval += tokenImage[0];
- break;
- }
- retval += add_escapes(tok.image);
- tok = tok.next;
- }
- retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn;
- retval += "." + eol;
- if (expectedTokenSequences.length == 1) {
- retval += "Was expecting:" + eol + " ";
- } else {
- retval += "Was expecting one of:" + eol + " ";
- }
- retval += expected.toString();
- return retval;
- }
-
- /**
- * The end of line string for this machine.
- */
- protected String eol = System.getProperty("line.separator", "\n");
-
- /**
- * Used to convert raw characters to their escaped version
- * when these raw version cannot be used as part of an ASCII
- * string literal.
- */
- protected String add_escapes(String str) {
- StringBuffer retval = new StringBuffer();
- char ch;
- for (int i = 0; i < str.length(); i++) {
- switch (str.charAt(i))
- {
- case 0 :
- continue;
- case '\b':
- retval.append("\\b");
- continue;
- case '\t':
- retval.append("\\t");
- continue;
- case '\n':
- retval.append("\\n");
- continue;
- case '\f':
- retval.append("\\f");
- continue;
- case '\r':
- retval.append("\\r");
- continue;
- case '\"':
- retval.append("\\\"");
- continue;
- case '\'':
- retval.append("\\\'");
- continue;
- case '\\':
- retval.append("\\\\");
- continue;
- default:
- if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
- String s = "0000" + Integer.toString(ch, 16);
- retval.append("\\u" + s.substring(s.length() - 4, s.length()));
- } else {
- retval.append(ch);
- }
- continue;
- }
- }
- return retval.toString();
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java b/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java
deleted file mode 100644
index 2724529..0000000
--- a/src/org/apache/james/mime4j/field/datetime/parser/SimpleCharStream.java
+++ /dev/null
@@ -1,454 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 4.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.datetime.parser;
-
-/**
- * An implementation of interface CharStream, where the stream is assumed to
- * contain only ASCII characters (without unicode processing).
- */
-
-public class SimpleCharStream
-{
- public static final boolean staticFlag = false;
- int bufsize;
- int available;
- int tokenBegin;
- public int bufpos = -1;
- protected int bufline[];
- protected int bufcolumn[];
-
- protected int column = 0;
- protected int line = 1;
-
- protected boolean prevCharIsCR = false;
- protected boolean prevCharIsLF = false;
-
- protected java.io.Reader inputStream;
-
- protected char[] buffer;
- protected int maxNextCharInd = 0;
- protected int inBuf = 0;
- protected int tabSize = 8;
-
- protected void setTabSize(int i) { tabSize = i; }
- protected int getTabSize(int i) { return tabSize; }
-
-
- protected void ExpandBuff(boolean wrapAround)
- {
- char[] newbuffer = new char[bufsize + 2048];
- int newbufline[] = new int[bufsize + 2048];
- int newbufcolumn[] = new int[bufsize + 2048];
-
- try
- {
- if (wrapAround)
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- System.arraycopy(buffer, 0, newbuffer,
- bufsize - tokenBegin, bufpos);
- buffer = newbuffer;
-
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos);
- bufline = newbufline;
-
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos);
- bufcolumn = newbufcolumn;
-
- maxNextCharInd = (bufpos += (bufsize - tokenBegin));
- }
- else
- {
- System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin);
- buffer = newbuffer;
-
- System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin);
- bufline = newbufline;
-
- System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin);
- bufcolumn = newbufcolumn;
-
- maxNextCharInd = (bufpos -= tokenBegin);
- }
- }
- catch (Throwable t)
- {
- throw new Error(t.getMessage());
- }
-
-
- bufsize += 2048;
- available = bufsize;
- tokenBegin = 0;
- }
-
- protected void FillBuff() throws java.io.IOException
- {
- if (maxNextCharInd == available)
- {
- if (available == bufsize)
- {
- if (tokenBegin > 2048)
- {
- bufpos = maxNextCharInd = 0;
- available = tokenBegin;
- }
- else if (tokenBegin < 0)
- bufpos = maxNextCharInd = 0;
- else
- ExpandBuff(false);
- }
- else if (available > tokenBegin)
- available = bufsize;
- else if ((tokenBegin - available) < 2048)
- ExpandBuff(true);
- else
- available = tokenBegin;
- }
-
- int i;
- try {
- if ((i = inputStream.read(buffer, maxNextCharInd,
- available - maxNextCharInd)) == -1)
- {
- inputStream.close();
- throw new java.io.IOException();
- }
- else
- maxNextCharInd += i;
- return;
- }
- catch(java.io.IOException e) {
- --bufpos;
- backup(0);
- if (tokenBegin == -1)
- tokenBegin = bufpos;
- throw e;
- }
- }
-
- public char BeginToken() throws java.io.IOException
- {
- tokenBegin = -1;
- char c = readChar();
- tokenBegin = bufpos;
-
- return c;
- }
-
- protected void UpdateLineColumn(char c)
- {
- column++;
-
- if (prevCharIsLF)
- {
- prevCharIsLF = false;
- line += (column = 1);
- }
- else if (prevCharIsCR)
- {
- prevCharIsCR = false;
- if (c == '\n')
- {
- prevCharIsLF = true;
- }
- else
- line += (column = 1);
- }
-
- switch (c)
- {
- case '\r' :
- prevCharIsCR = true;
- break;
- case '\n' :
- prevCharIsLF = true;
- break;
- case '\t' :
- column--;
- column += (tabSize - (column % tabSize));
- break;
- default :
- break;
- }
-
- bufline[bufpos] = line;
- bufcolumn[bufpos] = column;
- }
-
- public char readChar() throws java.io.IOException
- {
- if (inBuf > 0)
- {
- --inBuf;
-
- if (++bufpos == bufsize)
- bufpos = 0;
-
- return buffer[bufpos];
- }
-
- if (++bufpos >= maxNextCharInd)
- FillBuff();
-
- char c = buffer[bufpos];
-
- UpdateLineColumn(c);
- return (c);
- }
-
- /**
- * @deprecated
- * @see #getEndColumn
- */
- @Deprecated
- public int getColumn() {
- return bufcolumn[bufpos];
- }
-
- /**
- * @deprecated
- * @see #getEndLine
- */
- @Deprecated
- public int getLine() {
- return bufline[bufpos];
- }
-
- public int getEndColumn() {
- return bufcolumn[bufpos];
- }
-
- public int getEndLine() {
- return bufline[bufpos];
- }
-
- public int getBeginColumn() {
- return bufcolumn[tokenBegin];
- }
-
- public int getBeginLine() {
- return bufline[tokenBegin];
- }
-
- public void backup(int amount) {
-
- inBuf += amount;
- if ((bufpos -= amount) < 0)
- bufpos += bufsize;
- }
-
- public SimpleCharStream(java.io.Reader dstream, int startline,
- int startcolumn, int buffersize)
- {
- inputStream = dstream;
- line = startline;
- column = startcolumn - 1;
-
- available = bufsize = buffersize;
- buffer = new char[buffersize];
- bufline = new int[buffersize];
- bufcolumn = new int[buffersize];
- }
-
- public SimpleCharStream(java.io.Reader dstream, int startline,
- int startcolumn)
- {
- this(dstream, startline, startcolumn, 4096);
- }
-
- public SimpleCharStream(java.io.Reader dstream)
- {
- this(dstream, 1, 1, 4096);
- }
- public void ReInit(java.io.Reader dstream, int startline,
- int startcolumn, int buffersize)
- {
- inputStream = dstream;
- line = startline;
- column = startcolumn - 1;
-
- if (buffer == null || buffersize != buffer.length)
- {
- available = bufsize = buffersize;
- buffer = new char[buffersize];
- bufline = new int[buffersize];
- bufcolumn = new int[buffersize];
- }
- prevCharIsLF = prevCharIsCR = false;
- tokenBegin = inBuf = maxNextCharInd = 0;
- bufpos = -1;
- }
-
- public void ReInit(java.io.Reader dstream, int startline,
- int startcolumn)
- {
- ReInit(dstream, startline, startcolumn, 4096);
- }
-
- public void ReInit(java.io.Reader dstream)
- {
- ReInit(dstream, 1, 1, 4096);
- }
- public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
- {
- this(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, int startline,
- int startcolumn, int buffersize)
- {
- this(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn) throws java.io.UnsupportedEncodingException
- {
- this(dstream, encoding, startline, startcolumn, 4096);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, int startline,
- int startcolumn)
- {
- this(dstream, startline, startcolumn, 4096);
- }
-
- public SimpleCharStream(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
- {
- this(dstream, encoding, 1, 1, 4096);
- }
-
- public SimpleCharStream(java.io.InputStream dstream)
- {
- this(dstream, 1, 1, 4096);
- }
-
- public void ReInit(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn, int buffersize) throws java.io.UnsupportedEncodingException
- {
- ReInit(encoding == null ? new java.io.InputStreamReader(dstream) : new java.io.InputStreamReader(dstream, encoding), startline, startcolumn, buffersize);
- }
-
- public void ReInit(java.io.InputStream dstream, int startline,
- int startcolumn, int buffersize)
- {
- ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, buffersize);
- }
-
- public void ReInit(java.io.InputStream dstream, String encoding) throws java.io.UnsupportedEncodingException
- {
- ReInit(dstream, encoding, 1, 1, 4096);
- }
-
- public void ReInit(java.io.InputStream dstream)
- {
- ReInit(dstream, 1, 1, 4096);
- }
- public void ReInit(java.io.InputStream dstream, String encoding, int startline,
- int startcolumn) throws java.io.UnsupportedEncodingException
- {
- ReInit(dstream, encoding, startline, startcolumn, 4096);
- }
- public void ReInit(java.io.InputStream dstream, int startline,
- int startcolumn)
- {
- ReInit(dstream, startline, startcolumn, 4096);
- }
- public String GetImage()
- {
- if (bufpos >= tokenBegin)
- return new String(buffer, tokenBegin, bufpos - tokenBegin + 1);
- else
- return new String(buffer, tokenBegin, bufsize - tokenBegin) +
- new String(buffer, 0, bufpos + 1);
- }
-
- public char[] GetSuffix(int len)
- {
- char[] ret = new char[len];
-
- if ((bufpos + 1) >= len)
- System.arraycopy(buffer, bufpos - len + 1, ret, 0, len);
- else
- {
- System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0,
- len - bufpos - 1);
- System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1);
- }
-
- return ret;
- }
-
- public void Done()
- {
- buffer = null;
- bufline = null;
- bufcolumn = null;
- }
-
- /**
- * Method to adjust line and column numbers for the start of a token.
- */
- public void adjustBeginLineColumn(int newLine, int newCol)
- {
- int start = tokenBegin;
- int len;
-
- if (bufpos >= tokenBegin)
- {
- len = bufpos - tokenBegin + inBuf + 1;
- }
- else
- {
- len = bufsize - tokenBegin + bufpos + 1 + inBuf;
- }
-
- int i = 0, j = 0, k = 0;
- int nextColDiff = 0, columnDiff = 0;
-
- while (i < len &&
- bufline[j = start % bufsize] == bufline[k = ++start % bufsize])
- {
- bufline[j] = newLine;
- nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j];
- bufcolumn[j] = newCol + columnDiff;
- columnDiff = nextColDiff;
- i++;
- }
-
- if (i < len)
- {
- bufline[j] = newLine++;
- bufcolumn[j] = newCol + columnDiff;
-
- while (i++ < len)
- {
- if (bufline[j = start % bufsize] != bufline[++start % bufsize])
- bufline[j] = newLine++;
- else
- bufline[j] = newLine;
- }
- }
-
- line = bufline[j];
- column = bufcolumn[j];
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/Token.java b/src/org/apache/james/mime4j/field/datetime/parser/Token.java
deleted file mode 100644
index 0927a09..0000000
--- a/src/org/apache/james/mime4j/field/datetime/parser/Token.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.datetime.parser;
-
-/**
- * Describes the input token stream.
- */
-
-public class Token {
-
- /**
- * An integer that describes the kind of this token. This numbering
- * system is determined by JavaCCParser, and a table of these numbers is
- * stored in the file ...Constants.java.
- */
- public int kind;
-
- /**
- * beginLine and beginColumn describe the position of the first character
- * of this token; endLine and endColumn describe the position of the
- * last character of this token.
- */
- public int beginLine, beginColumn, endLine, endColumn;
-
- /**
- * The string image of the token.
- */
- public String image;
-
- /**
- * A reference to the next regular (non-special) token from the input
- * stream. If this is the last token from the input stream, or if the
- * token manager has not read tokens beyond this one, this field is
- * set to null. This is true only if this token is also a regular
- * token. Otherwise, see below for a description of the contents of
- * this field.
- */
- public Token next;
-
- /**
- * This field is used to access special tokens that occur prior to this
- * token, but after the immediately preceding regular (non-special) token.
- * If there are no such special tokens, this field is set to null.
- * When there are more than one such special token, this field refers
- * to the last of these special tokens, which in turn refers to the next
- * previous special token through its specialToken field, and so on
- * until the first special token (whose specialToken field is null).
- * The next fields of special tokens refer to other special tokens that
- * immediately follow it (without an intervening regular token). If there
- * is no such token, this field is null.
- */
- public Token specialToken;
-
- /**
- * Returns the image.
- */
- public String toString()
- {
- return image;
- }
-
- /**
- * Returns a new Token object, by default. However, if you want, you
- * can create and return subclass objects based on the value of ofKind.
- * Simply add the cases to the switch for all those special cases.
- * For example, if you have a subclass of Token called IDToken that
- * you want to create if ofKind is ID, simlpy add something like :
- *
- * case MyParserConstants.ID : return new IDToken();
- *
- * to the following switch statement. Then you can cast matchedToken
- * variable to the appropriate type and use it in your lexical actions.
- */
- public static final Token newToken(int ofKind)
- {
- switch(ofKind)
- {
- default : return new Token();
- }
- }
-
-}
diff --git a/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java b/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java
deleted file mode 100644
index e7043c1..0000000
--- a/src/org/apache/james/mime4j/field/datetime/parser/TokenMgrError.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */
-/*
- * Copyright 2004 the mime4j 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 org.apache.james.mime4j.field.datetime.parser;
-
-public class TokenMgrError extends Error
-{
- /*
- * Ordinals for various reasons why an Error of this type can be thrown.
- */
-
- /**
- * Lexical error occured.
- */
- static final int LEXICAL_ERROR = 0;
-
- /**
- * An attempt wass made to create a second instance of a static token manager.
- */
- static final int STATIC_LEXER_ERROR = 1;
-
- /**
- * Tried to change to an invalid lexical state.
- */
- static final int INVALID_LEXICAL_STATE = 2;
-
- /**
- * Detected (and bailed out of) an infinite loop in the token manager.
- */
- static final int LOOP_DETECTED = 3;
-
- /**
- * Indicates the reason why the exception is thrown. It will have
- * one of the above 4 values.
- */
- int errorCode;
-
- /**
- * Replaces unprintable characters by their espaced (or unicode escaped)
- * equivalents in the given string
- */
- protected static final String addEscapes(String str) {
- StringBuffer retval = new StringBuffer();
- char ch;
- for (int i = 0; i < str.length(); i++) {
- switch (str.charAt(i))
- {
- case 0 :
- continue;
- case '\b':
- retval.append("\\b");
- continue;
- case '\t':
- retval.append("\\t");
- continue;
- case '\n':
- retval.append("\\n");
- continue;
- case '\f':
- retval.append("\\f");
- continue;
- case '\r':
- retval.append("\\r");
- continue;
- case '\"':
- retval.append("\\\"");
- continue;
- case '\'':
- retval.append("\\\'");
- continue;
- case '\\':
- retval.append("\\\\");
- continue;
- default:
- if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
- String s = "0000" + Integer.toString(ch, 16);
- retval.append("\\u" + s.substring(s.length() - 4, s.length()));
- } else {
- retval.append(ch);
- }
- continue;
- }
- }
- return retval.toString();
- }
-
- /**
- * Returns a detailed message for the Error when it is thrown by the
- * token manager to indicate a lexical error.
- * Parameters :
- * EOFSeen : indicates if EOF caused the lexicl error
- * curLexState : lexical state in which this error occured
- * errorLine : line number when the error occured
- * errorColumn : column number when the error occured
- * errorAfter : prefix that was seen before this error occured
- * curchar : the offending character
- * Note: You can customize the lexical error message by modifying this method.
- */
- protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) {
- return("Lexical error at line " +
- errorLine + ", column " +
- errorColumn + ". Encountered: " +
- (EOFSeen ? "<EOF> " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") +
- "after : \"" + addEscapes(errorAfter) + "\"");
- }
-
- /**
- * You can also modify the body of this method to customize your error messages.
- * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not
- * of end-users concern, so you can return something like :
- *
- * "Internal Error : Please file a bug report .... "
- *
- * from this method for such cases in the release version of your parser.
- */
- public String getMessage() {
- return super.getMessage();
- }
-
- /*
- * Constructors of various flavors follow.
- */
-
- public TokenMgrError() {
- }
-
- public TokenMgrError(String message, int reason) {
- super(message);
- errorCode = reason;
- }
-
- public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) {
- this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason);
- }
-}
diff --git a/src/org/apache/james/mime4j/util/CharsetUtil.java b/src/org/apache/james/mime4j/util/CharsetUtil.java
deleted file mode 100644
index 4e712fc..0000000
--- a/src/org/apache/james/mime4j/util/CharsetUtil.java
+++ /dev/null
@@ -1,1249 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one *
- * or more contributor license agreements. See the NOTICE file *
- * distributed with this work for additional information *
- * regarding copyright ownership. The ASF licenses this file *
- * to you 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 org.apache.james.mime4j.util;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.IllegalCharsetNameException;
-import java.nio.charset.UnsupportedCharsetException;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.TreeSet;
-
-//BEGIN android-changed: Stubbing out logging
-import org.apache.james.mime4j.Log;
-import org.apache.james.mime4j.LogFactory;
-//END android-changed
-
-/**
- * Utility class for working with character sets. It is somewhat similar to
- * the Java 1.4 <code>java.nio.charset.Charset</code> class but knows many
- * more aliases and is compatible with Java 1.3. It will use a simple detection
- * mechanism to detect what character sets the current VM supports. This will
- * be a sub-set of the character sets listed in the
- * <a href="http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html">
- * Java 1.5 (J2SE5.0) Supported Encodings</a> document.
- * <p>
- * The <a href="http://www.iana.org/assignments/character-sets">
- * IANA Character Sets</a> document has been used to determine the preferred
- * MIME character set names and to get a list of known aliases.
- * <p>
- * This is a complete list of the character sets known to this class:
- * <table>
- * <tr>
- * <td>Canonical (Java) name</td>
- * <td>MIME preferred</td>
- * <td>Aliases</td>
- * </tr>
- * <tr>
- * <td>ASCII</td>
- * <td>US-ASCII</td>
- * <td>ANSI_X3.4-1968 iso-ir-6 ANSI_X3.4-1986 ISO_646.irv:1991 ISO646-US us IBM367 cp367 csASCII ascii7 646 iso_646.irv:1983 </td>
- * </tr>
- * <tr>
- * <td>Big5</td>
- * <td>Big5</td>
- * <td>csBig5 CN-Big5 BIG-FIVE BIGFIVE </td>
- * </tr>
- * <tr>
- * <td>Big5_HKSCS</td>
- * <td>Big5-HKSCS</td>
- * <td>big5hkscs </td>
- * </tr>
- * <tr>
- * <td>Big5_Solaris</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp037</td>
- * <td>IBM037</td>
- * <td>ebcdic-cp-us ebcdic-cp-ca ebcdic-cp-wt ebcdic-cp-nl csIBM037 </td>
- * </tr>
- * <tr>
- * <td>Cp1006</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1025</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1026</td>
- * <td>IBM1026</td>
- * <td>csIBM1026 </td>
- * </tr>
- * <tr>
- * <td>Cp1046</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1047</td>
- * <td>IBM1047</td>
- * <td>IBM-1047 </td>
- * </tr>
- * <tr>
- * <td>Cp1097</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1098</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1112</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1122</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1123</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1124</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1140</td>
- * <td>IBM01140</td>
- * <td>CCSID01140 CP01140 ebcdic-us-37+euro </td>
- * </tr>
- * <tr>
- * <td>Cp1141</td>
- * <td>IBM01141</td>
- * <td>CCSID01141 CP01141 ebcdic-de-273+euro </td>
- * </tr>
- * <tr>
- * <td>Cp1142</td>
- * <td>IBM01142</td>
- * <td>CCSID01142 CP01142 ebcdic-dk-277+euro ebcdic-no-277+euro </td>
- * </tr>
- * <tr>
- * <td>Cp1143</td>
- * <td>IBM01143</td>
- * <td>CCSID01143 CP01143 ebcdic-fi-278+euro ebcdic-se-278+euro </td>
- * </tr>
- * <tr>
- * <td>Cp1144</td>
- * <td>IBM01144</td>
- * <td>CCSID01144 CP01144 ebcdic-it-280+euro </td>
- * </tr>
- * <tr>
- * <td>Cp1145</td>
- * <td>IBM01145</td>
- * <td>CCSID01145 CP01145 ebcdic-es-284+euro </td>
- * </tr>
- * <tr>
- * <td>Cp1146</td>
- * <td>IBM01146</td>
- * <td>CCSID01146 CP01146 ebcdic-gb-285+euro </td>
- * </tr>
- * <tr>
- * <td>Cp1147</td>
- * <td>IBM01147</td>
- * <td>CCSID01147 CP01147 ebcdic-fr-297+euro </td>
- * </tr>
- * <tr>
- * <td>Cp1148</td>
- * <td>IBM01148</td>
- * <td>CCSID01148 CP01148 ebcdic-international-500+euro </td>
- * </tr>
- * <tr>
- * <td>Cp1149</td>
- * <td>IBM01149</td>
- * <td>CCSID01149 CP01149 ebcdic-is-871+euro </td>
- * </tr>
- * <tr>
- * <td>Cp1250</td>
- * <td>windows-1250</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1251</td>
- * <td>windows-1251</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1252</td>
- * <td>windows-1252</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1253</td>
- * <td>windows-1253</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1254</td>
- * <td>windows-1254</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1255</td>
- * <td>windows-1255</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1256</td>
- * <td>windows-1256</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1257</td>
- * <td>windows-1257</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1258</td>
- * <td>windows-1258</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1381</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp1383</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp273</td>
- * <td>IBM273</td>
- * <td>csIBM273 </td>
- * </tr>
- * <tr>
- * <td>Cp277</td>
- * <td>IBM277</td>
- * <td>EBCDIC-CP-DK EBCDIC-CP-NO csIBM277 </td>
- * </tr>
- * <tr>
- * <td>Cp278</td>
- * <td>IBM278</td>
- * <td>CP278 ebcdic-cp-fi ebcdic-cp-se csIBM278 </td>
- * </tr>
- * <tr>
- * <td>Cp280</td>
- * <td>IBM280</td>
- * <td>ebcdic-cp-it csIBM280 </td>
- * </tr>
- * <tr>
- * <td>Cp284</td>
- * <td>IBM284</td>
- * <td>ebcdic-cp-es csIBM284 </td>
- * </tr>
- * <tr>
- * <td>Cp285</td>
- * <td>IBM285</td>
- * <td>ebcdic-cp-gb csIBM285 </td>
- * </tr>
- * <tr>
- * <td>Cp297</td>
- * <td>IBM297</td>
- * <td>ebcdic-cp-fr csIBM297 </td>
- * </tr>
- * <tr>
- * <td>Cp33722</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp420</td>
- * <td>IBM420</td>
- * <td>ebcdic-cp-ar1 csIBM420 </td>
- * </tr>
- * <tr>
- * <td>Cp424</td>
- * <td>IBM424</td>
- * <td>ebcdic-cp-he csIBM424 </td>
- * </tr>
- * <tr>
- * <td>Cp437</td>
- * <td>IBM437</td>
- * <td>437 csPC8CodePage437 </td>
- * </tr>
- * <tr>
- * <td>Cp500</td>
- * <td>IBM500</td>
- * <td>ebcdic-cp-be ebcdic-cp-ch csIBM500 </td>
- * </tr>
- * <tr>
- * <td>Cp737</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp775</td>
- * <td>IBM775</td>
- * <td>csPC775Baltic </td>
- * </tr>
- * <tr>
- * <td>Cp838</td>
- * <td>IBM-Thai</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp850</td>
- * <td>IBM850</td>
- * <td>850 csPC850Multilingual </td>
- * </tr>
- * <tr>
- * <td>Cp852</td>
- * <td>IBM852</td>
- * <td>852 csPCp852 </td>
- * </tr>
- * <tr>
- * <td>Cp855</td>
- * <td>IBM855</td>
- * <td>855 csIBM855 </td>
- * </tr>
- * <tr>
- * <td>Cp856</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp857</td>
- * <td>IBM857</td>
- * <td>857 csIBM857 </td>
- * </tr>
- * <tr>
- * <td>Cp858</td>
- * <td>IBM00858</td>
- * <td>CCSID00858 CP00858 PC-Multilingual-850+euro </td>
- * </tr>
- * <tr>
- * <td>Cp860</td>
- * <td>IBM860</td>
- * <td>860 csIBM860 </td>
- * </tr>
- * <tr>
- * <td>Cp861</td>
- * <td>IBM861</td>
- * <td>861 cp-is csIBM861 </td>
- * </tr>
- * <tr>
- * <td>Cp862</td>
- * <td>IBM862</td>
- * <td>862 csPC862LatinHebrew </td>
- * </tr>
- * <tr>
- * <td>Cp863</td>
- * <td>IBM863</td>
- * <td>863 csIBM863 </td>
- * </tr>
- * <tr>
- * <td>Cp864</td>
- * <td>IBM864</td>
- * <td>cp864 csIBM864 </td>
- * </tr>
- * <tr>
- * <td>Cp865</td>
- * <td>IBM865</td>
- * <td>865 csIBM865 </td>
- * </tr>
- * <tr>
- * <td>Cp866</td>
- * <td>IBM866</td>
- * <td>866 csIBM866 </td>
- * </tr>
- * <tr>
- * <td>Cp868</td>
- * <td>IBM868</td>
- * <td>cp-ar csIBM868 </td>
- * </tr>
- * <tr>
- * <td>Cp869</td>
- * <td>IBM869</td>
- * <td>cp-gr csIBM869 </td>
- * </tr>
- * <tr>
- * <td>Cp870</td>
- * <td>IBM870</td>
- * <td>ebcdic-cp-roece ebcdic-cp-yu csIBM870 </td>
- * </tr>
- * <tr>
- * <td>Cp871</td>
- * <td>IBM871</td>
- * <td>ebcdic-cp-is csIBM871 </td>
- * </tr>
- * <tr>
- * <td>Cp875</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp918</td>
- * <td>IBM918</td>
- * <td>ebcdic-cp-ar2 csIBM918 </td>
- * </tr>
- * <tr>
- * <td>Cp921</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp922</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp930</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp933</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp935</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp937</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp939</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp942</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp942C</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp943</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp943C</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp948</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp949</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp949C</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp950</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp964</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>Cp970</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>EUC_CN</td>
- * <td>GB2312</td>
- * <td>x-EUC-CN csGB2312 euccn euc-cn gb2312-80 gb2312-1980 CN-GB CN-GB-ISOIR165 </td>
- * </tr>
- * <tr>
- * <td>EUC_JP</td>
- * <td>EUC-JP</td>
- * <td>csEUCPkdFmtJapanese Extended_UNIX_Code_Packed_Format_for_Japanese eucjis x-eucjp eucjp x-euc-jp </td>
- * </tr>
- * <tr>
- * <td>EUC_JP_LINUX</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>EUC_JP_Solaris</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>EUC_KR</td>
- * <td>EUC-KR</td>
- * <td>csEUCKR ksc5601 5601 ksc5601_1987 ksc_5601 ksc5601-1987 ks_c_5601-1987 euckr </td>
- * </tr>
- * <tr>
- * <td>EUC_TW</td>
- * <td>EUC-TW</td>
- * <td>x-EUC-TW cns11643 euctw </td>
- * </tr>
- * <tr>
- * <td>GB18030</td>
- * <td>GB18030</td>
- * <td>gb18030-2000 </td>
- * </tr>
- * <tr>
- * <td>GBK</td>
- * <td>windows-936</td>
- * <td>CP936 MS936 ms_936 x-mswin-936 </td>
- * </tr>
- * <tr>
- * <td>ISCII91</td>
- * <td>?</td>
- * <td>x-ISCII91 iscii </td>
- * </tr>
- * <tr>
- * <td>ISO2022CN</td>
- * <td>ISO-2022-CN</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>ISO2022JP</td>
- * <td>ISO-2022-JP</td>
- * <td>csISO2022JP JIS jis_encoding csjisencoding </td>
- * </tr>
- * <tr>
- * <td>ISO2022KR</td>
- * <td>ISO-2022-KR</td>
- * <td>csISO2022KR </td>
- * </tr>
- * <tr>
- * <td>ISO2022_CN_CNS</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>ISO2022_CN_GB</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>ISO8859_1</td>
- * <td>ISO-8859-1</td>
- * <td>ISO_8859-1:1987 iso-ir-100 ISO_8859-1 latin1 l1 IBM819 CP819 csISOLatin1 8859_1 819 IBM-819 ISO8859-1 ISO_8859_1 </td>
- * </tr>
- * <tr>
- * <td>ISO8859_13</td>
- * <td>ISO-8859-13</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>ISO8859_15</td>
- * <td>ISO-8859-15</td>
- * <td>ISO_8859-15 Latin-9 8859_15 csISOlatin9 IBM923 cp923 923 L9 IBM-923 ISO8859-15 LATIN9 LATIN0 csISOlatin0 ISO8859_15_FDIS </td>
- * </tr>
- * <tr>
- * <td>ISO8859_2</td>
- * <td>ISO-8859-2</td>
- * <td>ISO_8859-2:1987 iso-ir-101 ISO_8859-2 latin2 l2 csISOLatin2 8859_2 iso8859_2 </td>
- * </tr>
- * <tr>
- * <td>ISO8859_3</td>
- * <td>ISO-8859-3</td>
- * <td>ISO_8859-3:1988 iso-ir-109 ISO_8859-3 latin3 l3 csISOLatin3 8859_3 </td>
- * </tr>
- * <tr>
- * <td>ISO8859_4</td>
- * <td>ISO-8859-4</td>
- * <td>ISO_8859-4:1988 iso-ir-110 ISO_8859-4 latin4 l4 csISOLatin4 8859_4 </td>
- * </tr>
- * <tr>
- * <td>ISO8859_5</td>
- * <td>ISO-8859-5</td>
- * <td>ISO_8859-5:1988 iso-ir-144 ISO_8859-5 cyrillic csISOLatinCyrillic 8859_5 </td>
- * </tr>
- * <tr>
- * <td>ISO8859_6</td>
- * <td>ISO-8859-6</td>
- * <td>ISO_8859-6:1987 iso-ir-127 ISO_8859-6 ECMA-114 ASMO-708 arabic csISOLatinArabic 8859_6 </td>
- * </tr>
- * <tr>
- * <td>ISO8859_7</td>
- * <td>ISO-8859-7</td>
- * <td>ISO_8859-7:1987 iso-ir-126 ISO_8859-7 ELOT_928 ECMA-118 greek greek8 csISOLatinGreek 8859_7 sun_eu_greek </td>
- * </tr>
- * <tr>
- * <td>ISO8859_8</td>
- * <td>ISO-8859-8</td>
- * <td>ISO_8859-8:1988 iso-ir-138 ISO_8859-8 hebrew csISOLatinHebrew 8859_8 </td>
- * </tr>
- * <tr>
- * <td>ISO8859_9</td>
- * <td>ISO-8859-9</td>
- * <td>ISO_8859-9:1989 iso-ir-148 ISO_8859-9 latin5 l5 csISOLatin5 8859_9 </td>
- * </tr>
- * <tr>
- * <td>JISAutoDetect</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>JIS_C6626-1983</td>
- * <td>JIS_C6626-1983</td>
- * <td>x-JIS0208 JIS0208 csISO87JISX0208 x0208 JIS_X0208-1983 iso-ir-87 </td>
- * </tr>
- * <tr>
- * <td>JIS_X0201</td>
- * <td>JIS_X0201</td>
- * <td>X0201 JIS0201 csHalfWidthKatakana </td>
- * </tr>
- * <tr>
- * <td>JIS_X0212-1990</td>
- * <td>JIS_X0212-1990</td>
- * <td>iso-ir-159 x0212 JIS0212 csISO159JISX02121990 </td>
- * </tr>
- * <tr>
- * <td>KOI8_R</td>
- * <td>KOI8-R</td>
- * <td>csKOI8R koi8 </td>
- * </tr>
- * <tr>
- * <td>MS874</td>
- * <td>windows-874</td>
- * <td>cp874 </td>
- * </tr>
- * <tr>
- * <td>MS932</td>
- * <td>Windows-31J</td>
- * <td>windows-932 csWindows31J x-ms-cp932 </td>
- * </tr>
- * <tr>
- * <td>MS949</td>
- * <td>windows-949</td>
- * <td>windows949 ms_949 x-windows-949 </td>
- * </tr>
- * <tr>
- * <td>MS950</td>
- * <td>windows-950</td>
- * <td>x-windows-950 </td>
- * </tr>
- * <tr>
- * <td>MS950_HKSCS</td>
- * <td></td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacArabic</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacCentralEurope</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacCroatian</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacCyrillic</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacDingbat</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacGreek</td>
- * <td>MacGreek</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacHebrew</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacIceland</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacRoman</td>
- * <td>MacRoman</td>
- * <td>Macintosh MAC csMacintosh </td>
- * </tr>
- * <tr>
- * <td>MacRomania</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacSymbol</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacThai</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacTurkish</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>MacUkraine</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>SJIS</td>
- * <td>Shift_JIS</td>
- * <td>MS_Kanji csShiftJIS shift-jis x-sjis pck </td>
- * </tr>
- * <tr>
- * <td>TIS620</td>
- * <td>TIS-620</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>UTF-16</td>
- * <td>UTF-16</td>
- * <td>UTF_16 </td>
- * </tr>
- * <tr>
- * <td>UTF8</td>
- * <td>UTF-8</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>UnicodeBig</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>UnicodeBigUnmarked</td>
- * <td>UTF-16BE</td>
- * <td>X-UTF-16BE UTF_16BE ISO-10646-UCS-2 </td>
- * </tr>
- * <tr>
- * <td>UnicodeLittle</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * <tr>
- * <td>UnicodeLittleUnmarked</td>
- * <td>UTF-16LE</td>
- * <td>UTF_16LE X-UTF-16LE </td>
- * </tr>
- * <tr>
- * <td>x-Johab</td>
- * <td>johab</td>
- * <td>johab cp1361 ms1361 ksc5601-1992 ksc5601_1992 </td>
- * </tr>
- * <tr>
- * <td>x-iso-8859-11</td>
- * <td>?</td>
- * <td></td>
- * </tr>
- * </table>
- *
- *
- * @version $Id: CharsetUtil.java,v 1.1 2004/10/25 07:26:46 ntherning Exp $
- */
-public class CharsetUtil {
- private static Log log = LogFactory.getLog(CharsetUtil.class);
-
- private static class Charset implements Comparable<Charset> {
- private String canonical = null;
- private String mime = null;
- private String[] aliases = null;
-
- private Charset(String canonical, String mime, String[] aliases) {
- this.canonical = canonical;
- this.mime = mime;
- this.aliases = aliases;
- }
-
- public int compareTo(Charset c) {
- return this.canonical.compareTo(c.canonical);
- }
- }
-
- private static Charset[] JAVA_CHARSETS = {
- new Charset("ISO8859_1", "ISO-8859-1",
- new String[] {"ISO_8859-1:1987", "iso-ir-100", "ISO_8859-1",
- "latin1", "l1", "IBM819", "CP819",
- "csISOLatin1", "8859_1", "819", "IBM-819",
- "ISO8859-1", "ISO_8859_1"}),
- new Charset("ISO8859_2", "ISO-8859-2",
- new String[] {"ISO_8859-2:1987", "iso-ir-101", "ISO_8859-2",
- "latin2", "l2", "csISOLatin2", "8859_2",
- "iso8859_2"}),
- new Charset("ISO8859_3", "ISO-8859-3", new String[] {"ISO_8859-3:1988", "iso-ir-109", "ISO_8859-3", "latin3", "l3", "csISOLatin3", "8859_3"}),
- new Charset("ISO8859_4", "ISO-8859-4",
- new String[] {"ISO_8859-4:1988", "iso-ir-110", "ISO_8859-4",
- "latin4", "l4", "csISOLatin4", "8859_4"}),
- new Charset("ISO8859_5", "ISO-8859-5",
- new String[] {"ISO_8859-5:1988", "iso-ir-144", "ISO_8859-5",
- "cyrillic", "csISOLatinCyrillic", "8859_5"}),
- new Charset("ISO8859_6", "ISO-8859-6", new String[] {"ISO_8859-6:1987", "iso-ir-127", "ISO_8859-6", "ECMA-114", "ASMO-708", "arabic", "csISOLatinArabic", "8859_6"}),
- new Charset("ISO8859_7", "ISO-8859-7",
- new String[] {"ISO_8859-7:1987", "iso-ir-126", "ISO_8859-7",
- "ELOT_928", "ECMA-118", "greek", "greek8",
- "csISOLatinGreek", "8859_7", "sun_eu_greek"}),
- new Charset("ISO8859_8", "ISO-8859-8", new String[] {"ISO_8859-8:1988", "iso-ir-138", "ISO_8859-8", "hebrew", "csISOLatinHebrew", "8859_8"}),
- new Charset("ISO8859_9", "ISO-8859-9",
- new String[] {"ISO_8859-9:1989", "iso-ir-148", "ISO_8859-9",
- "latin5", "l5", "csISOLatin5", "8859_9"}),
-
- new Charset("ISO8859_13", "ISO-8859-13", new String[] {}),
- new Charset("ISO8859_15", "ISO-8859-15",
- new String[] {"ISO_8859-15", "Latin-9", "8859_15",
- "csISOlatin9", "IBM923", "cp923", "923", "L9",
- "IBM-923", "ISO8859-15", "LATIN9", "LATIN0",
- "csISOlatin0", "ISO8859_15_FDIS"}),
- new Charset("KOI8_R", "KOI8-R", new String[] {"csKOI8R", "koi8"}),
- new Charset("ASCII", "US-ASCII",
- new String[] {"ANSI_X3.4-1968", "iso-ir-6",
- "ANSI_X3.4-1986", "ISO_646.irv:1991",
- "ISO646-US", "us", "IBM367", "cp367",
- "csASCII", "ascii7", "646", "iso_646.irv:1983"}),
- new Charset("UTF8", "UTF-8", new String[] {}),
- new Charset("UTF-16", "UTF-16", new String[] {"UTF_16"}),
- new Charset("UnicodeBigUnmarked", "UTF-16BE", new String[] {"X-UTF-16BE", "UTF_16BE", "ISO-10646-UCS-2"}),
- new Charset("UnicodeLittleUnmarked", "UTF-16LE", new String[] {"UTF_16LE", "X-UTF-16LE"}),
- new Charset("Big5", "Big5", new String[] {"csBig5", "CN-Big5", "BIG-FIVE", "BIGFIVE"}),
- new Charset("Big5_HKSCS", "Big5-HKSCS", new String[] {"big5hkscs"}),
- new Charset("EUC_JP", "EUC-JP",
- new String[] {"csEUCPkdFmtJapanese",
- "Extended_UNIX_Code_Packed_Format_for_Japanese",
- "eucjis", "x-eucjp", "eucjp", "x-euc-jp"}),
- new Charset("EUC_KR", "EUC-KR",
- new String[] {"csEUCKR", "ksc5601", "5601", "ksc5601_1987",
- "ksc_5601", "ksc5601-1987", "ks_c_5601-1987",
- "euckr"}),
- new Charset("GB18030", "GB18030", new String[] {"gb18030-2000"}),
- new Charset("EUC_CN", "GB2312", new String[] {"x-EUC-CN", "csGB2312", "euccn", "euc-cn", "gb2312-80", "gb2312-1980", "CN-GB", "CN-GB-ISOIR165"}),
- new Charset("GBK", "windows-936", new String[] {"CP936", "MS936", "ms_936", "x-mswin-936"}),
-
- new Charset("Cp037", "IBM037", new String[] {"ebcdic-cp-us", "ebcdic-cp-ca", "ebcdic-cp-wt", "ebcdic-cp-nl", "csIBM037"}),
- new Charset("Cp273", "IBM273", new String[] {"csIBM273"}),
- new Charset("Cp277", "IBM277", new String[] {"EBCDIC-CP-DK", "EBCDIC-CP-NO", "csIBM277"}),
- new Charset("Cp278", "IBM278", new String[] {"CP278", "ebcdic-cp-fi", "ebcdic-cp-se", "csIBM278"}),
- new Charset("Cp280", "IBM280", new String[] {"ebcdic-cp-it", "csIBM280"}),
- new Charset("Cp284", "IBM284", new String[] {"ebcdic-cp-es", "csIBM284"}),
- new Charset("Cp285", "IBM285", new String[] {"ebcdic-cp-gb", "csIBM285"}),
- new Charset("Cp297", "IBM297", new String[] {"ebcdic-cp-fr", "csIBM297"}),
- new Charset("Cp420", "IBM420", new String[] {"ebcdic-cp-ar1", "csIBM420"}),
- new Charset("Cp424", "IBM424", new String[] {"ebcdic-cp-he", "csIBM424"}),
- new Charset("Cp437", "IBM437", new String[] {"437", "csPC8CodePage437"}),
- new Charset("Cp500", "IBM500", new String[] {"ebcdic-cp-be", "ebcdic-cp-ch", "csIBM500"}),
- new Charset("Cp775", "IBM775", new String[] {"csPC775Baltic"}),
- new Charset("Cp838", "IBM-Thai", new String[] {}),
- new Charset("Cp850", "IBM850", new String[] {"850", "csPC850Multilingual"}),
- new Charset("Cp852", "IBM852", new String[] {"852", "csPCp852"}),
- new Charset("Cp855", "IBM855", new String[] {"855", "csIBM855"}),
- new Charset("Cp857", "IBM857", new String[] {"857", "csIBM857"}),
- new Charset("Cp858", "IBM00858",
- new String[] {"CCSID00858", "CP00858",
- "PC-Multilingual-850+euro"}),
- new Charset("Cp860", "IBM860", new String[] {"860", "csIBM860"}),
- new Charset("Cp861", "IBM861", new String[] {"861", "cp-is", "csIBM861"}),
- new Charset("Cp862", "IBM862", new String[] {"862", "csPC862LatinHebrew"}),
- new Charset("Cp863", "IBM863", new String[] {"863", "csIBM863"}),
- new Charset("Cp864", "IBM864", new String[] {"cp864", "csIBM864"}),
- new Charset("Cp865", "IBM865", new String[] {"865", "csIBM865"}),
- new Charset("Cp866", "IBM866", new String[] {"866", "csIBM866"}),
- new Charset("Cp868", "IBM868", new String[] {"cp-ar", "csIBM868"}),
- new Charset("Cp869", "IBM869", new String[] {"cp-gr", "csIBM869"}),
- new Charset("Cp870", "IBM870", new String[] {"ebcdic-cp-roece", "ebcdic-cp-yu", "csIBM870"}),
- new Charset("Cp871", "IBM871", new String[] {"ebcdic-cp-is", "csIBM871"}),
- new Charset("Cp918", "IBM918", new String[] {"ebcdic-cp-ar2", "csIBM918"}),
- new Charset("Cp1026", "IBM1026", new String[] {"csIBM1026"}),
- new Charset("Cp1047", "IBM1047", new String[] {"IBM-1047"}),
- new Charset("Cp1140", "IBM01140",
- new String[] {"CCSID01140", "CP01140",
- "ebcdic-us-37+euro"}),
- new Charset("Cp1141", "IBM01141",
- new String[] {"CCSID01141", "CP01141",
- "ebcdic-de-273+euro"}),
- new Charset("Cp1142", "IBM01142", new String[] {"CCSID01142", "CP01142", "ebcdic-dk-277+euro", "ebcdic-no-277+euro"}),
- new Charset("Cp1143", "IBM01143", new String[] {"CCSID01143", "CP01143", "ebcdic-fi-278+euro", "ebcdic-se-278+euro"}),
- new Charset("Cp1144", "IBM01144", new String[] {"CCSID01144", "CP01144", "ebcdic-it-280+euro"}),
- new Charset("Cp1145", "IBM01145", new String[] {"CCSID01145", "CP01145", "ebcdic-es-284+euro"}),
- new Charset("Cp1146", "IBM01146", new String[] {"CCSID01146", "CP01146", "ebcdic-gb-285+euro"}),
- new Charset("Cp1147", "IBM01147", new String[] {"CCSID01147", "CP01147", "ebcdic-fr-297+euro"}),
- new Charset("Cp1148", "IBM01148", new String[] {"CCSID01148", "CP01148", "ebcdic-international-500+euro"}),
- new Charset("Cp1149", "IBM01149", new String[] {"CCSID01149", "CP01149", "ebcdic-is-871+euro"}),
- new Charset("Cp1250", "windows-1250", new String[] {}),
- new Charset("Cp1251", "windows-1251", new String[] {}),
- new Charset("Cp1252", "windows-1252", new String[] {}),
- new Charset("Cp1253", "windows-1253", new String[] {}),
- new Charset("Cp1254", "windows-1254", new String[] {}),
- new Charset("Cp1255", "windows-1255", new String[] {}),
- new Charset("Cp1256", "windows-1256", new String[] {}),
- new Charset("Cp1257", "windows-1257", new String[] {}),
- new Charset("Cp1258", "windows-1258", new String[] {}),
- new Charset("ISO2022CN", "ISO-2022-CN", new String[] {}),
- new Charset("ISO2022JP", "ISO-2022-JP", new String[] {"csISO2022JP", "JIS", "jis_encoding", "csjisencoding"}),
- new Charset("ISO2022KR", "ISO-2022-KR", new String[] {"csISO2022KR"}),
- new Charset("JIS_X0201", "JIS_X0201", new String[] {"X0201", "JIS0201", "csHalfWidthKatakana"}),
- new Charset("JIS_X0212-1990", "JIS_X0212-1990", new String[] {"iso-ir-159", "x0212", "JIS0212", "csISO159JISX02121990"}),
- new Charset("JIS_C6626-1983", "JIS_C6626-1983", new String[] {"x-JIS0208", "JIS0208", "csISO87JISX0208", "x0208", "JIS_X0208-1983", "iso-ir-87"}),
- new Charset("SJIS", "Shift_JIS", new String[] {"MS_Kanji", "csShiftJIS", "shift-jis", "x-sjis", "pck"}),
- new Charset("TIS620", "TIS-620", new String[] {}),
- new Charset("MS932", "Windows-31J", new String[] {"windows-932", "csWindows31J", "x-ms-cp932"}),
- new Charset("EUC_TW", "EUC-TW", new String[] {"x-EUC-TW", "cns11643", "euctw"}),
- new Charset("x-Johab", "johab", new String[] {"johab", "cp1361", "ms1361", "ksc5601-1992", "ksc5601_1992"}),
- new Charset("MS950_HKSCS", "", new String[] {}),
- new Charset("MS874", "windows-874", new String[] {"cp874"}),
- new Charset("MS949", "windows-949", new String[] {"windows949", "ms_949", "x-windows-949"}),
- new Charset("MS950", "windows-950", new String[] {"x-windows-950"}),
-
- new Charset("Cp737", null, new String[] {}),
- new Charset("Cp856", null, new String[] {}),
- new Charset("Cp875", null, new String[] {}),
- new Charset("Cp921", null, new String[] {}),
- new Charset("Cp922", null, new String[] {}),
- new Charset("Cp930", null, new String[] {}),
- new Charset("Cp933", null, new String[] {}),
- new Charset("Cp935", null, new String[] {}),
- new Charset("Cp937", null, new String[] {}),
- new Charset("Cp939", null, new String[] {}),
- new Charset("Cp942", null, new String[] {}),
- new Charset("Cp942C", null, new String[] {}),
- new Charset("Cp943", null, new String[] {}),
- new Charset("Cp943C", null, new String[] {}),
- new Charset("Cp948", null, new String[] {}),
- new Charset("Cp949", null, new String[] {}),
- new Charset("Cp949C", null, new String[] {}),
- new Charset("Cp950", null, new String[] {}),
- new Charset("Cp964", null, new String[] {}),
- new Charset("Cp970", null, new String[] {}),
- new Charset("Cp1006", null, new String[] {}),
- new Charset("Cp1025", null, new String[] {}),
- new Charset("Cp1046", null, new String[] {}),
- new Charset("Cp1097", null, new String[] {}),
- new Charset("Cp1098", null, new String[] {}),
- new Charset("Cp1112", null, new String[] {}),
- new Charset("Cp1122", null, new String[] {}),
- new Charset("Cp1123", null, new String[] {}),
- new Charset("Cp1124", null, new String[] {}),
- new Charset("Cp1381", null, new String[] {}),
- new Charset("Cp1383", null, new String[] {}),
- new Charset("Cp33722", null, new String[] {}),
- new Charset("Big5_Solaris", null, new String[] {}),
- new Charset("EUC_JP_LINUX", null, new String[] {}),
- new Charset("EUC_JP_Solaris", null, new String[] {}),
- new Charset("ISCII91", null, new String[] {"x-ISCII91", "iscii"}),
- new Charset("ISO2022_CN_CNS", null, new String[] {}),
- new Charset("ISO2022_CN_GB", null, new String[] {}),
- new Charset("x-iso-8859-11", null, new String[] {}),
- new Charset("JISAutoDetect", null, new String[] {}),
- new Charset("MacArabic", null, new String[] {}),
- new Charset("MacCentralEurope", null, new String[] {}),
- new Charset("MacCroatian", null, new String[] {}),
- new Charset("MacCyrillic", null, new String[] {}),
- new Charset("MacDingbat", null, new String[] {}),
- new Charset("MacGreek", "MacGreek", new String[] {}),
- new Charset("MacHebrew", null, new String[] {}),
- new Charset("MacIceland", null, new String[] {}),
- new Charset("MacRoman", "MacRoman", new String[] {"Macintosh", "MAC", "csMacintosh"}),
- new Charset("MacRomania", null, new String[] {}),
- new Charset("MacSymbol", null, new String[] {}),
- new Charset("MacThai", null, new String[] {}),
- new Charset("MacTurkish", null, new String[] {}),
- new Charset("MacUkraine", null, new String[] {}),
- new Charset("UnicodeBig", null, new String[] {}),
- new Charset("UnicodeLittle", null, new String[] {})
- };
-
- /**
- * Contains the canonical names of character sets which can be used to
- * decode bytes into Java chars.
- */
- private static TreeSet<String> decodingSupported = null;
-
- /**
- * Contains the canonical names of character sets which can be used to
- * encode Java chars into bytes.
- */
- private static TreeSet<String> encodingSupported = null;
-
- /**
- * Maps character set names to Charset objects. All possible names of
- * a charset will be mapped to the Charset.
- */
- private static HashMap<String, Charset> charsetMap = null;
-
- static {
- decodingSupported = new TreeSet<String>();
- encodingSupported = new TreeSet<String>();
- byte[] dummy = new byte[] {'d', 'u', 'm', 'm', 'y'};
- for (int i = 0; i < JAVA_CHARSETS.length; i++) {
- try {
- String s = new String(dummy, JAVA_CHARSETS[i].canonical);
- decodingSupported.add(JAVA_CHARSETS[i].canonical.toLowerCase(Locale.US));
- } catch (UnsupportedOperationException e) {
- } catch (UnsupportedEncodingException e) {
- }
- try {
- "dummy".getBytes(JAVA_CHARSETS[i].canonical);
- encodingSupported.add(JAVA_CHARSETS[i].canonical.toLowerCase(Locale.US));
- } catch (UnsupportedOperationException e) {
- } catch (UnsupportedEncodingException e) {
- }
- }
-
- charsetMap = new HashMap<String, Charset>();
- for (int i = 0; i < JAVA_CHARSETS.length; i++) {
- Charset c = JAVA_CHARSETS[i];
- charsetMap.put(c.canonical.toLowerCase(Locale.US), c);
- if (c.mime != null) {
- charsetMap.put(c.mime.toLowerCase(Locale.US), c);
- }
- if (c.aliases != null) {
- for (int j = 0; j < c.aliases.length; j++) {
- charsetMap.put(c.aliases[j].toLowerCase(Locale.US), c);
- }
- }
- }
-
- if (log.isDebugEnabled()) {
- log.debug("Character sets which support decoding: "
- + decodingSupported);
- log.debug("Character sets which support encoding: "
- + encodingSupported);
- }
- }
-
- /**
- * ANDROID: THE FOLLOWING SET OF STATIC STRINGS ARE COPIED FROM A NEWER VERSION OF MIME4J
- */
-
- /** carriage return - line feed sequence */
- public static final String CRLF = "\r\n";
-
- /** US-ASCII CR, carriage return (13) */
- public static final int CR = '\r';
-
- /** US-ASCII LF, line feed (10) */
- public static final int LF = '\n';
-
- /** US-ASCII SP, space (32) */
- public static final int SP = ' ';
-
- /** US-ASCII HT, horizontal-tab (9)*/
- public static final int HT = '\t';
-
- public static final java.nio.charset.Charset US_ASCII = java.nio.charset.Charset
- .forName("US-ASCII");
-
- public static final java.nio.charset.Charset ISO_8859_1 = java.nio.charset.Charset
- .forName("ISO-8859-1");
-
- public static final java.nio.charset.Charset UTF_8 = java.nio.charset.Charset
- .forName("UTF-8");
-
- /**
- * Returns <code>true</code> if the specified character is a whitespace
- * character (CR, LF, SP or HT).
- *
- * ANDROID: COPIED FROM A NEWER VERSION OF MIME4J
- *
- * @param ch
- * character to test.
- * @return <code>true</code> if the specified character is a whitespace
- * character, <code>false</code> otherwise.
- */
- public static boolean isWhitespace(char ch) {
- return ch == SP || ch == HT || ch == CR || ch == LF;
- }
-
- /**
- * Returns <code>true</code> if the specified string consists entirely of
- * whitespace characters.
- *
- * ANDROID: COPIED FROM A NEWER VERSION OF MIME4J
- *
- * @param s
- * string to test.
- * @return <code>true</code> if the specified string consists entirely of
- * whitespace characters, <code>false</code> otherwise.
- */
- public static boolean isWhitespace(final String s) {
- if (s == null) {
- throw new IllegalArgumentException("String may not be null");
- }
- final int len = s.length();
- for (int i = 0; i < len; i++) {
- if (!isWhitespace(s.charAt(i))) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Determines if the VM supports encoding (chars to bytes) the
- * specified character set. NOTE: the given character set name may
- * not be known to the VM even if this method returns <code>true</code>.
- * Use {@link #toJavaCharset(String)} to get the canonical Java character
- * set name.
- *
- * @param charsetName the characters set name.
- * @return <code>true</code> if encoding is supported, <code>false</code>
- * otherwise.
- */
- public static boolean isEncodingSupported(String charsetName) {
- return encodingSupported.contains(charsetName.toLowerCase(Locale.US));
- }
-
- /**
- * Determines if the VM supports decoding (bytes to chars) the
- * specified character set. NOTE: the given character set name may
- * not be known to the VM even if this method returns <code>true</code>.
- * Use {@link #toJavaCharset(String)} to get the canonical Java character
- * set name.
- *
- * @param charsetName the characters set name.
- * @return <code>true</code> if decoding is supported, <code>false</code>
- * otherwise.
- */
- public static boolean isDecodingSupported(String charsetName) {
- return decodingSupported.contains(charsetName.toLowerCase(Locale.US));
- }
-
- /**
- * Gets the preferred MIME character set name for the specified
- * character set or <code>null</code> if not known.
- *
- * @param charsetName the character set name to look for.
- * @return the MIME preferred name or <code>null</code> if not known.
- */
- public static String toMimeCharset(String charsetName) {
- Charset c = charsetMap.get(charsetName.toLowerCase(Locale.US));
- if (c != null) {
- return c.mime;
- }
- return null;
- }
-
- /**
- * Gets the canonical Java character set name for the specified
- * character set or <code>null</code> if not known. This should be
- * called before doing any conversions using the Java API. NOTE:
- * you must use {@link #isEncodingSupported(String)} or
- * {@link #isDecodingSupported(String)} to make sure the returned
- * Java character set is supported by the current VM.
- *
- * @param charsetName the character set name to look for.
- * @return the canonical Java name or <code>null</code> if not known.
- */
- public static String toJavaCharset(String charsetName) {
- Charset c = charsetMap.get(charsetName.toLowerCase(Locale.US));
- if (c != null) {
- return c.canonical;
- }
- return null;
- }
-
- public static java.nio.charset.Charset getCharset(String charsetName) {
- String defaultCharset = "ISO-8859-1";
-
- // Use the default chareset if given charset is null
- if(charsetName == null) charsetName = defaultCharset;
-
- try {
- return java.nio.charset.Charset.forName(charsetName);
- } catch (IllegalCharsetNameException e) {
- log.info("Illegal charset " + charsetName + ", fallback to " +
- defaultCharset + ": " + e);
- // Use default charset on exception
- return java.nio.charset.Charset.forName(defaultCharset);
- } catch (UnsupportedCharsetException ex) {
- log.info("Unsupported charset " + charsetName + ", fallback to " +
- defaultCharset + ": " + ex);
- // Use default charset on exception
- return java.nio.charset.Charset.forName(defaultCharset);
- }
-
- }
- /*
- * Uncomment the code below and run the main method to regenerate the
- * Javadoc table above when the known charsets change.
- */
-
- /*
- private static String dumpHtmlTable() {
- LinkedList l = new LinkedList(Arrays.asList(JAVA_CHARSETS));
- Collections.sort(l);
- StringBuffer sb = new StringBuffer();
- sb.append(" * <table>\n");
- sb.append(" * <tr>\n");
- sb.append(" * <td>Canonical (Java) name</td>\n");
- sb.append(" * <td>MIME preferred</td>\n");
- sb.append(" * <td>Aliases</td>\n");
- sb.append(" * </tr>\n");
-
- for (Iterator it = l.iterator(); it.hasNext();) {
- Charset c = (Charset) it.next();
- sb.append(" * <tr>\n");
- sb.append(" * <td>" + c.canonical + "</td>\n");
- sb.append(" * <td>" + (c.mime == null ? "?" : c.mime)+ "</td>\n");
- sb.append(" * <td>");
- for (int i = 0; c.aliases != null && i < c.aliases.length; i++) {
- sb.append(c.aliases[i] + " ");
- }
- sb.append("</td>\n");
- sb.append(" * </tr>\n");
- }
- sb.append(" * </table>\n");
- return sb.toString();
- }
-
- public static void main(String[] args) {
- System.out.println(dumpHtmlTable());
- }*/
-}
\ No newline at end of file
diff --git a/tests/Android.mk b/tests/Android.mk
index 2feb55a..850aca3 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -25,15 +25,15 @@
LOCAL_MODULE_TAGS := tests
-LOCAL_JAVA_LIBRARIES := telephony-common
+LOCAL_JAVA_LIBRARIES := telephony-common android-support-test
LOCAL_INSTRUMENTATION_FOR := TeleService
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
- mockito-target \
- legacy-android-test \
mockito-target-minus-junit4 \
espresso-core \
- truth-prebuilt
+ truth-prebuilt \
+ legacy-android-test
+
include $(BUILD_PACKAGE)
diff --git a/tests/src/com/android/TelephonyTestBase.java b/tests/src/com/android/TelephonyTestBase.java
index 6dee12b..044f26b 100644
--- a/tests/src/com/android/TelephonyTestBase.java
+++ b/tests/src/com/android/TelephonyTestBase.java
@@ -18,10 +18,9 @@
import android.content.Context;
import android.os.Handler;
+import android.os.Looper;
import android.support.test.InstrumentationRegistry;
-import com.android.phone.MockitoHelper;
-
import org.mockito.MockitoAnnotations;
import java.util.concurrent.CountDownLatch;
@@ -33,16 +32,17 @@
public class TelephonyTestBase {
protected Context mContext;
- MockitoHelper mMockitoHelper = new MockitoHelper();
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getTargetContext();
- mMockitoHelper.setUp(mContext, getClass());
MockitoAnnotations.initMocks(this);
+ // Set up the looper if it does not exist on the test thread.
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
}
public void tearDown() throws Exception {
- mMockitoHelper.tearDown();
}
protected final void waitForHandlerAction(Handler h, long timeoutMillis) {
diff --git a/tests/src/com/android/phone/MockitoHelper.java b/tests/src/com/android/phone/MockitoHelper.java
deleted file mode 100644
index 7998030..0000000
--- a/tests/src/com/android/phone/MockitoHelper.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone;
-
-import android.content.Context;
-
-import com.android.services.telephony.Log;
-
-/**
- * Helper for Mockito-based test cases.
- */
-public final class MockitoHelper {
-
- private static final String TAG = "MockitoHelper";
- private static final String DEXCACHE = "dexmaker.dexcache";
-
- private ClassLoader mOriginalClassLoader;
- private Thread mContextThread;
-
- /**
- * Creates a new helper, which in turn will set the context classloader so it can load Mockito
- * resources.
- *
- * @param packageClass test case class
- */
- public void setUp(Context context, Class<?> packageClass) throws Exception {
- // makes a copy of the context classloader
- mContextThread = Thread.currentThread();
- mOriginalClassLoader = mContextThread.getContextClassLoader();
- ClassLoader newClassLoader = packageClass.getClassLoader();
- Log.v(TAG, "Changing context classloader from " + mOriginalClassLoader
- + " to " + newClassLoader);
- mContextThread.setContextClassLoader(newClassLoader);
- String dexCache = context.getCacheDir().toString();
- Log.v(this, "Setting property %s to %s", DEXCACHE, dexCache);
- System.setProperty(DEXCACHE, dexCache);
- }
-
- /**
- * Restores the context classloader to the previous value.
- */
- public void tearDown() throws Exception {
- Log.v(TAG, "Restoring context classloader to " + mOriginalClassLoader);
- mContextThread.setContextClassLoader(mOriginalClassLoader);
- System.clearProperty(DEXCACHE);
- }
-}
\ No newline at end of file
diff --git a/tests/src/com/android/phone/RoamingDialogFragmentTest.java b/tests/src/com/android/phone/RoamingDialogFragmentTest.java
index 96a3fda..62633e0 100644
--- a/tests/src/com/android/phone/RoamingDialogFragmentTest.java
+++ b/tests/src/com/android/phone/RoamingDialogFragmentTest.java
@@ -21,6 +21,7 @@
import android.provider.Settings.SettingNotFoundException;
import android.support.test.espresso.matcher.PreferenceMatchers;
import android.support.test.rule.ActivityTestRule;
+import android.support.test.filters.FlakyTest;
import com.google.common.truth.Truth;
import junit.framework.AssertionFailedError;
import org.junit.Before;
@@ -68,6 +69,7 @@
}
}
+ @FlakyTest
@Test
public void dataRoamingDialogPersistsOnRotation() {
// click on the data roaming preference to trigger warning dialog
@@ -82,6 +84,7 @@
}
+ @FlakyTest
@Test
public void dataRoamingEnabledWhenPositiveButtonClicked() throws SettingNotFoundException {
// click on the data roaming preference to trigger warning dialog
@@ -95,6 +98,7 @@
Global.DATA_ROAMING)).isEqualTo(1);
}
+ @FlakyTest
@Test
public void dialogDismissedOnNegativeButtonClicked() {
// click on the data roaming preference to trigger warning dialog
@@ -107,6 +111,7 @@
onView(withText(R.string.roaming_alert_title)).check(doesNotExist());
}
+ @FlakyTest
@Test
public void dataRoamingStaysDisabledWhenDialogCanceled() throws SettingNotFoundException {
// click on the data roaming preference to trigger warning dialog
diff --git a/tests/src/com/android/phone/common/mail/MailTransportTest.java b/tests/src/com/android/phone/common/mail/MailTransportTest.java
deleted file mode 100644
index 9eaef6b..0000000
--- a/tests/src/com/android/phone/common/mail/MailTransportTest.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.common.mail;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.net.Network;
-import android.test.AndroidTestCase;
-
-import com.android.phone.MockitoHelper;
-import com.android.phone.common.mail.MailTransport.SocketCreator;
-import com.android.phone.common.mail.store.ImapStore;
-import com.android.phone.vvm.omtp.imap.ImapHelper;
-
-import junit.framework.AssertionFailedError;
-
-import org.mockito.MockitoAnnotations;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-
-import javax.net.SocketFactory;
-
-public class MailTransportTest extends AndroidTestCase {
-
- private static final String HOST_ADDRESS = "127.0.0.1";
- private static final String INVALID_HOST_ADDRESS = "255.255.255.255";
- private static final int HOST_PORT = 80;
- private static final int HOST_FLAGS = 0;
- // bypass verifyHostname() in open() by setting ImapStore.FLAG_TRUST_ALL
- private static final int HOST_FLAGS_SSL = ImapStore.FLAG_SSL & ImapStore.FLAG_TRUST_ALL;
- private static final InetAddress VALID_INET_ADDRESS = createInetAddress(HOST_ADDRESS);
- private static final InetAddress INVALID_INET_ADDRESS = createInetAddress(INVALID_HOST_ADDRESS);
-
- // ClassLoader need to be replaced for mockito to work.
- private MockitoHelper mMokitoHelper = new MockitoHelper();
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- mMokitoHelper.setUp(getContext(), getClass());
- MockitoAnnotations.initMocks(this);
- }
-
- @Override
- public void tearDown() throws Exception {
- mMokitoHelper.tearDown();
- super.tearDown();
- }
-
- public void testCreateSocket_anyNetwork() throws MessagingException {
- // With no network, Socket#Socket() should be called.
- MailTransport transport =
- new MailTransport(getContext(), createMockImapHelper(), null, HOST_ADDRESS,
- HOST_PORT, HOST_FLAGS);
- Socket socket = transport.createSocket();
- assertTrue(socket != null);
- }
-
- public void testCreateSocket_networkSpecified() throws MessagingException, IOException {
- // Network#getSocketFactory should be used to create socket.
- Network mockNetwork = createMockNetwork();
- MailTransport transport =
- new MailTransport(getContext(), createMockImapHelper(), mockNetwork, HOST_ADDRESS,
- HOST_PORT, HOST_FLAGS);
- Socket socket = transport.createSocket();
- assertTrue(socket != null);
- verify(mockNetwork).getSocketFactory();
- }
-
- public void testCreateSocket_socketCreator() throws MessagingException, IOException {
- // For testing purposes, how sockets are created can be overridden.
- SocketCreator socketCreator = new SocketCreator() {
-
- private final Socket mSocket = new Socket();
-
- @Override
- public Socket createSocket() {
- return mSocket;
- }
- };
-
- MailTransport transport = new
- MailTransport(getContext(), createMockImapHelper(), null, HOST_ADDRESS, HOST_PORT,
- HOST_FLAGS);
-
- transport.setSocketCreator(socketCreator);
-
- Socket socket = transport.createSocket();
- assertTrue(socket == socketCreator.createSocket());
- }
-
- public void testOpen() throws MessagingException {
- MailTransport transport = new MailTransport(getContext(), createMockImapHelper(), null,
- HOST_ADDRESS,
- HOST_PORT, HOST_FLAGS);
- transport.setSocketCreator(new TestSocketCreator());
- transport.open();
- assertTrue(transport.isOpen());
-
- }
-
- public void testOpen_Ssl() throws MessagingException {
- //opening with ssl support.
- MailTransport transport = new MailTransport(getContext(), createMockImapHelper(), null,
- HOST_ADDRESS, HOST_PORT, HOST_FLAGS_SSL);
- transport.setSocketCreator(new TestSocketCreator());
- transport.open();
- assertTrue(transport.isOpen());
-
- }
-
- public void testOpen_MultiIp() throws MessagingException {
- //In case of round robin DNS, try all resolved address until one succeeded.
- Network network = createMultiIpMockNetwork();
- MailTransport transport = new MailTransport(getContext(), createMockImapHelper(), network,
- HOST_ADDRESS,
- HOST_PORT, HOST_FLAGS);
- transport.setSocketCreator(new TestSocketCreator());
- transport.open();
- assertTrue(transport.isOpen());
- }
-
- public void testOpen_MultiIp_SSL() throws MessagingException {
- Network network = createMultiIpMockNetwork();
-
- MailTransport transport = new MailTransport(getContext(), createMockImapHelper(), network,
- HOST_ADDRESS,
- HOST_PORT, HOST_FLAGS_SSL);
- transport.setSocketCreator(new TestSocketCreator());
- transport.open();
- assertTrue(transport.isOpen());
- }
-
- public void testOpen_network_hostResolutionFailed() {
- // Couldn't resolve host on the network. Open() should fail.
- Network network = createMockNetwork();
- try {
- when(network.getAllByName(HOST_ADDRESS))
- .thenThrow(new UnknownHostException("host resolution failed"));
- } catch (IOException e) {
- //ignored
- }
-
- MailTransport transport = new MailTransport(getContext(), createMockImapHelper(), network,
- HOST_ADDRESS,
- HOST_PORT, HOST_FLAGS);
- try {
- transport.open();
- throw new AssertionFailedError("Should throw MessagingException");
- } catch (MessagingException e) {
- //expected
- }
- assertFalse(transport.isOpen());
- }
-
- public void testOpen_createSocketFailed() {
- // Unable to create socket. Open() should fail.
- MailTransport transport = new MailTransport(getContext(), createMockImapHelper(), null,
- HOST_ADDRESS,
- HOST_PORT, HOST_FLAGS);
- transport.setSocketCreator(new SocketCreator() {
- @Override
- public Socket createSocket() throws MessagingException {
- throw new MessagingException("createSocket failed");
- }
- });
- try {
- transport.open();
- throw new AssertionFailedError("Should throw MessagingException");
- } catch (MessagingException e) {
- //expected
- }
- assertFalse(transport.isOpen());
- }
-
- public void testOpen_network_createSocketFailed() {
- // Unable to create socket. Open() should fail.
-
- Network network = createOneIpMockNetwork();
- SocketFactory mockSocketFactory = mock(SocketFactory.class);
- try {
- when(mockSocketFactory.createSocket())
- .thenThrow(new IOException("unable to create socket"));
- } catch (IOException e) {
- //ignored
- }
- when(network.getSocketFactory()).thenReturn(mockSocketFactory);
-
- MailTransport transport = new MailTransport(getContext(), createMockImapHelper(), network,
- HOST_ADDRESS, HOST_PORT, HOST_FLAGS);
-
- try {
- transport.open();
- throw new AssertionFailedError("Should throw MessagingException");
- } catch (MessagingException e) {
- //expected
- }
- assertFalse(transport.isOpen());
- }
-
- public void testOpen_connectFailed_one() {
- // There is only one IP for this host, and we failed to connect to it. Open() should fail.
-
- MailTransport transport = new MailTransport(getContext(), createMockImapHelper(), null,
- HOST_ADDRESS, HOST_PORT, HOST_FLAGS);
- transport.setSocketCreator(new SocketCreator() {
- @Override
- public Socket createSocket() throws MessagingException {
- return new Socket() {
- @Override
- public void connect(SocketAddress address, int timeout) throws IOException {
- throw new IOException("connect failed");
- }
- };
- }
- });
- try {
- transport.open();
- throw new AssertionFailedError("Should throw MessagingException");
- } catch (MessagingException e) {
- //expected
- }
- assertFalse(transport.isOpen());
- }
-
- public void testOpen_connectFailed_multi() {
- // There are multiple IP for this host, and we failed to connect to any of it.
- // Open() should fail.
- MailTransport transport = new MailTransport(getContext(), createMockImapHelper(),
- createMultiIpMockNetwork(), HOST_ADDRESS, HOST_PORT, HOST_FLAGS);
- transport.setSocketCreator(new SocketCreator() {
- @Override
- public Socket createSocket() throws MessagingException {
- return new Socket() {
- @Override
- public void connect(SocketAddress address, int timeout) throws IOException {
- throw new IOException("connect failed");
- }
- };
- }
- });
- try {
- transport.open();
- throw new AssertionFailedError("Should throw MessagingException");
- } catch (MessagingException e) {
- //expected
- }
- assertFalse(transport.isOpen());
- }
-
- private class TestSocket extends Socket {
-
- boolean mConnected = false;
-
-
- /**
- * A make a mock connection to the address.
- *
- * @param address Only address equivalent to VALID_INET_ADDRESS or INVALID_INET_ADDRESS is
- * accepted
- * @param timeout Ignored but should >= 0.
- */
- @Override
- public void connect(SocketAddress address, int timeout) throws IOException {
- // copied from Socket#connect
- if (isClosed()) {
- throw new SocketException("Socket is closed");
- }
- if (timeout < 0) {
- throw new IllegalArgumentException("timeout < 0");
- }
- if (isConnected()) {
- throw new SocketException("Already connected");
- }
- if (address == null) {
- throw new IllegalArgumentException("remoteAddr == null");
- }
-
- if (!(address instanceof InetSocketAddress)) {
- throw new AssertionError("address should be InetSocketAddress");
- }
-
- InetSocketAddress inetSocketAddress = (InetSocketAddress) address;
- if (inetSocketAddress.getAddress().equals(INVALID_INET_ADDRESS)) {
- throw new IOException("invalid address");
- } else if (inetSocketAddress.getAddress().equals(VALID_INET_ADDRESS)) {
- mConnected = true;
- } else {
- throw new AssertionError("Only INVALID_ADDRESS or VALID_ADDRESS are allowed");
- }
- }
-
- @Override
- public InputStream getInputStream() {
- return null;
- }
-
- @Override
- public OutputStream getOutputStream() {
- return null;
- }
-
- @Override
- public boolean isConnected() {
- return mConnected;
- }
-
- }
-
-
- private class TestSocketCreator implements MailTransport.SocketCreator {
-
- @Override
- public Socket createSocket() throws MessagingException {
- Socket socket = new TestSocket();
- return socket;
- }
-
- }
-
- private ImapHelper createMockImapHelper() {
- return mock(ImapHelper.class);
- }
-
- /**
- * @return a mock Network that can create a TestSocket with {@code getSocketFactory()
- * .createSocket()}
- */
- private Network createMockNetwork() {
- Network network = mock(Network.class);
- SocketFactory mockSocketFactory = mock(SocketFactory.class);
- try {
- when(mockSocketFactory.createSocket()).thenReturn(new TestSocket());
- } catch (IOException e) {
- //ignored
- }
- when(network.getSocketFactory()).thenReturn(mockSocketFactory);
- return network;
- }
-
- /**
- * @return a mock Network like {@link MailTransportTest#createMockNetwork()}, but also supports
- * {@link Network#getAllByName(String)} with one valid result.
- */
- private Network createOneIpMockNetwork() {
- Network network = createMockNetwork();
- try {
- when(network.getAllByName(HOST_ADDRESS))
- .thenReturn(new InetAddress[] {VALID_INET_ADDRESS});
- } catch (UnknownHostException e) {
- //ignored
- }
-
- return network;
- }
-
- /**
- * @return a mock Network like {@link MailTransportTest#createMockNetwork()}, but also supports
- * {@link Network#getAllByName(String)}, which will return 2 address with the first one
- * invalid.
- */
- private Network createMultiIpMockNetwork() {
- Network network = createMockNetwork();
- try {
- when(network.getAllByName(HOST_ADDRESS))
- .thenReturn(new InetAddress[] {INVALID_INET_ADDRESS, VALID_INET_ADDRESS});
- } catch (UnknownHostException e) {
- //ignored
- }
-
- return network;
- }
-
- /**
- * helper method to translate{@code host} into a InetAddress.
- *
- * @param host IP address of the host. Domain name should not be used as this method should not
- * access the internet.
- */
- private static InetAddress createInetAddress(String host) {
- try {
- return InetAddress.getByName(host);
- } catch (UnknownHostException e) {
- return null;
- }
- }
-
-
-}
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
deleted file mode 100644
index 81717a1..0000000
--- a/tests/src/com/android/phone/common/mail/store/imap/DigestMd5UtilsTest.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone.common.mail.store.imap;
-
-import junit.framework.TestCase;
-
-public class DigestMd5UtilsTest extends TestCase {
-
- public void testGetResponse() {
- // Example data from RFC 2831.4
- 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";
- String response = DigestMd5Utils.getResponse(data, false);
- assertEquals("d388dad90d4bbd760a152321f2143af7", response);
- }
-
- public void testGetResponse_ResponseAuth() {
- // Example data from RFC 2831.4
- 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";
- String response = DigestMd5Utils.getResponse(data, true);
- 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");
- }
-}
diff --git a/tests/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelperTest.java b/tests/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelperTest.java
deleted file mode 100644
index bc0192c..0000000
--- a/tests/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelperTest.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-
-package com.android.phone.vvm.omtp;
-
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_CARRIER_VVM_PACKAGE_NAME_STRING;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_DESTINATION_NUMBER_STRING;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_PORT_NUMBER_INT;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_PREFETCH_BOOL;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_SSL_PORT_NUMBER_INT;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_TYPE_STRING;
-
-import android.os.PersistableBundle;
-import android.test.AndroidTestCase;
-
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-public class OmtpVvmCarrierConfigHelperTest extends AndroidTestCase {
-
- private static final String CARRIER_TYPE = "omtp.carrier";
- private static final String CARRIER_PACKAGE_NAME = "omtp.carrier.package";
- private static final boolean CARRIER_CELLULAR_REQUIRED = false;
- private static final boolean CARRIER_PREFETCH = true;
- private static final String CARRIER_DESTINATION_NUMBER = "123";
- private static final int CARRIER_APPLICATION_PORT = 456;
- private static final int DEFAULT_SSL_PORT = 0;
- private static final Set<String> DEFAULT_DISABLED_CAPABILITIES = null;
-
- private static final String TELEPHONY_TYPE = "omtp.telephony";
- private static final String[] TELEPHONY_PACKAGE_NAMES = {"omtp.telephony.package"};
- private static final boolean TELEPHONY_CELLULAR_REQUIRED = true;
- private static final boolean TELEPHONY_PREFETCH = false;
- private static final String TELEPHONY_DESTINATION_NUMBER = "321";
- private static final int TELEPHONY_APPLICATION_PORT = 654;
- private static final int TELEPHONY_SSL_PORT = 997;
- private static final String[] TELEPHONY_DISABLED_CAPABILITIES = {"foo"};
-
- private OmtpVvmCarrierConfigHelper mHelper;
-
- public void testCarrierConfig() {
- mHelper = new OmtpVvmCarrierConfigHelper(getContext(), createCarrierConfig(), null);
- verifyCarrierConfig();
- verifyDefaultExtraConfig();
- }
-
- public void testTelephonyConfig() {
- mHelper = new OmtpVvmCarrierConfigHelper(getContext(), null, createTelephonyConfig());
- verifyTelephonyConfig();
- verifyTelephonyExtraConfig();
- }
-
- public void testMixedConfig() {
- mHelper = new OmtpVvmCarrierConfigHelper(getContext(), createCarrierConfig(),
- createTelephonyConfig());
- verifyCarrierConfig();
- verifyTelephonyExtraConfig();
- }
-
- private PersistableBundle createCarrierConfig() {
- PersistableBundle bundle = new PersistableBundle();
- bundle.putString(KEY_VVM_TYPE_STRING, CARRIER_TYPE);
- bundle.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING,
- CARRIER_PACKAGE_NAME);
- bundle.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL,
- CARRIER_CELLULAR_REQUIRED);
- bundle.putBoolean(KEY_VVM_PREFETCH_BOOL,
- CARRIER_PREFETCH);
- bundle.putString(KEY_VVM_DESTINATION_NUMBER_STRING,
- CARRIER_DESTINATION_NUMBER);
- bundle.putInt(KEY_VVM_PORT_NUMBER_INT, CARRIER_APPLICATION_PORT);
- return bundle;
- }
-
- private void verifyCarrierConfig() {
- assertEquals(CARRIER_TYPE, mHelper.getVvmType());
- assertEquals(new HashSet<>(Arrays.asList(CARRIER_PACKAGE_NAME)),
- mHelper.getCarrierVvmPackageNames());
- assertEquals(CARRIER_CELLULAR_REQUIRED, mHelper.isCellularDataRequired());
- assertEquals(CARRIER_PREFETCH, mHelper.isPrefetchEnabled());
- assertEquals(CARRIER_APPLICATION_PORT, mHelper.getApplicationPort());
- assertEquals(CARRIER_DESTINATION_NUMBER, mHelper.getDestinationNumber());
- }
-
-
- private void verifyDefaultExtraConfig() {
- assertEquals(DEFAULT_SSL_PORT, mHelper.getSslPort());
- assertEquals(DEFAULT_DISABLED_CAPABILITIES, mHelper.getDisabledCapabilities());
- }
-
-
- private PersistableBundle createTelephonyConfig() {
- PersistableBundle bundle = new PersistableBundle();
- bundle.putString(KEY_VVM_TYPE_STRING, TELEPHONY_TYPE);
- bundle.putStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY,
- TELEPHONY_PACKAGE_NAMES);
- bundle.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL,
- TELEPHONY_CELLULAR_REQUIRED);
- bundle.putBoolean(KEY_VVM_PREFETCH_BOOL,
- TELEPHONY_PREFETCH);
- bundle.putString(KEY_VVM_DESTINATION_NUMBER_STRING,
- TELEPHONY_DESTINATION_NUMBER);
- bundle.putInt(KEY_VVM_PORT_NUMBER_INT, TELEPHONY_APPLICATION_PORT);
- bundle.putInt(KEY_VVM_SSL_PORT_NUMBER_INT, TELEPHONY_SSL_PORT);
- bundle.putStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY,
- TELEPHONY_DISABLED_CAPABILITIES);
- return bundle;
- }
-
- private void verifyTelephonyConfig() {
- assertEquals(TELEPHONY_TYPE, mHelper.getVvmType());
- assertEquals(new HashSet<>(Arrays.asList(TELEPHONY_PACKAGE_NAMES)),
- mHelper.getCarrierVvmPackageNames());
- assertEquals(TELEPHONY_CELLULAR_REQUIRED, mHelper.isCellularDataRequired());
- assertEquals(TELEPHONY_PREFETCH, mHelper.isPrefetchEnabled());
- assertEquals(TELEPHONY_APPLICATION_PORT, mHelper.getApplicationPort());
- assertEquals(TELEPHONY_DESTINATION_NUMBER, mHelper.getDestinationNumber());
- }
-
- private void verifyTelephonyExtraConfig() {
- assertEquals(TELEPHONY_SSL_PORT, mHelper.getSslPort());
- assertEquals(new HashSet<>(Arrays.asList(TELEPHONY_DISABLED_CAPABILITIES)),
- mHelper.getDisabledCapabilities());
- }
-}
diff --git a/tests/src/com/android/phone/vvm/omtp/StatusMessageTest.java b/tests/src/com/android/phone/vvm/omtp/StatusMessageTest.java
deleted file mode 100644
index 707463a..0000000
--- a/tests/src/com/android/phone/vvm/omtp/StatusMessageTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp;
-
-import android.os.Bundle;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.phone.vvm.omtp.sms.StatusMessage;
-
-import junit.framework.TestCase;
-
-@VisibleForTesting
-public class StatusMessageTest extends TestCase {
-
- public void testStatusMessage() {
- Bundle bundle = new Bundle();
- bundle.putString(OmtpConstants.PROVISIONING_STATUS, "status");
- bundle.putString(OmtpConstants.RETURN_CODE, "code");
- bundle.putString(OmtpConstants.SUBSCRIPTION_URL, "url");
- bundle.putString(OmtpConstants.SERVER_ADDRESS, "address");
- bundle.putString(OmtpConstants.TUI_ACCESS_NUMBER, "tui");
- bundle.putString(OmtpConstants.CLIENT_SMS_DESTINATION_NUMBER, "sms");
- bundle.putString(OmtpConstants.IMAP_PORT, "1234");
- bundle.putString(OmtpConstants.IMAP_USER_NAME, "username");
- bundle.putString(OmtpConstants.IMAP_PASSWORD, "password");
- bundle.putString(OmtpConstants.SMTP_PORT, "s1234");
- bundle.putString(OmtpConstants.SMTP_USER_NAME, "susername");
- bundle.putString(OmtpConstants.SMTP_PASSWORD, "spassword");
- bundle.putString(OmtpConstants.TUI_PASSWORD_LENGTH, "4-7");
-
- StatusMessage message = new StatusMessage(bundle);
- assertEquals("status", message.getProvisioningStatus());
- assertEquals("code", message.getReturnCode());
- assertEquals("url", message.getSubscriptionUrl());
- assertEquals("address", message.getServerAddress());
- assertEquals("tui", message.getTuiAccessNumber());
- assertEquals("sms", message.getClientSmsDestinationNumber());
- assertEquals("1234", message.getImapPort());
- assertEquals("username", message.getImapUserName());
- assertEquals("password", message.getImapPassword());
- assertEquals("s1234", message.getSmtpPort());
- assertEquals("susername", message.getSmtpUserName());
- assertEquals("spassword", message.getSmtpPassword());
- assertEquals("4-7", message.getTuiPasswordLength());
- }
-
- public void testSyncMessage_EmptyBundle() {
- StatusMessage message = new StatusMessage(new Bundle());
- assertEquals("", message.getProvisioningStatus());
- assertEquals("", message.getReturnCode());
- assertEquals("", message.getSubscriptionUrl());
- assertEquals("", message.getServerAddress());
- assertEquals("", message.getTuiAccessNumber());
- assertEquals("", message.getClientSmsDestinationNumber());
- assertEquals("", message.getImapPort());
- assertEquals("", message.getImapUserName());
- assertEquals("", message.getImapPassword());
- assertEquals("", message.getSmtpPort());
- assertEquals("", message.getSmtpUserName());
- assertEquals("", message.getSmtpPassword());
- assertEquals("", message.getTuiPasswordLength());
- }
-}
diff --git a/tests/src/com/android/phone/vvm/omtp/SyncMessageTest.java b/tests/src/com/android/phone/vvm/omtp/SyncMessageTest.java
deleted file mode 100644
index 61ae400..0000000
--- a/tests/src/com/android/phone/vvm/omtp/SyncMessageTest.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp;
-
-import android.os.Bundle;
-
-import com.android.phone.vvm.omtp.sms.SyncMessage;
-
-import junit.framework.TestCase;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Locale;
-
-public class SyncMessageTest extends TestCase {
-
- public void testSyncMessage() {
- Bundle bundle = new Bundle();
- bundle.putString(OmtpConstants.SYNC_TRIGGER_EVENT, "event");
- bundle.putString(OmtpConstants.MESSAGE_UID, "uid");
- bundle.putString(OmtpConstants.MESSAGE_LENGTH, "1");
- bundle.putString(OmtpConstants.CONTENT_TYPE, "type");
- bundle.putString(OmtpConstants.SENDER, "sender");
- bundle.putString(OmtpConstants.NUM_MESSAGE_COUNT, "2");
- bundle.putString(OmtpConstants.TIME, "29/08/1997 02:14 -0400");
-
- SyncMessage message = new SyncMessage(bundle);
- assertEquals("event", message.getSyncTriggerEvent());
- assertEquals("uid", message.getId());
- assertEquals(1, message.getLength());
- assertEquals("type", message.getContentType());
- assertEquals("sender", message.getSender());
- assertEquals(2, message.getNewMessageCount());
- try {
- assertEquals(new SimpleDateFormat(
- OmtpConstants.DATE_TIME_FORMAT, Locale.US)
- .parse("29/08/1997 02:14 -0400").getTime(), message.getTimestampMillis());
- } catch (ParseException e) {
- throw new AssertionError(e.toString());
- }
- }
-
- public void testSyncMessage_EmptyBundle() {
- SyncMessage message = new SyncMessage(new Bundle());
- assertEquals("", message.getSyncTriggerEvent());
- assertEquals("", message.getId());
- assertEquals(0, message.getLength());
- assertEquals("", message.getContentType());
- assertEquals("", message.getSender());
- assertEquals(0, message.getNewMessageCount());
- assertEquals(0, message.getTimestampMillis());
- }
-}
diff --git a/tests/src/com/android/phone/vvm/omtp/TelephonyVvmConfigManagerTest.java b/tests/src/com/android/phone/vvm/omtp/TelephonyVvmConfigManagerTest.java
deleted file mode 100644
index 8e7a0da..0000000
--- a/tests/src/com/android/phone/vvm/omtp/TelephonyVvmConfigManagerTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp;
-
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_DESTINATION_NUMBER_STRING;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_PORT_NUMBER_INT;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_PREFETCH_BOOL;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_SSL_PORT_NUMBER_INT;
-import static com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper.KEY_VVM_TYPE_STRING;
-
-import android.os.PersistableBundle;
-
-import junit.framework.TestCase;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlPullParserFactory;
-
-import java.io.StringReader;
-import java.util.Arrays;
-
-public class TelephonyVvmConfigManagerTest extends TestCase {
-
- private static final String XML_HEADER = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- + "<list name=\"carrier_config_list\">\n";
- private static final String XML_FOOTER = "</list>";
-
- private static final String CARRIER = " <pbundle_as_map>\n"
- + " <string-array name=\"mccmnc\">\n"
- + " <item value=\"12345\"/>\n"
- + " <item value=\"67890\"/>\n"
- + " </string-array>\n"
- + " <int name=\"vvm_port_number_int\" value=\"54321\"/>\n"
- + " <string name=\"vvm_destination_number_string\">11111</string>\n"
- + " <string-array name=\"carrier_vvm_package_name_string_array\">\n"
- + " <item value=\"com.android.phone\"/>\n"
- + " </string-array>\n"
- + " <string name=\"vvm_type_string\">vvm_type_omtp</string>\n"
- + " <boolean name=\"vvm_cellular_data_required\" value=\"true\"/>\n"
- + " <boolean name=\"vvm_prefetch\" value=\"true\"/>\n"
- + " <int name=\"vvm_ssl_port_number_int\" value=\"997\"/>\n"
- + " <string-array name=\"vvm_disabled_capabilities_string_array\">\n"
- + " <item value =\"foo\"/>\n"
- + " <item value =\"bar\"/>\n"
- + " </string-array>\n"
- + " </pbundle_as_map>\n";
-
- private static final String CARRIER_EMPTY = "<pbundle_as_map></pbundle_as_map>\n";
-
-
- public void testLoadConfigFromXml() {
- TelephonyVvmConfigManager manager = createManager(XML_HEADER + CARRIER + XML_FOOTER);
- verifyCarrier(manager.getConfig("12345"));
- verifyCarrier(manager.getConfig("67890"));
- }
-
- public void testLoadConfigFromXml_Multiple() {
- TelephonyVvmConfigManager manager =
- createManager(XML_HEADER + CARRIER + CARRIER + XML_FOOTER);
- verifyCarrier(manager.getConfig("12345"));
- verifyCarrier(manager.getConfig("67890"));
- }
-
- public void testLoadConfigFromXml_Empty() {
- createManager(XML_HEADER + CARRIER_EMPTY + XML_FOOTER);
- }
-
-
- private void verifyCarrier(PersistableBundle config) {
- assertTrue(Arrays.equals(new String[]{"12345", "67890"},
- config.getStringArray(TelephonyVvmConfigManager.KEY_MCCMNC)));
- assertEquals(54321, config.getInt(KEY_VVM_PORT_NUMBER_INT));
- assertEquals("11111", config.getString(KEY_VVM_DESTINATION_NUMBER_STRING));
- assertTrue(Arrays.equals(new String[]{"com.android.phone"},
- config.getStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY)));
- assertEquals("vvm_type_omtp", config.getString(KEY_VVM_TYPE_STRING));
- assertEquals(true, config.getBoolean(KEY_VVM_PREFETCH_BOOL));
- assertEquals(true, config.getBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL));
- assertEquals(997, config.getInt(KEY_VVM_SSL_PORT_NUMBER_INT));
- assertTrue(Arrays.equals(new String[]{"foo", "bar"},
- config.getStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY)));
- }
-
- private TelephonyVvmConfigManager createManager(String xml) {
- try {
- XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
- parser.setInput(new StringReader(xml));
- return new TelephonyVvmConfigManager(parser);
- } catch (XmlPullParserException e) {
- throw new RuntimeException(e);
- }
- }
-
-}
diff --git a/tests/src/com/android/phone/vvm/omtp/VisualVoicemailPreferencesTest.java b/tests/src/com/android/phone/vvm/omtp/VisualVoicemailPreferencesTest.java
deleted file mode 100644
index 1ae7899..0000000
--- a/tests/src/com/android/phone/vvm/omtp/VisualVoicemailPreferencesTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.android.phone.vvm.omtp;
-
-import android.content.ComponentName;
-import android.telecom.PhoneAccountHandle;
-import android.test.AndroidTestCase;
-import android.util.ArraySet;
-
-import java.util.Arrays;
-
-public class VisualVoicemailPreferencesTest extends AndroidTestCase {
-
- public void testWriteRead() {
- VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(getContext(),
- createFakeHandle("testWriteRead"));
- preferences.edit()
- .putBoolean("boolean", true)
- .putFloat("float", 0.5f)
- .putInt("int", 123)
- .putLong("long", 456)
- .putString("string", "foo")
- .putStringSet("stringset", new ArraySet<>(Arrays.asList("bar", "baz")))
- .apply();
-
- assertTrue(preferences.contains("boolean"));
- assertTrue(preferences.contains("float"));
- assertTrue(preferences.contains("int"));
- assertTrue(preferences.contains("long"));
- assertTrue(preferences.contains("string"));
- assertTrue(preferences.contains("stringset"));
-
- assertEquals(true, preferences.getBoolean("boolean", false));
- assertEquals(0.5f, preferences.getFloat("float", 0));
- assertEquals(123, preferences.getInt("int", 0));
- assertEquals(456, preferences.getLong("long", 0));
- assertEquals("foo", preferences.getString("string", null));
- assertEquals(new ArraySet<>(Arrays.asList("bar", "baz")),
- preferences.getStringSet("stringset", null));
- }
-
- public void testReadDefault() {
- VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(getContext(),
- createFakeHandle("testReadDefault"));
-
- assertFalse(preferences.contains("boolean"));
- assertFalse(preferences.contains("float"));
- assertFalse(preferences.contains("int"));
- assertFalse(preferences.contains("long"));
- assertFalse(preferences.contains("string"));
- assertFalse(preferences.contains("stringset"));
-
- assertEquals(true, preferences.getBoolean("boolean", true));
- assertEquals(2.5f, preferences.getFloat("float", 2.5f));
- assertEquals(321, preferences.getInt("int", 321));
- assertEquals(654, preferences.getLong("long", 654));
- assertEquals("foo2", preferences.getString("string", "foo2"));
- assertEquals(new ArraySet<>(Arrays.asList("bar2", "baz2")),
- preferences.getStringSet(
- "stringset", new ArraySet<>(Arrays.asList("bar2", "baz2"))));
- }
-
- public void testReadDefaultNull() {
- VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(getContext(),
- createFakeHandle("testReadDefaultNull"));
- assertNull(preferences.getString("string", null));
- assertNull(preferences.getStringSet("stringset", null));
- }
-
- public void testDifferentHandle() {
- VisualVoicemailPreferences preferences1 = new VisualVoicemailPreferences(getContext(),
- createFakeHandle("testDifferentHandle1"));
- VisualVoicemailPreferences preferences2 = new VisualVoicemailPreferences(getContext(),
- createFakeHandle("testDifferentHandle1"));
-
- preferences1.edit().putString("string", "foo");
- assertFalse(preferences2.contains("string"));
- }
-
- private PhoneAccountHandle createFakeHandle(String id) {
- return new PhoneAccountHandle(new ComponentName(getContext(), this.getClass()), id);
- }
-}
diff --git a/tests/src/com/android/phone/vvm/omtp/scheduling/BaseTaskTest.java b/tests/src/com/android/phone/vvm/omtp/scheduling/BaseTaskTest.java
deleted file mode 100644
index 27dd87e..0000000
--- a/tests/src/com/android/phone/vvm/omtp/scheduling/BaseTaskTest.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.phone.vvm.omtp.scheduling.Task.TaskId;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class BaseTaskTest extends BaseTaskTestBase {
-
-
- @Test
- public void testBaseTask() {
- DummyBaseTask task = (DummyBaseTask) submitTask(
- BaseTask.createIntent(mTestContext, DummyBaseTask.class, 123));
- assertTrue(task.getId().equals(new TaskId(1, 123)));
- assertTrue(!task.hasStarted());
- assertTrue(!task.hasRun);
- mService.runNextTask();
- assertTrue(task.hasStarted());
- assertTrue(task.hasRun);
- verify(task.policy).onBeforeExecute();
- verify(task.policy).onCompleted();
- }
-
- @Test
- public void testFail() {
- FailingBaseTask task = (FailingBaseTask) submitTask(
- BaseTask.createIntent(mTestContext, FailingBaseTask.class, 0));
- mService.runNextTask();
- verify(task.policy).onFail();
- }
-
- @Test
- public void testDuplicated() {
- DummyBaseTask task1 = (DummyBaseTask) submitTask(
- BaseTask.createIntent(mTestContext, DummyBaseTask.class, 123));
- verify(task1.policy, never()).onDuplicatedTaskAdded();
-
- DummyBaseTask task2 = (DummyBaseTask) submitTask(
- BaseTask.createIntent(mTestContext, DummyBaseTask.class, 123));
- verify(task1.policy).onDuplicatedTaskAdded();
-
- mService.runNextTask();
- assertTrue(task1.hasRun);
- assertTrue(!task2.hasRun);
- }
-
- @Test
- public void testDuplicated_DifferentSubId() {
- DummyBaseTask task1 = (DummyBaseTask) submitTask(
- BaseTask.createIntent(mTestContext, DummyBaseTask.class, 123));
- verify(task1.policy, never()).onDuplicatedTaskAdded();
-
- DummyBaseTask task2 = (DummyBaseTask) submitTask(
- BaseTask.createIntent(mTestContext, DummyBaseTask.class, 456));
- verify(task1.policy, never()).onDuplicatedTaskAdded();
- mService.runNextTask();
- assertTrue(task1.hasRun);
- assertTrue(!task2.hasRun);
-
- mService.runNextTask();
- assertTrue(task2.hasRun);
- }
-
- @Test
- public void testReadyTime() {
- BaseTask task = spy(new DummyBaseTask());
- assertTrue(task.getReadyInMilliSeconds() == 0);
- mTime = 500;
- assertTrue(task.getReadyInMilliSeconds() == -500);
- task.setExecutionTime(1000);
- assertTrue(task.getReadyInMilliSeconds() == 500);
- }
-
- public static class DummyBaseTask extends BaseTask {
-
- public Policy policy;
- public boolean hasRun = false;
-
- public DummyBaseTask() {
- super(1);
- policy = mock(Policy.class);
- addPolicy(policy);
- }
-
- @Override
- public void onExecuteInBackgroundThread() {
- hasRun = true;
- }
- }
-
- public static class FailingBaseTask extends BaseTask {
-
- public Policy policy;
- public FailingBaseTask() {
- super(1);
- policy = mock(Policy.class);
- addPolicy(policy);
- }
-
- @Override
- public void onExecuteInBackgroundThread() {
- fail();
- }
- }
-}
diff --git a/tests/src/com/android/phone/vvm/omtp/scheduling/BaseTaskTestBase.java b/tests/src/com/android/phone/vvm/omtp/scheduling/BaseTaskTestBase.java
deleted file mode 100644
index 1ffd3c4..0000000
--- a/tests/src/com/android/phone/vvm/omtp/scheduling/BaseTaskTestBase.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import com.android.phone.vvm.omtp.scheduling.BaseTask.Clock;
-
-import org.junit.After;
-import org.junit.Before;
-
-public class BaseTaskTestBase extends TaskSchedulerServiceTestBase {
-
- /**
- * "current time" of the deterministic clock.
- */
- public long mTime;
-
- @Before
- public void setUpBaseTaskTest() {
- mTime = 0;
- BaseTask.setClockForTesting(new TestClock());
- }
-
- @After
- public void tearDownBaseTaskTest() {
- BaseTask.setClockForTesting(new Clock());
- }
-
-
- private class TestClock extends Clock {
-
- @Override
- public long getTimeMillis() {
- return mTime;
- }
- }
-}
diff --git a/tests/src/com/android/phone/vvm/omtp/scheduling/PolicyTest.java b/tests/src/com/android/phone/vvm/omtp/scheduling/PolicyTest.java
deleted file mode 100644
index 9761d01..0000000
--- a/tests/src/com/android/phone/vvm/omtp/scheduling/PolicyTest.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import android.support.test.runner.AndroidJUnit4;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class PolicyTest extends BaseTaskTestBase {
-
- private static int sExecuteCounter;
-
- @Before
- public void setUpPolicyTest() {
- sExecuteCounter = 0;
- }
-
- @Test
- public void testPostponePolicy() {
- Task task = submitTask(BaseTask.createIntent(mTestContext, PostponeTask.class, 0));
- mService.runNextTask();
- assertTrue(task.getReadyInMilliSeconds() == 1000);
- submitTask(BaseTask.createIntent(mTestContext, PostponeTask.class, 0));
- assertTrue(task.getReadyInMilliSeconds() == 1000);
- mTime = 500;
- submitTask(BaseTask.createIntent(mTestContext, PostponeTask.class, 0));
- assertTrue(task.getReadyInMilliSeconds() == 1000);
- mTime = 2500;
- mService.runNextTask();
- assertTrue(sExecuteCounter == 1);
- }
-
- @Test
- public void testRetryPolicy() {
- Task task = submitTask(BaseTask.createIntent(mTestContext, FailingRetryTask.class, 0));
- mService.runNextTask();
- // Should queue retry at 1000
- assertTrue(sExecuteCounter == 1);
- mService.runNextTask();
- assertTrue(sExecuteCounter == 1);
- mTime = 1500;
- mService.runNextTask();
- // Should queue retry at 2500
- assertTrue(sExecuteCounter == 2);
- mService.runNextTask();
- assertTrue(sExecuteCounter == 2);
- mTime = 2000;
- mService.runNextTask();
- assertTrue(sExecuteCounter == 2);
- mTime = 3000;
- mService.runNextTask();
- // No more retries are queued.
- assertTrue(sExecuteCounter == 3);
- mService.runNextTask();
- assertTrue(sExecuteCounter == 3);
- mTime = 4500;
- mService.runNextTask();
- assertTrue(sExecuteCounter == 3);
- }
-
- @Test
- public void testMinimalIntervalPolicy() {
- MinimalIntervalPolicyTask task1 = (MinimalIntervalPolicyTask) submitTask(
- BaseTask.createIntent(mTestContext, MinimalIntervalPolicyTask.class, 0));
- mService.runNextTask();
- assertTrue(task1.hasRan);
- MinimalIntervalPolicyTask task2 = (MinimalIntervalPolicyTask) submitTask(
- BaseTask.createIntent(mTestContext, MinimalIntervalPolicyTask.class, 0));
- mService.runNextTask();
- assertTrue(!task2.hasRan);
-
- mTime = 1500;
- mService.runNextTask();
-
- MinimalIntervalPolicyTask task3 = (MinimalIntervalPolicyTask) submitTask(
- BaseTask.createIntent(mTestContext, MinimalIntervalPolicyTask.class, 0));
- mService.runNextTask();
- assertTrue(task3.hasRan);
- }
-
- public abstract static class PolicyTestTask extends BaseTask {
-
- public PolicyTestTask() {
- super(1);
- }
-
- @Override
- public void onExecuteInBackgroundThread() {
- sExecuteCounter++;
- }
- }
-
- public static class PostponeTask extends PolicyTestTask {
-
- PostponeTask() {
- addPolicy(new PostponePolicy(1000));
- }
- }
-
- public static class FailingRetryTask extends PolicyTestTask {
-
- public FailingRetryTask() {
- addPolicy(new RetryPolicy(2, 1000));
- }
-
- @Override
- public void onExecuteInBackgroundThread() {
- super.onExecuteInBackgroundThread();
- fail();
- }
- }
-
- public static class MinimalIntervalPolicyTask extends PolicyTestTask {
-
- boolean hasRan;
-
- MinimalIntervalPolicyTask() {
- addPolicy(new MinimalIntervalPolicy(1000));
- }
-
- @Override
- public void onExecuteInBackgroundThread() {
- super.onExecuteInBackgroundThread();
- hasRan = true;
- }
- }
-
-}
diff --git a/tests/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerServiceTest.java b/tests/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerServiceTest.java
deleted file mode 100644
index 2dd4ecf..0000000
--- a/tests/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerServiceTest.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.phone.vvm.omtp.scheduling.Task.TaskId;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.TimeoutException;
-
-@RunWith(AndroidJUnit4.class)
-public class TaskSchedulerServiceTest extends TaskSchedulerServiceTestBase {
-
- @Test
- public void testTaskIdComparison() {
- TaskId id1 = new TaskId(1, 1);
- TaskId id2 = new TaskId(1, 1);
- TaskId id3 = new TaskId(1, 2);
- assertTrue(id1.equals(id2));
- assertTrue(id1.equals(id1));
- assertTrue(!id1.equals(id3));
- }
-
- @Test
- public void testAddDuplicatedTask() throws TimeoutException {
- TestTask task1 = (TestTask) submitTask(
- TaskSchedulerService.createIntent(mTestContext, TestTask.class));
- TestTask task2 = (TestTask) submitTask(
- TaskSchedulerService.createIntent(mTestContext, TestTask.class));
- assertTrue(task1.onDuplicatedTaskAddedCounter.invokedOnce());
- mService.runNextTask();
- verifyRanOnce(task1);
- verifyNotRan(task2);
- mService.runNextTask();
- verifyRanOnce(task1);
- verifyNotRan(task2);
- }
-
- @Test
- public void testAddDuplicatedTaskAfterFirstCompleted() throws TimeoutException {
- TestTask task1 = (TestTask) submitTask(
- TaskSchedulerService.createIntent(mTestContext, TestTask.class));
- mService.runNextTask();
- verifyRanOnce(task1);
- TestTask task2 = (TestTask) submitTask(
- TaskSchedulerService.createIntent(mTestContext, TestTask.class));
- assertTrue(task1.onDuplicatedTaskAddedCounter.neverInvoked());
- mService.runNextTask();
- verifyRanOnce(task2);
- }
-
- @Test
- public void testAddMultipleTask() {
- TestTask task1 = (TestTask) submitTask(
- putTaskId(TaskSchedulerService.createIntent(mTestContext, TestTask.class),
- new TaskId(1, 0)));
- TestTask task2 = (TestTask) submitTask(
- putTaskId(TaskSchedulerService.createIntent(mTestContext, TestTask.class),
- new TaskId(2, 0)));
- TestTask task3 = (TestTask) submitTask(
- putTaskId(TaskSchedulerService.createIntent(mTestContext, TestTask.class),
- new TaskId(1, 1)));
- assertTrue(task1.onDuplicatedTaskAddedCounter.neverInvoked());
- mService.runNextTask();
- verifyRanOnce(task1);
- verifyNotRan(task2);
- verifyNotRan(task3);
- mService.runNextTask();
- verifyRanOnce(task1);
- verifyRanOnce(task2);
- verifyNotRan(task3);
- mService.runNextTask();
- verifyRanOnce(task1);
- verifyRanOnce(task2);
- verifyRanOnce(task3);
- }
-
- @Test
- public void testNotReady() {
- TestTask task1 = (TestTask) submitTask(
- putTaskId(TaskSchedulerService.createIntent(mTestContext, TestTask.class),
- new TaskId(1, 0)));
- task1.readyInMilliseconds = 1000;
- mService.runNextTask();
- verifyNotRan(task1);
- TestTask task2 = (TestTask) submitTask(
- putTaskId(TaskSchedulerService.createIntent(mTestContext, TestTask.class),
- new TaskId(2, 0)));
- mService.runNextTask();
- verifyNotRan(task1);
- verifyRanOnce(task2);
- task1.readyInMilliseconds = 50;
- mService.runNextTask();
- verifyRanOnce(task1);
- verifyRanOnce(task2);
- }
-
- @Test
- public void testInvalidTaskId() {
- Task task = mock(Task.class);
- when(task.getId()).thenReturn(new TaskId(Task.TASK_INVALID, 0));
- thrown.expect(AssertionError.class);
- mService.addTask(task);
- }
-
- @Test
- public void testDuplicatesAllowedTaskId() {
- TestTask task1 = (TestTask) submitTask(
- putTaskId(TaskSchedulerService.createIntent(mTestContext, TestTask.class),
- new TaskId(Task.TASK_ALLOW_DUPLICATES, 0)));
- TestTask task2 = (TestTask) submitTask(
- putTaskId(TaskSchedulerService.createIntent(mTestContext, TestTask.class),
- new TaskId(Task.TASK_ALLOW_DUPLICATES, 0)));
- assertTrue(task1.onDuplicatedTaskAddedCounter.neverInvoked());
- mService.runNextTask();
- verifyRanOnce(task1);
- verifyNotRan(task2);
- mService.runNextTask();
- verifyRanOnce(task1);
- verifyRanOnce(task2);
- }
-}
diff --git a/tests/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerServiceTestBase.java b/tests/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerServiceTestBase.java
deleted file mode 100644
index 63f5c2f..0000000
--- a/tests/src/com/android/phone/vvm/omtp/scheduling/TaskSchedulerServiceTestBase.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.phone.vvm.omtp.scheduling;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
-import android.os.Message;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ServiceTestRule;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.phone.Assert;
-import com.android.phone.vvm.omtp.scheduling.Task.TaskId;
-import com.android.phone.vvm.omtp.scheduling.TaskSchedulerService.MainThreadHandler;
-import com.android.phone.vvm.omtp.scheduling.TaskSchedulerService.WorkerThreadHandler;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-
-import java.util.concurrent.TimeoutException;
-
-@RunWith(AndroidJUnit4.class)
-public class TaskSchedulerServiceTestBase {
-
- private static final String EXTRA_ID = "test_extra_id";
- private static final String EXTRA_SUB_ID = "test_extra_sub_id";
-
- public TaskSchedulerService mService;
-
- @Rule
- public final ExpectedException thrown = ExpectedException.none();
-
- @Rule
- public final ServiceTestRule mServiceRule = new ServiceTestRule();
-
- public Context mTargetContext;
- public Context mTestContext;
-
- private static boolean sIsMainThread = true;
-
- private final TestMessageSender mMessageSender = new TestMessageSender();
-
- public static Intent putTaskId(Intent intent, TaskId taskId) {
- intent.putExtra(EXTRA_ID, taskId.id);
- intent.putExtra(EXTRA_SUB_ID, taskId.subId);
- return intent;
- }
-
- public static TaskId getTaskId(Intent intent) {
- return new TaskId(intent.getIntExtra(EXTRA_ID, 0), intent.getIntExtra(EXTRA_SUB_ID, 0));
- }
-
- @Before
- public void setUp() throws TimeoutException {
- Assert.setIsMainThreadForTesting(true);
- mTargetContext = InstrumentationRegistry.getTargetContext();
- IBinder binder = null;
- // bindService() might returns null on 2nd invocation because the service is not unbinded
- // yet. See https://code.google.com/p/android/issues/detail?id=180396
- while (binder == null) {
- binder = mServiceRule
- .bindService(new Intent(mTargetContext, TaskSchedulerService.class));
- }
- mService = ((TaskSchedulerService.LocalBinder) binder).getService();
- mTestContext = createTestContext(mTargetContext, mService);
- mService.setMessageSenderForTest(mMessageSender);
- mService.setTaskAutoRunDisabledForTest(true);
- mService.setContextForTest(mTestContext);
- }
-
- @After
- public void tearDown() {
- Assert.setIsMainThreadForTesting(null);
- mService.setTaskAutoRunDisabledForTest(false);
- mService.clearTasksForTest();
- mService.stopSelf();
- }
-
- public Task submitTask(Intent intent) {
- Task task = mService.createTask(intent, 0, 0);
- mService.addTask(task);
- return task;
- }
-
- public static void verifyRanOnce(TestTask task) {
- assertTrue(task.onBeforeExecuteCounter.invokedOnce());
- assertTrue(task.executeCounter.invokedOnce());
- assertTrue(task.onCompletedCounter.invokedOnce());
- }
-
- public static void verifyNotRan(TestTask task) {
- assertTrue(task.onBeforeExecuteCounter.neverInvoked());
- assertTrue(task.executeCounter.neverInvoked());
- assertTrue(task.onCompletedCounter.neverInvoked());
- }
-
- public static class TestTask implements Task {
-
- public int readyInMilliseconds;
-
- private TaskId mId;
-
- public final InvocationCounter onCreateCounter = new InvocationCounter();
- public final InvocationCounter onBeforeExecuteCounter = new InvocationCounter();
- public final InvocationCounter executeCounter = new InvocationCounter();
- public final InvocationCounter onCompletedCounter = new InvocationCounter();
- public final InvocationCounter onDuplicatedTaskAddedCounter = new InvocationCounter();
-
- @Override
- public void onCreate(Context context, Intent intent, int flags, int startId) {
- onCreateCounter.invoke();
- mId = getTaskId(intent);
- }
-
- @Override
- public TaskId getId() {
- return mId;
- }
-
- @Override
- public long getReadyInMilliSeconds() {
- Assert.isMainThread();
- return readyInMilliseconds;
- }
-
- @Override
- public void onBeforeExecute() {
- Assert.isMainThread();
- onBeforeExecuteCounter.invoke();
- }
-
- @Override
- public void onExecuteInBackgroundThread() {
- Assert.isNotMainThread();
- executeCounter.invoke();
- }
-
- @Override
- public void onCompleted() {
- Assert.isMainThread();
- onCompletedCounter.invoke();
- }
-
- @Override
- public void onDuplicatedTaskAdded(Task task) {
- Assert.isMainThread();
- onDuplicatedTaskAddedCounter.invoke();
- }
- }
-
- public static class InvocationCounter {
-
- private int mCounter;
-
- public void invoke() {
- mCounter++;
- }
-
- public boolean invokedOnce() {
- return mCounter == 1;
- }
-
- public boolean neverInvoked() {
- return mCounter == 0;
- }
- }
-
- private class TestMessageSender extends TaskSchedulerService.MessageSender {
-
- @Override
- public void send(Message message) {
- if (message.getTarget() instanceof MainThreadHandler) {
- Assert.setIsMainThreadForTesting(true);
- } else if (message.getTarget() instanceof WorkerThreadHandler) {
- Assert.setIsMainThreadForTesting(false);
- } else {
- throw new AssertionError("unexpected Handler " + message.getTarget());
- }
- message.getTarget().handleMessage(message);
- }
- }
-
- public static void assertTrue(boolean condition) {
- if (!condition) {
- throw new AssertionError();
- }
- }
-
- private static Context createTestContext(Context targetContext, TaskSchedulerService service) {
- TestContext context = mock(TestContext.class);
- when(context.getService()).thenReturn(service);
- when(context.startService(any())).thenCallRealMethod();
- when(context.getPackageName()).thenReturn(targetContext.getPackageName());
- return context;
- }
-
- public abstract class TestContext extends Context {
-
- @Override
- public ComponentName startService(Intent service) {
- getService().onStartCommand(service, 0, 0);
- return null;
- }
-
- public abstract TaskSchedulerService getService();
- }
-}
diff --git a/tests/src/com/android/services/telephony/EmergencyCallStateListenerTest.java b/tests/src/com/android/services/telephony/EmergencyCallStateListenerTest.java
new file mode 100644
index 0000000..a9221e9
--- /dev/null
+++ b/tests/src/com/android/services/telephony/EmergencyCallStateListenerTest.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.services.telephony;
+
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.telephony.ServiceState;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.FlakyTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.TelephonyTestBase;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.ServiceStateTracker;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests the EmergencyCallStateListener, which listens to one Phone and waits until its service
+ * state changes to accepting emergency calls or in service. If it can not find a tower to camp onto
+ * for emergency calls, then it will fail after a timeout period.
+ */
+@RunWith(AndroidJUnit4.class)
+public class EmergencyCallStateListenerTest extends TelephonyTestBase {
+
+ private static final long TIMEOUT_MS = 100;
+
+ @Mock Phone mMockPhone;
+ @Mock ServiceStateTracker mMockServiceStateTracker;
+ @Mock EmergencyCallStateListener.Callback mCallback;
+ EmergencyCallStateListener mListener;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mListener = new EmergencyCallStateListener();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mListener.getHandler().removeCallbacksAndMessages(null);
+ super.tearDown();
+ }
+
+ /**
+ * Ensure that we successfully register for the ServiceState changed messages in Telephony.
+ */
+ @Test
+ @SmallTest
+ public void testRegisterForCallback() {
+ mListener.waitForRadioOn(mMockPhone, mCallback);
+
+ waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
+
+ verify(mMockPhone).unregisterForServiceStateChanged(any(Handler.class));
+ verify(mMockPhone).registerForServiceStateChanged(any(Handler.class),
+ eq(EmergencyCallStateListener.MSG_SERVICE_STATE_CHANGED), isNull());
+ }
+
+ /**
+ * Prerequisites:
+ * - Phone is IN_SERVICE
+ * - Radio is on
+ *
+ * Test: Send SERVICE_STATE_CHANGED message
+ *
+ * Result: callback's onComplete is called with the isRadioReady=true
+ */
+ @Test
+ @SmallTest
+ public void testPhoneChangeState_InService() {
+ ServiceState state = new ServiceState();
+ state.setState(ServiceState.STATE_IN_SERVICE);
+ when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
+ when(mMockPhone.getServiceStateTracker()).thenReturn(mMockServiceStateTracker);
+ when(mMockServiceStateTracker.isRadioOn()).thenReturn(true);
+ mListener.waitForRadioOn(mMockPhone, mCallback);
+ waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
+
+ mListener.getHandler().obtainMessage(EmergencyCallStateListener.MSG_SERVICE_STATE_CHANGED,
+ new AsyncResult(null, state, null)).sendToTarget();
+
+ waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
+ verify(mCallback).onComplete(eq(mListener), eq(true));
+ }
+
+ /**
+ * Prerequisites:
+ * - Phone is OUT_OF_SERVICE (emergency calls only)
+ * - Radio is on
+ *
+ * Test: Send SERVICE_STATE_CHANGED message
+ *
+ * Result: callback's onComplete is called with the isRadioReady=true
+ */
+ @Test
+ @SmallTest
+ public void testPhoneChangeState_EmergencyCalls() {
+ ServiceState state = new ServiceState();
+ state.setState(ServiceState.STATE_OUT_OF_SERVICE);
+ state.setEmergencyOnly(true);
+ when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
+ when(mMockPhone.getServiceState()).thenReturn(state);
+ when(mMockPhone.getServiceStateTracker()).thenReturn(mMockServiceStateTracker);
+ when(mMockServiceStateTracker.isRadioOn()).thenReturn(true);
+ mListener.waitForRadioOn(mMockPhone, mCallback);
+ waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
+
+ mListener.getHandler().obtainMessage(EmergencyCallStateListener.MSG_SERVICE_STATE_CHANGED,
+ new AsyncResult(null, state, null)).sendToTarget();
+
+ waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
+ verify(mCallback).onComplete(eq(mListener), eq(true));
+ }
+
+ /**
+ * Prerequisites:
+ * - Phone is OUT_OF_SERVICE
+ * - Radio is on
+ *
+ * Test: Send SERVICE_STATE_CHANGED message
+ *
+ * Result: callback's onComplete is called with the isRadioReady=true. Even though the radio is
+ * not reporting emergency calls only, we still send onComplete so that the radio can trigger
+ * the emergency call.
+ */
+ @Test
+ @SmallTest
+ public void testPhoneChangeState_OutOfService() {
+ ServiceState state = new ServiceState();
+ state.setState(ServiceState.STATE_OUT_OF_SERVICE);
+ when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
+ when(mMockPhone.getServiceState()).thenReturn(state);
+ when(mMockPhone.getServiceStateTracker()).thenReturn(mMockServiceStateTracker);
+ when(mMockServiceStateTracker.isRadioOn()).thenReturn(true);
+ mListener.waitForRadioOn(mMockPhone, mCallback);
+ waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
+
+ // Still expect an answer because we will be sending the onComplete message as soon as the
+ // radio is confirmed to be on, whether or not it is out of service or not.
+ mListener.getHandler().obtainMessage(EmergencyCallStateListener.MSG_SERVICE_STATE_CHANGED,
+ new AsyncResult(null, state, null)).sendToTarget();
+
+ waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
+ verify(mCallback).onComplete(eq(mListener), eq(true));
+ }
+
+ /**
+ * Prerequisites:
+ * - Phone is OUT_OF_SERVICE (emergency calls only)
+ * - Radio is on
+ *
+ * Test: Wait for retry timer to complete (don't send ServiceState changed message)
+ *
+ * Result: callback's onComplete is called with the isRadioReady=true.
+ */
+ @Test
+ @FlakyTest
+ @SmallTest
+ public void testTimeout_EmergencyCalls() {
+ ServiceState state = new ServiceState();
+ state.setState(ServiceState.STATE_OUT_OF_SERVICE);
+ state.setEmergencyOnly(true);
+ when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
+ when(mMockPhone.getServiceState()).thenReturn(state);
+ when(mMockPhone.getServiceStateTracker()).thenReturn(mMockServiceStateTracker);
+ when(mMockServiceStateTracker.isRadioOn()).thenReturn(true);
+ mListener.setTimeBetweenRetriesMillis(100);
+
+ // Wait for the timer to expire and check state manually in onRetryTimeout
+ mListener.waitForRadioOn(mMockPhone, mCallback);
+ waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, 500);
+
+ verify(mCallback).onComplete(eq(mListener), eq(true));
+ }
+
+ /**
+ * Prerequisites:
+ * - Phone is OUT_OF_SERVICE
+ * - Radio is off
+ *
+ * Test: Wait for retry timer to complete, no ServiceState changed messages received.
+ *
+ * Result:
+ * - callback's onComplete is called with the isRadioReady=false.
+ * - setRadioPower was send twice (tried to turn on the radio)
+ */
+ @Test
+ @FlakyTest
+ @SmallTest
+ public void testTimeout_RetryFailure() {
+ ServiceState state = new ServiceState();
+ state.setState(ServiceState.STATE_POWER_OFF);
+ when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
+ when(mMockPhone.getServiceState()).thenReturn(state);
+ when(mMockPhone.getServiceStateTracker()).thenReturn(mMockServiceStateTracker);
+ when(mMockServiceStateTracker.isRadioOn()).thenReturn(false);
+ mListener.setTimeBetweenRetriesMillis(50);
+ mListener.setMaxNumRetries(2);
+
+ // Wait for the timer to expire and check state manually in onRetryTimeout
+ mListener.waitForRadioOn(mMockPhone, mCallback);
+ waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, 500);
+
+ verify(mCallback).onComplete(eq(mListener), eq(false));
+ verify(mMockPhone, times(2)).setRadioPower(eq(true));
+ }
+
+}
diff --git a/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java b/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
new file mode 100644
index 0000000..3d88af7
--- /dev/null
+++ b/tests/src/com/android/services/telephony/ImsConferenceControllerTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.services.telephony;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.times;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import android.os.Looper;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.telephony.PhoneConstants;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests the functionality in ImsConferenceController.java
+ */
+
+public class ImsConferenceControllerTest {
+
+ @Mock
+ private TelephonyConnectionServiceProxy mMockTelephonyConnectionServiceProxy;
+
+ private TelecomAccountRegistry mTelecomAccountRegistry;
+
+ private MockTelephonyConnection mMockTelephonyConnectionA;
+ private MockTelephonyConnection mMockTelephonyConnectionB;
+
+ private ImsConferenceController mControllerTest;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mTelecomAccountRegistry = TelecomAccountRegistry.getInstance(null);
+ mMockTelephonyConnectionA = new MockTelephonyConnection();
+ mMockTelephonyConnectionB = new MockTelephonyConnection();
+
+ mControllerTest = new ImsConferenceController(mTelecomAccountRegistry,
+ mMockTelephonyConnectionServiceProxy);
+ }
+
+ /**
+ * Behavior: add telephony connections B and A to conference controller,
+ * set status for connections, remove one call
+ * Assumption: after performing the behaviors, the status of Connection A is STATE_ACTIVE;
+ * the status of Connection B is STATE_HOLDING
+ * Expected: Connection A and Connection B are conferenceable with each other;
+ * Connection B is not conferenceable with Connection A after A is removed;
+ * addConference for ImsConference is not called
+ */
+ @Test
+ @SmallTest
+ public void testConferenceable() {
+
+ mControllerTest.add(mMockTelephonyConnectionB);
+ mControllerTest.add(mMockTelephonyConnectionA);
+
+ mMockTelephonyConnectionA.setActive();
+ mMockTelephonyConnectionB.setOnHold();
+
+ assertTrue(mMockTelephonyConnectionA.getConferenceables()
+ .contains(mMockTelephonyConnectionB));
+ assertTrue(mMockTelephonyConnectionB.getConferenceables()
+ .contains(mMockTelephonyConnectionA));
+
+ // verify addConference method is never called
+ verify(mMockTelephonyConnectionServiceProxy, never())
+ .addConference(any(ImsConference.class));
+
+ // call A removed
+ mControllerTest.remove(mMockTelephonyConnectionA);
+ assertFalse(mMockTelephonyConnectionB.getConferenceables()
+ .contains(mMockTelephonyConnectionA));
+ }
+
+ /**
+ * Behavior: add telephony connection B and A to conference controller,
+ * set status for merged connections
+ * Assumption: after performing the behaviors, the status of Connection A is STATE_ACTIVE;
+ * the status of Connection B is STATE_HOLDING;
+ * getPhoneType() in the original connection of the telephony connection
+ * is PhoneConstants.PHONE_TYPE_IMS
+ * Expected: addConference for ImsConference is called twice
+ */
+ @Test
+ @SmallTest
+ public void testMergeMultiPartyCalls() {
+
+ when(mMockTelephonyConnectionA.mMockRadioConnection.getPhoneType())
+ .thenReturn(PhoneConstants.PHONE_TYPE_IMS);
+ when(mMockTelephonyConnectionB.mMockRadioConnection.getPhoneType())
+ .thenReturn(PhoneConstants.PHONE_TYPE_IMS);
+ when(mMockTelephonyConnectionA.mMockRadioConnection.isMultiparty()).thenReturn(true);
+ when(mMockTelephonyConnectionB.mMockRadioConnection.isMultiparty()).thenReturn(true);
+
+ mControllerTest.add(mMockTelephonyConnectionB);
+ mControllerTest.add(mMockTelephonyConnectionA);
+
+ mMockTelephonyConnectionA.setActive();
+ mMockTelephonyConnectionB.setOnHold();
+
+ verify(mMockTelephonyConnectionServiceProxy, times(2))
+ .addConference(any(ImsConference.class));
+
+ }
+}
diff --git a/tests/src/com/android/services/telephony/MockTelephonyConnection.java b/tests/src/com/android/services/telephony/MockTelephonyConnection.java
new file mode 100644
index 0000000..634cbb5
--- /dev/null
+++ b/tests/src/com/android/services/telephony/MockTelephonyConnection.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.services.telephony;
+
+import static org.mockito.Mockito.when;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.Phone;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Mock Telephony Connection used in TelephonyConferenceController.java for testing purpose
+ */
+
+public class MockTelephonyConnection extends TelephonyConnection {
+
+ @Mock
+ com.android.internal.telephony.Connection mMockRadioConnection;
+
+ @Mock
+ Call mMockCall;
+
+ @Mock
+ Phone mMockPhone;
+
+ @Override
+ public com.android.internal.telephony.Connection getOriginalConnection() {
+ return mMockRadioConnection;
+ }
+
+ public MockTelephonyConnection() {
+ super(null, null, false);
+ MockitoAnnotations.initMocks(this);
+
+ // Set up mMockRadioConnection and mMockPhone to contain an active call
+ when(mMockRadioConnection.getState()).thenReturn(Call.State.ACTIVE);
+ when(mMockRadioConnection.getCall()).thenReturn(mMockCall);
+ when(mMockPhone.getRingingCall()).thenReturn(mMockCall);
+ when(mMockCall.getState()).thenReturn(Call.State.ACTIVE);
+ }
+
+ @Override
+ public boolean isConferenceSupported() {
+ return true;
+ }
+
+ @Override
+ public Phone getPhone() {
+ return mMockPhone;
+ }
+
+ public TelephonyConnection cloneConnection() {
+ return this;
+ }
+
+}
diff --git a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java b/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
deleted file mode 100644
index a8142e1..0000000
--- a/tests/src/com/android/services/telephony/RadioOnStateListenerTest.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.services.telephony;
-
-import android.os.AsyncResult;
-import android.os.Handler;
-import android.telephony.ServiceState;
-import android.support.test.runner.AndroidJUnit4;
-
-import com.android.TelephonyTestBase;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.PhoneConstants;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.isNull;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.when;
-
-/**
- * Tests the RadioOnStateListener, which listens to one Phone and waits until its service
- * state changes to accepting emergency calls or in service. If it can not find a tower to camp onto
- * for emergency calls, then it will fail after a timeout period.
- */
-@RunWith(AndroidJUnit4.class)
-public class RadioOnStateListenerTest extends TelephonyTestBase {
-
- private static final long TIMEOUT_MS = 100;
-
- @Mock Phone mMockPhone;
- @Mock RadioOnStateListener.Callback mCallback;
- RadioOnStateListener mListener;
-
- @Before
- public void setUp() throws Exception {
- super.setUp();
- mListener = new RadioOnStateListener();
- }
-
- @After
- public void tearDown() throws Exception {
- mListener.getHandler().removeCallbacksAndMessages(null);
- super.tearDown();
- }
-
- @Test
- public void testRegisterForCallback() {
- mListener.waitForRadioOn(mMockPhone, mCallback);
-
- waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
-
- verify(mMockPhone).unregisterForServiceStateChanged(any(Handler.class));
- verify(mMockPhone).registerForServiceStateChanged(any(Handler.class),
- eq(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED), isNull());
- }
-
- @Test
- public void testPhoneChangeState_InService() {
- ServiceState state = new ServiceState();
- state.setState(ServiceState.STATE_IN_SERVICE);
- when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
- mListener.waitForRadioOn(mMockPhone, mCallback);
- waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
-
- mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
- new AsyncResult(null, state, null)).sendToTarget();
-
- waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
- verify(mCallback).onComplete(eq(mListener), eq(true));
- }
-
- @Test
- public void testPhoneChangeState_EmergencyCalls() {
- ServiceState state = new ServiceState();
- state.setState(ServiceState.STATE_OUT_OF_SERVICE);
- state.setEmergencyOnly(true);
- when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
- when(mMockPhone.getServiceState()).thenReturn(state);
- mListener.waitForRadioOn(mMockPhone, mCallback);
- waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
-
- mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
- new AsyncResult(null, state, null)).sendToTarget();
-
- waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
- verify(mCallback).onComplete(eq(mListener), eq(true));
- }
-
- @Test
- public void testPhoneChangeState_OutOfService() {
- ServiceState state = new ServiceState();
- state.setState(ServiceState.STATE_OUT_OF_SERVICE);
- when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
- when(mMockPhone.getServiceState()).thenReturn(state);
- mListener.waitForRadioOn(mMockPhone, mCallback);
- waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
-
- // Don't expect any answer, since it is not the one that we want and the timeout for giving
- // up hasn't expired yet.
- mListener.getHandler().obtainMessage(RadioOnStateListener.MSG_SERVICE_STATE_CHANGED,
- new AsyncResult(null, state, null)).sendToTarget();
-
- waitForHandlerAction(mListener.getHandler(), TIMEOUT_MS);
- verify(mCallback, never()).onComplete(any(RadioOnStateListener.class), anyBoolean());
- }
-
- @Test
- public void testTimeout_EmergencyCalls() {
- ServiceState state = new ServiceState();
- state.setState(ServiceState.STATE_OUT_OF_SERVICE);
- state.setEmergencyOnly(true);
- when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
- when(mMockPhone.getServiceState()).thenReturn(state);
- mListener.waitForRadioOn(mMockPhone, mCallback);
- mListener.setTimeBetweenRetriesMillis(500);
-
- // Wait for the timer to expire and check state manually in onRetryTimeout
- waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, 600);
-
- verify(mCallback).onComplete(eq(mListener), eq(true));
- }
-
- @Test
- public void testTimeout_RetryFailure() {
- ServiceState state = new ServiceState();
- state.setState(ServiceState.STATE_POWER_OFF);
- when(mMockPhone.getState()).thenReturn(PhoneConstants.State.IDLE);
- when(mMockPhone.getServiceState()).thenReturn(state);
- mListener.waitForRadioOn(mMockPhone, mCallback);
- mListener.setTimeBetweenRetriesMillis(100);
- mListener.setMaxNumRetries(2);
-
- // Wait for the timer to expire and check state manually in onRetryTimeout
- waitForHandlerActionDelayed(mListener.getHandler(), TIMEOUT_MS, 600);
-
- verify(mCallback).onComplete(eq(mListener), eq(false));
- verify(mMockPhone, times(2)).setRadioPower(eq(true));
- }
-
-}
diff --git a/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java b/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java
new file mode 100644
index 0000000..739359a
--- /dev/null
+++ b/tests/src/com/android/services/telephony/TelephonyConferenceControllerTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.services.telephony;
+
+import android.os.Looper;
+import android.telecom.Conference;
+import android.telecom.Connection;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.mockito.ArgumentCaptor;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.any;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Tests the functionality in TelephonyConferenceController.java
+ * Assumption: these tests are based on setting status manually
+ */
+
+public class TelephonyConferenceControllerTest {
+
+ @Mock
+ private TelephonyConnectionServiceProxy mMockTelephonyConnectionServiceProxy;
+
+ @Mock
+ private Conference.Listener mMockListener;
+
+ private MockTelephonyConnection mMockTelephonyConnectionA;
+ private MockTelephonyConnection mMockTelephonyConnectionB;
+
+ private TelephonyConferenceController mControllerTest;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mMockTelephonyConnectionA = new MockTelephonyConnection();
+ mMockTelephonyConnectionB = new MockTelephonyConnection();
+
+ mControllerTest = new TelephonyConferenceController(mMockTelephonyConnectionServiceProxy);
+ }
+
+ /**
+ * Behavior: add telephony connections B and A to conference controller,
+ * set status for connections and calls, remove one call
+ * Assumption: after performing the behaviours, the status of Connection A is STATE_ACTIVE;
+ * the status of Connection B is STATE_HOLDING;
+ * the call in the original connection is Call.State.ACTIVE;
+ * isMultiparty of the call is false;
+ * isConferenceSupported of the connection is True
+ * Expected: Connection A and Connection B are conferenceable with each other
+ */
+ @Test
+ @SmallTest
+ public void testConferenceable() {
+
+ when(mMockTelephonyConnectionA.mMockRadioConnection.getCall()
+ .isMultiparty()).thenReturn(false);
+ when(mMockTelephonyConnectionB.mMockRadioConnection.getCall()
+ .isMultiparty()).thenReturn(false);
+
+ // add telephony connection B
+ mControllerTest.add(mMockTelephonyConnectionB);
+
+ // add telephony connection A
+ mControllerTest.add(mMockTelephonyConnectionA);
+
+ mMockTelephonyConnectionA.setActive();
+ mMockTelephonyConnectionB.setOnHold();
+
+ assertTrue(mMockTelephonyConnectionA.getConferenceables()
+ .contains(mMockTelephonyConnectionB));
+ assertTrue(mMockTelephonyConnectionB.getConferenceables()
+ .contains(mMockTelephonyConnectionA));
+
+ // verify addConference method is never called
+ verify(mMockTelephonyConnectionServiceProxy, never())
+ .addConference(any(TelephonyConference.class));
+
+ // call A removed
+ mControllerTest.remove(mMockTelephonyConnectionA);
+ assertFalse(mMockTelephonyConnectionB.getConferenceables()
+ .contains(mMockTelephonyConnectionA));
+ }
+
+ /**
+ * Behavior: add telephony connection B and A to conference controller,
+ * set status for connections and merged calls, remove one call
+ * Assumption: after performing the behaviours, the status of Connection A is STATE_ACTIVE;
+ * the status of Connection B is STATE_HOLDING;
+ * the call in the original connection is Call.State.ACTIVE;
+ * isMultiparty of the call is True;
+ * isConferenceSupported of the connection is True
+ * Expected: Connection A and Connection B are conferenceable with each other
+ * addConference is called
+ */
+ @Test
+ @SmallTest
+ public void testMergeMultiPartyCalls() {
+
+ // set isMultiparty() true to create the same senario of merge behaviour
+ when(mMockTelephonyConnectionA.mMockRadioConnection.getCall()
+ .isMultiparty()).thenReturn(true);
+ when(mMockTelephonyConnectionB.mMockRadioConnection.getCall()
+ .isMultiparty()).thenReturn(true);
+
+ // Add connections into connection Service
+ Collection<Connection> allConnections = new ArrayList<Connection>();
+ allConnections.add(mMockTelephonyConnectionA);
+ allConnections.add(mMockTelephonyConnectionB);
+ when(mMockTelephonyConnectionServiceProxy.getAllConnections())
+ .thenReturn(allConnections);
+
+ // add telephony connection B
+ mControllerTest.add(mMockTelephonyConnectionB);
+
+ // add telephony connection A
+ mControllerTest.add(mMockTelephonyConnectionA);
+
+ mMockTelephonyConnectionA.setActive();
+ mMockTelephonyConnectionB.setOnHold();
+
+ assertTrue(mMockTelephonyConnectionA.getConferenceables()
+ .contains(mMockTelephonyConnectionB));
+ assertTrue(mMockTelephonyConnectionB.getConferenceables()
+ .contains(mMockTelephonyConnectionA));
+
+ // capture the argument in the addConference method, and verify it is called
+ ArgumentCaptor<TelephonyConference> argumentCaptor = ArgumentCaptor.
+ forClass(TelephonyConference.class);
+ verify(mMockTelephonyConnectionServiceProxy).addConference(argumentCaptor.capture());
+
+ // add a listener to the added conference
+ argumentCaptor.getValue().addListener(mMockListener);
+
+ verify(mMockListener, never()).onDestroyed(any(Conference.class));
+
+ // call A removed
+ mControllerTest.remove(mMockTelephonyConnectionA);
+ assertFalse(mMockTelephonyConnectionB.getConferenceables()
+ .contains(mMockTelephonyConnectionA));
+
+ //onDestroy should be called during the destroy
+ verify(mMockListener).onDestroyed(any(Conference.class));
+ }
+}
diff --git a/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
new file mode 100644
index 0000000..45f74df
--- /dev/null
+++ b/tests/src/com/android/services/telephony/TelephonyConnectionServiceTest.java
@@ -0,0 +1,527 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.services.telephony;
+
+import android.telephony.RadioAccessFamily;
+import android.telephony.ServiceState;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.TelephonyManager;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.TelephonyTestBase;
+import com.android.internal.telephony.Phone;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Unit tests for TelephonyConnectionService.
+ */
+
+@RunWith(AndroidJUnit4.class)
+public class TelephonyConnectionServiceTest extends TelephonyTestBase {
+
+ private static final int SLOT_0_PHONE_ID = 0;
+ private static final int SLOT_1_PHONE_ID = 1;
+
+ @Mock TelephonyConnectionService.TelephonyManagerProxy mTelephonyManagerProxy;
+ @Mock TelephonyConnectionService.SubscriptionManagerProxy mSubscriptionManagerProxy;
+ @Mock TelephonyConnectionService.PhoneFactoryProxy mPhoneFactoryProxy;
+
+ TelephonyConnectionService mTestConnectionService;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mTestConnectionService = new TelephonyConnectionService();
+ mTestConnectionService.setPhoneFactoryProxy(mPhoneFactoryProxy);
+ mTestConnectionService.setTelephonyManagerProxy(mTelephonyManagerProxy);
+ mTestConnectionService.setSubscriptionManagerProxy(mSubscriptionManagerProxy);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mTestConnectionService = null;
+ super.tearDown();
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Users default Voice SIM choice is IN_SERVICE
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the default Voice SIM choice.
+ */
+ @Test
+ @SmallTest
+ public void testDefaultVoiceSimInService() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_IN_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ true /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot0Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Slot 0 is OUT_OF_SERVICE, Slot 1 is OUT_OF_SERVICE (emergency calls only)
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone
+ */
+ @Test
+ @SmallTest
+ public void testSlot1EmergencyOnly() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ true /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot1Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Slot 0 is OUT_OF_SERVICE, Slot 1 is IN_SERVICE
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone
+ */
+ @Test
+ @SmallTest
+ public void testSlot1InService() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_IN_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot1Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Slot 0 is PUK locked, Slot 1 is ready
+ * - Slot 0 is LTE capable, Slot 1 is GSM capable
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone. Although Slot 0 is more
+ * capable, it is locked, so use the other slot.
+ */
+ @Test
+ @SmallTest
+ public void testSlot0PukLocked() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ // Set Slot 0 to be PUK locked
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ // Make Slot 0 higher capability
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot1Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Slot 0 is PIN locked, Slot 1 is ready
+ * - Slot 0 is LTE capable, Slot 1 is GSM capable
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone. Although Slot 0 is more
+ * capable, it is locked, so use the other slot.
+ */
+ @Test
+ @SmallTest
+ public void testSlot0PinLocked() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ // Set Slot 0 to be PUK locked
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PIN_REQUIRED);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ // Make Slot 0 higher capability
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot1Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Slot 1 is PUK locked, Slot 0 is ready
+ * - Slot 1 is LTE capable, Slot 0 is GSM capable
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone. Although Slot 1 is more
+ * capable, it is locked, so use the other slot.
+ */
+ @Test
+ @SmallTest
+ public void testSlot1PukLocked() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ // Set Slot 1 to be PUK locked
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
+ // Make Slot 1 higher capability
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot0Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Slot 1 is PIN locked, Slot 0 is ready
+ * - Slot 1 is LTE capable, Slot 0 is GSM capable
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone. Although Slot 1 is more
+ * capable, it is locked, so use the other slot.
+ */
+ @Test
+ @SmallTest
+ public void testSlot1PinLocked() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ // Set Slot 1 to be PUK locked
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PIN_REQUIRED);
+ // Make Slot 1 higher capability
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot0Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Slot 1 is LTE capable, Slot 0 is GSM capable
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is more capable
+ */
+ @Test
+ @SmallTest
+ public void testSlot1HigherCapablity() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ // Make Slot 1 higher capability
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot1Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Slot 1 is GSM/LTE capable, Slot 0 is GSM capable
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it has more
+ * capabilities.
+ */
+ @Test
+ @SmallTest
+ public void testSlot1MoreCapabilities() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ // Make Slot 1 more capable
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
+ setPhoneRadioAccessFamily(slot1Phone,
+ RadioAccessFamily.RAF_GSM | RadioAccessFamily.RAF_LTE);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot1Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Both SIMs PUK Locked
+ * - Slot 0 is LTE capable, Slot 1 is GSM capable
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is more capable,
+ * ignoring that both SIMs are PUK locked.
+ */
+ @Test
+ @SmallTest
+ public void testSlot0MoreCapableBothPukLocked() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_PUK_REQUIRED);
+ // Make Slot 0 higher capability
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_GSM);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot0Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, two slots with SIMs inserted
+ * - Both SIMs have the same capability
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is the first slot.
+ */
+ @Test
+ @SmallTest
+ public void testEqualCapabilityTwoSimsInserted() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ // Make Capability the same
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
+ // Two SIMs inserted
+ setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
+ setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot0Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, only slot 0 inserted
+ * - Both SIMs have the same capability
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone because it is the only one
+ * with a SIM inserted
+ */
+ @Test
+ @SmallTest
+ public void testEqualCapabilitySim0Inserted() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
+ // Make Capability the same
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
+ // Slot 0 has SIM inserted.
+ setSlotHasIccCard(SLOT_0_PHONE_ID, true /*isInserted*/);
+ setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot0Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, only slot 1 inserted
+ * - Both SIMs have the same capability
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone because it is the only one
+ * with a SIM inserted
+ */
+ @Test
+ @SmallTest
+ public void testEqualCapabilitySim1Inserted() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_READY);
+ // Make Capability the same
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_LTE);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
+ // Slot 1 has SIM inserted.
+ setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
+ setSlotHasIccCard(SLOT_1_PHONE_ID, true /*isInserted*/);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot1Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, no SIMs inserted
+ * - SIM 1 has the higher capability
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 1 phone, since it is a higher
+ * capability
+ */
+ @Test
+ @SmallTest
+ public void testSim1HigherCapabilityNoSimsInserted() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
+ // Make Capability the same
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_GSM);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_LTE);
+ // No SIMs inserted
+ setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
+ setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot1Phone, resultPhone);
+ }
+
+ /**
+ * Prerequisites:
+ * - MSIM Device, no SIMs inserted
+ * - Both SIMs have the same capability (Unknown)
+ *
+ * Result: getFirstPhoneForEmergencyCall returns the slot 0 phone, since it is the first slot.
+ */
+ @Test
+ @SmallTest
+ public void testEqualCapabilityNoSimsInserted() {
+ Phone slot0Phone = makeTestPhone(SLOT_0_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ Phone slot1Phone = makeTestPhone(SLOT_1_PHONE_ID, ServiceState.STATE_OUT_OF_SERVICE,
+ false /*isEmergencyOnly*/);
+ setDefaultPhone(slot0Phone);
+ setupDeviceConfig(slot0Phone, slot1Phone, SLOT_0_PHONE_ID);
+ setPhoneSlotState(SLOT_0_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
+ setPhoneSlotState(SLOT_1_PHONE_ID, TelephonyManager.SIM_STATE_ABSENT);
+ // Make Capability the same
+ setPhoneRadioAccessFamily(slot0Phone, RadioAccessFamily.RAF_UNKNOWN);
+ setPhoneRadioAccessFamily(slot1Phone, RadioAccessFamily.RAF_UNKNOWN);
+ // No SIMs inserted
+ setSlotHasIccCard(SLOT_0_PHONE_ID, false /*isInserted*/);
+ setSlotHasIccCard(SLOT_1_PHONE_ID, false /*isInserted*/);
+
+ Phone resultPhone = mTestConnectionService.getFirstPhoneForEmergencyCall();
+
+ assertEquals(slot0Phone, resultPhone);
+ }
+
+ private Phone makeTestPhone(int phoneId, int serviceState, boolean isEmergencyOnly) {
+ Phone phone = mock(Phone.class);
+ ServiceState testServiceState = new ServiceState();
+ testServiceState.setState(serviceState);
+ testServiceState.setEmergencyOnly(isEmergencyOnly);
+ when(phone.getServiceState()).thenReturn(testServiceState);
+ when(phone.getPhoneId()).thenReturn(phoneId);
+ return phone;
+ }
+
+ // Setup 2 SIM device
+ private void setupDeviceConfig(Phone slot0Phone, Phone slot1Phone, int defaultVoicePhoneId) {
+ when(mTelephonyManagerProxy.getPhoneCount()).thenReturn(2);
+ when(mSubscriptionManagerProxy.getDefaultVoicePhoneId()).thenReturn(defaultVoicePhoneId);
+ when(mPhoneFactoryProxy.getPhone(eq(SLOT_0_PHONE_ID))).thenReturn(slot0Phone);
+ when(mPhoneFactoryProxy.getPhone(eq(SLOT_1_PHONE_ID))).thenReturn(slot1Phone);
+ }
+
+ private void setPhoneRadioAccessFamily(Phone phone, int radioAccessFamily) {
+ when(phone.getRadioAccessFamily()).thenReturn(radioAccessFamily);
+ }
+
+ private void setPhoneSlotState(int slotId, int slotState) {
+ when(mSubscriptionManagerProxy.getSimStateForSlotIdx(slotId)).thenReturn(slotState);
+ }
+
+ private void setSlotHasIccCard(int slotId, boolean isInserted) {
+ when(mTelephonyManagerProxy.hasIccCard(slotId)).thenReturn(isInserted);
+ }
+
+ private void setDefaultPhone(Phone phone) {
+ when(mPhoneFactoryProxy.getDefaultPhone()).thenReturn(phone);
+ }
+}