Merge "Add extra USSD code logging." into oc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9e39d30..c2b9800 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -76,6 +76,7 @@
     <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" />
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 6a0299f..cbd7a05 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -154,7 +154,7 @@
     <string name="vm_change_pin_progress_message" msgid="3977357361934350336">"Itxaron, mesedez."</string>
     <string name="vm_change_pin_error_too_short" msgid="5974971097302710497">"Laburregia da PIN kode berria."</string>
     <string name="vm_change_pin_error_too_long" msgid="8476870806115051865">"Luzeegia da PIN kode berria."</string>
-    <string name="vm_change_pin_error_too_weak" msgid="7883744811891784882">"Ahulegia da PIN kode berria. Pasahitza segurua izan dadin, ez du izan behar zenbaki-segidarik edo errepikatutako zenbakirik."</string>
+    <string name="vm_change_pin_error_too_weak" msgid="7883744811891784882">"Ez da batere segurua PIN kode berria. Pasahitza segurua izan dadin, ez du izan behar zenbaki-segidarik edo errepikatutako zenbakirik."</string>
     <string name="vm_change_pin_error_mismatch" msgid="2754685537970757317">"PIN kode zaharra ez dator bat."</string>
     <string name="vm_change_pin_error_invalid" msgid="3972205462701668653">"Balio ez duten karaktereak ditu PIN kode berriak."</string>
     <string name="vm_change_pin_error_system_error" msgid="6610603326230000207">"Ezin da aldatu PIN kodea"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index ab913b4..363be54 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -527,7 +527,7 @@
     <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>
-    <string name="phone_in_ecm_notification_complete_time" msgid="7730376844178948351">"មិន​មាន​ការតភ្ជាប់​ទិន្នន័យ រហូតដល់ <xliff:g id="COMPLETETIME">%s</xliff:g>"</string>
+    <string name="phone_in_ecm_notification_complete_time" msgid="7730376844178948351">"មិន​មាន​ការតភ្ជាប់​ទិន្នន័យ រហូតដល់ម៉ោង <xliff:g id="COMPLETETIME">%s</xliff:g>"</string>
     <plurals name="alert_dialog_exit_ecm" formatted="false" msgid="7179911675595441201">
       <item quantity="other">ទូរស័ព្ទនេះនឹងស្ថិតក្នុងរបៀប ហៅត្រលប់ពេលអាសន្ន រយៈពេល <xliff:g id="COUNT_1">%s</xliff:g> នាទី។ ខណៈពេលស្ថិតក្នុងរបៀបនេះ មិនមានកម្មវិធីដែលប្រើការភ្ជាប់ទិន្នន័យណា អាចប្រើបានបានឡើយ។ តើអ្នកចង់ចាកចេញឥឡូវនេះទេ?</item>
       <item quantity="one">ទូរស័ព្ទនេះនឹងស្ថិតក្នុងរបៀប ហៅត្រលប់ពេលអាសន្ន រយៈពេល <xliff:g id="COUNT_0">%s</xliff:g> នាទី។ ខណៈពេលស្ថិតក្នុងរបៀបនេះ មិនមានកម្មវិធីដែលប្រើការភ្ជាប់ទិន្នន័យណា អាចប្រើបានបានឡើយ។ តើអ្នកចង់ចាកចេញឥឡូវនេះទេ?</item>
diff --git a/res/values-mcc262-mnc01/strings.xml b/res/values-mcc262-mnc01/strings.xml
index 85c4333..0765a73 100644
--- a/res/values-mcc262-mnc01/strings.xml
+++ b/res/values-mcc262-mnc01/strings.xml
@@ -17,7 +17,7 @@
 <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>
+    <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>
+    <string name="status_hint_label_wifi_call">WLAN Call</string>
 </resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 76c81b1..d42144e 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -529,12 +529,12 @@
     <string name="phone_in_ecm_call_notification_text" msgid="4611608947314729773">"Ligação de dados desativada"</string>
     <string name="phone_in_ecm_notification_complete_time" msgid="7730376844178948351">"Sem ligação de dados até à(s) <xliff:g id="COMPLETETIME">%s</xliff:g>"</string>
     <plurals name="alert_dialog_exit_ecm" formatted="false" msgid="7179911675595441201">
