1/*
2 * Copyright (C) 2012 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.keyguard.test;
18
19import com.android.internal.policy.IKeyguardShowCallback;
20import com.android.internal.policy.IKeyguardExitCallback;
21import com.android.internal.policy.IKeyguardService;
22
23import android.app.Activity;
24import android.app.AlertDialog;
25import android.app.admin.DevicePolicyManager;
26import android.content.ComponentName;
27import android.content.Context;
28import android.content.Intent;
29import android.content.ServiceConnection;
30import android.os.Bundle;
31import android.os.Handler;
32import android.os.IBinder;
33import android.os.RemoteException;
34import android.os.SystemClock;
35import android.provider.Settings;
36import android.util.Log;
37import android.view.Menu;
38import android.view.MenuInflater;
39import android.view.MenuItem;
40import android.view.View;
41import android.view.View.OnClickListener;
42import android.view.WindowManagerPolicy;
43
44import com.android.internal.widget.LockPatternUtils;
45import com.android.internal.widget.LockPatternView.Cell;
46
47import java.util.List;
48
49public class KeyguardTestActivity extends Activity implements OnClickListener {
50    private static final String KEYGUARD_PACKAGE = "com.android.keyguard";
51    private static final String KEYGUARD_CLASS = "com.android.keyguard.KeyguardService";
52    private static final String TAG = "LockScreenTestActivity";
53    private static final int MODE_NONE = 0;
54    private static final int MODE_PIN = 1;
55    private static final int MODE_PASSWORD = 2;
56    private static final int MODE_PATTERN = 3;
57    private static final int MODE_SIM_PIN = 4;
58    private static final int MODE_SIM_PUK = 5;
59    private static final String SECURITY_MODE = "security_mode";
60    Handler mHandler = new Handler();
61
62    IKeyguardService mService = null;
63
64    KeyguardShowCallback mKeyguardShowCallback = new KeyguardShowCallback();
65    KeyguardExitCallback mKeyguardExitCallback = new KeyguardExitCallback();
66
67    RemoteServiceConnection mConnection;
68    private boolean mSentSystemReady;
69
70    class KeyguardShowCallback extends IKeyguardShowCallback.Stub {
71
72        @Override
73        public void onShown(IBinder windowToken) throws RemoteException {
74            Log.v(TAG, "Keyguard is shown, windowToken = " + windowToken);
75        }
76    }
77
78    class KeyguardExitCallback extends IKeyguardExitCallback.Stub {
79
80        @Override
81        public void onKeyguardExitResult(final boolean success) throws RemoteException {
82            mHandler.post(new Runnable() {
83                @Override
84                public void run() {
85                    new AlertDialog.Builder(KeyguardTestActivity.this)
86                    .setMessage("Result: " + success)
87                    .setPositiveButton("OK", null)
88                    .show();
89                }
90            });
91        }
92    };
93
94    private class RemoteServiceConnection implements ServiceConnection {
95        public void onServiceConnected(ComponentName className, IBinder service) {
96            Log.v(TAG, "onServiceConnected()");
97            mService = IKeyguardService.Stub.asInterface(service);
98            try {
99                mService.asBinder().linkToDeath(new IBinder.DeathRecipient() {
100                    @Override
101                    public void binderDied() {
102                        new AlertDialog.Builder(KeyguardTestActivity.this)
103                            .setMessage("Oops! Keygued died")
104                            .setPositiveButton("OK", null)
105                            .show();
106                    }
107                }, 0);
108            } catch (RemoteException e) {
109                Log.w(TAG, "Couldn't linkToDeath");
110                e.printStackTrace();
111            }
112//            try {
113//                mService.onSystemReady();
114//            } catch (RemoteException e) {
115//                Log.v(TAG, "Remote service died trying to call onSystemReady");
116//                e.printStackTrace();
117//            }
118        }
119
120        public void onServiceDisconnected(ComponentName className) {
121            Log.v(TAG, "onServiceDisconnected()");
122            mService = null;
123        }
124    };
125
126    private void bindService() {
127        if (mConnection == null) {
128            mConnection = new RemoteServiceConnection();
129            Intent intent = new Intent();
130            intent.setClassName(KEYGUARD_PACKAGE, KEYGUARD_CLASS);
131            Log.v(TAG, "BINDING SERVICE: " + KEYGUARD_CLASS);
132            if (!bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
133                Log.v(TAG, "FAILED TO BIND TO KEYGUARD!");
134            }
135        } else {
136            Log.v(TAG, "Service already bound");
137        }
138    }
139
140    @Override
141    protected void onCreate(Bundle savedInstanceState) {
142        super.onCreate(savedInstanceState);
143        setContentView(R.layout.keyguard_test_activity);
144        final int[] buttons = {
145                R.id.on_screen_turned_off, R.id.on_screen_turned_on,
146                R.id.do_keyguard, R.id.verify_unlock
147        };
148        for (int i = 0; i < buttons.length; i++) {
149            findViewById(buttons[i]).setOnClickListener(this);
150        }
151        Log.v(TAG, "Binding service...");
152        bindService();
153    }
154
155    @Override
156    protected void onSaveInstanceState(Bundle outState) {
157        super.onSaveInstanceState(outState);
158        outState.putInt(SECURITY_MODE, mSecurityMode);
159    }
160
161    @Override
162    protected void onRestoreInstanceState(Bundle savedInstanceState) {
163        super.onRestoreInstanceState(savedInstanceState);
164        setMode(savedInstanceState.getInt(SECURITY_MODE));
165    }
166
167// TODO: Find a secure way to inject mock into keyguard...
168//    @Override
169//    public boolean onCreateOptionsMenu(Menu menu) {
170//        MenuInflater inflater = getMenuInflater();
171//        inflater.inflate(R.menu.optionmenu, menu);
172//        return true;
173//    }
174
175    private void setMode(int mode) {
176        mTestSimPin = false;
177        mTestSimPuk = false;
178        mLockPasswordEnabled = false;
179        mLockPatternEnabled = false;
180        switch(mode) {
181            case MODE_NONE:
182                mSecurityModeMock = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
183                break;
184            case MODE_PIN:
185                mSecurityModeMock = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
186                mLockPasswordEnabled = true;
187                break;
188            case MODE_PASSWORD:
189                mSecurityModeMock = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
190                mLockPasswordEnabled = true;
191                break;
192            case MODE_PATTERN:
193                mSecurityModeMock = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
194                mLockPatternEnabled = true;
195                break;
196            case MODE_SIM_PIN:
197                mTestSimPin = true;
198                break;
199            case MODE_SIM_PUK:
200                mTestSimPuk = true;
201                break;
202        }
203        mSecurityMode = mode;
204    }
205
206    @Override
207    public boolean onOptionsItemSelected(MenuItem item) {
208        // Handle item selection
209        switch (item.getItemId()) {
210            case R.id.none_menu_item:
211                setMode(MODE_NONE);
212                break;
213            case R.id.pin_menu_item:
214                setMode(MODE_PIN);
215                break;
216            case R.id.password_menu_item:
217                setMode(MODE_PASSWORD);
218                break;
219            case R.id.pattern_menu_item:
220                setMode(MODE_PATTERN);
221                break;
222            case R.id.sim_pin_menu_item:
223                setMode(MODE_SIM_PIN);
224                break;
225            case R.id.sim_puk_menu_item:
226                setMode(MODE_SIM_PUK);
227                break;
228            case R.id.add_widget_item:
229                startWidgetPicker();
230                break;
231            default:
232                return super.onOptionsItemSelected(item);
233        }
234        try {
235            mService.doKeyguardTimeout(null);
236        } catch (RemoteException e) {
237            Log.e(TAG, "Remote service died");
238            e.printStackTrace();
239        }
240        return true;
241    }
242
243    private void startWidgetPicker() {
244        startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
245    }
246
247    @Override
248    public void onClick(View v) {
249        try {
250            switch (v.getId()) {
251            case R.id.on_screen_turned_on:
252                mService.onScreenTurnedOn(mKeyguardShowCallback);
253                break;
254            case R.id.on_screen_turned_off:
255                mService.onScreenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
256                break;
257            case R.id.do_keyguard:
258                if (!mSentSystemReady) {
259                    mSentSystemReady = true;
260                    mService.onSystemReady();
261                }
262                mService.doKeyguardTimeout(null);
263                break;
264            case R.id.verify_unlock:
265                mService.doKeyguardTimeout(null);
266                // Wait for keyguard to lock and then try this...
267                mHandler.postDelayed(new Runnable() {
268                    @Override
269                    public void run() {
270                        try {
271                            mService.verifyUnlock(mKeyguardExitCallback);
272                        } catch (RemoteException e) {
273                            Log.e(TAG, "Failed verifyUnlock()", e);
274                        }
275                    }
276                }, 5000);
277                break;
278            }
279        } catch (RemoteException e) {
280            Log.e(TAG, "onClick(): Failed due to remote exeption", e);
281        }
282    }
283
284    @Override
285    protected void onPause() {
286        super.onPause();
287        try {
288            if (mService != null) {
289                mService.setHidden(true);
290            }
291        } catch (RemoteException e) {
292            Log.e(TAG, "Remote service died");
293            e.printStackTrace();
294        }
295    }
296
297    protected void onResume() {
298        super.onResume();
299        try {
300            if (mService != null) {
301                mService.setHidden(false);
302            }
303        } catch (RemoteException e) {
304            Log.e(TAG, "Remote service died");
305            e.printStackTrace();
306        }
307    }
308
309    public int mSecurityModeMock;
310    private boolean mTestSimPin;
311    private boolean mTestSimPuk;
312    private boolean mLockPasswordEnabled;
313    public boolean mLockPatternEnabled;
314    private int mSecurityMode;
315
316    class LockPatternUtilsMock extends LockPatternUtils {
317        private long mDeadline;
318        public LockPatternUtilsMock(Context context) {
319            super(context);
320        }
321
322        @Override
323        public boolean checkPattern(List<Cell> pattern) {
324            return pattern.size() > 4;
325        }
326
327        @Override
328        public boolean checkPassword(String password) {
329            return password.length() > 4;
330        }
331        @Override
332        public long setLockoutAttemptDeadline() {
333            final long deadline = SystemClock.elapsedRealtime() + FAILED_ATTEMPT_TIMEOUT_MS;
334            mDeadline = deadline;
335            return deadline;
336        }
337        @Override
338        public boolean isLockScreenDisabled() {
339            return false;
340        }
341        @Override
342        public long getLockoutAttemptDeadline() {
343            return mDeadline;
344        }
345        @Override
346        public void reportFailedPasswordAttempt() {
347            // Ignored
348        }
349        @Override
350        public void reportSuccessfulPasswordAttempt() {
351            // Ignored
352        }
353        @Override
354        public boolean isLockPatternEnabled() {
355            return mLockPatternEnabled;
356        }
357
358        @Override
359        public boolean isLockPasswordEnabled() {
360            return mLockPasswordEnabled;
361        }
362
363        @Override
364        public int getKeyguardStoredPasswordQuality() {
365            return mSecurityModeMock;
366        }
367
368        public boolean isSecure() {
369            return mLockPatternEnabled || mLockPasswordEnabled || mTestSimPin || mTestSimPuk;
370        }
371
372    }
373}
374