Add simulator to manually override voicemail carrier configs

This allow new carriers to test their values or help debug/QA for situations like disabling prefetch.

Bug: 63013427
Test: N/A use at your own risk.
PiperOrigin-RevId: 162003756
Change-Id: Ifb227163bc3f2a94c1c07cc60fdc3a031fd625c8
diff --git a/Android.mk b/Android.mk
index efbdb09..b779a6a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -118,6 +118,7 @@
 	$(BASE_DIR)/incallui/telecomeventui/res \
 	$(BASE_DIR)/incallui/video/impl/res \
 	$(BASE_DIR)/incallui/video/protocol/res \
+	$(BASE_DIR)/voicemail/impl/configui/res \
 	$(BASE_DIR)/voicemail/impl/res \
 
 
@@ -178,6 +179,7 @@
 	$(BASE_DIR)/incallui/video/impl/AndroidManifest.xml \
 	$(BASE_DIR)/incallui/video/protocol/AndroidManifest.xml \
 	$(BASE_DIR)/voicemail/AndroidManifest.xml \
+	$(BASE_DIR)/voicemail/impl/configui/AndroidManifest.xml \
 	$(BASE_DIR)/voicemail/impl/AndroidManifest.xml \
 
 
@@ -257,6 +259,7 @@
 	--extra-packages com.android.incallui.video.impl \
 	--extra-packages com.android.phone.common \
 	--extra-packages com.android.voicemail \
+	--extra-packages com.android.voicemail.impl.configui \
 	--extra-packages com.android.voicemail.impl \
 	--extra-packages com.android.voicemail.impl.fetch \
 	--extra-packages com.android.voicemail.impl.settings \
diff --git a/java/com/android/voicemail/AndroidManifest.xml b/java/com/android/voicemail/AndroidManifest.xml
index aedfd6f..35beaf3 100644
--- a/java/com/android/voicemail/AndroidManifest.xml
+++ b/java/com/android/voicemail/AndroidManifest.xml
@@ -14,7 +14,7 @@
   ~ limitations under the License
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-  package="com.android.voicemailomtp">
+  package="com.android.voicemail">
 
   <uses-sdk
     android:minSdkVersion="23"
@@ -32,5 +32,14 @@
   <uses-permission android:name="android.permission.INTERNET"/>
   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
 
-  <application/>
+  <application>
+    <receiver
+        android:name=".VoicemailSecretCodeReceiver"
+        android:exported="true">
+      <intent-filter>
+        <action android:name="android.provider.Telephony.SECRET_CODE" />
+        <data android:scheme="android_secret_code" />
+      </intent-filter>
+    </receiver>
+  </application>
 </manifest>
diff --git a/java/com/android/voicemail/VoicemailClient.java b/java/com/android/voicemail/VoicemailClient.java
index 97b824b..847919a 100644
--- a/java/com/android/voicemail/VoicemailClient.java
+++ b/java/com/android/voicemail/VoicemailClient.java
@@ -18,7 +18,10 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.os.PersistableBundle;
 import android.provider.VoicemailContract.Voicemails;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.TelephonyManager;
@@ -52,6 +55,12 @@
       "com.android.voicemail.VoicemailClient.ACTION_SHOW_LEGACY_VOICEMAIL";
 
   /**
+   * Secret code to launch the voicemail config activity intended for OEMs and Carriers. {@code
+   * *#*#VVMCONFIG#*#*}
+   */
+  String VOICEMAIL_SECRET_CODE = "886266344";
+
+  /**
    * Whether the visual voicemail service is enabled for the {@code phoneAccountHandle}. "Enable"
    * means the user "wants" to have this service on, and does not mean the service is actually
    * functional(For example, the service is blocked on the carrier side. The service will be
@@ -122,4 +131,15 @@
    * provisioning. Being "activated" means all setup are completed, and VVM is expected to work.
    */
   boolean isActivated(Context context, PhoneAccountHandle phoneAccountHandle);
