merge from eclair

This commit is contained in:
Jean-Baptiste Queru
2009-11-15 12:06:39 -08:00
14 changed files with 1720 additions and 839 deletions

View File

@@ -19,38 +19,39 @@ package com.android.internal.policy.impl;
import com.android.internal.R;
import com.android.internal.widget.LockPatternUtils;
import android.accounts.AccountsServiceConstants;
import android.accounts.IAccountsService;
import android.content.ComponentName;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.OperationCanceledException;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.AccountManagerCallback;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.RemoteException;
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;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.os.Bundle;
import java.io.IOException;
/**
* When the user forgets their password a bunch of times, we fall back on their
* account's login/password to unlock the phone (and reset their lock pattern).
*
* <p>This class is useful only on platforms that support the
* IAccountsService.
*/
public class AccountUnlockScreen extends RelativeLayout implements KeyguardScreen,
View.OnClickListener, ServiceConnection, TextWatcher {
View.OnClickListener, TextWatcher {
private static final String LOCK_PATTERN_PACKAGE = "com.android.settings";
private static final String LOCK_PATTERN_CLASS =
"com.android.settings.ChooseLockPattern";
@@ -62,7 +63,6 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
private final KeyguardScreenCallback mCallback;
private final LockPatternUtils mLockPatternUtils;
private IAccountsService mAccountsService;
private TextView mTopHeader;
private TextView mInstructions;
@@ -71,15 +71,17 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
private Button mOk;
private Button mEmergencyCall;
/**
* Shown while making asynchronous check of password.
*/
private ProgressDialog mCheckingDialog;
/**
* AccountUnlockScreen constructor.
*
* @throws IllegalStateException if the IAccountsService is not
* available on the current platform.
*/
public AccountUnlockScreen(Context context,
KeyguardScreenCallback callback,
LockPatternUtils lockPatternUtils) {
KeyguardScreenCallback callback,
LockPatternUtils lockPatternUtils) {
super(context);
mCallback = callback;
mLockPatternUtils = lockPatternUtils;
@@ -88,6 +90,9 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
R.layout.keyguard_screen_glogin_unlock, this, true);
mTopHeader = (TextView) findViewById(R.id.topHeader);
mTopHeader.setText(mLockPatternUtils.isPermanentlyLocked() ?
R.string.lockscreen_glogin_too_many_attempts :
R.string.lockscreen_glogin_forgot_pattern);
mInstructions = (TextView) findViewById(R.id.instructions);
@@ -103,14 +108,6 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
mEmergencyCall = (Button) findViewById(R.id.emergencyCall);
mEmergencyCall.setOnClickListener(this);
Log.v("AccountUnlockScreen", "debug: Connecting to accounts service");
final boolean connected = mContext.bindService(AccountsServiceConstants.SERVICE_INTENT,
this, Context.BIND_AUTO_CREATE);
if (!connected) {
Log.v("AccountUnlockScreen", "debug: Couldn't connect to accounts service");
throw new IllegalStateException("couldn't bind to accounts service");
}
}
public void afterTextChanged(Editable s) {
@@ -150,30 +147,16 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
/** {@inheritDoc} */
public void cleanUp() {
mContext.unbindService(this);
if (mCheckingDialog != null) {
mCheckingDialog.hide();
}
}
/** {@inheritDoc} */
public void onClick(View v) {
mCallback.pokeWakelock();
if (v == mOk) {
if (checkPassword()) {
// clear out forgotten password
mLockPatternUtils.setPermanentlyLocked(false);
// launch the 'choose lock pattern' activity so
// the user can pick a new one if they want to
Intent intent = new Intent();
intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
// close the keyguard
mCallback.keyguardDone(true);
} else {
mInstructions.setText(R.string.lockscreen_glogin_invalid_input);
mPassword.setText("");
}
asyncCheckPassword();
}
if (v == mEmergencyCall) {
@@ -181,11 +164,37 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
}
}
private void onCheckPasswordResult(boolean success) {
if (success) {
// clear out forgotten password
mLockPatternUtils.setPermanentlyLocked(false);
mLockPatternUtils.setLockPatternEnabled(false);
mLockPatternUtils.saveLockPattern(null);
// launch the 'choose lock pattern' activity so
// the user can pick a new one if they want to
Intent intent = new Intent();
intent.setClassName(LOCK_PATTERN_PACKAGE, LOCK_PATTERN_CLASS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
// close the keyguard
mCallback.keyguardDone(true);
} else {
mInstructions.setText(R.string.lockscreen_glogin_invalid_input);
mPassword.setText("");
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
mCallback.goToLockScreen();
if (mLockPatternUtils.isPermanentlyLocked()) {
mCallback.goToLockScreen();
} else {
mCallback.forgotPattern(false);
}
return true;
}
return super.dispatchKeyEvent(event);
@@ -207,33 +216,25 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
* @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;
}
private Account findIntendedAccount(String username) {
Account[] accounts = AccountManager.get(mContext).getAccounts();
// 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;
Account bestAccount = null;
int bestScore = 0;
for (String a: accounts) {
for (Account a: accounts) {
int score = 0;
if (username.equals(a)) {
if (username.equals(a.name)) {
score = 4;
} else if (username.equalsIgnoreCase(a)) {
} else if (username.equalsIgnoreCase(a.name)) {
score = 3;
} else if (username.indexOf('@') < 0) {
int i = a.indexOf('@');
int i = a.name.indexOf('@');
if (i >= 0) {
String aUsername = a.substring(0, i);
String aUsername = a.name.substring(0, i);
if (username.equals(aUsername)) {
score = 2;
} else if (username.equalsIgnoreCase(aUsername)) {
@@ -251,28 +252,64 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
return bestAccount;
}
private boolean checkPassword() {
private void asyncCheckPassword() {
mCallback.pokeWakelock(AWAKE_POKE_MILLIS);
final String login = mLogin.getText().toString();
final String password = mPassword.getText().toString();
try {
String account = findIntendedAccount(login);
if (account == null) {
return false;
}
return mAccountsService.shouldUnlock(account, password);
} catch (RemoteException e) {
return false;
Account account = findIntendedAccount(login);
if (account == null) {
onCheckPasswordResult(false);
return;
}
getProgressDialog().show();
Bundle options = new Bundle();
options.putString(AccountManager.KEY_PASSWORD, password);
AccountManager.get(mContext).confirmCredentials(account, options, null /* activity */,
new AccountManagerCallback<Bundle>() {
public void run(AccountManagerFuture<Bundle> future) {
try {
mCallback.pokeWakelock(AWAKE_POKE_MILLIS);
final Bundle result = future.getResult();
final boolean verified = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
// ensure on UI thread
mLogin.post(new Runnable() {
public void run() {
onCheckPasswordResult(verified);
}
});
} catch (OperationCanceledException e) {
onCheckPasswordResult(false);
} catch (IOException e) {
onCheckPasswordResult(false);
} catch (AuthenticatorException e) {
onCheckPasswordResult(false);
} finally {
mLogin.post(new Runnable() {
public void run() {
getProgressDialog().hide();
}
});
}
}
}, null /* handler */);
}
/** {@inheritDoc} */
public void onServiceConnected(ComponentName name, IBinder service) {
Log.v("AccountUnlockScreen", "debug: About to grab as interface");
mAccountsService = IAccountsService.Stub.asInterface(service);
}
/** {@inheritDoc} */
public void onServiceDisconnected(ComponentName name) {
mAccountsService = null;
private Dialog getProgressDialog() {
if (mCheckingDialog == null) {
mCheckingDialog = new ProgressDialog(mContext);
mCheckingDialog.setMessage(
mContext.getString(R.string.lockscreen_glogin_checking_password));
mCheckingDialog.setIndeterminate(true);
mCheckingDialog.setCancelable(false);
mCheckingDialog.getWindow().setType(
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
if (!mContext.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) {
mCheckingDialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
}
}
return mCheckingDialog;
}
}

View File

@@ -16,6 +16,7 @@
package com.android.internal.policy.impl;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
@@ -26,6 +27,7 @@ import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
@@ -40,6 +42,8 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.app.ShutdownThread;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.telephony.TelephonyProperties;
import com.google.android.collect.Lists;
import java.util.ArrayList;
@@ -69,6 +73,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
private boolean mKeyguardShowing = false;
private boolean mDeviceProvisioned = false;
private ToggleAction.State mAirplaneState = ToggleAction.State.Off;
private boolean mIsWaitingForEcmExit = false;
/**
* @param context everything needs a context :(
@@ -81,6 +86,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
context.registerReceiver(mBroadcastReceiver, filter);
// get notified of phone state changes
@@ -141,20 +147,27 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
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);
if (Boolean.parseBoolean(
SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {
mIsWaitingForEcmExit = true;
// Launch ECM exit dialog
Intent ecmDialogIntent =
new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);
ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(ecmDialogIntent);
} else {
changeAirplaneModeSystemSetting(on);
}
}
@Override
protected void changeStateFromPress(boolean buttonOn) {
mState = buttonOn ? State.TurningOn : State.TurningOff;
mAirplaneState = mState;
// In ECM mode airplane state cannot be changed
if (!(Boolean.parseBoolean(
SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {
mState = buttonOn ? State.TurningOn : State.TurningOff;
mAirplaneState = mState;
}
}
public boolean showDuringKeyguard() {
@@ -200,8 +213,11 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
final AlertDialog dialog = ab.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
if (!mContext.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) {
dialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
}
dialog.setOnDismissListener(this);
@@ -218,7 +234,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
if (mKeyguardShowing) {
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
} else {
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
}
}
@@ -490,6 +506,14 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
if (!PhoneWindowManager.SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS.equals(reason)) {
mHandler.sendEmptyMessage(MESSAGE_DISMISS);
}
} else if (TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED.equals(action)) {
// Airplane mode can be changed after ECM exits if airplane toggle button
// is pressed during ECM mode
if (!(intent.getBooleanExtra("PHONE_IN_ECM_STATE", false)) &&
mIsWaitingForEcmExit) {
mIsWaitingForEcmExit = false;
changeAirplaneModeSystemSetting(true);
}
}
}
};
@@ -514,4 +538,17 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
}
}
};
/**
* Change the airplane mode system setting
*/
private void changeAirplaneModeSystemSetting(boolean on) {
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);
}
}

View File

@@ -28,10 +28,19 @@ public interface KeyguardScreenCallback extends KeyguardViewCallback {
void goToLockScreen();
/**
* Transitino to th unlock screen.
* Transition to the unlock screen.
*/
void goToUnlockScreen();
/**
* The user reported that they forgot their pattern (or not, when they want to back out of the
* forgot pattern screen).
*
* @param isForgotten True if the user hit the forgot pattern, false if they want to back out
* of the account screen.
*/
void forgotPattern(boolean isForgotten);
/**
* @return Whether the keyguard requires some sort of PIN.
*/

View File

@@ -35,7 +35,6 @@ import static android.provider.Telephony.Intents.EXTRA_SHOW_SPN;
import static android.provider.Telephony.Intents.EXTRA_SPN;
import static android.provider.Telephony.Intents.SPN_STRINGS_UPDATED_ACTION;
import com.android.internal.app.ShutdownThread;
import com.android.internal.telephony.IccCard;
import com.android.internal.telephony.TelephonyIntents;
import android.util.Log;
@@ -67,6 +66,8 @@ public class KeyguardUpdateMonitor {
private boolean mInPortrait;
private boolean mKeyboardOpen;
private boolean mKeyguardBypassEnabled;
private boolean mDevicePluggedIn;
private boolean mDeviceProvisioned;
@@ -163,6 +164,9 @@ public class KeyguardUpdateMonitor {
}
};
mKeyguardBypassEnabled = context.getResources().getBoolean(
com.android.internal.R.bool.config_bypass_keyguard_if_slider_open);
mDeviceProvisioned = Settings.Secure.getInt(
mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0;
@@ -295,13 +299,6 @@ public class KeyguardUpdateMonitor {
shouldShowBatteryInfo(), pluggedIn, batteryLevel);
}
}
// shut down gracefully if our battery is critically low and we are not powered
if (batteryLevel == 0 &&
pluggedInStatus != BATTERY_STATUS_CHARGING &&
pluggedInStatus != BATTERY_STATUS_UNKNOWN) {
ShutdownThread.shutdown(mContext, false);
}
}
/**
@@ -513,6 +510,10 @@ public class KeyguardUpdateMonitor {
return mKeyboardOpen;
}
public boolean isKeyguardBypassEnabled() {
return mKeyguardBypassEnabled;
}
public boolean isDevicePluggedIn() {
return mDevicePluggedIn;
}

View File

@@ -48,7 +48,7 @@ public class KeyguardViewManager implements KeyguardWindowController {
private WindowManager.LayoutParams mWindowLayoutParams;
private boolean mNeedsInput = false;
private FrameLayout mKeyguardHost;
private KeyguardViewBase mKeyguardView;
@@ -101,6 +101,8 @@ public class KeyguardViewManager implements KeyguardWindowController {
final int stretch = ViewGroup.LayoutParams.FILL_PARENT;
int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
| WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
| WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
/*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ;
if (!mNeedsInput) {
@@ -108,7 +110,7 @@ public class KeyguardViewManager implements KeyguardWindowController {
}
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD,
flags, PixelFormat.OPAQUE);
flags, PixelFormat.TRANSLUCENT);
lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
@@ -152,7 +154,7 @@ public class KeyguardViewManager implements KeyguardWindowController {
mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
}
}
/**
* Reset the state of the view.
*/
@@ -195,10 +197,14 @@ public class KeyguardViewManager implements KeyguardWindowController {
*
* @param keyCode The wake key.
*/
public void wakeWhenReadyTq(int keyCode) {
public boolean wakeWhenReadyTq(int keyCode) {
if (DEBUG) Log.d(TAG, "wakeWhenReady(" + keyCode + ")");
if (mKeyguardView != null) {
mKeyguardView.wakeWhenReadyTq(keyCode);
return true;
} else {
Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq");
return false;
}
}
@@ -209,10 +215,19 @@ public class KeyguardViewManager implements KeyguardWindowController {
if (DEBUG) Log.d(TAG, "hide()");
if (mKeyguardHost != null) {
mKeyguardHost.setVisibility(View.GONE);
// Don't do this right away, so we can let the view continue to animate
// as it goes away.
if (mKeyguardView != null) {
mKeyguardHost.removeView(mKeyguardView);
mKeyguardView.cleanUp();
final KeyguardViewBase lastView = mKeyguardView;
mKeyguardView = null;
mKeyguardHost.postDelayed(new Runnable() {
public void run() {
synchronized (KeyguardViewManager.this) {
mKeyguardHost.removeView(lastView);
lastView.cleanUp();
}
}
}, 500);
}
}
}

View File

@@ -19,11 +19,9 @@ package com.android.internal.policy.impl;
import com.android.internal.telephony.IccCard;
import com.android.internal.widget.LockPatternUtils;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.StatusBarManager;
import static android.app.StatusBarManager.DISABLE_EXPAND;
import static android.app.StatusBarManager.DISABLE_NONE;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -32,7 +30,9 @@ import android.os.Handler;
import android.os.LocalPowerManager;
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.telephony.TelephonyManager;
import android.util.Config;
import android.util.EventLog;
@@ -84,7 +84,7 @@ import android.view.WindowManagerPolicy;
* thread of the keyguard.
*/
public class KeyguardViewMediator implements KeyguardViewCallback,
KeyguardUpdateMonitor.ConfigurationChangeCallback, KeyguardUpdateMonitor.SimStateCallback {
KeyguardUpdateMonitor.SimStateCallback {
private final static boolean DEBUG = false && Config.LOGD;
private final static boolean DBG_WAKE = DEBUG || true;
@@ -104,6 +104,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
private static final int WAKE_WHEN_READY = 8;
private static final int KEYGUARD_DONE = 9;
private static final int KEYGUARD_DONE_DRAWING = 10;
private static final int KEYGUARD_DONE_AUTHENTICATING = 11;
/**
* The default amount of time we stay awake (used for all key input)
@@ -122,7 +123,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
* turning on the keyguard (i.e, the user has this much time to turn
* the screen back on without having to face the keyguard).
*/
private static final int KEYGUARD_DELAY_MS = 0;
private static final int KEYGUARD_DELAY_MS = 5000;
/**
* How long we'll wait for the {@link KeyguardViewCallback#keyguardDoneDrawing()}
@@ -149,6 +150,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
*/
private PowerManager.WakeLock mWakeLock;
/**
* Used to keep the device awake while to ensure the keyguard finishes opening before
* we sleep.
*/
private PowerManager.WakeLock mShowKeyguardWakeLock;
/**
* Does not turn on screen, held while a call to {@link KeyguardViewManager#wakeWhenReadyTq(int)}
* is called to make sure the device doesn't sleep before it has a chance to poke
@@ -157,11 +164,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
*/
private PowerManager.WakeLock mWakeAndHandOff;
/**
* Used to disable / reenable status bar expansion.
*/
private StatusBarManager mStatusBarManager;
private KeyguardViewManager mKeyguardViewManager;
// these are protected by synchronized (this)
@@ -182,6 +184,9 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
// answer whether the input should be restricted)
private boolean mShowing = false;
// true if the keyguard is hidden by another window
private boolean mHidden = false;
/**
* Helps remember whether the screen has turned on since the last time
* it turned off due to timeout. see {@link #onScreenTurnedOff(int)}
@@ -229,6 +234,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
"keyguard");
mWakeLock.setReferenceCounted(false);
mShowKeyguardWakeLock = mPM.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "show keyguard");
mShowKeyguardWakeLock.setReferenceCounted(false);
mWakeAndHandOff = mPM.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK,
@@ -245,7 +252,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
mUpdateMonitor = new KeyguardUpdateMonitor(context);
mUpdateMonitor.registerConfigurationChangeCallback(this);
mUpdateMonitor.registerSimStateCallback(this);
mKeyguardViewProperties =
@@ -347,14 +353,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
if (DEBUG) Log.d(TAG, "remembering to reshow, hiding keyguard, "
+ "disabling status bar expansion");
mNeedToReshowWhenReenabled = true;
setStatusBarExpandable(false);
hideLocked();
} else if (enabled && mNeedToReshowWhenReenabled) {
// reenabled after previously hidden, reshow
if (DEBUG) Log.d(TAG, "previously hidden, reshowing, reenabling "
+ "status bar expansion");
mNeedToReshowWhenReenabled = false;
setStatusBarExpandable(true);
if (mExitSecureCallback != null) {
if (DEBUG) Log.d(TAG, "onKeyguardExitResult(false), resetting");
@@ -409,15 +413,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
}
}
private void setStatusBarExpandable(boolean isExpandable) {
if (mStatusBarManager == null) {
mStatusBarManager =
(StatusBarManager) mContext.getSystemService(Context.STATUS_BAR_SERVICE);
}
mStatusBarManager.disable(isExpandable ? DISABLE_NONE : DISABLE_EXPAND);
}
/**
* Is the keyguard currently showing?
*/
@@ -425,6 +420,17 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
return mShowing;
}
/**
* Notify us when the keyguard is hidden by another window
*/
public void setHidden(boolean isHidden) {
if (DEBUG) Log.d(TAG, "setHidden " + isHidden);
synchronized (KeyguardViewMediator.this) {
mHidden = isHidden;
adjustUserActivityLocked();
}
}
/**
* Given the state of the keyguard, is the input restricted?
* Input is restricted when the keyguard is showing, or when the keyguard
@@ -434,6 +440,21 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
return mShowing || mNeedToReshowWhenReenabled || !mUpdateMonitor.isDeviceProvisioned();
}
/**
* Returns true if the change is resulting in the keyguard beign dismissed,
* meaning the screen can turn on immediately. Otherwise returns false.
*/
public boolean doLidChangeTq(boolean isLidOpen) {
mKeyboardOpen = isLidOpen;
if (mUpdateMonitor.isKeyguardBypassEnabled() && mKeyboardOpen
&& !mKeyguardViewProperties.isSecure() && mKeyguardViewManager.isShowing()) {
if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard");
mHandler.sendEmptyMessage(KEYGUARD_DONE_AUTHENTICATING);
return true;
}
return false;
}
/**
* Enable the keyguard if the settings are appropriate.
@@ -463,9 +484,13 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
}
// if the setup wizard hasn't run yet, don't show
final boolean requireSim = !SystemProperties.getBoolean("keyguard.no_require_sim",
false);
final boolean provisioned = mUpdateMonitor.isDeviceProvisioned();
final IccCard.State state = mUpdateMonitor.getSimState();
final boolean lockedOrMissing = state.isPinLocked() || (state == IccCard.State.ABSENT);
final boolean lockedOrMissing = state.isPinLocked()
|| ((state == IccCard.State.ABSENT) && requireSim);
if (!lockedOrMissing && !provisioned) {
if (DEBUG) Log.d(TAG, "doKeyguard: not showing because device isn't provisioned"
+ " and the sim is not locked or missing");
@@ -544,6 +569,8 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
*/
private void showLocked() {
if (DEBUG) Log.d(TAG, "showLocked");
// ensure we stay awake until we are finished displaying the keyguard
mShowKeyguardWakeLock.acquire();
Message msg = mHandler.obtainMessage(SHOW);
mHandler.sendMessage(msg);
}
@@ -558,26 +585,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
mHandler.sendMessage(msg);
}
/**
* {@link KeyguardUpdateMonitor} callbacks.
*/
/** {@inheritDoc} */
public void onOrientationChange(boolean inPortrait) {
}
/** {@inheritDoc} */
public void onKeyboardChange(boolean isKeyboardOpen) {
mKeyboardOpen = isKeyboardOpen;
if (mKeyboardOpen && !mKeyguardViewProperties.isSecure()
&& mKeyguardViewManager.isShowing()) {
if (DEBUG) Log.d(TAG, "bypassing keyguard on sliding open of keyboard with non-secure keyguard");
keyguardDone(true);
}
}
/** {@inheritDoc} */
public void onSimStateChanged(IccCard.State simState) {
if (DEBUG) Log.d(TAG, "onSimStateChanged: " + simState);
@@ -615,6 +622,10 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
}
}
public boolean isSecure() {
return mKeyguardViewProperties.isSecure();
}
private BroadcastReceiver mBroadCastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -719,10 +730,15 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
* @see #handleKeyguardDone
*/
public void keyguardDone(boolean authenticated) {
keyguardDone(authenticated, true);
}
public void keyguardDone(boolean authenticated, boolean wakeup) {
synchronized (this) {
EventLog.writeEvent(70000, 2);
if (DEBUG) Log.d(TAG, "keyguardDone(" + authenticated + ")");
Message msg = mHandler.obtainMessage(KEYGUARD_DONE);
msg.arg1 = wakeup ? 1 : 0;
mHandler.sendMessage(msg);
if (authenticated) {
@@ -738,7 +754,6 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
// the keyguard when they've released the lock
mExternallyEnabled = true;
mNeedToReshowWhenReenabled = false;
setStatusBarExpandable(true);
}
}
}
@@ -789,10 +804,14 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
handleWakeWhenReady(msg.arg1);
return;
case KEYGUARD_DONE:
handleKeyguardDone();
handleKeyguardDone(msg.arg1 != 0);
return;
case KEYGUARD_DONE_DRAWING:
handleKeyguardDoneDrawing();
return;
case KEYGUARD_DONE_AUTHENTICATING:
keyguardDone(true);
return;
}
}
};
@@ -801,10 +820,12 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
* @see #keyguardDone
* @see #KEYGUARD_DONE
*/
private void handleKeyguardDone() {
private void handleKeyguardDone(boolean wakeup) {
if (DEBUG) Log.d(TAG, "handleKeyguardDone");
handleHide();
mPM.userActivity(SystemClock.uptimeMillis(), true);
if (wakeup) {
mPM.userActivity(SystemClock.uptimeMillis(), true);
}
mWakeLock.release();
mContext.sendBroadcast(mUserPresentIntent);
}
@@ -853,12 +874,14 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
if (DEBUG) Log.d(TAG, "handleShow");
if (!mSystemReady) return;
// while we're showing, we control the wake state, so ask the power
// manager not to honor request for userActivity.
mRealPowerManager.enableUserActivity(false);
mKeyguardViewManager.show();
mShowing = true;
adjustUserActivityLocked();
try {
ActivityManagerNative.getDefault().closeSystemDialogs("lock");
} catch (RemoteException e) {
}
mShowKeyguardWakeLock.release();
}
}
@@ -869,11 +892,25 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
private void handleHide() {
synchronized (KeyguardViewMediator.this) {
if (DEBUG) Log.d(TAG, "handleHide");
// When we go away, tell the poewr manager to honor requests from userActivity.
mRealPowerManager.enableUserActivity(true);
if (mWakeAndHandOff.isHeld()) {
Log.w(TAG, "attempt to hide the keyguard while waking, ignored");
return;
}
mKeyguardViewManager.hide();
mShowing = false;
adjustUserActivityLocked();
}
}
private void adjustUserActivityLocked() {
// disable user activity if we are shown and not hidden
if (DEBUG) Log.d(TAG, "adjustUserActivityLocked mShowing: " + mShowing + " mHidden: " + mHidden);
boolean enabled = !mShowing || mHidden;
mRealPowerManager.enableUserActivity(enabled);
if (!enabled && mScreenOn) {
// reinstate our short screen timeout policy
pokeWakelock();
}
}
@@ -888,7 +925,11 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
// this should result in a call to 'poke wakelock' which will set a timeout
// on releasing the wakelock
mKeyguardViewManager.wakeWhenReadyTq(keyCode);
if (!mKeyguardViewManager.wakeWhenReadyTq(keyCode)) {
// poke wakelock ourselves if keyguard is no longer active
Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock, so poke it ourselves");
pokeWakelock();
}
/**
* Now that the keyguard is ready and has poked the wake lock, we can
@@ -897,7 +938,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
mWakeAndHandOff.release();
if (!mWakeLock.isHeld()) {
Log.w(TAG, "mKeyguardViewManager.wakeWhenReadyTq did not poke wake lock");
Log.w(TAG, "mWakeLock not held in mKeyguardViewManager.wakeWhenReadyTq");
}
}
}

View File

@@ -16,41 +16,47 @@
package com.android.internal.policy.impl;
import android.accounts.AccountsServiceConstants;
import android.accounts.IAccountsService;
import com.android.internal.R;
import com.android.internal.telephony.IccCard;
import com.android.internal.widget.LockPatternUtils;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.SystemProperties;
import com.android.internal.telephony.IccCard;
import android.text.TextUtils;
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;
import java.io.IOException;
/**
* The host view for all of the screens of the pattern unlock screen. There are
* two {@link Mode}s of operation, lock and unlock. This will show the appropriate
* screen, and listen for callbacks via {@link com.android.internal.policy.impl.KeyguardScreenCallback
* screen, and listen for callbacks via
* {@link com.android.internal.policy.impl.KeyguardScreenCallback}
* from the current screen.
*
* This view, in turn, communicates back to {@link com.android.internal.policy.impl.KeyguardViewManager}
* This view, in turn, communicates back to
* {@link com.android.internal.policy.impl.KeyguardViewManager}
* via its {@link com.android.internal.policy.impl.KeyguardViewCallback}, as appropriate.
*/
public class LockPatternKeyguardView extends KeyguardViewBase {
public class LockPatternKeyguardView extends KeyguardViewBase
implements AccountManagerCallback<Account[]> {
// intent action for launching emergency dialer activity.
static final String ACTION_EMERGENCY_DIAL = "com.android.phone.EmergencyDialer.DIAL";
@@ -60,12 +66,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
private final KeyguardUpdateMonitor mUpdateMonitor;
private final KeyguardWindowController mWindowController;
private View mLockScreen;
private View mUnlockScreen;
private boolean mScreenOn = false;
private boolean mHasAccount = false; // assume they don't have an account until we know better
private boolean mEnableFallback = false; // assume no fallback UI until we know better
/**
@@ -114,10 +120,13 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
private Mode mMode = Mode.LockScreen;
/**
* Keeps track of what mode the current unlock screen is
* Keeps track of what mode the current unlock screen is (cached from most recent computation in
* {@link #getUnlockMode}).
*/
private UnlockMode mUnlockScreenMode;
private boolean mForgotPattern;
/**
* If true, it means we are in the process of verifying that the user
* can get past the lock screen per {@link #verifyUnlock()}
@@ -130,11 +139,6 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
*/
private final LockPatternUtils mLockPatternUtils;
/**
* Used to fetch accounts from GLS.
*/
private ServiceConnection mServiceConnection;
/**
* @return Whether we are stuck on the lock screen because the sim is
* missing.
@@ -145,6 +149,22 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
&& (mUpdateMonitor.getSimState() == IccCard.State.ABSENT);
}
public void run(AccountManagerFuture<Account[]> future) {
// We err on the side of caution.
// In case of error we assume we have a SAML account.
boolean hasSAMLAccount = true;
try {
hasSAMLAccount = future.getResult().length > 0;
} catch (OperationCanceledException e) {
} catch (IOException e) {
} catch (AuthenticatorException e) {
}
mEnableFallback = !hasSAMLAccount;
if (mUnlockScreen instanceof UnlockScreen) {
((UnlockScreen)mUnlockScreen).setEnableFallback(true);
}
}
/**
* @param context Used to inflate, and create views.
* @param updateMonitor Knows the state of the world, and passed along to each
@@ -158,9 +178,21 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
LockPatternUtils lockPatternUtils,
KeyguardWindowController controller) {
super(context);
final boolean hasAccount = AccountManager.get(context).getAccounts().length > 0;
if (hasAccount) {
/* If we have a SAML account which requires web login we can not use the
fallback screen UI to ask the user for credentials.
For now we will disable fallback screen in this case.
Ultimately we could consider bringing up a web login from GLS
but need to make sure that it will work in the "locked screen" mode. */
String[] features = new String[] {"saml"};
AccountManager.get(context).getAccountsByTypeAndFeatures(
"com.google", features, this, null);
}
asyncCheckForAccount();
mEnableFallback = false;
mRequiresSim =
TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim"));
@@ -169,10 +201,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
mWindowController = controller;
mMode = getInitialMode();
mKeyguardScreenCallback = new KeyguardScreenCallback() {
public void goToLockScreen() {
mForgotPattern = false;
if (mIsVerifyUnlockOnly) {
// navigating away from unlock screen during verify mode means
// we are done and the user failed to authenticate.
@@ -197,6 +230,13 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
}
}
public void forgotPattern(boolean isForgotten) {
if (mEnableFallback) {
mForgotPattern = isForgotten;
updateScreen(Mode.UnlockScreen);
}
}
public boolean isSecure() {
return LockPatternKeyguardView.this.isSecure();
}
@@ -235,11 +275,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
public void reportFailedPatternAttempt() {
mUpdateMonitor.reportFailedAttempt();
final int failedAttempts = mUpdateMonitor.getFailedAttempts();
if (mHasAccount && failedAttempts ==
(LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
if (mEnableFallback && failedAttempts ==
(LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET
- LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
showAlmostAtAccountLoginDialog();
} else if (mHasAccount
} else if (mEnableFallback
&& failedAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_RESET) {
mLockPatternUtils.setPermanentlyLocked(true);
updateScreen(mMode);
@@ -248,9 +288,9 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
showTimeoutDialog();
}
}
public boolean doesFallbackUnlockScreenExist() {
return mHasAccount;
return mEnableFallback;
}
};
@@ -262,9 +302,11 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
// wall paper background
final BitmapDrawable drawable = (BitmapDrawable) context.getWallpaper();
setBackgroundDrawable(
new FastBitmapDrawable(drawable.getBitmap()));
if (false) {
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
@@ -277,45 +319,18 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
updateScreen(mMode);
}
/**
* Asynchronously checks for at least one account. This will set mHasAccount
* to true if an account is found.
*/
private void asyncCheckForAccount() {
mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
try {
IAccountsService accountsService = IAccountsService.Stub.asInterface(service);
String accounts[] = accountsService.getAccounts();
mHasAccount = (accounts.length > 0);
} catch (RemoteException e) {
// Not much we can do here...
Log.e(TAG, "Gls died while attempting to get accounts: " + e);
} finally {
getContext().unbindService(mServiceConnection);
mServiceConnection = null;
}
}
public void onServiceDisconnected(ComponentName className) {
// nothing to do here
}
};
boolean status = getContext().bindService(AccountsServiceConstants.SERVICE_INTENT,
mServiceConnection, Context.BIND_AUTO_CREATE);
if (!status) Log.e(TAG, "Failed to bind to GLS while checking for account");
}
@Override
public void reset() {
mIsVerifyUnlockOnly = false;
mForgotPattern = false;
updateScreen(getInitialMode());
}
@Override
public void onScreenTurnedOff() {
mScreenOn = false;
mForgotPattern = false;
if (mMode == Mode.LockScreen) {
((KeyguardScreen) mLockScreen).onPause();
} else {
@@ -423,7 +438,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
// 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) {
@@ -454,12 +469,14 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
View createUnlockScreenFor(UnlockMode unlockMode) {
if (unlockMode == UnlockMode.Pattern) {
return new UnlockScreen(
UnlockScreen view = new UnlockScreen(
mContext,
mLockPatternUtils,
mUpdateMonitor,
mKeyguardScreenCallback,
mUpdateMonitor.getFailedAttempts());
view.setEnableFallback(mEnableFallback);
return view;
} else if (unlockMode == UnlockMode.SimPin) {
return new SimUnlockScreen(
mContext,
@@ -525,7 +542,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
final IccCard.State simState = mUpdateMonitor.getSimState();
if (stuckOnLockScreenBecauseSimMissing() || (simState == IccCard.State.PUK_REQUIRED)) {
return Mode.LockScreen;
} else if (mUpdateMonitor.isKeyboardOpen() && isSecure()) {
} else if (isSecure()) {
return Mode.UnlockScreen;
} else {
return Mode.LockScreen;
@@ -540,7 +557,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
if (simState == IccCard.State.PIN_REQUIRED || simState == IccCard.State.PUK_REQUIRED) {
return UnlockMode.SimPin;
} else {
return mLockPatternUtils.isPermanentlyLocked() ?
return (mForgotPattern || mLockPatternUtils.isPermanentlyLocked()) ?
UnlockMode.Account:
UnlockMode.Pattern;
}
@@ -558,9 +575,12 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
.setNeutralButton(R.string.ok, null)
.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
dialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
if (!mContext.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) {
dialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
}
dialog.show();
}
@@ -578,15 +598,20 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
.setNeutralButton(R.string.ok, null)
.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
dialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
if (!mContext.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) {
dialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
}
dialog.show();
}
/**
* Used to put wallpaper on the background of the lock screen. Centers it Horizontally and
* vertically.
* Used to put wallpaper on the background of the lock screen. Centers it
* Horizontally and pins the bottom (assuming that the lock screen is aligned
* with the bottom, so the wallpaper should extend above the top into the
* status bar).
*/
static private class FastBitmapDrawable extends Drawable {
private Bitmap mBitmap;
@@ -602,7 +627,7 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
canvas.drawBitmap(
mBitmap,
(getBounds().width() - mBitmap.getWidth()) / 2,
(getBounds().height() - mBitmap.getHeight()) / 2,
(getBounds().height() - mBitmap.getHeight()),
null);
}

View File

@@ -18,21 +18,26 @@ package com.android.internal.policy.impl;
import com.android.internal.R;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.RotarySelector;
import android.content.Context;
import android.content.res.Resources;
import android.text.format.DateFormat;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.*;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.media.AudioManager;
import android.os.SystemProperties;
import com.android.internal.telephony.IccCard;
import java.util.Date;
import java.io.File;
import java.text.SimpleDateFormat;
/**
* The screen within {@link LockPatternKeyguardView} that shows general
@@ -40,40 +45,28 @@ import java.util.Date;
* past it, as applicable.
*/
class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateMonitor.InfoCallback,
KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback {
KeyguardUpdateMonitor.SimStateCallback, KeyguardUpdateMonitor.ConfigurationChangeCallback,
RotarySelector.OnDialTriggerListener {
private static final boolean DBG = false;
private static final String TAG = "LockScreen";
private static final String ENABLE_MENU_KEY_FILE = "/data/local/enable_menu_key";
private Status mStatus = Status.Normal;
private final LockPatternUtils mLockPatternUtils;
private final KeyguardUpdateMonitor mUpdateMonitor;
private final KeyguardScreenCallback mCallback;
private TextView mHeaderSimOk1;
private TextView mHeaderSimOk2;
private TextView mHeaderSimBad1;
private TextView mHeaderSimBad2;
private TextView mCarrier;
private RotarySelector mRotary;
private TextView mTime;
private TextView mDate;
private ViewGroup mBatteryInfoGroup;
private ImageView mBatteryInfoIcon;
private TextView mBatteryInfoText;
private View mBatteryInfoSpacer;
private ViewGroup mNextAlarmGroup;
private TextView mAlarmText;
private View mAlarmSpacer;
private ViewGroup mScreenLockedMessageGroup;
private TextView mLockInstructions;
private TextView mStatus1;
private TextView mStatus2;
private TextView mScreenLocked;
private Button mEmergencyCallButton;
/**
* false means sim is missing or PUK'd
*/
private boolean mSimOk = true;
// are we showing battery information?
private boolean mShowingBatteryInfo = false;
@@ -83,10 +76,83 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
// last known battery level
private int mBatteryLevel = 100;
private String mNextAlarm = null;
private Drawable mAlarmIcon = null;
private String mCharging = null;
private Drawable mChargingIcon = null;
private View[] mOnlyVisibleWhenSimOk;
private boolean mSilentMode;
private AudioManager mAudioManager;
private java.text.DateFormat mDateFormat;
private java.text.DateFormat mTimeFormat;
private boolean mCreatedInPortrait;
private boolean mEnableMenuKeyInLockScreen;
private View[] mOnlyVisibleWhenSimNotOk;
/**
* The status of this lock screen.
*/
enum Status {
/**
* Normal case (sim card present, it's not locked)
*/
Normal(true),
/**
* The sim card is 'network locked'.
*/
NetworkLocked(true),
/**
* The sim card is missing.
*/
SimMissing(false),
/**
* The sim card is missing, and this is the device isn't provisioned, so we don't let
* them get past the screen.
*/
SimMissingLocked(false),
/**
* The sim card is PUK locked, meaning they've entered the wrong sim unlock code too many
* times.
*/
SimPukLocked(false),
/**
* The sim card is locked.
*/
SimLocked(true);
private final boolean mShowStatusLines;
Status(boolean mShowStatusLines) {
this.mShowStatusLines = mShowStatusLines;
}
/**
* @return Whether the status lines (battery level and / or next alarm) are shown while
* in this state. Mostly dictated by whether this is room for them.
*/
public boolean showStatusLines() {
return mShowStatusLines;
}
}
/**
* In general, we enable unlocking the insecure key guard with the menu key. However, there are
* some cases where we wish to disable it, notably when the menu button placement or technology
* is prone to false positives.
*
* @return true if the menu key should be enabled
*/
private boolean shouldEnableMenuKey() {
final Resources res = getResources();
final boolean configDisabled = res.getBoolean(R.bool.config_disableMenuKeyInLockScreen);
final boolean isMonkey = SystemProperties.getBoolean("ro.monkey", false);
final boolean fileOverride = (new File(ENABLE_MENU_KEY_FILE)).exists();
return !configDisabled || isMonkey || fileOverride;
}
/**
* @param context Used to setup the view.
@@ -103,262 +169,391 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
mUpdateMonitor = updateMonitor;
mCallback = callback;
mEnableMenuKeyInLockScreen = shouldEnableMenuKey();
mCreatedInPortrait = updateMonitor.isInPortrait();
final LayoutInflater inflater = LayoutInflater.from(context);
inflater.inflate(R.layout.keyguard_screen_lock, this, true);
mSimOk = isSimOk(updateMonitor.getSimState());
mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo();
mPluggedIn = updateMonitor.isDevicePluggedIn();
mBatteryLevel = updateMonitor.getBatteryLevel();
mHeaderSimOk1 = (TextView) findViewById(R.id.headerSimOk1);
mHeaderSimOk2 = (TextView) findViewById(R.id.headerSimOk2);
mHeaderSimBad1 = (TextView) findViewById(R.id.headerSimBad1);
mHeaderSimBad2 = (TextView) findViewById(R.id.headerSimBad2);
if (mCreatedInPortrait) {
inflater.inflate(R.layout.keyguard_screen_rotary_unlock, this, true);
} else {
inflater.inflate(R.layout.keyguard_screen_rotary_unlock_land, this, true);
}
mCarrier = (TextView) findViewById(R.id.carrier);
mTime = (TextView) findViewById(R.id.time);
mDate = (TextView) findViewById(R.id.date);
mBatteryInfoGroup = (ViewGroup) findViewById(R.id.batteryInfo);
mBatteryInfoIcon = (ImageView) findViewById(R.id.batteryInfoIcon);
mBatteryInfoText = (TextView) findViewById(R.id.batteryInfoText);
mBatteryInfoSpacer = findViewById(R.id.batteryInfoSpacer);
mNextAlarmGroup = (ViewGroup) findViewById(R.id.nextAlarmInfo);
mAlarmText = (TextView) findViewById(R.id.nextAlarmText);
mAlarmSpacer = findViewById(R.id.nextAlarmSpacer);
mScreenLockedMessageGroup = (ViewGroup) findViewById(R.id.screenLockedInfo);
mLockInstructions = (TextView) findViewById(R.id.lockInstructions);
mStatus1 = (TextView) findViewById(R.id.status1);
mStatus2 = (TextView) findViewById(R.id.status2);
mEmergencyCallButton = (Button) findViewById(R.id.emergencyCallButton);
mEmergencyCallButton.setText(R.string.lockscreen_emergency_call);
mScreenLocked = (TextView) findViewById(R.id.screenLocked);
mRotary = (RotarySelector) findViewById(R.id.rotary);
mEmergencyCallButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mCallback.takeEmergencyCallAction();
}
});
mOnlyVisibleWhenSimOk = new View[] {
mHeaderSimOk1,
mHeaderSimOk2,
mBatteryInfoGroup,
mBatteryInfoSpacer,
mNextAlarmGroup,
mAlarmSpacer,
mScreenLockedMessageGroup,
mLockInstructions
};
mOnlyVisibleWhenSimNotOk = new View[] {
mHeaderSimBad1,
mHeaderSimBad2,
mEmergencyCallButton
};
setFocusable(true);
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
refreshBatteryDisplay();
refreshAlarmDisplay();
refreshTimeAndDateDisplay();
refreshUnlockIntructions();
refreshViewsWRTSimOk();
refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(), mUpdateMonitor.getTelephonySpn());
updateMonitor.registerInfoCallback(this);
updateMonitor.registerSimStateCallback(this);
updateMonitor.registerConfigurationChangeCallback(this);
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mSilentMode = mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT;
mRotary.setOnDialTriggerListener(this);
mRotary.setLeftHandleResource(R.drawable.ic_jog_dial_unlock);
mRotary.setRightHandleResource(mSilentMode ?
R.drawable.ic_jog_dial_sound_off :
R.drawable.ic_jog_dial_sound_on);
resetStatusInfo(updateMonitor);
}
private void resetStatusInfo(KeyguardUpdateMonitor updateMonitor) {
mShowingBatteryInfo = updateMonitor.shouldShowBatteryInfo();
mPluggedIn = updateMonitor.isDevicePluggedIn();
mBatteryLevel = updateMonitor.getBatteryLevel();
mStatus = getCurrentStatus(updateMonitor.getSimState());
updateLayout(mStatus);
refreshBatteryStringAndIcon();
refreshAlarmDisplay();
mTimeFormat = DateFormat.getTimeFormat(getContext());
mDateFormat = getLockScreenDateFormat();
refreshTimeAndDateDisplay();
updateStatusLines();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_MENU) {
if (keyCode == KeyEvent.KEYCODE_MENU && mEnableMenuKeyInLockScreen) {
mCallback.goToUnlockScreen();
}
return false;
}
private void refreshViewsWRTSimOk() {
if (mSimOk) {
for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) {
final View view = mOnlyVisibleWhenSimOk[i];
if (view == null) throw new RuntimeException("index " + i + " null");
view.setVisibility(View.VISIBLE);
}
for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) {
final View view = mOnlyVisibleWhenSimNotOk[i];
view.setVisibility(View.GONE);
}
refreshSimOkHeaders(mUpdateMonitor.getTelephonyPlmn(),
mUpdateMonitor.getTelephonySpn());
refreshAlarmDisplay();
refreshBatteryDisplay();
} else {
for (int i = 0; i < mOnlyVisibleWhenSimOk.length; i++) {
final View view = mOnlyVisibleWhenSimOk[i];
view.setVisibility(View.GONE);
}
for (int i = 0; i < mOnlyVisibleWhenSimNotOk.length; i++) {
final View view = mOnlyVisibleWhenSimNotOk[i];
view.setVisibility(View.VISIBLE);
}
refreshSimBadInfo();
/** {@inheritDoc} */
public void onDialTrigger(View v, int whichHandle) {
if (whichHandle == RotarySelector.OnDialTriggerListener.LEFT_HANDLE) {
mCallback.goToUnlockScreen();
} else if (whichHandle == RotarySelector.OnDialTriggerListener.RIGHT_HANDLE) {
// toggle silent mode
mSilentMode = !mSilentMode;
mAudioManager.setRingerMode(mSilentMode ? AudioManager.RINGER_MODE_SILENT
: AudioManager.RINGER_MODE_NORMAL);
final int handleIcon = mSilentMode ?
R.drawable.ic_jog_dial_sound_off :
R.drawable.ic_jog_dial_sound_on;
final int toastIcon = mSilentMode ?
R.drawable.ic_lock_ringer_off :
R.drawable.ic_lock_ringer_on;
mRotary.setRightHandleResource(handleIcon);
String message = mSilentMode ?
getContext().getString(R.string.global_action_silent_mode_on_status) :
getContext().getString(R.string.global_action_silent_mode_off_status);
toastMessage(mScreenLocked, message, toastIcon);
mCallback.pokeWakelock();
}
}
private void refreshSimBadInfo() {
final IccCard.State simState = mUpdateMonitor.getSimState();
if (simState == IccCard.State.PUK_REQUIRED) {
mHeaderSimBad1.setText(R.string.lockscreen_sim_puk_locked_message);
mHeaderSimBad2.setText(R.string.lockscreen_sim_puk_locked_instructions);
} else if (simState == IccCard.State.ABSENT) {
mHeaderSimBad1.setText(R.string.lockscreen_missing_sim_message);
mHeaderSimBad2.setVisibility(View.GONE);
//mHeaderSimBad2.setText(R.string.lockscreen_missing_sim_instructions);
} else {
mHeaderSimBad1.setVisibility(View.GONE);
mHeaderSimBad2.setVisibility(View.GONE);
}
/** {@inheritDoc} */
public void onGrabbedStateChange(View v, int grabbedState) {
// TODO: Update onscreen hint text based on the new state.
}
private void refreshUnlockIntructions() {
if (mLockPatternUtils.isLockPatternEnabled()
|| mUpdateMonitor.getSimState() == IccCard.State.PIN_REQUIRED
|| mUpdateMonitor.getSimState() == IccCard.State.ABSENT) {
mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_enabled);
} else {
mLockInstructions.setText(R.string.lockscreen_instructions_when_pattern_disabled);
/**
* Displays a message in a text view and then removes it.
* @param textView The text view.
* @param text The text.
* @param iconResourceId The left hand icon.
*/
private void toastMessage(final TextView textView, final String text, final int iconResourceId) {
if (mPendingR1 != null) {
textView.removeCallbacks(mPendingR1);
mPendingR1 = null;
}
if (mPendingR2 != null) {
textView.removeCallbacks(mPendingR2);
mPendingR2 = null;
}
mPendingR1 = new Runnable() {
public void run() {
textView.setText(text);
textView.setCompoundDrawablesWithIntrinsicBounds(iconResourceId, 0, 0, 0);
textView.setCompoundDrawablePadding(4);
}
};
textView.postDelayed(mPendingR1, 0);
mPendingR2 = new Runnable() {
public void run() {
textView.setText("");
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}
};
textView.postDelayed(mPendingR2, 3500);
}
private Runnable mPendingR1;
private Runnable mPendingR2;
private void refreshAlarmDisplay() {
final String nextAlarmText = mLockPatternUtils.getNextAlarm();
// bug 1685880: if we are in landscape and showing plmn, the information can end up not
// fitting on screen. in this case, the alarm will get cut.
final CharSequence plmn = mUpdateMonitor.getTelephonyPlmn();
final boolean showingPlmn = plmn != null && !TextUtils.isEmpty(plmn);
final boolean wontFit = !mUpdateMonitor.isInPortrait() && showingPlmn;
if (nextAlarmText != null && mSimOk && !wontFit) {
setAlarmInfoVisible(true);
mAlarmText.setText(nextAlarmText);
} else {
setAlarmInfoVisible(false);
mNextAlarm = mLockPatternUtils.getNextAlarm();
if (mNextAlarm != null) {
mAlarmIcon = getContext().getResources().getDrawable(R.drawable.ic_lock_idle_alarm);
}
updateStatusLines();
}
private void setAlarmInfoVisible(boolean visible) {
final int visibilityFlag = visible ? View.VISIBLE : View.GONE;
mNextAlarmGroup.setVisibility(visibilityFlag);
mAlarmSpacer.setVisibility(visibilityFlag);
}
/** {@inheritDoc} */
public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn,
int batteryLevel) {
if (DBG) Log.d(TAG, "onRefreshBatteryInfo(" + showBatteryInfo + ", " + pluggedIn + ")");
mShowingBatteryInfo = showBatteryInfo;
mPluggedIn = pluggedIn;
mBatteryLevel = batteryLevel;
refreshBatteryDisplay();
refreshBatteryStringAndIcon();
updateStatusLines();
}
private void refreshBatteryDisplay() {
if (!mShowingBatteryInfo || !mSimOk) {
mBatteryInfoGroup.setVisibility(View.GONE);
mBatteryInfoSpacer.setVisibility(View.GONE);
private void refreshBatteryStringAndIcon() {
if (!mShowingBatteryInfo) {
mCharging = null;
return;
}
mBatteryInfoGroup.setVisibility(View.VISIBLE);
mBatteryInfoSpacer.setVisibility(View.VISIBLE);
if (mChargingIcon == null) {
mChargingIcon =
getContext().getResources().getDrawable(R.drawable.ic_lock_idle_charging);
}
if (mPluggedIn) {
mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_charging);
if (mBatteryLevel >= 100) {
mBatteryInfoText.setText(R.string.lockscreen_charged);
mCharging = getContext().getString(R.string.lockscreen_charged);
} else {
mBatteryInfoText.setText(
getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel));
mCharging = getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel);
}
} else {
mBatteryInfoIcon.setImageResource(R.drawable.ic_lock_idle_low_battery);
mBatteryInfoText.setText(R.string.lockscreen_low_battery);
mCharging = getContext().getString(R.string.lockscreen_low_battery);
}
}
/** {@inheritDoc} */
public void onTimeChanged() {
refreshTimeAndDateDisplay();
}
private void refreshTimeAndDateDisplay() {
Date now = new Date();
mTime.setText(DateFormat.getTimeFormat(getContext()).format(now));
mDate.setText(DateFormat.getDateFormat(getContext()).format(now));
mTime.setText(mTimeFormat.format(now));
mDate.setText(mDateFormat.format(now));
}
/**
* @return A localized format like "Fri, Sep 18, 2009"
*/
private java.text.DateFormat getLockScreenDateFormat() {
SimpleDateFormat adjusted = null;
try {
// this call gives us the localized order
final SimpleDateFormat dateFormat = (SimpleDateFormat)
java.text.DateFormat.getDateInstance(java.text.DateFormat.FULL);
adjusted = new SimpleDateFormat(dateFormat.toPattern()
.replace("MMMM", "MMM") // we want "Sep", not "September"
.replace("EEEE", "EEE")); // we want "Fri", no "Friday"
} catch (ClassCastException e) {
// in case the library implementation changes and this throws a class cast exception
// or anything else that is funky
Log.e("LockScreen", "couldn't finnagle our custom date format :(", e);
return java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM);
}
return adjusted;
}
private void updateStatusLines() {
if (!mStatus.showStatusLines()
|| (mCharging == null && mNextAlarm == null)) {
mStatus1.setVisibility(View.INVISIBLE);
mStatus2.setVisibility(View.INVISIBLE);
} else if (mCharging != null && mNextAlarm == null) {
// charging only
mStatus1.setVisibility(View.VISIBLE);
mStatus2.setVisibility(View.INVISIBLE);
mStatus1.setText(mCharging);
mStatus1.setCompoundDrawablesWithIntrinsicBounds(mChargingIcon, null, null, null);
} else if (mNextAlarm != null && mCharging == null) {
// next alarm only
mStatus1.setVisibility(View.VISIBLE);
mStatus2.setVisibility(View.INVISIBLE);
mStatus1.setText(mNextAlarm);
mStatus1.setCompoundDrawablesWithIntrinsicBounds(mAlarmIcon, null, null, null);
} else if (mCharging != null && mNextAlarm != null) {
// both charging and next alarm
mStatus1.setVisibility(View.VISIBLE);
mStatus2.setVisibility(View.VISIBLE);
mStatus1.setText(mCharging);
mStatus1.setCompoundDrawablesWithIntrinsicBounds(mChargingIcon, null, null, null);
mStatus2.setText(mNextAlarm);
mStatus2.setCompoundDrawablesWithIntrinsicBounds(mAlarmIcon, null, null, null);
}
}
/** {@inheritDoc} */
public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
refreshSimOkHeaders(plmn, spn);
refreshAlarmDisplay(); // in case alarm won't fit anymore
if (DBG) Log.d(TAG, "onRefreshCarrierInfo(" + plmn + ", " + spn + ")");
updateLayout(mStatus);
}
private void refreshSimOkHeaders(CharSequence plmn, CharSequence spn) {
final IccCard.State simState = mUpdateMonitor.getSimState();
if (simState == IccCard.State.READY) {
if (plmn != null && !TextUtils.isEmpty(plmn)) {
mHeaderSimOk1.setVisibility(View.VISIBLE);
mHeaderSimOk1.setText(plmn);
} else {
mHeaderSimOk1.setVisibility(View.GONE);
}
private void putEmergencyBelow(int viewId) {
final RelativeLayout.LayoutParams layoutParams =
(RelativeLayout.LayoutParams) mEmergencyCallButton.getLayoutParams();
layoutParams.addRule(RelativeLayout.BELOW, viewId);
mEmergencyCallButton.setLayoutParams(layoutParams);
}
if (spn != null && !TextUtils.isEmpty(spn)) {
mHeaderSimOk2.setVisibility(View.VISIBLE);
mHeaderSimOk2.setText(spn);
} else {
mHeaderSimOk2.setVisibility(View.GONE);
}
} else if (simState == IccCard.State.PIN_REQUIRED) {
mHeaderSimOk1.setVisibility(View.VISIBLE);
mHeaderSimOk1.setText(R.string.lockscreen_sim_locked_message);
mHeaderSimOk2.setVisibility(View.GONE);
} else if (simState == IccCard.State.ABSENT) {
mHeaderSimOk1.setVisibility(View.VISIBLE);
mHeaderSimOk1.setText(R.string.lockscreen_missing_sim_message_short);
mHeaderSimOk2.setVisibility(View.GONE);
} else if (simState == IccCard.State.NETWORK_LOCKED) {
mHeaderSimOk1.setVisibility(View.VISIBLE);
mHeaderSimOk1.setText(R.string.lockscreen_network_locked_message);
mHeaderSimOk2.setVisibility(View.GONE);
/**
* Determine the current status of the lock screen given the sim state and other stuff.
*/
private Status getCurrentStatus(IccCard.State simState) {
boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned()
&& simState == IccCard.State.ABSENT);
if (missingAndNotProvisioned) {
return Status.SimMissingLocked;
}
switch (simState) {
case ABSENT:
return Status.SimMissing;
case NETWORK_LOCKED:
return Status.SimMissingLocked;
case NOT_READY:
return Status.SimMissing;
case PIN_REQUIRED:
return Status.SimLocked;
case PUK_REQUIRED:
return Status.SimPukLocked;
case READY:
return Status.Normal;
case UNKNOWN:
return Status.SimMissing;
}
return Status.SimMissing;
}
/**
* Update the layout to match the current status.
*/
private void updateLayout(Status status) {
switch (status) {
case Normal:
// text
mCarrier.setText(
getCarrierString(
mUpdateMonitor.getTelephonyPlmn(),
mUpdateMonitor.getTelephonySpn()));
// mScreenLocked.setText(R.string.lockscreen_screen_locked);
// layout
mScreenLocked.setVisibility(View.VISIBLE);
mRotary.setVisibility(View.VISIBLE);
mEmergencyCallButton.setVisibility(View.GONE);
break;
case NetworkLocked:
// text
mCarrier.setText(R.string.lockscreen_network_locked_message);
mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled);
// layout
mScreenLocked.setVisibility(View.VISIBLE);
mRotary.setVisibility(View.VISIBLE);
mEmergencyCallButton.setVisibility(View.GONE);
break;
case SimMissing:
// text
mCarrier.setText(R.string.lockscreen_missing_sim_message_short);
mScreenLocked.setText(R.string.lockscreen_instructions_when_pattern_disabled);
// layout
mScreenLocked.setVisibility(View.INVISIBLE);
mRotary.setVisibility(View.VISIBLE);
mEmergencyCallButton.setVisibility(View.VISIBLE);
putEmergencyBelow(R.id.divider);
break;
case SimMissingLocked:
// text
mCarrier.setText(R.string.lockscreen_missing_sim_message_short);
mScreenLocked.setText(R.string.lockscreen_missing_sim_instructions);
// layout
mScreenLocked.setVisibility(View.VISIBLE);
mRotary.setVisibility(View.GONE);
mEmergencyCallButton.setVisibility(View.VISIBLE);
putEmergencyBelow(R.id.screenLocked);
break;
case SimLocked:
// text
mCarrier.setText(R.string.lockscreen_sim_locked_message);
// layout
mScreenLocked.setVisibility(View.INVISIBLE);
mRotary.setVisibility(View.VISIBLE);
mEmergencyCallButton.setVisibility(View.GONE);
break;
case SimPukLocked:
// text
mCarrier.setText(R.string.lockscreen_sim_puk_locked_message);
mScreenLocked.setText(R.string.lockscreen_sim_puk_locked_instructions);
// layout
mScreenLocked.setVisibility(View.VISIBLE);
mRotary.setVisibility(View.GONE);
mEmergencyCallButton.setVisibility(View.VISIBLE);
putEmergencyBelow(R.id.screenLocked);
break;
}
}
static CharSequence getCarrierString(CharSequence telephonyPlmn, CharSequence telephonySpn) {
if (telephonyPlmn != null && telephonySpn == null) {
return telephonyPlmn;
} else if (telephonyPlmn != null && telephonySpn != null) {
return telephonyPlmn + "\n" + telephonySpn;
} else if (telephonyPlmn == null && telephonySpn != null) {
return telephonySpn;
} else {
return "";
}
}
public void onSimStateChanged(IccCard.State simState) {
mSimOk = isSimOk(simState);
refreshViewsWRTSimOk();
refreshUnlockIntructions();
if (DBG) Log.d(TAG, "onSimStateChanged(" + simState + ")");
mStatus = getCurrentStatus(simState);
updateLayout(mStatus);
updateStatusLines();
}
/**
* @return Whether the sim state is ok, meaning we don't need to show
* a special screen with the emergency call button and keep them from
* doing anything else.
*/
private boolean isSimOk(IccCard.State simState) {
boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned()
&& simState == IccCard.State.ABSENT);
return !(missingAndNotProvisioned || simState == IccCard.State.PUK_REQUIRED);
}
public void onOrientationChange(boolean inPortrait) {
if (inPortrait != mCreatedInPortrait) {
mCallback.recreateMe();
}
}
public void onKeyboardChange(boolean isKeyboardOpen) {
if (isKeyboardOpen) {
if (mUpdateMonitor.isKeyguardBypassEnabled() && isKeyboardOpen) {
mCallback.goToUnlockScreen();
}
}
@@ -376,7 +571,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
/** {@inheritDoc} */
public void onResume() {
resetStatusInfo(mUpdateMonitor);
}
/** {@inheritDoc} */
@@ -384,4 +579,3 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
mUpdateMonitor.removeCallback(this);
}
}

View File

@@ -20,6 +20,7 @@ import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import com.android.internal.view.menu.ContextMenuBuilder;
import com.android.internal.view.menu.MenuBuilder;
@@ -34,7 +35,6 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -124,6 +124,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
* this is 0, there is no key held down.
*/
private int mPanelChordingKey;
private boolean mPanelMayLongPress;
private ImageView mLeftIconView;
@@ -155,120 +156,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private TelephonyManager mTelephonyManager = null;
private boolean mSearchKeyDownReceived;
private boolean mKeycodeCallTimeoutActive = false;
private boolean mKeycodeCameraTimeoutActive = false;
static final int MSG_MENU_LONG_PRESS = 1;
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;
static final int MSG_SEARCH_LONG_PRESS = 7;
static final int MSG_SEARCH_LONG_PRESS_COMPLETE = 8;
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.
Message newMessage = Message.obtain(msg);
newMessage.what = MSG_CAMERA_LONG_PRESS_COMPLETE;
mKeycodeMenuTimeoutHandler.sendMessage(newMessage);
break;
}
case MSG_SEARCH_LONG_PRESS: {
if (!mSearchKeyDownReceived) return;
// See above.
Message newMessage = Message.obtain(msg);
newMessage.what = MSG_SEARCH_LONG_PRESS_COMPLETE;
mKeycodeMenuTimeoutHandler.sendMessage(newMessage);
break;
}
case MSG_MENU_LONG_PRESS_COMPLETE: {
if (mPanelChordingKey == 0) return;
mPanelChordingKey = 0;
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
} break;
case MSG_CALL_LONG_PRESS_COMPLETE: {
if (!mKeycodeCallTimeoutActive) return;
mKeycodeCallTimeoutActive = false;
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
// launch the VoiceDialer
Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
sendCloseSystemWindows();
getContext().startActivity(intent);
} catch (ActivityNotFoundException e) {
startCallActivity();
}
} break;
case MSG_CAMERA_LONG_PRESS_COMPLETE: {
if (!mKeycodeCameraTimeoutActive) return;
mKeycodeCameraTimeoutActive = false;
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
sendCloseSystemWindows();
// Broadcast an intent that the Camera button was longpressed
Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, (KeyEvent) msg.obj);
getContext().sendOrderedBroadcast(intent, null);
} break;
case MSG_SEARCH_LONG_PRESS_COMPLETE: {
if (getKeyguardManager().inKeyguardRestrictedInputMode() ||
!mSearchKeyDownReceived) {
mSearchKeyDownReceived = false;
return;
}
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
// launch the search activity
Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
sendCloseSystemWindows();
getContext().startActivity(intent);
// Only clear this if we successfully start the
// activity; otherwise we will allow the normal short
// press action to be performed.
mSearchKeyDownReceived = false;
} catch (ActivityNotFoundException e) {
}
} break;
}
}
};
public PhoneWindow(Context context) {
super(context);
mLayoutInflater = LayoutInflater.from(context);
@@ -295,11 +182,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
/* Custom title feature is enabled and the user is trying to enable another feature */
throw new AndroidRuntimeException("You cannot combine custom titles with other title features");
}
/* FEATURE_OPENGL disabled for 1.0
if (featureId == FEATURE_OPENGL) {
getAttributes().memoryType = WindowManager.LayoutParams.MEMORY_TYPE_GPU;
}
*/
return super.requestFeature(featureId);
}
@@ -567,7 +452,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WRAP_CONTENT, WRAP_CONTENT,
st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
st.x, st.y, WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG,
WindowManager.LayoutParams.FLAG_DITHER
| WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
st.decorView.mDefaultOpacity);
@@ -649,19 +534,35 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
* @return Whether the key was handled.
*/
public final boolean onKeyDownPanel(int featureId, KeyEvent event) {
// The panel key was pushed, so set the chording key
mPanelChordingKey = event.getKeyCode();
PanelFeatureState st = getPanelState(featureId, true);
if (!st.isOpen) {
if (getContext().getResources().getConfiguration().keyboard
== Configuration.KEYBOARD_NOKEYS) {
mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
mKeycodeMenuTimeoutHandler.sendMessageDelayed(
mKeycodeMenuTimeoutHandler.obtainMessage(MSG_MENU_LONG_PRESS),
ViewConfiguration.getLongPressTimeout());
final int keyCode = event.getKeyCode();
if (event.getRepeatCount() == 0) {
// The panel key was pushed, so set the chording key
mPanelChordingKey = keyCode;
mPanelMayLongPress = false;
PanelFeatureState st = getPanelState(featureId, true);
if (!st.isOpen) {
if (getContext().getResources().getConfiguration().keyboard
== Configuration.KEYBOARD_NOKEYS) {
mPanelMayLongPress = true;
}
return preparePanel(st, event);
}
return preparePanel(st, event);
} else if (mPanelMayLongPress && mPanelChordingKey == keyCode
&& (event.getFlags()&KeyEvent.FLAG_LONG_PRESS) != 0) {
// We have had a long press while in a state where this
// should be executed... do it!
mPanelChordingKey = 0;
mPanelMayLongPress = false;
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
}
return false;
@@ -676,8 +577,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// The panel key was released, so clear the chording key
if (mPanelChordingKey != 0) {
mPanelChordingKey = 0;
mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
mPanelMayLongPress = false;
if (event.isCanceled()) {
return;
}
boolean playSoundEffect = false;
PanelFeatureState st = getPanelState(featureId, true);
if (st.isOpen || st.isHandled) {
@@ -1214,6 +1119,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
* @see android.view.KeyEvent
*/
protected boolean onKeyDown(int featureId, int keyCode, KeyEvent event) {
final KeyEvent.DispatcherState dispatcher =
mDecor != null ? mDecor.getKeyDispatcherState() : null;
//Log.i(TAG, "Key down: repeat=" + event.getRepeatCount()
// + " flags=0x" + Integer.toHexString(event.getFlags()));
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN: {
@@ -1260,21 +1170,25 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
case KeyEvent.KEYCODE_CAMERA: {
if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
if (getKeyguardManager().inKeyguardRestrictedInputMode()
|| dispatcher == null) {
break;
}
if (event.getRepeatCount() > 0) break;
mKeycodeCameraTimeoutActive = true;
mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
Message message = mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CAMERA_LONG_PRESS);
message.obj = event;
mKeycodeMenuTimeoutHandler.sendMessageDelayed(message,
ViewConfiguration.getLongPressTimeout());
if (event.getRepeatCount() == 0) {
dispatcher.startTracking(event, this);
} else if (event.isLongPress() && dispatcher.isTracking(event)) {
dispatcher.performedLongPress(event);
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
sendCloseSystemWindows();
// Broadcast an intent that the Camera button was longpressed
Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
getContext().sendOrderedBroadcast(intent, null);
}
return true;
}
case KeyEvent.KEYCODE_MENU: {
if (event.getRepeatCount() > 0) break;
onKeyDownPanel((featureId < 0) ? FEATURE_OPTIONS_PANEL : featureId, event);
return true;
}
@@ -1282,48 +1196,61 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_BACK: {
if (event.getRepeatCount() > 0) break;
if (featureId < 0) break;
if (featureId == FEATURE_OPTIONS_PANEL) {
PanelFeatureState st = getPanelState(featureId, false);
if (st != null && st.isInExpandedMode) {
// If the user is in an expanded menu and hits back, it
// should go back to the icon menu
reopenMenu(true);
return true;
}
}
closePanel(featureId);
// Currently don't do anything with long press.
dispatcher.startTracking(event, this);
return true;
}
case KeyEvent.KEYCODE_CALL: {
if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
if (getKeyguardManager().inKeyguardRestrictedInputMode()
|| dispatcher == null) {
break;
}
if (event.getRepeatCount() > 0) break;
mKeycodeCallTimeoutActive = true;
mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS);
mKeycodeMenuTimeoutHandler.sendMessageDelayed(
mKeycodeMenuTimeoutHandler.obtainMessage(MSG_CALL_LONG_PRESS),
ViewConfiguration.getLongPressTimeout());
if (event.getRepeatCount() == 0) {
dispatcher.startTracking(event, this);
} else if (event.isLongPress() && dispatcher.isTracking(event)) {
dispatcher.performedLongPress(event);
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
// launch the VoiceDialer
Intent intent = new Intent(Intent.ACTION_VOICE_COMMAND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
sendCloseSystemWindows();
getContext().startActivity(intent);
} catch (ActivityNotFoundException e) {
startCallActivity();
}
}
return true;
}
case KeyEvent.KEYCODE_SEARCH: {
if (getKeyguardManager().inKeyguardRestrictedInputMode()
|| dispatcher == null) {
break;
}
if (event.getRepeatCount() == 0) {
mSearchKeyDownReceived = true;
dispatcher.startTracking(event, this);
} else if (event.isLongPress() && dispatcher.isTracking(event)) {
Configuration config = getContext().getResources().getConfiguration();
if (config.keyboard == Configuration.KEYBOARD_NOKEYS
|| config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
// If this device does not have a hardware keyboard,
// or that keyboard is hidden, then we can't use the
// search key for chording to perform shortcuts;
// instead, we will let the user long press,
mKeycodeMenuTimeoutHandler.removeMessages(MSG_SEARCH_LONG_PRESS);
mKeycodeMenuTimeoutHandler.sendMessageDelayed(
mKeycodeMenuTimeoutHandler.obtainMessage(MSG_SEARCH_LONG_PRESS),
ViewConfiguration.getLongPressTimeout());
|| config.hardKeyboardHidden
== Configuration.HARDKEYBOARDHIDDEN_YES) {
// launch the search activity
Intent intent = new Intent(Intent.ACTION_SEARCH_LONG_PRESS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
sendCloseSystemWindows();
getContext().startActivity(intent);
mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
// Only clear this if we successfully start the
// activity; otherwise we will allow the normal short
// press action to be performed.
dispatcher.performedLongPress(event);
} catch (ActivityNotFoundException e) {
// Ignore
}
}
return true;
}
break;
}
@@ -1349,6 +1276,14 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
* @see android.view.KeyEvent
*/
protected boolean onKeyUp(int featureId, int keyCode, KeyEvent event) {
final KeyEvent.DispatcherState dispatcher =
mDecor != null ? mDecor.getKeyDispatcherState() : null;
if (dispatcher != null) {
dispatcher.handleUpEvent(event);
}
//Log.i(TAG, "Key up: repeat=" + event.getRepeatCount()
// + " flags=0x" + Integer.toHexString(event.getFlags()));
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN: {
@@ -1374,6 +1309,24 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
return true;
}
case KeyEvent.KEYCODE_BACK: {
if (featureId < 0) break;
if (event.isTracking() && !event.isCanceled()) {
if (featureId == FEATURE_OPTIONS_PANEL) {
PanelFeatureState st = getPanelState(featureId, false);
if (st != null && st.isInExpandedMode) {
// If the user is in an expanded menu and hits back, it
// should go back to the icon menu
reopenMenu(true);
return true;
}
}
closePanel(featureId);
return true;
}
break;
}
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
case KeyEvent.KEYCODE_MEDIA_STOP:
@@ -1391,11 +1344,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
break;
}
if (event.getRepeatCount() > 0) break; // Can a key up event repeat?
mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
if (!mKeycodeCameraTimeoutActive) break;
mKeycodeCameraTimeoutActive = false;
// Add short press behavior here if desired
if (event.isTracking() && !event.isCanceled()) {
// Add short press behavior here if desired
}
return true;
}
@@ -1403,11 +1354,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
break;
}
if (event.getRepeatCount() > 0) break;
mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS);
if (!mKeycodeCallTimeoutActive) break;
mKeycodeCallTimeoutActive = false;
startCallActivity();
if (event.isTracking() && !event.isCanceled()) {
startCallActivity();
}
return true;
}
@@ -1416,13 +1365,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
* Do this in onKeyUp since the Search key is also used for
* chording quick launch shortcuts.
*/
if (getKeyguardManager().inKeyguardRestrictedInputMode() ||
!mSearchKeyDownReceived) {
mSearchKeyDownReceived = false;
if (getKeyguardManager().inKeyguardRestrictedInputMode()) {
break;
}
mSearchKeyDownReceived = false;
launchDefaultSearch();
if (event.isTracking() && !event.isCanceled()) {
launchDefaultSearch();
}
return true;
}
}
@@ -1584,9 +1532,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
PanelFeatureState st;
for (int i = panels.length - 1; i >= 0; i--) {
st = panels[i];
if ((st != null) && st.isOpen) {
// Clear st.isOpen (openPanel will not open if it's already open)
st.isOpen = false;
// We restore the panel if it was last open; we skip it if it
// now is open, to avoid a race condition if the user immediately
// opens it when we are resuming.
if ((st != null) && !st.isOpen && st.wasLastOpen) {
st.isInExpandedMode = st.wasLastExpanded;
openPanel(st, null);
}
}
@@ -1606,8 +1556,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private final Rect mFrameOffsets = new Rect();
private final Paint mBlackPaint = new Paint();
private boolean mChanging;
private Drawable mMenuBackground;
@@ -1617,7 +1565,6 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
public DecorView(Context context, int featureId) {
super(context);
mFeatureId = featureId;
mBlackPaint.setColor(0xFF000000);
}
@Override
@@ -2009,16 +1956,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
// no KEYCODE_CALL events active across focus changes
mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS);
mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
mKeycodeCallTimeoutActive = false;
mKeycodeCameraTimeoutActive = false;
mPanelMayLongPress = false;
// If the user is chording a menu shortcut, release the chord since
// this window lost focus
if (!hasWindowFocus && mPanelChordingKey > 0) {
if (!hasWindowFocus && mPanelChordingKey != 0) {
closePanel(FEATURE_OPTIONS_PANEL);
}
@@ -2031,6 +1973,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
final Callback cb = getCallback();
if (cb != null && mFeatureId < 0) {
cb.onAttachedToWindow();
}
if (mFeatureId == -1) {
/*
@@ -2043,6 +1990,23 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
openPanelsAfterRestore();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
final Callback cb = getCallback();
if (cb != null && mFeatureId < 0) {
cb.onDetachedFromWindow();
}
}
@Override
public void onCloseSystemDialogs(String reason) {
if (mFeatureId >= 0) {
closeAllPanels();
}
}
}
protected DecorView generateDecor() {
@@ -2097,6 +2061,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
setFlags(FLAG_FULLSCREEN, FLAG_FULLSCREEN&(~getForcedWindowFlags()));
}
if (a.getBoolean(com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
setFlags(FLAG_SHOW_WALLPAPER, FLAG_SHOW_WALLPAPER&(~getForcedWindowFlags()));
}
WindowManager.LayoutParams params = getAttributes();
if (!hasSoftInputMode()) {
@@ -2606,6 +2574,10 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
boolean refreshDecorView;
boolean wasLastOpen;
boolean wasLastExpanded;
/**
* Contains the state of the menu when told to freeze.
*/
@@ -2654,8 +2626,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
void onRestoreInstanceState(Parcelable state) {
SavedState savedState = (SavedState) state;
featureId = savedState.featureId;
isOpen = savedState.isOpen;
isInExpandedMode = savedState.isInExpandedMode;
wasLastOpen = savedState.isOpen;
wasLastExpanded = savedState.isInExpandedMode;
frozenMenuState = savedState.menuState;
/*

File diff suppressed because it is too large Load Diff

View File

@@ -70,8 +70,11 @@ public class PowerDialog extends Dialog implements OnClickListener,
setContentView(com.android.internal.R.layout.power_dialog);
getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
if (!getContext().getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
}
getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);

View File

@@ -20,7 +20,6 @@ import android.app.ActivityManager;
import android.app.Dialog;
import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -30,13 +29,10 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
@@ -59,7 +55,7 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener
private int mIconSize;
public RecentApplicationsDialog(Context context) {
super(context);
super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications);
final Resources resources = context.getResources();
mIconSize = (int) resources.getDimension(android.R.dimen.app_icon_size);
@@ -84,8 +80,8 @@ public class RecentApplicationsDialog extends Dialog implements OnClickListener
Window theWindow = getWindow();
theWindow.requestFeature(Window.FEATURE_NO_TITLE);
theWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
theWindow.setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
theWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
WindowManager.LayoutParams.FLAG_DIM_BEHIND);
theWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
theWindow.setTitle("Recents");

View File

@@ -182,9 +182,12 @@ public class SimUnlockScreen extends LinearLayout implements KeyguardScreen, Vie
mSimUnlockProgressDialog.setCancelable(false);
mSimUnlockProgressDialog.getWindow().setType(
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
mSimUnlockProgressDialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
if (!mContext.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) {
mSimUnlockProgressDialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
}
}
return mSimUnlockProgressDialog;
}

View File

@@ -17,30 +17,33 @@
package com.android.internal.policy.impl;
import android.content.Context;
import android.content.ServiceConnection;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.MotionEvent;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.text.format.DateFormat;
import android.text.TextUtils;
import com.android.internal.R;
import com.android.internal.telephony.IccCard;
import com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternView;
import com.android.internal.widget.LockPatternView.Cell;
import java.util.List;
import java.util.Date;
/**
* This is the screen that shows the 9 circle unlock widget and instructs
* the user how to unlock their device, or make an emergency call.
*/
class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback {
implements KeyguardScreen, KeyguardUpdateMonitor.ConfigurationChangeCallback,
KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback {
private static final String TAG = "UnlockScreen";
@@ -50,6 +53,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
// how long we stay awake once the user is ready to enter a pattern
private static final int UNLOCK_PATTERN_WAKE_INTERVAL_MS = 7000;
// how many cells the user has to cross before we poke the wakelock
private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
private int mFailedPatternAttemptsSinceLastTimeout = 0;
private int mTotalFailedPatternAttempts = 0;
private CountDownTimer mCountdownTimer = null;
@@ -58,10 +64,35 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
private final KeyguardUpdateMonitor mUpdateMonitor;
private final KeyguardScreenCallback mCallback;
/**
* whether there is a fallback option available when the pattern is forgotten.
*/
private boolean mEnableFallback;
private boolean mCreatedInPortrait;
private ImageView mUnlockIcon;
private TextView mUnlockHeader;
private TextView mCarrier;
private TextView mCenterDot;
private TextView mDate;
private TextView mTime;
// are we showing battery information?
private boolean mShowingBatteryInfo = false;
// last known plugged in state
private boolean mPluggedIn = false;
// last known battery level
private int mBatteryLevel = 100;
private String mNextAlarm = null;
private String mInstructions = null;
private TextView mStatus1;
private TextView mStatusSep;
private TextView mStatus2;
private LockPatternView mLockPatternView;
private ViewGroup mFooterNormal;
@@ -86,9 +117,6 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
private Button mForgotPatternButton;
private ServiceConnection mServiceConnection;
enum FooterMode {
Normal,
ForgotLockPattern,
@@ -104,6 +132,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
case ForgotLockPattern:
mFooterNormal.setVisibility(View.GONE);
mFooterForgotPattern.setVisibility(View.VISIBLE);
mForgotPatternButton.setVisibility(View.VISIBLE);
break;
case VerifyUnlocked:
mFooterNormal.setVisibility(View.GONE);
@@ -117,12 +146,15 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
* @param updateMonitor Used to lookup state affecting keyguard.
* @param callback Used to notify the manager when we're done, etc.
* @param totalFailedAttempts The current number of failed attempts.
* @param enableFallback True if a backup unlock option is available when the user has forgotten
* their pattern (e.g they have a google account so we can show them the account based
* backup option).
*/
UnlockScreen(Context context,
LockPatternUtils lockPatternUtils,
KeyguardUpdateMonitor updateMonitor,
KeyguardScreenCallback callback,
int totalFailedAttempts) {
LockPatternUtils lockPatternUtils,
KeyguardUpdateMonitor updateMonitor,
KeyguardScreenCallback callback,
int totalFailedAttempts) {
super(context);
mLockPatternUtils = lockPatternUtils;
mUpdateMonitor = updateMonitor;
@@ -136,12 +168,22 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
LayoutInflater.from(context).inflate(R.layout.keyguard_screen_unlock_landscape, this, true);
}
mUnlockIcon = (ImageView) findViewById(R.id.unlockLockIcon);
mCarrier = (TextView) findViewById(R.id.carrier);
mCenterDot = (TextView) findViewById(R.id.centerDot);
mDate = (TextView) findViewById(R.id.date);
mTime = (TextView) findViewById(R.id.time);
mCenterDot.setText("|");
refreshTimeAndDateDisplay();
mStatus1 = (TextView) findViewById(R.id.status1);
mStatusSep = (TextView) findViewById(R.id.statusSep);
mStatus2 = (TextView) findViewById(R.id.status2);
resetStatusInfo();
mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
mUnlockHeader = (TextView) findViewById(R.id.headerText);
mUnlockHeader.setText(R.string.lockscreen_pattern_instructions);
mFooterNormal = (ViewGroup) findViewById(R.id.footerNormal);
mFooterForgotPattern = (ViewGroup) findViewById(R.id.footerForgotPattern);
@@ -164,8 +206,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
mForgotPatternButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mLockPatternUtils.setPermanentlyLocked(true);
mCallback.goToUnlockScreen();
mCallback.forgotPattern(true);
}
});
@@ -187,18 +228,105 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
updateFooter(FooterMode.Normal);
mCreatedInPortrait = updateMonitor.isInPortrait();
updateMonitor.registerInfoCallback(this);
updateMonitor.registerSimStateCallback(this);
updateMonitor.registerConfigurationChangeCallback(this);
setFocusableInTouchMode(true);
// until we get an update...
mCarrier.setText(
LockScreen.getCarrierString(
mUpdateMonitor.getTelephonyPlmn(),
mUpdateMonitor.getTelephonySpn()));
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
mCallback.goToLockScreen();
return true;
}
return false;
public void setEnableFallback(boolean state) {
mEnableFallback = state;
}
private void resetStatusInfo() {
mInstructions = null;
mShowingBatteryInfo = mUpdateMonitor.shouldShowBatteryInfo();
mPluggedIn = mUpdateMonitor.isDevicePluggedIn();
mBatteryLevel = mUpdateMonitor.getBatteryLevel();
mNextAlarm = mLockPatternUtils.getNextAlarm();
updateStatusLines();
}
private void updateStatusLines() {
if (mInstructions != null) {
// instructions only
mStatus1.setText(mInstructions);
if (TextUtils.isEmpty(mInstructions)) {
mStatus1.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
} else {
mStatus1.setCompoundDrawablesWithIntrinsicBounds(
R.drawable.ic_lock_idle_lock, 0, 0, 0);
}
mStatus1.setVisibility(View.VISIBLE);
mStatusSep.setVisibility(View.GONE);
mStatus2.setVisibility(View.GONE);
} else if (mShowingBatteryInfo && mNextAlarm == null) {
// battery only
if (mPluggedIn) {
if (mBatteryLevel >= 100) {
mStatus1.setText(getContext().getString(R.string.lockscreen_charged));
} else {
mStatus1.setText(getContext().getString(R.string.lockscreen_plugged_in, mBatteryLevel));
}
} else {
mStatus1.setText(getContext().getString(R.string.lockscreen_low_battery));
}
mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_charging, 0, 0, 0);
mStatus1.setVisibility(View.VISIBLE);
mStatusSep.setVisibility(View.GONE);
mStatus2.setVisibility(View.GONE);
} else if (mNextAlarm != null && !mShowingBatteryInfo) {
// alarm only
mStatus1.setText(mNextAlarm);
mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_alarm, 0, 0, 0);
mStatus1.setVisibility(View.VISIBLE);
mStatusSep.setVisibility(View.GONE);
mStatus2.setVisibility(View.GONE);
} else if (mNextAlarm != null && mShowingBatteryInfo) {
// both battery and next alarm
mStatus1.setText(mNextAlarm);
mStatusSep.setText("|");
mStatus2.setText(getContext().getString(
R.string.lockscreen_battery_short,
Math.min(100, mBatteryLevel)));
mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_alarm, 0, 0, 0);
if (mPluggedIn) {
mStatus2.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_charging, 0, 0, 0);
} else {
mStatus2.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}
mStatus1.setVisibility(View.VISIBLE);
mStatusSep.setVisibility(View.VISIBLE);
mStatus2.setVisibility(View.VISIBLE);
} else {
// nothing specific to show; show general instructions
mStatus1.setText(R.string.lockscreen_pattern_instructions);
mStatus1.setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_lock_idle_lock, 0, 0, 0);
mStatus1.setVisibility(View.VISIBLE);
mStatusSep.setVisibility(View.GONE);
mStatus2.setVisibility(View.GONE);
}
}
private void refreshTimeAndDateDisplay() {
Date now = new Date();
mTime.setText(DateFormat.getTimeFormat(getContext()).format(now));
mDate.setText(DateFormat.getMediumDateFormat(getContext()).format(now));
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
@@ -210,11 +338,40 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
((SystemClock.elapsedRealtime() - mLastPokeTime)
> (UNLOCK_PATTERN_WAKE_INTERVAL_MS - 100))) {
mLastPokeTime = SystemClock.elapsedRealtime();
mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
}
return result;
}
// ---------- InfoCallback
/** {@inheritDoc} */
public void onRefreshBatteryInfo(boolean showBatteryInfo, boolean pluggedIn, int batteryLevel) {
mShowingBatteryInfo = showBatteryInfo;
mPluggedIn = pluggedIn;
mBatteryLevel = batteryLevel;
updateStatusLines();
}
/** {@inheritDoc} */
public void onTimeChanged() {
refreshTimeAndDateDisplay();
}
/** {@inheritDoc} */
public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
mCarrier.setText(LockScreen.getCarrierString(plmn, spn));
}
// ---------- SimStateCallback
/** {@inheritDoc} */
public void onSimStateChanged(IccCard.State simState) {
}
/** {@inheritDoc} */
public void onOrientationChange(boolean inPortrait) {
if (inPortrait != mCreatedInPortrait) {
@@ -241,8 +398,7 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
/** {@inheritDoc} */
public void onResume() {
// reset header
mUnlockHeader.setText(R.string.lockscreen_pattern_instructions);
mUnlockIcon.setVisibility(View.VISIBLE);
resetStatusInfo();
// reset lock pattern
mLockPatternView.enableInput();
@@ -262,10 +418,11 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
// the footer depends on how many total attempts the user has failed
if (mCallback.isVerifyUnlockOnly()) {
updateFooter(FooterMode.VerifyUnlocked);
} else if (mTotalFailedPatternAttempts < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT) {
updateFooter(FooterMode.Normal);
} else {
} else if (mEnableFallback &&
(mTotalFailedPatternAttempts >= LockPatternUtils.FAILED_ATTEMPTS_BEFORE_TIMEOUT)) {
updateFooter(FooterMode.ForgotLockPattern);
} else {
updateFooter(FooterMode.Normal);
}
}
@@ -274,6 +431,15 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
mUpdateMonitor.removeCallback(this);
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
if (hasWindowFocus) {
// when timeout dialog closes we want to update our state
onResume();
}
}
private class UnlockPatternListener
implements LockPatternView.OnPatternListener {
@@ -284,15 +450,25 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
public void onPatternCleared() {
}
public void onPatternCellAdded(List<Cell> pattern) {
// To guard against accidental poking of the wakelock, look for
// the user actually trying to draw a pattern of some minimal length.
if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
}
}
public void onPatternDetected(List<LockPatternView.Cell> pattern) {
if (mLockPatternUtils.checkPattern(pattern)) {
mLockPatternView
.setDisplayMode(LockPatternView.DisplayMode.Correct);
mUnlockIcon.setVisibility(View.GONE);
mUnlockHeader.setText("");
mInstructions = "";
updateStatusLines();
mCallback.keyguardDone(true);
} else {
mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
if (pattern.size() > MIN_PATTERN_BEFORE_POKE_WAKELOCK) {
mCallback.pokeWakelock(UNLOCK_PATTERN_WAKE_INTERVAL_MS);
}
mLockPatternView.setDisplayMode(LockPatternView.DisplayMode.Wrong);
if (pattern.size() >= LockPatternUtils.MIN_PATTERN_REGISTER_FAIL) {
mTotalFailedPatternAttempts++;
@@ -304,8 +480,9 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
handleAttemptLockout(deadline);
return;
}
mUnlockIcon.setVisibility(View.VISIBLE);
mUnlockHeader.setText(R.string.lockscreen_pattern_wrong);
// TODO mUnlockIcon.setVisibility(View.VISIBLE);
mInstructions = getContext().getString(R.string.lockscreen_pattern_wrong);
updateStatusLines();
mLockPatternView.postDelayed(
mCancelPatternRunnable,
PATTERN_CLEAR_TIMEOUT_MS);
@@ -322,20 +499,25 @@ class UnlockScreen extends LinearLayoutWithDefaultTouchRecepient
@Override
public void onTick(long millisUntilFinished) {
int secondsRemaining = (int) (millisUntilFinished / 1000);
mUnlockHeader.setText(getContext().getString(
mInstructions = getContext().getString(
R.string.lockscreen_too_many_failed_attempts_countdown,
secondsRemaining));
secondsRemaining);
updateStatusLines();
}
@Override
public void onFinish() {
mLockPatternView.setEnabled(true);
mUnlockHeader.setText(R.string.lockscreen_pattern_instructions);
mUnlockIcon.setVisibility(View.VISIBLE);
mInstructions = getContext().getString(R.string.lockscreen_pattern_instructions);
updateStatusLines();
// TODO mUnlockIcon.setVisibility(View.VISIBLE);
mFailedPatternAttemptsSinceLastTimeout = 0;
updateFooter(FooterMode.ForgotLockPattern);
if (mEnableFallback) {
updateFooter(FooterMode.ForgotLockPattern);
} else {
updateFooter(FooterMode.Normal);
}
}
}.start();
}
}