Merge "Fix animation of notification handle bar when panel changes height" into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index a29cdba..8a7fb79 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -19988,6 +19988,10 @@
 
 package android.security {
 
+  public class AndroidKeyPairGeneratorSpec implements java.security.spec.AlgorithmParameterSpec {
+    ctor public AndroidKeyPairGeneratorSpec(android.content.Context, java.lang.String, javax.security.auth.x500.X500Principal, java.math.BigInteger, java.util.Date, java.util.Date);
+  }
+
   public final class KeyChain {
     ctor public KeyChain();
     method public static void choosePrivateKeyAlias(android.app.Activity, android.security.KeyChainAliasCallback, java.lang.String[], java.security.Principal[], java.lang.String, int, java.lang.String);
diff --git a/core/java/android/net/arp/ArpPeer.java b/core/java/android/net/arp/ArpPeer.java
index 5f68fdf..2013b11 100644
--- a/core/java/android/net/arp/ArpPeer.java
+++ b/core/java/android/net/arp/ArpPeer.java
@@ -58,9 +58,11 @@
         mInterfaceName = interfaceName;
         mMyAddr = myAddr;
 
-        for (int i = 0; i < MAC_ADDR_LENGTH; i++) {
-            mMyMac[i] = (byte) Integer.parseInt(mac.substring(
-                        i*3, (i*3) + 2), 16);
+        if (mac != null) {
+            for (int i = 0; i < MAC_ADDR_LENGTH; i++) {
+                mMyMac[i] = (byte) Integer.parseInt(mac.substring(
+                            i*3, (i*3) + 2), 16);
+            }
         }
 
         if (myAddr instanceof Inet6Address || peer instanceof Inet6Address) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 83267af..a1901a5 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -268,13 +268,6 @@
     public static final int USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS = 1 << 0;
 
     /**
-     * Special wake lock tag used for the wake lock in the Window Manager that handles the
-     * {@link android.view.WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON} flag.
-     * @hide
-     */
-    public static final String KEEP_SCREEN_ON_FLAG_TAG = "KEEP_SCREEN_ON_FLAG";
-
-    /**
      * Go to sleep reason code: Going to sleep due by user request.
      * @hide
      */
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 0338ee7..de8e78c 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -56,6 +56,7 @@
 
     /**
      * Returns the user name of the user making this call.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @return the user name
      */
     public String getUserName() {
@@ -69,6 +70,7 @@
 
     /**
      * Returns the UserInfo object describing a specific user.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param userHandle the user handle of the user whose information is being requested.
      * @return the UserInfo object for a specific user.
      * @hide
@@ -84,6 +86,7 @@
 
     /**
      * Creates a user with the specified name and options.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      *
      * @param name the user's name
      * @param flags flags that identify the type of user and other properties.
@@ -103,6 +106,7 @@
 
     /**
      * Returns information for all users on this device.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @return the list of users that were created.
      * @hide
      */
@@ -117,6 +121,7 @@
 
     /**
      * Removes a user and all associated data.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param userHandle the integer handle of the user, where 0 is the primary user.
      * @hide
      */
@@ -131,6 +136,7 @@
 
     /**
      * Updates the user's name.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      *
      * @param userHandle the user's integer handle
      * @param name the new name for the user
@@ -162,6 +168,7 @@
     /**
      * Enable or disable the use of a guest account. If disabled, the existing guest account
      * will be wiped.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param enable whether to enable a guest account.
      * @hide
      */
@@ -175,6 +182,7 @@
 
     /**
      * Checks if a guest user is enabled for this device.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @return whether a guest user is enabled
      * @hide
      */
@@ -189,6 +197,7 @@
 
     /**
      * Wipes all the data for a user, but doesn't remove the user.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
      * @param userHandle
      * @hide
      */
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 436762d..82635d7 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -310,15 +310,15 @@
         /**
          * Notifies the listener about progress made by a find operation.
          *
-         * @param numberOfMatches how many matches have been found
          * @param activeMatchOrdinal the zero-based ordinal of the currently selected match
+         * @param numberOfMatches how many matches have been found
          * @param isDoneCounting whether the find operation has actually completed. The listener
          *                       may be notified multiple times while the
          *                       operation is underway, and the numberOfMatches
          *                       value should not be considered final unless
          *                       isDoneCounting is true.
          */
-        public void onFindResultReceived(int numberOfMatches, int activeMatchOrdinal,
+        public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches,
             boolean isDoneCounting);
     }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 89be5cb..1c9b440 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -790,7 +790,7 @@
          third party applications. -->
     <permission android:name="android.permission.MANAGE_USERS"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="signature"
+        android:protectionLevel="signature|system"
         android:label="@string/permlab_manageUsers"
         android:description="@string/permdesc_manageUsers" />
     
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 4b51994..2907f10 100755
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -29,6 +29,9 @@
 import android.provider.MediaStore;
 import android.util.Log;
 
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -582,7 +585,28 @@
         if (null == path || path.equals("")) {
             throw new IllegalArgumentException("Given path should be non null");
         }
-        return _getOriginalMimeType(mUniqueId, path);
+
+        String mime = null;
+
+        FileInputStream is = null;
+        try {
+            FileDescriptor fd = null;
+            File file = new File(path);
+            if (file.exists()) {
+                is = new FileInputStream(file);
+                fd = is.getFD();
+            }
+            mime = _getOriginalMimeType(mUniqueId, path, fd);
+        } catch (IOException ioe) {
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch(IOException e) {}
+            }
+        }
+
+        return mime;
     }
 
     /**
@@ -848,7 +872,7 @@
 
     private native int _getDrmObjectType(int uniqueId, String path, String mimeType);
 
-    private native String _getOriginalMimeType(int uniqueId, String path);
+    private native String _getOriginalMimeType(int uniqueId, String path, FileDescriptor fd);
 
     private native int _checkRightsStatus(int uniqueId, String path, int action);
 
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index fb685a2..baddf62 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -587,22 +587,28 @@
 }
 
 static jstring android_drm_DrmManagerClient_getOriginalMimeType(
-            JNIEnv* env, jobject thiz, jint uniqueId, jstring path) {
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring path, jobject fileDescriptor) {
     ALOGV("getOriginalMimeType Enter");
+
+    int fd = (fileDescriptor == NULL)
+                ? -1
+                : jniGetFDFromFileDescriptor(env, fileDescriptor);
+
     String8 mimeType
         = getDrmManagerClientImpl(env, thiz)
-            ->getOriginalMimeType(uniqueId, Utility::getStringValue(env, path));
+            ->getOriginalMimeType(uniqueId,
+                                  Utility::getStringValue(env, path), fd);
     ALOGV("getOriginalMimeType Exit");
     return env->NewStringUTF(mimeType.string());
 }
 
 static jint android_drm_DrmManagerClient_checkRightsStatus(
             JNIEnv* env, jobject thiz, jint uniqueId, jstring path, int action) {
-    ALOGV("getOriginalMimeType Enter");
+    ALOGV("checkRightsStatus Enter");
     int rightsStatus
         = getDrmManagerClientImpl(env, thiz)
             ->checkRightsStatus(uniqueId, Utility::getStringValue(env, path), action);
-    ALOGV("getOriginalMimeType Exit");
+    ALOGV("checkRightsStatus Exit");
     return rightsStatus;
 }
 
@@ -730,7 +736,7 @@
     {"_getDrmObjectType", "(ILjava/lang/String;Ljava/lang/String;)I",
                                     (void*)android_drm_DrmManagerClient_getDrmObjectType},
 
-    {"_getOriginalMimeType", "(ILjava/lang/String;)Ljava/lang/String;",
+    {"_getOriginalMimeType", "(ILjava/lang/String;Ljava/io/FileDescriptor;)Ljava/lang/String;",
                                     (void*)android_drm_DrmManagerClient_getOriginalMimeType},
 
     {"_checkRightsStatus", "(ILjava/lang/String;I)I",
diff --git a/keystore/java/android/security/AndroidKeyPairGenerator.java b/keystore/java/android/security/AndroidKeyPairGenerator.java
new file mode 100644
index 0000000..c42001b
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyPairGenerator.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2012 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 android.security;
+
+import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
+
+import org.apache.harmony.xnet.provider.jsse.OpenSSLEngine;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.KeyPairGeneratorSpi;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * Provides a way to create instances of a KeyPair which will be placed in the
+ * Android keystore service usable only by the application that called it. This
+ * can be used in conjunction with
+ * {@link java.security.KeyStore#getInstance(String)} using the
+ * {@code "AndroidKeyStore"} type.
+ * <p>
+ * This class can not be directly instantiated and must instead be used via the
+ * {@link KeyPairGenerator#getInstance(String)
+ * KeyPairGenerator.getInstance("AndroidKeyPairGenerator")} API.
+ *
+ * {@hide}
+ */
+@SuppressWarnings("deprecation")
+public class AndroidKeyPairGenerator extends KeyPairGeneratorSpi {
+    public static final String NAME = "AndroidKeyPairGenerator";
+
+    private android.security.KeyStore mKeyStore;
+
+    private AndroidKeyPairGeneratorSpec mSpec;
+
+    /**
+     * Generate a KeyPair which is backed by the Android keystore service. You
+     * must call {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)}
+     * with an {@link AndroidKeyPairGeneratorSpec} as the {@code params}
+     * argument before calling this otherwise an {@code IllegalStateException}
+     * will be thrown.
+     * <p>
+     * This will create an entry in the Android keystore service with a
+     * self-signed certificate using the {@code params} specified in the
+     * {@code initialize(params)} call.
+     *
+     * @throws IllegalStateException when called before calling
+     *             {@link KeyPairGenerator#initialize(AlgorithmParameterSpec)}
+     * @see java.security.KeyPairGeneratorSpi#generateKeyPair()
+     */
+    @Override
+    public KeyPair generateKeyPair() {
+        if (mKeyStore == null || mSpec == null) {
+            throw new IllegalStateException(
+                    "Must call initialize with an AndroidKeyPairGeneratorSpec first");
+        }
+
+        final String alias = mSpec.getKeystoreAlias();
+
+        Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+
+        final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
+        mKeyStore.generate(privateKeyAlias);
+
+        final PrivateKey privKey;
+        final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
+        try {
+            privKey = engine.getPrivateKeyById(privateKeyAlias);
+        } catch (InvalidKeyException e) {
+            throw new RuntimeException("Can't get key", e);
+        }
+
+        final byte[] pubKeyBytes = mKeyStore.getPubkey(privateKeyAlias);
+
+        final PublicKey pubKey;
+        try {
+            final KeyFactory keyFact = KeyFactory.getInstance("RSA");
+            pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
+        } catch (NoSuchAlgorithmException e) {
+            throw new IllegalStateException("Can't instantiate RSA key generator", e);
+        } catch (InvalidKeySpecException e) {
+            throw new IllegalStateException("keystore returned invalid key encoding", e);
+        }
+
+        final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
+        certGen.setPublicKey(pubKey);
+        certGen.setSerialNumber(mSpec.getSerialNumber());
+        certGen.setSubjectDN(mSpec.getSubjectDN());
+        certGen.setIssuerDN(mSpec.getSubjectDN());
+        certGen.setNotBefore(mSpec.getStartDate());
+        certGen.setNotAfter(mSpec.getEndDate());
+        certGen.setSignatureAlgorithm("sha1WithRSA");
+
+        final X509Certificate cert;
+        try {
+            cert = certGen.generate(privKey);
+        } catch (Exception e) {
+            Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+            throw new IllegalStateException("Can't generate certificate", e);
+        }
+
+        byte[] certBytes;
+        try {
+            certBytes = cert.getEncoded();
+        } catch (CertificateEncodingException e) {
+            Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+            throw new IllegalStateException("Can't get encoding of certificate", e);
+        }
+
+        if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, certBytes)) {
+            Credentials.deleteAllTypesForAlias(mKeyStore, alias);
+            throw new IllegalStateException("Can't store certificate in AndroidKeyStore");
+        }
+
+        return new KeyPair(pubKey, privKey);
+    }
+
+    @Override
+    public void initialize(int keysize, SecureRandom random) {
+        throw new IllegalArgumentException("cannot specify keysize with AndroidKeyPairGenerator");
+    }
+
+    @Override
+    public void initialize(AlgorithmParameterSpec params, SecureRandom random)
+            throws InvalidAlgorithmParameterException {
+        if (params == null) {
+            throw new InvalidAlgorithmParameterException(
+                    "must supply params of type AndroidKeyPairGenericSpec");
+        } else if (!(params instanceof AndroidKeyPairGeneratorSpec)) {
+            throw new InvalidAlgorithmParameterException(
+                    "params must be of type AndroidKeyPairGeneratorSpec");
+        }
+
+        AndroidKeyPairGeneratorSpec spec = (AndroidKeyPairGeneratorSpec) params;
+
+        mSpec = spec;
+        mKeyStore = android.security.KeyStore.getInstance();
+    }
+}
diff --git a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
new file mode 100644
index 0000000..311359c
--- /dev/null
+++ b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2012 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 android.security;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.cert.Certificate;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * This provides the required parameters needed for initializing the KeyPair
+ * generator that works with
+ * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore
+ * facility</a>.
+ */
+public class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec {
+    private final String mKeystoreAlias;
+
+    private final Context mContext;
+
+    private final X500Principal mSubjectDN;
+
+    private final BigInteger mSerialNumber;
+
+    private final Date mStartDate;
+
+    private final Date mEndDate;
+
+    /**
+     * Parameter specification for the "{@code AndroidKeyPairGenerator}"
+     * instance of the {@link java.security.KeyPairGenerator} API. The
+     * {@code context} passed in may be used to pop up some UI to ask the user
+     * to unlock or initialize the Android keystore facility.
+     * <p>
+     * After generation, the {@code keyStoreAlias} is used with the
+     * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
+     * interface to retrieve the {@link PrivateKey} and its associated
+     * {@link Certificate} chain.
+     * <p>
+     * The KeyPair generator will create a self-signed certificate with the
+     * properties of {@code subjectDN} as its X.509v3 Subject Distinguished Name
+     * and as its X.509v3 Issuer Distinguished Name, using the specified
+     * {@code serialNumber}, and the validity date starting at {@code startDate}
+     * and ending at {@code endDate}.
+     *
+     * @param context Android context for the activity
+     * @param keyStoreAlias name to use for the generated key in the Android
+     *            keystore
+     * @param subjectDN X.509 v3 Subject Distinguished Name
+     * @param serialNumber X509 v3 certificate serial number
+     * @param startDate the start of the self-signed certificate validity period
+     * @param endDate the end date of the self-signed certificate validity
+     *            period
+     * @throws IllegalArgumentException when any argument is {@code null} or
+     *             {@code endDate} is before {@code startDate}.
+     */
+    public AndroidKeyPairGeneratorSpec(Context context, String keyStoreAlias,
+            X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate) {
+        if (context == null) {
+            throw new IllegalArgumentException("context == null");
+        } else if (TextUtils.isEmpty(keyStoreAlias)) {
+            throw new IllegalArgumentException("keyStoreAlias must not be empty");
+        } else if (subjectDN == null) {
+            throw new IllegalArgumentException("subjectDN == null");
+        } else if (serialNumber == null) {
+            throw new IllegalArgumentException("serialNumber == null");
+        } else if (startDate == null) {
+            throw new IllegalArgumentException("startDate == null");
+        } else if (endDate == null) {
+            throw new IllegalArgumentException("endDate == null");
+        } else if (endDate.before(startDate)) {
+            throw new IllegalArgumentException("endDate < startDate");
+        }
+
+        mContext = context;
+        mKeystoreAlias = keyStoreAlias;
+        mSubjectDN = subjectDN;
+        mSerialNumber = serialNumber;
+        mStartDate = startDate;
+        mEndDate = endDate;
+    }
+
+    /**
+     * @hide
+     */
+    String getKeystoreAlias() {
+        return mKeystoreAlias;
+    }
+
+    /**
+     * @hide
+     */
+    Context getContext() {
+        return mContext;
+    }
+
+    /**
+     * @hide
+     */
+    X500Principal getSubjectDN() {
+        return mSubjectDN;
+    }
+
+    /**
+     * @hide
+     */
+    BigInteger getSerialNumber() {
+        return mSerialNumber;
+    }
+
+    /**
+     * @hide
+     */
+    Date getStartDate() {
+        return mStartDate;
+    }
+
+    /**
+     * @hide
+     */
+    Date getEndDate() {
+        return mEndDate;
+    }
+}
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index a629f8d..e19217f 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -46,9 +46,8 @@
 import java.util.Set;
 
 /**
- * A java.security.KeyStore interface for the Android KeyStore. This class is
- * hidden from the Android API, but an instance of it can be created via the
- * {@link java.security.KeyStore#getInstance(String)
+ * A java.security.KeyStore interface for the Android KeyStore. An instance of
+ * it can be created via the {@link java.security.KeyStore#getInstance(String)
  * KeyStore.getInstance("AndroidKeyStore")} interface. This returns a
  * java.security.KeyStore backed by this "AndroidKeyStore" implementation.
  * <p>
@@ -277,7 +276,7 @@
          * Make sure we clear out all the types we know about before trying to
          * write.
          */
