1/*
2 * Copyright (C) 2013 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
17package com.android.internal.app;
18
19import android.content.Context;
20import android.os.Bundle;
21import android.os.UserManager;
22import android.text.Editable;
23import android.text.TextWatcher;
24import android.view.KeyEvent;
25import android.view.LayoutInflater;
26import android.view.View;
27import android.view.View.OnClickListener;
28import android.widget.Button;
29import android.widget.EditText;
30import android.widget.TextView;
31import android.widget.TextView.OnEditorActionListener;
32
33import com.android.internal.R;
34
35/**
36 * This activity is launched by Settings and other apps to either create a new PIN or
37 * challenge for an existing PIN. The PIN is maintained by UserManager.
38 */
39public class RestrictionsPinActivity extends AlertActivity
40        implements OnClickListener, TextWatcher, OnEditorActionListener {
41
42    protected UserManager mUserManager;
43    protected boolean mHasRestrictionsPin;
44
45    protected EditText mPinText;
46    protected TextView mPinErrorMessage;
47    private Button mOkButton;
48    private Button mCancelButton;
49
50    @Override
51    public void onCreate(Bundle icicle) {
52        super.onCreate(icicle);
53
54        mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
55        mHasRestrictionsPin = mUserManager.hasRestrictionsChallenge();
56        initUi();
57        setupAlert();
58    }
59
60    protected void initUi() {
61        AlertController.AlertParams ap = mAlertParams;
62        ap.mTitle = getString(R.string.restr_pin_enter_admin_pin);
63        LayoutInflater inflater =
64                (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
65        ap.mView = inflater.inflate(R.layout.restrictions_pin_challenge, null);
66
67        mPinErrorMessage = (TextView) ap.mView.findViewById(R.id.pin_error_message);
68        mPinText = (EditText) ap.mView.findViewById(R.id.pin_text);
69        mOkButton = (Button) ap.mView.findViewById(R.id.pin_ok_button);
70        mCancelButton = (Button) ap.mView.findViewById(R.id.pin_cancel_button);
71
72        mPinText.addTextChangedListener(this);
73
74        mOkButton.setOnClickListener(this);
75        mCancelButton.setOnClickListener(this);
76    }
77
78    protected boolean verifyingPin() {
79        return true;
80    }
81
82    public void onResume() {
83        super.onResume();
84
85        setPositiveButtonState(false);
86        boolean hasPin = mUserManager.hasRestrictionsChallenge();
87        if (hasPin) {
88            mPinErrorMessage.setVisibility(View.INVISIBLE);
89            mPinText.setOnEditorActionListener(this);
90            updatePinTimer(-1);
91        } else if (verifyingPin()) {
92            setResult(RESULT_OK);
93            finish();
94        }
95    }
96
97    protected void setPositiveButtonState(boolean enabled) {
98        mOkButton.setEnabled(enabled);
99    }
100
101    private boolean updatePinTimer(int pinTimerMs) {
102        if (pinTimerMs < 0) {
103            pinTimerMs = mUserManager.checkRestrictionsChallenge(null);
104        }
105        boolean enableInput;
106        if (pinTimerMs >= 200) {
107            // Do the count down timer for less than a minute, otherwise just say try again later.
108            if (pinTimerMs <= 60000) {
109                final int seconds = (pinTimerMs + 200) / 1000;
110                final String formatString = getResources().getQuantityString(
111                        R.plurals.restr_pin_countdown,
112                        seconds);
113                mPinErrorMessage.setText(String.format(formatString, seconds));
114            } else {
115                mPinErrorMessage.setText(R.string.restr_pin_try_later);
116            }
117            enableInput = false;
118            mPinErrorMessage.setVisibility(View.VISIBLE);
119            mPinText.setText("");
120            mPinText.postDelayed(mCountdownRunnable, Math.min(1000, pinTimerMs));
121        } else {
122            enableInput = true;
123            mPinErrorMessage.setText(R.string.restr_pin_incorrect);
124        }
125        mPinText.setEnabled(enableInput);
126        setPositiveButtonState(enableInput);
127        return enableInput;
128    }
129
130    protected void performPositiveButtonAction() {
131        int result = mUserManager.checkRestrictionsChallenge(mPinText.getText().toString());
132        if (result == UserManager.PIN_VERIFICATION_SUCCESS) {
133            setResult(RESULT_OK);
134            finish();
135        } else if (result >= 0) {
136            mPinErrorMessage.setText(R.string.restr_pin_incorrect);
137            mPinErrorMessage.setVisibility(View.VISIBLE);
138            updatePinTimer(result);
139            mPinText.setText("");
140        }
141    }
142
143    @Override
144    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
145    }
146
147    @Override
148    public void onTextChanged(CharSequence s, int start, int before, int count) {
149        CharSequence pin = mPinText.getText();
150        setPositiveButtonState(pin != null && pin.length() >= 4);
151    }
152
153    @Override
154    public void afterTextChanged(Editable s) {
155    }
156
157    @Override
158    public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
159        performPositiveButtonAction();
160        return true;
161    }
162
163    private Runnable mCountdownRunnable = new Runnable() {
164        public void run() {
165            if (updatePinTimer(-1)) {
166                // If we are no longer counting down, clear the message.
167                mPinErrorMessage.setVisibility(View.INVISIBLE);
168            }
169        }
170    };
171
172    @Override
173    public void onClick(View v) {
174        if (v == mOkButton) {
175            performPositiveButtonAction();
176        } else if (v == mCancelButton) {
177            setResult(RESULT_CANCELED);
178            finish();
179        }
180    }
181}
182