Home | History | Annotate | Download | only in impl
      1 /*
      2  * Copyright (C) 2008 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.internal.policy.impl;
     18 
     19 import android.app.Dialog;
     20 import android.app.ProgressDialog;
     21 import android.content.Context;
     22 import android.content.res.Configuration;
     23 import android.os.RemoteException;
     24 import android.os.ServiceManager;
     25 
     26 import com.android.internal.telephony.ITelephony;
     27 import com.android.internal.widget.LockPatternUtils;
     28 
     29 import android.text.Editable;
     30 import android.util.Log;
     31 import android.view.KeyEvent;
     32 import android.view.LayoutInflater;
     33 import android.view.View;
     34 import android.view.WindowManager;
     35 import android.widget.Button;
     36 import android.widget.LinearLayout;
     37 import android.widget.TextView;
     38 import com.android.internal.R;
     39 
     40 /**
     41  * Displays a dialer like interface to unlock the SIM PUK.
     42  */
     43 public class SimPukUnlockScreen extends LinearLayout implements KeyguardScreen,
     44         View.OnClickListener, View.OnFocusChangeListener {
     45 
     46     private static final int DIGIT_PRESS_WAKE_MILLIS = 5000;
     47 
     48     private final KeyguardUpdateMonitor mUpdateMonitor;
     49     private final KeyguardScreenCallback mCallback;
     50     private KeyguardStatusViewManager mKeyguardStatusViewManager;
     51 
     52     private TextView mHeaderText;
     53     private TextView mPukText;
     54     private TextView mPinText;
     55     private TextView mFocusedEntry;
     56 
     57     private View mOkButton;
     58     private View mDelPukButton;
     59     private View mDelPinButton;
     60 
     61     private ProgressDialog mSimUnlockProgressDialog = null;
     62 
     63     private LockPatternUtils mLockPatternUtils;
     64 
     65     private int mCreationOrientation;
     66 
     67     private int mKeyboardHidden;
     68 
     69     private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
     70 
     71     public SimPukUnlockScreen(Context context, Configuration configuration,
     72             KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback,
     73             LockPatternUtils lockpatternutils) {
     74         super(context);
     75         mUpdateMonitor = updateMonitor;
     76         mCallback = callback;;
     77 
     78         mCreationOrientation = configuration.orientation;
     79         mKeyboardHidden = configuration.hardKeyboardHidden;
     80         mLockPatternUtils = lockpatternutils;
     81 
     82         LayoutInflater inflater = LayoutInflater.from(context);
     83         if (mKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
     84             inflater.inflate(
     85                     R.layout.keyguard_screen_sim_puk_landscape, this, true);
     86         } else {
     87             inflater.inflate(
     88                     R.layout.keyguard_screen_sim_puk_portrait, this, true);
     89             new TouchInput();
     90         }
     91 
     92         mHeaderText = (TextView) findViewById(R.id.headerText);
     93 
     94         mPukText = (TextView) findViewById(R.id.pukDisplay);
     95         mPinText = (TextView) findViewById(R.id.pinDisplay);
     96         mDelPukButton = findViewById(R.id.pukDel);
     97         mDelPinButton = findViewById(R.id.pinDel);
     98         mOkButton = findViewById(R.id.ok);
     99 
    100         mDelPinButton.setOnClickListener(this);
    101         mDelPukButton.setOnClickListener(this);
    102         mOkButton.setOnClickListener(this);
    103 
    104         mHeaderText.setText(R.string.keyguard_password_enter_puk_code);
    105         // To make marquee work
    106         mHeaderText.setSelected(true);
    107 
    108         mKeyguardStatusViewManager = new KeyguardStatusViewManager(this, updateMonitor,
    109                 lockpatternutils, callback, true);
    110 
    111         mPinText.setFocusableInTouchMode(true);
    112         mPinText.setOnFocusChangeListener(this);
    113         mPukText.setFocusableInTouchMode(true);
    114         mPukText.setOnFocusChangeListener(this);
    115     }
    116 
    117     /** {@inheritDoc} */
    118     public boolean needsInput() {
    119         return false;
    120     }
    121 
    122     /** {@inheritDoc} */
    123     public void onPause() {
    124         mKeyguardStatusViewManager.onPause();
    125     }
    126 
    127     /** {@inheritDoc} */
    128     public void onResume() {
    129         // start fresh
    130         mHeaderText.setText(R.string.keyguard_password_enter_puk_code);
    131         mKeyguardStatusViewManager.onResume();
    132     }
    133 
    134     /** {@inheritDoc} */
    135     public void cleanUp() {
    136         // dismiss the dialog.
    137         if (mSimUnlockProgressDialog != null) {
    138             mSimUnlockProgressDialog.dismiss();
    139             mSimUnlockProgressDialog = null;
    140         }
    141         mUpdateMonitor.removeCallback(this);
    142     }
    143 
    144 
    145     /**
    146      * Since the IPC can block, we want to run the request in a separate thread
    147      * with a callback.
    148      */
    149     private abstract class CheckSimPuk extends Thread {
    150 
    151         private final String mPin, mPuk;
    152 
    153         protected CheckSimPuk(String puk, String pin) {
    154             mPuk = puk;
    155             mPin = pin;
    156         }
    157 
    158         abstract void onSimLockChangedResponse(boolean success);
    159 
    160         @Override
    161         public void run() {
    162             try {
    163                 final boolean result = ITelephony.Stub.asInterface(ServiceManager
    164                         .checkService("phone")).supplyPuk(mPuk, mPin);
    165 
    166                 post(new Runnable() {
    167                     public void run() {
    168                         onSimLockChangedResponse(result);
    169                     }
    170                 });
    171             } catch (RemoteException e) {
    172                 post(new Runnable() {
    173                     public void run() {
    174                         onSimLockChangedResponse(false);
    175                     }
    176                 });
    177             }
    178         }
    179     }
    180 
    181     public void onClick(View v) {
    182         if (v == mDelPukButton) {
    183             if (mFocusedEntry != mPukText)
    184                 mPukText.requestFocus();
    185             final Editable digits = mPukText.getEditableText();
    186             final int len = digits.length();
    187             if (len > 0) {
    188                 digits.delete(len-1, len);
    189             }
    190         } else if (v == mDelPinButton) {
    191             if (mFocusedEntry != mPinText)
    192                 mPinText.requestFocus();
    193             final Editable digits = mPinText.getEditableText();
    194             final int len = digits.length();
    195             if (len > 0) {
    196                 digits.delete(len-1, len);
    197             }
    198         } else if (v == mOkButton) {
    199             checkPuk();
    200         }
    201         mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS);
    202 
    203     }
    204 
    205     @Override
    206     public void onFocusChange(View v, boolean hasFocus) {
    207         if (hasFocus)
    208             mFocusedEntry = (TextView)v;
    209     }
    210 
    211     private Dialog getSimUnlockProgressDialog() {
    212         if (mSimUnlockProgressDialog == null) {
    213             mSimUnlockProgressDialog = new ProgressDialog(mContext);
    214             mSimUnlockProgressDialog.setMessage(
    215                     mContext.getString(R.string.lockscreen_sim_unlock_progress_dialog_message));
    216             mSimUnlockProgressDialog.setIndeterminate(true);
    217             mSimUnlockProgressDialog.setCancelable(false);
    218             mSimUnlockProgressDialog.getWindow().setType(
    219                     WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
    220         }
    221         return mSimUnlockProgressDialog;
    222     }
    223 
    224     private void checkPuk() {
    225         // make sure that the puk is at least 8 digits long.
    226         if (mPukText.getText().length() < 8) {
    227             // otherwise, display a message to the user, and don't submit.
    228             mHeaderText.setText(R.string.invalidPuk);
    229             mPukText.setText("");
    230             return;
    231         }
    232 
    233         if (mPinText.getText().length() < 4
    234                 || mPinText.getText().length() > 8) {
    235             // otherwise, display a message to the user, and don't submit.
    236             mHeaderText.setText(R.string.invalidPin);
    237             mPinText.setText("");
    238             return;
    239         }
    240 
    241         getSimUnlockProgressDialog().show();
    242 
    243         new CheckSimPuk(mPukText.getText().toString(),
    244                 mPinText.getText().toString()) {
    245             void onSimLockChangedResponse(final boolean success) {
    246                 mPinText.post(new Runnable() {
    247                     public void run() {
    248                         if (mSimUnlockProgressDialog != null) {
    249                             mSimUnlockProgressDialog.hide();
    250                         }
    251                         if (success) {
    252                             // before closing the keyguard, report back that
    253                             // the sim is unlocked so it knows right away
    254                             mUpdateMonitor.reportSimUnlocked();
    255                             mCallback.goToUnlockScreen();
    256                         } else {
    257                             mHeaderText.setText(R.string.badPuk);
    258                             mPukText.setText("");
    259                             mPinText.setText("");
    260                         }
    261                     }
    262                 });
    263             }
    264         }.start();
    265     }
    266 
    267 
    268     public boolean onKeyDown(int keyCode, KeyEvent event) {
    269         if (keyCode == KeyEvent.KEYCODE_BACK) {
    270             mCallback.goToLockScreen();
    271             return true;
    272         }
    273         final char match = event.getMatch(DIGITS);
    274         if (match != 0) {
    275             reportDigit(match - '0');
    276             return true;
    277         }
    278         if (keyCode == KeyEvent.KEYCODE_DEL) {
    279             mFocusedEntry.onKeyDown(keyCode, event);
    280             final Editable digits = mFocusedEntry.getEditableText();
    281             final int len = digits.length();
    282             if (len > 0) {
    283                 digits.delete(len-1, len);
    284             }
    285             mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS);
    286             return true;
    287         }
    288 
    289         if (keyCode == KeyEvent.KEYCODE_ENTER) {
    290             checkPuk();
    291             return true;
    292         }
    293 
    294         return false;
    295     }
    296 
    297     private void reportDigit(int digit) {
    298         mFocusedEntry.append(Integer.toString(digit));
    299     }
    300 
    301     void updateConfiguration() {
    302         Configuration newConfig = getResources().getConfiguration();
    303         if (newConfig.orientation != mCreationOrientation) {
    304             mCallback.recreateMe(newConfig);
    305         } else if (newConfig.hardKeyboardHidden != mKeyboardHidden) {
    306             mKeyboardHidden = newConfig.hardKeyboardHidden;
    307         }
    308 
    309     }
    310 
    311     @Override
    312     protected void onAttachedToWindow() {
    313         super.onAttachedToWindow();
    314         updateConfiguration();
    315     }
    316 
    317     /** {@inheritDoc} */
    318     @Override
    319     protected void onConfigurationChanged(Configuration newConfig) {
    320         super.onConfigurationChanged(newConfig);
    321         updateConfiguration();
    322     }
    323 
    324     /**
    325      * Helper class to handle input from touch dialer.  Only relevant when
    326      * the keyboard is shut.
    327      */
    328     private class TouchInput implements View.OnClickListener {
    329         private TextView mZero;
    330         private TextView mOne;
    331         private TextView mTwo;
    332         private TextView mThree;
    333         private TextView mFour;
    334         private TextView mFive;
    335         private TextView mSix;
    336         private TextView mSeven;
    337         private TextView mEight;
    338         private TextView mNine;
    339         private TextView mCancelButton;
    340 
    341         private TouchInput() {
    342             mZero = (TextView) findViewById(R.id.zero);
    343             mOne = (TextView) findViewById(R.id.one);
    344             mTwo = (TextView) findViewById(R.id.two);
    345             mThree = (TextView) findViewById(R.id.three);
    346             mFour = (TextView) findViewById(R.id.four);
    347             mFive = (TextView) findViewById(R.id.five);
    348             mSix = (TextView) findViewById(R.id.six);
    349             mSeven = (TextView) findViewById(R.id.seven);
    350             mEight = (TextView) findViewById(R.id.eight);
    351             mNine = (TextView) findViewById(R.id.nine);
    352             mCancelButton = (TextView) findViewById(R.id.cancel);
    353 
    354             mZero.setText("0");
    355             mOne.setText("1");
    356             mTwo.setText("2");
    357             mThree.setText("3");
    358             mFour.setText("4");
    359             mFive.setText("5");
    360             mSix.setText("6");
    361             mSeven.setText("7");
    362             mEight.setText("8");
    363             mNine.setText("9");
    364 
    365             mZero.setOnClickListener(this);
    366             mOne.setOnClickListener(this);
    367             mTwo.setOnClickListener(this);
    368             mThree.setOnClickListener(this);
    369             mFour.setOnClickListener(this);
    370             mFive.setOnClickListener(this);
    371             mSix.setOnClickListener(this);
    372             mSeven.setOnClickListener(this);
    373             mEight.setOnClickListener(this);
    374             mNine.setOnClickListener(this);
    375             mCancelButton.setOnClickListener(this);
    376         }
    377 
    378 
    379         public void onClick(View v) {
    380             if (v == mCancelButton) {
    381                 // clear the PIN/PUK entry fields if the user cancels
    382                 mPinText.setText("");
    383                 mPukText.setText("");
    384                 mCallback.goToLockScreen();
    385                 return;
    386             }
    387 
    388             final int digit = checkDigit(v);
    389             if (digit >= 0) {
    390                 mCallback.pokeWakelock(DIGIT_PRESS_WAKE_MILLIS);
    391                 reportDigit(digit);
    392             }
    393         }
    394 
    395         private int checkDigit(View v) {
    396             int digit = -1;
    397             if (v == mZero) {
    398                 digit = 0;
    399             } else if (v == mOne) {
    400                 digit = 1;
    401             } else if (v == mTwo) {
    402                 digit = 2;
    403             } else if (v == mThree) {
    404                 digit = 3;
    405             } else if (v == mFour) {
    406                 digit = 4;
    407             } else if (v == mFive) {
    408                 digit = 5;
    409             } else if (v == mSix) {
    410                 digit = 6;
    411             } else if (v == mSeven) {
    412                 digit = 7;
    413             } else if (v == mEight) {
    414                 digit = 8;
    415             } else if (v == mNine) {
    416                 digit = 9;
    417             }
    418             return digit;
    419         }
    420     }
    421 
    422 }
    423