-        deleteAllTypesForAlias(alias);
+        Credentials.deleteAllTypesForAlias(mKeyStore, alias);
 
         if (!mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, keyBytes)) {
             throw new KeyStoreException("Couldn't put private key in keystore");
@@ -315,26 +314,11 @@
 
     @Override
     public void engineDeleteEntry(String alias) throws KeyStoreException {
-        if (!deleteAllTypesForAlias(alias)) {
+        if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) {
             throw new KeyStoreException("No such entry " + alias);
         }
     }
 
-    /**
-     * Delete all types (private key, certificate, CA certificate) for a
-     * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if there was at least one of those types.
-     */
-    private boolean deleteAllTypesForAlias(String alias) {
-        /*
-         * Make sure every type is deleted. There can be all three types, so
-         * don't use a conditional here.
-         */
-        return mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + alias)
-                | mKeyStore.delete(Credentials.USER_CERTIFICATE + alias)
-                | mKeyStore.delete(Credentials.CA_CERTIFICATE + alias);
-    }
-
     private Set<String> getUniqueAliases() {
         final String[] rawAliases = mKeyStore.saw("");
         if (rawAliases == null) {
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
index df22f58..40d7e1a 100644
--- a/keystore/java/android/security/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -29,6 +29,11 @@
     public AndroidKeyStoreProvider() {
         super(PROVIDER_NAME, 1.0, "Android KeyStore security provider");
 
+        // java.security.KeyStore
         put("KeyStore." + AndroidKeyStore.NAME, AndroidKeyStore.class.getName());
+
+        // java.security.KeyPairGenerator
+        put("KeyPairGenerator." + AndroidKeyPairGenerator.NAME,
+                AndroidKeyPairGenerator.class.getName());
     }
 }
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 68ba2b1..72332eb 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -185,4 +185,19 @@
             Log.w(LOGTAG, e.toString());
         }
     }
