summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/voicemail/settings
diff options
context:
space:
mode:
authorZachary Heidepriem <zachh@google.com>2017-11-06 19:10:44 -0800
committerZachary Heidepriem <zachh@google.com>2017-11-06 19:10:44 -0800
commit7547d3e963dab2b1ef467ad27c3f0d25e150b50c (patch)
tree642c7b180b33d1371c1f474be03fbb8de2110f6d /java/com/android/dialer/voicemail/settings
parentb519cd522d472b5d7980cc015aa37c101be99386 (diff)
Move voicemail settings to dialer UI
The voicemail module should not contain any UI code. Bug: 37258159 Test: DialerSettingsActivityTest,VoicemailSettingsFragmentTest. A future CL is refactoring VoicemailChangePinActivity into a fragment. PiperOrigin-RevId: 174125949 Change-Id: I89cf6a083b0a0952332440d76e7ae0cb1c801931
Diffstat (limited to 'java/com/android/dialer/voicemail/settings')
-rw-r--r--java/com/android/dialer/voicemail/settings/AndroidManifest.xml34
-rw-r--r--java/com/android/dialer/voicemail/settings/VoicemailChangePinActivity.java595
-rw-r--r--java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java279
-rw-r--r--java/com/android/dialer/voicemail/settings/res/layout/voicemail_change_pin.xml94
-rw-r--r--java/com/android/dialer/voicemail/settings/res/values/strings.xml121
-rw-r--r--java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml46
6 files changed, 1169 insertions, 0 deletions
diff --git a/java/com/android/dialer/voicemail/settings/AndroidManifest.xml b/java/com/android/dialer/voicemail/settings/AndroidManifest.xml
new file mode 100644
index 000000000..4a0784f84
--- /dev/null
+++ b/java/com/android/dialer/voicemail/settings/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?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.dialer.voicemail.settings">
+
+ <application>
+ <activity
+ android:exported="false"
+ android:label="@string/voicemail_change_pin_preference_title"
+ android:name="com.android.dialer.voicemail.settings.VoicemailChangePinActivity"
+ android:parentActivityName="com.android.dialer.app.settings.DialerSettingsActivity"
+ android:theme="@style/SettingsStyle"
+ android:windowSoftInputMode="stateVisible|adjustResize">
+ <intent-filter>
+ <action android:name="com.android.dialer.action.CHANGE_PIN"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/java/com/android/dialer/voicemail/settings/VoicemailChangePinActivity.java b/java/com/android/dialer/voicemail/settings/VoicemailChangePinActivity.java
new file mode 100644
index 000000000..4d53d61d2
--- /dev/null
+++ b/java/com/android/dialer/voicemail/settings/VoicemailChangePinActivity.java
@@ -0,0 +1,595 @@
+/*
+ * 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.dialer.voicemail.settings;
+
+import android.annotation.TargetApi;
+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.os.Build.VERSION_CODES;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.support.annotation.Nullable;
+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.dialer.common.LogUtil;
+import com.android.dialer.common.concurrent.DialerExecutor;
+import com.android.dialer.common.concurrent.DialerExecutor.Worker;
+import com.android.dialer.common.concurrent.DialerExecutorComponent;
+import com.android.dialer.logging.DialerImpression;
+import com.android.dialer.logging.Logger;
+import com.android.voicemail.PinChanger;
+import com.android.voicemail.PinChanger.ChangePinResult;
+import com.android.voicemail.PinChanger.PinSpecification;
+import com.android.voicemail.VoicemailClient;
+import com.android.voicemail.VoicemailComponent;
+import java.lang.ref.WeakReference;
+
+/**
+ * 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
+ * VoicemailClient#PARAM_PHONE_ACCOUNT_HANDLE}
+ */
+@TargetApi(VERSION_CODES.O)
+public class VoicemailChangePinActivity extends Activity
+ implements OnClickListener, OnEditorActionListener, TextWatcher {
+
+ private static final String TAG = "VmChangePinActivity";
+ public static final String ACTION_CHANGE_PIN = "com.android.dialer.action.CHANGE_PIN";
+
+ private static final int MESSAGE_HANDLE_RESULT = 1;
+
+ private PhoneAccountHandle mPhoneAccountHandle;
+ private PinChanger mPinChanger;
+
+ private static class ChangePinParams {
+ PinChanger pinChanger;
+ PhoneAccountHandle phoneAccountHandle;
+ String oldPin;
+ String newPin;
+ }
+
+ private DialerExecutor<ChangePinParams> mChangePinExecutor;
+
+ 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 ChangePinHandler(new WeakReference<>(this));
+
+ 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 == PinChanger.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(
+ final VoicemailChangePinActivity activity, @ChangePinResult int result) {
+ if (result == PinChanger.CHANGE_PIN_SUCCESS) {
+ activity.updateState(State.EnterNewPin);
+ } else if (result == PinChanger.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 {
+ LogUtil.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.
+ activity.mPinChanger.setScrambledPin(null);
+ 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 == PinChanger.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.
+ activity.mPinChanger.setScrambledPin(null);
+
+ activity.finish();
+ Logger.get(activity).logImpression(DialerImpression.Type.VVM_CHANGE_PIN_COMPLETED);
+ Toast.makeText(
+ activity, activity.getString(R.string.change_pin_succeeded), Toast.LENGTH_SHORT)
+ .show();
+ } else {
+ CharSequence message = activity.getChangePinResultMessage(result);
+ LogUtil.i(TAG, "Change PIN failed: " + message);
+ activity.showError(message);
+ if (result == PinChanger.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(VoicemailClient.PARAM_PHONE_ACCOUNT_HANDLE);
+ mPinChanger =
+ VoicemailComponent.get(this)
+ .getVoicemailClient()
+ .createPinChanger(getApplicationContext(), 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);
+
+ if (isPinScrambled(this, mPhoneAccountHandle)) {
+ mOldPin = mPinChanger.getScrambledPin();
+ updateState(State.VerifyOldPin);
+ } else {
+ updateState(State.EnterOldPin);
+ }
+
+ mChangePinExecutor =
+ DialerExecutorComponent.get(this)
+ .dialerExecutorFactory()
+ .createUiTaskBuilder(getFragmentManager(), "changePin", new ChangePinWorker())
+ .onSuccess(this::sendResult)
+ .onFailure((tr) -> sendResult(PinChanger.CHANGE_PIN_SYSTEM_ERROR))
+ .build();
+ }
+
+ /** Extracts the pin length requirement sent by the server with a STATUS SMS. */
+ private void readPinLength() {
+ PinSpecification pinSpecification = mPinChanger.getPinSpecification();
+ mPinMinLength = pinSpecification.minLength;
+ mPinMaxLength = pinSpecification.maxLength;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateState(mUiState);
+ }
+
+ public void handleNext() {
+ if (mPinEntry.length() == 0) {
+ return;
+ }
+ mUiState.handleNext(this);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v.getId() == R.id.next_button) {
+ handleNext();
+ } else if (v.getId() == R.id.cancel_button) {
+ finish();
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ 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;
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ mUiState.onInputChanged(this);
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // Do nothing
+ }
+
+ @Override
+ 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 boolean isPinScrambled(Context context, PhoneAccountHandle phoneAccountHandle) {
+ return VoicemailComponent.get(context)
+ .getVoicemailClient()
+ .createPinChanger(context, phoneAccountHandle)
+ .getScrambledPin()
+ != null;
+ }
+
+ 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 PinChanger#CHANGE_PIN_SUCCESS}
+ */
+ private CharSequence getChangePinResultMessage(@ChangePinResult int result) {
+ switch (result) {
+ case PinChanger.CHANGE_PIN_TOO_SHORT:
+ return getString(R.string.vm_change_pin_error_too_short);
+ case PinChanger.CHANGE_PIN_TOO_LONG:
+ return getString(R.string.vm_change_pin_error_too_long);
+ case PinChanger.CHANGE_PIN_TOO_WEAK:
+ return getString(R.string.vm_change_pin_error_too_weak);
+ case PinChanger.CHANGE_PIN_INVALID_CHARACTER:
+ return getString(R.string.vm_change_pin_error_invalid);
+ case PinChanger.CHANGE_PIN_MISMATCH:
+ return getString(R.string.vm_change_pin_error_mismatch);
+ case PinChanger.CHANGE_PIN_SYSTEM_ERROR:
+ return getString(R.string.vm_change_pin_error_system_error);
+ default:
+ LogUtil.e(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();
+
+ ChangePinParams params = new ChangePinParams();
+ params.pinChanger = mPinChanger;
+ params.phoneAccountHandle = mPhoneAccountHandle;
+ params.oldPin = oldPin;
+ params.newPin = newPin;
+
+ mChangePinExecutor.executeSerial(params);
+ }
+
+ private void sendResult(@ChangePinResult int result) {
+ LogUtil.i(TAG, "Change PIN result: " + result);
+ if (mProgressDialog.isShowing()
+ && !VoicemailChangePinActivity.this.isDestroyed()
+ && !VoicemailChangePinActivity.this.isFinishing()) {
+ mProgressDialog.dismiss();
+ } else {
+ LogUtil.i(TAG, "Dialog not visible, not dismissing");
+ }
+ mHandler.obtainMessage(MESSAGE_HANDLE_RESULT, result, 0).sendToTarget();
+ }
+
+ private static class ChangePinHandler extends Handler {
+
+ private final WeakReference<VoicemailChangePinActivity> activityWeakReference;
+
+ private ChangePinHandler(WeakReference<VoicemailChangePinActivity> activityWeakReference) {
+ this.activityWeakReference = activityWeakReference;
+ }
+
+ @Override
+ public void handleMessage(Message message) {
+ VoicemailChangePinActivity activity = activityWeakReference.get();
+ if (activity == null) {
+ return;
+ }
+ if (message.what == MESSAGE_HANDLE_RESULT) {
+ activity.mUiState.handleResult(activity, message.arg1);
+ }
+ }
+ }
+
+ private static class ChangePinWorker implements Worker<ChangePinParams, Integer> {
+
+ @Nullable
+ @Override
+ public Integer doInBackground(@Nullable ChangePinParams input) throws Throwable {
+ return input.pinChanger.changePin(input.oldPin, input.newPin);
+ }
+ }
+}
diff --git a/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
new file mode 100644
index 000000000..efeed0861
--- /dev/null
+++ b/java/com/android/dialer/voicemail/settings/VoicemailSettingsFragment.java
@@ -0,0 +1,279 @@
+/**
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * <p>http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * <p>Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT 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.dialer.voicemail.settings;
+
+import android.annotation.TargetApi;
+import android.content.Intent;
+import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
+import android.preference.SwitchPreference;
+import android.provider.Settings;
+import android.support.annotation.Nullable;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyManager;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.LogUtil;
+import com.android.dialer.logging.DialerImpression;
+import com.android.dialer.logging.Logger;
+import com.android.dialer.notification.NotificationChannelManager;
+import com.android.voicemail.VoicemailClient;
+import com.android.voicemail.VoicemailClient.ActivationStateListener;
+import com.android.voicemail.VoicemailComponent;
+
+/**
+ * Fragment for voicemail settings. Requires {@link VoicemailClient#PARAM_PHONE_ACCOUNT_HANDLE} set
+ * in arguments.
+ */
+@TargetApi(VERSION_CODES.O)
+public class VoicemailSettingsFragment extends PreferenceFragment
+ implements Preference.OnPreferenceChangeListener, ActivationStateListener {
+
+ private static final String TAG = "VmSettingsActivity";
+
+ @Nullable private PhoneAccountHandle phoneAccountHandle;
+
+ private VoicemailClient voicemailClient;
+
+ private Preference voicemailNotificationPreference;
+ private SwitchPreference voicemailVisualVoicemail;
+ private SwitchPreference autoArchiveSwitchPreference;
+ private SwitchPreference donateVoicemailSwitchPreference;
+ private Preference voicemailChangePinPreference;
+ private PreferenceScreen advancedSettings;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ phoneAccountHandle =
+ Assert.isNotNull(getArguments().getParcelable(VoicemailClient.PARAM_PHONE_ACCOUNT_HANDLE));
+ voicemailClient = VoicemailComponent.get(getContext()).getVoicemailClient();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_SETTINGS_VIEWED);
+ voicemailClient.addActivationStateListener(this);
+ PreferenceScreen preferenceScreen = getPreferenceScreen();
+ if (preferenceScreen != null) {
+ preferenceScreen.removeAll();
+ }
+
+ addPreferencesFromResource(R.xml.voicemail_settings);
+
+ PreferenceScreen prefSet = getPreferenceScreen();
+
+ voicemailNotificationPreference =
+ findPreference(getString(R.string.voicemail_notifications_key));
+ voicemailNotificationPreference.setIntent(getNotificationSettingsIntent());
+
+ voicemailNotificationPreference.setOnPreferenceClickListener(
+ new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ Logger.get(getContext())
+ .logImpression(DialerImpression.Type.VVM_CHANGE_RINGTONE_CLICKED);
+ // Let the preference handle the click.
+ return false;
+ }
+ });
+
+ voicemailVisualVoicemail =
+ (SwitchPreference) findPreference(getString(R.string.voicemail_visual_voicemail_key));
+
+ autoArchiveSwitchPreference =
+ (SwitchPreference)
+ findPreference(getString(R.string.voicemail_visual_voicemail_archive_key));
+
+ donateVoicemailSwitchPreference =
+ (SwitchPreference)
+ findPreference(getString(R.string.voicemail_visual_voicemail_donation_key));
+
+ if (!VoicemailComponent.get(getContext())
+ .getVoicemailClient()
+ .isVoicemailArchiveAvailable(getContext())) {
+ getPreferenceScreen().removePreference(autoArchiveSwitchPreference);
+ }
+
+ if (!VoicemailComponent.get(getContext())
+ .getVoicemailClient()
+ .isVoicemailDonationEnabled(getContext(), phoneAccountHandle)) {
+ getPreferenceScreen().removePreference(donateVoicemailSwitchPreference);
+ }
+
+ voicemailChangePinPreference = findPreference(getString(R.string.voicemail_change_pin_key));
+
+ if (voicemailClient.hasCarrierSupport(getContext(), phoneAccountHandle)) {
+ Assert.isNotNull(phoneAccountHandle);
+ Intent changePinIntent =
+ new Intent(new Intent(getContext(), VoicemailChangePinActivity.class));
+ changePinIntent.putExtra(VoicemailClient.PARAM_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
+
+ voicemailChangePinPreference.setIntent(changePinIntent);
+ voicemailChangePinPreference.setOnPreferenceClickListener(
+ new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_CHANGE_PIN_CLICKED);
+ // Let the preference handle the click.
+ return false;
+ }
+ });
+ if (VoicemailChangePinActivity.isPinScrambled(getContext(), phoneAccountHandle)) {
+ voicemailChangePinPreference.setTitle(R.string.voicemail_set_pin_preference_title);
+ } else {
+ voicemailChangePinPreference.setTitle(R.string.voicemail_change_pin_preference_title);
+ }
+ updateChangePin();
+
+ voicemailVisualVoicemail.setOnPreferenceChangeListener(this);
+ voicemailVisualVoicemail.setChecked(
+ voicemailClient.isVoicemailEnabled(getContext(), phoneAccountHandle));
+
+ autoArchiveSwitchPreference.setOnPreferenceChangeListener(this);
+ autoArchiveSwitchPreference.setChecked(
+ voicemailClient.isVoicemailArchiveEnabled(getContext(), phoneAccountHandle));
+
+ donateVoicemailSwitchPreference.setOnPreferenceChangeListener(this);
+ donateVoicemailSwitchPreference.setChecked(
+ voicemailClient.isVoicemailDonationEnabled(getContext(), phoneAccountHandle));
+ updateDonateVoicemail();
+ } else {
+ prefSet.removePreference(voicemailVisualVoicemail);
+ prefSet.removePreference(autoArchiveSwitchPreference);
+ prefSet.removePreference(donateVoicemailSwitchPreference);
+ prefSet.removePreference(voicemailChangePinPreference);
+ }
+
+ advancedSettings =
+ (PreferenceScreen) findPreference(getString(R.string.voicemail_advanced_settings_key));
+ Intent advancedSettingsIntent = new Intent(TelephonyManager.ACTION_CONFIGURE_VOICEMAIL);
+ advancedSettingsIntent.putExtra(TelephonyManager.EXTRA_HIDE_PUBLIC_SETTINGS, true);
+ advancedSettingsIntent.putExtra(
+ TelephonyManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle);
+ advancedSettings.setIntent(advancedSettingsIntent);
+ voicemailChangePinPreference.setOnPreferenceClickListener(
+ new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ Logger.get(getContext())
+ .logImpression(DialerImpression.Type.VVM_ADVANCED_SETINGS_CLICKED);
+ // Let the preference handle the click.
+ return false;
+ }
+ });
+ }
+
+ @Override
+ public void onPause() {
+ voicemailClient.removeActivationStateListener(this);
+ super.onPause();
+ }
+
+ /**
+ * Implemented to support onPreferenceChangeListener to look for preference changes.
+ *
+ * @param preference is the preference to be changed
+ * @param objValue should be the value of the selection, NOT its localized display value.
+ */
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object objValue) {
+ LogUtil.d(TAG, "onPreferenceChange: \"" + preference + "\" changed to \"" + objValue + "\"");
+ if (preference.getKey().equals(voicemailVisualVoicemail.getKey())) {
+ boolean isEnabled = (boolean) objValue;
+ voicemailClient.setVoicemailEnabled(getContext(), phoneAccountHandle, isEnabled);
+
+ if (isEnabled) {
+ Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_USER_ENABLED_IN_SETTINGS);
+ } else {
+ Logger.get(getContext()).logImpression(DialerImpression.Type.VVM_USER_DISABLED_IN_SETTINGS);
+ }
+
+ updateChangePin();
+ updateDonateVoicemail();
+ } else if (preference.getKey().equals(autoArchiveSwitchPreference.getKey())) {
+ logArchiveToggle((boolean) objValue);
+ voicemailClient.setVoicemailArchiveEnabled(
+ getContext(), phoneAccountHandle, (boolean) objValue);
+ } else if (preference.getKey().equals(donateVoicemailSwitchPreference.getKey())) {
+ logArchiveToggle((boolean) objValue);
+ voicemailClient.setVoicemailDonationEnabled(
+ getContext(), phoneAccountHandle, (boolean) objValue);
+ }
+
+ // Always let the preference setting proceed.
+ return true;
+ }
+
+ private void updateChangePin() {
+ if (!voicemailClient.isVoicemailEnabled(getContext(), phoneAccountHandle)) {
+ voicemailChangePinPreference.setSummary(
+ R.string.voicemail_change_pin_preference_summary_disable);
+ voicemailChangePinPreference.setEnabled(false);
+ } else if (!voicemailClient.isActivated(getContext(), phoneAccountHandle)) {
+ voicemailChangePinPreference.setSummary(
+ R.string.voicemail_change_pin_preference_summary_not_activated);
+ voicemailChangePinPreference.setEnabled(false);
+ } else {
+ voicemailChangePinPreference.setSummary(null);
+ voicemailChangePinPreference.setEnabled(true);
+ }
+ }
+
+ private void updateDonateVoicemail() {
+ if (!voicemailClient.isVoicemailEnabled(getContext(), phoneAccountHandle)) {
+ donateVoicemailSwitchPreference.setSummary(
+ R.string.voicemail_donate_preference_summary_disable);
+ donateVoicemailSwitchPreference.setEnabled(false);
+ } else if (!voicemailClient.isActivated(getContext(), phoneAccountHandle)) {
+ donateVoicemailSwitchPreference.setSummary(
+ R.string.voicemail_donate_preference_summary_not_activated);
+ donateVoicemailSwitchPreference.setEnabled(false);
+ } else {
+ donateVoicemailSwitchPreference.setSummary(R.string.voicemail_donate_preference_summary_info);
+ donateVoicemailSwitchPreference.setEnabled(true);
+ }
+ }
+
+ private void logArchiveToggle(boolean userTurnedOn) {
+ if (userTurnedOn) {
+ Logger.get(getContext())
+ .logImpression(DialerImpression.Type.VVM_USER_TURNED_ARCHIVE_ON_FROM_SETTINGS);
+ } else {
+ Logger.get(getContext())
+ .logImpression(DialerImpression.Type.VVM_USER_TURNED_ARCHIVE_OFF_FROM_SETTINGS);
+ }
+ }
+
+ @Override
+ public void onActivationStateChanged(PhoneAccountHandle phoneAccountHandle, boolean isActivated) {
+ if (this.phoneAccountHandle.equals(phoneAccountHandle)) {
+ updateChangePin();
+ updateDonateVoicemail();
+ }
+ }
+
+ private Intent getNotificationSettingsIntent() {
+ String channelId =
+ NotificationChannelManager.getVoicemailChannelId(getContext(), phoneAccountHandle);
+ return new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
+ .putExtra(Settings.EXTRA_CHANNEL_ID, channelId)
+ .putExtra(Settings.EXTRA_APP_PACKAGE, getContext().getPackageName());
+ }
+}
diff --git a/java/com/android/dialer/voicemail/settings/res/layout/voicemail_change_pin.xml b/java/com/android/dialer/voicemail/settings/res/layout/voicemail_change_pin.xml
new file mode 100644
index 000000000..304bd37ec
--- /dev/null
+++ b/java/com/android/dialer/voicemail/settings/res/layout/voicemail_change_pin.xml
@@ -0,0 +1,94 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical">
+ <!-- header text ('Enter Pin') -->
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingTop="48dp"
+ android:paddingStart="48dp"
+ android:paddingEnd="48dp">
+ <TextView
+ android:id="@+id/headerText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:lines="2"
+ android:textAppearance="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"
+ android:accessibilityLiveRegion="polite"/>
+
+ <!-- hint text ('PIN too short') -->
+ <TextView
+ android:id="@+id/hintText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:lines="2"/>
+
+ <!-- error text ('PIN too short') -->
+ <TextView
+ android:id="@+id/errorText"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:lines="2"
+ android:textColor="@android:color/holo_red_dark"/>
+
+ <!-- Password entry field -->
+ <EditText
+ android:id="@+id/pin_entry"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:imeOptions="actionNext|flagNoExtractUi"
+ android:inputType="numberPassword"
+ android:textSize="24sp"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:gravity="end"
+ android:orientation="horizontal">
+
+ <!-- left : cancel -->
+ <Button
+ android:id="@+id/cancel_button"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="@string/change_pin_cancel_label"/>
+
+ <!-- right : continue -->
+ <Button
+ android:id="@+id/next_button"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:text="@string/change_pin_continue_label"/>
+
+ </LinearLayout>
+</LinearLayout>
diff --git a/java/com/android/dialer/voicemail/settings/res/values/strings.xml b/java/com/android/dialer/voicemail/settings/res/values/strings.xml
new file mode 100644
index 000000000..4e502b488
--- /dev/null
+++ b/java/com/android/dialer/voicemail/settings/res/values/strings.xml
@@ -0,0 +1,121 @@
+<?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">
+
+ <!-- Title of the "Voicemail" settings screen, with a text label identifying which SIM the settings are for. -->
+ <string name="voicemail_settings_with_label">Voicemail (<xliff:g example="Mock Carrier" id="subscriptionlabel">%s</xliff:g>)</string>
+
+ <!-- Call settings screen, setting option name -->
+ <string name="voicemail_settings_title">Voicemail</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 to select
+ which sound to play and whether to vibrate when a voicemail notification is received.
+ [CHAR LIMIT=30] -->
+ <string name="voicemail_notifications_preference_title">Notifications</string>
+ <string name="voicemail_advanced_settings_key" translatable="false">voicemail_advanced_settings_key</string>
+
+ <!-- Title for advanced settings in the voicemail settings -->
+ <string name="voicemail_advanced_settings_title">Advanced Settings</string>
+
+ <!-- DO NOT TRANSLATE. Internal key for a visual voicemail preference. -->
+ <string name="voicemail_visual_voicemail_key" translatable="false">voicemail_visual_voicemail_key</string>
+
+ <!-- DO NOT TRANSLATE. Internal key for a visual voicemail archive preference. -->
+ <string name="voicemail_visual_voicemail_archive_key" translatable="false">archive_is_enabled</string>
+
+ <!-- DO NOT TRANSLATE. Internal key for a voicemail change pin preference. -->
+ <string name="voicemail_change_pin_key" translatable="false">voicemail_change_pin_key</string>
+
+ <!-- Visual voicemail on/off title [CHAR LIMIT=40] -->
+ <string name="voicemail_visual_voicemail_switch_title">Visual Voicemail</string>
+
+ <!-- Visual voicemail archive on/off title [CHAR LIMIT=40] -->
+ <string name="voicemail_visual_voicemail_auto_archive_switch_title">Extra backup and storage</string>
+
+ <!-- Voicemail change PIN dialog title [CHAR LIMIT=40] -->
+ <string name="voicemail_set_pin_preference_title">Set PIN</string>
+ <!-- Voicemail change PIN dialog title [CHAR LIMIT=40] -->
+ <string name="voicemail_change_pin_preference_title">Change PIN</string>
+
+ <string name="voicemail_change_pin_preference_summary_disable">Visual voicemail must be enabled to change PIN</string>
+ <string name="voicemail_change_pin_preference_summary_not_activated">Visual voicemail is not activated yet, please try again later</string>
+
+ <!-- Hint for the old PIN field in the change vociemail PIN dialog -->
+ <string name="vm_change_pin_old_pin">Old PIN</string>
+ <!-- Hint for the new PIN field in the change vociemail PIN dialog -->
+ <string name="vm_change_pin_new_pin">New PIN</string>
+
+ <!-- Message on the dialog when PIN changing is in progress -->
+ <string name="vm_change_pin_progress_message">Please wait.</string>
+ <!-- Error message for the voicemail PIN change if the PIN is too short -->
+ <string name="vm_change_pin_error_too_short">The new PIN is too short.</string>
+ <!-- Error message for the voicemail PIN change if the PIN is too long -->
+ <string name="vm_change_pin_error_too_long">The new PIN is too long.</string>
+ <!-- Error message for the voicemail PIN change if the PIN is too weak -->
+ <string name="vm_change_pin_error_too_weak">The new PIN is too weak. A strong password should not have continuous sequence or repeated digits.</string>
+ <!-- Error message for the voicemail PIN change if the old PIN entered doesn't match -->
+ <string name="vm_change_pin_error_mismatch">The old PIN does not match.</string>
+ <!-- Error message for the voicemail PIN change if the new PIN contains invalid character -->
+ <string name="vm_change_pin_error_invalid">The new PIN contains invalid characters.</string>
+ <!-- Error message for the voicemail PIN change if operation has failed -->
+ <string name="vm_change_pin_error_system_error">Unable to change PIN</string>
+
+ <!-- The title for the change voicemail PIN activity -->
+ <string name="change_pin_title">Change Voicemail PIN</string>
+ <!-- The label for the continue button in change voicemail PIN activity -->
+ <string name="change_pin_continue_label">Continue</string>
+ <!-- The label for the cancel button in change voicemail PIN activity -->
+ <string name="change_pin_cancel_label">Cancel</string>
+ <!-- The label for the ok button in change voicemail PIN activity -->
+ <string name="change_pin_ok_label">Ok</string>
+ <!-- The title for the enter old pin step in change voicemail PIN activity -->
+ <string name="change_pin_enter_old_pin_header">Confirm your old PIN</string>
+ <!-- The hint for the enter old pin step in change voicemail PIN activity -->
+ <string name="change_pin_enter_old_pin_hint">Enter your voicemail PIN to continue.</string>
+ <!-- The title for the enter new pin step in change voicemail PIN activity -->
+ <string name="change_pin_enter_new_pin_header">Set a new PIN</string>
+ <!-- The hint for the enter new pin step in change voicemail PIN activity -->
+ <string name="change_pin_enter_new_pin_hint">PIN must be <xliff:g example="4" id="min">%1$d</xliff:g>-<xliff:g example="7" id="max">%2$d</xliff:g> digits.</string>
+ <!-- The title for the confirm new pin step in change voicemail PIN activity -->
+ <string name="change_pin_confirm_pin_header">Confirm your PIN</string>
+ <!-- The error message for th confirm new pin step in change voicemail PIN activity, if the pin doen't match the one previously entered -->
+ <string name="change_pin_confirm_pins_dont_match">PINs don\'t match</string>
+ <!-- The toast to show after the voicemail PIN has been successfully changed -->
+ <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="voicemail_visual_voicemail_donation_key" translatable="false">donate_voicemails</string>
+
+ <!-- Title for visual voicemail setting that enables user to donate their voicemails for analysis.
+ [CHAR LIMIT=40] -->
+ <string name="voicemail_visual_voicemail_donation_switch_title">
+ Voicemail transcription analysis
+ </string>
+ <!-- Summary information for visual voicemail donation setting when visual voicemail is not enabled
+ [CHAR LIMIT=NONE] -->
+ <string name="voicemail_donate_preference_summary_disable">Visual voicemail must be enabled to donate voicemails</string>
+ <!-- Summary information for visual voicemail donation setting when visual voicemail is not activated
+ [CHAR LIMIT=NONE] -->
+ <string name="voicemail_donate_preference_summary_not_activated">Visual voicemail is not activated yet, please try again later</string>
+ <!-- Summary information for visual voicemail donation setting [CHAR LIMIT=NONE] -->
+ <string name="voicemail_donate_preference_summary_info">Let Google review your voicemail messages to improve transcription quality</string>
+
+</resources>
diff --git a/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml b/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
new file mode 100644
index 000000000..9b0391ad4
--- /dev/null
+++ b/java/com/android/dialer/voicemail/settings/res/xml/voicemail_settings.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ android:title="@string/voicemail_settings_title">
+
+ <Preference
+ android:key="@string/voicemail_notifications_key"
+ android:title="@string/voicemail_notifications_preference_title"/>
+
+ <SwitchPreference
+ android:key="@string/voicemail_visual_voicemail_key"
+ android:title="@string/voicemail_visual_voicemail_switch_title"/>"
+
+ <SwitchPreference
+ android:key="@string/voicemail_visual_voicemail_archive_key"
+ android:dependency="@string/voicemail_visual_voicemail_key"
+ android:title="@string/voicemail_visual_voicemail_auto_archive_switch_title"/>"
+
+ <SwitchPreference
+ android:key="@string/voicemail_visual_voicemail_donation_key"
+ android:dependency="@string/voicemail_visual_voicemail_key"
+ android:title="@string/voicemail_visual_voicemail_donation_switch_title"/>"
+
+ <Preference
+ android:key="@string/voicemail_change_pin_key"
+ android:title="@string/voicemail_change_pin_preference_title"/>
+
+ <PreferenceScreen
+ android:key="@string/voicemail_advanced_settings_key"
+ android:title="@string/voicemail_advanced_settings_title">
+ </PreferenceScreen>
+</PreferenceScreen>