+
+  /**
+   * Called when {@link #VOICEMAIL_SECRET_CODE} is dialed. {@code context} will be a broadcast
+   * receiver context.
+   */
+  @MainThread
+  void showConfigUi(@NonNull Context context);
+
+  @NonNull
+  PersistableBundle getConfig(
+      @NonNull Context context, @Nullable PhoneAccountHandle phoneAccountHandle);
 }
diff --git a/java/com/android/voicemail/VoicemailSecretCodeReceiver.java b/java/com/android/voicemail/VoicemailSecretCodeReceiver.java
new file mode 100644
index 0000000..6d14241
--- /dev/null
+++ b/java/com/android/voicemail/VoicemailSecretCodeReceiver.java
@@ -0,0 +1,36 @@
+/*
+ * 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.voicemail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import com.android.dialer.common.LogUtil;
+
+/** Receives android.provider.Telephony.SECRET_CODE */
+public class VoicemailSecretCodeReceiver extends BroadcastReceiver {
+
+  @Override
+  public void onReceive(Context context, Intent intent) {
+    String host = intent.getData().getHost();
+    if (!VoicemailClient.VOICEMAIL_SECRET_CODE.equals(host)) {
+      return;
+    }
+    LogUtil.i("VoicemailSecretCodeReceiver.onReceive", "secret code received");
+    VoicemailComponent.get(context).getVoicemailClient().showConfigUi(context);
+  }
+}
diff --git a/java/com/android/voicemail/impl/AndroidManifest.xml b/java/com/android/voicemail/impl/AndroidManifest.xml
index 6a7e689..3c7df66 100644
--- a/java/com/android/voicemail/impl/AndroidManifest.xml
+++ b/java/com/android/voicemail/impl/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-  package="com.android.voicemailomtp">
+  package="com.android.voicemail.impl">
 
   <application
     android:supportsRtl="true">
diff --git a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java
index 4a9e433..700e1cb 100644
--- a/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java
+++ b/java/com/android/voicemail/impl/OmtpVvmCarrierConfigHelper.java
@@ -15,9 +15,11 @@
  */
 package com.android.voicemail.impl;
 
+import android.annotation.TargetApi;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.support.annotation.NonNull;
@@ -30,6 +32,7 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import com.android.dialer.common.Assert;
+import com.android.voicemail.impl.configui.ConfigOverrideFragment;
 import com.android.voicemail.impl.protocol.VisualVoicemailProtocol;
 import com.android.voicemail.impl.protocol.VisualVoicemailProtocolFactory;
 import com.android.voicemail.impl.sms.StatusMessage;
@@ -48,27 +51,28 @@
  *
  * <p>The current hidden configs are: {@link #getSslPort()} {@link #getDisabledCapabilities()}
  */
+@TargetApi(VERSION_CODES.O)
 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 =
+  public static final String KEY_VVM_TYPE_STRING = CarrierConfigManager.KEY_VVM_TYPE_STRING;
+  public 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 =
+  public static final String KEY_VVM_PORT_NUMBER_INT = CarrierConfigManager.KEY_VVM_PORT_NUMBER_INT;
+  public 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 =
+  public 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 =
+  public static final String KEY_VVM_PREFETCH_BOOL = CarrierConfigManager.KEY_VVM_PREFETCH_BOOL;
+  public 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";
+  public 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";
+  public 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
@@ -76,10 +80,10 @@
    *
    * @see #getDisabledCapabilities()
    */
-  static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY =
+  public 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";
+  public static final String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
 
   private final Context mContext;
   private final PersistableBundle mCarrierConfig;
@@ -87,6 +91,8 @@
   private final VisualVoicemailProtocol mProtocol;
   private final PersistableBundle mTelephonyConfig;
 
+  @Nullable private final PersistableBundle mOverrideConfig;
+
   private PhoneAccountHandle mPhoneAccountHandle;
 
   public OmtpVvmCarrierConfigHelper(Context context, @Nullable PhoneAccountHandle handle) {
@@ -100,6 +106,7 @@
       VvmLog.e(TAG, "PhoneAccountHandle is invalid");
       mCarrierConfig = null;
       mTelephonyConfig = null;
+      mOverrideConfig = null;
       mVvmType = null;
       mProtocol = null;
       return;
@@ -111,6 +118,13 @@
 
     mVvmType = getVvmType();
     mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType);
+
+    if (ConfigOverrideFragment.isOverridden(context)) {
+      mOverrideConfig = ConfigOverrideFragment.getConfig(context);
+      VvmLog.w(TAG, "Config override is activated: " + mOverrideConfig);
+    } else {
+      mOverrideConfig = null;
+    }
   }
 
   @VisibleForTesting
@@ -119,10 +133,23 @@
     mContext = context;
     mCarrierConfig = carrierConfig;
     mTelephonyConfig = telephonyConfig;
+    mOverrideConfig = null;
     mVvmType = getVvmType();
     mProtocol = VisualVoicemailProtocolFactory.create(mContext.getResources(), mVvmType);
   }
 
+  public PersistableBundle getConfig() {
+    PersistableBundle result = new PersistableBundle();
+    if (mTelephonyConfig != null) {
+      result.putAll(mTelephonyConfig);
+    }
+    if (mCarrierConfig != null) {
+      result.putAll(mCarrierConfig);
+    }
+
+    return result;
+  }
+
   public Context getContext() {
     return mContext;
   }
@@ -426,6 +453,13 @@
   @Nullable
   private Object getValue(String key, Object defaultValue) {
     Object result;
+    if (mOverrideConfig != null) {
+      result = mOverrideConfig.get(key);
+      if (result != null) {
+        return result;
+      }
+    }
+
     if (mCarrierConfig != null) {
       result = mCarrierConfig.get(key);
       if (result != null) {
diff --git a/java/com/android/voicemail/impl/VoicemailClientImpl.java b/java/com/android/voicemail/impl/VoicemailClientImpl.java
index 83ce6c5..96cd534 100644
--- a/java/com/android/voicemail/impl/VoicemailClientImpl.java
+++ b/java/com/android/voicemail/impl/VoicemailClientImpl.java
@@ -17,8 +17,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build.VERSION_CODES;
+import android.os.PersistableBundle;
 import android.provider.VoicemailContract.Status;
 import android.provider.VoicemailContract.Voicemails;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.v4.os.BuildCompat;
 import android.telecom.PhoneAccountHandle;
@@ -28,6 +30,7 @@
 import com.android.dialer.configprovider.ConfigProviderBindings;
 import com.android.voicemail.VisualVoicemailTypeExtensions;
 import com.android.voicemail.VoicemailClient;
+import com.android.voicemail.impl.configui.VoicemailSecretCodeActivity;
 import com.android.voicemail.impl.settings.VisualVoicemailSettingsUtil;
 import com.android.voicemail.impl.settings.VoicemailChangePinActivity;
 import com.android.voicemail.impl.settings.VoicemailSettingsFragment;
@@ -126,6 +129,18 @@
     return VvmAccountManager.isAccountActivated(context, phoneAccountHandle);
   }
 
+  @Override
+  public void showConfigUi(@NonNull Context context) {
+    Intent intent = new Intent(context, VoicemailSecretCodeActivity.class);
+    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+    context.startActivity(intent);
+  }
+
+  @Override
+  public PersistableBundle getConfig(Context context, PhoneAccountHandle phoneAccountHandle) {
+    return new OmtpVvmCarrierConfigHelper(context, phoneAccountHandle).getConfig();
+  }
+
   @TargetApi(VERSION_CODES.O)
   @Override
   public void appendOmtpVoicemailSelectionClause(
diff --git a/java/com/android/voicemail/impl/configui/AndroidManifest.xml b/java/com/android/voicemail/impl/configui/AndroidManifest.xml
new file mode 100644
index 0000000..95796f9
--- /dev/null
+++ b/java/com/android/voicemail/impl/configui/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.voicemail.impl.configui">
+
+  <application>
+    <activity android:name="com.android.voicemail.impl.configui.VoicemailSecretCodeActivity"
+        android:exported="false">
+    </activity>
+  </application>
+</manifest>
diff --git a/java/com/android/voicemail/impl/configui/ConfigOverrideFragment.java b/java/com/android/voicemail/impl/configui/ConfigOverrideFragment.java
new file mode 100644
index 0000000..18b2b92
--- /dev/null
+++ b/java/com/android/voicemail/impl/configui/ConfigOverrideFragment.java
@@ -0,0 +1,175 @@
+/*
+ * 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.voicemail.impl.configui;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.preference.EditTextPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.text.TextUtils;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.concurrent.ThreadUtil;
+import com.android.voicemail.VoicemailComponent;
+
+/**
+ * Fragment to edit the override values for the {@link import
+ * com.android.voicemail.impl.OmtpVvmCarrierConfigHelper}
+ */
+public class ConfigOverrideFragment extends PreferenceFragment
+    implements OnPreferenceChangeListener {
+
+  /**
+   * Any preference with key that starts with this prefix will be written to the dialer carrier
+   * config.
+   */
+  @VisibleForTesting static final String CONFIG_OVERRIDE_KEY_PREFIX = "vvm_config_override_key_";
+
+  @Override
+  public void onCreate(@Nullable Bundle savedInstanceState) {
+    super.onCreate(savedInstanceState);
+    PreferenceManager.setDefaultValues(getActivity(), R.xml.vvm_config_override, false);
+    addPreferencesFromResource(R.xml.vvm_config_override);
+
+    // add listener so the value of a EditTextPreference will be updated to the summary.
+    for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) {
+      Preference preference = getPreferenceScreen().getPreference(i);
+      preference.setOnPreferenceChangeListener(this);
+      updatePreference(preference);
+    }
+  }
+
+  @Override
+  public boolean onPreferenceChange(Preference preference, Object newValue) {
+    Assert.isMainThread();
+    ThreadUtil.postOnUiThread(() -> updatePreference(preference));
+    return true;
+  }
+
+  private void updatePreference(Preference preference) {
+    if (preference instanceof EditTextPreference) {
+      EditTextPreference editTextPreference = (EditTextPreference) preference;
+      editTextPreference.setSummary(editTextPreference.getText());
+    }
+  }
+
+  @Override
+  public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
+    if (TextUtils.equals(
+        preference.getKey(), getString(R.string.vvm_config_override_load_current_key))) {
+      loadCurrentConfig();
+    }
+    return super.onPreferenceTreeClick(preferenceScreen, preference);
+  }
+
+  /**
+   * Loads the config for the currently carrier into the override values, from the dialer or the
+   * carrier config app. This is a "reset" button to load the defaults.
+   */
+  private void loadCurrentConfig() {
+    Context context = getActivity();
+    PhoneAccountHandle phoneAccountHandle =
+        context
+            .getSystemService(TelecomManager.class)
+            .getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_VOICEMAIL);
+
+    PersistableBundle config =
+        VoicemailComponent.get(context).getVoicemailClient().getConfig(context, phoneAccountHandle);
+
+    for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) {
+      Preference preference = getPreferenceScreen().getPreference(i);
+      String key = preference.getKey();
+      if (!key.startsWith(CONFIG_OVERRIDE_KEY_PREFIX)) {
+        continue;
+      }
+
+      String configKey = key.substring(CONFIG_OVERRIDE_KEY_PREFIX.length());
+
+      if (configKey.endsWith("bool")) {
+        ((SwitchPreference) preference).setChecked(config.getBoolean(configKey));
+      } else if (configKey.endsWith("int")) {
+        ((EditTextPreference) preference).setText(String.valueOf(config.getInt(configKey)));
+      } else if (configKey.endsWith("string")) {
+        ((EditTextPreference) preference).setText(config.getString(configKey));
+      } else if (configKey.endsWith("string_array")) {
+        ((EditTextPreference) preference).setText(toCsv(config.getStringArray(configKey)));
+      } else {
+        throw Assert.createAssertionFailException("unknown type for key " + configKey);
+      }
+      updatePreference(preference);
+    }
+  }
+
+  public static boolean isOverridden(Context context) {
+    return PreferenceManager.getDefaultSharedPreferences(context)
+        .getBoolean(context.getString(R.string.vvm_config_override_enabled_key), false);
+  }
+
+  public static PersistableBundle getConfig(Context context) {
+    Assert.checkState(isOverridden(context));
+    PersistableBundle result = new PersistableBundle();
+
+    SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
+    for (String key : preferences.getAll().keySet()) {
+      if (!key.startsWith(CONFIG_OVERRIDE_KEY_PREFIX)) {
+        continue;
+      }
+      String configKey = key.substring(CONFIG_OVERRIDE_KEY_PREFIX.length());
+      if (configKey.endsWith("bool")) {
+        result.putBoolean(configKey, preferences.getBoolean(key, false));
+      } else if (configKey.endsWith("int")) {
+        result.putInt(configKey, Integer.valueOf(preferences.getString(key, null)));
+      } else if (configKey.endsWith("string")) {
+        result.putString(configKey, preferences.getString(key, null));
+      } else if (configKey.endsWith("string_array")) {
+        result.putStringArray(configKey, fromCsv(preferences.getString(key, null)));
+      } else {
+        throw Assert.createAssertionFailException("unknown type for key " + configKey);
+      }
+    }
+    return result;
+  }
+
+  private static String toCsv(String[] array) {
+    if (array == null) {
+      return "";
+    }
+    StringBuilder result = new StringBuilder();
+    for (String element : array) {
+      if (result.length() != 0) {
+        result.append(",");
+      }
+      result.append(element);
+    }
+    return result.toString();
+  };
+
+  private static String[] fromCsv(String csv) {
+    return csv.split(",");
+  }
+}
diff --git a/java/com/android/voicemail/impl/configui/VoicemailSecretCodeActivity.java b/java/com/android/voicemail/impl/configui/VoicemailSecretCodeActivity.java
new file mode 100644
index 0000000..beeb956
--- /dev/null
+++ b/java/com/android/voicemail/impl/configui/VoicemailSecretCodeActivity.java
@@ -0,0 +1,58 @@
+/*
+ * 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.voicemail.impl.configui;
+
+import android.content.Intent;
+import android.preference.PreferenceActivity;
+import android.provider.VoicemailContract;
+import java.util.List;
+
+/** Activity launched by simulator->voicemail, provides debug features. */
+@SuppressWarnings("FragmentInjection") // not exported
+public class VoicemailSecretCodeActivity extends PreferenceActivity {
+
+  private Header syncHeader;
+
+  @Override
+  public void onBuildHeaders(List<Header> target) {
+    super.onBuildHeaders(target);
+    syncHeader = new Header();
+    syncHeader.title = "Sync";
+    target.add(syncHeader);
+
+    Header configOverride = new Header();
+    configOverride.fragment = ConfigOverrideFragment.class.getName();
+    configOverride.title = "VVM config override";
+    target.add(configOverride);
+  }
+
+  @Override
+  public void onHeaderClick(Header header, int position) {
+    if (header == syncHeader) {
+      Intent intent = new Intent(VoicemailContract.ACTION_SYNC_VOICEMAIL);
+      intent.setPackage(getPackageName());
+      sendBroadcast(intent);
+      return;
+    }
+    super.onHeaderClick(header, position);
+  }
+
+  @Override
+  protected boolean isValidFragment(String fragmentName) {
+    return true;
+  }
+}
diff --git a/java/com/android/voicemail/impl/configui/res/values/strings.xml b/java/com/android/voicemail/impl/configui/res/values/strings.xml
new file mode 100644
index 0000000..fea76be
--- /dev/null
+++ b/java/com/android/voicemail/impl/configui/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?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">
+  <string name="vvm_config_override_load_current_key" translatable="false">vvm_config_override_load_current</string>
+  <string name="vvm_config_override_enabled_key" translatable="false">vvm_config_override_enabled</string>
+
+</resources>
diff --git a/java/com/android/voicemail/impl/configui/res/xml/vvm_config_override.xml b/java/com/android/voicemail/impl/configui/res/xml/vvm_config_override.xml
new file mode 100644
index 0000000..c4a23c7
--- /dev/null
+++ b/java/com/android/voicemail/impl/configui/res/xml/vvm_config_override.xml
@@ -0,0 +1,76 @@
+<?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.
+-->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+  <Preference
+    android:key="@string/vvm_config_override_load_current_key"
+    android:title="Load current"/>
+
+  <SwitchPreference
+      android:key="@string/vvm_config_override_enabled_key"
+      android:title="Override enabled"
+      android:defaultValue="false"/>
+
+  <!-- Keys should be a key in CarrierConfigManager prefixed with "vvm_config_override_key_" -->
+  <EditTextPreference
+    android:key="vvm_config_override_key_vvm_type_string"
+      android:title="type"
+      android:defaultValue="vvm_type_omtp"
+    />
+
+  <EditTextPreference
+      android:key="vvm_config_override_key_vvm_destination_number_string"
+      android:title="destination number"
+      />
+
+  <EditTextPreference
+      android:key="vvm_config_override_key_vvm_port_number_int"
+      android:title="destination port"
+      />
+  <EditTextPreference
+      android:key="vvm_config_override_key_carrier_vvm_package_name_string_array"
+      android:title="vvm package name (CSV)"
+      />
+
+  <SwitchPreference
+      android:key="vvm_config_override_key_vvm_prefetch_bool"
+      android:title="prefetch"
+      android:defaultValue="true"/>
+
+  <SwitchPreference
+      android:key="vvm_config_override_key_vvm_cellular_data_required_bool"
+      android:title="cellular data required"
+      android:defaultValue="false"/>
+  <EditTextPreference
+      android:key="vvm_config_override_key_vvm_ssl_port_number_int"
+      android:title="SSL port"
+      />
+
+  <SwitchPreference
+      android:key="vvm_config_override_key_vvm_legacy_mode_enabled_bool"
+      android:title="legacy mode"
+      android:defaultValue="false"/>
+
+  <EditTextPreference
+      android:key="vvm_config_override_key_vvm_disabled_capabilities_string_array"
+      android:title="disabled capabilities (CSV)"
+      />
+
+  <EditTextPreference
+      android:key="vvm_config_override_key_vvm_client_prefix_string"
+      android:title="client prefix"
+      />
+</PreferenceScreen>
\ No newline at end of file
diff --git a/java/com/android/voicemail/impl/res/values/strings.xml b/java/com/android/voicemail/impl/res/values/strings.xml
index 375a1e9..a846541 100644
--- a/java/com/android/voicemail/impl/res/values/strings.xml
+++ b/java/com/android/voicemail/impl/res/values/strings.xml
@@ -107,4 +107,8 @@
   <string name="change_pin_succeeded">Voicemail PIN updated</string>
   <!-- The error message to show if the server reported an error while attempting to change the voicemail PIN -->
   <string name="change_pin_system_error">Unable to set PIN</string>
+
+  <string name="vvm_config_override_load_current_key" translatable="false">vvm_config_override_load_current</string>
+  <string name="vvm_config_override_enabled_key" translatable="false">vvm_config_override_enabled</string>
+
 </resources>
diff --git a/java/com/android/voicemail/stub/StubVoicemailClient.java b/java/com/android/voicemail/stub/StubVoicemailClient.java
index e2b4707..9a89e30 100644
--- a/java/com/android/voicemail/stub/StubVoicemailClient.java
+++ b/java/com/android/voicemail/stub/StubVoicemailClient.java
@@ -18,6 +18,9 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.os.PersistableBundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.TelephonyManager;
 import com.android.voicemail.VoicemailClient;
@@ -81,4 +84,13 @@
   public boolean isActivated(Context context, PhoneAccountHandle phoneAccountHandle) {
     return false;
   }
+
+  @Override
+  public void showConfigUi(@NonNull Context context) {}
+
+  @Override
+  public PersistableBundle getConfig(
+      @NonNull Context context, @Nullable PhoneAccountHandle phoneAccountHandle) {
+    return new PersistableBundle();
+  }
 }