+
+    /**
+     * Delete all types (private key, certificate, CA certificate) for a
+     * particular {@code alias}. All three can exist for any given alias.
+     * Returns {@code true} if there was at least one of those types.
+     */
+    static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
+        /*
+         * Make sure every type is deleted. There can be all three types, so
+         * don't use a conditional here.
+         */
+        return keystore.delKey(Credentials.USER_PRIVATE_KEY + alias)
+                | keystore.delete(Credentials.USER_CERTIFICATE + alias)
+                | keystore.delete(Credentials.CA_CERTIFICATE + alias);
+    }
 }
diff --git a/keystore/java/android/security/package.html b/keystore/java/android/security/package.html
new file mode 100644
index 0000000..610cbf0
--- /dev/null
+++ b/keystore/java/android/security/package.html
@@ -0,0 +1,9 @@
+<HTML>
+<BODY>
+  <p>Provides access to a few facilities of the Android security
+    subsystems.</p>
+  <p>For information on how to use this facility, see the <a
+      href="{@docRoot}guide/topics/security/keystore.html">Android
+      KeyStore facility</a> guide.</p>
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
new file mode 100644
index 0000000..e6a3750
--- /dev/null
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2012 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 android.security;
+
+import android.test.AndroidTestCase;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+public class AndroidKeyPairGeneratorSpecTest extends AndroidTestCase {
+    private static final String TEST_ALIAS_1 = "test1";
+
+    private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
+
+    private static final long NOW_MILLIS = System.currentTimeMillis();
+
+    private static final BigInteger SERIAL_1 = BigInteger.ONE;
+
+    /* We have to round this off because X509v3 doesn't store milliseconds. */
+    private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
+
+    @SuppressWarnings("deprecation")
+    private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
+
+    public void testConstructor_Success() throws Exception {
+        AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec(getContext(),
+                TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW, NOW_PLUS_10_YEARS);
+
+        assertEquals("Context should be the one specified", getContext(), spec.getContext());
+
+        assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias());
+
+        assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN());
+
+        assertEquals("startDate should be the one specified", NOW, spec.getStartDate());
+
+        assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
+    }
+
+    public void testConstructor_NullContext_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
+                    NOW_PLUS_10_YEARS);
+            fail("Should throw IllegalArgumentException when context is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_NullKeystoreAlias_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), null, TEST_DN_1, SERIAL_1, NOW,
+                    NOW_PLUS_10_YEARS);
+            fail("Should throw IllegalArgumentException when keystoreAlias is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_NullSubjectDN_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, null, SERIAL_1, NOW,
+                    NOW_PLUS_10_YEARS);
+            fail("Should throw IllegalArgumentException when subjectDN is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_NullSerial_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, null, NOW,
+                    NOW_PLUS_10_YEARS);
+            fail("Should throw IllegalArgumentException when startDate is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_NullStartDate_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, null,
+                    NOW_PLUS_10_YEARS);
+            fail("Should throw IllegalArgumentException when startDate is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_NullEndDate_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW,
+                    null);
+            fail("Should throw IllegalArgumentException when keystoreAlias is null");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testConstructor_EndBeforeStart_Failure() throws Exception {
+        try {
+            new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, TEST_DN_1, SERIAL_1,
+                    NOW_PLUS_10_YEARS, NOW);
+            fail("Should throw IllegalArgumentException when end is before start");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+}
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
new file mode 100644
index 0000000..d108caaa
--- /dev/null
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012 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 android.security;
+
+import android.test.AndroidTestCase;
+
+import java.io.ByteArrayInputStream;
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+import javax.security.auth.x500.X500Principal;
+
+public class AndroidKeyPairGeneratorTest extends AndroidTestCase {
+    private android.security.KeyStore mAndroidKeyStore;
+
+    private java.security.KeyPairGenerator mGenerator;
+
+    private static final String TEST_ALIAS_1 = "test1";
+
+    private static final String TEST_ALIAS_2 = "test2";
+
+    private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
+
+    private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2");
+
+    private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE;
+
+    private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L);
+
+    private static final long NOW_MILLIS = System.currentTimeMillis();
+
+    /* We have to round this off because X509v3 doesn't store milliseconds. */
+    private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
+
+    @SuppressWarnings("deprecation")
+    private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
+
+    @Override
+    protected void setUp() throws Exception {
+        mAndroidKeyStore = android.security.KeyStore.getInstance();
+
+        assertTrue(mAndroidKeyStore.reset());
+
+        assertEquals(android.security.KeyStore.State.UNINITIALIZED, mAndroidKeyStore.state());
+
+        assertTrue(mAndroidKeyStore.password("1111"));
+
+        assertEquals(android.security.KeyStore.State.UNLOCKED, mAndroidKeyStore.state());
+
+        assertEquals(0, mAndroidKeyStore.saw("").length);
+
+        mGenerator = java.security.KeyPairGenerator.getInstance(AndroidKeyPairGenerator.NAME);
+    }
+
+    public void testKeyPairGenerator_Initialize_Params_Success() throws Exception {
+        mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+                TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
+    }
+
+    public void testKeyPairGenerator_Initialize_KeySize_Failure() throws Exception {
+        try {
+            mGenerator.initialize(1024);
+            fail("KeyPairGenerator should not support setting the key size");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testKeyPairGenerator_Initialize_KeySizeAndSecureRandom_Failure() throws Exception {
+        try {
+            mGenerator.initialize(1024, new SecureRandom());
+            fail("KeyPairGenerator should not support setting the key size");
+        } catch (IllegalArgumentException success) {
+        }
+    }
+
+    public void testKeyPairGenerator_Initialize_ParamsAndSecureRandom_Failure() throws Exception {
+        mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+                TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS), new SecureRandom());
+    }
+
+    public void testKeyPairGenerator_GenerateKeyPair_Success() throws Exception {
+        mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+                TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
+
+        final KeyPair pair = mGenerator.generateKeyPair();
+        assertNotNull("The KeyPair returned should not be null", pair);
+
+        assertKeyPairCorrect(pair, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS);
+    }
+
+    public void testKeyPairGenerator_GenerateKeyPair_Replaced_Success() throws Exception {
+        // Generate the first key
+        {
+            mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_1,
+                    TEST_DN_1, TEST_SERIAL_1, NOW, NOW_PLUS_10_YEARS));
+            final KeyPair pair1 = mGenerator.generateKeyPair();
+            assertNotNull("The KeyPair returned should not be null", pair1);
+            assertKeyPairCorrect(pair1, TEST_ALIAS_1, TEST_DN_1, TEST_SERIAL_1, NOW,
+                    NOW_PLUS_10_YEARS);
+        }
+
+        // Replace the original key
+        {
+            mGenerator.initialize(new AndroidKeyPairGeneratorSpec(getContext(), TEST_ALIAS_2,
+                    TEST_DN_2, TEST_SERIAL_2, NOW, NOW_PLUS_10_YEARS));
+            final KeyPair pair2 = mGenerator.generateKeyPair();
+            assertNotNull("The KeyPair returned should not be null", pair2);
+            assertKeyPairCorrect(pair2, TEST_ALIAS_2, TEST_DN_2, TEST_SERIAL_2, NOW,
+                    NOW_PLUS_10_YEARS);
+        }
+    }
+
+    private void assertKeyPairCorrect(KeyPair pair, String alias, X500Principal dn,
+            BigInteger serial, Date start, Date end) throws Exception {
+        final PublicKey pubKey = pair.getPublic();
+        assertNotNull("The PublicKey for the KeyPair should be not null", pubKey);
+
+        final PrivateKey privKey = pair.getPrivate();
+        assertNotNull("The PrivateKey for the KeyPair should be not null", privKey);
+
+        final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+        assertNotNull("The user certificate should exist for the generated entry", userCertBytes);
+
+        final CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        final Certificate userCert = cf
+                .generateCertificate(new ByteArrayInputStream(userCertBytes));
+
+        assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate);
+
+        final X509Certificate x509userCert = (X509Certificate) userCert;
+
+        assertEquals("PublicKey used to sign certificate should match one returned in KeyPair",
+                pubKey, x509userCert.getPublicKey());
+
+        assertEquals("The Subject DN should be the one passed into the params", dn,
+                x509userCert.getSubjectDN());
+
+        assertEquals("The Issuer DN should be the same as the Subject DN", dn,
+                x509userCert.getIssuerDN());
+
+        assertEquals("The Serial should be the one passed into the params", serial,
+                x509userCert.getSerialNumber());
+
+        assertEquals("The notBefore date should be the one passed into the params", start,
+                x509userCert.getNotBefore());
+
+        assertEquals("The notAfter date should be the one passed into the params", end,
+                x509userCert.getNotAfter());
+
+        x509userCert.verify(pubKey);
+
+        final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+        assertNull("A list of CA certificates should not exist for the generated entry", caCerts);
+
+        final byte[] pubKeyBytes = mAndroidKeyStore.getPubkey(Credentials.USER_PRIVATE_KEY + alias);
+        assertNotNull("The keystore should return the public key for the generated key",
+                pubKeyBytes);
+    }
+}
diff --git a/services/java/com/android/server/TwilightService.java b/services/java/com/android/server/TwilightService.java
index 5be7205..a7bce54 100644
--- a/services/java/com/android/server/TwilightService.java
+++ b/services/java/com/android/server/TwilightService.java
@@ -50,7 +50,7 @@
 public final class TwilightService {
     private static final String TAG = "TwilightService";
 
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static final String ACTION_UPDATE_TWILIGHT_STATE =
             "com.android.server.action.UPDATE_TWILIGHT_STATE";
@@ -463,6 +463,11 @@
         }
 
         private void updateTwilightState() {
+            if (mLocation == null) {
+                setTwilightState(null);
+                return;
+            }
+
             final long now = System.currentTimeMillis();
 
             // calculate yesterday's twilight
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index c292bbc..f5b4053 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -137,11 +137,17 @@
     public UserInfo getUserInfo(int userId) {
         checkManageUsersPermission("query user");
         synchronized (mUsers) {
-            UserInfo info = mUsers.get(userId);
-            return info;
+            return getUserInfoLocked(userId);
         }
     }
 
+    /*
+     * Should be locked on mUsers before calling this.
+     */
+    private UserInfo getUserInfoLocked(int userId) {
+        return mUsers.get(userId);
+    }
+
     public boolean exists(int userId) {
         synchronized (mUsers) {
             return ArrayUtils.contains(mUserIds, userId);
@@ -212,8 +218,9 @@
     }
 
     /**
-     * Enforces that only the system UID or root's UID can call a method exposed
-     * via Binder.
+     * Enforces that only the system UID or root's UID or apps that have the
+     * {@link android.Manifest.permission.MANAGE_USERS MANAGE_USERS}
+     * permission can make certain calls to the UserManager.
      *
      * @param message used as message if SecurityException is thrown
      * @throws SecurityException if the caller is not system or root
@@ -534,7 +541,7 @@
     public int getUserSerialNumber(int userHandle) {
         synchronized (mUsers) {
             if (!exists(userHandle)) return -1;
-            return getUserInfo(userHandle).serialNumber;
+            return getUserInfoLocked(userHandle).serialNumber;
         }
     }
 
@@ -542,7 +549,7 @@
     public int getUserHandle(int userSerialNumber) {
         synchronized (mUsers) {
             for (int userId : mUserIds) {
-                if (getUserInfo(userId).serialNumber == userSerialNumber) return userId;
+                if (getUserInfoLocked(userId).serialNumber == userSerialNumber) return userId;
             }
             // Not found
             return -1;
@@ -617,14 +624,16 @@
      * @return
      */
     private int getNextAvailableId() {
-        int i = 0;
-        while (i < Integer.MAX_VALUE) {
-            if (mUsers.indexOfKey(i) < 0) {
-                break;
+        synchronized (mUsers) {
+            int i = 0;
+            while (i < Integer.MAX_VALUE) {
+                if (mUsers.indexOfKey(i) < 0) {
+                    break;
+                }
+                i++;
             }
-            i++;
+            return i;
         }
-        return i;
     }
 
     private boolean createPackageFolders(int id, File userPath) {
diff --git a/services/java/com/android/server/power/Notifier.java b/services/java/com/android/server/power/Notifier.java
index 37384d2..9d928e5 100644
--- a/services/java/com/android/server/power/Notifier.java
+++ b/services/java/com/android/server/power/Notifier.java
@@ -28,7 +28,6 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
-import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.WorkSource;
@@ -117,19 +116,15 @@
                     + ", workSource=" + workSource);
         }
 
-        if (!isWakeLockAlreadyReportedToBatteryStats(tag, ownerUid)) {
-            try {
-                final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
-                if (workSource != null) {
-                    mBatteryStats.noteStartWakelockFromSource(
-                            workSource, ownerPid, tag, monitorType);
-                } else {
-                    mBatteryStats.noteStartWakelock(
-                            ownerUid, ownerPid, tag, monitorType);
-                }
-            } catch (RemoteException ex) {
-                // Ignore
+        try {
+            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+            if (workSource != null) {
+                mBatteryStats.noteStartWakelockFromSource(workSource, ownerPid, tag, monitorType);
+            } else {
+                mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, monitorType);
             }
+        } catch (RemoteException ex) {
+            // Ignore
         }
     }
 
@@ -144,30 +139,18 @@
                     + ", workSource=" + workSource);
         }
 
-        if (!isWakeLockAlreadyReportedToBatteryStats(tag, ownerUid)) {
-            try {
-                final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
-                if (workSource != null) {
-                    mBatteryStats.noteStopWakelockFromSource(
-                            workSource, ownerPid, tag, monitorType);
-                } else {
-                    mBatteryStats.noteStopWakelock(
-                            ownerUid, ownerPid, tag, monitorType);
-                }
-            } catch (RemoteException ex) {
-                // Ignore
+        try {
+            final int monitorType = getBatteryStatsWakeLockMonitorType(flags);
+            if (workSource != null) {
+                mBatteryStats.noteStopWakelockFromSource(workSource, ownerPid, tag, monitorType);
+            } else {
+                mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, monitorType);
             }
+        } catch (RemoteException ex) {
+            // Ignore
         }
     }
 
-    private static boolean isWakeLockAlreadyReportedToBatteryStats(String tag, int uid) {
-        // The window manager already takes care of reporting battery stats associated
-        // with the use of the KEEP_SCREEN_ON_FLAG.
-        // TODO: Use a WorkSource to handle this situation instead of hardcoding it here.
-        return uid == Process.SYSTEM_UID
-                && tag.equals(PowerManager.KEEP_SCREEN_ON_FLAG_TAG);
-    }
-
     private static int getBatteryStatsWakeLockMonitorType(int flags) {
         switch (flags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
             case PowerManager.PARTIAL_WAKE_LOCK:
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 1ba1022..d3a3ffb 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -405,7 +405,7 @@
         mScreenAutoBrightnessAdjustmentSetting = Settings.System.getFloat(resolver,
                 Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ, 0.0f);
         if (oldScreenAutoBrightnessAdjustmentSetting != mScreenAutoBrightnessAdjustmentSetting) {
-            mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = -1;
+            mTemporaryScreenAutoBrightnessAdjustmentSettingOverride = Float.NaN;
         }
 
         mScreenBrightnessModeSetting = Settings.System.getInt(resolver,
@@ -1347,7 +1347,8 @@
     }
 
     private static boolean isValidAutoBrightnessAdjustment(float value) {
-        return !Float.isNaN(value);
+        // Handles NaN by always returning false.
+        return value >= -1.0f && value <= 1.0f;
     }
 
     private int getDesiredScreenPowerState() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index fd90082..b0c5835 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -94,6 +94,7 @@
 import android.os.SystemProperties;
 import android.os.TokenWatcher;
 import android.os.Trace;
+import android.os.WorkSource;
 import android.provider.Settings;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
@@ -923,7 +924,7 @@
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
         mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
-                | PowerManager.ON_AFTER_RELEASE, PowerManager.KEEP_SCREEN_ON_FLAG_TAG);
+                | PowerManager.ON_AFTER_RELEASE, TAG);
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
         mInputManager = new InputManagerService(context, mInputMonitor);
@@ -7020,7 +7021,7 @@
         public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
         public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
         public static final int WINDOW_FREEZE_TIMEOUT = 11;
-        public static final int HOLD_SCREEN_CHANGED = 12;
+
         public static final int APP_TRANSITION_TIMEOUT = 13;
         public static final int PERSIST_ANIMATION_SCALE = 14;
         public static final int FORCE_GC = 15;
@@ -7041,8 +7042,6 @@
         public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
         public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
 
-        private Session mLastReportedHold;
-
         public H() {
         }
 
@@ -7294,33 +7293,6 @@
                     break;
                 }
 
