auto import from //depot/cupcake/@137055

This commit is contained in:
The Android Open Source Project
2009-03-02 22:54:37 -08:00
parent e1e5e408a4
commit e10e0bc288
6 changed files with 330 additions and 66 deletions

View File

@@ -32,6 +32,7 @@ import android.text.Editable;
import android.text.InputFilter;
import android.text.LoginFilter;
import android.text.TextWatcher;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -50,8 +51,6 @@ import android.widget.TextView;
*/
public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen,
View.OnClickListener, ServiceConnection, TextWatcher {
private static final String LOCK_PATTERN_PACKAGE = "com.android.settings";
private static final String LOCK_PATTERN_CLASS =
"com.android.settings.ChooseLockPattern";
@@ -135,7 +134,7 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
public boolean needsInput() {
return true;
}
/** {@inheritDoc} */
public void onPause() {
@@ -192,11 +191,75 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
return super.dispatchKeyEvent(event);
}
/**
* Given the string the user entered in the 'username' field, find
* the stored account that they probably intended. Prefer, in order:
*
* - an exact match for what was typed, or
* - a case-insensitive match for what was typed, or
* - if they didn't include a domain, an exact match of the username, or
* - if they didn't include a domain, a case-insensitive
* match of the username.
*
* If there is a tie for the best match, choose neither --
* the user needs to be more specific.
*
* @return an account name from the database, or null if we can't
* find a single best match.
*/
private String findIntendedAccount(String username) {
String[] accounts = null;
try {
accounts = mAccountsService.getAccounts();
} catch (RemoteException e) {
return null;
}
if (accounts == null) {
return null;
}
// Try to figure out which account they meant if they
// typed only the username (and not the domain), or got
// the case wrong.
String bestAccount = null;
int bestScore = 0;
for (String a: accounts) {
int score = 0;
if (username.equals(a)) {
score = 4;
} else if (username.equalsIgnoreCase(a)) {
score = 3;
} else if (username.indexOf('@') < 0) {
int i = a.indexOf('@');
if (i >= 0) {
String aUsername = a.substring(0, i);
if (username.equals(aUsername)) {
score = 2;
} else if (username.equalsIgnoreCase(aUsername)) {
score = 1;
}
}
}
if (score > bestScore) {
bestAccount = a;
bestScore = score;
} else if (score == bestScore) {
bestAccount = null;
}
}
return bestAccount;
}
private boolean checkPassword() {
final String login = mLogin.getText().toString();
final String password = mPassword.getText().toString();
try {
return mAccountsService.shouldUnlock(login, password);
String account = findIntendedAccount(login);
if (account == null) {
return false;
}
return mAccountsService.shouldUnlock(account, password);
} catch (RemoteException e) {
return false;
}

View File

@@ -16,29 +16,30 @@
package com.android.internal.policy.impl;
import com.android.internal.R;
import com.google.android.collect.Lists;
import android.app.AlertDialog;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.DialogInterface;
import android.media.AudioManager;
import android.os.LocalPowerManager;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.R;
import com.google.android.collect.Lists;
import java.util.ArrayList;
@@ -49,34 +50,41 @@ import java.util.ArrayList;
*/
class GlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener {
private static final String TAG = "GlobalActions";
private StatusBarManager mStatusBar;
private final Context mContext;
private final LocalPowerManager mPowerManager;
private final AudioManager mAudioManager;
private ArrayList<Action> mItems;
private AlertDialog mDialog;
private ToggleAction mSilentModeToggle;
private ToggleAction mAirplaneModeOn;
private MyAdapter mAdapter;
private boolean mKeyguardShowing = false;
private boolean mDeviceProvisioned = false;
private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
/**
* @param context everything needs a context :)
* @param powerManager used to turn the screen off (the lock action).
* @param context everything needs a context :(
*/
public GlobalActions(Context context, LocalPowerManager powerManager) {
public GlobalActions(Context context) {
mContext = context;
mPowerManager = powerManager;
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
// receive broadcasts
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
context.registerReceiver(mBroadcastReceiver, filter);
// get notified of phone state changes
TelephonyManager telephonyManager =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SERVICE_STATE);
}
/**
@@ -123,29 +131,48 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
};
mAirplaneModeOn = new ToggleAction(
R.drawable.ic_lock_airplane_mode,
R.drawable.ic_lock_airplane_mode_off,
R.string.global_actions_toggle_airplane_mode,
R.string.global_actions_airplane_mode_on_status,
R.string.global_actions_airplane_mode_off_status) {
void onToggle(boolean on) {
// Change the system setting
Settings.System.putInt(
mContext.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON,
on ? 1 : 0);
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", on);
mContext.sendBroadcast(intent);
}
@Override
protected void changeStateFromPress(boolean buttonOn) {
mState = buttonOn ? State.TurningOn : State.TurningOff;
mAirplaneState = mState;
}
public boolean showDuringKeyguard() {
return true;
}
public boolean showBeforeProvisioning() {
return false;
}
};
mItems = Lists.newArrayList(
/* Disabled pending bug 1304831 -- key or touch events wake up device before it
* can go to sleep.
// first: lock screen
new SinglePressAction(com.android.internal.R.drawable.ic_lock_lock, R.string.global_action_lock) {
public void onPress() {
mPowerManager.goToSleep(SystemClock.uptimeMillis() + 1);
}
public boolean showDuringKeyguard() {
return false;
}
public boolean showBeforeProvisioning() {
return false;
}
},
*/
// next: silent mode
// silent mode
mSilentModeToggle,
// next: airplane mode
mAirplaneModeOn,
// last: power off
new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off, R.string.global_action_power_off) {
new SinglePressAction(
com.android.internal.R.drawable.ic_lock_power_off,
R.string.global_action_power_off) {
public void onPress() {
// shutdown by making sure radio and power are handled accordingly.
@@ -180,10 +207,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
private void prepareDialog() {
// TODO: May need another 'Vibrate' toggle button, but for now treat them the same
final boolean silentModeOn =
mAudioManager.getRingerMode() != AudioManager.RINGER_MODE_NORMAL;
mSilentModeToggle.updateState(silentModeOn);
mSilentModeToggle.updateState(
silentModeOn ? ToggleAction.State.On : ToggleAction.State.Off);
mAirplaneModeOn.updateState(mAirplaneState);
mAdapter.notifyDataSetChanged();
if (mKeyguardShowing) {
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
@@ -192,6 +220,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
}
/** {@inheritDoc} */
public void onDismiss(DialogInterface dialog) {
mStatusBar.disable(StatusBarManager.DISABLE_NONE);
@@ -229,6 +258,16 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
return count;
}
@Override
public boolean isEnabled(int position) {
return getItem(position).isEnabled();
}
@Override
public boolean areAllItemsEnabled() {
return false;
}
public Action getItem(int position) {
int filteredPos = 0;
@@ -259,7 +298,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
public View getView(int position, View convertView, ViewGroup parent) {
Action action = getItem(position);
return action.create(mContext, (LinearLayout) convertView, LayoutInflater.from(mContext));
return action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
}
}
@@ -273,7 +312,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
* What each item in the global actions dialog must be able to support.
*/
private interface Action {
LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater);
View create(Context context, View convertView, ViewGroup parent, LayoutInflater inflater);
void onPress();
@@ -288,6 +327,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
* device is provisioned.
*/
boolean showBeforeProvisioning();
boolean isEnabled();
}
/**
@@ -303,12 +344,17 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mMessageResId = messageResId;
}
public boolean isEnabled() {
return true;
}
abstract public void onPress();
public LinearLayout create(Context context, LinearLayout convertView, LayoutInflater inflater) {
LinearLayout v = (LinearLayout) ((convertView != null) ?
public View create(
Context context, View convertView, ViewGroup parent, LayoutInflater inflater) {
View v = (convertView != null) ?
convertView :
inflater.inflate(R.layout.global_actions_item, null));
inflater.inflate(R.layout.global_actions_item, parent, false);
ImageView icon = (ImageView) v.findViewById(R.id.icon);
TextView messageView = (TextView) v.findViewById(R.id.message);
@@ -326,9 +372,26 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
* A toggle action knows whether it is on or off, and displays an icon
* and status message accordingly.
*/
static abstract class ToggleAction implements Action {
private static abstract class ToggleAction implements Action {
private boolean mOn = false;
enum State {
Off(false),
TurningOn(true),
TurningOff(true),
On(false);
private final boolean inTransition;
State(boolean intermediate) {
inTransition = intermediate;
}
public boolean inTransition() {
return inTransition;
}
}
protected State mState = State.Off;
// prefs
private final int mEnabledIconResId;
@@ -356,12 +419,12 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
mDisabledStatusMessageResId = disabledStatusMessageResId;
}
public LinearLayout create(Context context, LinearLayout convertView,
public View create(Context context, View convertView, ViewGroup parent,
LayoutInflater inflater) {
LinearLayout v = (LinearLayout) ((convertView != null) ?
View v = (convertView != null) ?
convertView :
inflater.inflate(R
.layout.global_actions_item, null));
.layout.global_actions_item, parent, false);
ImageView icon = (ImageView) v.findViewById(R.id.icon);
TextView messageView = (TextView) v.findViewById(R.id.message);
@@ -369,23 +432,50 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
messageView.setText(mMessageResId);
boolean on = ((mState == State.On) || (mState == State.TurningOn));
icon.setImageDrawable(context.getResources().getDrawable(
(mOn ? mEnabledIconResId : mDisabledIconResid)));
statusView.setText(mOn ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
(on ? mEnabledIconResId : mDisabledIconResid)));
statusView.setText(on ? mEnabledStatusMessageResId : mDisabledStatusMessageResId);
statusView.setVisibility(View.VISIBLE);
final boolean enabled = isEnabled();
messageView.setEnabled(enabled);
statusView.setEnabled(enabled);
icon.setEnabled(enabled);
v.setEnabled(enabled);
return v;
}
public void onPress() {
updateState(!mOn);
onToggle(mOn);
public final void onPress() {
if (mState.inTransition()) {
Log.w(TAG, "shouldn't be able to toggle when in transition");
return;
}
final boolean nowOn = !(mState == State.On);
onToggle(nowOn);
changeStateFromPress(nowOn);
}
public boolean isEnabled() {
return !mState.inTransition();
}
/**
* Implementations may override this if their state can be in on of the intermediate
* states until some notification is received (e.g airplane mode is 'turning off' until
* we know the wireless connections are back online
* @param buttonOn Whether the button was turned on or off
*/
protected void changeStateFromPress(boolean buttonOn) {
mState = buttonOn ? State.On : State.Off;
}
abstract void onToggle(boolean on);
public void updateState(boolean on) {
mOn = on;
public void updateState(State state) {
mState = state;
}
}
@@ -401,6 +491,16 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
};
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
final boolean inAirplaneMode = serviceState.getState() == ServiceState.STATE_POWER_OFF;
mAirplaneState = inAirplaneMode ? ToggleAction.State.On : ToggleAction.State.Off;
mAirplaneModeOn.updateState(mAirplaneState);
mAdapter.notifyDataSetChanged();
}
};
private static final int MESSAGE_DISMISS = 0;
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {

View File

@@ -32,6 +32,12 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.PixelFormat;
import android.graphics.ColorFilter;
import com.android.internal.R;
import com.android.internal.widget.LockPatternUtils;
@@ -233,7 +239,8 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
(LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
- LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
showAlmostAtAccountLoginDialog();
} else if (mHasAccount && failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
} else if (mHasAccount
&& failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
mLockPatternUtils.setPermanentlyLocked(true);
updateScreen(mMode);
} else if ((failedAttempts % LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)
@@ -254,6 +261,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
setFocusableInTouchMode(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
// wall paper background
final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper();
setBackgroundDrawable(
new FastBitmapDrawable(drawable.getBitmap()));
// create both the lock and unlock screen so they are quickly available
// when the screen turns on
mLockScreen = createLockScreen();
@@ -408,6 +420,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
final View visibleScreen = (mode == Mode.LockScreen)
? mLockScreen : getUnlockScreenForCurrentUnlockMode();
// do this before changing visibility so focus isn't requested before the input
// flag is set
mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());
if (mScreenOn) {
if (goneScreen.getVisibility() == View.VISIBLE) {
@@ -421,8 +437,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
goneScreen.setVisibility(View.GONE);
visibleScreen.setVisibility(View.VISIBLE);
mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());
if (!visibleScreen.requestFocus()) {
throw new IllegalStateException("keyguard screen must be able to take "
+ "focus when shown " + visibleScreen.getClass().getCanonicalName());
@@ -567,4 +582,58 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
dialog.show();
}
/**
* Used to put wallpaper on the background of the lock screen. Centers it Horizontally and
* vertically.
*/
static private class FastBitmapDrawable extends Drawable {
private Bitmap mBitmap;
private FastBitmapDrawable(Bitmap bitmap) {
mBitmap = bitmap;
}
@Override
public void draw(Canvas canvas) {
canvas.drawBitmap(
mBitmap,
(getBounds().width() - mBitmap.getWidth()) / 2,
(getBounds().height() - mBitmap.getHeight()) / 2,
null);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getIntrinsicWidth() {
return mBitmap.getWidth();
}
@Override
public int getIntrinsicHeight() {
return mBitmap.getHeight();
}
@Override
public int getMinimumWidth() {
return mBitmap.getWidth();
}
@Override
public int getMinimumHeight() {
return mBitmap.getHeight();
}
}
}

View File

@@ -155,14 +155,45 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private boolean mKeycodeCameraTimeoutActive = false;
static final int MSG_MENU_LONG_PRESS = 1;
static final int MSG_CALL_LONG_PRESS = 2;
static final int MSG_CAMERA_LONG_PRESS = 3;
static final int MSG_MENU_LONG_PRESS_COMPLETE = 2;
static final int MSG_CALL_LONG_PRESS = 3;
static final int MSG_CALL_LONG_PRESS_COMPLETE = 4;
static final int MSG_CAMERA_LONG_PRESS = 5;
static final int MSG_CAMERA_LONG_PRESS_COMPLETE = 6;
private final Handler mKeycodeMenuTimeoutHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_MENU_LONG_PRESS: {
if (mPanelChordingKey == 0) return;
// Before actually doing the long press, enqueue another
// message and do the processing there. This helps if
// the app isn't being responsive, and finally woke up --
// if the window manager wasn't told about it processing
// the down key for too long, it would enqueue the key up
// at a time after the timeout of this message. So we go
// through another message, to make sure we process an up
// before continuing.
mKeycodeMenuTimeoutHandler.sendEmptyMessage(
MSG_MENU_LONG_PRESS_COMPLETE);
break;
}
case MSG_CALL_LONG_PRESS: {
if (!mKeycodeCallTimeoutActive) return;
// See above.
mKeycodeMenuTimeoutHandler.sendEmptyMessage(
MSG_CALL_LONG_PRESS_COMPLETE);
break;
}
case MSG_CAMERA_LONG_PRESS: {
if (!mKeycodeCameraTimeoutActive) return;
// See above.
mKeycodeMenuTimeoutHandler.sendEmptyMessage(
MSG_CAMERA_LONG_PRESS_COMPLETE);
break;
}
case MSG_MENU_LONG_PRESS_COMPLETE: {
if (mPanelChordingKey == 0) return;
mPanelChordingKey = 0;
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
@@ -172,7 +203,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
imm.showSoftInputUnchecked(InputMethodManager.SHOW_FORCED);
}
} break;
case MSG_CALL_LONG_PRESS: {
case MSG_CALL_LONG_PRESS_COMPLETE: {
if (!mKeycodeCallTimeoutActive) return;
mKeycodeCallTimeoutActive = false;
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
@@ -186,7 +217,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
startCallActivity();
}
} break;
case MSG_CAMERA_LONG_PRESS: {
case MSG_CAMERA_LONG_PRESS_COMPLETE: {
if (!mKeycodeCameraTimeoutActive) return;
mKeycodeCameraTimeoutActive = false;
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
@@ -194,6 +225,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj);
getContext().sendOrderedBroadcast(intent, null);
sendCloseSystemWindows();
} break;
}
}

View File

@@ -139,7 +139,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
// Vibrator pattern for haptic feedback of a long press.
private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 40, 41};
private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21};
// Vibrator pattern for haptic feedback of a zoom ring tick
private static final long[] ZOOM_RING_TICK_VIBE_PATTERN = {0, 10};
@@ -388,7 +388,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
void showGlobalActionsDialog() {
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext, mPowerManager);
mGlobalActions = new GlobalActions(mContext);
}
final boolean keyguardShowing = mKeyguardMediator.isShowing();
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());

View File

@@ -289,7 +289,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
mLockPatternView
.setDisplayMode(LockPatternView.DisplayMode.Correct);
mUnlockIcon.setVisibility(View.GONE);
mUnlockHeader.setText(R.string.lockscreen_pattern_correct);
mUnlockHeader.setText("");
mCallback.keyguardDone(true);
} else {
mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS);