merge from open-source master
diff --git a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java
index 65102c6..098a651 100644
--- a/policy/com/android/internal/policy/impl/AccountUnlockScreen.java
+++ b/policy/com/android/internal/policy/impl/AccountUnlockScreen.java
@@ -19,21 +19,15 @@
 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.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;
@@ -45,12 +39,9 @@
 /**
  * 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 +53,6 @@
 
     private final KeyguardScreenCallback mCallback;
     private final LockPatternUtils mLockPatternUtils;
-    private IAccountsService mAccountsService;
 
     private TextView mTopHeader;
     private TextView mInstructions;
@@ -73,9 +63,6 @@
 
     /**
      * AccountUnlockScreen constructor.
-     *
-     * @throws IllegalStateException if the IAccountsService is not
-     * available on the current platform.
      */
     public AccountUnlockScreen(Context context,
             KeyguardScreenCallback callback,
@@ -103,14 +90,6 @@
 
         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,7 +129,6 @@
 
     /** {@inheritDoc} */
     public void cleanUp() {
-        mContext.unbindService(this);
     }
 
     /** {@inheritDoc} */
@@ -207,33 +185,25 @@
      * @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).blockingGetAccounts();
 
         // 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.mName)) {
                 score = 4;
-            } else if (username.equalsIgnoreCase(a)) {
+            } else if (username.equalsIgnoreCase(a.mName)) {
                 score = 3;
             } else if (username.indexOf('@') < 0) {
-                int i = a.indexOf('@');
+                int i = a.mName.indexOf('@');
                 if (i >= 0) {
-                    String aUsername = a.substring(0, i);
+                    String aUsername = a.mName.substring(0, i);
                     if (username.equals(aUsername)) {
                         score = 2;
                     } else if (username.equalsIgnoreCase(aUsername)) {
@@ -254,25 +224,18 @@
     private boolean checkPassword() {
         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) {
+        Account account = findIntendedAccount(login);
+        if (account == null) {
             return false;
         }
-    }
-
-    /** {@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;
+        // TODO(fredq) change this to asynchronously issue the request and wait for the response (by
+        // supplying a callback rather than calling get() immediately)
+        try {
+            return AccountManager.get(mContext).confirmPassword(
+                    account, password, null /* callback */, null /* handler */).getResult();
+        } catch (android.accounts.OperationCanceledException e) {
+            // the request was canceled
+            return false;
+        }
     }
 }
diff --git a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
index cd21427..44e893b 100644
--- a/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
+++ b/policy/com/android/internal/policy/impl/KeyguardUpdateMonitor.java
@@ -35,7 +35,6 @@
 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;
@@ -295,13 +294,6 @@
                         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);
-        }
     }
 
     /**
diff --git a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 6a1c279..4294de4 100644
--- a/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -16,38 +16,36 @@
 
 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.AccountManager;
 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;
 
 /**
  * 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 {
@@ -60,12 +58,12 @@
 
     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
 
 
     /**
@@ -131,11 +129,6 @@
     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.
      */
@@ -158,9 +151,28 @@
             LockPatternUtils lockPatternUtils,
             KeyguardWindowController controller) {
         super(context);
-        
-        asyncCheckForAccount();
-        
+
+        final boolean hasAccount = AccountManager.get(context).blockingGetAccounts().length > 0;
+        boolean hasSAMLAccount = false;
+        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. */
+
+            try {
+                hasSAMLAccount =
+                    AccountManager.get(context).blockingGetAccountsWithTypeAndFeatures(
+                            "com.GOOGLE.GAIA", new String[] {"saml"}).length > 0;
+            } catch (Exception e) {
+                // We err on the side of caution.
+                // In case of error we assume we have a SAML account.
+                hasSAMLAccount = true;
+            }
+        }
+        mEnableFallback = hasAccount && !hasSAMLAccount;
+
         mRequiresSim =
                 TextUtils.isEmpty(SystemProperties.get("keyguard.no_require_sim"));
 
@@ -169,7 +181,7 @@
         mWindowController = controller;
 
         mMode = getInitialMode();
-        
+
         mKeyguardScreenCallback = new KeyguardScreenCallback() {
 
             public void goToLockScreen() {
@@ -235,11 +247,11 @@
             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 +260,9 @@
                     showTimeoutDialog();
                 }
             }
-            
+
             public boolean doesFallbackUnlockScreenExist() {
-                return mHasAccount;
+                return mEnableFallback;
             }
         };
 
