1 /* 2 * Copyright (C) 2017 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.settings.widget; 18 19 import android.app.AlertDialog; 20 import android.app.Dialog; 21 import android.app.Fragment; 22 import android.content.Context; 23 import android.content.DialogInterface; 24 import android.content.res.TypedArray; 25 import android.os.Bundle; 26 import android.text.Editable; 27 import android.text.InputType; 28 import android.text.TextUtils; 29 import android.text.TextWatcher; 30 import android.util.Log; 31 import android.view.inputmethod.InputMethodManager; 32 import android.widget.Button; 33 import android.widget.EditText; 34 35 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 36 import com.android.internal.util.HexDump; 37 import com.android.settings.R; 38 39 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 40 import java.security.MessageDigest; 41 import java.security.NoSuchAlgorithmException; 42 43 public class CarrierDemoPasswordDialogFragment extends InstrumentedDialogFragment { 44 45 private static final String TAG = "CarrierDemoPasswordDF"; 46 47 private MessageDigest mMessageDigest; 48 CarrierDemoPasswordDialogFragment()49 public CarrierDemoPasswordDialogFragment() { 50 try { 51 mMessageDigest = MessageDigest.getInstance("SHA-256"); 52 } catch (NoSuchAlgorithmException e) { 53 Log.e(TAG, "Unable to verify demo mode password", e); 54 } 55 } 56 57 @Override onCreateDialog(Bundle savedInstanceState)58 public Dialog onCreateDialog(Bundle savedInstanceState) { 59 final AlertDialog dialog = new AlertDialog.Builder(getContext()) 60 .setPositiveButton(R.string.retail_demo_reset_next, 61 new DialogInterface.OnClickListener() { 62 @Override 63 public void onClick(DialogInterface dialog, int which) { 64 final Fragment parentFragment = getParentFragment(); 65 if (parentFragment instanceof Callback 66 && which == DialogInterface.BUTTON_POSITIVE) { 67 ((Callback) parentFragment).onPasswordVerified(); 68 } 69 } 70 }) 71 .setNegativeButton(android.R.string.cancel, null) 72 .setMessage(R.string.retail_demo_reset_message) 73 .setTitle(R.string.retail_demo_reset_title) 74 .create(); 75 76 final Context context = dialog.getContext(); 77 final EditText passwordField = new EditText(context); 78 passwordField.setSingleLine(); 79 passwordField.setInputType(InputType.TYPE_CLASS_TEXT 80 | InputType.TYPE_TEXT_VARIATION_PASSWORD); 81 passwordField.addTextChangedListener(new TextWatcher() { 82 @Override 83 public void beforeTextChanged(CharSequence s, int start, int count, int after) { 84 // no-op 85 } 86 87 @Override 88 public void onTextChanged(CharSequence s, int start, int before, int count) { 89 verifyPassword(dialog, passwordField.getText().toString()); 90 } 91 92 @Override 93 public void afterTextChanged(Editable s) { 94 // no-op 95 } 96 }); 97 98 dialog.setOnShowListener(new DialogInterface.OnShowListener() { 99 @Override 100 public void onShow(DialogInterface dialogInterface) { 101 verifyPassword(dialog, passwordField.getText().toString()); 102 passwordField.requestFocus(); 103 final InputMethodManager imm = (InputMethodManager) getContext().getSystemService( 104 Context.INPUT_METHOD_SERVICE); 105 imm.showSoftInput(passwordField, InputMethodManager.SHOW_IMPLICIT); 106 } 107 }); 108 dialog.setCanceledOnTouchOutside(false); 109 110 final TypedArray a = context.obtainStyledAttributes( 111 new int[] { android.R.attr.dialogPreferredPadding }); 112 final int sidePadding = a.getDimensionPixelSize(0, 0); 113 dialog.setView(passwordField, sidePadding, 0, sidePadding, 0); 114 a.recycle(); 115 116 return dialog; 117 } 118 verifyPassword(AlertDialog dialog, String input)119 private void verifyPassword(AlertDialog dialog, String input) { 120 final Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE); 121 if (mMessageDigest == null || TextUtils.isEmpty(input)) { 122 positiveButton.setEnabled(false); 123 return; 124 } 125 final String passwordHash = getContext().getString( 126 com.android.internal.R.string.config_carrierDemoModePassword); 127 if (passwordHash == null || TextUtils.isEmpty(passwordHash)) { 128 // This device does not support carrier demo mode. 129 return; 130 } 131 final byte[] inputDigest = mMessageDigest.digest(input.getBytes()); 132 final String inputHash = HexDump.toHexString(inputDigest, 0, inputDigest.length, false); 133 positiveButton.setEnabled(TextUtils.equals(passwordHash, inputHash)); 134 } 135 136 @Override getMetricsCategory()137 public int getMetricsCategory() { 138 return MetricsEvent.CARRIER_DEMO_MODE_PASSWORD; 139 } 140 141 public interface Callback { onPasswordVerified()142 void onPasswordVerified(); 143 } 144 } 145