Merge "More work on voice interaction visuals." into lmp-preview-dev
diff --git a/api/current.txt b/api/current.txt
index 9935cd7..3c95508 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7040,7 +7040,6 @@
     field public static final java.lang.String VIBRATOR_SERVICE = "vibrator";
     field public static final java.lang.String WALLPAPER_SERVICE = "wallpaper";
     field public static final java.lang.String WIFI_P2P_SERVICE = "wifip2p";
-    field public static final java.lang.String WIFI_PASSPOINT_SERVICE = "wifipasspoint";
     field public static final java.lang.String WIFI_SERVICE = "wifi";
     field public static final java.lang.String WINDOW_SERVICE = "window";
   }
@@ -8200,7 +8199,7 @@
   }
 
   public class LauncherActivityInfo {
-    method public int getApplicationFlags();
+    method public android.content.pm.ApplicationInfo getApplicationInfo();
     method public android.graphics.drawable.Drawable getBadgedIcon(int);
     method public android.content.ComponentName getComponentName();
     method public long getFirstInstallTime();
@@ -8211,21 +8210,21 @@
   }
 
   public class LauncherApps {
-    method public synchronized void addOnAppsChangedListener(android.content.pm.LauncherApps.OnAppsChangedListener);
+    method public void addOnAppsChangedListener(android.content.pm.LauncherApps.OnAppsChangedListener);
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
     method public boolean isActivityEnabledForProfile(android.content.ComponentName, android.os.UserHandle);
     method public boolean isPackageEnabledForProfile(java.lang.String, android.os.UserHandle);
-    method public synchronized void removeOnAppsChangedListener(android.content.pm.LauncherApps.OnAppsChangedListener);
+    method public void removeOnAppsChangedListener(android.content.pm.LauncherApps.OnAppsChangedListener);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
-    method public void startActivityForProfile(android.content.ComponentName, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
+    method public void startActivityForProfile(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
   }
 
   public static abstract interface LauncherApps.OnAppsChangedListener {
-    method public abstract void onPackageAdded(android.os.UserHandle, java.lang.String);
-    method public abstract void onPackageChanged(android.os.UserHandle, java.lang.String);
-    method public abstract void onPackageRemoved(android.os.UserHandle, java.lang.String);
-    method public abstract void onPackagesAvailable(android.os.UserHandle, java.lang.String[], boolean);
-    method public abstract void onPackagesUnavailable(android.os.UserHandle, java.lang.String[], boolean);
+    method public abstract void onPackageAdded(java.lang.String, android.os.UserHandle);
+    method public abstract void onPackageChanged(java.lang.String, android.os.UserHandle);
+    method public abstract void onPackageRemoved(java.lang.String, android.os.UserHandle);
+    method public abstract void onPackagesAvailable(java.lang.String[], android.os.UserHandle, boolean);
+    method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -17112,7 +17111,6 @@
   public class WifiManager {
     method public int addNetwork(android.net.wifi.WifiConfiguration);
     method public static int calculateSignalLevel(int, int);
-    method public void cancelWps(android.net.wifi.WifiManager.ActionListener);
     method public static int compareSignalLevel(int, int);
     method public android.net.wifi.WifiManager.MulticastLock createMulticastLock(java.lang.String);
     method public android.net.wifi.WifiManager.WifiLock createWifiLock(int, java.lang.String);
@@ -17136,12 +17134,9 @@
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
     method public boolean startScan();
-    method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsListener);
     method public int updateNetwork(android.net.wifi.WifiConfiguration);
     field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
     field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
-    field public static final int BUSY = 2; // 0x2
-    field public static final int ERROR = 0; // 0x0
     field public static final int ERROR_AUTHENTICATING = 1; // 0x1
     field public static final java.lang.String EXTRA_BSSID = "bssid";
     field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
@@ -17152,8 +17147,6 @@
     field public static final java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
     field public static final java.lang.String EXTRA_WIFI_INFO = "wifiInfo";
     field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_state";
-    field public static final int INVALID_ARGS = 8; // 0x8
-    field public static final int IN_PROGRESS = 1; // 0x1
     field public static final java.lang.String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
     field public static final java.lang.String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
     field public static final java.lang.String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
@@ -17169,16 +17162,6 @@
     field public static final int WIFI_STATE_ENABLED = 3; // 0x3
     field public static final int WIFI_STATE_ENABLING = 2; // 0x2
     field public static final int WIFI_STATE_UNKNOWN = 4; // 0x4
-    field public static final int WPS_AUTH_FAILURE = 6; // 0x6
-    field public static final int WPS_OVERLAP_ERROR = 3; // 0x3
-    field public static final int WPS_TIMED_OUT = 7; // 0x7
-    field public static final int WPS_TKIP_ONLY_PROHIBITED = 5; // 0x5
-    field public static final int WPS_WEP_PROHIBITED = 4; // 0x4
-  }
-
-  public static abstract interface WifiManager.ActionListener {
-    method public abstract void onFailure(int);
-    method public abstract void onSuccess();
   }
 
   public class WifiManager.MulticastLock {
@@ -17196,12 +17179,6 @@
     method public void setWorkSource(android.os.WorkSource);
   }
 
-  public static abstract interface WifiManager.WpsListener {
-    method public abstract void onCompletion();
-    method public abstract void onFailure(int);
-    method public abstract void onStartSuccess(java.lang.String);
-  }
-
   public class WifiScanner {
     method public void configureWifiChange(int, int, int, int, int, android.net.wifi.WifiScanner.HotspotInfo[]);
     method public void resetHotlist(android.net.wifi.WifiScanner.HotlistListener);
@@ -17287,7 +17264,6 @@
     ctor public WpsInfo(android.net.wifi.WpsInfo);
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
-    field public java.lang.String BSSID;
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int DISPLAY = 1; // 0x1
     field public static final int INVALID = 4; // 0x4
@@ -17495,29 +17471,6 @@
 
 }
 
-package android.net.wifi.passpoint {
-
-  public class WifiPasspointCredential implements android.os.Parcelable {
-    ctor public WifiPasspointCredential(java.lang.String, android.net.wifi.WifiEnterpriseConfig);
-    method public int describeContents();
-    method public java.lang.String getClientCertPath();
-    method public int getEapMethod();
-    method public java.lang.String getFqdn();
-    method public java.lang.String getImsi();
-    method public java.lang.String getRealm();
-    method public java.lang.String getUserName();
-    method public void writeToParcel(android.os.Parcel, int);
-  }
-
-  public class WifiPasspointManager {
-    method public boolean addCredential(android.net.wifi.passpoint.WifiPasspointCredential);
-    method public java.util.List<android.net.wifi.passpoint.WifiPasspointCredential> getSavedCredentials();
-    method public boolean removeCredential(android.net.wifi.passpoint.WifiPasspointCredential);
-    method public boolean updateCredential(android.net.wifi.passpoint.WifiPasspointCredential);
-  }
-
-}
-
 package android.nfc {
 
   public class FormatException extends java.lang.Exception {
@@ -17652,25 +17605,15 @@
 
 package android.nfc.cardemulation {
 
-  public final class AidGroup implements android.os.Parcelable {
-    ctor public AidGroup(java.util.ArrayList<java.lang.String>, java.lang.String);
-    method public int describeContents();
-    method public java.util.ArrayList<java.lang.String> getAids();
-    method public java.lang.String getCategory();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final int MAX_NUM_AIDS = 256; // 0x100
-  }
-
   public final class CardEmulation {
     method public boolean categoryAllowsForegroundPreference(java.lang.String);
-    method public android.nfc.cardemulation.AidGroup getAidGroupForService(android.content.ComponentName, java.lang.String);
+    method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, java.lang.String);
     method public static synchronized android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
     method public int getSelectionModeForCategory(java.lang.String);
     method public boolean isDefaultServiceForAid(android.content.ComponentName, java.lang.String);
     method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
-    method public boolean registerAidGroupForService(android.content.ComponentName, android.nfc.cardemulation.AidGroup);
-    method public boolean removeAidGroupForService(android.content.ComponentName, java.lang.String);
+    method public boolean registerAidsForService(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
+    method public boolean removeAidsForService(android.content.ComponentName, java.lang.String);
     method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
     method public boolean unsetPreferredService(android.app.Activity);
     field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b0673b5..2ff85c6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2363,6 +2363,7 @@
      *
      * @see #getSystemService
      * @see android.net.wifi.passpoint.WifiPasspointManager
+     * @hide
      */
     public static final String WIFI_PASSPOINT_SERVICE = "wifipasspoint";
 
diff --git a/core/java/android/content/pm/LauncherActivityInfo.java b/core/java/android/content/pm/LauncherActivityInfo.java
index 9087338..5d48868 100644
--- a/core/java/android/content/pm/LauncherActivityInfo.java
+++ b/core/java/android/content/pm/LauncherActivityInfo.java
@@ -30,6 +30,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.DisplayMetrics;
 import android.util.Log;
 
 /**
@@ -47,21 +48,22 @@
     private ActivityInfo mActivityInfo;
     private ComponentName mComponentName;
     private UserHandle mUser;
-    // TODO: Fetch this value from PM
     private long mFirstInstallTime;
 
     /**
      * Create a launchable activity object for a given ResolveInfo and user.
-     * 
+     *
      * @param context The context for fetching resources.
      * @param info ResolveInfo from which to create the LauncherActivityInfo.
      * @param user The UserHandle of the profile to which this activity belongs.
      */
-    LauncherActivityInfo(Context context, ResolveInfo info, UserHandle user) {
+    LauncherActivityInfo(Context context, ResolveInfo info, UserHandle user,
+            long firstInstallTime) {
         this(context);
-        this.mActivityInfo = info.activityInfo;
-        this.mComponentName = LauncherApps.getComponentName(info);
-        this.mUser = user;
+        mActivityInfo = info.activityInfo;
+        mComponentName = LauncherApps.getComponentName(info);
+        mUser = user;
+        mFirstInstallTime = firstInstallTime;
     }
 
     LauncherActivityInfo(Context context) {
@@ -79,7 +81,13 @@
     }
 
     /**
-     * Returns the user handle of the user profile that this activity belongs to.
+     * Returns the user handle of the user profile that this activity belongs to. In order to
+     * persist the identity of the profile, do not store the UserHandle. Instead retrieve its
+     * serial number from UserManager. You can convert the serial number back to a UserHandle
+     * for later use.
+     *
+     * @see UserManager#getSerialNumberForUser(UserHandle)
+     * @see UserManager#getUserForSerialNumber(long)
      *
      * @return The UserHandle of the profile.
      */
@@ -89,7 +97,7 @@
 
     /**
      * Retrieves the label for the activity.
-     * 
+     *
      * @return The label for the activity.
      */
     public CharSequence getLabel() {
@@ -98,8 +106,10 @@
 
     /**
      * Returns the icon for this activity, without any badging for the profile.
-     * @param density The preferred density of the icon, zero for default density.
+     * @param density The preferred density of the icon, zero for default density. Use
+     * density DPI values from {@link DisplayMetrics}.
      * @see #getBadgedIcon(int)
+     * @see DisplayMetrics
      * @return The drawable associated with the activity
      */
     public Drawable getIcon(int density) {
@@ -109,15 +119,25 @@
 
     /**
      * Returns the application flags from the ApplicationInfo of the activity.
-     * 
+     *
      * @return Application flags
+     * @hide remove before shipping
      */
     public int getApplicationFlags() {
         return mActivityInfo.applicationInfo.flags;
     }
 
     /**
+     * Returns the application info for the appliction this activity belongs to.
+     * @return
+     */
+    public ApplicationInfo getApplicationInfo() {
+        return mActivityInfo.applicationInfo;
+    }
+
+    /**
      * Returns the time at which the package was first installed.
+     *
      * @return The time of installation of the package, in milliseconds.
      */
     public long getFirstInstallTime() {
@@ -134,7 +154,9 @@
 
     /**
      * Returns the activity icon with badging appropriate for the profile.
-     * @param density Optional density for the icon, or 0 to use the default density.
+     * @param density Optional density for the icon, or 0 to use the default density. Use
+     * {@link DisplayMetrics} for DPI values.
+     * @see DisplayMetrics
      * @return A badged icon for the activity.
      */
     public Drawable getBadgedIcon(int density) {
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8025b60..04c0b9f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -16,15 +16,18 @@
 
 package android.content.pm;
 
+import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ILauncherApps;
 import android.content.pm.IOnAppsChangedListener;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Log;
 
 import java.util.ArrayList;
@@ -36,6 +39,12 @@
  * managed profiles. This is mainly for use by launchers. Apps can be queried for each user profile.
  * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
  * for package changes here.
+ * <p>
+ * To watch for managed profiles being added or removed, register for the following broadcasts:
+ * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
+ * <p>
+ * You can retrieve the list of profiles associated with this user with
+ * {@link UserManager#getUserProfiles()}.
  */
 public class LauncherApps {
 
@@ -44,12 +53,13 @@
 
     private Context mContext;
     private ILauncherApps mService;
+    private PackageManager mPm;
 
     private List<OnAppsChangedListener> mListeners
             = new ArrayList<OnAppsChangedListener>();
 
     /**
-     * Callbacks for changes to this and related managed profiles.
+     * Callbacks for package changes to this and related managed profiles.
      */
     public interface OnAppsChangedListener {
         /**
@@ -57,6 +67,7 @@
          *
          * @param user The UserHandle of the profile that generated the change.
          * @param packageName The name of the package that was removed.
+         * @hide remove before ship
          */
         void onPackageRemoved(UserHandle user, String packageName);
 
@@ -65,6 +76,7 @@
          *
          * @param user The UserHandle of the profile that generated the change.
          * @param packageName The name of the package that was added.
+         * @hide remove before ship
          */
         void onPackageAdded(UserHandle user, String packageName);
 
@@ -73,6 +85,7 @@
          *
          * @param user The UserHandle of the profile that generated the change.
          * @param packageName The name of the package that has changed.
+         * @hide remove before ship
          */
         void onPackageChanged(UserHandle user, String packageName);
 
@@ -86,6 +99,7 @@
          *            available.
          * @param replacing Indicates whether these packages are replacing
          *            existing ones.
+         * @hide remove before ship
          */
         void onPackagesAvailable(UserHandle user, String[] packageNames, boolean replacing);
 
@@ -99,14 +113,66 @@
          *            unavailable.
          * @param replacing Indicates whether the packages are about to be
          *            replaced with new versions.
+         * @hide remove before ship
          */
         void onPackagesUnavailable(UserHandle user, String[] packageNames, boolean replacing);
+
+        /**
+         * Indicates that a package was removed from the specified profile.
+         *
+         * @param packageName The name of the package that was removed.
+         * @param user The UserHandle of the profile that generated the change.
+         */
+        void onPackageRemoved(String packageName, UserHandle user);
+
+        /**
+         * Indicates that a package was added to the specified profile.
+         *
+         * @param packageName The name of the package that was added.
+         * @param user The UserHandle of the profile that generated the change.
+         */
+        void onPackageAdded(String packageName, UserHandle user);
+
+        /**
+         * Indicates that a package was modified in the specified profile.
+         *
+         * @param packageName The name of the package that has changed.
+         * @param user The UserHandle of the profile that generated the change.
+         */
+        void onPackageChanged(String packageName, UserHandle user);
+
+        /**
+         * Indicates that one or more packages have become available. For
+         * example, this can happen when a removable storage card has
+         * reappeared.
+         *
+         * @param packageNames The names of the packages that have become
+         *            available.
+         * @param user The UserHandle of the profile that generated the change.
+         * @param replacing Indicates whether these packages are replacing
+         *            existing ones.
+         */
+        void onPackagesAvailable(String [] packageNames, UserHandle user, boolean replacing);
+
+        /**
+         * Indicates that one or more packages have become unavailable. For
+         * example, this can happen when a removable storage card has been
+         * removed.
+         *
+         * @param packageNames The names of the packages that have become
+         *            unavailable.
+         * @param user The UserHandle of the profile that generated the change.
+         * @param replacing Indicates whether the packages are about to be
+         *            replaced with new versions.
+         */
+        void onPackagesUnavailable(String[] packageNames, UserHandle user, boolean replacing);
     }
 
     /** @hide */
     public LauncherApps(Context context, ILauncherApps service) {
         mContext = context;
         mService = service;
+        mPm = context.getPackageManager();
     }
 
     /**
@@ -131,7 +197,15 @@
         final int count = activities.size();
         for (int i = 0; i < count; i++) {
             ResolveInfo ri = activities.get(i);
-            LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri, user);
+            long firstInstallTime = 0;
+            try {
+                firstInstallTime = mPm.getPackageInfo(ri.activityInfo.packageName,
+                    PackageManager.GET_UNINSTALLED_PACKAGES).firstInstallTime;
+            } catch (NameNotFoundException nnfe) {
+                // Sorry, can't find package
+            }
+            LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri, user,
+                    firstInstallTime);
             if (DEBUG) {
                 Log.v(TAG, "Returning activity for profile " + user + " : "
                         + lai.getComponentName());
@@ -157,7 +231,15 @@
         try {
             ResolveInfo ri = mService.resolveActivity(intent, user);
             if (ri != null) {
-                LauncherActivityInfo info = new LauncherActivityInfo(mContext, ri, user);
+                long firstInstallTime = 0;
+                try {
+                    firstInstallTime = mPm.getPackageInfo(ri.activityInfo.packageName,
+                            PackageManager.GET_UNINSTALLED_PACKAGES).firstInstallTime;
+                } catch (NameNotFoundException nnfe) {
+                    // Sorry, can't find package
+                }
+                LauncherActivityInfo info = new LauncherActivityInfo(mContext, ri, user,
+                        firstInstallTime);
                 return info;
             }
         } catch (RemoteException re) {
@@ -173,9 +255,23 @@
      * @param sourceBounds The Rect containing the source bounds of the clicked icon
      * @param opts Options to pass to startActivity
      * @param user The UserHandle of the profile
+     * @hide remove before ship
      */
     public void startActivityForProfile(ComponentName component, Rect sourceBounds,
             Bundle opts, UserHandle user) {
+        startActivityForProfile(component, user, sourceBounds, opts);
+    }
+
+    /**
+     * Starts an activity in the specified profile.
+     *
+     * @param component The ComponentName of the activity to launch
+     * @param user The UserHandle of the profile
+     * @param sourceBounds The Rect containing the source bounds of the clicked icon
+     * @param opts Options to pass to startActivity
+     */
+    public void startActivityForProfile(ComponentName component, UserHandle user, Rect sourceBounds,
+            Bundle opts) {
         if (DEBUG) {
             Log.i(TAG, "StartActivityForProfile " + component + " " + user.getIdentifier());
         }
@@ -224,13 +320,15 @@
      *
      * @param listener The listener to add.
      */
-    public synchronized void addOnAppsChangedListener(OnAppsChangedListener listener) {
-        if (listener != null && !mListeners.contains(listener)) {
-            mListeners.add(listener);
-            if (mListeners.size() == 1) {
-                try {
-                    mService.addOnAppsChangedListener(mAppsChangedListener);
-                } catch (RemoteException re) {
+    public void addOnAppsChangedListener(OnAppsChangedListener listener) {
+        synchronized (this) {
+            if (listener != null && !mListeners.contains(listener)) {
+                mListeners.add(listener);
+                if (mListeners.size() == 1) {
+                    try {
+                        mService.addOnAppsChangedListener(mAppsChangedListener);
+                    } catch (RemoteException re) {
+                    }
                 }
             }
         }
@@ -242,12 +340,14 @@
      * @param listener The listener to remove.
      * @see #addOnAppsChangedListener(OnAppsChangedListener)
      */
-    public synchronized void removeOnAppsChangedListener(OnAppsChangedListener listener) {
-        mListeners.remove(listener);
-        if (mListeners.size() == 0) {
-            try {
-                mService.removeOnAppsChangedListener(mAppsChangedListener);
-            } catch (RemoteException re) {
+    public void removeOnAppsChangedListener(OnAppsChangedListener listener) {
+        synchronized (this) {
+            mListeners.remove(listener);
+            if (mListeners.size() == 0) {
+                try {
+                    mService.removeOnAppsChangedListener(mAppsChangedListener);
+                } catch (RemoteException re) {
+                }
             }
         }
     }
@@ -261,7 +361,8 @@
             }
             synchronized (LauncherApps.this) {
                 for (OnAppsChangedListener listener : mListeners) {
-                    listener.onPackageRemoved(user, packageName);
+                    listener.onPackageRemoved(user, packageName); // TODO: Remove before ship
+                    listener.onPackageRemoved(packageName, user);
                 }
             }
         }
@@ -273,7 +374,8 @@
             }
             synchronized (LauncherApps.this) {
                 for (OnAppsChangedListener listener : mListeners) {
-                    listener.onPackageChanged(user, packageName);
+                    listener.onPackageChanged(user, packageName); // TODO: Remove before ship
+                    listener.onPackageChanged(packageName, user);
                 }
             }
         }
@@ -285,7 +387,8 @@
             }
             synchronized (LauncherApps.this) {
                 for (OnAppsChangedListener listener : mListeners) {
-                    listener.onPackageAdded(user, packageName);
+                    listener.onPackageAdded(user, packageName); // TODO: Remove before ship
+                    listener.onPackageAdded(packageName, user);
                 }
             }
         }
@@ -298,7 +401,8 @@
             }
             synchronized (LauncherApps.this) {
                 for (OnAppsChangedListener listener : mListeners) {
-                    listener.onPackagesAvailable(user, packageNames, replacing);
+                    listener.onPackagesAvailable(user, packageNames, replacing); // TODO: Remove
+                    listener.onPackagesAvailable(packageNames, user, replacing);
                 }
             }
         }
@@ -311,7 +415,8 @@
             }
             synchronized (LauncherApps.this) {
                 for (OnAppsChangedListener listener : mListeners) {
-                    listener.onPackagesUnavailable(user, packageNames, replacing);
+                    listener.onPackagesUnavailable(user, packageNames, replacing); // TODO: Remove
+                    listener.onPackagesUnavailable(packageNames, user, replacing);
                 }
             }
         }
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index b0449224..cabda5d 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -2,6 +2,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.List;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -21,6 +22,8 @@
  * <p>The format of AIDs is defined in the ISO/IEC 7816-4 specification. This class
  * requires the AIDs to be input as a hexadecimal string, with an even amount of
  * hexadecimal characters, e.g. "F014811481".
+ *
+ * @hide
  */
 public final class AidGroup implements Parcelable {
     /**
@@ -30,7 +33,7 @@
 
     static final String TAG = "AidGroup";
 
-    final ArrayList<String> aids;
+    final List<String> aids;
     final String category;
     final String description;
 
@@ -40,7 +43,7 @@
      * @param aids The list of AIDs present in the group
      * @param category The category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
      */
-    public AidGroup(ArrayList<String> aids, String category) {
+    public AidGroup(List<String> aids, String category) {
         if (aids == null || aids.size() == 0) {
             throw new IllegalArgumentException("No AIDS in AID group.");
         }
@@ -72,7 +75,7 @@
     /**
      * @return the list of  AIDs in this group
      */
-    public ArrayList<String> getAids() {
+    public List<String> getAids() {
         return aids;
     }
 
@@ -121,11 +124,6 @@
         }
     };
 
-    /**
-     * @hide
-     * Note: description is not serialized, since it's not localized
-     * and resource identifiers don't make sense to persist.
-     */
     static public AidGroup createFromXml(XmlPullParser parser) throws XmlPullParserException, IOException {
         String category = parser.getAttributeValue(null, "category");
         ArrayList<String> aids = new ArrayList<String>();
@@ -152,9 +150,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
     public void writeAsXml(XmlSerializer out) throws IOException {
         out.attribute(null, "category", category);
         for (String aid : aids) {
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index e24a22a..4b9e890 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -303,12 +303,13 @@
     }
 
     /**
-     * Registers a group of AIDs for the specified service.
+     * Registers a list of AIDs for a specific category for the
+     * specified service.
      *
-     * <p>If an AID group for that category was previously
+     * <p>If a list of AIDs for that category was previously
      * registered for this service (either statically
      * through the manifest, or dynamically by using this API),
-     * that AID group will be replaced with this one.
+     * that list of AIDs will be replaced with this one.
      *
      * <p>Note that you can only register AIDs for a service that
      * is running under the same UID as the caller of this API. Typically
@@ -317,10 +318,13 @@
      * be shared between packages using shared UIDs.
      *
      * @param service The component name of the service
-     * @param aidGroup The group of AIDs to be registered
+     * @param category The category of AIDs to be registered
+     * @param aids A list containing the AIDs to be registered
      * @return whether the registration was successful.
      */
-    public boolean registerAidGroupForService(ComponentName service, AidGroup aidGroup) {
+    public boolean registerAidsForService(ComponentName service, String category,
+            List<String> aids) {
+        AidGroup aidGroup = new AidGroup(aids, category);
         try {
             return sService.registerAidGroupForService(UserHandle.myUserId(), service, aidGroup);
         } catch (RemoteException e) {
@@ -341,21 +345,24 @@
     }
 
     /**
-     * Retrieves the currently registered AID group for the specified
+     * Retrieves the currently registered AIDs for the specified
      * category for a service.
      *
-     * <p>Note that this will only return AID groups that were dynamically
-     * registered using {@link #registerAidGroupForService(ComponentName, AidGroup)}
-     * method. It will *not* return AID groups that were statically registered
+     * <p>Note that this will only return AIDs that were dynamically
+     * registered using {@link #registerAidsForService(ComponentName, String, List)}
+     * method. It will *not* return AIDs that were statically registered
      * in the manifest.
      *
      * @param service The component name of the service
-     * @param category The category of the AID group to be returned, e.g. {@link #CATEGORY_PAYMENT}
-     * @return The AID group, or null if it couldn't be found
+     * @param category The category for which the AIDs were registered,
+     *                 e.g. {@link #CATEGORY_PAYMENT}
+     * @return The list of AIDs registered for this category, or null if it couldn't be found.
      */
-    public AidGroup getAidGroupForService(ComponentName service, String category) {
+    public List<String> getAidsForService(ComponentName service, String category) {
         try {
-            return sService.getAidGroupForService(UserHandle.myUserId(), service, category);
+            AidGroup group =  sService.getAidGroupForService(UserHandle.myUserId(), service,
+                    category);
+            return (group != null ? group.getAids() : null);
         } catch (RemoteException e) {
             recoverService();
             if (sService == null) {
@@ -363,7 +370,9 @@
                 return null;
             }
             try {
-                return sService.getAidGroupForService(UserHandle.myUserId(), service, category);
+                AidGroup group = sService.getAidGroupForService(UserHandle.myUserId(), service,
+                        category);
+                return (group != null ? group.getAids() : null);
             } catch (RemoteException ee) {
                 Log.e(TAG, "Failed to recover CardEmulationService.");
                 return null;
@@ -372,21 +381,21 @@
     }
 
     /**
-     * Removes a registered AID group for the specified category for the
+     * Removes a previously registered list of AIDs for the specified category for the
      * service provided.
      *
-     * <p>Note that this will only remove AID groups that were dynamically
-     * registered using the {@link #registerAidGroupForService(ComponentName, AidGroup)}
-     * method. It will *not* remove AID groups that were statically registered in
-     * the manifest. If a dynamically registered AID group is removed using
+     * <p>Note that this will only remove AIDs that were dynamically
+     * registered using the {@link #registerAidsForService(ComponentName, String, List)}
+     * method. It will *not* remove AIDs that were statically registered in
+     * the manifest. If dynamically registered AIDs are removed using
      * this method, and a statically registered AID group for the same category
      * exists in the manifest, the static AID group will become active again.
      *
      * @param service The component name of the service
-     * @param category The category of the AID group to be removed, e.g. {@link #CATEGORY_PAYMENT}
+     * @param category The category of the AIDs to be removed, e.g. {@link #CATEGORY_PAYMENT}
      * @return whether the group was successfully removed.
      */
-    public boolean removeAidGroupForService(ComponentName service, String category) {
+    public boolean removeAidsForService(ComponentName service, String category) {
         try {
             return sService.removeAidGroupForService(UserHandle.myUserId(), service, category);
         } catch (RemoteException e) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtilsCache.java b/core/java/com/android/internal/widget/LockPatternUtilsCache.java
index 550aa6d..624f67c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtilsCache.java
+++ b/core/java/com/android/internal/widget/LockPatternUtilsCache.java
@@ -28,6 +28,11 @@
  */
 public class LockPatternUtilsCache implements ILockSettings {
 
+    private static final String HAS_LOCK_PATTERN_CACHE_KEY
+            = "LockPatternUtils.Cache.HasLockPatternCacheKey";
+    private static final String HAS_LOCK_PASSWORD_CACHE_KEY
+            = "LockPatternUtils.Cache.HasLockPasswordCacheKey";
+
     private static LockPatternUtilsCache sInstance;
 
     private final ILockSettings mService;
@@ -109,7 +114,9 @@
 
     @Override
     public void setLockPattern(String pattern, int userId) throws RemoteException {
+        invalidateCache(HAS_LOCK_PATTERN_CACHE_KEY, userId);
         mService.setLockPattern(pattern, userId);
+        putCache(HAS_LOCK_PATTERN_CACHE_KEY, userId, pattern != null);
     }
 
     @Override
@@ -119,7 +126,9 @@
 
     @Override
     public void setLockPassword(String password, int userId) throws RemoteException {
+        invalidateCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId);
         mService.setLockPassword(password, userId);
+        putCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId, password != null);
     }
 
     @Override
@@ -134,12 +143,24 @@
 
     @Override
     public boolean havePattern(int userId) throws RemoteException {
-        return mService.havePattern(userId);
+        Object value = peekCache(HAS_LOCK_PATTERN_CACHE_KEY, userId);
+        if (value instanceof Boolean) {
+            return (boolean) value;
+        }
+        boolean result = mService.havePattern(userId);
+        putCache(HAS_LOCK_PATTERN_CACHE_KEY, userId, result);
+        return result;
     }
 
     @Override
     public boolean havePassword(int userId) throws RemoteException {
-        return mService.havePassword(userId);
+        Object value = peekCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId);
+        if (value instanceof Boolean) {
+            return (boolean) value;
+        }
+        boolean result = mService.havePassword(userId);
+        putCache(HAS_LOCK_PASSWORD_CACHE_KEY, userId, result);
+        return result;
     }
 
     @Override
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 36ed344..d841d53 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -57,6 +57,7 @@
     private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
 
     private static final boolean PROFILE_DRAWING = false;
+    private final CellState[][] mCellStates;
     private boolean mDrawingProfilingStarted = false;
 
     private Paint mPaint = new Paint();
@@ -187,6 +188,12 @@
         }
     }
 
+    public static class CellState {
+        public float scale = 1.0f;
+        public float translateY = 0.0f;
+        public float alpha = 1.0f;
+     }
+
     /**
      * How to display the current pattern.
      */
@@ -296,6 +303,18 @@
             mBitmapHeight = Math.max(mBitmapHeight, bitmap.getHeight());
         }
 
+        mPaint.setFilterBitmap(true);
+
+        mCellStates = new CellState[3][3];
+        for (int i = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++) {
+                mCellStates[i][j] = new CellState();
+            }
+        }
+    }
+
+    public CellState[][] getCellStates() {
+        return mCellStates;
     }
 
     private Bitmap getBitmapFor(int resId) {
@@ -873,18 +892,22 @@
             //float centerY = mPaddingTop + i * mSquareHeight + (mSquareHeight / 2);
             for (int j = 0; j < 3; j++) {
                 float leftX = paddingLeft + j * squareWidth;
-                drawCircle(canvas, (int) leftX, (int) topY, drawLookup[i][j]);
+                float scale = mCellStates[i][j].scale;
+                mPaint.setAlpha((int) (mCellStates[i][j].alpha * 255));
+                float translationY = mCellStates[i][j].translateY;
+                drawCircle(canvas, (int) leftX, (int) topY + translationY, scale, drawLookup[i][j]);
             }
         }
 
+        // Reset the alpha to draw normally
+        mPaint.setAlpha(255);
+
         // TODO: the path should be created and cached every time we hit-detect a cell
         // only the last segment of the path should be computed here
         // draw the path of the pattern (unless we are in stealth mode)
         final boolean drawPath = !mInStealthMode;
 
         // draw the arrows associated with the path (unless we are in stealth mode)
-        boolean oldFlag = (mPaint.getFlags() & Paint.FILTER_BITMAP_FLAG) != 0;
-        mPaint.setFilterBitmap(true); // draw with higher quality since we render with transforms
         if (drawPath) {
             for (int i = 0; i < count - 1; i++) {
                 Cell cell = pattern.get(i);
@@ -898,7 +921,8 @@
                 }
 
                 float leftX = paddingLeft + cell.column * squareWidth;
-                float topY = paddingTop + cell.row * squareHeight;
+                float topY = paddingTop + cell.row * squareHeight
+                        + mCellStates[cell.row][cell.column].translateY;
 
                 drawArrow(canvas, leftX, topY, cell, next);
             }
@@ -919,6 +943,9 @@
 
                 float centerX = getCenterXForColumn(cell.column);
                 float centerY = getCenterYForRow(cell.row);
+
+                // Respect translation in animation
+                centerY += mCellStates[cell.row][cell.column].translateY;
                 if (i == 0) {
                     currentPath.moveTo(centerX, centerY);
                 } else {
@@ -933,8 +960,6 @@
             }
             canvas.drawPath(currentPath, mPathPaint);
         }
-
-        mPaint.setFilterBitmap(oldFlag); // restore default flag
     }
 
     private void drawArrow(Canvas canvas, float leftX, float topY, Cell start, Cell end) {
@@ -979,7 +1004,8 @@
      * @param topY
      * @param partOfPattern Whether this circle is part of the pattern.
      */
-    private void drawCircle(Canvas canvas, int leftX, int topY, boolean partOfPattern) {
+    private void drawCircle(Canvas canvas, float leftX, float topY, float scale,
+            boolean partOfPattern) {
         Bitmap outerCircle;
         Bitmap innerCircle;
 
@@ -1019,7 +1045,7 @@
 
         mCircleMatrix.setTranslate(leftX + offsetX, topY + offsetY);
         mCircleMatrix.preTranslate(mBitmapWidth/2, mBitmapHeight/2);
-        mCircleMatrix.preScale(sx, sy);
+        mCircleMatrix.preScale(sx * scale, sy * scale);
         mCircleMatrix.preTranslate(-mBitmapWidth/2, -mBitmapHeight/2);
 
         canvas.drawBitmap(outerCircle, mCircleMatrix, mPaint);
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index 01d9ab3..e9cdfcd 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -162,5 +162,5 @@
     <dimen name="big_font_size">120dp</dimen>
 
     <!-- The y translation to apply at the start in appear animations. -->
-    <dimen name="appear_y_translation_start">24dp</dimen>
+    <dimen name="appear_y_translation_start">32dp</dimen>
 </resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java b/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
new file mode 100644
index 0000000..0d30ea6
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 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.keyguard;
+
+import android.animation.Animator;
+import android.view.animation.Interpolator;
+
+/**
+ * An interface which can create animations when starting an appear animation with
+ * {@link com.android.keyguard.AppearAnimationUtils}
+ */
+public interface AppearAnimationCreator<T> {
+     void createAnimation(T animatedObject, long delay, long duration,
+            float startTranslationY, Interpolator interpolator, Runnable finishListener);
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java b/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
index ea896d5..6bb1f2c 100644
--- a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
+++ b/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
@@ -16,84 +16,124 @@
 
 package com.android.keyguard;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
 import android.content.Context;
 import android.view.View;
-import android.view.ViewPropertyAnimator;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
 /**
  * A class to make nice appear transitions for views in a tabular layout.
  */
-public class AppearAnimationUtils {
+public class AppearAnimationUtils implements AppearAnimationCreator<View> {
 
     public static final long APPEAR_DURATION = 220;
 
     private final Interpolator mLinearOutSlowIn;
     private final float mStartTranslation;
+    private final AppearAnimationProperties mProperties = new AppearAnimationProperties();
+    private final float mDelayScale;
 
     public AppearAnimationUtils(Context ctx) {
-        mLinearOutSlowIn = AnimationUtils.loadInterpolator(
-                ctx, android.R.interpolator.linear_out_slow_in);
-        mStartTranslation =
-                ctx.getResources().getDimensionPixelOffset(R.dimen.appear_y_translation_start);
+        this(ctx, 1.0f, 1.0f);
     }
 
-    public void startAppearAnimation(View[][] views, final Runnable finishListener) {
+    public AppearAnimationUtils(Context ctx, float delayScaleFactor,
+            float translationScaleFactor) {
+        mLinearOutSlowIn = AnimationUtils.loadInterpolator(
+                ctx, android.R.interpolator.linear_out_slow_in);
+        mStartTranslation = ctx.getResources().getDimensionPixelOffset(
+                R.dimen.appear_y_translation_start) * translationScaleFactor;
+        mDelayScale = delayScaleFactor;
+    }
+
+    public void startAppearAnimation(View[][] objects, final Runnable finishListener) {
+        startAppearAnimation(objects, finishListener, this);
+    }
+
+    public <T> void startAppearAnimation(T[][] objects, final Runnable finishListener,
+            AppearAnimationCreator<T> creator) {
+        AppearAnimationProperties properties = getDelays(objects);
+        startAnimations(properties, objects, finishListener, creator);
+    }
+
+    private <T> void startAnimations(AppearAnimationProperties properties, T[][] objects,
+            final Runnable finishListener, AppearAnimationCreator creator) {;
+        if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) {
+            finishListener.run();
+            return;
+        }
+        for (int row = 0; row < properties.delays.length; row++) {
+            long[] columns = properties.delays[row];
+            for (int col = 0; col < columns.length; col++) {
+                long delay = columns[col];
+                Runnable endRunnable = null;
+                if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == col) {
+                    endRunnable = finishListener;
+                }
+                creator.createAnimation(objects[row][col], delay, APPEAR_DURATION,
+                        mStartTranslation, mLinearOutSlowIn, endRunnable);
+            }
+        }
+
+    }
+
+    private <T> AppearAnimationProperties getDelays(T[][] items) {
         long maxDelay = 0;
-        ViewPropertyAnimator maxDelayAnimator = null;
-        for (int row = 0; row < views.length; row++) {
-            View[] columns = views[row];
+        mProperties.maxDelayColIndex = -1;
+        mProperties.maxDelayRowIndex = -1;
+        mProperties.delays = new long[items.length][];
+        for (int row = 0; row < items.length; row++) {
+            T[] columns = items[row];
+            mProperties.delays[row] = new long[columns.length];
             for (int col = 0; col < columns.length; col++) {
                 long delay = calculateDelay(row, col);
-                ViewPropertyAnimator animator = startAppearAnimation(columns[col], delay);
-                if (animator != null && delay > maxDelay) {
+                mProperties.delays[row][col] = delay;
+                if (items[row][col] != null && delay > maxDelay) {
                     maxDelay = delay;
-                    maxDelayAnimator = animator;
+                    mProperties.maxDelayColIndex = col;
+                    mProperties.maxDelayRowIndex = row;
                 }
             }
         }
-        if (maxDelayAnimator != null) {
-            maxDelayAnimator.setListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    finishListener.run();
-                }
-            });
-        } else {
-            finishListener.run();
-        }
-    }
-
-    private ViewPropertyAnimator startAppearAnimation(View view, long delay) {
-        if (view == null) return null;
-        view.setAlpha(0f);
-        view.setTranslationY(mStartTranslation);
-        view.animate()
-                .alpha(1f)
-                .translationY(0)
-                .setInterpolator(mLinearOutSlowIn)
-                .setDuration(APPEAR_DURATION)
-                .setStartDelay(delay)
-                .setListener(null);
-        if (view.hasOverlappingRendering()) {
-            view.animate().withLayer();
-        }
-        return view.animate();
+        return mProperties;
     }
 
     private long calculateDelay(int row, int col) {
-        return (long) (row * 40 + col * (Math.pow(row, 0.4) + 0.4) * 20);
+        return (long) ((row * 40 + col * (Math.pow(row, 0.4) + 0.4) * 20) * mDelayScale);
     }
 
-    public TimeInterpolator getInterpolator() {
+    public Interpolator getInterpolator() {
         return mLinearOutSlowIn;
     }
 
     public float getStartTranslation() {
         return mStartTranslation;
     }
+
+    @Override
+    public void createAnimation(View view, long delay, long duration, float startTranslationY,
+            Interpolator interpolator, Runnable endRunnable) {
+        if (view != null) {
+            view.setAlpha(0f);
+            view.setTranslationY(startTranslationY);
+            view.animate()
+                    .alpha(1f)
+                    .translationY(0)
+                    .setInterpolator(interpolator)
+                    .setDuration(duration)
+                    .setStartDelay(delay);
+            if (view.hasOverlappingRendering()) {
+                view.animate().withLayer();
+            }
+            if (endRunnable != null) {
+                view.animate().withEndAction(endRunnable);
+            }
+        }
+    }
+
+    public class AppearAnimationProperties {
+        public long[][] delays;
+        public int maxDelayRowIndex;
+        public int maxDelayColIndex;
+    }
 }
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 5853ff9..e6de72f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -21,6 +21,9 @@
 import android.accounts.AccountManagerFuture;
 import android.accounts.AuthenticatorException;
 import android.accounts.OperationCanceledException;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -28,10 +31,13 @@
 import android.os.CountDownTimer;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Interpolator;
 import android.widget.Button;
 import android.widget.LinearLayout;
 
@@ -41,7 +47,8 @@
 import java.io.IOException;
 import java.util.List;
 
-public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView {
+public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView,
+        AppearAnimationCreator<LockPatternView.CellState> {
 
     private static final String TAG = "SecurityPatternView";
     private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -59,6 +66,7 @@
     private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
 
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+    private final AppearAnimationUtils mAppearAnimationUtils;
 
     private CountDownTimer mCountdownTimer = null;
     private LockPatternUtils mLockPatternUtils;
@@ -87,6 +95,8 @@
     private SecurityMessageDisplay mSecurityMessageDisplay;
     private View mEcaView;
     private Drawable mBouncerFrame;
+    private ViewGroup mKeyguardBouncerFrame;
+    private KeyguardMessageArea mHelpMessage;
 
     enum FooterMode {
         Normal,
@@ -101,6 +111,8 @@
     public KeyguardPatternView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
+        mAppearAnimationUtils = new AppearAnimationUtils(context, 1.5f /* delayScale */,
+                2.0f /* transitionScale */);
     }
 
     public void setKeyguardCallback(KeyguardSecurityCallback callback) {
@@ -148,6 +160,9 @@
         if (bouncerFrameView != null) {
             mBouncerFrame = bouncerFrameView.getBackground();
         }
+
+        mKeyguardBouncerFrame = (ViewGroup) findViewById(R.id.keyguard_bouncer_frame);
+        mHelpMessage = (KeyguardMessageArea) findViewById(R.id.keyguard_message_area);
     }
 
     private void updateFooter(FooterMode mode) {
@@ -403,8 +418,69 @@
 
     @Override
     public void startAppearAnimation() {
-        // TODO: Fancy animation.
-        setAlpha(0);
-        animate().alpha(1).withLayer().setDuration(200);
+        enableClipping(false);
+        mAppearAnimationUtils.startAppearAnimation(
+                mLockPatternView.getCellStates(),
+                new Runnable() {
+                    @Override
+                    public void run() {
+                        enableClipping(true);
+                    }
+                },
+                this);
+        if (!TextUtils.isEmpty(mHelpMessage.getText())) {
+            mAppearAnimationUtils.createAnimation(mHelpMessage, 0,
+                    AppearAnimationUtils.APPEAR_DURATION,
+                    mAppearAnimationUtils.getStartTranslation(),
+                    mAppearAnimationUtils.getInterpolator(),
+                    null /* finishRunnable */);
+        }
+    }
+
+    private void enableClipping(boolean enable) {
+        setClipChildren(enable);
+        mKeyguardBouncerFrame.setClipToPadding(enable);
+        mKeyguardBouncerFrame.setClipChildren(enable);
+    }
+
+    @Override
+    public void createAnimation(final LockPatternView.CellState animatedCell, long delay,
+            long duration, float startTranslationY, Interpolator interpolator,
+            final Runnable finishListener) {
+        animatedCell.scale = 0.0f;
+        animatedCell.translateY = startTranslationY;
+        ValueAnimator animator = ValueAnimator.ofFloat(startTranslationY, 0.0f);
+        animator.setInterpolator(interpolator);
+        animator.setDuration(duration);
+        animator.setStartDelay(delay);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                float animatedFraction = animation.getAnimatedFraction();
+                animatedCell.scale = animatedFraction;
+                animatedCell.translateY = (float) animation.getAnimatedValue();
+                mLockPatternView.invalidate();
+            }
+        });
+        if (finishListener != null) {
+            animator.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    finishListener.run();
+                }
+            });
+
+            // Also animate the Emergency call
+            mAppearAnimationUtils.createAnimation(mEcaView, delay, duration, startTranslationY,
+            interpolator, null);
+
+            // And the forgot pattern button
+            if (mForgotPatternButton.getVisibility() == View.VISIBLE) {
+                mAppearAnimationUtils.createAnimation(mForgotPatternButton, delay, duration,
+                        startTranslationY, interpolator, null);
+            }
+        }
+        animator.start();
+        mLockPatternView.invalidate();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 21b41c7..422d47f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -83,6 +83,7 @@
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Locale;
 
@@ -117,6 +118,9 @@
     public static final int EXPANDED_LEAVE_ALONE = -10000;
     public static final int EXPANDED_FULL_OPEN = -10001;
 
+    /** If true, delays dismissing the Keyguard until the ActivityManager calls back. */
+    protected static final boolean DELAY_DISMISS_TO_ACTIVITY_LAUNCH = false;
+
     protected CommandQueue mCommandQueue;
     protected IStatusBarService mBarService;
     protected H mHandler = createHandler();
@@ -228,7 +232,7 @@
             }
             final boolean isActivity = pendingIntent.isActivity();
             if (isActivity) {
-                startNotificationActivity(new OnDismissAction() {
+                dismissKeyguardThenExecute(new OnDismissAction() {
                     @Override
                     public boolean onDismiss() {
                         try {
@@ -250,7 +254,8 @@
                             animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
                             visibilityChanged(false);
                         }
-                        return handled; // Wait for activity start.
+                        // Wait for activity start.
+                        return handled && DELAY_DISMISS_TO_ACTIVITY_LAUNCH;
                     }
                 });
                 return true;
@@ -479,7 +484,7 @@
      * Takes the necessary steps to prepare the status bar for starting an activity, then starts it.
      * @param action A dismiss action that is called if it's safe to start the activity.
      */
-    protected void startNotificationActivity(OnDismissAction action) {
+    protected void dismissKeyguardThenExecute(OnDismissAction action) {
         action.onDismiss();
     }
 
@@ -1049,7 +1054,7 @@
         }
 
         public void onClick(final View v) {
-            startNotificationActivity(new OnDismissAction() {
+            dismissKeyguardThenExecute(new OnDismissAction() {
                 public boolean onDismiss() {
                     try {
                         // The intent we are sending is for the application, which
@@ -1069,7 +1074,7 @@
                         v.getLocationOnScreen(pos);
                         Intent overlay = new Intent();
                         overlay.setSourceBounds(new Rect(pos[0], pos[1],
-                                pos[0]+v.getWidth(), pos[1]+v.getHeight()));
+                                pos[0] + v.getWidth(), pos[1] + v.getHeight()));
                         try {
                             mIntent.send(mContext, 0, overlay);
                             sent = true;
@@ -1094,7 +1099,7 @@
                     visibilityChanged(false);
 
                     boolean waitForActivityLaunch = sent && mIntent.isActivity();
-                    return waitForActivityLaunch;
+                    return waitForActivityLaunch && DELAY_DISMISS_TO_ACTIVITY_LAUNCH;
                 }
             });
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index dce5a30..365ee57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -48,6 +48,8 @@
         ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
         View.OnClickListener, KeyguardPageSwipeHelper.Callback {
 
+    private static float EXPANSION_RUBBER_BAND_EXTRA_FACTOR = 0.4f;
+
     private KeyguardPageSwipeHelper mPageSwiper;
     PhoneStatusBar mStatusBar;
     private StatusBarHeaderView mHeader;
@@ -743,8 +745,11 @@
     @Override
     protected void onOverExpansionChanged(float overExpansion) {
         float currentOverScroll = mNotificationStackScroller.getCurrentOverScrolledPixels(true);
-        mNotificationStackScroller.setOverScrolledPixels(currentOverScroll + overExpansion
-                        - mOverExpansion, true /* onTop */, false /* animate */);
+        float expansionChange = overExpansion - mOverExpansion;
+        expansionChange *= EXPANSION_RUBBER_BAND_EXTRA_FACTOR;
+        mNotificationStackScroller.setOverScrolledPixels(currentOverScroll + expansionChange,
+                true /* onTop */,
+                false /* animate */);
         super.onOverExpansionChanged(overExpansion);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 0e5b7e1..dedfff0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2348,16 +2348,24 @@
         }
     };
 
-    public void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
+    public void startActivityDismissingKeyguard(final Intent intent, boolean onlyProvisioned) {
         if (onlyProvisioned && !isDeviceProvisioned()) return;
-        try {
-            // Dismiss the lock screen when Settings starts.
-            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
-        } catch (RemoteException e) {
-        }
-        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-        mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
-        animateCollapsePanels();
+
+        dismissKeyguardThenExecute(new OnDismissAction() {
+            @Override
+            public boolean onDismiss() {
+                try {
+                    // Dismiss the lock screen when Settings starts.
+                    ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+                } catch (RemoteException e) {
+                }
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+                animateCollapsePanels();
+
+                return DELAY_DISMISS_TO_ACTIVITY_LAUNCH;
+            }
+        });
     }
 
     private View.OnClickListener mClockClickListener = new View.OnClickListener() {
@@ -2418,7 +2426,7 @@
     };
 
     @Override
-    protected void startNotificationActivity(OnDismissAction action) {
+    protected void dismissKeyguardThenExecute(OnDismissAction action) {
         if (mStatusBarKeyguardViewManager.isShowing()) {
             mStatusBarKeyguardViewManager.dismissWithAction(action);
         } else {
diff --git a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
index 3cf7e82..8c8209f 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java
@@ -30,6 +30,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 
 /**
  * Stores a mapping of global keys.
@@ -123,4 +124,21 @@
             }
         }
     }
+
+    public void dump(String prefix, PrintWriter pw) {
+        final int numKeys = mKeyMapping.size();
+        if (numKeys == 0) {
+            pw.print(prefix); pw.println("mKeyMapping.size=0");
+            return;
+        }
+        pw.print(prefix); pw.println("mKeyMapping={");
+        for (int i = 0; i < numKeys; ++i) {
+            pw.print("  ");
+            pw.print(prefix);
+            pw.print(KeyEvent.keyCodeToString(mKeyMapping.keyAt(i)));
+            pw.print("=");
+            pw.println(mKeyMapping.valueAt(i).flattenToString());
+        }
+        pw.print(prefix); pw.println("}");
+    }
 }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 27f7e07..c483836 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -5628,6 +5628,7 @@
         pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation);
                 pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock);
         pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
+        mGlobalKeyManager.dump(prefix, pw);
         mStatusBarController.dump(pw, prefix);
         mNavigationBarController.dump(pw, prefix);
         PolicyControl.dump(prefix, pw);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 1157de7d..963117c 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -216,6 +216,18 @@
      * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
      */
     public String BSSID;
+    /**
+     * Fully qualified domain name (FQDN), for Passpoint credential.
+     * e.g. {@code "mail.example.com"}.
+     * @hide
+     */
+    public String FQDN;
+    /**
+     * Network access identifier (NAI) realm, for Passpoint credential.
+     * e.g. {@code "myhost.example.com"}.
+     * @hide
+     */
+    public String naiRealm;
 
     /**
      * Pre-shared key for use with WPA-PSK.
@@ -484,6 +496,8 @@
         networkId = INVALID_NETWORK_ID;
         SSID = null;
         BSSID = null;
+        FQDN = null;
+        naiRealm = null;
         priority = 0;
         hiddenSSID = false;
         disableReason = DISABLED_UNKNOWN_REASON;
@@ -565,7 +579,8 @@
             sbuf.append("- DSBLE: ").append(this.disableReason).append(" ");
         }
         sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
-                append(" BSSID: ").append(this.BSSID).append(" PRIO: ").append(this.priority).
+                append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN).
+                append(" REALM: ").append(this.naiRealm).append(" PRIO: ").append(this.priority).
                 append('\n');
         sbuf.append(" KeyMgmt:");
         for (int k = 0; k < this.allowedKeyManagement.size(); k++) {
@@ -870,6 +885,8 @@
             disableReason = source.disableReason;
             SSID = source.SSID;
             BSSID = source.BSSID;
+            FQDN = source.FQDN;
+            naiRealm = source.naiRealm;
             preSharedKey = source.preSharedKey;
 
             wepKeys = new String[4];
@@ -932,6 +949,8 @@
         dest.writeInt(disableReason);
         dest.writeString(SSID);
         dest.writeString(BSSID);
+        dest.writeString(FQDN);
+        dest.writeString(naiRealm);
         dest.writeString(preSharedKey);
         for (String wepKey : wepKeys) {
             dest.writeString(wepKey);
@@ -976,6 +995,8 @@
                 config.disableReason = in.readInt();
                 config.SSID = in.readString();
                 config.BSSID = in.readString();
+                config.FQDN = in.readString();
+                config.naiRealm = in.readString();
                 config.preSharedKey = in.readString();
                 for (int i = 0; i < config.wepKeys.length; i++) {
                     config.wepKeys[i] = in.readString();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 141a69e..bf46745 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1413,12 +1413,14 @@
     /**
      * Passed with {@link ActionListener#onFailure}.
      * Indicates that the operation failed due to an internal error.
+     * @hide
      */
     public static final int ERROR                       = 0;
 
     /**
      * Passed with {@link ActionListener#onFailure}.
      * Indicates that the operation is already in progress
+     * @hide
      */
     public static final int IN_PROGRESS                 = 1;
 
@@ -1426,28 +1428,30 @@
      * Passed with {@link ActionListener#onFailure}.
      * Indicates that the operation failed because the framework is busy and
      * unable to service the request
+     * @hide
      */
     public static final int BUSY                        = 2;
 
     /* WPS specific errors */
-    /** WPS overlap detected */
+    /** WPS overlap detected {@hide} */
     public static final int WPS_OVERLAP_ERROR           = 3;
-    /** WEP on WPS is prohibited */
+    /** WEP on WPS is prohibited {@hide} */
     public static final int WPS_WEP_PROHIBITED          = 4;
-    /** TKIP only prohibited */
+    /** TKIP only prohibited {@hide} */
     public static final int WPS_TKIP_ONLY_PROHIBITED    = 5;
-    /** Authentication failure on WPS */
+    /** Authentication failure on WPS {@hide} */
     public static final int WPS_AUTH_FAILURE            = 6;
-    /** WPS timed out */
+    /** WPS timed out {@hide} */
     public static final int WPS_TIMED_OUT               = 7;
 
     /**
      * Passed with {@link ActionListener#onFailure}.
      * Indicates that the operation failed due to invalid inputs
+     * @hide
      */
     public static final int INVALID_ARGS                = 8;
 
-    /** Interface for callback invocation on an application action */
+    /** Interface for callback invocation on an application action {@hide} */
     public interface ActionListener {
         /** The operation succeeded */
         public void onSuccess();
@@ -1459,7 +1463,7 @@
         public void onFailure(int reason);
     }
 
-    /** Interface for callback invocation on a start WPS action */
+    /** Interface for callback invocation on a start WPS action {@hide} */
     public interface WpsListener {
         /** WPS start succeeded */
         public void onStartSuccess(String pin);
@@ -1741,6 +1745,7 @@
      * @param listener for callbacks on success or failure. Can be null.
      * @throws IllegalStateException if the WifiManager instance needs to be
      * initialized again
+     * @hide
      */
     public void startWps(WpsInfo config, WpsListener listener) {
         if (config == null) throw new IllegalArgumentException("config cannot be null");
@@ -1754,6 +1759,7 @@
      * @param listener for callbacks on success or failure. Can be null.
      * @throws IllegalStateException if the WifiManager instance needs to be
      * initialized again
+     * @hide
      */
     public void cancelWps(ActionListener listener) {
         validateChannel();
diff --git a/wifi/java/android/net/wifi/WpsInfo.java b/wifi/java/android/net/wifi/WpsInfo.java
index ae2e771..2ad4ad0 100644
--- a/wifi/java/android/net/wifi/WpsInfo.java
+++ b/wifi/java/android/net/wifi/WpsInfo.java
@@ -40,7 +40,7 @@
     /** Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details */
     public int setup;
 
-    /** Passed with pin method KEYPAD */
+    /** @hide */
     public String BSSID;
 
     /** Passed with pin method configuration */
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
index 08b430f..0769a64 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
@@ -25,6 +25,10 @@
 import java.util.Iterator;
 import java.util.Map;
 
+/**
+ * A class representing a Wi-Fi Passpoint credential.
+ * @hide
+ */
 public class WifiPasspointCredential implements Parcelable {
 
     private final static String TAG = "PasspointCredential";
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index ee4dc5a..e140c135 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -35,6 +35,7 @@
 
 /**
  * Provides APIs for managing Wifi Passpoint credentials.
+ * @hide
  */
 public class WifiPasspointManager {