+      <item quantity="one">The phone will be in Emergency Callback mode for <xliff:g id="COUNT_1">%s</xliff:g> minutes. While in this mode no applications using a data connection can be used. Do you want to exit now?</item>
       <item quantity="other">O telemóvel fica no modo de Chamada de emergência durante <xliff:g id="COUNT_1">%s</xliff:g> minutos. Neste modo, não é possível utilizar aplicações com uma ligação de dados. Pretende sair agora?</item>
-      <item quantity="one">O telemóvel fica no modo de Chamada de emergência durante <xliff:g id="COUNT_0">%s</xliff:g> minuto. Neste modo, não é possível utilizar aplicações com uma ligação de dados. Pretende sair agora?</item>
     </plurals>
     <plurals name="alert_dialog_not_avaialble_in_ecm" formatted="false" msgid="8042973425225093895">
+      <item quantity="one">The selected action isn\'t available while in the Emergency Callback mode. The phone will be in this mode for <xliff:g id="COUNT_1">%s</xliff:g> minutes. Do you want to exit now?</item>
       <item quantity="other">A ação selecionada não está disponível no modo de Chamada de emergência. O telemóvel fica neste modo durante <xliff:g id="COUNT_1">%s</xliff:g> minutos. Pretende sair agora?</item>
-      <item quantity="one">A ação selecionada não está disponível no modo de Chamada de emergência. O telemóvel fica neste modo durante <xliff:g id="COUNT_0">%s</xliff:g> minuto. Pretende sair agora?</item>
     </plurals>
     <string name="alert_dialog_in_ecm_call" msgid="1886723687211887104">"A ação selecionada não está disponível durante uma chamada de emergência."</string>
     <string name="progress_dialog_exiting_ecm" msgid="4835734101617817074">"A sair do modo de chamada de retorno de emergência"</string>
diff --git a/src/com/android/phone/PhoneGlobals.java b/src/com/android/phone/PhoneGlobals.java
index 39937eb..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;
 
 /**
@@ -145,6 +146,8 @@
     private Activity mPUKEntryActivity;
     private ProgressDialog mPUKEntryProgressDialog;
 
+    private boolean mDataDisconnectedDueToRoaming = false;
+
     private WakeState mWakeState = WakeState.SLEEP;
 
     private PowerManager mPowerManager;
@@ -157,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) {
@@ -333,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);
 
@@ -671,16 +679,21 @@
                 // The "data disconnected due to roaming" notification is shown
                 // if (a) you have the "data roaming" feature turned off, and
                 // (b) you just lost data connectivity because you're roaming.
-                if (PhoneConstants.DataState.DISCONNECTED.name().equals(state)
+                // (c) if we haven't shown the notification for this disconnection earlier.
+                if (!mDataDisconnectedDueToRoaming
+                        && PhoneConstants.DataState.DISCONNECTED.name().equals(state)
                         && Phone.REASON_ROAMING_ON.equals(reason)
                         && !phone.getDataRoamingEnabled()) {
                     // Notify the user that data call is disconnected due to roaming. Note that
                     // calling this multiple times will not cause multiple notifications.
                     mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_DISCONNECTED);
-                } else if (PhoneConstants.DataState.CONNECTED.name().equals(state)) {
+                    mDataDisconnectedDueToRoaming = true;
+                } else if (mDataDisconnectedDueToRoaming
+                        && PhoneConstants.DataState.CONNECTED.name().equals(state)) {
                     // Cancel the notification when data is available. Note it is okay to call this
                     // even if the notification doesn't exist.
                     mHandler.sendEmptyMessage(EVENT_DATA_ROAMING_OK);
+                    mDataDisconnectedDueToRoaming = false;
                 }
             } else if ((action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) &&
                     (mPUKEntryActivity != null)) {
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;
+    }
+}