Merge "Clarify some Binder docs regarding things that are thread-local."
diff --git a/api/current.xml b/api/current.xml
index d282e06..03d8a3a 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -205705,6 +205705,331 @@
 </parameter>
 </method>
 </interface>
+<class name="OverScroller"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="OverScroller"
+ type="android.widget.OverScroller"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<constructor name="OverScroller"
+ type="android.widget.OverScroller"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="interpolator" type="android.view.animation.Interpolator">
+</parameter>
+</constructor>
+<constructor name="OverScroller"
+ type="android.widget.OverScroller"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="interpolator" type="android.view.animation.Interpolator">
+</parameter>
+<parameter name="bounceCoefficientX" type="float">
+</parameter>
+<parameter name="bounceCoefficientY" type="float">
+</parameter>
+</constructor>
+<method name="abortAnimation"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="computeScrollOffset"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="fling"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startX" type="int">
+</parameter>
+<parameter name="startY" type="int">
+</parameter>
+<parameter name="velocityX" type="int">
+</parameter>
+<parameter name="velocityY" type="int">
+</parameter>
+<parameter name="minX" type="int">
+</parameter>
+<parameter name="maxX" type="int">
+</parameter>
+<parameter name="minY" type="int">
+</parameter>
+<parameter name="maxY" type="int">
+</parameter>
+</method>
+<method name="fling"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startX" type="int">
+</parameter>
+<parameter name="startY" type="int">
+</parameter>
+<parameter name="velocityX" type="int">
+</parameter>
+<parameter name="velocityY" type="int">
+</parameter>
+<parameter name="minX" type="int">
+</parameter>
+<parameter name="maxX" type="int">
+</parameter>
+<parameter name="minY" type="int">
+</parameter>
+<parameter name="maxY" type="int">
+</parameter>
+<parameter name="overX" type="int">
+</parameter>
+<parameter name="overY" type="int">
+</parameter>
+</method>
+<method name="forceFinished"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="finished" type="boolean">
+</parameter>
+</method>
+<method name="getCurrX"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getCurrY"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFinalX"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFinalY"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStartX"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStartY"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isFinished"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isOverscrolled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="notifyHorizontalEdgeReached"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startX" type="int">
+</parameter>
+<parameter name="finalX" type="int">
+</parameter>
+<parameter name="overX" type="int">
+</parameter>
+</method>
+<method name="notifyVerticalEdgeReached"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startY" type="int">
+</parameter>
+<parameter name="finalY" type="int">
+</parameter>
+<parameter name="overY" type="int">
+</parameter>
+</method>
+<method name="springback"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startX" type="int">
+</parameter>
+<parameter name="startY" type="int">
+</parameter>
+<parameter name="minX" type="int">
+</parameter>
+<parameter name="maxX" type="int">
+</parameter>
+<parameter name="minY" type="int">
+</parameter>
+<parameter name="maxY" type="int">
+</parameter>
+</method>
+<method name="startScroll"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startX" type="int">
+</parameter>
+<parameter name="startY" type="int">
+</parameter>
+<parameter name="dx" type="int">
+</parameter>
+<parameter name="dy" type="int">
+</parameter>
+</method>
+<method name="startScroll"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startX" type="int">
+</parameter>
+<parameter name="startY" type="int">
+</parameter>
+<parameter name="dx" type="int">
+</parameter>
+<parameter name="dy" type="int">
+</parameter>
+<parameter name="duration" type="int">
+</parameter>
+</method>
+</class>
 <class name="PopupWindow"
  extends="java.lang.Object"
  abstract="false"
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 8356029..15c8856 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -227,11 +227,13 @@
      * @hide for internal use only
      */
     public static Bundle sanitizeResult(Bundle result) {
-        if (result.containsKey(KEY_AUTHTOKEN)
-                && !TextUtils.isEmpty(result.getString(KEY_AUTHTOKEN))) {
-            final Bundle newResult = new Bundle(result);
-            newResult.putString(KEY_AUTHTOKEN, "<omitted for logging purposes>");
-            return newResult;
+        if (result != null) {
+            if (result.containsKey(KEY_AUTHTOKEN)
+                    && !TextUtils.isEmpty(result.getString(KEY_AUTHTOKEN))) {
+                final Bundle newResult = new Bundle(result);
+                newResult.putString(KEY_AUTHTOKEN, "<omitted for logging purposes>");
+                return newResult;
+            }
         }
         return result;
     }
@@ -251,6 +253,7 @@
      * @return An {@link AccountManager} instance
      */
     public static AccountManager get(Context context) {
+        if (context == null) throw new IllegalArgumentException("context is null");
         return (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
     }
 
@@ -269,6 +272,7 @@
      * @return The account's password, null if none or if the account doesn't exist
      */
     public String getPassword(final Account account) {
+        if (account == null) throw new IllegalArgumentException("account is null");
         try {
             return mService.getPassword(account);
         } catch (RemoteException e) {
@@ -293,6 +297,8 @@
      * @return The user data, null if the account or key doesn't exist
      */
     public String getUserData(final Account account, final String key) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (key == null) throw new IllegalArgumentException("key is null");
         try {
             return mService.getUserData(account, key);
         } catch (RemoteException e) {
@@ -393,6 +399,8 @@
     public AccountManagerFuture<Boolean> hasFeatures(final Account account,
             final String[] features,
             AccountManagerCallback<Boolean> callback, Handler handler) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (features == null) throw new IllegalArgumentException("features is null");
         return new Future2Task<Boolean>(handler, callback) {
             public void doWork() throws RemoteException {
                 mService.hasFeatures(mResponse, account, features);
@@ -436,13 +444,9 @@
     public AccountManagerFuture<Account[]> getAccountsByTypeAndFeatures(
             final String type, final String[] features,
             AccountManagerCallback<Account[]> callback, Handler handler) {
+        if (type == null) throw new IllegalArgumentException("type is null");
         return new Future2Task<Account[]>(handler, callback) {
             public void doWork() throws RemoteException {
-                if (type == null) {
-                    Log.e(TAG, "Type is null");
-                    set(new Account[0]);
-                    return;
-                }
                 mService.getAccountsByFeatures(mResponse, type, features);
             }
             public Account[] bundleToResult(Bundle bundle) throws AuthenticatorException {
@@ -476,6 +480,7 @@
      *     already exists, the account is null, or another error occurs.
      */
     public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
+        if (account == null) throw new IllegalArgumentException("account is null");
         try {
             return mService.addAccount(account, password, userdata);
         } catch (RemoteException e) {
@@ -507,6 +512,7 @@
      */
     public AccountManagerFuture<Boolean> removeAccount(final Account account,
             AccountManagerCallback<Boolean> callback, Handler handler) {
+        if (account == null) throw new IllegalArgumentException("account is null");
         return new Future2Task<Boolean>(handler, callback) {
             public void doWork() throws RemoteException {
                 mService.removeAccount(mResponse, account);
@@ -537,6 +543,8 @@
      * @param authToken The auth token to invalidate
      */
     public void invalidateAuthToken(final String accountType, final String authToken) {
+        if (accountType == null) throw new IllegalArgumentException("accountType is null");
+        if (authToken == null) throw new IllegalArgumentException("authToken is null");
         try {
             mService.invalidateAuthToken(accountType, authToken);
         } catch (RemoteException e) {
@@ -563,13 +571,8 @@
      *     no auth token is cached or the account does not exist.
      */
     public String peekAuthToken(final Account account, final String authTokenType) {
-        if (account == null) {
-            Log.e(TAG, "peekAuthToken: the account must not be null");
-            return null;
-        }
-        if (authTokenType == null) {
-            return null;
-        }
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         try {
             return mService.peekAuthToken(account, authTokenType);
         } catch (RemoteException e) {
@@ -594,10 +597,7 @@
      * @param password The password to set, null to clear the password
      */
     public void setPassword(final Account account, final String password) {
-        if (account == null) {
-            Log.e(TAG, "the account must not be null");
-            return;
-        }
+        if (account == null) throw new IllegalArgumentException("account is null");
         try {
             mService.setPassword(account, password);
         } catch (RemoteException e) {
@@ -621,10 +621,7 @@
      * @param account The account whose password to clear
      */
     public void clearPassword(final Account account) {
-        if (account == null) {
-            Log.e(TAG, "the account must not be null");
-            return;
-        }
+        if (account == null) throw new IllegalArgumentException("account is null");
         try {
             mService.clearPassword(account);
         } catch (RemoteException e) {
@@ -649,14 +646,8 @@
      * @param value The value to set, null to clear this userdata key
      */
     public void setUserData(final Account account, final String key, final String value) {
-        if (account == null) {
-            Log.e(TAG, "the account must not be null");
-            return;
-        }
-        if (key == null) {
-            Log.e(TAG, "the key must not be null");
-            return;
-        }
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (key == null) throw new IllegalArgumentException("key is null");
         try {
             mService.setUserData(account, key, value);
         } catch (RemoteException e) {
@@ -682,6 +673,8 @@
      * @param authToken The auth token to add to the cache
      */
     public void setAuthToken(Account account, final String authTokenType, final String authToken) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         try {
             mService.setAuthToken(account, authTokenType, authToken);
         } catch (RemoteException e) {
@@ -716,6 +709,8 @@
     public String blockingGetAuthToken(Account account, String authTokenType,
             boolean notifyAuthFailure)
             throws OperationCanceledException, IOException, AuthenticatorException {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         Bundle bundle = getAuthToken(account, authTokenType, notifyAuthFailure, null /* callback */,
                 null /* handler */).getResult();
         if (bundle == null) {
@@ -786,7 +781,7 @@
     public AccountManagerFuture<Bundle> getAuthToken(
             final Account account, final String authTokenType, final Bundle options,
             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
-        if (activity == null) throw new IllegalArgumentException("activity is null");
+        if (account == null) throw new IllegalArgumentException("account is null");
         if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
@@ -930,14 +925,9 @@
             final String authTokenType, final String[] requiredFeatures,
             final Bundle addAccountOptions,
             final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
+        if (accountType == null) throw new IllegalArgumentException("accountType is null");
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
-                if (accountType == null) {
-                    Log.e(TAG, "the account must not be null");
-                    // to unblock caller waiting on Future.get()
-                    set(new Bundle());
-                    return;
-                }
                 mService.addAcount(mResponse, accountType, authTokenType,
                         requiredFeatures, activity != null, addAccountOptions);
             }
@@ -1004,6 +994,7 @@
             final Activity activity,
             final AccountManagerCallback<Bundle> callback,
             final Handler handler) {
+        if (account == null) throw new IllegalArgumentException("account is null");
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
                 mService.confirmCredentials(mResponse, account, options, activity != null);
@@ -1064,6 +1055,7 @@
             final Bundle options, final Activity activity,
             final AccountManagerCallback<Bundle> callback,
             final Handler handler) {
+        if (account == null) throw new IllegalArgumentException("account is null");
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
                 mService.updateCredentials(mResponse, account, authTokenType, activity != null,
@@ -1112,6 +1104,7 @@
     public AccountManagerFuture<Bundle> editProperties(final String accountType,
             final Activity activity, final AccountManagerCallback<Bundle> callback,
             final Handler handler) {
+        if (accountType == null) throw new IllegalArgumentException("accountType is null");
         return new AmsTask(activity, handler, callback) {
             public void doWork() throws RemoteException {
                 mService.editProperties(mResponse, accountType, activity != null);
@@ -1734,10 +1727,7 @@
      * @throws IllegalStateException if listener was not already added
      */
     public void removeOnAccountsUpdatedListener(OnAccountsUpdateListener listener) {
-        if (listener == null) {
-            Log.e(TAG, "Missing listener");
-            return;
-        }
+        if (listener == null) throw new IllegalArgumentException("listener is null");
         synchronized (mAccountsUpdatedListeners) {
             if (!mAccountsUpdatedListeners.containsKey(listener)) {
                 Log.e(TAG, "Listener was not previously added");
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 16b603c..1d9e0f1 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -282,6 +282,7 @@
     }
 
     public String getPassword(Account account) {
+        if (account == null) throw new IllegalArgumentException("account is null");
         checkAuthenticateAccountsPermission(account);
 
         long identityToken = clearCallingIdentity();
@@ -312,6 +313,8 @@
     }
 
     public String getUserData(Account account, String key) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (key == null) throw new IllegalArgumentException("key is null");
         checkAuthenticateAccountsPermission(account);
         long identityToken = clearCallingIdentity();
         try {
@@ -382,6 +385,7 @@
     }
 
     public boolean addAccount(Account account, String password, Bundle extras) {
+        if (account == null) throw new IllegalArgumentException("account is null");
         checkAuthenticateAccountsPermission(account);
 
         // fails if the account already exists
@@ -451,6 +455,9 @@
 
     public void hasFeatures(IAccountManagerResponse response,
             Account account, String[] features) {
+        if (response == null) throw new IllegalArgumentException("response is null");
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (features == null) throw new IllegalArgumentException("features is null");
         checkReadAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
@@ -509,6 +516,8 @@
     }
 
     public void removeAccount(IAccountManagerResponse response, Account account) {
+        if (response == null) throw new IllegalArgumentException("response is null");
+        if (account == null) throw new IllegalArgumentException("account is null");
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
@@ -565,6 +574,8 @@
     }
 
     public void invalidateAuthToken(String accountType, String authToken) {
+        if (accountType == null) throw new IllegalArgumentException("accountType is null");
+        if (authToken == null) throw new IllegalArgumentException("authToken is null");
         checkManageAccountsOrUseCredentialsPermissions();
         long identityToken = clearCallingIdentity();
         try {
@@ -658,6 +669,8 @@
     }
 
     public String peekAuthToken(Account account, String authTokenType) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         checkAuthenticateAccountsPermission(account);
         long identityToken = clearCallingIdentity();
         try {
@@ -668,6 +681,8 @@
     }
 
     public void setAuthToken(Account account, String authTokenType, String authToken) {
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         checkAuthenticateAccountsPermission(account);
         long identityToken = clearCallingIdentity();
         try {
@@ -678,6 +693,7 @@
     }
 
     public void setPassword(Account account, String password) {
+        if (account == null) throw new IllegalArgumentException("account is null");
         checkAuthenticateAccountsPermission(account);
         long identityToken = clearCallingIdentity();
         try {
@@ -714,6 +730,7 @@
     }
 
     public void clearPassword(Account account) {
+        if (account == null) throw new IllegalArgumentException("account is null");
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
@@ -724,6 +741,8 @@
     }
 
     public void setUserData(Account account, String key, String value) {
+        if (key == null) throw new IllegalArgumentException("key is null");
+        if (account == null) throw new IllegalArgumentException("account is null");
         checkAuthenticateAccountsPermission(account);
         long identityToken = clearCallingIdentity();
         if (account == null) {
@@ -786,6 +805,9 @@
     public void getAuthToken(IAccountManagerResponse response, final Account account,
             final String authTokenType, final boolean notifyOnAuthFailure,
             final boolean expectActivityLaunch, final Bundle loginOptions) {
+        if (response == null) throw new IllegalArgumentException("response is null");
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
         final int callerUid = Binder.getCallingUid();
         final boolean permissionGranted = permissionIsGranted(account, authTokenType, callerUid);
@@ -955,6 +977,8 @@
     public void addAcount(final IAccountManagerResponse response, final String accountType,
             final String authTokenType, final String[] requiredFeatures,
             final boolean expectActivityLaunch, final Bundle options) {
+        if (response == null) throw new IllegalArgumentException("response is null");
+        if (accountType == null) throw new IllegalArgumentException("accountType is null");
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
@@ -981,6 +1005,8 @@
 
     public void confirmCredentials(IAccountManagerResponse response,
             final Account account, final Bundle options, final boolean expectActivityLaunch) {
+        if (response == null) throw new IllegalArgumentException("response is null");
+        if (account == null) throw new IllegalArgumentException("account is null");
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
@@ -1002,6 +1028,9 @@
     public void updateCredentials(IAccountManagerResponse response, final Account account,
             final String authTokenType, final boolean expectActivityLaunch,
             final Bundle loginOptions) {
+        if (response == null) throw new IllegalArgumentException("response is null");
+        if (account == null) throw new IllegalArgumentException("account is null");
+        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
@@ -1025,6 +1054,8 @@
 
     public void editProperties(IAccountManagerResponse response, final String accountType,
             final boolean expectActivityLaunch) {
+        if (response == null) throw new IllegalArgumentException("response is null");
+        if (accountType == null) throw new IllegalArgumentException("accountType is null");
         checkManageAccountsPermission();
         long identityToken = clearCallingIdentity();
         try {
@@ -1142,6 +1173,8 @@
 
     public void getAccountsByFeatures(IAccountManagerResponse response,
             String type, String[] features) {
+        if (response == null) throw new IllegalArgumentException("response is null");
+        if (type == null) throw new IllegalArgumentException("accountType is null");
         checkReadAccountsPermission();
         if (features != null && type == null) {
             if (response != null) {
@@ -1878,7 +1911,8 @@
      * @hide
      */
     public void grantAppPermission(Account account, String authTokenType, int uid) {
-        if (account == null  || authTokenType == null) {
+        if (account == null || authTokenType == null) {
+            Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
             return;
         }
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
@@ -1908,7 +1942,8 @@
      * @hide
      */
     public void revokeAppPermission(Account account, String authTokenType, int uid) {
-        if (account == null  || authTokenType == null) {
+        if (account == null || authTokenType == null) {
+            Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
             return;
         }
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
diff --git a/core/java/android/accounts/GrantCredentialsPermissionActivity.java b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
index f4b7258..fd340cbe 100644
--- a/core/java/android/accounts/GrantCredentialsPermissionActivity.java
+++ b/core/java/android/accounts/GrantCredentialsPermissionActivity.java
@@ -57,6 +57,14 @@
         final Bundle extras = getIntent().getExtras();
         mAccount = extras.getParcelable(EXTRAS_ACCOUNT);
         mAuthTokenType = extras.getString(EXTRAS_AUTH_TOKEN_TYPE);
+
+        if (mAccount == null || mAuthTokenType == null) {
+            // we were somehow started with bad parameters. abort the activity.
+            setResult(Activity.RESULT_CANCELED);
+            finish();
+            return;
+        }
+
         mUid = extras.getInt(EXTRAS_REQUESTING_UID);
         final String accountTypeLabel = extras.getString(EXTRAS_ACCOUNT_TYPE_LABEL);
         final String[] packages = extras.getStringArray(EXTRAS_PACKAGES);
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 1254782..e970e7e 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -78,8 +78,9 @@
 
     /**
      * Start tethering services with the specified dhcp server range
+     * arg is a set of start end pairs defining the ranges.
      */
-    void startTethering(String dhcpRangeStart, String dhcpRangeEnd);
+    void startTethering(in String[] dhcpRanges);
 
     /**
      * Stop currently running tethering services
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6e37f69..b8e5747 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2508,11 +2508,13 @@
         public static final String WIFI_ON = "wifi_on";
 
         /**
-         * Whether the Wi-Fi AP should be on.
+         * Used to save the Wifi_ON state prior to tethering.
+         * This state will be checked to restore Wifi after
+         * the user turns off tethering.
          *
          * @hide
          */
-        public static final String WIFI_AP_ON = "wifi_ap_on";
+        public static final String WIFI_SAVED_STATE = "wifi_saved_state";
 
         /**
          * AP SSID
diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java
index 3ed9851..034c88a 100644
--- a/core/java/android/webkit/MimeTypeMap.java
+++ b/core/java/android/webkit/MimeTypeMap.java
@@ -484,6 +484,7 @@
             sMimeTypeMap.loadEntry("text/x-tex", "cls");
             sMimeTypeMap.loadEntry("text/x-vcalendar", "vcs");
             sMimeTypeMap.loadEntry("text/x-vcard", "vcf");
+            sMimeTypeMap.loadEntry("video/3gpp", "3gpp");
             sMimeTypeMap.loadEntry("video/3gpp", "3gp");
             sMimeTypeMap.loadEntry("video/3gpp", "3g2");
             sMimeTypeMap.loadEntry("video/dl", "dl");
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 9150b5e..bd6105f 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2597,6 +2597,8 @@
                 mTouchMode = TOUCH_MODE_OVERFLING;
                 invalidate();
                 post(this);
+            } else {
+                mTouchMode = TOUCH_MODE_REST;
             }
         }
 
@@ -2610,14 +2612,7 @@
         }
 
         void edgeReached() {
-            mScroller.notifyVerticalEdgeReached(mScrollY, 0, Integer.MAX_VALUE);
-            mTouchMode = TOUCH_MODE_OVERFLING;
-            invalidate();
-            post(this);
-        }
-
-        void marginReached() {
-            mScroller.notifyVerticalBoundaryReached(mScrollY, 0);
+            mScroller.notifyVerticalEdgeReached(mScrollY, 0, getOverscrollMax());
             mTouchMode = TOUCH_MODE_OVERFLING;
             invalidate();
             post(this);
diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java
index 06da5fa..3bd4767 100644
--- a/core/java/android/widget/HorizontalScrollView.java
+++ b/core/java/android/widget/HorizontalScrollView.java
@@ -599,6 +599,7 @@
         } else {
             super.scrollTo(scrollX, scrollY);
         }
+        awakenScrollBars();
     }
     
     private int getOverscrollMax() {
@@ -961,7 +962,6 @@
             dx = Math.max(0, Math.min(scrollX + dx, maxX)) - scrollX;
 
             mScroller.startScroll(scrollX, mScrollY, dx, 0);
-            awakenScrollBars(mScroller.getDuration());
             invalidate();
         } else {
             if (!mScroller.isFinished()) {
@@ -1319,7 +1319,6 @@
                 mScrollViewMovedFocus = false;
             }
     
-            awakenScrollBars(mScroller.getDuration());
             invalidate();
         }
     }
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 48e7493..e8d92de 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -17,21 +17,27 @@
 package android.widget;
 
 import android.content.Context;
+import android.util.FloatMath;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
+import android.widget.Scroller.MagneticScroller;
 
 /**
  * This class encapsulates scrolling with the ability to overshoot the bounds
- * of a scrolling operation. This class attempts to be a drop-in replacement
- * for {@link android.widget.Scroller} in most cases.
- * 
- * @hide Pending API approval
+ * of a scrolling operation. This class is a drop-in replacement for
+ * {@link android.widget.Scroller} in most cases.
  */
-public class OverScroller extends Scroller {
+public class OverScroller {
+    private int mMode;
 
-    // Identical to mScrollers, but casted to MagneticOverScroller. 
-    private MagneticOverScroller mOverScrollerX;
-    private MagneticOverScroller mOverScrollerY;
+    private MagneticOverScroller mScrollerX;
+    private MagneticOverScroller mScrollerY;
+
+    private final Interpolator mInterpolator;
+
+    private static final int DEFAULT_DURATION = 250;
+    private static final int SCROLL_MODE = 0;
+    private static final int FLING_MODE = 1;
 
     /**
      * Creates an OverScroller with a viscous fluid scroll interpolator.
@@ -64,15 +70,259 @@
      */
     public OverScroller(Context context, Interpolator interpolator,
             float bounceCoefficientX, float bounceCoefficientY) {
-        super(context, interpolator);
-        mOverScrollerX.setBounceCoefficient(bounceCoefficientX);
-        mOverScrollerY.setBounceCoefficient(bounceCoefficientY);
+        mInterpolator = interpolator;
+        mScrollerX = new MagneticOverScroller();
+        mScrollerY = new MagneticOverScroller();
+        MagneticScroller.initializeFromContext(context);
+
+        mScrollerX.setBounceCoefficient(bounceCoefficientX);
+        mScrollerY.setBounceCoefficient(bounceCoefficientY);
     }
 
-    @Override
-    void instantiateScrollers() {
-        mScrollerX = mOverScrollerX = new MagneticOverScroller();
-        mScrollerY = mOverScrollerY = new MagneticOverScroller();
+    /**
+     *
+     * Returns whether the scroller has finished scrolling.
+     *
+     * @return True if the scroller has finished scrolling, false otherwise.
+     */
+    public final boolean isFinished() {
+        return mScrollerX.mFinished && mScrollerY.mFinished;
+    }
+
+    /**
+     * Force the finished field to a particular value. Contrary to
+     * {@link #abortAnimation()}, forcing the animation to finished
+     * does NOT cause the scroller to move to the final x and y
+     * position.
+     *
+     * @param finished The new finished value.
+     */
+    public final void forceFinished(boolean finished) {
+        mScrollerX.mFinished = mScrollerY.mFinished = finished;
+    }
+
+    /**
+     * Returns the current X offset in the scroll.
+     *
+     * @return The new X offset as an absolute distance from the origin.
+     */
+    public final int getCurrX() {
+        return mScrollerX.mCurrentPosition;
+    }
+
+    /**
+     * Returns the current Y offset in the scroll.
+     *
+     * @return The new Y offset as an absolute distance from the origin.
+     */
+    public final int getCurrY() {
+        return mScrollerY.mCurrentPosition;
+    }
+
+    /**
+     * @hide
+     * Returns the current velocity.
+     *
+     * @return The original velocity less the deceleration, norm of the X and Y velocity vector.
+     */
+    public float getCurrVelocity() {
+        float squaredNorm = mScrollerX.mCurrVelocity * mScrollerX.mCurrVelocity;
+        squaredNorm += mScrollerY.mCurrVelocity * mScrollerY.mCurrVelocity;
+        return FloatMath.sqrt(squaredNorm);
+    }
+
+    /**
+     * Returns the start X offset in the scroll.
+     *
+     * @return The start X offset as an absolute distance from the origin.
+     */
+    public final int getStartX() {
+        return mScrollerX.mStart;
+    }
+
+    /**
+     * Returns the start Y offset in the scroll.
+     *
+     * @return The start Y offset as an absolute distance from the origin.
+     */
+    public final int getStartY() {
+        return mScrollerY.mStart;
+    }
+
+    /**
+     * Returns where the scroll will end. Valid only for "fling" scrolls.
+     *
+     * @return The final X offset as an absolute distance from the origin.
+     */
+    public final int getFinalX() {
+        return mScrollerX.mFinal;
+    }
+
+    /**
+     * Returns where the scroll will end. Valid only for "fling" scrolls.
+     *
+     * @return The final Y offset as an absolute distance from the origin.
+     */
+    public final int getFinalY() {
+        return mScrollerY.mFinal;
+    }
+
+    /**
+     * Returns how long the scroll event will take, in milliseconds.
+     *
+     * @return The duration of the scroll in milliseconds.
+     *
+     * @hide Pending removal once nothing depends on it
+     * @deprecated OverScrollers don't necessarily have a fixed duration.
+     *             This function will lie to the best of its ability.
+     */
+    public final int getDuration() {
+        return Math.max(mScrollerX.mDuration, mScrollerY.mDuration);
+    }
+
+    /**
+     * Extend the scroll animation. This allows a running animation to scroll
+     * further and longer, when used with {@link #setFinalX(int)} or {@link #setFinalY(int)}.
+     *
+     * @param extend Additional time to scroll in milliseconds.
+     * @see #setFinalX(int)
+     * @see #setFinalY(int)
+     *
+     * @hide Pending removal once nothing depends on it
+     * @deprecated OverScrollers don't necessarily have a fixed duration.
+     *             Instead of setting a new final position and extending
+     *             the duration of an existing scroll, use startScroll
+     *             to begin a new animation.
+     */
+    public void extendDuration(int extend) {
+        mScrollerX.extendDuration(extend);
+        mScrollerY.extendDuration(extend);
+    }
+
+    /**
+     * Sets the final position (X) for this scroller.
+     *
+     * @param newX The new X offset as an absolute distance from the origin.
+     * @see #extendDuration(int)
+     * @see #setFinalY(int)
+     *
+     * @hide Pending removal once nothing depends on it
+     * @deprecated OverScroller's final position may change during an animation.
+     *             Instead of setting a new final position and extending
+     *             the duration of an existing scroll, use startScroll
+     *             to begin a new animation.
+     */
+    public void setFinalX(int newX) {
+        mScrollerX.setFinalPosition(newX);
+    }
+
+    /**
+     * Sets the final position (Y) for this scroller.
+     *
+     * @param newY The new Y offset as an absolute distance from the origin.
+     * @see #extendDuration(int)
+     * @see #setFinalX(int)
+     *
+     * @hide Pending removal once nothing depends on it
+     * @deprecated OverScroller's final position may change during an animation.
+     *             Instead of setting a new final position and extending
+     *             the duration of an existing scroll, use startScroll
+     *             to begin a new animation.
+     */
+    public void setFinalY(int newY) {
+        mScrollerY.setFinalPosition(newY);
+    }
+
+    /**
+     * Call this when you want to know the new location. If it returns true, the
+     * animation is not yet finished.
+     */
+    public boolean computeScrollOffset() {
+        if (isFinished()) {
+            return false;
+        }
+
+        switch (mMode) {
+            case SCROLL_MODE:
+                long time = AnimationUtils.currentAnimationTimeMillis();
+                // Any scroller can be used for time, since they were started
+                // together in scroll mode. We use X here.
+                final long elapsedTime = time - mScrollerX.mStartTime;
+
+                final int duration = mScrollerX.mDuration;
+                if (elapsedTime < duration) {
+                    float q = (float) (elapsedTime) / duration;
+
+                    if (mInterpolator == null)
+                        q = Scroller.viscousFluid(q);
+                    else
+                        q = mInterpolator.getInterpolation(q);
+
+                    mScrollerX.updateScroll(q);
+                    mScrollerY.updateScroll(q);
+                } else {
+                    abortAnimation();
+                }
+                break;
+
+            case FLING_MODE:
+                if (!mScrollerX.mFinished) {
+                    if (!mScrollerX.update()) {
+                        if (!mScrollerX.continueWhenFinished()) {
+                            mScrollerX.finish();
+                        }
+                    }
+                }
+
+                if (!mScrollerY.mFinished) {
+                    if (!mScrollerY.update()) {
+                        if (!mScrollerY.continueWhenFinished()) {
+                            mScrollerY.finish();
+                        }
+                    }
+                }
+
+                break;
+        }
+
+        return true;
+    }
+
+    /**
+     * Start scrolling by providing a starting point and the distance to travel.
+     * The scroll will use the default value of 250 milliseconds for the
+     * duration.
+     *
+     * @param startX Starting horizontal scroll offset in pixels. Positive
+     *        numbers will scroll the content to the left.
+     * @param startY Starting vertical scroll offset in pixels. Positive numbers
+     *        will scroll the content up.
+     * @param dx Horizontal distance to travel. Positive numbers will scroll the
+     *        content to the left.
+     * @param dy Vertical distance to travel. Positive numbers will scroll the
+     *        content up.
+     */
+    public void startScroll(int startX, int startY, int dx, int dy) {
+        startScroll(startX, startY, dx, dy, DEFAULT_DURATION);
+    }
+
+    /**
+     * Start scrolling by providing a starting point and the distance to travel.
+     *
+     * @param startX Starting horizontal scroll offset in pixels. Positive
+     *        numbers will scroll the content to the left.
+     * @param startY Starting vertical scroll offset in pixels. Positive numbers
+     *        will scroll the content up.
+     * @param dx Horizontal distance to travel. Positive numbers will scroll the
+     *        content to the left.
+     * @param dy Vertical distance to travel. Positive numbers will scroll the
+     *        content up.
+     * @param duration Duration of the scroll in milliseconds.
+     */
+    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
+        mMode = SCROLL_MODE;
+        mScrollerX.startScroll(startX, dx, duration);
+        mScrollerY.startScroll(startY, dy, duration);
     }
 
     /**
@@ -91,12 +341,11 @@
         mMode = FLING_MODE;
 
         // Make sure both methods are called.
-        final boolean spingbackX = mOverScrollerX.springback(startX, minX, maxX);
-        final boolean spingbackY = mOverScrollerY.springback(startY, minY, maxY);
+        final boolean spingbackX = mScrollerX.springback(startX, minX, maxX);
+        final boolean spingbackY = mScrollerY.springback(startY, minY, maxY);
         return spingbackX || spingbackY;
     }
 
-    @Override
     public void fling(int startX, int startY, int velocityX, int velocityY,
             int minX, int maxX, int minY, int maxY) {
         fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY, 0, 0);
@@ -105,7 +354,7 @@
     /**
      * Start scrolling based on a fling gesture. The distance traveled will
      * depend on the initial velocity of the fling.
-     * 
+     *
      * @param startX Starting point of the scroll (X)
      * @param startY Starting point of the scroll (Y)
      * @param velocityX Initial velocity of the fling (X) measured in pixels per
@@ -132,43 +381,87 @@
     public void fling(int startX, int startY, int velocityX, int velocityY,
             int minX, int maxX, int minY, int maxY, int overX, int overY) {
         mMode = FLING_MODE;
-        mOverScrollerX.fling(startX, velocityX, minX, maxX, overX);
-        mOverScrollerY.fling(startY, velocityY, minY, maxY, overY);
+        mScrollerX.fling(startX, velocityX, minX, maxX, overX);
+        mScrollerY.fling(startY, velocityY, minY, maxY, overY);
     }
 
-    void notifyHorizontalBoundaryReached(int startX, int finalX) {
-        mOverScrollerX.springback(startX, finalX, finalX);
+    /**
+     * Notify the scroller that we've reached a horizontal boundary.
+     * Normally the information to handle this will already be known
+     * when the animation is started, such as in a call to one of the
+     * fling functions. However there are cases where this cannot be known
+     * in advance. This function will transition the current motion and
+     * animate from startX to finalX as appropriate.
+     *
+     * @param startX Starting/current X position
+     * @param finalX Desired final X position
+     * @param overX Magnitude of overscroll allowed. This should be the maximum
+     *              desired distance from finalX. Absolute value - must be positive.
+     */
+    public void notifyHorizontalEdgeReached(int startX, int finalX, int overX) {
+        mScrollerX.notifyEdgeReached(startX, finalX, overX);
     }
 
-    void notifyVerticalBoundaryReached(int startY, int finalY) {
-        mOverScrollerY.springback(startY, finalY, finalY);
-    }
-
-    void notifyHorizontalEdgeReached(int startX, int finalX, int overX) {
-        mOverScrollerX.notifyEdgeReached(startX, finalX, overX);
-    }
-
-    void notifyVerticalEdgeReached(int startY, int finalY, int overY) {
-        mOverScrollerY.notifyEdgeReached(startY, finalY, overY);
+    /**
+     * Notify the scroller that we've reached a vertical boundary.
+     * Normally the information to handle this will already be known
+     * when the animation is started, such as in a call to one of the
+     * fling functions. However there are cases where this cannot be known
+     * in advance. This function will animate a parabolic motion from
+     * startY to finalY.
+     *
+     * @param startY Starting/current Y position
+     * @param finalY Desired final Y position
+     * @param overY Magnitude of overscroll allowed. This should be the maximum
+     *              desired distance from finalY.
+     */
+    public void notifyVerticalEdgeReached(int startY, int finalY, int overY) {
+        mScrollerY.notifyEdgeReached(startY, finalY, overY);
     }
 
     /**
      * Returns whether the current Scroller is currently returning to a valid position.
      * Valid bounds were provided by the
      * {@link #fling(int, int, int, int, int, int, int, int, int, int)} method.
-     * 
+     *
      * One should check this value before calling
-     * {@link startScroll(int, int, int, int)} as the interpolation currently in progress to restore
-     * a valid position will then be stopped. The caller has to take into account the fact that the
-     * started scroll will start from an overscrolled position.
+     * {@link #startScroll(int, int, int, int)} as the interpolation currently in progress
+     * to restore a valid position will then be stopped. The caller has to take into account
+     * the fact that the started scroll will start from an overscrolled position.
      * 
-     * @return true when the current position is overscrolled and interpolated back to a valid value.
+     * @return true when the current position is overscrolled and in the process of
+     *         interpolating back to a valid value.
      */
     public boolean isOverscrolled() {
-        return ((!mOverScrollerX.mFinished &&
-                mOverScrollerX.mState != MagneticOverScroller.TO_EDGE) ||
-                (!mOverScrollerY.mFinished &&
-                        mOverScrollerY.mState != MagneticOverScroller.TO_EDGE));
+        return ((!mScrollerX.mFinished &&
+                mScrollerX.mState != MagneticOverScroller.TO_EDGE) ||
+                (!mScrollerY.mFinished &&
+                        mScrollerY.mState != MagneticOverScroller.TO_EDGE));
+    }
+
+    /**
+     * Stops the animation. Contrary to {@link #forceFinished(boolean)},
+     * aborting the animating causes the scroller to move to the final x and y
+     * positions.
+     *
+     * @see #forceFinished(boolean)
+     */
+    public void abortAnimation() {
+        mScrollerX.finish();
+        mScrollerY.finish();
+    }
+
+    /**
+     * Returns the time elapsed since the beginning of the scrolling.
+     *
+     * @return The elapsed time in milliseconds.
+     * 
+     * @hide
+     */
+    public int timePassed() {
+        final long time = AnimationUtils.currentAnimationTimeMillis();
+        final long startTime = Math.min(mScrollerX.mStartTime, mScrollerY.mStartTime);
+        return (int) (time - startTime);
     }
 
     static class MagneticOverScroller extends Scroller.MagneticScroller {
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 36d244f..23e1234 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -963,7 +963,6 @@
             dy = Math.max(0, Math.min(scrollY + dy, maxY)) - scrollY;
 
             mScroller.startScroll(mScrollX, scrollY, 0, dy);
-            awakenScrollBars(mScroller.getDuration());
             invalidate();
         } else {
             if (!mScroller.isFinished()) {
diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java
index 6a2f000..abb3e32 100644
--- a/core/java/android/widget/Scroller.java
+++ b/core/java/android/widget/Scroller.java
@@ -32,16 +32,16 @@
  * computeScrollOffset() will always return false to indicate that scrolling is over.
  */
 public class Scroller  {
-    int mMode;
+    private int mMode;
 
-    MagneticScroller mScrollerX;
-    MagneticScroller mScrollerY;
+    private MagneticScroller mScrollerX;
+    private MagneticScroller mScrollerY;
 
     private final Interpolator mInterpolator;
 
-    static final int DEFAULT_DURATION = 250;
-    static final int SCROLL_MODE = 0;
-    static final int FLING_MODE = 1;
+    private static final int DEFAULT_DURATION = 250;
+    private static final int SCROLL_MODE = 0;
+    private static final int FLING_MODE = 1;
 
     // This controls the viscous fluid effect (how much of it)
     private final static float VISCOUS_FLUID_SCALE = 8.0f;
@@ -65,16 +65,12 @@
      * null, the default (viscous) interpolator will be used.
      */
     public Scroller(Context context, Interpolator interpolator) {
-        instantiateScrollers();
+        mScrollerX = new MagneticScroller();
+        mScrollerY = new MagneticScroller();
         MagneticScroller.initializeFromContext(context);
 
         mInterpolator = interpolator;
     }
-    
-    void instantiateScrollers() {
-        mScrollerX = new MagneticScroller();
-        mScrollerY = new MagneticScroller();        
-    }
 
     /**
      * 
@@ -289,7 +285,7 @@
         mScrollerY.fling(startY, velocityY, minY, maxY);
     }
 
-    private static float viscousFluid(float x) {
+    static float viscousFluid(float x) {
         x *= VISCOUS_FLUID_SCALE;
         if (x < 1.0f) {
             x -= (1.0f - (float)Math.exp(-x));
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 37cd412..dbbd286 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -47,7 +47,6 @@
 public class LockPatternUtils {
 
     private static final String TAG = "LockPatternUtils";
-    private static final boolean LDEBUG = false;
 
     private static final String LOCK_PATTERN_FILE = "/system/gesture.key";
     private static final String LOCK_PASSWORD_FILE = "/system/password.key";
@@ -81,17 +80,6 @@
     public static final int MIN_LOCK_PATTERN_SIZE = 4;
 
     /**
-     * Type of password being stored.
-     * pattern = pattern screen
-     * pin = digit-only password
-     * password = alphanumeric password
-     */
-    public static final int MODE_UNSPECIFIED = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-    public static final int MODE_PATTERN = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
-    public static final int MODE_PIN = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
-    public static final int MODE_PASSWORD = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
-
-    /**
      * The minimum number of dots the user must include in a wrong pattern
      * attempt for it to be counted against the counts that affect
      * {@link #FAILED_ATTEMPTS_BEFORE_TIMEOUT} and {@link #FAILED_ATTEMPTS_BEFORE_RESET}
@@ -110,7 +98,7 @@
     private static String sLockPatternFilename;
     private static String sLockPasswordFilename;
 
-    DevicePolicyManager getDevicePolicyManager() {
+    public DevicePolicyManager getDevicePolicyManager() {
         if (mDevicePolicyManager == null) {
             mDevicePolicyManager =
                 (DevicePolicyManager)mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
@@ -141,22 +129,13 @@
         return getDevicePolicyManager().getPasswordMinimumLength(null);
     }
 
+
     /**
      * Gets the device policy password mode. If the mode is non-specific, returns
      * MODE_PATTERN which allows the user to choose anything.
      */
-    public int getRequestedPasswordMode() {
-        int policyMode = getDevicePolicyManager().getPasswordQuality(null);
-        switch (policyMode) {
-            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
-            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
-                return MODE_PASSWORD;
-            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
-                return MODE_PIN;
-            case DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED:
-                return MODE_PATTERN;
-        }
-        return MODE_PATTERN;
+    public int getRequestedPasswordQuality() {
+        return getDevicePolicyManager().getPasswordQuality(null);
     }
 
     /**
@@ -232,7 +211,7 @@
         try {
             // Check if we can read a byte from the file
             RandomAccessFile raf = new RandomAccessFile(filename, "r");
-            byte first = raf.readByte();
+            raf.readByte();
             raf.close();
             return true;
         } catch (FileNotFoundException fnfe) {
@@ -273,41 +252,42 @@
      * information it has.
      */
     public int getActivePasswordQuality() {
-        switch (getPasswordMode()) {
-            case MODE_UNSPECIFIED:
-                return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
-            case MODE_PATTERN:
+        int activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+        switch (getKeyguardStoredPasswordQuality()) {
+            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
                 if (isLockPatternEnabled()) {
-                    return DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
-                } else {
-                    return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
                 }
-            case MODE_PIN:
+                break;
+            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
                 if (isLockPasswordEnabled()) {
-                    return DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
-                } else {
-                    return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
                 }
-            case MODE_PASSWORD:
+                break;
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
                 if (isLockPasswordEnabled()) {
-                    return DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
-                } else {
-                    return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
                 }
+                break;
+            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
+                if (isLockPasswordEnabled()) {
+                    activePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+                }
+                break;
         }
-        return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+        return activePasswordQuality;
     }
-    
+
     /**
      * Clear any lock pattern or password.
      */
     public void clearLock() {
         getDevicePolicyManager().setActivePasswordState(
                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0);
-        saveLockPassword(null, LockPatternUtils.MODE_PATTERN);
+        saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
         setLockPatternEnabled(false);
         saveLockPattern(null);
-        setLong(PASSWORD_TYPE_KEY, MODE_PATTERN);
+        setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
     }
 
     /**
@@ -330,7 +310,7 @@
             DevicePolicyManager dpm = getDevicePolicyManager();
             if (pattern != null) {
                 setBoolean(PATTERN_EVER_CHOSEN_KEY, true);
-                setLong(PASSWORD_TYPE_KEY, MODE_PATTERN);
+                setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
                 dpm.setActivePasswordState(
                         DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, pattern.size());
             } else {
@@ -374,12 +354,13 @@
     }
 
     /**
-     * Save a lock password.  Does not ensure that the pattern is as good
+     * Save a lock password.  Does not ensure that the password is as good
      * as the requested mode, but will adjust the mode to be as good as the
      * pattern.
      * @param password The password to save
+     * @param quality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
      */
-    public void saveLockPassword(String password, int mode) {
+    public void saveLockPassword(String password, int quality) {
         // Compute the hash
         final byte[] hash = passwordToHash(password);
         try {
@@ -394,10 +375,10 @@
             raf.close();
             DevicePolicyManager dpm = getDevicePolicyManager();
             if (password != null) {
-                setLong(PASSWORD_TYPE_KEY, mode);
-                int quality = computePasswordQuality(password);
-                if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
-                    dpm.setActivePasswordState(quality, password.length());
+                int computedQuality = computePasswordQuality(password);
+                setLong(PASSWORD_TYPE_KEY, computedQuality);
+                if (computedQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
+                    dpm.setActivePasswordState(computedQuality, password.length());
                 } else {
                     // The password is not anything.
                     dpm.setActivePasswordState(
@@ -416,8 +397,14 @@
         }
     }
 
-    public int getPasswordMode() {
-        return (int) getLong(PASSWORD_TYPE_KEY, MODE_PATTERN);
+    /**
+     * Retrieves the quality mode we're in.
+     * {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
+     *
+     * @return stored password quality
+     */
+    public int getKeyguardStoredPasswordQuality() {
+        return (int) getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
     }
 
     /**
@@ -536,7 +523,10 @@
      */
     public boolean isLockPasswordEnabled() {
         long mode = getLong(PASSWORD_TYPE_KEY, 0);
-        return savedPasswordExists() && (mode == MODE_PASSWORD || mode == MODE_PIN);
+        return savedPasswordExists() &&
+                (mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
+                        || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
+                        || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC);
     }
 
     /**
@@ -544,7 +534,8 @@
      */
     public boolean isLockPatternEnabled() {
         return getBoolean(Settings.Secure.LOCK_PATTERN_ENABLED)
-                && getLong(PASSWORD_TYPE_KEY, MODE_PATTERN) == MODE_PATTERN;
+                && getLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING)
+                        == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
     }
 
     /**
@@ -660,9 +651,13 @@
     }
 
     public boolean isSecure() {
-        long mode = getPasswordMode();
-        boolean secure = mode == MODE_PATTERN && isLockPatternEnabled() && savedPatternExists()
-            || (mode == MODE_PIN || mode == MODE_PASSWORD) && savedPasswordExists();
+        long mode = getKeyguardStoredPasswordQuality();
+        final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
+        final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
+                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
+                || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
+        final boolean secure = isPattern && isLockPatternEnabled() && savedPatternExists()
+                || isPassword && savedPasswordExists();
         return secure;
     }
 
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 901be58..d26cd28 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -23,7 +23,6 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <sys/stat.h>
-#include <sys/syscall.h>
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -36,6 +35,7 @@
 #include <binder/Parcel.h>
 #include <binder/ProcessState.h>
 #include <binder/IServiceManager.h>
+#include <utils/threads.h>
 
 #include <android_runtime/AndroidRuntime.h>
 
@@ -850,8 +850,8 @@
 // have gettid, so we just ignore this and don't log if we can't
 // get the thread id.
 static bool should_time_binder_calls() {
-#ifdef __NR_gettid
-  return (getpid() == syscall(__NR_gettid));
+#ifdef HAVE_GETTID
+  return (getpid() == androidGetTid());
 #else
 #warning no gettid(), so not logging Binder calls...
   return false;
diff --git a/core/res/res/color/primary_text_dark.xml b/core/res/res/color/primary_text_dark.xml
index 2ec46b9..39c9e22 100644
--- a/core/res/res/color/primary_text_dark.xml
+++ b/core/res/res/color/primary_text_dark.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false" android:color="@android:color/bright_foreground_dark_disabled"/>
-	<item android:state_window_focused="false" android:color="@android:color/bright_foreground_dark"/>
+    <item android:state_window_focused="false" android:color="@android:color/bright_foreground_dark"/>
     <item android:state_pressed="true" android:color="@android:color/bright_foreground_dark_inverse"/>
     <item android:state_selected="true" android:color="@android:color/bright_foreground_dark_inverse"/>
     <item android:color="@android:color/bright_foreground_dark"/> <!-- not selected -->
diff --git a/core/res/res/color/primary_text_light.xml b/core/res/res/color/primary_text_light.xml
index bd9ac8b..e112034 100644
--- a/core/res/res/color/primary_text_light.xml
+++ b/core/res/res/color/primary_text_light.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false" android:color="@android:color/bright_foreground_light_disabled"/>
-    <item android:state_window_focused="false" android:color="@android:color/bright_foreground_light"/>
+    <item android:state_window_focused="false" android:color="@android:color/bright_foreground_light"/>
     <item android:state_pressed="true" android:color="@android:color/bright_foreground_light"/>
     <item android:state_selected="true" android:color="@android:color/bright_foreground_light"/>
     <item android:color="@android:color/bright_foreground_light"/> <!-- not selected -->
diff --git a/core/res/res/color/secondary_text_dark.xml b/core/res/res/color/secondary_text_dark.xml
index 0d96221..c195ef0 100644
--- a/core/res/res/color/secondary_text_dark.xml
+++ b/core/res/res/color/secondary_text_dark.xml
@@ -15,7 +15,7 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_disabled"/>
+    <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_disabled"/>
     <item android:state_window_focused="false" android:color="@android:color/dim_foreground_dark"/>
     <item android:state_selected="true" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_inverse_disabled"/>
     <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_dark_inverse_disabled"/>
diff --git a/core/res/res/color/secondary_text_light.xml b/core/res/res/color/secondary_text_light.xml
index 0846b5e..99249a5 100644
--- a/core/res/res/color/secondary_text_light.xml
+++ b/core/res/res/color/secondary_text_light.xml
@@ -15,7 +15,7 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_light_disabled"/>
+    <item android:state_window_focused="false" android:state_enabled="false" android:color="@android:color/dim_foreground_light_disabled"/>
     <item android:state_window_focused="false" android:color="@android:color/dim_foreground_light"/>
     <!-- Since there is only one selector (for both light and dark), the light's selected state shouldn't be inversed like the dark's. -->
     <item android:state_pressed="true" android:state_enabled="false" android:color="@android:color/dim_foreground_light_disabled"/>
diff --git a/core/res/res/color/tertiary_text_dark.xml b/core/res/res/color/tertiary_text_dark.xml
index 7ce3580..66227bc 100644
--- a/core/res/res/color/tertiary_text_dark.xml
+++ b/core/res/res/color/tertiary_text_dark.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false" android:color="#808080"/>
-	<item android:state_window_focused="false" android:color="#808080"/>
+    <item android:state_window_focused="false" android:color="#808080"/>
     <item android:state_pressed="true" android:color="#808080"/>
     <item android:state_selected="true" android:color="@android:color/dim_foreground_light"/>
     <item android:color="#808080"/> <!-- not selected -->
diff --git a/core/res/res/color/tertiary_text_light.xml b/core/res/res/color/tertiary_text_light.xml
index 7e61fc89..ea65756 100644
--- a/core/res/res/color/tertiary_text_light.xml
+++ b/core/res/res/color/tertiary_text_light.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false" android:color="#808080"/>
-	<item android:state_window_focused="false" android:color="#808080"/>
+    <item android:state_window_focused="false" android:color="#808080"/>
     <item android:state_pressed="true" android:color="#808080"/>
     <item android:state_selected="true" android:color="#808080"/>
     <item android:color="#808080"/> <!-- not selected -->
diff --git a/core/res/res/drawable-hdpi/stat_sys_adb.png b/core/res/res/drawable-hdpi/stat_sys_adb.png
new file mode 100644
index 0000000..aef8650
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_adb.png b/core/res/res/drawable-mdpi/stat_sys_adb.png
new file mode 100644
index 0000000..12abeda
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable/btn_default.xml b/core/res/res/drawable/btn_default.xml
index b8ce2bf..4765084 100644
--- a/core/res/res/drawable/btn_default.xml
+++ b/core/res/res/drawable/btn_default.xml
@@ -15,9 +15,9 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="true"
+    <item android:state_window_focused="false" android:state_enabled="true"
         android:drawable="@drawable/btn_default_normal" />
-    <item android:state_window_focused="false" android:state_enabled="false"
+    <item android:state_window_focused="false" android:state_enabled="false"
         android:drawable="@drawable/btn_default_normal_disable" />
     <item android:state_pressed="true" 
         android:drawable="@drawable/btn_default_pressed" />
diff --git a/core/res/res/drawable/btn_default_small.xml b/core/res/res/drawable/btn_default_small.xml
index 247e9e2..5485ea0 100644
--- a/core/res/res/drawable/btn_default_small.xml
+++ b/core/res/res/drawable/btn_default_small.xml
@@ -15,9 +15,9 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="true"
+    <item android:state_window_focused="false" android:state_enabled="true"
         android:drawable="@drawable/btn_default_small_normal" />
-    <item android:state_window_focused="false" android:state_enabled="false"
+    <item android:state_window_focused="false" android:state_enabled="false"
         android:drawable="@drawable/btn_default_small_normal_disable" />
     <item android:state_pressed="true" 
         android:drawable="@drawable/btn_default_small_pressed" />
diff --git a/core/res/res/drawable/btn_dialog.xml b/core/res/res/drawable/btn_dialog.xml
index ed4c28a..d1d7e29 100644
--- a/core/res/res/drawable/btn_dialog.xml
+++ b/core/res/res/drawable/btn_dialog.xml
@@ -15,9 +15,9 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="true"
+    <item android:state_window_focused="false" android:state_enabled="true"
         android:drawable="@drawable/btn_dialog_normal" />
-    <item android:state_window_focused="false" android:state_enabled="false"
+    <item android:state_window_focused="false" android:state_enabled="false"
         android:drawable="@drawable/btn_dialog_disable" />
     <item android:state_pressed="true"
         android:drawable="@drawable/btn_dialog_pressed" />
diff --git a/core/res/res/drawable/btn_dropdown.xml b/core/res/res/drawable/btn_dropdown.xml
index 34a0504..d9905c6 100644
--- a/core/res/res/drawable/btn_dropdown.xml
+++ b/core/res/res/drawable/btn_dropdown.xml
@@ -18,7 +18,7 @@
     <item
         android:state_window_focused="false" android:state_enabled="true"
         android:drawable="@drawable/btn_dropdown_normal" />
-    <item
+    <item
         android:state_window_focused="false" android:state_enabled="false"
         android:drawable="@drawable/btn_dropdown_disabled" />
     <item
diff --git a/core/res/res/drawable/btn_global_search.xml b/core/res/res/drawable/btn_global_search.xml
index 531f07e..2807a01 100644
--- a/core/res/res/drawable/btn_global_search.xml
+++ b/core/res/res/drawable/btn_global_search.xml
@@ -16,9 +16,9 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <!-- TODO Need different assets for some of these button states. -->
-    <item android:state_window_focused="false" android:state_enabled="true"
+    <item android:state_window_focused="false" android:state_enabled="true"
         android:drawable="@drawable/btn_global_search_normal" />
-    <item android:state_window_focused="false" android:state_enabled="false"
+    <item android:state_window_focused="false" android:state_enabled="false"
         android:drawable="@drawable/btn_global_search_normal" />
     <item android:state_pressed="true" 
         android:drawable="@drawable/btn_default_pressed" />
diff --git a/core/res/res/drawable/btn_search_dialog.xml b/core/res/res/drawable/btn_search_dialog.xml
index b7f5187..082633e 100644
--- a/core/res/res/drawable/btn_search_dialog.xml
+++ b/core/res/res/drawable/btn_search_dialog.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     
-   <item android:state_window_focused="false" android:state_enabled="true"
+   <item android:state_window_focused="false" android:state_enabled="true"
         android:drawable="@drawable/btn_search_dialog_default" />
         
     <item android:state_pressed="true" 
diff --git a/core/res/res/drawable/btn_search_dialog_voice.xml b/core/res/res/drawable/btn_search_dialog_voice.xml
index 748aaf5..1a76efa 100644
--- a/core/res/res/drawable/btn_search_dialog_voice.xml
+++ b/core/res/res/drawable/btn_search_dialog_voice.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     
-   <item android:state_window_focused="false" android:state_enabled="true"
+   <item android:state_window_focused="false" android:state_enabled="true"
         android:drawable="@drawable/btn_search_dialog_voice_default" />
         
     <item android:state_pressed="true" 
diff --git a/core/res/res/drawable/edit_text.xml b/core/res/res/drawable/edit_text.xml
index 23a97e9..315278d 100644
--- a/core/res/res/drawable/edit_text.xml
+++ b/core/res/res/drawable/edit_text.xml
@@ -15,9 +15,9 @@
 -->
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_window_focused="false" android:state_enabled="true"
+    <item android:state_window_focused="false" android:state_enabled="true"
         android:drawable="@drawable/textfield_default" />
-    <item android:state_window_focused="false" android:state_enabled="false"
+    <item android:state_window_focused="false" android:state_enabled="false"
         android:drawable="@drawable/textfield_disabled" />
     <item android:state_pressed="true" android:drawable="@drawable/textfield_pressed" />
     <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_selected" />
diff --git a/core/res/res/drawable/textfield_search.xml b/core/res/res/drawable/textfield_search.xml
index 2923368..78c9486 100644
--- a/core/res/res/drawable/textfield_search.xml
+++ b/core/res/res/drawable/textfield_search.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     
-    <item android:state_window_focused="false" android:state_enabled="true"
+    <item android:state_window_focused="false" android:state_enabled="true"
         android:drawable="@drawable/textfield_search_default" />
         
     <item android:state_pressed="true"
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 91a2bc1..63d1446 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -778,8 +778,8 @@
                         com.android.internal.R.styleable.DrawableCorners_bottomLeftRadius, radius);
                 int bottomRightRadius = a.getDimensionPixelSize(
                         com.android.internal.R.styleable.DrawableCorners_bottomRightRadius, radius);
-                if (topLeftRadius != radius && topRightRadius != radius &&
-                        bottomLeftRadius != radius && bottomRightRadius != radius) {
+                if (topLeftRadius != radius || topRightRadius != radius ||
+                        bottomLeftRadius != radius || bottomRightRadius != radius) {
                     setCornerRadii(new float[] {
                             topLeftRadius, topLeftRadius,
                             topRightRadius, topRightRadius,
diff --git a/include/ui/GraphicBufferAllocator.h b/include/ui/GraphicBufferAllocator.h
index be9c79b..741d763 100644
--- a/include/ui/GraphicBufferAllocator.h
+++ b/include/ui/GraphicBufferAllocator.h
@@ -86,7 +86,6 @@
     GraphicBufferAllocator();
     ~GraphicBufferAllocator();
     
-    mutable Mutex mLock;
     alloc_device_t  *mAllocDev;
 };
 
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 57d5fc3..6ae7e74 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -78,8 +78,6 @@
 status_t GraphicBufferAllocator::alloc(uint32_t w, uint32_t h, PixelFormat format,
         int usage, buffer_handle_t* handle, int32_t* stride)
 {
-    Mutex::Autolock _l(mLock);
-
     // make sure to not allocate a 0 x 0 buffer
     w = clamp(w);
     h = clamp(h);
@@ -118,8 +116,6 @@
 
 status_t GraphicBufferAllocator::free(buffer_handle_t handle)
 {
-    Mutex::Autolock _l(mLock);
-
     status_t err;
     if (sw_gralloc_handle_t::validate(handle) < 0) {
         err = mAllocDev->free(mAllocDev, handle);
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 1b99e78..0f79b15 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -158,7 +158,7 @@
     private final static boolean LOG_THREADS = false;
     private final static boolean LOG_PAUSE_RESUME = true;
     private final static boolean LOG_SURFACE = true;
-    private final static boolean LOG_RENDERER = false;
+    private final static boolean LOG_RENDERER = true;
     private final static boolean LOG_RENDERER_DRAW_FRAME = false;
     private final static boolean LOG_EGL = true;
     // Work-around for bug 2263168
@@ -1161,6 +1161,15 @@
                                 break;
                             }
 
+                            // Update the pause state.
+                            if (mPaused != mRequestPaused) {
+                                mPaused = mRequestPaused;
+                                sGLThreadManager.notifyAll();
+                                if (LOG_PAUSE_RESUME) {
+                                    Log.i("GLThread", "mPaused is now " + mPaused + " tid=" + getId());
+                                }
+                            }
+
                             // Have we lost the EGL context?
                             if (lostEglContext) {
                                 stopEglSurfaceLocked();
@@ -1360,6 +1369,13 @@
                 }
                 mHasSurface = true;
                 sGLThreadManager.notifyAll();
+                while((mWaitingForSurface) && (!mExited)) {
+                    try {
+                        sGLThreadManager.wait();
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
             }
         }
 
@@ -1385,8 +1401,18 @@
                 if (LOG_PAUSE_RESUME) {
                     Log.i("GLThread", "onPause tid=" + getId());
                 }
-                mPaused = true;
+                mRequestPaused = true;
                 sGLThreadManager.notifyAll();
+                while ((! mExited) && (! mPaused)) {
+                    if (LOG_PAUSE_RESUME) {
+                        Log.i("Main thread", "onPause waiting for mPaused.");
+                    }
+                    try {
+                        sGLThreadManager.wait();
+                    } catch (InterruptedException ex) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
             }
         }
 
@@ -1395,9 +1421,20 @@
                 if (LOG_PAUSE_RESUME) {
                     Log.i("GLThread", "onResume tid=" + getId());
                 }
-                mPaused = false;
+                mRequestPaused = false;
                 mRequestRender = true;
+                mRenderComplete = false;
                 sGLThreadManager.notifyAll();
+                while ((! mExited) && mPaused && (!mRenderComplete)) {
+                    if (LOG_PAUSE_RESUME) {
+                        Log.i("Main thread", "onResume waiting for !mPaused.");
+                    }
+                    try {
+                        sGLThreadManager.wait();
+                    } catch (InterruptedException ex) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
             }
         }
 
@@ -1458,6 +1495,7 @@
         // variables are protected by the sGLThreadManager monitor
         private boolean mShouldExit;
         private boolean mExited;
+        private boolean mRequestPaused;
         private boolean mPaused;
         private boolean mHasSurface;
         private boolean mWaitingForSurface;
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
index 1224a96..27bb545 100644
--- a/opengl/libagl/state.cpp
+++ b/opengl/libagl/state.cpp
@@ -37,7 +37,7 @@
 // ----------------------------------------------------------------------------
 
 static char const * const gVendorString     = "Android";
-static char const * const gRendererString   = "Android PixelFlinger 1.2";
+static char const * const gRendererString   = "Android PixelFlinger 1.3";
 static char const * const gVersionString    = "OpenGL ES-CM 1.0";
 static char const * const gExtensionsString =
     "GL_OES_byte_coordinates "              // OK
diff --git a/services/java/com/android/server/DiskStatsService.java b/services/java/com/android/server/DiskStatsService.java
new file mode 100644
index 0000000..8ef974a
--- /dev/null
+++ b/services/java/com/android/server/DiskStatsService.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.StatFs;
+import android.os.SystemClock;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * This service exists only as a "dumpsys" target which reports
+ * statistics about the status of the disk.
+ */
+public class DiskStatsService extends Binder {
+    private final Context mContext;
+
+    public DiskStatsService(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        // This data is accessible to any app -- no permission check needed.
+
+        // Run a quick-and-dirty performance test: write 512 bytes
+        byte[] junk = new byte[512];
+        for (int i = 0; i < junk.length; i++) junk[i] = (byte) i;  // Write nonzero bytes
+
+        File tmp = new File(Environment.getDataDirectory(), "system/perftest.tmp");
+        FileOutputStream fos = null;
+        IOException error = null;
+
+        long before = SystemClock.uptimeMillis();
+        try {
+            fos = new FileOutputStream(tmp);
+            fos.write(junk);
+        } catch (IOException e) {
+            error = e;
+        } finally {
+            try { if (fos != null) fos.close(); } catch (IOException e) {}
+        }
+
+        long after = SystemClock.uptimeMillis();
+        if (tmp.exists()) tmp.delete();
+
+        if (error != null) {
+            pw.print("Test-Error: ");
+            pw.println(error.toString());
+        } else {
+            pw.print("Latency: ");
+            pw.print(after - before);
+            pw.println("ms [512B Data Write]");
+        }
+
+        reportFreeSpace(Environment.getDataDirectory(), "Data", pw);
+        reportFreeSpace(Environment.getDownloadCacheDirectory(), "Cache", pw);
+        reportFreeSpace(new File("/system"), "System", pw);
+
+        // TODO: Read /proc/yaffs and report interesting values;
+        // add configurable (through args) performance test parameters.
+    }
+
+    private void reportFreeSpace(File path, String name, PrintWriter pw) {
+        try {
+            StatFs statfs = new StatFs(path.getPath());
+            long bsize = statfs.getBlockSize();
+            long avail = statfs.getAvailableBlocks();
+            long total = statfs.getBlockCount();
+            if (bsize <= 0 || total <= 0) {
+                throw new IllegalArgumentException(
+                        "Invalid stat: bsize=" + bsize + " avail=" + avail + " total=" + total);
+            }
+
+            pw.print(name);
+            pw.print("-Free: ");
+            pw.print(avail * bsize / 1024);
+            pw.print("K / ");
+            pw.print(total * bsize / 1024);
+            pw.print("K total = ");
+            pw.print(avail * 100 / total);
+            pw.println("% free");
+        } catch (IllegalArgumentException e) {
+            pw.print(name);
+            pw.print("-Error: ");
+            pw.println(e.toString());
+            return;
+        }
+    }
+}
diff --git a/services/java/com/android/server/NetStatService.java b/services/java/com/android/server/NetStatService.java
index ac3445e..7fe6743 100644
--- a/services/java/com/android/server/NetStatService.java
+++ b/services/java/com/android/server/NetStatService.java
@@ -19,11 +19,16 @@
 import android.content.Context;
 import android.net.TrafficStats;
 import android.os.INetStatService;
+import android.os.SystemClock;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 
 public class NetStatService extends INetStatService.Stub {
+    private final Context mContext;
 
     public NetStatService(Context context) {
-
+        mContext = context;
     }
 
     public long getMobileTxPackets() {
@@ -57,4 +62,35 @@
     public long getTotalRxBytes() {
         return TrafficStats.getTotalRxBytes();
     }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        // This data is accessible to any app -- no permission check needed.
+
+        pw.print("Elapsed: total=");
+        pw.print(SystemClock.elapsedRealtime());
+        pw.print("ms awake=");
+        pw.print(SystemClock.uptimeMillis());
+        pw.println("ms");
+
+        pw.print("Mobile: Tx=");
+        pw.print(getMobileTxBytes());
+        pw.print("B/");
+        pw.print(getMobileTxPackets());
+        pw.print("Pkts Rx=");
+        pw.print(getMobileRxBytes());
+        pw.print("B/");
+        pw.print(getMobileRxPackets());
+        pw.println("Pkts");
+
+        pw.print("Total: Tx=");
+        pw.print(getTotalTxBytes());
+        pw.print("B/");
+        pw.print(getTotalTxPackets());
+        pw.print("Pkts Rx=");
+        pw.print(getTotalRxBytes());
+        pw.print("B/");
+        pw.print(getTotalRxPackets());
+        pw.println("Pkts");
+    }
 }
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index a3f2e09..072fc1b 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -312,11 +312,17 @@
         mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
     }
 
-    public void startTethering(String dhcpRangeStart, String dhcpRangeEnd)
+    public void startTethering(String[] dhcpRange)
              throws IllegalStateException {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
-        mConnector.doCommand(String.format("tether start %s %s", dhcpRangeStart, dhcpRangeEnd));
+        // cmd is "tether start first_start first_stop second_start second_stop ..."
+        // an odd number of addrs will fail
+        String cmd = "tether start";
+        for (String d : dhcpRange) {
+            cmd += " " + d;
+        }
+        mConnector.doCommand(cmd);
     }
 
     public void stopTethering() throws IllegalStateException {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index da9232b..3e1adf1 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -1136,11 +1136,13 @@
 
                     if (mAdbNotification == null) {
                         mAdbNotification = new Notification();
-                        mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_warning;
+                        mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_adb;
                         mAdbNotification.when = 0;
                         mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
                         mAdbNotification.tickerText = title;
-                        mAdbNotification.defaults |= Notification.DEFAULT_SOUND;
+                        mAdbNotification.defaults = 0; // please be quiet
+                        mAdbNotification.sound = null;
+                        mAdbNotification.vibrate = null;
                     }
 
                     Intent intent = new Intent(
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index b023958..25a60a6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -399,6 +399,13 @@
             } catch (Throwable e) {
                 Slog.e(TAG, "Failure installing status bar icons", e);
             }
+
+            try {
+                Slog.i(TAG, "DiskStats Service");
+                ServiceManager.addService("diskstats", new DiskStatsService(context));
+            } catch (Throwable e) {
+                Slog.e(TAG, "Failure starting DiskStats Service", e);
+            }
         }
 
         // make sure the ADB_ENABLED setting value matches the secure property value
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index b41443e..e4d7623 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -264,10 +264,11 @@
      * if needed
      */
     public void startWifi() {
-        boolean wifiEnabled = getPersistedWifiEnabled();
+        /* Start if Wi-Fi is enabled or the saved state indicates Wi-Fi was on */
+        boolean wifiEnabled = getPersistedWifiEnabled() || testAndClearWifiSavedState();
         Slog.i(TAG, "WifiService starting up with Wi-Fi " +
                 (wifiEnabled ? "enabled" : "disabled"));
-        setWifiEnabledBlocking(wifiEnabled, false, Process.myUid());
+        setWifiEnabledBlocking(wifiEnabled, true, Process.myUid());
     }
 
     private void updateTetherState(ArrayList<String> available, ArrayList<String> tethered) {
@@ -289,8 +290,8 @@
                     try {
                         ifcg = service.getInterfaceConfig(intf);
                         if (ifcg != null) {
-                            /* IP/netmask: 169.254.2.2/255.255.255.0 */
-                            ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 2;
+                            /* IP/netmask: 192.168.43.1/255.255.255.0 */
+                            ifcg.ipAddr = (192 << 24) + (168 << 16) + (43 << 8) + 1;
                             ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0;
                             ifcg.interfaceFlags = "up";
 
@@ -316,6 +317,19 @@
         }
     }
 
+    private boolean testAndClearWifiSavedState() {
+        final ContentResolver cr = mContext.getContentResolver();
+        int wifiSavedState = 0;
+        try {
+            wifiSavedState = Settings.Secure.getInt(cr, Settings.Secure.WIFI_SAVED_STATE);
+            if(wifiSavedState == 1)
+                Settings.Secure.putInt(cr, Settings.Secure.WIFI_SAVED_STATE, 0);
+        } catch (Settings.SettingNotFoundException e) {
+            ;
+        }
+        return (wifiSavedState == 1);
+    }
+
     private boolean getPersistedWifiEnabled() {
         final ContentResolver cr = mContext.getContentResolver();
         try {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index a1cf868..0e4b38d 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -7401,7 +7401,7 @@
                 try {
                     try {
                         mSurfaceX = mFrame.left + mXOffset;
-                        mSurfaceY = mFrame.top = mYOffset;
+                        mSurfaceY = mFrame.top + mYOffset;
                         mSurface.setPosition(mSurfaceX, mSurfaceY);
                         mSurfaceLayer = mAnimLayer;
                         mSurface.setLayer(mAnimLayer);
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 5e1b82f..f335287 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -31,6 +31,7 @@
 import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
 import android.net.NetworkInfo;
+import android.net.NetworkUtils;
 import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Environment;
@@ -80,11 +81,16 @@
 
     private BroadcastReceiver mStateReceiver;
 
-    private static final String USB_NEAR_IFACE_ADDR      = "169.254.2.1";
+    private static final String USB_NEAR_IFACE_ADDR      = "192.168.42.129";
+    private static final String USB_NETMASK              = "255.255.255.0";
+
+    // FYI - the default wifi is 192.168.43.1 and 255.255.255.0
 
     private String[] mDhcpRange;
-    private static final String DHCP_DEFAULT_RANGE_START = "169.254.2.10";
-    private static final String DHCP_DEFAULT_RANGE_STOP  = "169.254.2.64";
+    private static final String DHCP_DEFAULT_RANGE1_START = "192.168.42.2";
+    private static final String DHCP_DEFAULT_RANGE1_STOP  = "192.168.42.254";
+    private static final String DHCP_DEFAULT_RANGE2_START = "192.168.43.2";
+    private static final String DHCP_DEFAULT_RANGE2_STOP  = "192.168.43.254";
 
     private String[] mDnsServers;
     private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
@@ -138,15 +144,12 @@
 
         mDhcpRange = context.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_dhcp_range);
-        if (mDhcpRange.length == 0) {
-            mDhcpRange = new String[2];
-            mDhcpRange[0] = DHCP_DEFAULT_RANGE_START;
-            mDhcpRange[1] = DHCP_DEFAULT_RANGE_STOP;
-        } else if(mDhcpRange.length == 1) {
-            String[] tmp = new String[2];
-            tmp[0] = mDhcpRange[0];
-            tmp[1] = new String("");
-            mDhcpRange = tmp;
+        if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) {
+            mDhcpRange = new String[4];
+            mDhcpRange[0] = DHCP_DEFAULT_RANGE1_START;
+            mDhcpRange[1] = DHCP_DEFAULT_RANGE1_STOP;
+            mDhcpRange[2] = DHCP_DEFAULT_RANGE2_START;
+            mDhcpRange[3] = DHCP_DEFAULT_RANGE2_STOP;
         }
         mDunRequired = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_tether_dun_required);
@@ -504,8 +507,16 @@
                 try {
                     ifcg = service.getInterfaceConfig(iface);
                     if (ifcg != null) {
-                        ifcg.ipAddr = (169 << 24) + (254 << 16) + (2 << 8) + 1;
-                        ifcg.netmask = (255 << 24) + (255 << 16) + (255 << 8) + 0;
+                        String[] addr = USB_NEAR_IFACE_ADDR.split("\\.");
+                        ifcg.ipAddr = (Integer.parseInt(addr[0]) << 24) +
+                                (Integer.parseInt(addr[1]) << 16) +
+                                (Integer.parseInt(addr[2]) << 8) +
+                                (Integer.parseInt(addr[3]));
+                        addr = USB_NETMASK.split("\\.");
+                        ifcg.netmask = (Integer.parseInt(addr[0]) << 24) +
+                                (Integer.parseInt(addr[1]) << 16) +
+                                (Integer.parseInt(addr[2]) << 8) +
+                                (Integer.parseInt(addr[3]));
                         if (enabled) {
                             ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up");
                         } else {
@@ -836,6 +847,7 @@
                         if (mMyUpstreamIfaceName != null) {
                             try {
                                 service.disableNat(mIfaceName, mMyUpstreamIfaceName);
+                                mMyUpstreamIfaceName = null;
                             } catch (Exception e) {
                                 try {
                                     service.untetherInterface(mIfaceName);
@@ -876,6 +888,7 @@
                         if (mMyUpstreamIfaceName != null) {
                             try {
                                 service.disableNat(mIfaceName, mMyUpstreamIfaceName);
+                                mMyUpstreamIfaceName = null;
                             } catch (Exception e) {
                                 try {
                                     service.untetherInterface(mIfaceName);
@@ -915,6 +928,7 @@
                         if (mMyUpstreamIfaceName != null) {
                             try {
                                 service.disableNat(mIfaceName, mMyUpstreamIfaceName);
+                                mMyUpstreamIfaceName = null;
                             } catch (Exception e) {
                                 try {
                                     service.untetherInterface(mIfaceName);
@@ -1015,6 +1029,8 @@
 
         private boolean mConnectionRequested = false;
 
+        private String mUpstreamIfaceName = null;
+
         private static final int UPSTREAM_SETTLE_TIME_MS     = 10000;
         private static final int CELL_CONNECTION_RENEW_MS    = 40000;
 
@@ -1101,7 +1117,7 @@
                     return false;
                 }
                 try {
-                    service.startTethering(mDhcpRange[0], mDhcpRange[1]);
+                    service.startTethering(mDhcpRange);
                 } catch (Exception e) {
                     transitionTo(mStartTetheringErrorState);
                     return false;
@@ -1217,10 +1233,11 @@
                     // wait for things to settle and retry
                     sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
                 }
-                notifyTetheredOfNewIface(iface);
+                notifyTetheredOfNewUpstreamIface(iface);
             }
-            protected void notifyTetheredOfNewIface(String ifaceName) {
+            protected void notifyTetheredOfNewUpstreamIface(String ifaceName) {
                 Log.d(TAG, "notifying tethered with iface =" + ifaceName);
+                mUpstreamIfaceName = ifaceName;
                 for (Object o : mNotifyList) {
                     TetherInterfaceSM sm = (TetherInterfaceSM)o;
                     sm.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
@@ -1273,7 +1290,7 @@
             @Override
             public void exit() {
                 turnOffMobileConnection();
-                notifyTetheredOfNewIface(null);
+                notifyTetheredOfNewUpstreamIface(null);
             }
             @Override
             public boolean processMessage(Message message) {
@@ -1283,7 +1300,8 @@
                     case CMD_TETHER_MODE_REQUESTED:
                         TetherInterfaceSM who = (TetherInterfaceSM)message.obj;
                         mNotifyList.add(who);
-                        who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED);
+                        who.sendMessage(TetherInterfaceSM.CMD_TETHER_CONNECTION_CHANGED,
+                                mUpstreamIfaceName);
                         break;
                     case CMD_TETHER_MODE_UNREQUESTED:
                         who = (TetherInterfaceSM)message.obj;
diff --git a/services/java/com/android/server/status/NotificationViewList.java b/services/java/com/android/server/status/NotificationViewList.java
index 1598b68..1bb56a7 100644
--- a/services/java/com/android/server/status/NotificationViewList.java
+++ b/services/java/com/android/server/status/NotificationViewList.java
@@ -173,6 +173,12 @@
     }
 
     void add(StatusBarNotification notification) {
+        if (StatusBarService.SPEW) {
+            Slog.d(StatusBarService.TAG, "before add NotificationViewList"
+                    + " notification.data.ongoingEvent=" + notification.data.ongoingEvent);
+            dump(notification);
+        }
+
         ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest;
         long when = notification.data.when;
         final int N = list.size();
@@ -187,20 +193,25 @@
         list.add(index, notification);
 
         if (StatusBarService.SPEW) {
-            Slog.d(StatusBarService.TAG, "NotificationViewList index=" + index);
+            Slog.d(StatusBarService.TAG, "after add NotificationViewList index=" + index);
             dump(notification);
         }
     }
 
     void dump(StatusBarNotification notification) {
         if (StatusBarService.SPEW) {
+            boolean showTime = false;
             String s = "";
             for (int i=0; i<mOngoing.size(); i++) {
                 StatusBarNotification that = mOngoing.get(i);
                 if (that.key == notification.key) {
                     s += "[";
                 }
-                s += that.data.when;
+                if (showTime) {
+                    s += that.data.when;
+                } else {
+                    s += that.data.pkg + "/" + that.data.id + "/" + that.view;
+                }
                 if (that.key == notification.key) {
                     s += "]";
                 }
@@ -214,7 +225,11 @@
                 if (that.key == notification.key) {
                     s += "[";
                 }
-                s += that.data.when;
+                if (showTime) {
+                    s += that.data.when;
+                } else {
+                    s += that.data.pkg + "/" + that.data.id + "/" + that.view;
+                }
                 if (that.key == notification.key) {
                     s += "]";
                 }
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 27b7b504..bcaf0a4 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -893,6 +893,8 @@
     void updateNotificationView(StatusBarNotification notification, NotificationData oldData) {
         NotificationData n = notification.data;
         if (oldData != null && n != null
+                && n.when == oldData.when
+                && n.ongoingEvent == oldData.ongoingEvent
                 && n.contentView != null && oldData.contentView != null
                 && n.contentView.getPackage() != null
                 && oldData.contentView.getPackage() != null