1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.phone.settings; 18 19 import android.annotation.Nullable; 20 import android.app.Activity; 21 import android.app.AlertDialog; 22 import android.app.ProgressDialog; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.DialogInterface.OnDismissListener; 26 import android.content.SharedPreferences; 27 import android.net.Network; 28 import android.os.Bundle; 29 import android.os.Handler; 30 import android.os.Message; 31 import android.preference.PreferenceManager; 32 import android.telecom.PhoneAccountHandle; 33 import android.text.Editable; 34 import android.text.InputFilter; 35 import android.text.InputFilter.LengthFilter; 36 import android.text.TextWatcher; 37 import android.view.KeyEvent; 38 import android.view.View; 39 import android.view.View.OnClickListener; 40 import android.view.WindowManager; 41 import android.view.inputmethod.EditorInfo; 42 import android.widget.Button; 43 import android.widget.EditText; 44 import android.widget.TextView; 45 import android.widget.TextView.OnEditorActionListener; 46 import android.widget.Toast; 47 import com.android.phone.PhoneUtils; 48 import com.android.phone.R; 49 import com.android.phone.VoicemailStatus; 50 import com.android.phone.common.mail.MessagingException; 51 import com.android.phone.vvm.omtp.OmtpConstants; 52 import com.android.phone.vvm.omtp.OmtpConstants.ChangePinResult; 53 import com.android.phone.vvm.omtp.OmtpEvents; 54 import com.android.phone.vvm.omtp.OmtpVvmCarrierConfigHelper; 55 import com.android.phone.vvm.omtp.VisualVoicemailPreferences; 56 import com.android.phone.vvm.omtp.VvmLog; 57 import com.android.phone.vvm.omtp.imap.ImapHelper; 58 import com.android.phone.vvm.omtp.imap.ImapHelper.InitializingException; 59 import com.android.phone.vvm.omtp.sync.VvmNetworkRequestCallback; 60 61 /** 62 * Dialog to change the voicemail PIN. The TUI (Telephony User Interface) PIN is used when accessing 63 * traditional voicemail through phone call. The intent to launch this activity must contain {@link 64 * #EXTRA_PHONE_ACCOUNT_HANDLE} 65 */ 66 public class VoicemailChangePinActivity extends Activity implements OnClickListener, 67 OnEditorActionListener, TextWatcher { 68 69 private static final String TAG = "VmChangePinActivity"; 70 71 public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "extra_phone_account_handle"; 72 73 private static final String KEY_DEFAULT_OLD_PIN = "default_old_pin"; 74 75 private static final int MESSAGE_HANDLE_RESULT = 1; 76 77 private PhoneAccountHandle mPhoneAccountHandle; 78 private OmtpVvmCarrierConfigHelper mConfig; 79 80 private int mPinMinLength; 81 private int mPinMaxLength; 82 83 private State mUiState = State.Initial; 84 private String mOldPin; 85 private String mFirstPin; 86 87 private ProgressDialog mProgressDialog; 88 89 private TextView mHeaderText; 90 private TextView mHintText; 91 private TextView mErrorText; 92 private EditText mPinEntry; 93 private Button mCancelButton; 94 private Button mNextButton; 95 96 private Handler mHandler = new Handler() { 97 @Override 98 public void handleMessage(Message message) { 99 if (message.what == MESSAGE_HANDLE_RESULT) { 100 mUiState.handleResult(VoicemailChangePinActivity.this, message.arg1); 101 } 102 } 103 }; 104 105 private enum State { 106 /** 107 * Empty state to handle initial state transition. Will immediately switch into {@link 108 * #VerifyOldPin} if a default PIN has been set by the OMTP client, or {@link #EnterOldPin} 109 * if not. 110 */ 111 Initial, 112 /** 113 * Prompt the user to enter old PIN. The PIN will be verified with the server before 114 * proceeding to {@link #EnterNewPin}. 115 */ 116 EnterOldPin { 117 @Override onEnter(VoicemailChangePinActivity activity)118 public void onEnter(VoicemailChangePinActivity activity) { 119 activity.setHeader(R.string.change_pin_enter_old_pin_header); 120 activity.mHintText.setText(R.string.change_pin_enter_old_pin_hint); 121 activity.mNextButton.setText(R.string.change_pin_continue_label); 122 activity.mErrorText.setText(null); 123 } 124 125 @Override onInputChanged(VoicemailChangePinActivity activity)126 public void onInputChanged(VoicemailChangePinActivity activity) { 127 activity.setNextEnabled(activity.getCurrentPasswordInput().length() > 0); 128 } 129 130 131 @Override handleNext(VoicemailChangePinActivity activity)132 public void handleNext(VoicemailChangePinActivity activity) { 133 activity.mOldPin = activity.getCurrentPasswordInput(); 134 activity.verifyOldPin(); 135 } 136 137 @Override handleResult(VoicemailChangePinActivity activity, @ChangePinResult int result)138 public void handleResult(VoicemailChangePinActivity activity, 139 @ChangePinResult int result) { 140 if (result == OmtpConstants.CHANGE_PIN_SUCCESS) { 141 activity.updateState(State.EnterNewPin); 142 } else { 143 CharSequence message = activity.getChangePinResultMessage(result); 144 activity.showError(message); 145 activity.mPinEntry.setText(""); 146 } 147 } 148 }, 149 /** 150 * The default old PIN is found. Show a blank screen while verifying with the server to make 151 * sure the PIN is still valid. If the PIN is still valid, proceed to {@link #EnterNewPin}. 152 * If not, the user probably changed the PIN through other means, proceed to {@link 153 * #EnterOldPin}. If any other issue caused the verifying to fail, show an error and exit. 154 */ 155 VerifyOldPin { 156 @Override onEnter(VoicemailChangePinActivity activity)157 public void onEnter(VoicemailChangePinActivity activity) { 158 activity.findViewById(android.R.id.content).setVisibility(View.INVISIBLE); 159 activity.verifyOldPin(); 160 } 161 162 @Override handleResult(VoicemailChangePinActivity activity, @ChangePinResult int result)163 public void handleResult(VoicemailChangePinActivity activity, 164 @ChangePinResult int result) { 165 if (result == OmtpConstants.CHANGE_PIN_SUCCESS) { 166 activity.updateState(State.EnterNewPin); 167 } else if (result == OmtpConstants.CHANGE_PIN_SYSTEM_ERROR) { 168 activity.getWindow().setSoftInputMode( 169 WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); 170 activity.showError(activity.getString(R.string.change_pin_system_error), 171 new OnDismissListener() { 172 @Override 173 public void onDismiss(DialogInterface dialog) { 174 activity.finish(); 175 } 176 }); 177 } else { 178 VvmLog.e(TAG, "invalid default old PIN: " + activity 179 .getChangePinResultMessage(result)); 180 // If the default old PIN is rejected by the server, the PIN is probably changed 181 // through other means, or the generated pin is invalid 182 // Wipe the default old PIN so the old PIN input box will be shown to the user 183 // on the next time. 184 setDefaultOldPIN(activity, activity.mPhoneAccountHandle, null); 185 activity.handleOmtpEvent(OmtpEvents.CONFIG_PIN_SET); 186 activity.updateState(State.EnterOldPin); 187 } 188 } 189 190 @Override onLeave(VoicemailChangePinActivity activity)191 public void onLeave(VoicemailChangePinActivity activity) { 192 activity.findViewById(android.R.id.content).setVisibility(View.VISIBLE); 193 } 194 }, 195 /** 196 * Let the user enter the new PIN and validate the format. Only length is enforced, PIN 197 * strength check relies on the server. After a valid PIN is entered, proceed to {@link 198 * #ConfirmNewPin} 199 */ 200 EnterNewPin { 201 @Override onEnter(VoicemailChangePinActivity activity)202 public void onEnter(VoicemailChangePinActivity activity) { 203 activity.mHeaderText.setText(R.string.change_pin_enter_new_pin_header); 204 activity.mNextButton.setText(R.string.change_pin_continue_label); 205 activity.mHintText.setText( 206 activity.getString(R.string.change_pin_enter_new_pin_hint, 207 activity.mPinMinLength, activity.mPinMaxLength)); 208 } 209 210 @Override onInputChanged(VoicemailChangePinActivity activity)211 public void onInputChanged(VoicemailChangePinActivity activity) { 212 String password = activity.getCurrentPasswordInput(); 213 if (password.length() == 0) { 214 activity.setNextEnabled(false); 215 return; 216 } 217 CharSequence error = activity.validatePassword(password); 218 if (error != null) { 219 activity.mErrorText.setText(error); 220 activity.setNextEnabled(false); 221 } else { 222 activity.mErrorText.setText(null); 223 activity.setNextEnabled(true); 224 } 225 } 226 227 @Override handleNext(VoicemailChangePinActivity activity)228 public void handleNext(VoicemailChangePinActivity activity) { 229 CharSequence errorMsg; 230 errorMsg = activity.validatePassword(activity.getCurrentPasswordInput()); 231 if (errorMsg != null) { 232 activity.showError(errorMsg); 233 return; 234 } 235 activity.mFirstPin = activity.getCurrentPasswordInput(); 236 activity.updateState(State.ConfirmNewPin); 237 } 238 }, 239 /** 240 * Let the user type in the same PIN again to avoid typos. If the PIN matches then perform a 241 * PIN change to the server. Finish the activity if succeeded. Return to {@link 242 * #EnterOldPin} if the old PIN is rejected, {@link #EnterNewPin} for other failure. 243 */ 244 ConfirmNewPin { 245 @Override onEnter(VoicemailChangePinActivity activity)246 public void onEnter(VoicemailChangePinActivity activity) { 247 activity.mHeaderText.setText(R.string.change_pin_confirm_pin_header); 248 activity.mHintText.setText(null); 249 activity.mNextButton.setText(R.string.change_pin_ok_label); 250 } 251 252 @Override onInputChanged(VoicemailChangePinActivity activity)253 public void onInputChanged(VoicemailChangePinActivity activity) { 254 if (activity.getCurrentPasswordInput().length() == 0) { 255 activity.setNextEnabled(false); 256 return; 257 } 258 if (activity.getCurrentPasswordInput().equals(activity.mFirstPin)) { 259 activity.setNextEnabled(true); 260 activity.mErrorText.setText(null); 261 } else { 262 activity.setNextEnabled(false); 263 activity.mErrorText.setText(R.string.change_pin_confirm_pins_dont_match); 264 } 265 } 266 267 @Override handleResult(VoicemailChangePinActivity activity, @ChangePinResult int result)268 public void handleResult(VoicemailChangePinActivity activity, 269 @ChangePinResult int result) { 270 if (result == OmtpConstants.CHANGE_PIN_SUCCESS) { 271 // If the PIN change succeeded we no longer know what the old (current) PIN is. 272 // Wipe the default old PIN so the old PIN input box will be shown to the user 273 // on the next time. 274 setDefaultOldPIN(activity, activity.mPhoneAccountHandle, null); 275 activity.handleOmtpEvent(OmtpEvents.CONFIG_PIN_SET); 276 277 activity.finish(); 278 279 Toast.makeText(activity, activity.getString(R.string.change_pin_succeeded), 280 Toast.LENGTH_SHORT).show(); 281 } else { 282 CharSequence message = activity.getChangePinResultMessage(result); 283 VvmLog.i(TAG, "Change PIN failed: " + message); 284 activity.showError(message); 285 if (result == OmtpConstants.CHANGE_PIN_MISMATCH) { 286 // Somehow the PIN has changed, prompt to enter the old PIN again. 287 activity.updateState(State.EnterOldPin); 288 } else { 289 // The new PIN failed to fulfil other restrictions imposed by the server. 290 activity.updateState(State.EnterNewPin); 291 } 292 293 } 294 295 } 296 297 @Override handleNext(VoicemailChangePinActivity activity)298 public void handleNext(VoicemailChangePinActivity activity) { 299 activity.processPinChange(activity.mOldPin, activity.mFirstPin); 300 } 301 }; 302 303 /** 304 * The activity has switched from another state to this one. 305 */ onEnter(VoicemailChangePinActivity activity)306 public void onEnter(VoicemailChangePinActivity activity) { 307 // Do nothing 308 } 309 310 /** 311 * The user has typed something into the PIN input field. Also called after {@link 312 * #onEnter(VoicemailChangePinActivity)} 313 */ onInputChanged(VoicemailChangePinActivity activity)314 public void onInputChanged(VoicemailChangePinActivity activity) { 315 // Do nothing 316 } 317 318 /** 319 * The asynchronous call to change the PIN on the server has returned. 320 */ handleResult(VoicemailChangePinActivity activity, @ChangePinResult int result)321 public void handleResult(VoicemailChangePinActivity activity, @ChangePinResult int result) { 322 // Do nothing 323 } 324 325 /** 326 * The user has pressed the "next" button. 327 */ handleNext(VoicemailChangePinActivity activity)328 public void handleNext(VoicemailChangePinActivity activity) { 329 // Do nothing 330 } 331 332 /** 333 * The activity has switched from this state to another one. 334 */ onLeave(VoicemailChangePinActivity activity)335 public void onLeave(VoicemailChangePinActivity activity) { 336 // Do nothing 337 } 338 339 } 340 341 @Override onCreate(Bundle savedInstanceState)342 public void onCreate(Bundle savedInstanceState) { 343 super.onCreate(savedInstanceState); 344 345 mPhoneAccountHandle = getIntent().getParcelableExtra(EXTRA_PHONE_ACCOUNT_HANDLE); 346 mConfig = new OmtpVvmCarrierConfigHelper(this, mPhoneAccountHandle); 347 setContentView(R.layout.voicemail_change_pin); 348 setTitle(R.string.change_pin_title); 349 350 readPinLength(); 351 352 View view = findViewById(android.R.id.content); 353 354 mCancelButton = (Button) view.findViewById(R.id.cancel_button); 355 mCancelButton.setOnClickListener(this); 356 mNextButton = (Button) view.findViewById(R.id.next_button); 357 mNextButton.setOnClickListener(this); 358 359 mPinEntry = (EditText) view.findViewById(R.id.pin_entry); 360 mPinEntry.setOnEditorActionListener(this); 361 mPinEntry.addTextChangedListener(this); 362 if (mPinMaxLength != 0) { 363 mPinEntry.setFilters(new InputFilter[]{new LengthFilter(mPinMaxLength)}); 364 } 365 366 367 mHeaderText = (TextView) view.findViewById(R.id.headerText); 368 mHintText = (TextView) view.findViewById(R.id.hintText); 369 mErrorText = (TextView) view.findViewById(R.id.errorText); 370 371 migrateDefaultOldPin(); 372 373 if (isDefaultOldPinSet(this, mPhoneAccountHandle)) { 374 mOldPin = getDefaultOldPin(this, mPhoneAccountHandle); 375 updateState(State.VerifyOldPin); 376 } else { 377 updateState(State.EnterOldPin); 378 } 379 } 380 handleOmtpEvent(OmtpEvents event)381 private void handleOmtpEvent(OmtpEvents event) { 382 mConfig.handleEvent(getVoicemailStatusEditor(), event); 383 } 384 getVoicemailStatusEditor()385 private VoicemailStatus.Editor getVoicemailStatusEditor() { 386 // This activity does not have any automatic retry mechanism, errors should be written right 387 // away. 388 return VoicemailStatus.edit(this, mPhoneAccountHandle); 389 } 390 391 /** 392 * Extracts the pin length requirement sent by the server with a STATUS SMS. 393 */ readPinLength()394 private void readPinLength() { 395 VisualVoicemailPreferences preferences = new VisualVoicemailPreferences(this, 396 mPhoneAccountHandle); 397 // The OMTP pin length format is {min}-{max} 398 String[] lengths = preferences.getString(OmtpConstants.TUI_PASSWORD_LENGTH, "").split("-"); 399 if (lengths.length == 2) { 400 try { 401 mPinMinLength = Integer.parseInt(lengths[0]); 402 mPinMaxLength = Integer.parseInt(lengths[1]); 403 } catch (NumberFormatException e) { 404 mPinMinLength = 0; 405 mPinMaxLength = 0; 406 } 407 } else { 408 mPinMinLength = 0; 409 mPinMaxLength = 0; 410 } 411 } 412 413 @Override onResume()414 public void onResume() { 415 super.onResume(); 416 updateState(mUiState); 417 418 } 419 handleNext()420 public void handleNext() { 421 if (mPinEntry.length() == 0) { 422 return; 423 } 424 mUiState.handleNext(this); 425 } 426 onClick(View v)427 public void onClick(View v) { 428 switch (v.getId()) { 429 case R.id.next_button: 430 handleNext(); 431 break; 432 433 case R.id.cancel_button: 434 finish(); 435 break; 436 } 437 } 438 onEditorAction(TextView v, int actionId, KeyEvent event)439 public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { 440 // Check if this was the result of hitting the enter or "done" key 441 if (actionId == EditorInfo.IME_NULL 442 || actionId == EditorInfo.IME_ACTION_DONE 443 || actionId == EditorInfo.IME_ACTION_NEXT) { 444 handleNext(); 445 return true; 446 } 447 return false; 448 } 449 afterTextChanged(Editable s)450 public void afterTextChanged(Editable s) { 451 mUiState.onInputChanged(this); 452 } 453 beforeTextChanged(CharSequence s, int start, int count, int after)454 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 455 // Do nothing 456 } 457 onTextChanged(CharSequence s, int start, int before, int count)458 public void onTextChanged(CharSequence s, int start, int before, int count) { 459 // Do nothing 460 } 461 462 /** 463 * After replacing the default PIN with a random PIN, call this to store the random PIN. The 464 * stored PIN will be automatically entered when the user attempts to change the PIN. 465 */ setDefaultOldPIN(Context context, PhoneAccountHandle phoneAccountHandle, String pin)466 public static void setDefaultOldPIN(Context context, PhoneAccountHandle phoneAccountHandle, 467 String pin) { 468 new VisualVoicemailPreferences(context, phoneAccountHandle) 469 .edit().putString(KEY_DEFAULT_OLD_PIN, pin).apply(); 470 } 471 isDefaultOldPinSet(Context context, PhoneAccountHandle phoneAccountHandle)472 public static boolean isDefaultOldPinSet(Context context, 473 PhoneAccountHandle phoneAccountHandle) { 474 return getDefaultOldPin(context, phoneAccountHandle) != null; 475 } 476 getDefaultOldPin(Context context, PhoneAccountHandle phoneAccountHandle)477 private static String getDefaultOldPin(Context context, PhoneAccountHandle phoneAccountHandle) { 478 return new VisualVoicemailPreferences(context, phoneAccountHandle) 479 .getString(KEY_DEFAULT_OLD_PIN); 480 } 481 482 /** 483 * Storage location has changed mid development. Migrate from the old location to avoid losing 484 * tester's default old pin. 485 */ migrateDefaultOldPin()486 private void migrateDefaultOldPin() { 487 String key = "voicemail_pin_dialog_preference_" 488 + PhoneUtils.getSubIdForPhoneAccountHandle(mPhoneAccountHandle) 489 + "_default_old_pin"; 490 491 SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); 492 if (preferences.contains(key)) { 493 setDefaultOldPIN(this, mPhoneAccountHandle, preferences.getString(key, null)); 494 preferences.edit().putString(key, null).apply(); 495 } 496 } 497 getCurrentPasswordInput()498 private String getCurrentPasswordInput() { 499 return mPinEntry.getText().toString(); 500 } 501 updateState(State state)502 private void updateState(State state) { 503 State previousState = mUiState; 504 mUiState = state; 505 if (previousState != state) { 506 previousState.onLeave(this); 507 mPinEntry.setText(""); 508 mUiState.onEnter(this); 509 } 510 mUiState.onInputChanged(this); 511 } 512 513 /** 514 * Validates PIN and returns a message to display if PIN fails test. 515 * 516 * @param password the raw password the user typed in 517 * @return error message to show to user or null if password is OK 518 */ validatePassword(String password)519 private CharSequence validatePassword(String password) { 520 if (mPinMinLength == 0 && mPinMaxLength == 0) { 521 // Invalid length requirement is sent by the server, just accept anything and let the 522 // server decide. 523 return null; 524 } 525 526 if (password.length() < mPinMinLength) { 527 return getString(R.string.vm_change_pin_error_too_short); 528 } 529 return null; 530 } 531 setHeader(int text)532 private void setHeader(int text) { 533 mHeaderText.setText(text); 534 mPinEntry.setContentDescription(mHeaderText.getText()); 535 } 536 537 /** 538 * Get the corresponding message for the {@link ChangePinResult}.<code>result</code> must not 539 * {@link OmtpConstants#CHANGE_PIN_SUCCESS} 540 */ getChangePinResultMessage(@hangePinResult int result)541 private CharSequence getChangePinResultMessage(@ChangePinResult int result) { 542 switch (result) { 543 case OmtpConstants.CHANGE_PIN_TOO_SHORT: 544 return getString(R.string.vm_change_pin_error_too_short); 545 case OmtpConstants.CHANGE_PIN_TOO_LONG: 546 return getString(R.string.vm_change_pin_error_too_long); 547 case OmtpConstants.CHANGE_PIN_TOO_WEAK: 548 return getString(R.string.vm_change_pin_error_too_weak); 549 case OmtpConstants.CHANGE_PIN_INVALID_CHARACTER: 550 return getString(R.string.vm_change_pin_error_invalid); 551 case OmtpConstants.CHANGE_PIN_MISMATCH: 552 return getString(R.string.vm_change_pin_error_mismatch); 553 case OmtpConstants.CHANGE_PIN_SYSTEM_ERROR: 554 return getString(R.string.vm_change_pin_error_system_error); 555 default: 556 VvmLog.wtf(TAG, "Unexpected ChangePinResult " + result); 557 return null; 558 } 559 } 560 verifyOldPin()561 private void verifyOldPin() { 562 processPinChange(mOldPin, mOldPin); 563 } 564 setNextEnabled(boolean enabled)565 private void setNextEnabled(boolean enabled) { 566 mNextButton.setEnabled(enabled); 567 } 568 569 showError(CharSequence message)570 private void showError(CharSequence message) { 571 showError(message, null); 572 } 573 showError(CharSequence message, @Nullable OnDismissListener callback)574 private void showError(CharSequence message, @Nullable OnDismissListener callback) { 575 new AlertDialog.Builder(this) 576 .setMessage(message) 577 .setPositiveButton(android.R.string.ok, null) 578 .setOnDismissListener(callback) 579 .show(); 580 } 581 582 /** 583 * Asynchronous call to change the PIN on the server. 584 */ processPinChange(String oldPin, String newPin)585 private void processPinChange(String oldPin, String newPin) { 586 mProgressDialog = new ProgressDialog(this); 587 mProgressDialog.setCancelable(false); 588 mProgressDialog.setMessage(getString(R.string.vm_change_pin_progress_message)); 589 mProgressDialog.show(); 590 591 ChangePinNetworkRequestCallback callback = new ChangePinNetworkRequestCallback(oldPin, 592 newPin); 593 callback.requestNetwork(); 594 } 595 596 private class ChangePinNetworkRequestCallback extends VvmNetworkRequestCallback { 597 598 private final String mOldPin; 599 private final String mNewPin; 600 ChangePinNetworkRequestCallback(String oldPin, String newPin)601 public ChangePinNetworkRequestCallback(String oldPin, String newPin) { 602 super(mConfig, mPhoneAccountHandle, 603 VoicemailChangePinActivity.this.getVoicemailStatusEditor()); 604 mOldPin = oldPin; 605 mNewPin = newPin; 606 } 607 608 @Override onAvailable(Network network)609 public void onAvailable(Network network) { 610 super.onAvailable(network); 611 try (ImapHelper helper = 612 new ImapHelper(VoicemailChangePinActivity.this, mPhoneAccountHandle, network, 613 getVoicemailStatusEditor())) { 614 615 @ChangePinResult int result = 616 helper.changePin(mOldPin, mNewPin); 617 sendResult(result); 618 } catch (InitializingException | MessagingException e) { 619 VvmLog.e(TAG, "ChangePinNetworkRequestCallback: onAvailable: ", e); 620 sendResult(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR); 621 } 622 } 623 624 @Override onFailed(String reason)625 public void onFailed(String reason) { 626 super.onFailed(reason); 627 sendResult(OmtpConstants.CHANGE_PIN_SYSTEM_ERROR); 628 } 629 sendResult(@hangePinResult int result)630 private void sendResult(@ChangePinResult int result) { 631 VvmLog.i(TAG, "Change PIN result: " + result); 632 if (mProgressDialog.isShowing() && !VoicemailChangePinActivity.this.isDestroyed() && 633 !VoicemailChangePinActivity.this.isFinishing()) { 634 mProgressDialog.dismiss(); 635 } else { 636 VvmLog.i(TAG, "Dialog not visible, not dismissing"); 637 } 638 mHandler.obtainMessage(MESSAGE_HANDLE_RESULT, result, 0).sendToTarget(); 639 releaseNetwork(); 640 } 641 } 642 643 } 644