@@ -277,35 +289,6 @@
         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() {
@@ -423,7 +406,7 @@
         // 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) {
diff --git a/policy/com/android/internal/policy/impl/PhoneWindow.java b/policy/com/android/internal/policy/impl/PhoneWindow.java
index 6341771..345b620 100644
--- a/policy/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/com/android/internal/policy/impl/PhoneWindow.java
@@ -295,11 +295,9 @@
             /* 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);
     }
 
@@ -678,6 +676,10 @@
             mPanelChordingKey = 0;
             mKeycodeMenuTimeoutHandler.removeMessages(MSG_MENU_LONG_PRESS);
 
+            if (event.isCanceled()) {
+                return;
+            }
+            
             boolean playSoundEffect = false;
             PanelFeatureState st = getPanelState(featureId, true);
             if (st.isOpen || st.isHandled) {
@@ -1395,7 +1397,9 @@
                 mKeycodeMenuTimeoutHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
                 if (!mKeycodeCameraTimeoutActive) break;
                 mKeycodeCameraTimeoutActive = false;
-                // Add short press behavior here if desired
+                if (!event.isCanceled()) {
+                    // Add short press behavior here if desired
+                }
                 return true;
             }
 
@@ -1407,7 +1411,9 @@
                 mKeycodeMenuTimeoutHandler.removeMessages(MSG_CALL_LONG_PRESS);
                 if (!mKeycodeCallTimeoutActive) break;
                 mKeycodeCallTimeoutActive = false;
-                startCallActivity();
+                if (!event.isCanceled()) {
+                    startCallActivity();
+                }
                 return true;
             }
 
@@ -1422,7 +1428,9 @@
                     break;
                 }
                 mSearchKeyDownReceived = false;
-                launchDefaultSearch();
+                if (!event.isCanceled()) {
+                    launchDefaultSearch();
+                }
                 return true;
             }
         }
diff --git a/policy/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/com/android/internal/policy/impl/PhoneWindowManager.java
index 8140b3d..8c0e95d 100644
--- a/policy/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -149,6 +149,9 @@
     // Vibrator pattern for haptic feedback of a long press.
     private static final long[] LONG_PRESS_VIBE_PATTERN = {0, 1, 20, 21};
     
+    // Vibrator pattern for haptic feedback of virtual key press.
+    private static final long[] VIRTUAL_KEY_VIBE_PATTERN = {0, 1, 20, 21};
+    
     final Object mLock = new Object();
     
     Context mContext;
@@ -373,7 +376,7 @@
         }
     }
 
-    Runnable mEndCallLongPress = new Runnable() {
+    Runnable mPowerLongPress = new Runnable() {
         public void run() {
             mShouldTurnOffOnKeyUp = false;
             performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
@@ -775,7 +778,7 @@
 
     /** {@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 +803,36 @@
                 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();
-                        } else {
-                            Log.w(TAG, "Unable to find ITelephony interface");
+                    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);
                         }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
-                    }
-    
-                    if (incomingRinging) {
-                        Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
+        
+                        if (incomingRinging) {
+                            Log.i(TAG, "Ignoring HOME; there's a ringing incoming call.");
+                        } else {
+                            launchHomeFromHotKey();
+                        }
                     } 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
@@ -1365,17 +1372,12 @@
      * @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");
+        final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
+        if (am == null) {
+            Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
             return false;
         }
-        try {
-            return audio.isMusicActive();
-        } catch (RemoteException e) {
-            Log.w(TAG, "IAudioService.isMusicActive() threw RemoteException " + e);
-            return false;
-        }
+        return am.isMusicActive();
     }
 
     /**
@@ -1475,33 +1477,36 @@
         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;
                     // 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 !!!");
+                    if (code == KeyEvent.KEYCODE_ENDCALL) {
+                        try {
+                            ITelephony phoneServ = getPhoneInterface();
+                            if (phoneServ != null) {
+                                hungUp = phoneServ.endCall();
+                            } else {
+                                Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex);
                         }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "ITelephony.endCall() threw RemoteException" + ex);
                     }
                     if (hungUp || !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;
@@ -1859,6 +1864,13 @@
         return false;
     }
     
+    public void keyFeedbackFromInput(KeyEvent event) {
+        if (event.getAction() == KeyEvent.ACTION_DOWN
+                && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) {
+            mVibrator.vibrate(VIRTUAL_KEY_VIBE_PATTERN, -1);
+        }
+    }
+    
     public void screenOnStoppedLw() {
         if (!mKeyguardMediator.isShowing()) {
             long curTime = SystemClock.uptimeMillis();