-                case HOLD_SCREEN_CHANGED: {
-                    Session oldHold;
-                    Session newHold;
-                    synchronized (mWindowMap) {
-                        oldHold = mLastReportedHold;
-                        newHold = (Session)msg.obj;
-                        mLastReportedHold = newHold;
-                    }
-
-                    if (oldHold != newHold) {
-                        try {
-                            if (oldHold != null) {
-                                mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
-                                        "window",
-                                        BatteryStats.WAKE_TYPE_WINDOW);
-                            }
-                            if (newHold != null) {
-                                mBatteryStats.noteStartWakelock(newHold.mUid, -1,
-                                        "window",
-                                        BatteryStats.WAKE_TYPE_WINDOW);
-                            }
-                        } catch (RemoteException e) {
-                        }
-                    }
-                    break;
-                }
-
                 case APP_TRANSITION_TIMEOUT: {
                     synchronized (mWindowMap) {
                         if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
@@ -9134,7 +9106,7 @@
         // Finally update all input windows now that the window changes have stabilized.
         mInputMonitor.updateInputWindowsLw(true /*force*/);
 
-        setHoldScreenLocked(mInnerFields.mHoldScreen != null);
+        setHoldScreenLocked(mInnerFields.mHoldScreen);
         if (!mDisplayFrozen) {
             if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
                 mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
@@ -9149,11 +9121,6 @@
                         toBrightnessOverride(mInnerFields.mButtonBrightness));
             }
         }
-        if (mInnerFields.mHoldScreen != mHoldingScreenOn) {
-            mHoldingScreenOn = mInnerFields.mHoldScreen;
-            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, mInnerFields.mHoldScreen);
-            mH.sendMessage(m);
-        }
 
         if (mTurnOnScreen) {
             if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
@@ -9237,13 +9204,17 @@
         }
     }
 
-    /**
-     * Must be called with the main window manager lock held.
-     */
-    void setHoldScreenLocked(boolean holding) {
-        boolean state = mHoldingScreenWakeLock.isHeld();
-        if (holding != state) {
-            if (holding) {
+    void setHoldScreenLocked(final Session newHoldScreen) {
+        final boolean hold = newHoldScreen != null;
+
+        if (hold && mHoldingScreenOn != newHoldScreen) {
+            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
+        }
+        mHoldingScreenOn = newHoldScreen;
+
+        final boolean state = mHoldingScreenWakeLock.isHeld();
+        if (hold != state) {
+            if (hold) {
                 mPolicy.screenOnStartedLw();
                 mHoldingScreenWakeLock.acquire();
             } else {
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 89b2474..8aeb2af 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -34,7 +34,8 @@
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
-
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    
     <application>
         <uses-library android:name="android.test.runner" />