Merge "Implement UI for changing voicemail PIN" into nyc-mr1-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index ddc2dbe..9778d2c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -732,5 +732,11 @@
<data android:scheme="package"/>
</intent-filter>
</receiver>
+
+ <activity android:name=".settings.VoicemailChangePinActivity"
+ android:exported="false"
+ android:theme="@style/DialerSettingsLight"
+ android:windowSoftInputMode="stateVisible|adjustResize">
+ </activity>
</application>
</manifest>
diff --git a/res/layout/voicemail_change_pin.xml b/res/layout/voicemail_change_pin.xml
new file mode 100644
index 0000000..ba0d823
--- /dev/null
+++ b/res/layout/voicemail_change_pin.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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:padding="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/res/values/strings.xml b/res/values/strings.xml
index a18ee87..d549653 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -336,7 +336,7 @@
<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">Changing PIN</string>
+ <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 -->
@@ -1258,6 +1258,8 @@
<string name="voicemail_visual_voicemail_switch_title">Visual Voicemail</string>
<!-- Voicemail change PIN dialog title [CHAR LIMIT=40] -->
+ <string name="voicemail_set_pin_dialog_title">Set PIN</string>
+ <!-- Voicemail change PIN dialog title [CHAR LIMIT=40] -->
<string name="voicemail_change_pin_dialog_title">Change PIN</string>
<!-- Voicemail ringtone title. The user clicks on this preference to select
@@ -1353,4 +1355,28 @@
There are too many active calls. Please end or merge existing calls before placing a new one.
</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 id="min" example="4">%1$d</xliff:g>-<xliff:g id="max" example="7">%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>
</resources>
diff --git a/res/xml/voicemail_settings.xml b/res/xml/voicemail_settings.xml
index 734d9d7..e1dafb0 100644
--- a/res/xml/voicemail_settings.xml
+++ b/res/xml/voicemail_settings.xml
@@ -65,8 +65,7 @@
android:key="@string/voicemail_visual_voicemail_key"
android:title="@string/voicemail_visual_voicemail_switch_title" />"
- <com.android.phone.settings.VoicemailChangePinDialogPreference
- android:key="@string/voicemail_change_pin_key"
- android:title="@string/voicemail_change_pin_dialog_title" />
-
+ <Preference
+ android:key="@string/voicemail_change_pin_key"
+ android:title="@string/voicemail_change_pin_dialog_title" />
</PreferenceScreen>
diff --git a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
index d7e573e..c38b595 100644
--- a/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
+++ b/src/com/android/phone/settings/VisualVoicemailSettingsUtil.java
@@ -16,49 +16,31 @@
package com.android.phone.settings;
import android.content.Context;
-import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
import android.telecom.PhoneAccountHandle;
import com.android.internal.telephony.Phone;
import com.android.phone.PhoneUtils;
import com.android.phone.R;
-import com.android.phone.vvm.omtp.OmtpConstants;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
-import com.android.phone.vvm.omtp.sms.StatusMessage;
+import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
/**
- * Save visual voicemail login values and whether or not a particular account is enabled in shared
- * preferences to be retrieved later.
- * Because a voicemail source is tied 1:1 to a phone account, the phone account handle is used in
- * the key for each voicemail source and the associated data.
+ * Save whether or not a particular account is enabled in shared to be retrieved later.
*/
public class VisualVoicemailSettingsUtil {
- private static final String VISUAL_VOICEMAIL_SHARED_PREFS_KEY_PREFIX =
- "visual_voicemail_";
private static final String IS_ENABLED_KEY = "is_enabled";
- // Record the timestamp of the last full sync so that duplicate syncs can be reduced.
- private static final String LAST_FULL_SYNC_TIMESTAMP = "last_full_sync_timestamp";
- // Constant indicating that there has never been a full sync.
- public static final long NO_PRIOR_FULL_SYNC = -1;
- // Setting for how often retries should be done.
- private static final String SYNC_RETRY_INTERVAL = "sync_retry_interval";
- private static final long MAX_SYNC_RETRY_INTERVAL_MS = 86400000; // 24 hours
- private static final long DEFAULT_SYNC_RETRY_INTERVAL_MS = 900000; // 15 minutes
- public static void setVisualVoicemailEnabled(Context context, PhoneAccountHandle phoneAccount,
+ public static void setEnabled(Context context, PhoneAccountHandle phoneAccount,
boolean isEnabled) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- prefs.edit()
- .putBoolean(getVisualVoicemailSharedPrefsKey(IS_ENABLED_KEY, phoneAccount),
- isEnabled)
+ new VisualVoicemailPreferences(context, phoneAccount).edit()
+ .putBoolean(IS_ENABLED_KEY, isEnabled)
.apply();
}
- public static boolean isVisualVoicemailEnabled(Context context,
+ public static boolean isEnabled(Context context,
PhoneAccountHandle phoneAccount) {
if (phoneAccount == null) {
return false;
@@ -67,19 +49,18 @@
return false;
}
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- String key = getVisualVoicemailSharedPrefsKey(IS_ENABLED_KEY, phoneAccount);
- if (prefs.contains(key)) {
+ VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phoneAccount);
+ if (prefs.contains(IS_ENABLED_KEY)) {
// isEnableByDefault is a bit expensive, so don't use it as default value of
// getBoolean(). The "false" here should never be actually used.
- return prefs.getBoolean(key, false);
+ return prefs.getBoolean(IS_ENABLED_KEY, false);
}
return new OmtpVvmCarrierConfigHelper(context,
PhoneAccountHandleConverter.toSubId(phoneAccount)).isEnabledByDefault();
}
- public static boolean isVisualVoicemailEnabled(Phone phone) {
- return isVisualVoicemailEnabled(phone.getContext(),
+ public static boolean isEnabled(Phone phone) {
+ return isEnabled(phone.getContext(),
PhoneUtils.makePstnPhoneAccountHandle(phone));
}
@@ -89,82 +70,12 @@
* VVM app is installed. If the carrier VVM app is installed the client should give priority to
* it if the settings are not touched.
*/
- public static boolean isVisualVoicemailUserSet(Context context,
+ public static boolean isEnabledUserSet(Context context,
PhoneAccountHandle phoneAccount) {
if (phoneAccount == null) {
return false;
}
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- return prefs.contains(getVisualVoicemailSharedPrefsKey(IS_ENABLED_KEY, phoneAccount));
- }
-
- public static void setVisualVoicemailCredentialsFromStatusMessage(Context context,
- PhoneAccountHandle phoneAccount, StatusMessage message) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- SharedPreferences.Editor editor = prefs.edit();
-
- editor.putString(
- getVisualVoicemailSharedPrefsKey(OmtpConstants.IMAP_PORT, phoneAccount),
- message.getImapPort());
- editor.putString(
- getVisualVoicemailSharedPrefsKey(OmtpConstants.SERVER_ADDRESS, phoneAccount),
- message.getServerAddress());
- editor.putString(
- getVisualVoicemailSharedPrefsKey(OmtpConstants.IMAP_USER_NAME, phoneAccount),
- message.getImapUserName());
- editor.putString(
- getVisualVoicemailSharedPrefsKey(OmtpConstants.IMAP_PASSWORD, phoneAccount),
- message.getImapPassword());
- editor.commit();
- }
-
- public static String getVisualVoicemailCredentials(Context context, String key,
- PhoneAccountHandle phoneAccount) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- return prefs.getString(getVisualVoicemailSharedPrefsKey(key, phoneAccount), null);
- }
-
- public static long getVisualVoicemailRetryInterval(Context context,
- PhoneAccountHandle phoneAccount) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- return prefs.getLong(getVisualVoicemailSharedPrefsKey(SYNC_RETRY_INTERVAL, phoneAccount),
- DEFAULT_SYNC_RETRY_INTERVAL_MS);
- }
-
- public static void resetVisualVoicemailRetryInterval(Context context,
- PhoneAccountHandle phoneAccount) {
- setVisualVoicemailRetryInterval(context, phoneAccount, DEFAULT_SYNC_RETRY_INTERVAL_MS);
- }
-
- public static void setVisualVoicemailRetryInterval(Context context,
- PhoneAccountHandle phoneAccount, long interval) {
- SharedPreferences.Editor editor =
- PreferenceManager.getDefaultSharedPreferences(context).edit();
- editor.putLong(getVisualVoicemailSharedPrefsKey(SYNC_RETRY_INTERVAL, phoneAccount),
- Math.min(interval, MAX_SYNC_RETRY_INTERVAL_MS));
- editor.commit();
- }
-
- public static void setVisualVoicemailLastFullSyncTime(Context context,
- PhoneAccountHandle phoneAccount, long timestamp) {
- SharedPreferences.Editor editor =
- PreferenceManager.getDefaultSharedPreferences(context).edit();
- editor.putLong(getVisualVoicemailSharedPrefsKey(LAST_FULL_SYNC_TIMESTAMP, phoneAccount),
- timestamp);
- editor.commit();
-
- }
-
- public static long getVisualVoicemailLastFullSyncTime(Context context,
- PhoneAccountHandle phoneAccount) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- return prefs.getLong(
- getVisualVoicemailSharedPrefsKey(LAST_FULL_SYNC_TIMESTAMP, phoneAccount),
- NO_PRIOR_FULL_SYNC);
- }
-
- public static String getVisualVoicemailSharedPrefsKey(String key,
- PhoneAccountHandle phoneAccount) {
- return VISUAL_VOICEMAIL_SHARED_PREFS_KEY_PREFIX + key + "_" + phoneAccount.getId();
+ VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(context, phoneAccount);
+ return prefs.contains(IS_ENABLED_KEY);
}
}
diff --git a/src/com/android/phone/settings/VoicemailChangePinActivity.java b/src/com/android/phone/settings/VoicemailChangePinActivity.java
new file mode 100644
index 0000000..68cc621
--- /dev/null
+++ b/src/com/android/phone/settings/VoicemailChangePinActivity.java
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.phone.settings;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnDismissListener;
+import android.content.SharedPreferences;
+import android.net.Network;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.PreferenceManager;
+import android.telecom.PhoneAccountHandle;
+import android.text.Editable;
+import android.text.InputFilter;
+import android.text.InputFilter.LengthFilter;
+import android.text.TextWatcher;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+import android.widget.Toast;
+
+import com.android.phone.PhoneUtils;
+import com.android.phone.R;
+import com.android.phone.common.mail.MessagingException;
+import com.android.phone.vvm.omtp.OmtpConstants;
+import com.android.phone.vvm.omtp.OmtpConstants.ChangePinResult;
+import com.android.phone.vvm.omtp.OmtpEvents;
+import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
+import com.android.phone.vvm.omtp.VvmLog;
+import com.android.phone.vvm.omtp.imap.ImapHelper;
+import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback;
+
+/**
+ * Dialog to change the voicemail PIN. The TUI (Telephony User Interface) PIN is used when accessing
+ * traditional voicemail through phone call. The intent to launch this activity must contain {@link
+ * #EXTRA_PHONE_ACCOUNT_HANDLE}
+ */
+public class VoicemailChangePinActivity extends Activity implements OnClickListener,
+ OnEditorActionListener, TextWatcher {
+
+ private static final String TAG = "VmChangePinActivity";
+
+ public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle";
+
+ private static final String KEY_DEFAULT_OLD_PIN = "default_old_pin";
+
+ private static final int MESSAGE_HANDLE_RESULT = 1;
+
+ private PhoneAccountHandle mPhoneAccountHandle;
+ private OmtpVvmCarrierConfigHelper mConfig;
+
+ private int mPinMinLength;
+ private int mPinMaxLength;
+
+ private State mUiState = State.Initial;
+ private String mOldPin;
+ private String mFirstPin;
+
+ private ProgressDialog mProgressDialog;
+
+ private TextView mHeaderText;
+ private TextView mHintText;
+ private TextView mErrorText;
+ private EditText mPinEntry;
+ private Button mCancelButton;
+ private Button mNextButton;
+
+ private Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == MESSAGE_HANDLE_RESULT) {
+ mUiState.handleResult(VoicemailChangePinActivity.this, message.arg1);
+ }
+ }
+ };
+
+ private enum State {
+ /**
+ * Empty state to handle initial state transition. Will immediately switch into {@link
+ * #VerifyOldPin} if a default PIN has been set by the OMTP client, or {@link #EnterOldPin}
+ * if not.
+ */
+ Initial,
+ /**
+ * Prompt the user to enter old PIN. The PIN will be verified with the server before
+ * proceeding to {@link #EnterNewPin}.
+ */
+ EnterOldPin {
+ @Override
+ public void onEnter(VoicemailChangePinActivity activity) {
+ activity.setHeader(R.string.change_pin_enter_old_pin_header);
+ activity.mHintText.setText(R.string.change_pin_enter_old_pin_hint);
+ activity.mNextButton.setText(R.string.change_pin_continue_label);
+ activity.mErrorText.setText(null);
+ }
+
+ @Override
+ public void onInputChanged(VoicemailChangePinActivity activity) {
+ activity.setNextEnabled(activity.getCurrentPasswordInput().length() > 0);
+ }
+
+
+ @Override
+ public void handleNext(VoicemailChangePinActivity activity) {
+ activity.mOldPin = activity.getCurrentPasswordInput();
+ activity.verifyOldPin();
+ }
+
+ @Override
+ public void handleResult(VoicemailChangePinActivity activity,
+ @ChangePinResult int result) {
+ if (result == OmtpConstants.CHANGE_PIN_SUCCESS) {
+ activity.updateState(State.EnterNewPin);
+ } else {
+ CharSequence message = activity.getChangePinResultMessage(result);
+ activity.showError(message);
+ activity.mPinEntry.setText("");
+ }
+ }
+ },
+ /**
+ * The default old PIN is found. Show a blank screen while verifying with the server to make
+ * sure the PIN is still valid. If the PIN is still valid, proceed to {@link #EnterNewPin}.
+ * If not, the user probably changed the PIN through other means, proceed to {@link
+ * #EnterOldPin}. If any other issue caused the verifying to fail, show an error and exit.
+ */
+ VerifyOldPin {
+ @Override
+ public void onEnter(VoicemailChangePinActivity activity) {
+ activity.findViewById(android.R.id.content).setVisibility(View.INVISIBLE);
+ activity.verifyOldPin();
+ }
+
+ @Override
+ public void handleResult(VoicemailChangePinActivity activity,
+ @ChangePinResult int result) {
+ if (result == OmtpConstants.CHANGE_PIN_SUCCESS) {
+ activity.updateState(State.EnterNewPin);
+ } else if (result == OmtpConstants.CHANGE_PIN_SYSTEM_ERROR) {
+ activity.getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
+ activity.showError(activity.getString(R.string.change_pin_system_error),
+ new OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ activity.finish();
+ }
+ });
+ } else {
+ VvmLog.e(TAG, "invalid default old PIN: " + activity
+ .getChangePinResultMessage(result));
+ // If the default old PIN is rejected by the server, the PIN is probably changed
+ // through other means, or the generated pin is invalid
+ // Wipe the default old PIN so the old PIN input box will be shown to the user
+ // on the next time.
+ setDefaultOldPIN(activity, activity.mPhoneAccountHandle, null);
+ activity.mConfig.handleEvent(OmtpEvents.CONFIG_PIN_SET);
+ activity.updateState(State.EnterOldPin);
+ }
+ }
+
+ @Override
+ public void onLeave(VoicemailChangePinActivity activity) {
+ activity.findViewById(android.R.id.content).setVisibility(View.VISIBLE);
+ }
+ },
+ /**
+ * Let the user enter the new PIN and validate the format. Only length is enforced, PIN
+ * strength check relies on the server. After a valid PIN is entered, proceed to {@link
+ * #ConfirmNewPin}
+ */
+ EnterNewPin {
+ @Override
+ public void onEnter(VoicemailChangePinActivity activity) {
+ activity.mHeaderText.setText(R.string.change_pin_enter_new_pin_header);
+ activity.mNextButton.setText(R.string.change_pin_continue_label);
+ activity.mHintText.setText(
+ activity.getString(R.string.change_pin_enter_new_pin_hint,
+ activity.mPinMinLength, activity.mPinMaxLength));
+ }
+
+ @Override
+ public void onInputChanged(VoicemailChangePinActivity activity) {
+ String password = activity.getCurrentPasswordInput();
+ 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().equals(activity.mFirstPin)) {
+ activity.setNextEnabled(true);
+ activity.mErrorText.setText(null);
+ } else {
+ activity.setNextEnabled(false);
+ activity.mErrorText.setText(R.string.change_pin_confirm_pins_dont_match);
+ }
+ }
+
+ @Override
+ public void handleResult(VoicemailChangePinActivity activity,
+ @ChangePinResult int result) {
+ if (result == OmtpConstants.CHANGE_PIN_SUCCESS) {
+ // If the PIN change succeeded we no longer know what the old (current) PIN is.
+ // Wipe the default old PIN so the old PIN input box will be shown to the user
+ // on the next time.
+ setDefaultOldPIN(activity, activity.mPhoneAccountHandle, null);
+ activity.mConfig.handleEvent(OmtpEvents.CONFIG_PIN_SET);
+
+ activity.finish();
+
+ Toast.makeText(activity, activity.getString(R.string.change_pin_succeeded),
+ Toast.LENGTH_SHORT).show();
+ } else {
+ CharSequence message = activity.getChangePinResultMessage(result);
+ activity.showError(message);
+ if (result == OmtpConstants.CHANGE_PIN_MISMATCH) {
+ // Somehow the PIN has changed, prompt to enter the old PIN again.
+ activity.updateState(State.EnterOldPin);
+ } else {
+ // The new PIN failed to fulfil other restrictions imposed by the server.
+ activity.updateState(State.EnterNewPin);
+ }
+
+ }
+
+ }
+
+ @Override
+ public void handleNext(VoicemailChangePinActivity activity) {
+ activity.processPinChange(activity.mOldPin, activity.mFirstPin);
+ }
+ };
+
+ /**
+ * The activity has switched from another state to this one.
+ */
+ public void onEnter(VoicemailChangePinActivity activity) {
+ // Do nothing
+ }
+
+ /**
+ * The user has typed something into the PIN input field. Also called after {@link
+ * #onEnter(VoicemailChangePinActivity)}
+ */
+ public void onInputChanged(VoicemailChangePinActivity activity) {
+ // Do nothing
+ }
+
+ /**
+ * The asynchronous call to change the PIN on the server has returned.
+ */
+ public void handleResult(VoicemailChangePinActivity activity, @ChangePinResult int result) {
+ // Do nothing
+ }
+
+ /**
+ * The user has pressed the "next" button.
+ */
+ public void handleNext(VoicemailChangePinActivity activity) {
+ // Do nothing
+ }
+
+ /**
+ * The activity has switched from this state to another one.
+ */
+ public void onLeave(VoicemailChangePinActivity activity) {
+ // Do nothing
+ }
+
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mPhoneAccountHandle = getIntent().getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE);
+ mConfig = new OmtpVvmCarrierConfigHelper(this, mPhoneAccountHandle);
+ setContentView(R.layout.voicemail_change_pin);
+ setTitle(R.string.change_pin_title);
+
+ readPinLength();
+
+ View view = findViewById(android.R.id.content);
+
+ mCancelButton = (Button) view.findViewById(R.id.cancel_button);
+ mCancelButton.setOnClickListener(this);
+ mNextButton = (Button) view.findViewById(R.id.next_button);
+ mNextButton.setOnClickListener(this);
+
+ mPinEntry = (EditText) view.findViewById(R.id.pin_entry);
+ mPinEntry.setOnEditorActionListener(this);
+ mPinEntry.addTextChangedListener(this);
+ if (mPinMaxLength != 0) {
+ mPinEntry.setFilters(new InputFilter[]{new LengthFilter(mPinMaxLength)});
+ }
+
+
+ mHeaderText = (TextView) view.findViewById(R.id.headerText);
+ mHintText = (TextView) view.findViewById(R.id.hintText);
+ mErrorText = (TextView) view.findViewById(R.id.errorText);
+
+ migrateDefaultOldPin();
+
+ if (isDefaultOldPinSet(this, mPhoneAccountHandle)) {
+ mOldPin = getDefaultOldPin(this, mPhoneAccountHandle);
+ updateState(State.VerifyOldPin);
+ } else {
+ updateState(State.EnterOldPin);
+ }
+ }
+
+ /**
+ * Extracts the pin length requirement sent by the server with a STATUS SMS.
+ */
+ private void readPinLength() {
+ VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(this,
+ mPhoneAccountHandle);
+ // The OMTP pin length format is {min}-{max}
+ String[] lengths = preferences.getString(OmtpConstants.TUI_PASSWORD_LENGTH, "").split("-");
+ if (lengths.length == 2) {
+ try {
+ mPinMinLength = Integer.parseInt(lengths[0]);
+ mPinMaxLength = Integer.parseInt(lengths[1]);
+ } catch (NumberFormatException e) {
+ mPinMinLength = 0;
+ mPinMaxLength = 0;
+ }
+ } else {
+ mPinMinLength = 0;
+ mPinMaxLength = 0;
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ updateState(mUiState);
+
+ }
+
+ public void handleNext() {
+ if (mPinEntry.length() == 0) {
+ return;
+ }
+ mUiState.handleNext(this);
+ }
+
+ public void onClick(View v) {
+ switch (v.getId()) {
+ case R.id.next_button:
+ handleNext();
+ break;
+
+ case R.id.cancel_button:
+ finish();
+ break;
+ }
+ }
+
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ // Check if this was the result of hitting the enter or "done" key
+ if (actionId == EditorInfo.IME_NULL
+ || actionId == EditorInfo.IME_ACTION_DONE
+ || actionId == EditorInfo.IME_ACTION_NEXT) {
+ handleNext();
+ return true;
+ }
+ return false;
+ }
+
+ public void afterTextChanged(Editable s) {
+ mUiState.onInputChanged(this);
+ }
+
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // Do nothing
+ }
+
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ // Do nothing
+ }
+
+ /**
+ * After replacing the default PIN with a random PIN, call this to store the random PIN. The
+ * stored PIN will be automatically entered when the user attempts to change the PIN.
+ */
+ public static void setDefaultOldPIN(Context context, PhoneAccountHandle phoneAccountHandle,
+ String pin) {
+ new VisualVoicemailPreferences(context, phoneAccountHandle)
+ .edit().putString(KEY_DEFAULT_OLD_PIN, pin).apply();
+ }
+
+ public static boolean isDefaultOldPinSet(Context context,
+ PhoneAccountHandle phoneAccountHandle) {
+ return getDefaultOldPin(context, phoneAccountHandle) != null;
+ }
+
+ private static String getDefaultOldPin(Context context, PhoneAccountHandle phoneAccountHandle) {
+ return new VisualVoicemailPreferences(context, phoneAccountHandle)
+ .getString(KEY_DEFAULT_OLD_PIN);
+ }
+
+ /**
+ * Storage location has changed mid development. Migrate from the old location to avoid losing
+ * tester's default old pin.
+ */
+ private void migrateDefaultOldPin() {
+ String key = "voicemail_pin_dialog_preference_"
+ + PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccountHandle)
+ + "_default_old_pin";
+
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+ if (preferences.contains(key)) {
+ setDefaultOldPIN(this, mPhoneAccountHandle, preferences.getString(key, null));
+ preferences.edit().putString(key, null).apply();
+ }
+ }
+
+ private String getCurrentPasswordInput() {
+ return mPinEntry.getText().toString();
+ }
+
+ private void updateState(State state) {
+ State previousState = mUiState;
+ mUiState = state;
+ if (previousState != state) {
+ previousState.onLeave(this);
+ mPinEntry.setText("");
+ mUiState.onEnter(this);
+ }
+ mUiState.onInputChanged(this);
+ }
+
+ /**
+ * Validates PIN and returns a message to display if PIN fails test.
+ *
+ * @param password the raw password the user typed in
+ * @return error message to show to user or null if password is OK
+ */
+ private CharSequence validatePassword(String password) {
+ if (mPinMinLength == 0 && mPinMaxLength == 0) {
+ // Invalid length requirement is sent by the server, just accept anything and let the
+ // server decide.
+ return null;
+ }
+
+ if (password.length() < mPinMinLength) {
+ return getString(R.string.vm_change_pin_error_too_short);
+ }
+ return null;
+ }
+
+ private void setHeader(int text) {
+ mHeaderText.setText(text);
+ mPinEntry.setContentDescription(mHeaderText.getText());
+ }
+
+ /**
+ * Get the corresponding message for the {@link ChangePinResult}.<code>result</code> must not
+ * {@link OmtpConstants#CHANGE_PIN_SUCCESS}
+ */
+ private CharSequence getChangePinResultMessage(@ChangePinResult int result) {
+ switch (result) {
+ case OmtpConstants.CHANGE_PIN_TOO_SHORT:
+ return getString(R.string.vm_change_pin_error_too_short);
+ case OmtpConstants.CHANGE_PIN_TOO_LONG:
+ return getString(R.string.vm_change_pin_error_too_long);
+ case OmtpConstants.CHANGE_PIN_TOO_WEAK:
+ return getString(R.string.vm_change_pin_error_too_weak);
+ case OmtpConstants.CHANGE_PIN_INVALID_CHARACTER:
+ return getString(R.string.vm_change_pin_error_invalid);
+ case OmtpConstants.CHANGE_PIN_MISMATCH:
+ return getString(R.string.vm_change_pin_error_mismatch);
+ case OmtpConstants.CHANGE_PIN_SYSTEM_ERROR:
+ return getString(R.string.vm_change_pin_error_system_error);
+ default:
+ VvmLog.wtf(TAG, "Unexpected ChangePinResult " + result);
+ return null;
+ }
+ }
+
+ private void verifyOldPin() {
+ processPinChange(mOldPin, mOldPin);
+ }
+
+ private void setNextEnabled(boolean enabled) {
+ mNextButton.setEnabled(enabled);
+ }
+
+
+ private void showError(CharSequence message) {
+ showError(message, null);
+ }
+
+ private void showError(CharSequence message, @Nullable OnDismissListener callback) {
+ new AlertDialog.Builder(this)
+ .setMessage(message)
+ .setPositiveButton(android.R.string.ok, null)
+ .setOnDismissListener(callback)
+ .show();
+ }
+
+ /**
+ * Asynchronous call to change the PIN on the server.
+ */
+ private void processPinChange(String oldPin, String newPin) {
+ mProgressDialog = new ProgressDialog(this);
+ mProgressDialog.setCancelable(false);
+ mProgressDialog.setMessage(getString(R.string.vm_change_pin_progress_message));
+ mProgressDialog.show();
+
+ ChangePinNetworkRequestCallback callback = new ChangePinNetworkRequestCallback(oldPin,
+ newPin);
+ callback.requestNetwork();
+ }
+
+ private class ChangePinNetworkRequestCallback extends VvmNetworkRequestCallback {
+
+ private final String mOldPin;
+ private final String mNewPin;
+
+ public ChangePinNetworkRequestCallback(String oldPin, String newPin) {
+ super(mConfig, mPhoneAccountHandle);
+ mOldPin = oldPin;
+ mNewPin = newPin;
+ }
+
+ @Override
+ public void onAvailable(Network network) {
+ super.onAvailable(network);
+ try (ImapHelper helper =
+ new ImapHelper(VoicemailChangePinActivity.this, mPhoneAccountHandle, network)){
+
+ @ChangePinResult int result =
+ helper.changePin(mOldPin, mNewPin);
+ sendResult(result);
+ } catch (MessagingException e) {
+ sendResult(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR);
+ }
+ }
+
+ @Override
+ public void onFailed(String reason) {
+ super.onFailed(reason);
+ sendResult(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR);
+ }
+
+ private void sendResult(@ChangePinResult int result) {
+ mProgressDialog.dismiss();
+ mHandler.obtainMessage(MESSAGE_HANDLE_RESULT, result, 0).sendToTarget();
+ releaseNetwork();
+ }
+ }
+
+}
diff --git a/src/com/android/phone/settings/VoicemailChangePinDialogPreference.java b/src/com/android/phone/settings/VoicemailChangePinDialogPreference.java
deleted file mode 100644
index 3411228..0000000
--- a/src/com/android/phone/settings/VoicemailChangePinDialogPreference.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.phone.settings;
-
-import android.annotation.Nullable;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.net.Network;
-import android.preference.DialogPreference;
-import android.preference.PreferenceManager;
-import android.telecom.PhoneAccountHandle;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.widget.EditText;
-
-import com.android.phone.PhoneUtils;
-import com.android.phone.R;
-import com.android.phone.common.mail.MessagingException;
-import com.android.phone.vvm.omtp.OmtpConstants;
-import com.android.phone.vvm.omtp.OmtpConstants.ChangePinResult;
-import com.android.phone.vvm.omtp.OmtpEvents;
-import com.android.phone.vvm.omtp.imap.ImapHelper;
-import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback;
-
-/**
- * Dialog to change the voicemail PIN. The TUI PIN is used when accessing traditional voicemail through
- * phone call.
- */
-public class VoicemailChangePinDialogPreference extends DialogPreference {
-
- private static final String TAG = "VmChangePinDialog";
-
- private EditText mOldPin;
- private EditText mNewPin;
- private PhoneAccountHandle mPhoneAccountHandle;
-
- private ProgressDialog mProgressDialog;
-
- private static final String DEFAULT_OLD_PIN_KEY = "default_old_pin";
-
- public VoicemailChangePinDialogPreference(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public VoicemailChangePinDialogPreference(Context context, AttributeSet attrs,
- int defStyle) {
- super(context, attrs, defStyle);
- }
-
- @Override
- protected View onCreateDialogView() {
- setDialogLayoutResource(R.layout.voicemail_dialog_change_pin);
-
- View dialog = super.onCreateDialogView();
-
- mOldPin = (EditText) dialog.findViewById(R.id.vm_old_pin);
- mNewPin = (EditText) dialog.findViewById(R.id.vm_new_pin);
- String defaultOldPin = getDefaultOldPin(getContext(), mPhoneAccountHandle);
- if (defaultOldPin != null) {
- // If the old PIN was set by the system, read its' value and hide the input box.
- mOldPin.setText(defaultOldPin);
- mOldPin.setVisibility(View.GONE);
- dialog.findViewById(R.id.vm_old_pin_label).setVisibility(View.GONE);
- }
- return dialog;
- }
-
- @Override
- protected void onDialogClosed(boolean positiveResult) {
- if (positiveResult) {
- processPinChange();
- }
- super.onDialogClosed(positiveResult);
- }
-
- public VoicemailChangePinDialogPreference setPhoneAccountHandle(PhoneAccountHandle handle) {
- mPhoneAccountHandle = handle;
- return this;
- }
-
- @Nullable
- public static String getDefaultOldPin(Context context, PhoneAccountHandle handle) {
- return getSharedPreference(context)
- .getString(getPerPhoneAccountKey(handle, DEFAULT_OLD_PIN_KEY), null);
- }
-
- public static void setDefaultOldPIN(Context context, PhoneAccountHandle handle,
- @Nullable String pin) {
- SharedPreferences preferences = getSharedPreference(context);
- preferences.edit()
- .putString(getPerPhoneAccountKey(handle, DEFAULT_OLD_PIN_KEY), pin)
- .apply();
- }
-
- private static String getPerPhoneAccountKey(PhoneAccountHandle handle, String key) {
- return "voicemail_pin_dialog_preference_"
- + PhoneUtils.getSubIdForPhoneAccountHandle(handle) + "_" + key;
- }
-
- private static SharedPreferences getSharedPreference(Context context) {
- return PreferenceManager.getDefaultSharedPreferences(context);
- }
-
- private void processPinChange() {
- mProgressDialog = new ProgressDialog(getContext());
- mProgressDialog.setCancelable(false);
- mProgressDialog.setMessage(getContext().getString(R.string.vm_change_pin_progress_message));
- mProgressDialog.show();
-
- ChangePinNetworkRequestCallback callback = new ChangePinNetworkRequestCallback();
- callback.requestNetwork();
- }
-
- private void finishPinChange() {
- mProgressDialog.dismiss();
- }
-
- private void showError(@ChangePinResult int result) {
- if (result != OmtpConstants.CHANGE_PIN_SUCCESS) {
- CharSequence message;
- switch (result) {
- case OmtpConstants.CHANGE_PIN_TOO_SHORT:
- message = getContext().getString(R.string.vm_change_pin_error_too_short);
- break;
- case OmtpConstants.CHANGE_PIN_TOO_LONG:
- message = getContext().getString(R.string.vm_change_pin_error_too_long);
- break;
-
- case OmtpConstants.CHANGE_PIN_TOO_WEAK:
- message = getContext().getString(R.string.vm_change_pin_error_too_weak);
- break;
- case OmtpConstants.CHANGE_PIN_INVALID_CHARACTER:
- message = getContext().getString(R.string.vm_change_pin_error_invalid);
- break;
- case OmtpConstants.CHANGE_PIN_MISMATCH:
- message = getContext().getString(R.string.vm_change_pin_error_mismatch);
- break;
- case OmtpConstants.CHANGE_PIN_SYSTEM_ERROR:
- message = getContext().getString(R.string.vm_change_pin_error_system_error);
- break;
- default:
- Log.wtf(TAG, "Unexpected ChangePinResult " + result);
- return;
- }
- new AlertDialog.Builder(getContext())
- .setMessage(message)
- .setPositiveButton(android.R.string.ok, null)
- .show();
- }
- }
-
- private class ChangePinNetworkRequestCallback extends VvmNetworkRequestCallback {
-
- public ChangePinNetworkRequestCallback() {
- super(getContext(), mPhoneAccountHandle);
- }
-
- @Override
- public void onAvailable(Network network) {
- super.onAvailable(network);
- try (ImapHelper helper = new ImapHelper(getContext(), mPhoneAccountHandle, network)) {
- @ChangePinResult int result =
- helper.changePin(mOldPin.getText().toString(),
- mNewPin.getText().toString());
- finishPinChange();
- if (result != OmtpConstants.CHANGE_PIN_SUCCESS) {
- showError(result);
- }
-
- if (result == OmtpConstants.CHANGE_PIN_SUCCESS
- || result == OmtpConstants.CHANGE_PIN_MISMATCH) {
- // If the PIN change succeeded we no longer know what the old (current) PIN is.
- // If the default old PIN is rejected by the server, the PIN is probably changed
- // through other means.
- // Wipe the default old PIN so the old PIN input box will be shown to the user
- // on the next time.
- setDefaultOldPIN(mContext, mPhoneAccountHandle, null);
- helper.handleEvent(OmtpEvents.CONFIG_PIN_SET);
- }
- } catch (MessagingException e) {
- finishPinChange();
- showError(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR);
- }
-
- }
-
- @Override
- public void onFailed(String reason) {
- super.onFailed(reason);
- finishPinChange();
- showError(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR);
- }
- }
-}
diff --git a/src/com/android/phone/settings/VoicemailSettingsActivity.java b/src/com/android/phone/settings/VoicemailSettingsActivity.java
index b10af6e..af4f2ad 100644
--- a/src/com/android/phone/settings/VoicemailSettingsActivity.java
+++ b/src/com/android/phone/settings/VoicemailSettingsActivity.java
@@ -205,7 +205,7 @@
private VoicemailRingtonePreference mVoicemailNotificationRingtone;
private CheckBoxPreference mVoicemailNotificationVibrate;
private SwitchPreference mVoicemailVisualVoicemail;
- private VoicemailChangePinDialogPreference mVoicemailChangePinPreference;
+ private Preference mVoicemailChangePinPreference;
//*********************************************************************************************
// Preference Activity Methods
@@ -266,18 +266,24 @@
mVoicemailVisualVoicemail = (SwitchPreference) findPreference(
getResources().getString(R.string.voicemail_visual_voicemail_key));
- mVoicemailChangePinPreference = (VoicemailChangePinDialogPreference) findPreference(
+ mVoicemailChangePinPreference = findPreference(
getResources().getString(R.string.voicemail_change_pin_key));
- mVoicemailChangePinPreference
- .setPhoneAccountHandle(PhoneUtils.makePstnPhoneAccountHandle(mPhone));
+ PhoneAccountHandle phoneAccountHandle = PhoneUtils.makePstnPhoneAccountHandle(mPhone);
+ Intent changePinIntent = new Intent(new Intent(this, VoicemailChangePinActivity.class));
+ changePinIntent.putExtra(VoicemailChangePinActivity.EXTRA_PHONE_ACCOUNT_HANDLE,
+ phoneAccountHandle);
+
+ mVoicemailChangePinPreference.setIntent(changePinIntent);
+ if (VoicemailChangePinActivity.isDefaultOldPinSet(this, phoneAccountHandle)) {
+ mVoicemailChangePinPreference.setTitle(R.string.voicemail_set_pin_dialog_title);
+ } else {
+ mVoicemailChangePinPreference.setTitle(R.string.voicemail_change_pin_dialog_title);
+ }
if (mOmtpVvmCarrierConfigHelper.isValid()) {
mVoicemailVisualVoicemail.setOnPreferenceChangeListener(this);
mVoicemailVisualVoicemail.setChecked(
- VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(mPhone));
-
- mVoicemailChangePinPreference
- .setPhoneAccountHandle(PhoneUtils.makePstnPhoneAccountHandle(mPhone));
+ VisualVoicemailSettingsUtil.isEnabled(mPhone));
} else {
prefSet.removePreference(mVoicemailVisualVoicemail);
prefSet.removePreference(mVoicemailChangePinPreference);
@@ -405,7 +411,7 @@
boolean isEnabled = (boolean) objValue;
PhoneAccountHandle handle = PhoneUtils.makePstnPhoneAccountHandle(mPhone);
VisualVoicemailSettingsUtil
- .setVisualVoicemailEnabled(mPhone.getContext(), handle, isEnabled);
+ .setEnabled(mPhone.getContext(), handle, isEnabled);
PreferenceScreen prefSet = getPreferenceScreen();
if (isEnabled) {
OmtpVvmSourceManager.getInstance(mPhone.getContext()).addPhoneStateListener(mPhone);
diff --git a/src/com/android/phone/vvm/omtp/OmtpConstants.java b/src/com/android/phone/vvm/omtp/OmtpConstants.java
index 8975b59..3f5722f 100644
--- a/src/com/android/phone/vvm/omtp/OmtpConstants.java
+++ b/src/com/android/phone/vvm/omtp/OmtpConstants.java
@@ -125,6 +125,7 @@
public static final String SERVER_ADDRESS = "srv";
/** Phone number to access voicemails through Telephony User Interface */
public static final String TUI_ACCESS_NUMBER = "tui";
+ public static final String TUI_PASSWORD_LENGTH = "pw_len";
/** Number to send client origination SMS */
public static final String CLIENT_SMS_DESTINATION_NUMBER = "dn";
public static final String IMAP_PORT = "ipt";
diff --git a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
index e8ae403..04fb8e5 100644
--- a/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
+++ b/src/com/android/phone/vvm/omtp/OmtpVvmCarrierConfigHelper.java
@@ -33,6 +33,7 @@
import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocol;
import com.android.phone.vvm.omtp.protocol.VisualVoicemailProtocolFactory;
import com.android.phone.vvm.omtp.sms.StatusMessage;
+import com.android.phone.vvm.omtp.utils.PhoneAccountHandleConverter;
import java.util.Arrays;
import java.util.Set;
@@ -96,6 +97,8 @@
private final VisualVoicemailProtocol mProtocol;
private final PersistableBundle mTelephonyConfig;
+ private PhoneAccountHandle mPhoneAccountHandle;
+
public OmtpVvmCarrierConfigHelper(Context context, int subId) {
mContext = context;
mSubId = subId;
@@ -110,6 +113,11 @@
mProtocol = VisualVoicemailProtocolFactory.create(mVvmType);
}
+ public OmtpVvmCarrierConfigHelper(Context context, PhoneAccountHandle handle) {
+ this(context, PhoneAccountHandleConverter.toSubId(handle));
+ mPhoneAccountHandle = handle;
+ }
+
@VisibleForTesting
OmtpVvmCarrierConfigHelper(PersistableBundle carrierConfig,
PersistableBundle telephonyConfig) {
@@ -129,6 +137,13 @@
return mSubId;
}
+ public PhoneAccountHandle getPhoneAccountHandle() {
+ if (mPhoneAccountHandle == null) {
+ mPhoneAccountHandle = PhoneAccountHandleConverter.fromSubId(mSubId);
+ }
+ return mPhoneAccountHandle;
+ }
+
/**
* return whether the carrier's visual voicemail is supported, with KEY_VVM_TYPE_STRING set as a
* known protocol.
diff --git a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
index f22711a..375109d 100644
--- a/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
+++ b/src/com/android/phone/vvm/omtp/SimChangeReceiver.java
@@ -88,7 +88,7 @@
if (carrierConfigHelper.isValid()) {
PhoneAccountHandle phoneAccount = PhoneAccountHandleConverter.fromSubId(subId);
- if (VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(context, phoneAccount)) {
+ if (VisualVoicemailSettingsUtil.isEnabled(context, phoneAccount)) {
VvmLog.i(TAG, "Sim state or carrier config changed: requesting"
+ " activation for " + subId);
diff --git a/src/com/android/phone/vvm/omtp/VisualVoicemailPreferences.java b/src/com/android/phone/vvm/omtp/VisualVoicemailPreferences.java
new file mode 100644
index 0000000..be51ea9
--- /dev/null
+++ b/src/com/android/phone/vvm/omtp/VisualVoicemailPreferences.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.phone.vvm.omtp;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.telecom.PhoneAccountHandle;
+
+import com.android.phone.NeededForTesting;
+
+import java.util.Set;
+
+/**
+ * Save visual voicemail values in shared preferences to be retrieved later. Because a voicemail
+ * source is tied 1:1 to a phone account, the phone account handle is used in the key for each
+ * voicemail source and the associated data.
+ */
+public class VisualVoicemailPreferences {
+
+ private static final String VISUAL_VOICEMAIL_SHARED_PREFS_KEY_PREFIX =
+ "visual_voicemail_";
+
+ private final SharedPreferences mPreferences;
+ private final PhoneAccountHandle mPhoneAccountHandle;
+
+ public VisualVoicemailPreferences(Context context, PhoneAccountHandle phoneAccountHandle) {
+ mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ mPhoneAccountHandle = phoneAccountHandle;
+ }
+
+ public class Editor {
+
+ private final SharedPreferences.Editor mEditor;
+
+ private Editor() {
+ mEditor = mPreferences.edit();
+ }
+
+ public void apply() {
+ mEditor.apply();
+ }
+
+ public Editor putBoolean(String key, boolean value) {
+ mEditor.putBoolean(getKey(key), value);
+ return this;
+ }
+
+ @NeededForTesting
+ public Editor putFloat(String key, float value) {
+ mEditor.putFloat(getKey(key), value);
+ return this;
+ }
+
+ public Editor putInt(String key, int value) {
+ mEditor.putInt(getKey(key), value);
+ return this;
+ }
+
+ @NeededForTesting
+ public Editor putLong(String key, long value) {
+ mEditor.putLong(getKey(key), value);
+ return this;
+ }
+
+ public Editor putString(String key, String value) {
+ mEditor.putString(getKey(key), value);
+ return this;
+ }
+
+ @NeededForTesting
+ public Editor putStringSet(String key, Set<String> value) {
+ mEditor.putStringSet(getKey(key), value);
+ return this;
+ }
+ }
+
+ public Editor edit() {
+ return new Editor();
+ }
+
+ public boolean getBoolean(String key, boolean defValue) {
+ return getValue(key, defValue);
+ }
+
+ @NeededForTesting
+ public float getFloat(String key, float defValue) {
+ return getValue(key, defValue);
+ }
+
+ public int getInt(String key, int defValue) {
+ return getValue(key, defValue);
+ }
+
+ @NeededForTesting
+ public long getLong(String key, long defValue) {
+ return getValue(key, defValue);
+ }
+
+ public String getString(String key, String defValue) {
+ return getValue(key, defValue);
+ }
+
+ @Nullable
+ public String getString(String key) {
+ return getValue(key, null);
+ }
+
+ @NeededForTesting
+ public Set<String> getStringSet(String key, Set<String> defValue) {
+ return getValue(key, defValue);
+ }
+
+ public boolean contains(String key) {
+ return mPreferences.contains(getKey(key));
+ }
+
+ private <T> T getValue(String key, T defValue) {
+ if (!contains(key)) {
+ return defValue;
+ }
+ Object object = mPreferences.getAll().get(getKey(key));
+ if (object == null) {
+ return defValue;
+ }
+ return (T) object;
+ }
+
+ private String getKey(String key) {
+ return VISUAL_VOICEMAIL_SHARED_PREFS_KEY_PREFIX + key + "_" + mPhoneAccountHandle.getId();
+ }
+}
diff --git a/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java b/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
index 8a0495b..7c20065 100644
--- a/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
+++ b/src/com/android/phone/vvm/omtp/VvmPackageInstallReceiver.java
@@ -48,7 +48,7 @@
OmtpVvmSourceManager vvmSourceManager = OmtpVvmSourceManager.getInstance(context);
Set<PhoneAccountHandle> phoneAccounts = vvmSourceManager.getOmtpVvmSources();
for (PhoneAccountHandle phoneAccount : phoneAccounts) {
- if (VisualVoicemailSettingsUtil.isVisualVoicemailUserSet(context, phoneAccount)) {
+ if (VisualVoicemailSettingsUtil.isEnabledUserSet(context, phoneAccount)) {
// Skip the check if this voicemail source's setting is overridden by the user.
continue;
}
diff --git a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
index 908d0f7..4db02d0 100644
--- a/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
+++ b/src/com/android/phone/vvm/omtp/imap/ImapHelper.java
@@ -16,11 +16,9 @@
package com.android.phone.vvm.omtp.imap;
import android.content.Context;
-import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
-import android.preference.PreferenceManager;
import android.provider.VoicemailContract;
import android.telecom.PhoneAccountHandle;
import android.telecom.Voicemail;
@@ -44,11 +42,11 @@
import com.android.phone.common.mail.store.imap.ImapConstants;
import com.android.phone.common.mail.store.imap.ImapResponse;
import com.android.phone.common.mail.utils.LogUtils;
-import com.android.phone.settings.VisualVoicemailSettingsUtil;
import com.android.phone.vvm.omtp.OmtpConstants;
import com.android.phone.vvm.omtp.OmtpConstants.ChangePinResult;
import com.android.phone.vvm.omtp.OmtpEvents;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
import com.android.phone.vvm.omtp.VvmLog;
import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService.TranscriptionFetchedCallback;
@@ -78,7 +76,7 @@
private final PhoneAccountHandle mPhoneAccount;
private final Network mNetwork;
- SharedPreferences mPrefs;
+ VisualVoicemailPreferences mPrefs;
private static final String PREF_KEY_QUOTA_OCCUPIED = "quota_occupied_";
private static final String PREF_KEY_QUOTA_TOTAL = "quota_total_";
@@ -93,18 +91,16 @@
mNetwork = network;
mConfig = new OmtpVvmCarrierConfigHelper(context,
PhoneUtils.getSubIdForPhoneAccountHandle(phoneAccount));
+ mPrefs = new VisualVoicemailPreferences(context,
+ phoneAccount);
try {
TempDirectory.setTempDirectory(context);
- String username = VisualVoicemailSettingsUtil.getVisualVoicemailCredentials(context,
- OmtpConstants.IMAP_USER_NAME, phoneAccount);
- String password = VisualVoicemailSettingsUtil.getVisualVoicemailCredentials(context,
- OmtpConstants.IMAP_PASSWORD, phoneAccount);
- String serverName = VisualVoicemailSettingsUtil.getVisualVoicemailCredentials(context,
- OmtpConstants.SERVER_ADDRESS, phoneAccount);
+ String username = mPrefs.getString(OmtpConstants.IMAP_USER_NAME, null);
+ String password = mPrefs.getString(OmtpConstants.IMAP_PASSWORD, null);
+ String serverName = mPrefs.getString(OmtpConstants.SERVER_ADDRESS, null);
int port = Integer.parseInt(
- VisualVoicemailSettingsUtil.getVisualVoicemailCredentials(context,
- OmtpConstants.IMAP_PORT, phoneAccount));
+ mPrefs.getString(OmtpConstants.IMAP_PORT, null));
int auth = ImapStore.FLAG_NONE;
int sslPort = mConfig.getSslPort();
@@ -120,11 +116,10 @@
LogUtils.w(TAG, "Could not parse port number");
}
- mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
- mQuotaOccupied = mPrefs.getInt(getSharedPrefsKey(PREF_KEY_QUOTA_OCCUPIED),
- VoicemailContract.Status.QUOTA_UNAVAILABLE);
- mQuotaTotal = mPrefs.getInt(getSharedPrefsKey(PREF_KEY_QUOTA_TOTAL),
- VoicemailContract.Status.QUOTA_UNAVAILABLE);
+ mQuotaOccupied = mPrefs
+ .getInt(PREF_KEY_QUOTA_OCCUPIED, VoicemailContract.Status.QUOTA_UNAVAILABLE);
+ mQuotaTotal = mPrefs
+ .getInt(PREF_KEY_QUOTA_TOTAL, VoicemailContract.Status.QUOTA_UNAVAILABLE);
}
@Override
@@ -500,8 +495,8 @@
.setQuota(mQuotaOccupied, mQuotaTotal)
.apply();
mPrefs.edit()
- .putInt(getSharedPrefsKey(PREF_KEY_QUOTA_OCCUPIED), mQuotaOccupied)
- .putInt(getSharedPrefsKey(PREF_KEY_QUOTA_TOTAL), mQuotaTotal)
+ .putInt(PREF_KEY_QUOTA_OCCUPIED, mQuotaOccupied)
+ .putInt(PREF_KEY_QUOTA_TOTAL, mQuotaTotal)
.apply();
VvmLog.v(TAG, "Quota changed to " + mQuotaOccupied + "/" + mQuotaTotal);
}
@@ -702,8 +697,4 @@
IoUtils.closeQuietly(out);
}
}
-
- private String getSharedPrefsKey(String key) {
- return VisualVoicemailSettingsUtil.getVisualVoicemailSharedPrefsKey(key, mPhoneAccount);
- }
}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java
index 8eacb99..3645407 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3EventHandler.java
@@ -22,7 +22,7 @@
import android.util.Log;
import com.android.phone.VoicemailStatus;
-import com.android.phone.settings.VoicemailChangePinDialogPreference;
+import com.android.phone.settings.VoicemailChangePinActivity;
import com.android.phone.vvm.omtp.DefaultOmtpEventHandler;
import com.android.phone.vvm.omtp.OmtpEvents;
import com.android.phone.vvm.omtp.OmtpEvents.Type;
@@ -116,7 +116,7 @@
case CONFIG_REQUEST_STATUS_SUCCESS:
PhoneAccountHandle handle = PhoneAccountHandleConverter
.fromSubId(config.getSubId());
- if (VoicemailChangePinDialogPreference.getDefaultOldPin(context, handle) == null) {
+ if (VoicemailChangePinActivity.isDefaultOldPinSet(context, handle)) {
return false;
} else {
postError(context, config, PIN_NOT_SET);
diff --git a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
index fadf104..d15786f 100644
--- a/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
+++ b/src/com/android/phone/vvm/omtp/protocol/Vvm3Protocol.java
@@ -25,10 +25,11 @@
import com.android.phone.common.mail.MessagingException;
import com.android.phone.settings.VisualVoicemailSettingsUtil;
-import com.android.phone.settings.VoicemailChangePinDialogPreference;
+import com.android.phone.settings.VoicemailChangePinActivity;
import com.android.phone.vvm.omtp.OmtpConstants;
import com.android.phone.vvm.omtp.OmtpEvents;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
import com.android.phone.vvm.omtp.VvmLog;
import com.android.phone.vvm.omtp.imap.ImapHelper;
import com.android.phone.vvm.omtp.sms.OmtpMessageSender;
@@ -61,7 +62,7 @@
private static String VVM3_VM_LANGUAGE_ENGLISH_STANDARD_NO_GUEST_PROMPTS = "5";
private static String VVM3_VM_LANGUAGE_SPANISH_STANDARD_NO_GUEST_PROMPTS = "6";
- private static final int PIN_LENGTH = 6;
+ private static final int DEFAULT_PIN_LENGTH = 6;
@Override
public void startActivation(OmtpVvmCarrierConfigHelper config) {
@@ -92,13 +93,16 @@
new Vvm3Subscriber(phoneAccountHandle, config, data).subscribe();
} else if (OmtpConstants.SUBSCRIBER_NEW.equals(message.getProvisioningStatus())) {
VvmLog.i(TAG, "setting up new user");
- VisualVoicemailSettingsUtil.setVisualVoicemailCredentialsFromStatusMessage(
- config.getContext(), phoneAccountHandle, message);
+ // Save the IMAP credentials in preferences so they are persistent and can be retrieved.
+ VisualVoicemailPreferences prefs =
+ new VisualVoicemailPreferences(config.getContext(), phoneAccountHandle);
+ message.putStatus(prefs.edit()).apply();
+
startProvisionNewUser(phoneAccountHandle, config, message);
} else if (OmtpConstants.SUBSCRIBER_PROVISIONED.equals(message.getProvisioningStatus())) {
VvmLog.i(TAG, "User provisioned but not activated, disabling VVM");
VisualVoicemailSettingsUtil
- .setVisualVoicemailEnabled(config.getContext(), phoneAccountHandle, false);
+ .setEnabled(config.getContext(), phoneAccountHandle, false);
} else if (OmtpConstants.SUBSCRIBER_BLOCKED.equals(message.getProvisioningStatus())) {
VvmLog.i(TAG, "User blocked");
config.handleEvent(OmtpEvents.VVM3_SUBSCRIBER_BLOCKED);
@@ -192,16 +196,14 @@
return false;
}
- if (VoicemailChangePinDialogPreference.getDefaultOldPin(mContext, mPhoneAccount)
- != null) {
+ if (VoicemailChangePinActivity.isDefaultOldPinSet(mContext, mPhoneAccount)) {
// The pin was already set
VvmLog.i(TAG, "PIN already set");
return true;
}
- String newPin = generatePin();
+ String newPin = generatePin(getMinimumPinLength(mContext, mPhoneAccount));
if (helper.changePin(defaultPin, newPin) == OmtpConstants.CHANGE_PIN_SUCCESS) {
- VoicemailChangePinDialogPreference
- .setDefaultOldPIN(mContext, mPhoneAccount, newPin);
+ VoicemailChangePinActivity.setDefaultOldPIN(mContext, mPhoneAccount, newPin);
helper.handleEvent(OmtpEvents.CONFIG_DEFAULT_PIN_REPLACED);
}
VvmLog.i(TAG, "new user: PIN set");
@@ -227,10 +229,25 @@
}
}
- private static String generatePin() {
+ private static int getMinimumPinLength(Context context, PhoneAccountHandle phoneAccountHandle) {
+ VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(context,
+ phoneAccountHandle);
+ // The OMTP pin length format is {min}-{max}
+ String[] lengths = preferences.getString(OmtpConstants.TUI_PASSWORD_LENGTH, "").split("-");
+ if (lengths.length == 2) {
+ try {
+ return Integer.parseInt(lengths[0]);
+ } catch (NumberFormatException e) {
+ return DEFAULT_PIN_LENGTH;
+ }
+ }
+ return DEFAULT_PIN_LENGTH;
+ }
+
+ private static String generatePin(int length) {
SecureRandom random = new SecureRandom();
- // TODO(b/29102412): generate base on the length requirement from the server
- return String.format("%010d", Math.abs(random.nextLong())).substring(0, PIN_LENGTH);
+ return String.format(Locale.US, "%010d", Math.abs(random.nextLong()))
+ .substring(0, length);
}
}
diff --git a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
index 5bf7900..30ea43d 100644
--- a/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
+++ b/src/com/android/phone/vvm/omtp/sms/OmtpMessageReceiver.java
@@ -31,6 +31,7 @@
import com.android.phone.vvm.omtp.OmtpConstants;
import com.android.phone.vvm.omtp.OmtpEvents;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
import com.android.phone.vvm.omtp.VvmLog;
import com.android.phone.vvm.omtp.sync.OmtpVvmSourceManager;
import com.android.phone.vvm.omtp.sync.OmtpVvmSyncService;
@@ -41,6 +42,7 @@
* Receive SMS messages and send for processing by the OMTP visual voicemail source.
*/
public class OmtpMessageReceiver extends BroadcastReceiver {
+
private static final String TAG = "OmtpMessageReceiver";
private Context mContext;
@@ -63,7 +65,7 @@
}
OmtpVvmCarrierConfigHelper helper = new OmtpVvmCarrierConfigHelper(mContext, subId);
- if (!VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(mContext, phone)) {
+ if (!VisualVoicemailSettingsUtil.isEnabled(mContext, phone)) {
if (helper.isLegacyModeEnabled()) {
LegacyModeSmsHandler.handle(context, intent, phone);
} else {
@@ -146,7 +148,7 @@
default:
VvmLog.e(TAG,
"Unrecognized sync trigger event: " + message.getSyncTriggerEvent());
- break;
+ break;
}
if (serviceIntent != null) {
@@ -163,10 +165,8 @@
helper.handleEvent(OmtpEvents.CONFIG_REQUEST_STATUS_SUCCESS);
// Save the IMAP credentials in preferences so they are persistent and can be retrieved.
- VisualVoicemailSettingsUtil.setVisualVoicemailCredentialsFromStatusMessage(
- mContext,
- phone,
- message);
+ VisualVoicemailPreferences prefs = new VisualVoicemailPreferences(mContext, phone);
+ message.putStatus(prefs.edit()).apply();
// Add the source to indicate that it is active.
vvmSourceManager.addSource(phone);
diff --git a/src/com/android/phone/vvm/omtp/sms/StatusMessage.java b/src/com/android/phone/vvm/omtp/sms/StatusMessage.java
index f9d972f..65455d0 100644
--- a/src/com/android/phone/vvm/omtp/sms/StatusMessage.java
+++ b/src/com/android/phone/vvm/omtp/sms/StatusMessage.java
@@ -20,6 +20,7 @@
import com.android.phone.NeededForTesting;
import com.android.phone.vvm.omtp.OmtpConstants;
+import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
/**
* Structured data representation of OMTP STATUS message.
@@ -44,6 +45,7 @@
private final String mSmtpPort;
private final String mSmtpUserName;
private final String mSmtpPassword;
+ private final String mTuiPasswordLength;
@Override
public String toString() {
@@ -58,7 +60,8 @@
+ ", mImapPassword=" + Log.pii(mImapPassword)
+ ", mSmtpPort=" + mSmtpPort
+ ", mSmtpUserName=" + mSmtpUserName
- + ", mSmtpPassword=" + Log.pii(mSmtpPassword) + "]";
+ + ", mSmtpPassword=" + Log.pii(mSmtpPassword)
+ + ", mTuiPasswordLength=" + mTuiPasswordLength + "]";
}
public StatusMessage(Bundle wrappedData) {
@@ -75,6 +78,7 @@
mSmtpPort = getString(wrappedData, OmtpConstants.SMTP_PORT);
mSmtpUserName = getString(wrappedData, OmtpConstants.SMTP_USER_NAME);
mSmtpPassword = getString(wrappedData, OmtpConstants.SMTP_PASSWORD);
+ mTuiPasswordLength = getString(wrappedData, OmtpConstants.TUI_PASSWORD_LENGTH);
}
private static String unquote(String string) {
@@ -180,6 +184,10 @@
return mSmtpPassword;
}
+ public String getTuiPasswordLength() {
+ return mTuiPasswordLength;
+ }
+
private static String getString(Bundle bundle, String key) {
String value = bundle.getString(key);
if (value == null) {
@@ -187,4 +195,16 @@
}
return value;
}
+
+ /**
+ * Saves a StatusMessage to the {@link VisualVoicemailPreferences}. Not all fields are saved.
+ */
+ public VisualVoicemailPreferences.Editor putStatus(VisualVoicemailPreferences.Editor editor) {
+ return editor
+ .putString(OmtpConstants.IMAP_PORT, getImapPort())
+ .putString(OmtpConstants.SERVER_ADDRESS, getServerAddress())
+ .putString(OmtpConstants.IMAP_USER_NAME, getImapUserName())
+ .putString(OmtpConstants.IMAP_PASSWORD, getImapPassword())
+ .putString(OmtpConstants.TUI_PASSWORD_LENGTH, getTuiPasswordLength());
+ }
}
\ No newline at end of file
diff --git a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
index 9884e9d..7e62829 100644
--- a/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
+++ b/src/com/android/phone/vvm/omtp/sync/OmtpVvmSyncService.java
@@ -33,6 +33,7 @@
import com.android.phone.settings.VisualVoicemailSettingsUtil;
import com.android.phone.vvm.omtp.OmtpEvents;
import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper;
+import com.android.phone.vvm.omtp.VisualVoicemailPreferences;
import com.android.phone.vvm.omtp.VvmLog;
import com.android.phone.vvm.omtp.fetch.VoicemailFetchedCallback;
import com.android.phone.vvm.omtp.imap.ImapHelper;
@@ -87,6 +88,11 @@
// Minimum time allowed between manual syncs
private static final int MINIMUM_MANUAL_SYNC_INTERVAL_MILLIS = 3 * 1000;
+ // Record the timestamp of the last full sync so that duplicate syncs can be reduced.
+ private static final String LAST_FULL_SYNC_TIMESTAMP = "last_full_sync_timestamp";
+ // Constant indicating that there has never been a full sync.
+ public static final long NO_PRIOR_FULL_SYNC = -1;
+
private VoicemailsQueryHelper mQueryHelper;
public OmtpVvmSyncService() {
@@ -100,19 +106,6 @@
public static Intent getSyncIntent(Context context, String action,
PhoneAccountHandle phoneAccount, Voicemail voicemail, boolean firstAttempt) {
- if (firstAttempt) {
- if (phoneAccount != null) {
- VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(context,
- phoneAccount);
- } else {
- OmtpVvmSourceManager vvmSourceManager =
- OmtpVvmSourceManager.getInstance(context);
- Set<PhoneAccountHandle> sources = vvmSourceManager.getOmtpVvmSources();
- for (PhoneAccountHandle source : sources) {
- VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(context, source);
- }
- }
- }
Intent serviceIntent = new Intent(context, OmtpVvmSyncService.class);
serviceIntent.setAction(action);
@@ -194,14 +187,14 @@
private void setupAndSendRequest(PhoneAccountHandle phoneAccount, Voicemail voicemail,
String action, boolean isManualSync) {
- if (!VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(this, phoneAccount)) {
+ if (!VisualVoicemailSettingsUtil.isEnabled(this, phoneAccount)) {
VvmLog.v(TAG, "Sync requested for disabled account");
return;
}
if (SYNC_FULL_SYNC.equals(action)) {
- long lastSyncTime = VisualVoicemailSettingsUtil.getVisualVoicemailLastFullSyncTime(
- this, phoneAccount);
+ long lastSyncTime = new VisualVoicemailPreferences(this, phoneAccount)
+ .getLong(LAST_FULL_SYNC_TIMESTAMP, NO_PRIOR_FULL_SYNC);
long currentTime = System.currentTimeMillis();
int minimumInterval = isManualSync ? MINIMUM_MANUAL_SYNC_INTERVAL_MILLIS
: MINIMUM_MANUAL_SYNC_INTERVAL_MILLIS;
@@ -221,8 +214,9 @@
VoicemailStatus.edit(this, phoneAccount).apply();
return;
}
- VisualVoicemailSettingsUtil.setVisualVoicemailLastFullSyncTime(
- this, phoneAccount, currentTime);
+ new VisualVoicemailPreferences(this, phoneAccount).edit()
+ .putLong(LAST_FULL_SYNC_TIMESTAMP, currentTime)
+ .apply();
}
VvmNetworkRequestCallback networkCallback = new SyncNetworkRequestCallback(this,
@@ -238,8 +232,6 @@
try (ImapHelper imapHelper = new ImapHelper(this, phoneAccount, network)) {
if (!imapHelper.isSuccessfullyInitialized()) {
VvmLog.w(TAG, "Can't retrieve Imap credentials.");
- VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
- phoneAccount);
return;
}
@@ -251,17 +243,14 @@
}
imapHelper.updateQuota();
- // Need to check again for whether visual voicemail is enabled because it could
- // have been disabled while waiting for the response from the network.
- if (VisualVoicemailSettingsUtil.isVisualVoicemailEnabled(this, phoneAccount) &&
- !success) {
+ // Need to check again for whether visual voicemail is enabled because it could have
+ // been disabled while waiting for the response from the network.
+ if (VisualVoicemailSettingsUtil.isEnabled(this, phoneAccount) &&
+ !success) {
retryCount--;
VvmLog.v(TAG, "Retrying " + action);
} else {
// Nothing more to do here, just exit.
- VisualVoicemailSettingsUtil.resetVisualVoicemailRetryInterval(this,
- phoneAccount);
-
imapHelper.handleEvent(OmtpEvents.DATA_IMAP_OPERATION_COMPLETED);
return;
}
@@ -420,24 +409,6 @@
return carrierConfigHelper.isPrefetchEnabled() && !imapHelper.isRoaming();
}
- protected void setRetryAlarm(PhoneAccountHandle phoneAccount, String action) {
- Intent serviceIntent = new Intent(this, OmtpVvmSyncService.class);
- serviceIntent.setAction(action);
- serviceIntent.putExtra(OmtpVvmSyncService.EXTRA_PHONE_ACCOUNT, phoneAccount);
- PendingIntent pendingIntent = PendingIntent.getService(this, 0, serviceIntent, 0);
- long retryInterval = VisualVoicemailSettingsUtil.getVisualVoicemailRetryInterval(this,
- phoneAccount);
-
- VvmLog.v(TAG, "Retrying " + action + " in " + retryInterval + "ms");
-
- AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
- alarmManager.set(AlarmManager.RTC, System.currentTimeMillis() + retryInterval,
- pendingIntent);
-
- VisualVoicemailSettingsUtil.setVisualVoicemailRetryInterval(this, phoneAccount,
- retryInterval * 2);
- }
-
/**
* Builds a map from provider data to message for the given collection of voicemails.
*/
diff --git a/tests/src/com/android/phone/vvm/omtp/StatusMessageTest.java b/tests/src/com/android/phone/vvm/omtp/StatusMessageTest.java
index fd3aa2c..707463a 100644
--- a/tests/src/com/android/phone/vvm/omtp/StatusMessageTest.java
+++ b/tests/src/com/android/phone/vvm/omtp/StatusMessageTest.java
@@ -40,6 +40,7 @@
bundle.putString(OmtpConstants.SMTP_PORT, "s1234");
bundle.putString(OmtpConstants.SMTP_USER_NAME, "susername");
bundle.putString(OmtpConstants.SMTP_PASSWORD, "spassword");
+ bundle.putString(OmtpConstants.TUI_PASSWORD_LENGTH, "4-7");
StatusMessage message = new StatusMessage(bundle);
assertEquals("status", message.getProvisioningStatus());
@@ -54,6 +55,7 @@
assertEquals("s1234", message.getSmtpPort());
assertEquals("susername", message.getSmtpUserName());
assertEquals("spassword", message.getSmtpPassword());
+ assertEquals("4-7", message.getTuiPasswordLength());
}
public void testSyncMessage_EmptyBundle() {
@@ -70,5 +72,6 @@
assertEquals("", message.getSmtpPort());
assertEquals("", message.getSmtpUserName());
assertEquals("", message.getSmtpPassword());
+ assertEquals("", message.getTuiPasswordLength());
}
}
diff --git a/tests/src/com/android/phone/vvm/omtp/VisualVoicemailPreferencesTest.java b/tests/src/com/android/phone/vvm/omtp/VisualVoicemailPreferencesTest.java
new file mode 100644
index 0000000..1ae7899
--- /dev/null
+++ b/tests/src/com/android/phone/vvm/omtp/VisualVoicemailPreferencesTest.java
@@ -0,0 +1,81 @@
+package com.android.phone.vvm.omtp;
+
+import android.content.ComponentName;
+import android.telecom.PhoneAccountHandle;
+import android.test.AndroidTestCase;
+import android.util.ArraySet;
+
+import java.util.Arrays;
+
+public class VisualVoicemailPreferencesTest extends AndroidTestCase {
+
+ public void testWriteRead() {
+ VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(getContext(),
+ createFakeHandle("testWriteRead"));
+ preferences.edit()
+ .putBoolean("boolean", true)
+ .putFloat("float", 0.5f)
+ .putInt("int", 123)
+ .putLong("long", 456)
+ .putString("string", "foo")
+ .putStringSet("stringset", new ArraySet<>(Arrays.asList("bar", "baz")))
+ .apply();
+
+ assertTrue(preferences.contains("boolean"));
+ assertTrue(preferences.contains("float"));
+ assertTrue(preferences.contains("int"));
+ assertTrue(preferences.contains("long"));
+ assertTrue(preferences.contains("string"));
+ assertTrue(preferences.contains("stringset"));
+
+ assertEquals(true, preferences.getBoolean("boolean", false));
+ assertEquals(0.5f, preferences.getFloat("float", 0));
+ assertEquals(123, preferences.getInt("int", 0));
+ assertEquals(456, preferences.getLong("long", 0));
+ assertEquals("foo", preferences.getString("string", null));
+ assertEquals(new ArraySet<>(Arrays.asList("bar", "baz")),
+ preferences.getStringSet("stringset", null));
+ }
+
+ public void testReadDefault() {
+ VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(getContext(),
+ createFakeHandle("testReadDefault"));
+
+ assertFalse(preferences.contains("boolean"));
+ assertFalse(preferences.contains("float"));
+ assertFalse(preferences.contains("int"));
+ assertFalse(preferences.contains("long"));
+ assertFalse(preferences.contains("string"));
+ assertFalse(preferences.contains("stringset"));
+
+ assertEquals(true, preferences.getBoolean("boolean", true));
+ assertEquals(2.5f, preferences.getFloat("float", 2.5f));
+ assertEquals(321, preferences.getInt("int", 321));
+ assertEquals(654, preferences.getLong("long", 654));
+ assertEquals("foo2", preferences.getString("string", "foo2"));
+ assertEquals(new ArraySet<>(Arrays.asList("bar2", "baz2")),
+ preferences.getStringSet(
+ "stringset", new ArraySet<>(Arrays.asList("bar2", "baz2"))));
+ }
+
+ public void testReadDefaultNull() {
+ VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(getContext(),
+ createFakeHandle("testReadDefaultNull"));
+ assertNull(preferences.getString("string", null));
+ assertNull(preferences.getStringSet("stringset", null));
+ }
+
+ public void testDifferentHandle() {
+ VisualVoicemailPreferences preferences1 = new VisualVoicemailPreferences(getContext(),
+ createFakeHandle("testDifferentHandle1"));
+ VisualVoicemailPreferences preferences2 = new VisualVoicemailPreferences(getContext(),
+ createFakeHandle("testDifferentHandle1"));
+
+ preferences1.edit().putString("string", "foo");
+ assertFalse(preferences2.contains("string"));
+ }
+
+ private PhoneAccountHandle createFakeHandle(String id) {
+ return new PhoneAccountHandle(new ComponentName(getContext(), this.getClass()), id);
+ }
+}