PageRenderTime 28ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/phone/com/android/internal/policy/impl/AccountUnlockScreen.java

https://github.com/MIPS/frameworks-policies-base
Java | 347 lines | 239 code | 47 blank | 61 comment | 33 complexity | 30645c5d49dc2cc6562c8a43d79edbb6 MD5 | raw file
  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. package com.android.internal.policy.impl;
  17. import com.android.internal.R;
  18. import com.android.internal.widget.LockPatternUtils;
  19. import android.accounts.Account;
  20. import android.accounts.AccountManager;
  21. import android.accounts.OperationCanceledException;
  22. import android.accounts.AccountManagerFuture;
  23. import android.accounts.AuthenticatorException;
  24. import android.accounts.AccountManagerCallback;
  25. import android.content.Context;
  26. import android.content.Intent;
  27. import android.content.res.Configuration;
  28. import android.graphics.Rect;
  29. import android.text.Editable;
  30. import android.text.InputFilter;
  31. import android.text.LoginFilter;
  32. import android.text.TextWatcher;
  33. import android.view.KeyEvent;
  34. import android.view.LayoutInflater;
  35. import android.view.View;
  36. import android.view.WindowManager;
  37. import android.widget.Button;
  38. import android.widget.EditText;
  39. import android.widget.RelativeLayout;
  40. import android.widget.TextView;
  41. import android.app.Dialog;
  42. import android.app.ProgressDialog;
  43. import android.os.Bundle;
  44. import java.io.IOException;
  45. /**
  46. * When the user forgets their password a bunch of times, we fall back on their
  47. * account's login/password to unlock the phone (and reset their lock pattern).
  48. */
  49. public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen,
  50. KeyguardUpdateMonitor.InfoCallback,View.OnClickListener, TextWatcher {
  51. private static final String LOCK_PATTERN_PACKAGE = "com.android.settings";
  52. private static final String LOCK_PATTERN_CLASS =
  53. "com.android.settings.ChooseLockPattern";
  54. /**
  55. * The amount of millis to stay awake once this screen detects activity
  56. */
  57. private static final int AWAKE_POKE_MILLIS = 30000;
  58. private final KeyguardScreenCallback mCallback;
  59. private final LockPatternUtils mLockPatternUtils;
  60. private KeyguardUpdateMonitor mUpdateMonitor;
  61. private TextView mTopHeader;
  62. private TextView mInstructions;
  63. private EditText mLogin;
  64. private EditText mPassword;
  65. private Button mOk;
  66. private Button mEmergencyCall;
  67. /**
  68. * Shown while making asynchronous check of password.
  69. */
  70. private ProgressDialog mCheckingDialog;
  71. /**
  72. * AccountUnlockScreen constructor.
  73. * @param configuration
  74. * @param updateMonitor
  75. */
  76. public AccountUnlockScreen(Context context,Configuration configuration,
  77. KeyguardUpdateMonitor updateMonitor, KeyguardScreenCallback callback,
  78. LockPatternUtils lockPatternUtils) {
  79. super(context);
  80. mCallback = callback;
  81. mLockPatternUtils = lockPatternUtils;
  82. LayoutInflater.from(context).inflate(
  83. R.layout.keyguard_screen_glogin_unlock, this, true);
  84. mTopHeader = (TextView) findViewById(R.id.topHeader);
  85. mTopHeader.setText(mLockPatternUtils.isPermanentlyLocked() ?
  86. R.string.lockscreen_glogin_too_many_attempts :
  87. R.string.lockscreen_glogin_forgot_pattern);
  88. mInstructions = (TextView) findViewById(R.id.instructions);
  89. mLogin = (EditText) findViewById(R.id.login);
  90. mLogin.setFilters(new InputFilter[] { new LoginFilter.UsernameFilterGeneric() } );
  91. mLogin.addTextChangedListener(this);
  92. mPassword = (EditText) findViewById(R.id.password);
  93. mPassword.addTextChangedListener(this);
  94. mOk = (Button) findViewById(R.id.ok);
  95. mOk.setOnClickListener(this);
  96. mEmergencyCall = (Button) findViewById(R.id.emergencyCall);
  97. mEmergencyCall.setOnClickListener(this);
  98. mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCall);
  99. mUpdateMonitor = updateMonitor;
  100. mUpdateMonitor.registerInfoCallback(this);
  101. }
  102. public void afterTextChanged(Editable s) {
  103. }
  104. public void beforeTextChanged(CharSequence s, int start, int count, int after) {
  105. }
  106. public void onTextChanged(CharSequence s, int start, int before, int count) {
  107. mCallback.pokeWakelock(AWAKE_POKE_MILLIS);
  108. }
  109. @Override
  110. protected boolean onRequestFocusInDescendants(int direction,
  111. Rect previouslyFocusedRect) {
  112. // send focus to the login field
  113. return mLogin.requestFocus(direction, previouslyFocusedRect);
  114. }
  115. /** {@inheritDoc} */
  116. public boolean needsInput() {
  117. return true;
  118. }
  119. /** {@inheritDoc} */
  120. public void onPause() {
  121. }
  122. /** {@inheritDoc} */
  123. public void onResume() {
  124. // start fresh
  125. mLogin.setText("");
  126. mPassword.setText("");
  127. mLogin.requestFocus();
  128. mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCall);
  129. }
  130. /** {@inheritDoc} */
  131. public void cleanUp() {
  132. if (mCheckingDialog != null) {
  133. mCheckingDialog.hide();
  134. }
  135. mUpdateMonitor.removeCallback(this);
  136. }
  137. /** {@inheritDoc} */
  138. public void onClick(View v) {
  139. mCallback.pokeWakelock();
  140. if (v == mOk) {
  141. asyncCheckPassword();
  142. }
  143. if (v == mEmergencyCall) {
  144. mCallback.takeEmergencyCallAction();
  145. }
  146. }
  147. private void postOnCheckPasswordResult(final boolean success) {
  148. // ensure this runs on UI thread
  149. mLogin.post(new Runnable() {
  150. public void run() {
  151. if (success) {
  152. // clear out forgotten password
  153. mLockPatternUtils.setPermanentlyLocked(false);
  154. mLockPatternUtils.setLockPatternEnabled(false);
  155. mLockPatternUtils.saveLockPattern(null);
  156. // launch the 'choose lock pattern' activity so
  157. // the user can pick a new one if they want to
  158. Intent intent = new Intent();
  159. intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS);
  160. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  161. mContext.startActivity(intent);
  162. mCallback.reportSuccessfulUnlockAttempt();
  163. // close the keyguard
  164. mCallback.keyguardDone(true);
  165. } else {
  166. mInstructions.setText(R.string.lockscreen_glogin_invalid_input);
  167. mPassword.setText("");
  168. mCallback.reportFailedUnlockAttempt();
  169. }
  170. }
  171. });
  172. }
  173. @Override
  174. public boolean dispatchKeyEvent(KeyEvent event) {
  175. if (event.getAction() == KeyEvent.ACTION_DOWN
  176. && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
  177. if (mLockPatternUtils.isPermanentlyLocked()) {
  178. mCallback.goToLockScreen();
  179. } else {
  180. mCallback.forgotPattern(false);
  181. }
  182. return true;
  183. }
  184. return super.dispatchKeyEvent(event);
  185. }
  186. /**
  187. * Given the string the user entered in the 'username' field, find
  188. * the stored account that they probably intended. Prefer, in order:
  189. *
  190. * - an exact match for what was typed, or
  191. * - a case-insensitive match for what was typed, or
  192. * - if they didn't include a domain, an exact match of the username, or
  193. * - if they didn't include a domain, a case-insensitive
  194. * match of the username.
  195. *
  196. * If there is a tie for the best match, choose neither --
  197. * the user needs to be more specific.
  198. *
  199. * @return an account name from the database, or null if we can't
  200. * find a single best match.
  201. */
  202. private Account findIntendedAccount(String username) {
  203. Account[] accounts = AccountManager.get(mContext).getAccountsByType("com.google");
  204. // Try to figure out which account they meant if they
  205. // typed only the username (and not the domain), or got
  206. // the case wrong.
  207. Account bestAccount = null;
  208. int bestScore = 0;
  209. for (Account a: accounts) {
  210. int score = 0;
  211. if (username.equals(a.name)) {
  212. score = 4;
  213. } else if (username.equalsIgnoreCase(a.name)) {
  214. score = 3;
  215. } else if (username.indexOf('@') < 0) {
  216. int i = a.name.indexOf('@');
  217. if (i >= 0) {
  218. String aUsername = a.name.substring(0, i);
  219. if (username.equals(aUsername)) {
  220. score = 2;
  221. } else if (username.equalsIgnoreCase(aUsername)) {
  222. score = 1;
  223. }
  224. }
  225. }
  226. if (score > bestScore) {
  227. bestAccount = a;
  228. bestScore = score;
  229. } else if (score == bestScore) {
  230. bestAccount = null;
  231. }
  232. }
  233. return bestAccount;
  234. }
  235. private void asyncCheckPassword() {
  236. mCallback.pokeWakelock(AWAKE_POKE_MILLIS);
  237. final String login = mLogin.getText().toString();
  238. final String password = mPassword.getText().toString();
  239. Account account = findIntendedAccount(login);
  240. if (account == null) {
  241. postOnCheckPasswordResult(false);
  242. return;
  243. }
  244. getProgressDialog().show();
  245. Bundle options = new Bundle();
  246. options.putString(AccountManager.KEY_PASSWORD, password);
  247. AccountManager.get(mContext).confirmCredentials(account, options, null /* activity */,
  248. new AccountManagerCallback<Bundle>() {
  249. public void run(AccountManagerFuture<Bundle> future) {
  250. try {
  251. mCallback.pokeWakelock(AWAKE_POKE_MILLIS);
  252. final Bundle result = future.getResult();
  253. final boolean verified = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
  254. postOnCheckPasswordResult(verified);
  255. } catch (OperationCanceledException e) {
  256. postOnCheckPasswordResult(false);
  257. } catch (IOException e) {
  258. postOnCheckPasswordResult(false);
  259. } catch (AuthenticatorException e) {
  260. postOnCheckPasswordResult(false);
  261. } finally {
  262. mLogin.post(new Runnable() {
  263. public void run() {
  264. getProgressDialog().hide();
  265. }
  266. });
  267. }
  268. }
  269. }, null /* handler */);
  270. }
  271. private Dialog getProgressDialog() {
  272. if (mCheckingDialog == null) {
  273. mCheckingDialog = new ProgressDialog(mContext);
  274. mCheckingDialog.setMessage(
  275. mContext.getString(R.string.lockscreen_glogin_checking_password));
  276. mCheckingDialog.setIndeterminate(true);
  277. mCheckingDialog.setCancelable(false);
  278. mCheckingDialog.getWindow().setType(
  279. WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
  280. if (!mContext.getResources().getBoolean(
  281. com.android.internal.R.bool.config_sf_slowBlur)) {
  282. mCheckingDialog.getWindow().setFlags(
  283. WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
  284. WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
  285. }
  286. }
  287. return mCheckingDialog;
  288. }
  289. public void onPhoneStateChanged(String newState) {
  290. mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCall);
  291. }
  292. public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) {
  293. }
  294. public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
  295. }
  296. public void onRingerModeChanged(int state) {
  297. }
  298. public void onTimeChanged() {
  299. }
  300. }