summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Baptiste Queru <jbq@google.com>2009-11-12 18:46:07 -0800
committerJean-Baptiste Queru <jbq@google.com>2009-11-12 18:46:07 -0800
commit13ccdc2d7acd051840ba4b9e6a92ce10ac4fcb38 (patch)
tree56337fd5da3883c82656181b17f7c96ee7ffda87
parent1dc1ccaf5c8cc136b71537f310a3f13150aaef41 (diff)
downloadbase-13ccdc2d7acd051840ba4b9e6a92ce10ac4fcb38.tar.gz
eclair snapshot
-rw-r--r--mid/com/android/internal/policy/impl/MidWindow.java17
-rw-r--r--mid/com/android/internal/policy/impl/MidWindowManager.java44
-rw-r--r--phone/com/android/internal/policy/impl/AccountUnlockScreen.java195
-rw-r--r--phone/com/android/internal/policy/impl/GlobalActions.java63
-rw-r--r--phone/com/android/internal/policy/impl/KeyguardScreenCallback.java11
-rw-r--r--phone/com/android/internal/policy/impl/KeyguardUpdateMonitor.java17
-rw-r--r--phone/com/android/internal/policy/impl/KeyguardViewManager.java27
-rw-r--r--phone/com/android/internal/policy/impl/KeyguardViewMediator.java151
-rw-r--r--phone/com/android/internal/policy/impl/LockPatternKeyguardView.java183
-rw-r--r--phone/com/android/internal/policy/impl/LockScreen.java604
-rw-r--r--phone/com/android/internal/policy/impl/PhoneWindow.java368
-rwxr-xr-x[-rw-r--r--]phone/com/android/internal/policy/impl/PhoneWindowManager.java638
-rw-r--r--phone/com/android/internal/policy/impl/PowerDialog.java7
-rw-r--r--phone/com/android/internal/policy/impl/RecentApplicationsDialog.java10
-rw-r--r--phone/com/android/internal/policy/impl/SimUnlockScreen.java9
-rw-r--r--phone/com/android/internal/policy/impl/UnlockScreen.java266
16 files changed, 1764 insertions, 846 deletions
diff --git a/mid/com/android/internal/policy/impl/MidWindow.java b/mid/com/android/internal/policy/impl/MidWindow.java
index 68727fb..b2e9ebd 100644
--- a/mid/com/android/internal/policy/impl/MidWindow.java
+++ b/mid/com/android/internal/policy/impl/MidWindow.java
@@ -67,6 +67,8 @@ import android.view.WindowManager;
import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+
+import android.view.Window.Callback;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
@@ -1886,6 +1888,11 @@ public class MidWindow 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) {
/*
@@ -1898,6 +1905,16 @@ public class MidWindow extends Window implements MenuBuilder.Callback {
openPanelsAfterRestore();
}
}
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ final Callback cb = getCallback();
+ if (cb != null && mFeatureId < 0) {
+ cb.onDetachedFromWindow();
+ }
+ }
}
protected DecorView generateDecor() {
diff --git a/mid/com/android/internal/policy/impl/MidWindowManager.java b/mid/com/android/internal/policy/impl/MidWindowManager.java
index 2bff15b..ffdf872 100644
--- a/mid/com/android/internal/policy/impl/MidWindowManager.java
+++ b/mid/com/android/internal/policy/impl/MidWindowManager.java
@@ -83,6 +83,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
import android.view.WindowManagerPolicy.WindowState;
+import android.view.animation.Animation;
import android.media.IAudioService;
import android.media.AudioManager;
@@ -354,6 +355,19 @@ public class MidWindowManager implements WindowManagerPolicy {
return 0;
}
+ public int getMaxWallpaperLayer() {
+ return STATUS_BAR_LAYER;
+ }
+
+ public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
+ return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
+ }
+
+ public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
+ return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
+ && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER;
+ }
+
/** {@inheritDoc} */
public View addStartingWindow(IBinder appToken, String packageName,
int theme, CharSequence nonLocalizedLabel,
@@ -520,13 +534,17 @@ public class MidWindowManager implements WindowManagerPolicy {
return 0;
}
+ public Animation createForceHideEnterAnimation() {
+ return null;
+ }
+
private static IAudioService getAudioInterface() {
return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
}
/** {@inheritDoc} */
public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down,
- int repeatCount) {
+ int repeatCount, int flags) {
if (false) {
Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount="
+ repeatCount);
@@ -762,8 +780,8 @@ public class MidWindowManager implements WindowManagerPolicy {
}
/** {@inheritDoc} */
- public boolean finishLayoutLw() {
- return false;
+ public int finishLayoutLw() {
+ return 0;
}
/** {@inheritDoc} */
@@ -834,17 +852,12 @@ public class MidWindowManager implements WindowManagerPolicy {
* @return Whether music is being played right now.
*/
private boolean isMusicActive() {
- final IAudioService audio = getAudioInterface();
- if (audio == null) {
- Log.w(TAG, "isMusicActive: couldn't get IAudioService reference");
- return false;
- }
- try {
- return audio.isMusicActive();
- } catch (RemoteException e) {
- Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e);
+ final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
+ if (am == null) {
+ Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
return false;
}
+ return am.isMusicActive();
}
/**
@@ -1072,6 +1085,13 @@ public class MidWindowManager implements WindowManagerPolicy {
return false;
}
+ public void keyFeedbackFromInput(KeyEvent event) {
+ }
+
public void screenOnStoppedLw() {
}
+
+ public boolean allowKeyRepeat() {
+ return true;
+ }
}
diff --git a/phone/com/android/internal/policy/impl/AccountUnlockScreen.java b/phone/com/android/internal/policy/impl/AccountUnlockScreen.java
index 65102c6..7992dd8 100644
--- a/phone/com/android/internal/policy/impl/AccountUnlockScreen.java
+++ b/phone/com/android/internal/policy/impl/AccountUnlockScreen.java
@@ -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;
@@ -72,14 +72,16 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
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;
}
}
diff --git a/phone/com/android/internal/policy/impl/GlobalActions.java b/phone/com/android/internal/policy/impl/GlobalActions.java
index 377ff78..2f1f024 100644
--- a/phone/com/android/internal/policy/impl/GlobalActions.java
+++ b/phone/com/android/internal/policy/impl/GlobalActions.java
@@ -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);
+ }
}
diff --git a/phone/com/android/internal/policy/impl/KeyguardScreenCallback.java b/phone/com/android/internal/policy/impl/KeyguardScreenCallback.java
index b46b37d..6bb6a45 100644
--- a/phone/com/android/internal/policy/impl/KeyguardScreenCallback.java
+++ b/phone/com/android/internal/policy/impl/KeyguardScreenCallback.java
@@ -28,11 +28,20 @@ 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.
*/
boolean isSecure();
diff --git a/phone/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/phone/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
index cd21427..58905a1 100644
--- a/phone/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/phone/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -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;
}
diff --git a/phone/com/android/internal/policy/impl/KeyguardViewManager.java b/phone/com/android/internal/policy/impl/KeyguardViewManager.java
index 297d62f..bac2fca 100644
--- a/phone/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/phone/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -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);
}
}
}
diff --git a/phone/com/android/internal/policy/impl/KeyguardViewMediator.java b/phone/com/android/internal/policy/impl/KeyguardViewMediator.java
index 043f727..f5591b2 100644
--- a/phone/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/phone/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -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()}
@@ -150,6 +151,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
* the wake lock.
@@ -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?
*/
@@ -426,6 +421,17 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
}
/**
+ * 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
* was suppressed by an app that disabled the keyguard or we haven't been provisioned yet.
@@ -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");
}
}
}
diff --git a/phone/com/android/internal/policy/impl/LockPatternKeyguardView.java b/phone/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 6a1c279..0ebd945 100644
--- a/phone/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/phone/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -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()}
@@ -131,11 +140,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);
}
diff --git a/phone/com/android/internal/policy/impl/LockScreen.java b/phone/com/android/internal/policy/impl/LockScreen.java
index 0495a76..dda5097 100644
--- a/phone/com/android/internal/policy/impl/LockScreen.java
+++ b/phone/com/android/internal/policy/impl/LockScreen.java
@@ -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 boolean mSilentMode;
+ private AudioManager mAudioManager;
+ private java.text.DateFormat mDateFormat;
+ private java.text.DateFormat mTimeFormat;
+ private boolean mCreatedInPortrait;
+ private boolean mEnableMenuKeyInLockScreen;
- private View[] mOnlyVisibleWhenSimOk;
+ /**
+ * 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;
+ }
- private View[] mOnlyVisibleWhenSimNotOk;
+ /**
+ * @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;
- final LayoutInflater inflater = LayoutInflater.from(context);
- inflater.inflate(R.layout.keyguard_screen_lock, this, true);
+ mEnableMenuKeyInLockScreen = shouldEnableMenuKey();
- 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);
+ mCreatedInPortrait = updateMonitor.isInPortrait();
- mHeaderSimBad1 = (TextView) findViewById(R.id.headerSimBad1);
- mHeaderSimBad2 = (TextView) findViewById(R.id.headerSimBad2);
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ 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));
}
- public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
- refreshSimOkHeaders(plmn, spn);
- refreshAlarmDisplay(); // in case alarm won't fit anymore
+ /**
+ * @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 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);
- }
-
- 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);
+ 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);
}
}
- public void onSimStateChanged(IccCard.State simState) {
- mSimOk = isSimOk(simState);
- refreshViewsWRTSimOk();
- refreshUnlockIntructions();
+ /** {@inheritDoc} */
+ public void onRefreshCarrierInfo(CharSequence plmn, CharSequence spn) {
+ if (DBG) Log.d(TAG, "onRefreshCarrierInfo(" + plmn + ", " + spn + ")");
+ updateLayout(mStatus);
+ }
+
+ private void putEmergencyBelow(int viewId) {
+ final RelativeLayout.LayoutParams layoutParams =
+ (RelativeLayout.LayoutParams) mEmergencyCallButton.getLayoutParams();
+ layoutParams.addRule(RelativeLayout.BELOW, viewId);
+ mEmergencyCallButton.setLayoutParams(layoutParams);
}
/**
- * @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.
+ * Determine the current status of the lock screen given the sim state and other stuff.
*/
- private boolean isSimOk(IccCard.State simState) {
+ private Status getCurrentStatus(IccCard.State simState) {
boolean missingAndNotProvisioned = (!mUpdateMonitor.isDeviceProvisioned()
&& simState == IccCard.State.ABSENT);
- return !(missingAndNotProvisioned || simState == IccCard.State.PUK_REQUIRED);
+ 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) {
+ if (DBG) Log.d(TAG, "onSimStateChanged(" + simState + ")");
+ mStatus = getCurrentStatus(simState);
+ updateLayout(mStatus);
+ updateStatusLines();
+ }
+
+
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);
}
}
-
diff --git a/phone/com/android/internal/policy/impl/PhoneWindow.java b/phone/com/android/internal/policy/impl/PhoneWindow.java
index 6341771..6dd5d93 100644
--- a/phone/com/android/internal/policy/impl/PhoneWindow.java
+++ b/phone/com/android/internal/policy/impl/PhoneWindow.java
@@ -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);
+ }
+
+ } 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 preparePanel(st, event);
+
}
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;
/*
diff --git a/phone/com/android/internal/policy/impl/PhoneWindowManager.java b/phone/com/android/internal/policy/impl/PhoneWindowManager.java
index 8140b3d..e57fbe8 100644..100755
--- a/phone/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/phone/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -20,17 +20,19 @@ import android.app.Activity;
import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.IStatusBar;
+import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
-import android.content.ContentQueryMap;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Rect;
+import android.os.BatteryManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.LocalPowerManager;
@@ -67,6 +69,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -88,8 +91,12 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import android.view.WindowManagerImpl;
import android.view.WindowManagerPolicy;
+import android.view.WindowManagerPolicy.WindowState;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
import android.media.IAudioService;
import android.media.AudioManager;
@@ -108,29 +115,31 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final boolean SHOW_STARTING_ANIMATIONS = true;
static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;
- static final int APPLICATION_LAYER = 1;
- static final int PHONE_LAYER = 2;
- static final int SEARCH_BAR_LAYER = 3;
- static final int STATUS_BAR_PANEL_LAYER = 4;
+ // wallpaper is at the bottom, though the window manager may move it.
+ static final int WALLPAPER_LAYER = 2;
+ static final int APPLICATION_LAYER = 2;
+ static final int PHONE_LAYER = 3;
+ static final int SEARCH_BAR_LAYER = 4;
+ static final int STATUS_BAR_PANEL_LAYER = 5;
// toasts and the plugged-in battery thing
- static final int TOAST_LAYER = 5;
- static final int STATUS_BAR_LAYER = 6;
+ static final int TOAST_LAYER = 6;
+ static final int STATUS_BAR_LAYER = 7;
// SIM errors and unlock. Not sure if this really should be in a high layer.
- static final int PRIORITY_PHONE_LAYER = 7;
+ static final int PRIORITY_PHONE_LAYER = 8;
// like the ANR / app crashed dialogs
- static final int SYSTEM_ALERT_LAYER = 8;
+ static final int SYSTEM_ALERT_LAYER = 9;
// system-level error dialogs
- static final int SYSTEM_ERROR_LAYER = 9;
+ static final int SYSTEM_ERROR_LAYER = 10;
// on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_LAYER = 10;
+ static final int INPUT_METHOD_LAYER = 11;
// on-screen keyboards and other such input method user interfaces go here.
- static final int INPUT_METHOD_DIALOG_LAYER = 11;
+ static final int INPUT_METHOD_DIALOG_LAYER = 12;
// the keyguard; nothing on top of these can take focus, since they are
// responsible for power management when displayed.
- static final int KEYGUARD_LAYER = 12;
- static final int KEYGUARD_DIALOG_LAYER = 13;
+ static final int KEYGUARD_LAYER = 13;
+ static final int KEYGUARD_DIALOG_LAYER = 14;
// things in here CAN NOT take focus, but are shown on top of everything else.
- static final int SYSTEM_OVERLAY_LAYER = 14;
+ static final int SYSTEM_OVERLAY_LAYER = 15;
static final int APPLICATION_MEDIA_SUBLAYER = -2;
static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
@@ -146,9 +155,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
- // Vibrator pattern for haptic feedback of a long press.
- private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21};
-
final Object mLock = new Object();
Context mContext;
@@ -156,6 +162,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
LocalPowerManager mPowerManager;
Vibrator mVibrator; // Vibrator for giving feedback of orientation changes
+ // Vibrator pattern for haptic feedback of a long press.
+ long[] mLongPressVibePattern;
+
+ // Vibrator pattern for haptic feedback of virtual key press.
+ long[] mVirtualKeyVibePattern;
+
+ // Vibrator pattern for haptic feedback during boot when safe mode is disabled.
+ long[] mSafeModeDisabledVibePattern;
+
+ // Vibrator pattern for haptic feedback during boot when safe mode is enabled.
+ long[] mSafeModeEnabledVibePattern;
+
/** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
boolean mEnableShiftMenuBugReports = false;
@@ -168,7 +186,21 @@ public class PhoneWindowManager implements WindowManagerPolicy {
RecentApplicationsDialog mRecentAppsDialog;
Handler mHandler;
+ final IntentFilter mBatteryStatusFilter = new IntentFilter();
+
boolean mLidOpen;
+ int mPlugged;
+ boolean mRegisteredBatteryReceiver;
+ int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ int mLidOpenRotation;
+ int mCarDockRotation;
+ int mDeskDockRotation;
+ int mCarDockKeepsScreenOn;
+ int mDeskDockKeepsScreenOn;
+ boolean mCarDockEnablesAccelerometer;
+ boolean mDeskDockEnablesAccelerometer;
+ int mLidKeyboardAccessibility;
+ int mLidNavigationAccessibility;
boolean mScreenOn = false;
boolean mOrientationSensorEnabled = false;
int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -200,9 +232,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowState mTopFullscreenOpaqueWindowState;
boolean mForceStatusBar;
- boolean mHideKeyguard;
+ boolean mHideLockScreen;
+ boolean mDismissKeyguard;
boolean mHomePressed;
Intent mHomeIntent;
+ Intent mCarDockIntent;
+ Intent mDeskDockIntent;
boolean mSearchKeyPressed;
boolean mConsumeSearchKeyUp;
@@ -219,6 +254,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
ShortcutManager mShortcutManager;
PowerManager.WakeLock mBroadcastWakeLock;
+ PowerManager.WakeLock mDockWakeLock;
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
@@ -284,7 +320,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void onOrientationChanged(int rotation) {
// Send updates based on orientation value
- if (true) Log.i(TAG, "onOrientationChanged, rotation changed to " +rotation);
+ if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation);
try {
mWindowManager.setRotation(rotation, false,
mFancyRotationAnimation);
@@ -297,14 +333,27 @@ public class PhoneWindowManager implements WindowManagerPolicy {
MyOrientationListener mOrientationListener;
boolean useSensorForOrientationLp(int appOrientation) {
+ // The app says use the sensor.
if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) {
return true;
}
- if (mAccelerometerDefault != 0 && (
- appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER ||
- appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
+ // The user preference says we can rotate, and the app is willing to rotate.
+ if (mAccelerometerDefault != 0 &&
+ (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
+ || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) {
return true;
}
+ // We're in a dock that has a rotation affinity, an the app is willing to rotate.
+ if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR)
+ || (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) {
+ // Note we override the nosensor flag here.
+ if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER
+ || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
+ || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) {
+ return true;
+ }
+ }
+ // Else, don't use the sensor.
return false;
}
@@ -319,6 +368,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// orientation, then we need to turn the sensor or.
return true;
}
+ if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) ||
+ (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) {
+ // enable accelerometer if we are docked in a dock that enables accelerometer
+ // orientation management,
+ return true;
+ }
if (mAccelerometerDefault == 0) {
// If the setting for using the sensor by default is enabled, then
// we will always leave it on. Note that the user could go to
@@ -350,7 +405,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
//Could have been invoked due to screen turning on or off or
//change of the currently visible window's orientation
- if (localLOGV) Log.i(TAG, "Screen status="+mScreenOn+
+ if (localLOGV) Log.v(TAG, "Screen status="+mScreenOn+
", current orientation="+mCurrentAppOrientation+
", SensorEnabled="+mOrientationSensorEnabled);
boolean disable = true;
@@ -360,7 +415,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
//enable listener if not already enabled
if (!mOrientationSensorEnabled) {
mOrientationListener.enable();
- if(localLOGV) Log.i(TAG, "Enabling listeners");
+ if(localLOGV) Log.v(TAG, "Enabling listeners");
mOrientationSensorEnabled = true;
}
}
@@ -368,12 +423,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
//check if sensors need to be disabled
if (disable && mOrientationSensorEnabled) {
mOrientationListener.disable();
- if(localLOGV) Log.i(TAG, "Disabling listeners");
+ if(localLOGV) Log.v(TAG, "Disabling listeners");
mOrientationSensorEnabled = false;
}
}
- Runnable mEndCallLongPress = new Runnable() {
+ Runnable mPowerLongPress = new Runnable() {
public void run() {
mShouldTurnOffOnKeyUp = false;
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
@@ -443,10 +498,81 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHomeIntent.addCategory(Intent.CATEGORY_HOME);
mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ mCarDockIntent = new Intent(Intent.ACTION_MAIN, null);
+ mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK);
+ mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ mDeskDockIntent = new Intent(Intent.ACTION_MAIN, null);
+ mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK);
+ mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"PhoneWindowManager.mBroadcastWakeLock");
+ mDockWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK,
+ "PhoneWindowManager.mDockWakeLock");
+ mDockWakeLock.setReferenceCounted(false);
mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable"));
+ mLidOpenRotation = readRotation(
+ com.android.internal.R.integer.config_lidOpenRotation);
+ mCarDockRotation = readRotation(
+ com.android.internal.R.integer.config_carDockRotation);
+ mDeskDockRotation = readRotation(
+ com.android.internal.R.integer.config_deskDockRotation);
+ mCarDockKeepsScreenOn = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_carDockKeepsScreenOn);
+ mDeskDockKeepsScreenOn = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_deskDockKeepsScreenOn);
+ mCarDockEnablesAccelerometer = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_carDockEnablesAccelerometer);
+ mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_deskDockEnablesAccelerometer);
+ mLidKeyboardAccessibility = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lidKeyboardAccessibility);
+ mLidNavigationAccessibility = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_lidNavigationAccessibility);
+ // register for battery events
+ mBatteryStatusFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
+ mPlugged = 0;
+ updatePlugged(context.registerReceiver(null, mBatteryStatusFilter));
+ // register for dock events
+ context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT));
+ mVibrator = new Vibrator();
+ mLongPressVibePattern = getLongIntArray(mContext.getResources(),
+ com.android.internal.R.array.config_longPressVibePattern);
+ mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
+ com.android.internal.R.array.config_virtualKeyVibePattern);
+ mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(),
+ com.android.internal.R.array.config_safeModeDisabledVibePattern);
+ mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(),
+ com.android.internal.R.array.config_safeModeEnabledVibePattern);
+ }
+
+ void updatePlugged(Intent powerIntent) {
+ if (localLOGV) Log.v(TAG, "New battery status: " + powerIntent.getExtras());
+ if (powerIntent != null) {
+ mPlugged = powerIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
+ if (localLOGV) Log.v(TAG, "PLUGGED: " + mPlugged);
+ }
+ }
+
+ private int readRotation(int resID) {
+ try {
+ int rotation = mContext.getResources().getInteger(resID);
+ switch (rotation) {
+ case 0:
+ return Surface.ROTATION_0;
+ case 90:
+ return Surface.ROTATION_90;
+ case 180:
+ return Surface.ROTATION_180;
+ case 270:
+ return Surface.ROTATION_270;
+ }
+ } catch (Resources.NotFoundException e) {
+ // fall through
+ }
+ return -1;
}
/** {@inheritDoc} */
@@ -465,7 +591,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// monitor/control what they are doing.
break;
case TYPE_INPUT_METHOD:
- // The window manager will check this.
+ case TYPE_WALLPAPER:
+ // The window manager will check these.
break;
case TYPE_PHONE:
case TYPE_PRIORITY_PHONE:
@@ -499,7 +626,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
void readLidState() {
try {
- int sw = mWindowManager.getSwitchState(0);
+ int sw = mWindowManager.getSwitchState(RawInputEvent.SW_LID);
if (sw >= 0) {
mLidOpen = sw == 0;
}
@@ -508,17 +635,32 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ private int determineHiddenState(boolean lidOpen,
+ int mode, int hiddenValue, int visibleValue) {
+ switch (mode) {
+ case 1:
+ return lidOpen ? visibleValue : hiddenValue;
+ case 2:
+ return lidOpen ? hiddenValue : visibleValue;
+ }
+ return visibleValue;
+ }
+
/** {@inheritDoc} */
public void adjustConfigurationLw(Configuration config) {
readLidState();
final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen;
mPowerManager.setKeyboardVisibility(lidOpen);
- config.keyboardHidden = (lidOpen || mHasSoftInput)
- ? Configuration.KEYBOARDHIDDEN_NO
- : Configuration.KEYBOARDHIDDEN_YES;
- config.hardKeyboardHidden = lidOpen
- ? Configuration.KEYBOARDHIDDEN_NO
- : Configuration.KEYBOARDHIDDEN_YES;
+ config.hardKeyboardHidden = determineHiddenState(lidOpen,
+ mLidKeyboardAccessibility, Configuration.HARDKEYBOARDHIDDEN_YES,
+ Configuration.HARDKEYBOARDHIDDEN_NO);
+ config.navigationHidden = determineHiddenState(lidOpen,
+ mLidNavigationAccessibility, Configuration.NAVIGATIONHIDDEN_YES,
+ Configuration.NAVIGATIONHIDDEN_NO);
+ config.keyboardHidden = (config.hardKeyboardHidden
+ == Configuration.HARDKEYBOARDHIDDEN_NO || mHasSoftInput)
+ ? Configuration.KEYBOARDHIDDEN_NO
+ : Configuration.KEYBOARDHIDDEN_YES;
}
public boolean isCheekPressedAgainstScreen(MotionEvent ev) {
@@ -566,6 +708,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return PRIORITY_PHONE_LAYER;
case TYPE_TOAST:
return TOAST_LAYER;
+ case TYPE_WALLPAPER:
+ return WALLPAPER_LAYER;
}
Log.e(TAG, "Unknown window type: " + type);
return APPLICATION_LAYER;
@@ -588,6 +732,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return 0;
}
+ public int getMaxWallpaperLayer() {
+ return STATUS_BAR_LAYER;
+ }
+
+ public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) {
+ return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD;
+ }
+
+ public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) {
+ return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
+ && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER;
+ }
+
/** {@inheritDoc} */
public View addStartingWindow(IBinder appToken, String packageName,
int theme, CharSequence nonLocalizedLabel,
@@ -756,6 +913,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return 0;
}
+ public Animation createForceHideEnterAnimation() {
+ return AnimationUtils.loadAnimation(mContext,
+ com.android.internal.R.anim.lock_screen_behind_enter);
+ }
+
static ITelephony getPhoneInterface() {
return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE));
}
@@ -775,7 +937,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down,
- int repeatCount) {
+ int repeatCount, int flags) {
boolean keyguardOn = keyguardOn();
if (false) {
@@ -800,32 +962,36 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (!down) {
mHomePressed = false;
- // If an incoming call is ringing, HOME is totally disabled.
- // (The user is already on the InCallScreen at this point,
- // and his ONLY options are to answer or reject the call.)
- boolean incomingRinging = false;
- try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- incomingRinging = phoneServ.isRinging();
+ if ((flags&KeyEvent.FLAG_CANCELED) == 0) {
+ // If an incoming call is ringing, HOME is totally disabled.
+ // (The user is already on the InCallScreen at this point,
+ // and his ONLY options are to answer or reject the call.)
+ boolean incomingRinging = false;
+ try {
+ ITelephony phoneServ = getPhoneInterface();
+ if (phoneServ != null) {
+ incomingRinging = phoneServ.isRinging();
+ } else {
+ Log.w(TAG, "Unable to find ITelephony interface");
+ }
+ } catch (RemoteException ex) {
+ Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
+ }
+
+ if (incomingRinging) {
+ Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
} else {
- Log.w(TAG, "Unable to find ITelephony interface");
+ launchHomeFromHotKey();
}
- } catch (RemoteException ex) {
- Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
- }
-
- if (incomingRinging) {
- Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
} else {
- launchHomeFromHotKey();
+ Log.i(TAG, "Ignoring HOME; event canceled.");
}
}
}
return true;
}
-
+
// First we always handle the home key here, so applications
// can never break it, although if keyguard is on, we do let
// it handle it, because that gives us the correct 5 second
@@ -942,9 +1108,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* given the situation with the keyguard.
*/
void launchHomeFromHotKey() {
- if (mKeyguardMediator.isShowing()) {
+ if (!mHideLockScreen && mKeyguardMediator.isShowing()) {
// don't launch home if keyguard showing
- } else if (mKeyguardMediator.isInputRestricted()) {
+ } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) {
// when in keyguard restricted mode, must first verify unlock
// before launching home
mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() {
@@ -955,7 +1121,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} catch (RemoteException e) {
}
sendCloseSystemWindows();
- mContext.startActivity(mHomeIntent);
+ startDockOrHome();
}
}
});
@@ -966,7 +1132,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} catch (RemoteException e) {
}
sendCloseSystemWindows();
- mContext.startActivity(mHomeIntent);
+ startDockOrHome();
}
}
@@ -994,7 +1160,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mTopFullscreenOpaqueWindowState = null;
mForceStatusBar = false;
- mHideKeyguard = false;
+ mHideLockScreen = false;
+ mDismissKeyguard = false;
// decide where the status bar goes ahead of time
if (mStatusBar != null) {
@@ -1192,20 +1359,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
win.computeFrameLw(pf, df, cf, vf);
- if (win.isVisibleLw()) {
+ if (mTopFullscreenOpaqueWindowState == null &&
+ win.isVisibleOrBehindKeyguardLw()) {
if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
mForceStatusBar = true;
- } else if (mTopFullscreenOpaqueWindowState == null
- && attrs.type >= FIRST_APPLICATION_WINDOW
+ }
+ if (attrs.type >= FIRST_APPLICATION_WINDOW
&& attrs.type <= LAST_APPLICATION_WINDOW
&& win.fillsScreenLw(mW, mH, false, false)) {
if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
mTopFullscreenOpaqueWindowState = win;
+ if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
+ if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win);
+ mHideLockScreen = true;
+ }
}
- if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
- // TODO Add a check for the window to be full screen
- if (localLOGV) Log.i(TAG, "Setting mHideKeyguard to true by win " + win);
- mHideKeyguard = true;
+ if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) {
+ if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win);
+ mDismissKeyguard = true;
}
}
@@ -1229,15 +1400,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/** {@inheritDoc} */
- public boolean finishLayoutLw() {
- boolean changed = false;
+ public int finishLayoutLw() {
+ int changes = 0;
boolean hiding = false;
if (mStatusBar != null) {
- //Log.i(TAG, "force=" + mForceStatusBar
- // + " top=" + mTopFullscreenOpaqueWindowState);
+ if (localLOGV) Log.i(TAG, "force=" + mForceStatusBar
+ + " top=" + mTopFullscreenOpaqueWindowState);
if (mForceStatusBar) {
if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
- changed |= mStatusBar.showLw(true);
+ if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
} else if (mTopFullscreenOpaqueWindowState != null) {
//Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()
// + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw());
@@ -1248,26 +1419,49 @@ public class PhoneWindowManager implements WindowManagerPolicy {
(lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
if (hideStatusBar) {
if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar");
- changed |= mStatusBar.hideLw(true);
+ if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
hiding = true;
} else {
if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar");
- changed |= mStatusBar.showLw(true);
+ if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT;
}
}
}
// Hide the key guard if a visible window explicitly specifies that it wants to be displayed
// when the screen is locked
if (mKeyguard != null) {
- if (localLOGV) Log.i(TAG, "finishLayoutLw::mHideKeyguard="+mHideKeyguard);
- if (mHideKeyguard) {
- changed |= mKeyguard.hideLw(true);
+ if (localLOGV) Log.v(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen);
+ if (mDismissKeyguard && !mKeyguardMediator.isSecure()) {
+ if (mKeyguard.hideLw(false)) {
+ changes |= FINISH_LAYOUT_REDO_LAYOUT
+ | FINISH_LAYOUT_REDO_CONFIG
+ | FINISH_LAYOUT_REDO_WALLPAPER;
+ }
+ if (mKeyguardMediator.isShowing()) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ mKeyguardMediator.keyguardDone(false, false);
+ }
+ });
+ }
+ } else if (mHideLockScreen) {
+ if (mKeyguard.hideLw(false)) {
+ mKeyguardMediator.setHidden(true);
+ changes |= FINISH_LAYOUT_REDO_LAYOUT
+ | FINISH_LAYOUT_REDO_CONFIG
+ | FINISH_LAYOUT_REDO_WALLPAPER;
+ }
} else {
- changed |= mKeyguard.showLw(true);
+ if (mKeyguard.showLw(false)) {
+ mKeyguardMediator.setHidden(false);
+ changes |= FINISH_LAYOUT_REDO_LAYOUT
+ | FINISH_LAYOUT_REDO_CONFIG
+ | FINISH_LAYOUT_REDO_WALLPAPER;
+ }
}
}
- if (changed && hiding) {
+ if (changes != 0 && hiding) {
IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar"));
if (sbs != null) {
try {
@@ -1278,7 +1472,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- return changed;
+ return changes;
}
/** {@inheritDoc} */
@@ -1299,15 +1493,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public boolean preprocessInputEventTq(RawInputEvent event) {
switch (event.type) {
case RawInputEvent.EV_SW:
- if (event.keycode == 0) {
+ if (event.keycode == RawInputEvent.SW_LID) {
// lid changed state
mLidOpen = event.value == 0;
+ boolean awakeNow = mKeyguardMediator.doLidChangeTq(mLidOpen);
updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
- if (keyguardIsShowingTq()) {
+ if (awakeNow) {
+ // If the lid opening and we don't have to keep the
+ // keyguard up, then we can turn on the screen
+ // immediately.
+ mKeyguardMediator.pokeWakelock();
+ } else if (keyguardIsShowingTq()) {
if (mLidOpen) {
- // only do this if it's opening -- closing the device shouldn't turn it
- // off, but it also shouldn't turn it on.
- mKeyguardMediator.pokeWakelock();
+ // If we are opening the lid and not hiding the
+ // keyguard, then we need to have it turn on the
+ // screen once it is shown.
+ mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(
+ KeyEvent.KEYCODE_POWER);
}
} else {
// Light up the keyboard if we are sliding up.
@@ -1365,27 +1567,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* @return Whether music is being played right now.
*/
boolean isMusicActive() {
- final IAudioService audio = getAudioInterface();
- if (audio == null) {
- Log.w(TAG, "isMusicActive: couldn't get IAudioService reference");
- return false;
- }
- try {
- return audio.isMusicActive();
- } catch (RemoteException e) {
- Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e);
+ final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
+ if (am == null) {
+ Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
return false;
}
+ return am.isMusicActive();
}
/**
* Tell the audio service to adjust the volume appropriate to the event.
* @param keycode
*/
- void sendVolToMusic(int keycode) {
+ void handleVolumeKey(int stream, int keycode) {
final IAudioService audio = getAudioInterface();
if (audio == null) {
- Log.w(TAG, "sendVolToMusic: couldn't get IAudioService reference");
+ Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference");
return;
}
try {
@@ -1393,8 +1590,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// during the call, but we do it as a precaution for the rare possibility
// that the music stops right before we call this
mBroadcastWakeLock.acquire();
- audio.adjustStreamVolume(
- AudioManager.STREAM_MUSIC,
+ audio.adjustStreamVolume(stream,
keycode == KeyEvent.KEYCODE_VOLUME_UP
? AudioManager.ADJUST_RAISE
: AudioManager.ADJUST_LOWER,
@@ -1456,12 +1652,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else if (isMusicActive()) {
// when keyguard is showing and screen off, we need
// to handle the volume key for music here
- sendVolToMusic(event.keycode);
+ handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode);
}
}
}
}
} else if (!screenIsOn) {
+ // If we are in-call with screen off and keyguard is not showing,
+ // then handle the volume key ourselves.
+ // This is necessary because the phone app will disable the keyguard
+ // when the proximity sensor is in use.
+ if (isInCall() && event.type == RawInputEvent.EV_KEY &&
+ (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN
+ || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) {
+ result &= ~ACTION_PASS_TO_USER;
+ handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode);
+ }
if (isWakeKey) {
// a wake key has a sole purpose of waking the device; don't pass
// it to the user
@@ -1475,33 +1681,41 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean down = event.value != 0;
if (type == RawInputEvent.EV_KEY) {
- if (code == KeyEvent.KEYCODE_ENDCALL) {
+ if (code == KeyEvent.KEYCODE_ENDCALL
+ || code == KeyEvent.KEYCODE_POWER) {
if (down) {
- boolean hungUp = false;
+ boolean handled = false;
// key repeats are generated by the window manager, and we don't see them
// here, so unless the driver is doing something it shouldn't be, we know
// this is the real press event.
- try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- hungUp = phoneServ.endCall();
- } else {
- Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
+ ITelephony phoneServ = getPhoneInterface();
+ if (phoneServ != null) {
+ try {
+ if (code == KeyEvent.KEYCODE_ENDCALL) {
+ handled = phoneServ.endCall();
+ } else if (code == KeyEvent.KEYCODE_POWER && phoneServ.isRinging()) {
+ // Pressing power during incoming call should silence the ringer
+ phoneServ.silenceRinger();
+ handled = true;
+ }
+ } catch (RemoteException ex) {
+ Log.w(TAG, "ITelephony threw RemoteException" + ex);
}
- } catch (RemoteException ex) {
- Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex);
+ } else {
+ Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
}
- if (hungUp || !screenIsOn) {
+ // power button should turn off screen in addition to hanging up the phone
+ if ((handled && code != KeyEvent.KEYCODE_POWER) || !screenIsOn) {
mShouldTurnOffOnKeyUp = false;
} else {
// only try to turn off the screen if we didn't already hang up
mShouldTurnOffOnKeyUp = true;
- mHandler.postDelayed(mEndCallLongPress,
+ mHandler.postDelayed(mPowerLongPress,
ViewConfiguration.getGlobalActionKeyTimeout());
result &= ~ACTION_PASS_TO_USER;
}
} else {
- mHandler.removeCallbacks(mEndCallLongPress);
+ mHandler.removeCallbacks(mPowerLongPress);
if (mShouldTurnOffOnKeyUp) {
mShouldTurnOffOnKeyUp = false;
boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0;
@@ -1620,7 +1834,34 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mBroadcastWakeLock.release();
}
};
-
+
+ BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ updatePlugged(intent);
+ updateDockKeepingScreenOn();
+ }
+ };
+
+ BroadcastReceiver mDockReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+ Intent.EXTRA_DOCK_STATE_UNDOCKED);
+ boolean watchBattery = mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ if (watchBattery != mRegisteredBatteryReceiver) {
+ mRegisteredBatteryReceiver = watchBattery;
+ if (watchBattery) {
+ updatePlugged(mContext.registerReceiver(mBatteryReceiver,
+ mBatteryStatusFilter));
+ } else {
+ mContext.unregisterReceiver(mBatteryReceiver);
+ }
+ }
+ updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
+ updateDockKeepingScreenOn();
+ updateOrientationListenerLp();
+ }
+ };
+
/** {@inheritDoc} */
public boolean isWakeRelMovementTq(int device, int classes,
RawInputEvent event) {
@@ -1736,7 +1977,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// or orientation sensor disabled
//or case.unspecified
if (mLidOpen) {
- return Surface.ROTATION_90;
+ return mLidOpenRotation;
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
+ return mCarDockRotation;
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
+ return mDeskDockRotation;
} else {
if (useSensorForOrientationLp(orientation)) {
// If the user has enabled auto rotation by default, do it.
@@ -1751,8 +1996,19 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public boolean detectSafeMode() {
try {
int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU);
- mSafeMode = menuState > 0;
- Log.i(TAG, "Menu key state: " + menuState + " safeMode=" + mSafeMode);
+ int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S);
+ int dpadState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER);
+ int trackballState = mWindowManager.getScancodeState(RawInputEvent.BTN_MOUSE);
+ mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0;
+ performHapticFeedbackLw(null, mSafeMode
+ ? HapticFeedbackConstants.SAFE_MODE_ENABLED
+ : HapticFeedbackConstants.SAFE_MODE_DISABLED, true);
+ if (mSafeMode) {
+ Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
+ + " dpad=" + dpadState + " trackball=" + trackballState + ")");
+ } else {
+ Log.i(TAG, "SAFE MODE not enabled");
+ }
return mSafeMode;
} catch (RemoteException e) {
// Doom! (it's also local)
@@ -1760,23 +2016,25 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ static long[] getLongIntArray(Resources r, int resid) {
+ int[] ar = r.getIntArray(resid);
+ if (ar == null) {
+ return null;
+ }
+ long[] out = new long[ar.length];
+ for (int i=0; i<ar.length; i++) {
+ out[i] = ar[i];
+ }
+ return out;
+ }
+
/** {@inheritDoc} */
public void systemReady() {
- try {
- if (mSafeMode) {
- // If the user is holding the menu key code, then we are
- // going to boot into safe mode.
- ActivityManagerNative.getDefault().enterSafeMode();
- }
- // tell the keyguard
- mKeyguardMediator.onSystemReady();
- android.os.SystemProperties.set("dev.bootcomplete", "1");
- synchronized (mLock) {
- updateOrientationListenerLp();
- mVibrator = new Vibrator();
- }
- } catch (RemoteException e) {
- // Ignore
+ // tell the keyguard
+ mKeyguardMediator.onSystemReady();
+ android.os.SystemProperties.set("dev.bootcomplete", "1");
+ synchronized (mLock) {
+ updateOrientationListenerLp();
}
}
@@ -1787,12 +2045,41 @@ public class PhoneWindowManager implements WindowManagerPolicy {
updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
}
+ void updateDockKeepingScreenOn() {
+ if (mPlugged != 0) {
+ if (localLOGV) Log.v(TAG, "Update: mDockState=" + mDockState
+ + " mPlugged=" + mPlugged
+ + " mCarDockKeepsScreenOn" + mCarDockKeepsScreenOn
+ + " mDeskDockKeepsScreenOn" + mDeskDockKeepsScreenOn);
+ if (mDockState == Intent.EXTRA_DOCK_STATE_CAR
+ && (mPlugged&mCarDockKeepsScreenOn) != 0) {
+ if (!mDockWakeLock.isHeld()) {
+ mDockWakeLock.acquire();
+ }
+ return;
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK
+ && (mPlugged&mDeskDockKeepsScreenOn) != 0) {
+ if (!mDockWakeLock.isHeld()) {
+ mDockWakeLock.acquire();
+ }
+ return;
+ }
+ }
+
+ if (mDockWakeLock.isHeld()) {
+ mDockWakeLock.release();
+ }
+ }
+
void updateRotation(int animFlags) {
mPowerManager.setKeyboardVisibility(mLidOpen);
- int rotation= Surface.ROTATION_0;
+ int rotation = Surface.ROTATION_0;
if (mLidOpen) {
- // always use landscape if lid is open
- rotation = Surface.ROTATION_90;
+ rotation = mLidOpenRotation;
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) {
+ rotation = mCarDockRotation;
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) {
+ rotation = mDeskDockRotation;
}
//if lid is closed orientation will be portrait
try {
@@ -1805,6 +2092,53 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
/**
+ * Return an Intent to launch the currently active dock as home. Returns
+ * null if the standard home should be launched.
+ * @return
+ */
+ Intent createHomeDockIntent() {
+ if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+ return null;
+ }
+
+ Intent intent;
+ if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
+ intent = mCarDockIntent;
+ } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+ intent = mDeskDockIntent;
+ } else {
+ Log.w(TAG, "Unknown dock state: " + mDockState);
+ return null;
+ }
+
+ ActivityInfo ai = intent.resolveActivityInfo(
+ mContext.getPackageManager(), PackageManager.GET_META_DATA);
+ if (ai == null) {
+ return null;
+ }
+
+ if (ai.metaData != null && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) {
+ intent = new Intent(intent);
+ intent.setClassName(ai.packageName, ai.name);
+ return intent;
+ }
+
+ return null;
+ }
+
+ void startDockOrHome() {
+ Intent dock = createHomeDockIntent();
+ if (dock != null) {
+ try {
+ mContext.startActivity(dock);
+ return;
+ } catch (ActivityNotFoundException e) {
+ }
+ }
+ mContext.startActivity(mHomeIntent);
+ }
+
+ /**
* goes to the home screen
* @return whether it did anything
*/
@@ -1816,13 +2150,23 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} catch (RemoteException e) {
}
sendCloseSystemWindows();
- mContext.startActivity(mHomeIntent);
+ startDockOrHome();
} else {
// This code brings home to the front or, if it is already
// at the front, puts the device to sleep.
try {
ActivityManagerNative.getDefault().stopAppSwitches();
sendCloseSystemWindows();
+ Intent dock = createHomeDockIntent();
+ if (dock != null) {
+ int result = ActivityManagerNative.getDefault()
+ .startActivity(null, dock,
+ dock.resolveTypeIfNeeded(mContext.getContentResolver()),
+ null, 0, null, null, 0, true /* onlyIfNeeded*/, false);
+ if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) {
+ return false;
+ }
+ }
int result = ActivityManagerNative.getDefault()
.startActivity(null, mHomeIntent,
mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
@@ -1847,23 +2191,45 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) {
- if (!always && Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) {
+ final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(),
+ Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0;
+ if (!always && (hapticsDisabled || mKeyguardMediator.isShowing())) {
return false;
}
switch (effectId) {
case HapticFeedbackConstants.LONG_PRESS:
- mVibrator.vibrate(LONG_PRESS_VIBE_PATTERN, -1);
+ mVibrator.vibrate(mLongPressVibePattern, -1);
+ return true;
+ case HapticFeedbackConstants.VIRTUAL_KEY:
+ mVibrator.vibrate(mVirtualKeyVibePattern, -1);
+ return true;
+ case HapticFeedbackConstants.SAFE_MODE_DISABLED:
+ mVibrator.vibrate(mSafeModeDisabledVibePattern, -1);
+ return true;
+ case HapticFeedbackConstants.SAFE_MODE_ENABLED:
+ mVibrator.vibrate(mSafeModeEnabledVibePattern, -1);
return true;
}
return false;
}
+ public void keyFeedbackFromInput(KeyEvent event) {
+ if (event.getAction() == KeyEvent.ACTION_DOWN
+ && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) {
+ performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+ }
+ }
+
public void screenOnStoppedLw() {
if (!mKeyguardMediator.isShowing()) {
long curTime = SystemClock.uptimeMillis();
mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
}
}
+
+ public boolean allowKeyRepeat() {
+ // disable key repeat when screen is off
+ return mScreenOn;
+ }
}
diff --git a/phone/com/android/internal/policy/impl/PowerDialog.java b/phone/com/android/internal/policy/impl/PowerDialog.java
index f4d4b04..de35bd7 100644
--- a/phone/com/android/internal/policy/impl/PowerDialog.java
+++ b/phone/com/android/internal/policy/impl/PowerDialog.java
@@ -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);
diff --git a/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java b/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java
index a680cc8..4c46be5 100644
--- a/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java
+++ b/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java
@@ -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");
diff --git a/phone/com/android/internal/policy/impl/SimUnlockScreen.java b/phone/com/android/internal/policy/impl/SimUnlockScreen.java
index 0f7fe32..3881d11 100644
--- a/phone/com/android/internal/policy/impl/SimUnlockScreen.java
+++ b/phone/com/android/internal/policy/impl/SimUnlockScreen.java
@@ -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;
}
diff --git a/phone/com/android/internal/policy/impl/UnlockScreen.java b/phone/com/android/internal/policy/impl/UnlockScreen.java
index 9aedf90..a5032b3 100644
--- a/phone/com/android/internal/policy/impl/UnlockScreen.java
+++ b/phone/com/android/internal/policy/impl/UnlockScreen.java
@@ -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);
- mLockPatternView = (LockPatternView) findViewById(R.id.lockPattern);
- mUnlockHeader = (TextView) findViewById(R.id.headerText);
+ mCenterDot.setText("|");
+ refreshTimeAndDateDisplay();
- mUnlockHeader.setText(R.string.lockscreen_pattern_instructions);
+ 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);
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,19 +228,106 @@ 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;
+ 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);
}
- return false;
}
+
+ 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) {
// as long as the user is entering a pattern (i.e sending a touch
@@ -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();
}
-
}