Merge "Added MediaController.TransportControls#playFromUri."
diff --git a/api/current.txt b/api/current.txt
index 784245a..11a7e6c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6987,6 +6987,7 @@
     field public static final int SCAN_MODE_BALANCED = 1; // 0x1
     field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
     field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
+    field public static final int SCAN_MODE_OPPORTUNISTIC = -1; // 0xffffffff
   }
 
   public static final class ScanSettings.Builder {
@@ -18620,7 +18621,10 @@
     field public int frequency;
     field public boolean is80211McRTTResponder;
     field public int level;
+    field public java.lang.String operatorFriendlyName;
+    field public boolean passpointNetwork;
     field public long timestamp;
+    field public java.lang.String venueName;
   }
 
   public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -18647,6 +18651,7 @@
   public class WifiConfiguration implements android.os.Parcelable {
     ctor public WifiConfiguration();
     method public int describeContents();
+    method public boolean isPasspoint();
     method public void writeToParcel(android.os.Parcel, int);
     field public java.lang.String BSSID;
     field public java.lang.String FQDN;
@@ -36190,6 +36195,7 @@
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SELECT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
+    field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_ON_SCREEN;
   }
 
   public static final class AccessibilityNodeInfo.CollectionInfo {
diff --git a/api/system-current.txt b/api/system-current.txt
index 6bcd2c6..57ab4b7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7181,6 +7181,7 @@
     field public static final int SCAN_MODE_BALANCED = 1; // 0x1
     field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2
     field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0
+    field public static final int SCAN_MODE_OPPORTUNISTIC = -1; // 0xffffffff
     field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1
     field public static final int SCAN_RESULT_TYPE_FULL = 0; // 0x0
   }
@@ -20115,7 +20116,8 @@
   }
 
   public class RttManager {
-    method public android.net.wifi.RttManager.Capabilities getCapabilities();
+    method public deprecated android.net.wifi.RttManager.Capabilities getCapabilities();
+    method public android.net.wifi.RttManager.RttCapabilities getRttCapabilities();
     method public void startRanging(android.net.wifi.RttManager.RttParams[], android.net.wifi.RttManager.RttListener);
     method public void stopRanging(android.net.wifi.RttManager.RttListener);
     field public static final int BASE = 160256; // 0x27200
@@ -20125,10 +20127,19 @@
     field public static final int CMD_OP_STOP_RANGING = 160257; // 0x27201
     field public static final int CMD_OP_SUCCEEDED = 160259; // 0x27203
     field public static final java.lang.String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
+    field public static final int PREAMBLE_HT = 2; // 0x2
+    field public static final int PREAMBLE_LEGACY = 1; // 0x1
+    field public static final int PREAMBLE_VHT = 4; // 0x4
     field public static final int REASON_INVALID_LISTENER = -3; // 0xfffffffd
     field public static final int REASON_INVALID_REQUEST = -4; // 0xfffffffc
     field public static final int REASON_NOT_AVAILABLE = -2; // 0xfffffffe
     field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
+    field public static final int RTT_BW_10_SUPPORT = 2; // 0x2
+    field public static final int RTT_BW_160_SUPPORT = 32; // 0x20
+    field public static final int RTT_BW_20_SUPPORT = 4; // 0x4
+    field public static final int RTT_BW_40_SUPPORT = 8; // 0x8
+    field public static final int RTT_BW_5_SUPPORT = 1; // 0x1
+    field public static final int RTT_BW_80_SUPPORT = 16; // 0x10
     field public static final int RTT_CHANNEL_WIDTH_10 = 6; // 0x6
     field public static final int RTT_CHANNEL_WIDTH_160 = 3; // 0x3
     field public static final int RTT_CHANNEL_WIDTH_20 = 0; // 0x0
@@ -20136,26 +20147,31 @@
     field public static final int RTT_CHANNEL_WIDTH_5 = 5; // 0x5
     field public static final int RTT_CHANNEL_WIDTH_80 = 2; // 0x2
     field public static final int RTT_CHANNEL_WIDTH_80P80 = 4; // 0x4
-    field public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
+    field public static final deprecated int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
     field public static final int RTT_PEER_TYPE_AP = 1; // 0x1
     field public static final int RTT_PEER_TYPE_STA = 2; // 0x2
     field public static final int RTT_PEER_TYPE_UNSPECIFIED = 0; // 0x0
     field public static final int RTT_STATUS_ABORTED = 8; // 0x8
     field public static final int RTT_STATUS_FAILURE = 1; // 0x1
     field public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6; // 0x6
+    field public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12; // 0xc
+    field public static final int RTT_STATUS_FAIL_INVALID_TS = 9; // 0x9
     field public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4; // 0x4
     field public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7; // 0x7
     field public static final int RTT_STATUS_FAIL_NO_RSP = 2; // 0x2
+    field public static final int RTT_STATUS_FAIL_PROTOCOL = 10; // 0xa
     field public static final int RTT_STATUS_FAIL_REJECTED = 3; // 0x3
+    field public static final int RTT_STATUS_FAIL_SCHEDULE = 11; // 0xb
     field public static final int RTT_STATUS_FAIL_TM_TIMEOUT = 5; // 0x5
     field public static final int RTT_STATUS_SUCCESS = 0; // 0x0
-    field public static final int RTT_TYPE_11_MC = 4; // 0x4
-    field public static final int RTT_TYPE_11_V = 2; // 0x2
+    field public static final deprecated int RTT_TYPE_11_MC = 4; // 0x4
+    field public static final deprecated int RTT_TYPE_11_V = 2; // 0x2
     field public static final int RTT_TYPE_ONE_SIDED = 1; // 0x1
-    field public static final int RTT_TYPE_UNSPECIFIED = 0; // 0x0
+    field public static final int RTT_TYPE_TWO_SIDED = 4; // 0x4
+    field public static final deprecated int RTT_TYPE_UNSPECIFIED = 0; // 0x0
   }
 
-  public class RttManager.Capabilities {
+  public deprecated class RttManager.Capabilities {
     ctor public RttManager.Capabilities();
     field public int supportedPeerType;
     field public int supportedType;
@@ -20174,6 +20190,20 @@
     field public android.net.wifi.RttManager.RttResult[] mResults;
   }
 
+  public static class RttManager.RttCapabilities implements android.os.Parcelable {
+    ctor public RttManager.RttCapabilities();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public int bwSupported;
+    field public boolean lciSupported;
+    field public boolean lcrSupported;
+    field public boolean oneSidedRttSupported;
+    field public int preambleSupported;
+    field public deprecated boolean supportedPeerType;
+    field public deprecated boolean supportedType;
+    field public boolean twoSided11McRttSupported;
+  }
+
   public static abstract interface RttManager.RttListener {
     method public abstract void onAborted();
     method public abstract void onFailure(int, java.lang.String);
@@ -20182,30 +20212,64 @@
 
   public static class RttManager.RttParams {
     ctor public RttManager.RttParams();
+    field public boolean LCIRequest;
+    field public boolean LCRRequest;
+    field public int bandwidth;
     field public java.lang.String bssid;
+    field public int burstTimeout;
+    field public int centerFreq0;
+    field public int centerFreq1;
     field public int channelWidth;
     field public int deviceType;
     field public int frequency;
-    field public int num_retries;
-    field public int num_samples;
+    field public int interval;
+    field public int numRetriesPerFTMR;
+    field public int numRetriesPerMeasurementFrame;
+    field public int numSamplesPerBurst;
+    field public deprecated int num_retries;
+    field public deprecated int num_samples;
+    field public int numberBurst;
+    field public int preamble;
     field public int requestType;
   }
 
   public static class RttManager.RttResult {
     ctor public RttManager.RttResult();
     field public java.lang.String bssid;
-    field public int distance_cm;
-    field public int distance_sd_cm;
-    field public int distance_spread_cm;
-    field public int requestType;
+    field public int burstDuration;
+    field public int burstNumber;
+    field public int distance;
+    field public int distanceSpread;
+    field public int distanceStandardDeviation;
+    field public deprecated int distance_cm;
+    field public deprecated int distance_sd_cm;
+    field public deprecated int distance_spread_cm;
+    field public int frameNumberPerBurstPeer;
+    field public int measurementFrameNumber;
+    field public int measurementType;
+    field public deprecated int requestType;
+    field public int retryAfterDuration;
     field public int rssi;
-    field public int rssi_spread;
-    field public long rtt_ns;
-    field public long rtt_sd_ns;
-    field public long rtt_spread_ns;
+    field public int rssiSpread;
+    field public deprecated int rssi_spread;
+    field public long rtt;
+    field public long rttSpread;
+    field public long rttStandardDeviation;
+    field public deprecated long rtt_ns;
+    field public deprecated long rtt_sd_ns;
+    field public deprecated long rtt_spread_ns;
+    field public int rxRate;
     field public int status;
+    field public int successMeasurementFrameNumber;
     field public long ts;
-    field public int tx_rate;
+    field public int txRate;
+    field public deprecated int tx_rate;
+  }
+
+  public class RttManager.wifiInformationElement {
+    ctor public RttManager.wifiInformationElement();
+    field public java.lang.String data;
+    field public int id;
   }
 
   public class ScanResult implements android.os.Parcelable {
@@ -20225,7 +20289,10 @@
     field public int frequency;
     field public boolean is80211McRTTResponder;
     field public int level;
+    field public java.lang.String operatorFriendlyName;
+    field public boolean passpointNetwork;
     field public long timestamp;
+    field public java.lang.String venueName;
   }
 
   public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -20252,6 +20319,7 @@
   public class WifiConfiguration implements android.os.Parcelable {
     ctor public WifiConfiguration();
     method public int describeContents();
+    method public boolean isPasspoint();
     method public void writeToParcel(android.os.Parcel, int);
     field public java.lang.String BSSID;
     field public java.lang.String FQDN;
@@ -38564,6 +38632,7 @@
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SELECT;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_SELECTION;
     field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SET_TEXT;
+    field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SHOW_ON_SCREEN;
   }
 
   public static final class AccessibilityNodeInfo.CollectionInfo {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e8630b1..ea48b61 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -611,11 +611,10 @@
     /**
      * @hide
      * Activity action: ask the user to add a new device administrator as the profile owner
-     * for this user. Only system privileged apps that have MANAGE_USERS and MANAGE_DEVICE_ADMINS
-     * permission can call this API.
+     * for this user. Only system apps can launch this intent.
      *
-     * <p>The ComponentName of the profile owner admin is pass in {@link #EXTRA_DEVICE_ADMIN} extra
-     * field. This will invoke a UI to bring the user through adding the profile owner admin
+     * <p>The ComponentName of the profile owner admin is passed in the {@link #EXTRA_DEVICE_ADMIN}
+     * extra field. This will invoke a UI to bring the user through adding the profile owner admin
      * to remotely control restrictions on the user.
      *
      * <p>The intent must be invoked via {@link Activity#startActivityForResult()} to receive the
@@ -627,8 +626,8 @@
      * field to provide the user with additional explanation (in addition
      * to your component's description) about what is being added.
      *
-     * <p>If there is already a profile owner active or the caller doesn't have the required
-     * permissions, the operation will return a failure result.
+     * <p>If there is already a profile owner active or the caller is not a system app, the
+     * operation will return a failure result.
      */
     @SystemApi
     public static final String ACTION_SET_PROFILE_OWNER
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 7eae439..0106686 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -25,6 +25,13 @@
  * parameters for the scan.
  */
 public final class ScanSettings implements Parcelable {
+
+    /**
+     * A special Bluetooth LE scan mode. Applications using this scan mode will passively listen for
+     * other scan results without starting BLE scans themselves.
+     */
+    public static final int SCAN_MODE_OPPORTUNISTIC = -1;
+
     /**
      * Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the
      * least power.
@@ -177,7 +184,7 @@
          * @throws IllegalArgumentException If the {@code scanMode} is invalid.
          */
         public Builder setScanMode(int scanMode) {
-            if (scanMode < SCAN_MODE_LOW_POWER || scanMode > SCAN_MODE_LOW_LATENCY) {
+            if (scanMode < SCAN_MODE_OPPORTUNISTIC || scanMode > SCAN_MODE_LOW_LATENCY) {
                 throw new IllegalArgumentException("invalid scan mode " + scanMode);
             }
             mScanMode = scanMode;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 34a0727..a0e2bf8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2337,7 +2337,7 @@
      * successfully finding a network for the applications request.  Retrieve it with
      * {@link android.content.Intent#getParcelableExtra(String)}.
      * <p>
-     * Note that if you intend to invoke (@link #setProcessDefaultNetwork(Network)) or
+     * Note that if you intend to invoke {@link #setProcessDefaultNetwork} or
      * {@link Network#openConnection(java.net.URL)} then you must get a
      * ConnectivityManager instance before doing so.
      */
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index a7f9c5b..8c8bfab 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -148,9 +148,9 @@
      */
     public static final int NET_CAPABILITY_TRUSTED        = 14;
 
-    /*
+    /**
      * Indicates that this network is not a VPN.  This capability is set by default and should be
-     * explicitly cleared when creating VPN networks.
+     * explicitly cleared for VPN networks.
      */
     public static final int NET_CAPABILITY_NOT_VPN        = 15;
 
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 26e6b850..1a06e0a 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -29,6 +29,7 @@
 import android.content.pm.ApplicationInfo;
 import android.telephony.SignalStrength;
 import android.text.format.DateFormat;
+import android.util.ArrayMap;
 import android.util.Printer;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -283,21 +284,21 @@
          *
          * @return a Map from Strings to Uid.Wakelock objects.
          */
-        public abstract Map<String, ? extends Wakelock> getWakelockStats();
+        public abstract ArrayMap<String, ? extends Wakelock> getWakelockStats();
 
         /**
          * Returns a mapping containing sync statistics.
          *
          * @return a Map from Strings to Timer objects.
          */
-        public abstract Map<String, ? extends Timer> getSyncStats();
+        public abstract ArrayMap<String, ? extends Timer> getSyncStats();
 
         /**
          * Returns a mapping containing scheduled job statistics.
          *
          * @return a Map from Strings to Timer objects.
          */
-        public abstract Map<String, ? extends Timer> getJobStats();
+        public abstract ArrayMap<String, ? extends Timer> getJobStats();
 
         /**
          * The statistics associated with a particular wake lock.
@@ -323,14 +324,14 @@
          *
          * @return a Map from Strings to Uid.Proc objects.
          */
-        public abstract Map<String, ? extends Proc> getProcessStats();
+        public abstract ArrayMap<String, ? extends Proc> getProcessStats();
 
         /**
          * Returns a mapping containing package statistics.
          *
          * @return a Map from Strings to Uid.Pkg objects.
          */
-        public abstract Map<String, ? extends Pkg> getPackageStats();
+        public abstract ArrayMap<String, ? extends Pkg> getPackageStats();
         
         /**
          * {@hide}
@@ -501,17 +502,16 @@
         public static abstract class Pkg {
 
             /**
-             * Returns the number of times this package has done something that could wake up the
-             * device from sleep.
-             *
-             * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
+             * Returns information about all wakeup alarms that have been triggered for this
+             * package.  The mapping keys are tag names for the alarms, the counter contains
+             * the number of times the alarm was triggered while on battery.
              */
-            public abstract int getWakeups(int which);
+            public abstract ArrayMap<String, ? extends Counter> getWakeupAlarmStats();
 
             /**
              * Returns a mapping containing service statistics.
              */
-            public abstract Map<String, ? extends Serv> getServiceStats();
+            public abstract ArrayMap<String, ? extends Serv> getServiceStats();
 
             /**
              * The statistics associated with a particular service.
@@ -1352,7 +1352,7 @@
                 int idx = code&HistoryItem.EVENT_TYPE_MASK;
                 HashMap<String, SparseIntArray> active = mActiveEvents[idx];
                 if (active == null) {
-                    active = new HashMap<String, SparseIntArray>();
+                    active = new HashMap<>();
                     mActiveEvents[idx] = active;
                 }
                 SparseIntArray uids = active.get(name);
@@ -2382,12 +2382,12 @@
         final long wifiRunningTime = getGlobalWifiRunningTime(rawRealtime, which);
         final long bluetoothOnTime = getBluetoothOnTime(rawRealtime, which);
 
-        StringBuilder sb = new StringBuilder(128);
+        final StringBuilder sb = new StringBuilder(128);
         
-        SparseArray<? extends Uid> uidStats = getUidStats();
+        final SparseArray<? extends Uid> uidStats = getUidStats();
         final int NU = uidStats.size();
         
-        String category = STAT_NAMES[which];
+        final String category = STAT_NAMES[which];
 
         // Dump "battery" stat
         dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, 
@@ -2402,37 +2402,35 @@
         long partialWakeLockTimeTotal = 0;
         
         for (int iu = 0; iu < NU; iu++) {
-            Uid u = uidStats.valueAt(iu);
+            final Uid u = uidStats.valueAt(iu);
 
-            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
-            if (wakelocks.size() > 0) {
-                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent 
-                        : wakelocks.entrySet()) {
-                    Uid.Wakelock wl = ent.getValue();
-                    
-                    Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
-                    if (fullWakeTimer != null) {
-                        fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(rawRealtime,
-                                which);
-                    }
+            final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+                    = u.getWakelockStats();
+            for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+                final Uid.Wakelock wl = wakelocks.valueAt(iw);
 
-                    Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
-                    if (partialWakeTimer != null) {
-                        partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked(
-                            rawRealtime, which);
-                    }
+                final Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
+                if (fullWakeTimer != null) {
+                    fullWakeLockTimeTotal += fullWakeTimer.getTotalTimeLocked(rawRealtime,
+                            which);
+                }
+
+                final Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
+                if (partialWakeTimer != null) {
+                    partialWakeLockTimeTotal += partialWakeTimer.getTotalTimeLocked(
+                        rawRealtime, which);
                 }
             }
         }
         
-        long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
-        long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
-        long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
-        long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
-        long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
-        long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
-        long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
-        long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+        final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+        final long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+        final long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+        final long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+        final long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+        final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+        final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+        final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
 
         // Dump network stats
         dumpLine(pw, 0 /* uid */, category, GLOBAL_NETWORK_DATA,
@@ -2544,7 +2542,7 @@
         }
         
         if (reqUid < 0) {
-            Map<String, ? extends Timer> kernelWakelocks = getKernelWakelockStats();
+            final Map<String, ? extends Timer> kernelWakelocks = getKernelWakelockStats();
             if (kernelWakelocks.size() > 0) {
                 for (Map.Entry<String, ? extends Timer> ent : kernelWakelocks.entrySet()) {
                     sb.setLength(0);
@@ -2553,7 +2551,7 @@
                             sb.toString());
                 }
             }
-            Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
+            final Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
             if (wakeupReasons.size() > 0) {
                 for (Map.Entry<String, ? extends Timer> ent : wakeupReasons.entrySet()) {
                     // Not doing the regular wake lock formatting to remain compatible
@@ -2566,10 +2564,10 @@
             }
         }
         
-        BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
+        final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
         helper.create(this);
         helper.refreshStats(which, UserHandle.USER_ALL);
-        List<BatterySipper> sippers = helper.getUsageList();
+        final List<BatterySipper> sippers = helper.getUsageList();
         if (sippers != null && sippers.size() > 0) {
             dumpLine(pw, 0 /* uid */, category, POWER_USE_SUMMARY_DATA,
                     BatteryStatsHelper.makemAh(helper.getPowerProfile().getBatteryCapacity()),
@@ -2577,7 +2575,7 @@
                     BatteryStatsHelper.makemAh(helper.getMinDrainedPower()),
                     BatteryStatsHelper.makemAh(helper.getMaxDrainedPower()));
             for (int i=0; i<sippers.size(); i++) {
-                BatterySipper bs = sippers.get(i);
+                final BatterySipper bs = sippers.get(i);
                 int uid = 0;
                 String label;
                 switch (bs.drainType) {
@@ -2629,22 +2627,22 @@
             if (reqUid >= 0 && uid != reqUid) {
                 continue;
             }
-            Uid u = uidStats.valueAt(iu);
+            final Uid u = uidStats.valueAt(iu);
             // Dump Network stats per uid, if any
-            long mobileBytesRx = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
-            long mobileBytesTx = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
-            long wifiBytesRx = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
-            long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
-            long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
-            long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
-            long mobileActiveTime = u.getMobileRadioActiveTime(which);
-            int mobileActiveCount = u.getMobileRadioActiveCount(which);
-            long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
-            long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
-            long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
-            long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
-            int wifiScanCount = u.getWifiScanCount(which);
-            long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
+            final long mobileBytesRx = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+            final long mobileBytesTx = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+            final long wifiBytesRx = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+            final long wifiBytesTx = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+            final long mobilePacketsRx = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+            final long mobilePacketsTx = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+            final long mobileActiveTime = u.getMobileRadioActiveTime(which);
+            final int mobileActiveCount = u.getMobileRadioActiveCount(which);
+            final long wifiPacketsRx = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+            final long wifiPacketsTx = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+            final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
+            final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+            final int wifiScanCount = u.getWifiScanCount(which);
+            final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
 
             if (mobileBytesRx > 0 || mobileBytesTx > 0 || wifiBytesRx > 0 || wifiBytesTx > 0
                     || mobilePacketsRx > 0 || mobilePacketsTx > 0 || wifiPacketsRx > 0
@@ -2675,93 +2673,90 @@
                 }
             }
             
-            Map<String, ? extends Uid.Wakelock> wakelocks = u.getWakelockStats();
-            if (wakelocks.size() > 0) {
-                for (Map.Entry<String, ? extends Uid.Wakelock> ent : wakelocks.entrySet()) {
-                    Uid.Wakelock wl = ent.getValue();
-                    String linePrefix = "";
-                    sb.setLength(0);
-                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), 
-                            rawRealtime, "f", which, linePrefix);
-                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), 
-                            rawRealtime, "p", which, linePrefix);
-                    linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), 
-                            rawRealtime, "w", which, linePrefix);
-                    
-                    // Only log if we had at lease one wakelock...
-                    if (sb.length() > 0) {
-                        String name = ent.getKey();
-                        if (name.indexOf(',') >= 0) {
-                            name = name.replace(',', '_');
-                        }
-                        dumpLine(pw, uid, category, WAKELOCK_DATA, name, sb.toString());
+            final ArrayMap<String, ? extends Uid.Wakelock> wakelocks = u.getWakelockStats();
+            for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+                final Uid.Wakelock wl = wakelocks.valueAt(iw);
+                String linePrefix = "";
+                sb.setLength(0);
+                linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL),
+                        rawRealtime, "f", which, linePrefix);
+                linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL),
+                        rawRealtime, "p", which, linePrefix);
+                linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW),
+                        rawRealtime, "w", which, linePrefix);
+
+                // Only log if we had at lease one wakelock...
+                if (sb.length() > 0) {
+                    String name = wakelocks.keyAt(iw);
+                    if (name.indexOf(',') >= 0) {
+                        name = name.replace(',', '_');
                     }
+                    dumpLine(pw, uid, category, WAKELOCK_DATA, name, sb.toString());
                 }
             }
 
-            Map<String, ? extends Timer> syncs = u.getSyncStats();
-            if (syncs.size() > 0) {
-                for (Map.Entry<String, ? extends Timer> ent : syncs.entrySet()) {
-                    Timer timer = ent.getValue();
-                    // Convert from microseconds to milliseconds with rounding
-                    long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
-                    int count = timer.getCountLocked(which);
-                    if (totalTime != 0) {
-                        dumpLine(pw, uid, category, SYNC_DATA, ent.getKey(), totalTime, count);
-                    }
+            final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
+            for (int isy=syncs.size()-1; isy>=0; isy--) {
+                final Timer timer = syncs.valueAt(isy);
+                // Convert from microseconds to milliseconds with rounding
+                final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+                final int count = timer.getCountLocked(which);
+                if (totalTime != 0) {
+                    dumpLine(pw, uid, category, SYNC_DATA, syncs.keyAt(isy), totalTime, count);
                 }
             }
 
-            Map<String, ? extends Timer> jobs = u.getJobStats();
-            if (jobs.size() > 0) {
-                for (Map.Entry<String, ? extends Timer> ent : jobs.entrySet()) {
-                    Timer timer = ent.getValue();
-                    // Convert from microseconds to milliseconds with rounding
-                    long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
-                    int count = timer.getCountLocked(which);
-                    if (totalTime != 0) {
-                        dumpLine(pw, uid, category, JOB_DATA, ent.getKey(), totalTime, count);
-                    }
+            final ArrayMap<String, ? extends Timer> jobs = u.getJobStats();
+            for (int ij=jobs.size()-1; ij>=0; ij--) {
+                final Timer timer = jobs.valueAt(ij);
+                // Convert from microseconds to milliseconds with rounding
+                final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+                final int count = timer.getCountLocked(which);
+                if (totalTime != 0) {
+                    dumpLine(pw, uid, category, JOB_DATA, jobs.keyAt(ij), totalTime, count);
                 }
             }
 
-            SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
-            int NSE = sensors.size();
+            final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+            final int NSE = sensors.size();
             for (int ise=0; ise<NSE; ise++) {
-                Uid.Sensor se = sensors.valueAt(ise);
-                int sensorNumber = sensors.keyAt(ise);
-                Timer timer = se.getSensorTime();
+                final Uid.Sensor se = sensors.valueAt(ise);
+                final int sensorNumber = sensors.keyAt(ise);
+                final Timer timer = se.getSensorTime();
                 if (timer != null) {
                     // Convert from microseconds to milliseconds with rounding
-                    long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
-                    int count = timer.getCountLocked(which);
+                    final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500)
+                            / 1000;
+                    final int count = timer.getCountLocked(which);
                     if (totalTime != 0) {
                         dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count);
                     }
                 }
             }
 
-            Timer vibTimer = u.getVibratorOnTimer();
+            final Timer vibTimer = u.getVibratorOnTimer();
             if (vibTimer != null) {
                 // Convert from microseconds to milliseconds with rounding
-                long totalTime = (vibTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
-                int count = vibTimer.getCountLocked(which);
+                final long totalTime = (vibTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+                        / 1000;
+                final int count = vibTimer.getCountLocked(which);
                 if (totalTime != 0) {
                     dumpLine(pw, uid, category, VIBRATOR_DATA, totalTime, count);
                 }
             }
 
-            Timer fgTimer = u.getForegroundActivityTimer();
+            final Timer fgTimer = u.getForegroundActivityTimer();
             if (fgTimer != null) {
                 // Convert from microseconds to milliseconds with rounding
-                long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
-                int count = fgTimer.getCountLocked(which);
+                final long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+                        / 1000;
+                final int count = fgTimer.getCountLocked(which);
                 if (totalTime != 0) {
                     dumpLine(pw, uid, category, FOREGROUND_DATA, totalTime, count);
                 }
             }
 
-            Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE];
+            final Object[] stateTimes = new Object[Uid.NUM_PROCESS_STATE];
             long totalStateTime = 0;
             for (int ips=0; ips<Uid.NUM_PROCESS_STATE; ips++) {
                 totalStateTime += u.getProcessStateTime(ips, rawRealtime, which);
@@ -2771,50 +2766,48 @@
                 dumpLine(pw, uid, category, STATE_TIME_DATA, stateTimes);
             }
 
-            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
-            if (processStats.size() > 0) {
-                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
-                        : processStats.entrySet()) {
-                    Uid.Proc ps = ent.getValue();
+            final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
+                    = u.getProcessStats();
+            for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
+                final Uid.Proc ps = processStats.valueAt(ipr);
 
-                    final long userMillis = ps.getUserTime(which);
-                    final long systemMillis = ps.getSystemTime(which);
-                    final long foregroundMillis = ps.getForegroundTime(which);
-                    final int starts = ps.getStarts(which);
-                    final int numCrashes = ps.getNumCrashes(which);
-                    final int numAnrs = ps.getNumAnrs(which);
+                final long userMillis = ps.getUserTime(which);
+                final long systemMillis = ps.getSystemTime(which);
+                final long foregroundMillis = ps.getForegroundTime(which);
+                final int starts = ps.getStarts(which);
+                final int numCrashes = ps.getNumCrashes(which);
+                final int numAnrs = ps.getNumAnrs(which);
 
-                    if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0
-                            || starts != 0 || numAnrs != 0 || numCrashes != 0) {
-                        dumpLine(pw, uid, category, PROCESS_DATA, ent.getKey(), userMillis,
-                                systemMillis, foregroundMillis, starts, numAnrs, numCrashes);
-                    }
+                if (userMillis != 0 || systemMillis != 0 || foregroundMillis != 0
+                        || starts != 0 || numAnrs != 0 || numCrashes != 0) {
+                    dumpLine(pw, uid, category, PROCESS_DATA, processStats.keyAt(ipr), userMillis,
+                            systemMillis, foregroundMillis, starts, numAnrs, numCrashes);
                 }
             }
 
-            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
-            if (packageStats.size() > 0) {
-                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
-                        : packageStats.entrySet()) {
-              
-                    Uid.Pkg ps = ent.getValue();
-                    int wakeups = ps.getWakeups(which);
-                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
-                    for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
-                            : serviceStats.entrySet()) {
-                        BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
-                        long startTime = ss.getStartTime(batteryUptime, which);
-                        int starts = ss.getStarts(which);
-                        int launches = ss.getLaunches(which);
-                        if (startTime != 0 || starts != 0 || launches != 0) {
-                            dumpLine(pw, uid, category, APK_DATA, 
-                                    wakeups, // wakeup alarms
-                                    ent.getKey(), // Apk
-                                    sent.getKey(), // service
-                                    startTime / 1000, // time spent started, in ms
-                                    starts,
-                                    launches);
-                        }
+            final ArrayMap<String, ? extends BatteryStats.Uid.Pkg> packageStats
+                    = u.getPackageStats();
+            for (int ipkg=packageStats.size()-1; ipkg>=0; ipkg--) {
+                final Uid.Pkg ps = packageStats.valueAt(ipkg);
+                int wakeups = 0;
+                final ArrayMap<String, ? extends Counter> alarms = ps.getWakeupAlarmStats();
+                for (int iwa=alarms.size()-1; iwa>=0; iwa--) {
+                    wakeups += alarms.valueAt(iwa).getCountLocked(which);
+                }
+                final ArrayMap<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+                for (int isvc=serviceStats.size()-1; isvc>=0; isvc--) {
+                    final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
+                    final long startTime = ss.getStartTime(batteryUptime, which);
+                    final int starts = ss.getStarts(which);
+                    final int launches = ss.getLaunches(which);
+                    if (startTime != 0 || starts != 0 || launches != 0) {
+                        dumpLine(pw, uid, category, APK_DATA,
+                                wakeups, // wakeup alarms
+                                packageStats.keyAt(ipkg), // Apk
+                                serviceStats.keyAt(isvc), // service
+                                startTime / 1000, // time spent started, in ms
+                                starts,
+                                launches);
                     }
                 }
             }
@@ -2863,9 +2856,9 @@
         final long batteryTimeRemaining = computeBatteryTimeRemaining(rawRealtime);
         final long chargeTimeRemaining = computeChargeTimeRemaining(rawRealtime);
 
-        StringBuilder sb = new StringBuilder(128);
+        final StringBuilder sb = new StringBuilder(128);
         
-        SparseArray<? extends Uid> uidStats = getUidStats();
+        final SparseArray<? extends Uid> uidStats = getUidStats();
         final int NU = uidStats.size();
 
         sb.setLength(0);
@@ -2992,7 +2985,7 @@
                     sb.append("("); sb.append(formatRatioLocked(phoneOnTime, whichBatteryRealtime));
                     sb.append(") "); sb.append(getPhoneOnCount(which)); sb.append("x");
         }
-        int connChanges = getNumConnectivityChange(which);
+        final int connChanges = getNumConnectivityChange(which);
         if (connChanges != 0) {
             pw.print(prefix);
             pw.print("  Connectivity changes: "); pw.println(connChanges);
@@ -3002,50 +2995,48 @@
         long fullWakeLockTimeTotalMicros = 0;
         long partialWakeLockTimeTotalMicros = 0;
 
-        final ArrayList<TimerEntry> timers = new ArrayList<TimerEntry>();
+        final ArrayList<TimerEntry> timers = new ArrayList<>();
 
         for (int iu = 0; iu < NU; iu++) {
-            Uid u = uidStats.valueAt(iu);
+            final Uid u = uidStats.valueAt(iu);
 
-            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
-            if (wakelocks.size() > 0) {
-                for (Map.Entry<String, ? extends BatteryStats.Uid.Wakelock> ent 
-                        : wakelocks.entrySet()) {
-                    Uid.Wakelock wl = ent.getValue();
-                    
-                    Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
-                    if (fullWakeTimer != null) {
-                        fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked(
-                                rawRealtime, which);
-                    }
+            final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+                    = u.getWakelockStats();
+            for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+                final Uid.Wakelock wl = wakelocks.valueAt(iw);
 
-                    Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
-                    if (partialWakeTimer != null) {
-                        long totalTimeMicros = partialWakeTimer.getTotalTimeLocked(
-                                rawRealtime, which);
-                        if (totalTimeMicros > 0) {
-                            if (reqUid < 0) {
-                                // Only show the ordered list of all wake
-                                // locks if the caller is not asking for data
-                                // about a specific uid.
-                                timers.add(new TimerEntry(ent.getKey(), u.getUid(),
-                                        partialWakeTimer, totalTimeMicros));
-                            }
-                            partialWakeLockTimeTotalMicros += totalTimeMicros;
+                final Timer fullWakeTimer = wl.getWakeTime(WAKE_TYPE_FULL);
+                if (fullWakeTimer != null) {
+                    fullWakeLockTimeTotalMicros += fullWakeTimer.getTotalTimeLocked(
+                            rawRealtime, which);
+                }
+
+                final Timer partialWakeTimer = wl.getWakeTime(WAKE_TYPE_PARTIAL);
+                if (partialWakeTimer != null) {
+                    final long totalTimeMicros = partialWakeTimer.getTotalTimeLocked(
+                            rawRealtime, which);
+                    if (totalTimeMicros > 0) {
+                        if (reqUid < 0) {
+                            // Only show the ordered list of all wake
+                            // locks if the caller is not asking for data
+                            // about a specific uid.
+                            timers.add(new TimerEntry(wakelocks.keyAt(iw), u.getUid(),
+                                    partialWakeTimer, totalTimeMicros));
                         }
+                        partialWakeLockTimeTotalMicros += totalTimeMicros;
                     }
                 }
             }
         }
         
-        long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
-        long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
-        long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
-        long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
-        long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
-        long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
-        long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
-        long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+        final long mobileRxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+        final long mobileTxTotalBytes = getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+        final long wifiRxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+        final long wifiTxTotalBytes = getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+        final long mobileRxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+        final long mobileTxTotalPackets = getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+        final long wifiRxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+        final long wifiTxTotalPackets = getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
 
         if (fullWakeLockTimeTotalMicros != 0) {
             sb.setLength(0);
@@ -3367,7 +3358,7 @@
             pw.println();
         }
 
-        BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
+        final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly);
         helper.create(this);
         helper.refreshStats(which, UserHandle.USER_ALL);
         List<BatterySipper> sippers = helper.getUsageList();
@@ -3382,7 +3373,7 @@
                     }
                     pw.println();
             for (int i=0; i<sippers.size(); i++) {
-                BatterySipper bs = sippers.get(i);
+                final BatterySipper bs = sippers.get(i);
                 switch (bs.drainType) {
                     case IDLE:
                         pw.print(prefix); pw.print("    Idle: "); printmAh(pw, bs.value);
@@ -3439,7 +3430,7 @@
             pw.print(prefix); pw.println("  Per-app mobile ms per packet:");
             long totalTime = 0;
             for (int i=0; i<sippers.size(); i++) {
-                BatterySipper bs = sippers.get(i);
+                final BatterySipper bs = sippers.get(i);
                 sb.setLength(0);
                 sb.append(prefix); sb.append("    Uid ");
                 UserHandle.formatUid(sb, bs.uidObj.getUid());
@@ -3476,12 +3467,14 @@
         };
 
         if (reqUid < 0) {
-            Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
+            final Map<String, ? extends BatteryStats.Timer> kernelWakelocks
+                    = getKernelWakelockStats();
             if (kernelWakelocks.size() > 0) {
-                final ArrayList<TimerEntry> ktimers = new ArrayList<TimerEntry>();
-                for (Map.Entry<String, ? extends BatteryStats.Timer> ent : kernelWakelocks.entrySet()) {
-                    BatteryStats.Timer timer = ent.getValue();
-                    long totalTimeMillis = computeWakeLock(timer, rawRealtime, which);
+                final ArrayList<TimerEntry> ktimers = new ArrayList<>();
+                for (Map.Entry<String, ? extends BatteryStats.Timer> ent
+                        : kernelWakelocks.entrySet()) {
+                    final BatteryStats.Timer timer = ent.getValue();
+                    final long totalTimeMillis = computeWakeLock(timer, rawRealtime, which);
                     if (totalTimeMillis > 0) {
                         ktimers.add(new TimerEntry(ent.getKey(), 0, timer, totalTimeMillis));
                     }
@@ -3490,7 +3483,7 @@
                     Collections.sort(ktimers, timerComparator);
                     pw.print(prefix); pw.println("  All kernel wake locks:");
                     for (int i=0; i<ktimers.size(); i++) {
-                        TimerEntry timer = ktimers.get(i);
+                        final TimerEntry timer = ktimers.get(i);
                         String linePrefix = ": ";
                         sb.setLength(0);
                         sb.append(prefix);
@@ -3526,12 +3519,12 @@
                 pw.println();
             }
 
-            Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
+            final Map<String, ? extends Timer> wakeupReasons = getWakeupReasonStats();
             if (wakeupReasons.size() > 0) {
                 pw.print(prefix); pw.println("  All wakeup reasons:");
-                final ArrayList<TimerEntry> reasons = new ArrayList<TimerEntry>();
+                final ArrayList<TimerEntry> reasons = new ArrayList<>();
                 for (Map.Entry<String, ? extends Timer> ent : wakeupReasons.entrySet()) {
-                    Timer timer = ent.getValue();
+                    final Timer timer = ent.getValue();
                     reasons.add(new TimerEntry(ent.getKey(), 0, timer,
                             timer.getCountLocked(which)));
                 }
@@ -3557,7 +3550,7 @@
                 continue;
             }
             
-            Uid u = uidStats.valueAt(iu);
+            final Uid u = uidStats.valueAt(iu);
 
             pw.print(prefix);
             pw.print("  ");
@@ -3565,20 +3558,20 @@
             pw.println(":");
             boolean uidActivity = false;
 
-            long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
-            long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
-            long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
-            long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
-            long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
-            long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
-            long uidMobileActiveTime = u.getMobileRadioActiveTime(which);
-            int uidMobileActiveCount = u.getMobileRadioActiveCount(which);
-            long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
-            long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
-            long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
-            long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
-            int wifiScanCount = u.getWifiScanCount(which);
-            long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
+            final long mobileRxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_RX_DATA, which);
+            final long mobileTxBytes = u.getNetworkActivityBytes(NETWORK_MOBILE_TX_DATA, which);
+            final long wifiRxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_RX_DATA, which);
+            final long wifiTxBytes = u.getNetworkActivityBytes(NETWORK_WIFI_TX_DATA, which);
+            final long mobileRxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_RX_DATA, which);
+            final long mobileTxPackets = u.getNetworkActivityPackets(NETWORK_MOBILE_TX_DATA, which);
+            final long uidMobileActiveTime = u.getMobileRadioActiveTime(which);
+            final int uidMobileActiveCount = u.getMobileRadioActiveCount(which);
+            final long wifiRxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_RX_DATA, which);
+            final long wifiTxPackets = u.getNetworkActivityPackets(NETWORK_WIFI_TX_DATA, which);
+            final long fullWifiLockOnTime = u.getFullWifiLockTime(rawRealtime, which);
+            final long wifiScanTime = u.getWifiScanTime(rawRealtime, which);
+            final int wifiScanCount = u.getWifiScanCount(which);
+            final long uidWifiRunningTime = u.getWifiRunningTime(rawRealtime, which);
 
             if (mobileRxBytes > 0 || mobileTxBytes > 0
                     || mobileRxPackets > 0 || mobileTxPackets > 0) {
@@ -3636,7 +3629,7 @@
             if (u.hasUserActivity()) {
                 boolean hasData = false;
                 for (int i=0; i<Uid.NUM_USER_ACTIVITY_TYPES; i++) {
-                    int val = u.getUserActivityCount(i, which);
+                    final int val = u.getUserActivityCount(i, which);
                     if (val != 0) {
                         if (!hasData) {
                             sb.setLength(0);
@@ -3655,125 +3648,121 @@
                 }
             }
 
-            Map<String, ? extends BatteryStats.Uid.Wakelock> wakelocks = u.getWakelockStats();
-            if (wakelocks.size() > 0) {
-                long totalFull = 0, totalPartial = 0, totalWindow = 0;
-                int count = 0;
-                for (Map.Entry<String, ? extends Uid.Wakelock> ent : wakelocks.entrySet()) {
-                    Uid.Wakelock wl = ent.getValue();
-                    String linePrefix = ": ";
-                    sb.setLength(0);
-                    sb.append(prefix);
-                    sb.append("    Wake lock ");
-                    sb.append(ent.getKey());
-                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), rawRealtime,
-                            "full", which, linePrefix);
-                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), rawRealtime,
-                            "partial", which, linePrefix);
-                    linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime,
-                            "window", which, linePrefix);
-                    if (true || !linePrefix.equals(": ")) {
-                        sb.append(" realtime");
-                        // Only print out wake locks that were held
-                        pw.println(sb.toString());
-                        uidActivity = true;
-                        count++;
-                    }
-                    totalFull += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL),
-                            rawRealtime, which);
-                    totalPartial += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL),
-                            rawRealtime, which);
-                    totalWindow += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW),
-                            rawRealtime, which);
-                }
-                if (count > 1) {
-                    if (totalFull != 0 || totalPartial != 0 || totalWindow != 0) {
-                        sb.setLength(0);
-                        sb.append(prefix);
-                        sb.append("    TOTAL wake: ");
-                        boolean needComma = false;
-                        if (totalFull != 0) {
-                            needComma = true;
-                            formatTimeMs(sb, totalFull);
-                            sb.append("full");
-                        }
-                        if (totalPartial != 0) {
-                            if (needComma) {
-                                sb.append(", ");
-                            }
-                            needComma = true;
-                            formatTimeMs(sb, totalPartial);
-                            sb.append("partial");
-                        }
-                        if (totalWindow != 0) {
-                            if (needComma) {
-                                sb.append(", ");
-                            }
-                            needComma = true;
-                            formatTimeMs(sb, totalWindow);
-                            sb.append("window");
-                        }
-                        sb.append(" realtime");
-                        pw.println(sb.toString());
-                    }
-                }
-            }
-
-            Map<String, ? extends Timer> syncs = u.getSyncStats();
-            if (syncs.size() > 0) {
-                for (Map.Entry<String, ? extends Timer> ent : syncs.entrySet()) {
-                    Timer timer = ent.getValue();
-                    // Convert from microseconds to milliseconds with rounding
-                    long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
-                    int count = timer.getCountLocked(which);
-                    sb.setLength(0);
-                    sb.append(prefix);
-                    sb.append("    Sync ");
-                    sb.append(ent.getKey());
-                    sb.append(": ");
-                    if (totalTime != 0) {
-                        formatTimeMs(sb, totalTime);
-                        sb.append("realtime (");
-                        sb.append(count);
-                        sb.append(" times)");
-                    } else {
-                        sb.append("(not used)");
-                    }
+            final ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> wakelocks
+                    = u.getWakelockStats();
+            long totalFullWakelock = 0, totalPartialWakelock = 0, totalWindowWakelock = 0;
+            int countWakelock = 0;
+            for (int iw=wakelocks.size()-1; iw>=0; iw--) {
+                final Uid.Wakelock wl = wakelocks.valueAt(iw);
+                String linePrefix = ": ";
+                sb.setLength(0);
+                sb.append(prefix);
+                sb.append("    Wake lock ");
+                sb.append(wakelocks.keyAt(iw));
+                linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), rawRealtime,
+                        "full", which, linePrefix);
+                linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), rawRealtime,
+                        "partial", which, linePrefix);
+                linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), rawRealtime,
+                        "window", which, linePrefix);
+                if (true || !linePrefix.equals(": ")) {
+                    sb.append(" realtime");
+                    // Only print out wake locks that were held
                     pw.println(sb.toString());
                     uidActivity = true;
+                    countWakelock++;
                 }
+                totalFullWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_FULL),
+                        rawRealtime, which);
+                totalPartialWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_PARTIAL),
+                        rawRealtime, which);
+                totalWindowWakelock += computeWakeLock(wl.getWakeTime(WAKE_TYPE_WINDOW),
+                        rawRealtime, which);
             }
-
-            Map<String, ? extends Timer> jobs = u.getJobStats();
-            if (jobs.size() > 0) {
-                for (Map.Entry<String, ? extends Timer> ent : jobs.entrySet()) {
-                    Timer timer = ent.getValue();
-                    // Convert from microseconds to milliseconds with rounding
-                    long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
-                    int count = timer.getCountLocked(which);
+            if (countWakelock > 1) {
+                if (totalFullWakelock != 0 || totalPartialWakelock != 0
+                        || totalWindowWakelock != 0) {
                     sb.setLength(0);
                     sb.append(prefix);
-                    sb.append("    Job ");
-                    sb.append(ent.getKey());
-                    sb.append(": ");
-                    if (totalTime != 0) {
-                        formatTimeMs(sb, totalTime);
-                        sb.append("realtime (");
-                        sb.append(count);
-                        sb.append(" times)");
-                    } else {
-                        sb.append("(not used)");
+                    sb.append("    TOTAL wake: ");
+                    boolean needComma = false;
+                    if (totalFullWakelock != 0) {
+                        needComma = true;
+                        formatTimeMs(sb, totalFullWakelock);
+                        sb.append("full");
                     }
+                    if (totalPartialWakelock != 0) {
+                        if (needComma) {
+                            sb.append(", ");
+                        }
+                        needComma = true;
+                        formatTimeMs(sb, totalPartialWakelock);
+                        sb.append("partial");
+                    }
+                    if (totalWindowWakelock != 0) {
+                        if (needComma) {
+                            sb.append(", ");
+                        }
+                        needComma = true;
+                        formatTimeMs(sb, totalWindowWakelock);
+                        sb.append("window");
+                    }
+                    sb.append(" realtime");
                     pw.println(sb.toString());
-                    uidActivity = true;
                 }
             }
 
-            SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
-            int NSE = sensors.size();
+            final ArrayMap<String, ? extends Timer> syncs = u.getSyncStats();
+            for (int isy=syncs.size()-1; isy>=0; isy--) {
+                final Timer timer = syncs.valueAt(isy);
+                // Convert from microseconds to milliseconds with rounding
+                final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+                final int count = timer.getCountLocked(which);
+                sb.setLength(0);
+                sb.append(prefix);
+                sb.append("    Sync ");
+                sb.append(syncs.keyAt(isy));
+                sb.append(": ");
+                if (totalTime != 0) {
+                    formatTimeMs(sb, totalTime);
+                    sb.append("realtime (");
+                    sb.append(count);
+                    sb.append(" times)");
+                } else {
+                    sb.append("(not used)");
+                }
+                pw.println(sb.toString());
+                uidActivity = true;
+            }
+
+            final ArrayMap<String, ? extends Timer> jobs = u.getJobStats();
+            for (int ij=jobs.size()-1; ij>=0; ij--) {
+                final Timer timer = jobs.valueAt(ij);
+                // Convert from microseconds to milliseconds with rounding
+                final long totalTime = (timer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
+                final int count = timer.getCountLocked(which);
+                sb.setLength(0);
+                sb.append(prefix);
+                sb.append("    Job ");
+                sb.append(jobs.keyAt(ij));
+                sb.append(": ");
+                if (totalTime != 0) {
+                    formatTimeMs(sb, totalTime);
+                    sb.append("realtime (");
+                    sb.append(count);
+                    sb.append(" times)");
+                } else {
+                    sb.append("(not used)");
+                }
+                pw.println(sb.toString());
+                uidActivity = true;
+            }
+
+            final SparseArray<? extends BatteryStats.Uid.Sensor> sensors = u.getSensorStats();
+            final int NSE = sensors.size();
             for (int ise=0; ise<NSE; ise++) {
-                Uid.Sensor se = sensors.valueAt(ise);
-                int sensorNumber = sensors.keyAt(ise);
+                final Uid.Sensor se = sensors.valueAt(ise);
+                final int sensorNumber = sensors.keyAt(ise);
                 sb.setLength(0);
                 sb.append(prefix);
                 sb.append("    Sensor ");
@@ -3785,12 +3774,12 @@
                 }
                 sb.append(": ");
 
-                Timer timer = se.getSensorTime();
+                final Timer timer = se.getSensorTime();
                 if (timer != null) {
                     // Convert from microseconds to milliseconds with rounding
-                    long totalTime = (timer.getTotalTimeLocked(
+                    final long totalTime = (timer.getTotalTimeLocked(
                             rawRealtime, which) + 500) / 1000;
-                    int count = timer.getCountLocked(which);
+                    final int count = timer.getCountLocked(which);
                     //timer.logState();
                     if (totalTime != 0) {
                         formatTimeMs(sb, totalTime);
@@ -3808,12 +3797,12 @@
                 uidActivity = true;
             }
 
-            Timer vibTimer = u.getVibratorOnTimer();
+            final Timer vibTimer = u.getVibratorOnTimer();
             if (vibTimer != null) {
                 // Convert from microseconds to milliseconds with rounding
-                long totalTime = (vibTimer.getTotalTimeLocked(
+                final long totalTime = (vibTimer.getTotalTimeLocked(
                         rawRealtime, which) + 500) / 1000;
-                int count = vibTimer.getCountLocked(which);
+                final int count = vibTimer.getCountLocked(which);
                 //timer.logState();
                 if (totalTime != 0) {
                     sb.setLength(0);
@@ -3828,11 +3817,12 @@
                 }
             }
 
-            Timer fgTimer = u.getForegroundActivityTimer();
+            final Timer fgTimer = u.getForegroundActivityTimer();
             if (fgTimer != null) {
                 // Convert from microseconds to milliseconds with rounding
-                long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500) / 1000;
-                int count = fgTimer.getCountLocked(which);
+                final long totalTime = (fgTimer.getTotalTimeLocked(rawRealtime, which) + 500)
+                        / 1000;
+                final int count = fgTimer.getCountLocked(which);
                 if (totalTime != 0) {
                     sb.setLength(0);
                     sb.append(prefix);
@@ -3862,126 +3852,122 @@
                 }
             }
 
-            Map<String, ? extends BatteryStats.Uid.Proc> processStats = u.getProcessStats();
-            if (processStats.size() > 0) {
-                for (Map.Entry<String, ? extends BatteryStats.Uid.Proc> ent
-                    : processStats.entrySet()) {
-                    Uid.Proc ps = ent.getValue();
-                    long userTime;
-                    long systemTime;
-                    long foregroundTime;
-                    int starts;
-                    int numExcessive;
+            final ArrayMap<String, ? extends BatteryStats.Uid.Proc> processStats
+                    = u.getProcessStats();
+            for (int ipr=processStats.size()-1; ipr>=0; ipr--) {
+                final Uid.Proc ps = processStats.valueAt(ipr);
+                long userTime;
+                long systemTime;
+                long foregroundTime;
+                int starts;
+                int numExcessive;
 
-                    userTime = ps.getUserTime(which);
-                    systemTime = ps.getSystemTime(which);
-                    foregroundTime = ps.getForegroundTime(which);
-                    starts = ps.getStarts(which);
-                    final int numCrashes = ps.getNumCrashes(which);
-                    final int numAnrs = ps.getNumAnrs(which);
-                    numExcessive = which == STATS_SINCE_CHARGED
-                            ? ps.countExcessivePowers() : 0;
+                userTime = ps.getUserTime(which);
+                systemTime = ps.getSystemTime(which);
+                foregroundTime = ps.getForegroundTime(which);
+                starts = ps.getStarts(which);
+                final int numCrashes = ps.getNumCrashes(which);
+                final int numAnrs = ps.getNumAnrs(which);
+                numExcessive = which == STATS_SINCE_CHARGED
+                        ? ps.countExcessivePowers() : 0;
 
-                    if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0
-                            || numExcessive != 0 || numCrashes != 0 || numAnrs != 0) {
-                        sb.setLength(0);
-                        sb.append(prefix); sb.append("    Proc ");
-                                sb.append(ent.getKey()); sb.append(":\n");
-                        sb.append(prefix); sb.append("      CPU: ");
-                                formatTimeMs(sb, userTime); sb.append("usr + ");
-                                formatTimeMs(sb, systemTime); sb.append("krn ; ");
-                                formatTimeMs(sb, foregroundTime); sb.append("fg");
-                        if (starts != 0 || numCrashes != 0 || numAnrs != 0) {
-                            sb.append("\n"); sb.append(prefix); sb.append("      ");
-                            boolean hasOne = false;
-                            if (starts != 0) {
-                                hasOne = true;
-                                sb.append(starts); sb.append(" starts");
-                            }
-                            if (numCrashes != 0) {
-                                if (hasOne) {
-                                    sb.append(", ");
-                                }
-                                hasOne = true;
-                                sb.append(numCrashes); sb.append(" crashes");
-                            }
-                            if (numAnrs != 0) {
-                                if (hasOne) {
-                                    sb.append(", ");
-                                }
-                                sb.append(numAnrs); sb.append(" anrs");
-                            }
+                if (userTime != 0 || systemTime != 0 || foregroundTime != 0 || starts != 0
+                        || numExcessive != 0 || numCrashes != 0 || numAnrs != 0) {
+                    sb.setLength(0);
+                    sb.append(prefix); sb.append("    Proc ");
+                            sb.append(processStats.keyAt(ipr)); sb.append(":\n");
+                    sb.append(prefix); sb.append("      CPU: ");
+                            formatTimeMs(sb, userTime); sb.append("usr + ");
+                            formatTimeMs(sb, systemTime); sb.append("krn ; ");
+                            formatTimeMs(sb, foregroundTime); sb.append("fg");
+                    if (starts != 0 || numCrashes != 0 || numAnrs != 0) {
+                        sb.append("\n"); sb.append(prefix); sb.append("      ");
+                        boolean hasOne = false;
+                        if (starts != 0) {
+                            hasOne = true;
+                            sb.append(starts); sb.append(" starts");
                         }
-                        pw.println(sb.toString());
-                        for (int e=0; e<numExcessive; e++) {
-                            Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e);
-                            if (ew != null) {
-                                pw.print(prefix); pw.print("      * Killed for ");
-                                        if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) {
-                                            pw.print("wake lock");
-                                        } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) {
-                                            pw.print("cpu");
-                                        } else {
-                                            pw.print("unknown");
-                                        }
-                                        pw.print(" use: ");
-                                        TimeUtils.formatDuration(ew.usedTime, pw);
-                                        pw.print(" over ");
-                                        TimeUtils.formatDuration(ew.overTime, pw);
-                                        if (ew.overTime != 0) {
-                                            pw.print(" (");
-                                            pw.print((ew.usedTime*100)/ew.overTime);
-                                            pw.println("%)");
-                                        }
+                        if (numCrashes != 0) {
+                            if (hasOne) {
+                                sb.append(", ");
                             }
+                            hasOne = true;
+                            sb.append(numCrashes); sb.append(" crashes");
                         }
-                        uidActivity = true;
-                    }
-                }
-            }
-
-            Map<String, ? extends BatteryStats.Uid.Pkg> packageStats = u.getPackageStats();
-            if (packageStats.size() > 0) {
-                for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg> ent
-                    : packageStats.entrySet()) {
-                    pw.print(prefix); pw.print("    Apk "); pw.print(ent.getKey()); pw.println(":");
-                    boolean apkActivity = false;
-                    Uid.Pkg ps = ent.getValue();
-                    int wakeups = ps.getWakeups(which);
-                    if (wakeups != 0) {
-                        pw.print(prefix); pw.print("      ");
-                                pw.print(wakeups); pw.println(" wakeup alarms");
-                        apkActivity = true;
-                    }
-                    Map<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
-                    if (serviceStats.size() > 0) {
-                        for (Map.Entry<String, ? extends BatteryStats.Uid.Pkg.Serv> sent
-                                : serviceStats.entrySet()) {
-                            BatteryStats.Uid.Pkg.Serv ss = sent.getValue();
-                            long startTime = ss.getStartTime(batteryUptime, which);
-                            int starts = ss.getStarts(which);
-                            int launches = ss.getLaunches(which);
-                            if (startTime != 0 || starts != 0 || launches != 0) {
-                                sb.setLength(0);
-                                sb.append(prefix); sb.append("      Service ");
-                                        sb.append(sent.getKey()); sb.append(":\n");
-                                sb.append(prefix); sb.append("        Created for: ");
-                                        formatTimeMs(sb, startTime / 1000);
-                                        sb.append("uptime\n");
-                                sb.append(prefix); sb.append("        Starts: ");
-                                        sb.append(starts);
-                                        sb.append(", launches: "); sb.append(launches);
-                                pw.println(sb.toString());
-                                apkActivity = true;
+                        if (numAnrs != 0) {
+                            if (hasOne) {
+                                sb.append(", ");
                             }
+                            sb.append(numAnrs); sb.append(" anrs");
                         }
                     }
-                    if (!apkActivity) {
-                        pw.print(prefix); pw.println("      (nothing executed)");
+                    pw.println(sb.toString());
+                    for (int e=0; e<numExcessive; e++) {
+                        Uid.Proc.ExcessivePower ew = ps.getExcessivePower(e);
+                        if (ew != null) {
+                            pw.print(prefix); pw.print("      * Killed for ");
+                                    if (ew.type == Uid.Proc.ExcessivePower.TYPE_WAKE) {
+                                        pw.print("wake lock");
+                                    } else if (ew.type == Uid.Proc.ExcessivePower.TYPE_CPU) {
+                                        pw.print("cpu");
+                                    } else {
+                                        pw.print("unknown");
+                                    }
+                                    pw.print(" use: ");
+                                    TimeUtils.formatDuration(ew.usedTime, pw);
+                                    pw.print(" over ");
+                                    TimeUtils.formatDuration(ew.overTime, pw);
+                                    if (ew.overTime != 0) {
+                                        pw.print(" (");
+                                        pw.print((ew.usedTime*100)/ew.overTime);
+                                        pw.println("%)");
+                                    }
+                        }
                     }
                     uidActivity = true;
                 }
             }
+
+            final ArrayMap<String, ? extends BatteryStats.Uid.Pkg> packageStats
+                    = u.getPackageStats();
+            for (int ipkg=packageStats.size()-1; ipkg>=0; ipkg--) {
+                pw.print(prefix); pw.print("    Apk "); pw.print(packageStats.keyAt(ipkg));
+                pw.println(":");
+                boolean apkActivity = false;
+                final Uid.Pkg ps = packageStats.valueAt(ipkg);
+                final ArrayMap<String, ? extends Counter> alarms = ps.getWakeupAlarmStats();
+                for (int iwa=alarms.size()-1; iwa>=0; iwa--) {
+                    pw.print(prefix); pw.print("      Wakeup alarm ");
+                            pw.print(alarms.keyAt(iwa)); pw.print(": ");
+                            pw.print(alarms.valueAt(iwa).getCountLocked(which));
+                            pw.println(" times");
+                    apkActivity = true;
+                }
+                final ArrayMap<String, ? extends  Uid.Pkg.Serv> serviceStats = ps.getServiceStats();
+                for (int isvc=serviceStats.size()-1; isvc>=0; isvc--) {
+                    final BatteryStats.Uid.Pkg.Serv ss = serviceStats.valueAt(isvc);
+                    final long startTime = ss.getStartTime(batteryUptime, which);
+                    final int starts = ss.getStarts(which);
+                    final int launches = ss.getLaunches(which);
+                    if (startTime != 0 || starts != 0 || launches != 0) {
+                        sb.setLength(0);
+                        sb.append(prefix); sb.append("      Service ");
+                                sb.append(serviceStats.keyAt(isvc)); sb.append(":\n");
+                        sb.append(prefix); sb.append("        Created for: ");
+                                formatTimeMs(sb, startTime / 1000);
+                                sb.append("uptime\n");
+                        sb.append(prefix); sb.append("        Starts: ");
+                                sb.append(starts);
+                                sb.append(", launches: "); sb.append(launches);
+                        pw.println(sb.toString());
+                        apkActivity = true;
+                    }
+                }
+                if (!apkActivity) {
+                    pw.print(prefix); pw.println("      (nothing executed)");
+                }
+                uidActivity = true;
+            }
             if (!uidActivity) {
                 pw.print(prefix); pw.println("    (nothing executed)");
             }
@@ -4498,7 +4484,6 @@
         return true;
     }
 
-    public static final int DUMP_UNPLUGGED_ONLY = 1<<0;
     public static final int DUMP_CHARGED_ONLY = 1<<1;
     public static final int DUMP_DAILY_ONLY = 1<<2;
     public static final int DUMP_HISTORY_ONLY = 1<<3;
@@ -4647,7 +4632,7 @@
         prepareForDumpLocked();
 
         final boolean filtering = (flags
-                & (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
+                & (DUMP_HISTORY_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
 
         if ((flags&DUMP_HISTORY_ONLY) != 0 || !filtering) {
             final long historyTotalSize = getHistoryTotalSize();
@@ -4691,7 +4676,7 @@
             }
         }
 
-        if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
+        if (filtering && (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
             return;
         }
 
@@ -4769,7 +4754,7 @@
             LevelStepTracker csteps = getDailyChargeLevelStepTracker();
             ArrayList<PackageChange> pkgc = getDailyPackageChanges();
             if (dsteps.mNumStepDurations > 0 || csteps.mNumStepDurations > 0 || pkgc != null) {
-                if ((flags&DUMP_DAILY_ONLY) != 0) {
+                if ((flags&DUMP_DAILY_ONLY) != 0 || !filtering) {
                     if (dumpDurationSteps(pw, "    ", "  Current daily discharge step durations:",
                             dsteps, false)) {
                         dumpDailyLevelStepSummary(pw, "      ", "Discharge", dsteps,
@@ -4801,7 +4786,7 @@
                 pw.print(" to ");
                 pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", dit.mEndTime).toString());
                 pw.println(":");
-                if ((flags&DUMP_DAILY_ONLY) != 0) {
+                if ((flags&DUMP_DAILY_ONLY) != 0 || !filtering) {
                     if (dumpDurationSteps(pw, "      ",
                             "    Discharge step durations:", dit.mDischargeSteps, false)) {
                         dumpDailyLevelStepSummary(pw, "        ", "Discharge", dit.mDischargeSteps,
@@ -4830,11 +4815,6 @@
                     (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
             pw.println();
         }
-        if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) {
-            pw.println("Statistics since last unplugged:");
-            dumpLocked(context, pw, "", STATS_SINCE_UNPLUGGED, reqUid,
-                    (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
-        }
     }
     
     @SuppressWarnings("unused")
@@ -4848,7 +4828,7 @@
         long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
 
         final boolean filtering = (flags &
-                (DUMP_HISTORY_ONLY|DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
+                (DUMP_HISTORY_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) != 0;
 
         if ((flags&DUMP_INCLUDE_HISTORY) != 0 || (flags&DUMP_HISTORY_ONLY) != 0) {
             if (startIteratingHistoryLocked()) {
@@ -4874,7 +4854,7 @@
             }
         }
 
-        if (filtering && (flags&(DUMP_UNPLUGGED_ONLY|DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
+        if (filtering && (flags&(DUMP_CHARGED_ONLY|DUMP_DAILY_ONLY)) == 0) {
             return;
         }
 
@@ -4924,9 +4904,5 @@
             dumpCheckinLocked(context, pw, STATS_SINCE_CHARGED, -1,
                     (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
         }
-        if (!filtering || (flags&DUMP_UNPLUGGED_ONLY) != 0) {
-            dumpCheckinLocked(context, pw, STATS_SINCE_UNPLUGGED, -1,
-                    (flags&DUMP_DEVICE_WIFI_ONLY) != 0);
-        }
     }
 }
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index ac6bbb7..d24bc13 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -19,6 +19,7 @@
 import android.security.keymaster.ExportResult;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterBlob;
 import android.security.keymaster.OperationResult;
 import android.security.KeystoreArguments;
 
@@ -61,11 +62,12 @@
     int addRngEntropy(in byte[] data);
     int generateKey(String alias, in KeymasterArguments arguments, int uid, int flags,
         out KeyCharacteristics characteristics);
-    int getKeyCharacteristics(String alias, in byte[] clientId,
-        in byte[] appId, out KeyCharacteristics characteristics);
+    int getKeyCharacteristics(String alias, in KeymasterBlob clientId, in KeymasterBlob appId,
+        out KeyCharacteristics characteristics);
     int importKey(String alias, in KeymasterArguments arguments, int format,
         in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics);
-    ExportResult exportKey(String alias, int format, in byte[] clientId, in byte[] appId);
+    ExportResult exportKey(String alias, int format, in KeymasterBlob clientId,
+        in KeymasterBlob appId);
     OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable,
         in KeymasterArguments params, out KeymasterArguments operationParams);
     OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index b26b10c..0626bbc 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -31,8 +31,6 @@
 
     private static final NetworkSecurityPolicy INSTANCE = new NetworkSecurityPolicy();
 
-    private volatile boolean mCleartextTrafficPermitted = true;
-
     private NetworkSecurityPolicy() {}
 
     /**
@@ -62,7 +60,7 @@
      * honor this aspect of the policy.
      */
     public boolean isCleartextTrafficPermitted() {
-        return mCleartextTrafficPermitted;
+        return libcore.net.NetworkSecurityPolicy.isCleartextTrafficPermitted();
     }
 
     /**
@@ -74,6 +72,6 @@
      * @hide
      */
     public void setCleartextTrafficPermitted(boolean permitted) {
-        mCleartextTrafficPermitted = permitted;
+        libcore.net.NetworkSecurityPolicy.setCleartextTrafficPermitted(permitted);
     }
 }
diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl
new file mode 100644
index 0000000..8f70f7c
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterBlob.aidl
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2015, 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.keymaster;
+
+/* @hide */
+parcelable KeymasterBlob;
diff --git a/core/java/android/security/keymaster/KeymasterBlob.java b/core/java/android/security/keymaster/KeymasterBlob.java
new file mode 100644
index 0000000..cb95604
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterBlob.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2015, 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.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+public class KeymasterBlob implements Parcelable {
+    public byte[] blob;
+
+    public KeymasterBlob(byte[] blob) {
+        this.blob = blob;
+    }
+    public static final Parcelable.Creator<KeymasterBlob> CREATOR = new
+            Parcelable.Creator<KeymasterBlob>() {
+                public KeymasterBlob createFromParcel(Parcel in) {
+                    return new KeymasterBlob(in);
+                }
+
+                public KeymasterBlob[] newArray(int length) {
+                    return new KeymasterBlob[length];
+                }
+            };
+
+    protected KeymasterBlob(Parcel in) {
+        blob = in.createByteArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeByteArray(blob);
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterBlobArgument.java b/core/java/android/security/keymaster/KeymasterBlobArgument.java
index 9af4445..7d587bf 100644
--- a/core/java/android/security/keymaster/KeymasterBlobArgument.java
+++ b/core/java/android/security/keymaster/KeymasterBlobArgument.java
@@ -26,6 +26,13 @@
 
     public KeymasterBlobArgument(int tag, byte[] blob) {
         super(tag);
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_BIGNUM:
+            case KeymasterDefs.KM_BYTES:
+                break; // OK.
+            default:
+                throw new IllegalArgumentException("Bad blob tag " + tag);
+        }
         this.blob = blob;
     }
 
diff --git a/core/java/android/security/keymaster/KeymasterBooleanArgument.java b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
index 5481e8f..9c03674 100644
--- a/core/java/android/security/keymaster/KeymasterBooleanArgument.java
+++ b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
@@ -28,6 +28,12 @@
 
     public KeymasterBooleanArgument(int tag) {
         super(tag);
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_BOOL:
+                break; // OK.
+            default:
+                throw new IllegalArgumentException("Bad bool tag " + tag);
+        }
     }
 
     public KeymasterBooleanArgument(int tag, Parcel in) {
diff --git a/core/java/android/security/keymaster/KeymasterDateArgument.java b/core/java/android/security/keymaster/KeymasterDateArgument.java
index 310f546..bffd24d 100644
--- a/core/java/android/security/keymaster/KeymasterDateArgument.java
+++ b/core/java/android/security/keymaster/KeymasterDateArgument.java
@@ -27,6 +27,12 @@
 
     public KeymasterDateArgument(int tag, Date date) {
         super(tag);
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_DATE:
+                break; // OK.
+            default:
+                throw new IllegalArgumentException("Bad date tag " + tag);
+        }
         this.date = date;
     }
 
diff --git a/core/java/android/security/keymaster/KeymasterIntArgument.java b/core/java/android/security/keymaster/KeymasterIntArgument.java
index c3738d7..da81715 100644
--- a/core/java/android/security/keymaster/KeymasterIntArgument.java
+++ b/core/java/android/security/keymaster/KeymasterIntArgument.java
@@ -26,6 +26,15 @@
 
     public KeymasterIntArgument(int tag, int value) {
         super(tag);
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_INT:
+            case KeymasterDefs.KM_INT_REP:
+            case KeymasterDefs.KM_ENUM:
+            case KeymasterDefs.KM_ENUM_REP:
+                break; // OK.
+            default:
+                throw new IllegalArgumentException("Bad int tag " + tag);
+        }
         this.value = value;
     }
 
diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java
index 3c565b8..9d2be09 100644
--- a/core/java/android/security/keymaster/KeymasterLongArgument.java
+++ b/core/java/android/security/keymaster/KeymasterLongArgument.java
@@ -26,6 +26,12 @@
 
     public KeymasterLongArgument(int tag, long value) {
         super(tag);
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_LONG:
+                break; // OK.
+            default:
+                throw new IllegalArgumentException("Bad long tag " + tag);
+        }
         this.value = value;
     }
 
diff --git a/core/java/android/service/fingerprint/Fingerprint.aidl b/core/java/android/service/fingerprint/Fingerprint.aidl
new file mode 100644
index 0000000..c9fd989
--- /dev/null
+++ b/core/java/android/service/fingerprint/Fingerprint.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 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.service.fingerprint;
+
+// @hide
+parcelable Fingerprint;
diff --git a/core/java/android/service/fingerprint/Fingerprint.java b/core/java/android/service/fingerprint/Fingerprint.java
new file mode 100644
index 0000000..37552eb
--- /dev/null
+++ b/core/java/android/service/fingerprint/Fingerprint.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 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.service.fingerprint;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Container for fingerprint metadata.
+ * @hide
+ */
+public final class Fingerprint implements Parcelable {
+    private CharSequence mName;
+    private int mGroupId;
+    private int mFingerId;
+    private long mDeviceId; // physical device this is associated with
+
+    public Fingerprint(CharSequence name, int groupId, int fingerId, long deviceId) {
+        mName = name;
+        mGroupId = groupId;
+        mFingerId = fingerId;
+        mDeviceId = deviceId;
+    }
+
+    private Fingerprint(Parcel in) {
+        mName = in.readString();
+        mGroupId = in.readInt();
+        mFingerId = in.readInt();
+        mDeviceId = in.readLong();
+    }
+
+    /**
+     * Gets the human-readable name for the given fingerprint.
+     * @return name given to finger
+     */
+    public CharSequence getName() { return mName; }
+
+    /**
+     * Gets the device-specific finger id.  Used by Settings to map a name to a specific
+     * fingerprint template.
+     * @return device-specific id for this finger
+     * @hide
+     */
+    public int getFingerId() { return mFingerId; }
+
+    /**
+     * Gets the group id specified when the fingerprint was enrolled.
+     * @return group id for the set of fingerprints this one belongs to.
+     * @hide
+     */
+    public int getGroupId() { return mGroupId; }
+
+    /**
+     * Device this fingerprint belongs to.
+     * @hide
+     */
+    public long getDeviceId() { return mDeviceId; }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mName.toString());
+        out.writeInt(mGroupId);
+        out.writeInt(mFingerId);
+        out.writeLong(mDeviceId);
+    }
+
+    public static final Parcelable.Creator<Fingerprint> CREATOR
+            = new Parcelable.Creator<Fingerprint>() {
+        public Fingerprint createFromParcel(Parcel in) {
+            return new Fingerprint(in);
+        }
+
+        public Fingerprint[] newArray(int size) {
+            return new Fingerprint[size];
+        }
+    };
+};
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManager.java b/core/java/android/service/fingerprint/FingerprintManager.java
index 6375668..bb90e40 100644
--- a/core/java/android/service/fingerprint/FingerprintManager.java
+++ b/core/java/android/service/fingerprint/FingerprintManager.java
@@ -20,17 +20,25 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.os.Binder;
+import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.fingerprint.FingerprintManager.EnrollmentCallback;
 import android.util.Log;
 import android.util.Slog;
 
+import java.security.Signature;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
+import javax.crypto.Cipher;
+
 /**
  * A class that coordinates access to the fingerprint hardware.
  * @hide
@@ -45,9 +53,6 @@
     private static final int MSG_ERROR = 103;
     private static final int MSG_REMOVED = 104;
 
-    // Errors generated by layers above HAL
-    public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
-
     // Message types.  Must agree with HAL (fingerprint.h)
     public static final int FINGERPRINT_ERROR = -1;
     public static final int FINGERPRINT_ACQUIRED = 1;
@@ -60,52 +65,420 @@
     public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
     public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
     public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
+    public static final int FINGERPRINT_ERROR_CANCELED = 5;
+    public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
 
-    // FINGERPRINT_ACQUIRED messages.  Must agree with HAL (fingerprint.h)
+    // Image acquisition messages.  Must agree with HAL (fingerprint.h)
     public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
     public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
     public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
-    public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4;
-    public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8;
-    public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16;
+    public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3;
+    public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4;
+    public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5;
+    public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
 
     private IFingerprintService mService;
-    private FingerprintManagerReceiver mClientReceiver;
     private Context mContext;
     private IBinder mToken = new Binder();
+    private AuthenticationCallback mAuthenticationCallback;
+    private EnrollmentCallback mEnrollmentCallback;
+    private RemovalCallback mRemovalCallback;
+    private CryptoObject mCryptoObject;
+    private Fingerprint mRemovalFingerprint;
+    private boolean mListening;
+
+    /**
+     * A wrapper class for a limited number of crypto objects supported by FingerprintManager.
+     */
+    public static class CryptoObject {
+        CryptoObject(Signature signature) { mSignature = signature; }
+        CryptoObject(Cipher cipher) { mCipher = cipher; }
+        private Signature mSignature;
+        private Cipher mCipher;
+    };
+
+    /**
+     * Container for callback data from {@link FingerprintManager#authenticate(CryptoObject,
+     *     AuthenticationCallback, CancellationSignal, int)}
+     */
+    public static final class AuthenticationResult {
+        private Fingerprint mFingerprint;
+        private CryptoObject mCryptoObject;
+
+        public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) {
+            mCryptoObject = crypto;
+            mFingerprint = fingerprint;
+        }
+
+        /**
+         * Obtain the crypto object associated with this transaction
+         * @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,
+         *     AuthenticationCallback, CancellationSignal, int)}
+         */
+        public CryptoObject getCryptoObject() { return mCryptoObject; }
+
+        /**
+         * Obtain the Fingerprint associated with this operation.  Applications are discouraged
+         * from associating specific fingers with specific applications or operations.  Hence this
+         * is not public.
+         * @hide
+         */
+        public Fingerprint getFingerprint() { return mFingerprint; }
+    };
+
+    /**
+     * Callback structure provided to {@link FingerprintManager#authenticate(CryptoObject,
+     * AuthenticationCallback, CancellationSignal, int)}. Users of {@link #FingerprintManager()}
+     * must provide an implementation of this to {@link FingerprintManager#authenticate(
+     * CryptoObject, AuthenticationCallback, CancellationSignal, int) for listening to fingerprint
+     * events.
+     */
+    public static abstract class AuthenticationCallback {
+        /**
+         * Called when an unrecoverable error has been encountered and the operation is complete.
+         * No further callbacks will be made on this object.
+         * @param errMsgId an integer identifying the error message.
+         * @param errString a human-readible error string that can be shown in UI.
+         */
+        public abstract void onAuthenticationError(int errMsgId, CharSequence errString);
+
+        /**
+         * Called when a recoverable error has been encountered during authentication.  The help
+         * string is provided to give the user guidance for what went wrong, such as
+         * "Sensor dirty, please clean it."
+         * @param helpMsgId an integer identifying the error message.
+         * @param helpString a human-readible string that can be shown in UI.
+         */
+        public abstract void onAuthenticationHelp(int helpMsgId, CharSequence helpString);
+
+        /**
+         * Called when a fingerprint is recognized.
+         * @param result an object containing authentication-related data.
+         */
+        public abstract void onAuthenticationSucceeded(AuthenticationResult result);
+    };
+
+    /**
+     * Callback structure provided to {@link FingerprintManager#enroll(long, EnrollmentCallback,
+     * CancellationSignal, int). Users of {@link #FingerprintManager()}
+     * must provide an implementation of this to {@link FingerprintManager#enroll(long,
+     * EnrollmentCallback, CancellationSignal, int) for listening to fingerprint events.
+     */
+    public static abstract class EnrollmentCallback {
+        /**
+         * Called when an unrecoverable error has been encountered and the operation is complete.
+         * No further callbacks will be made on this object.
+         * @param errMsgId an integer identifying the error message.
+         * @param errString a human-readible error string that can be shown in UI.
+         */
+        public abstract void onEnrollmentError(int errMsgId, CharSequence errString);
+
+        /**
+         * Called when a recoverable error has been encountered during enrollment.  The help
+         * string is provided to give the user guidance for what went wrong, such as
+         * "Sensor dirty, please clean it" or what they need to do next, such as
+         * "Touch sensor again."
+         * @param helpMsgId an integer identifying the error message.
+         * @param helpString a human-readible string that can be shown in UI.
+         */
+        public abstract void onEnrollmentHelp(int helpMsgId, CharSequence helpString);
+
+        /**
+         * Called as each enrollment step progresses. Enrollment is considered complete when
+         * remaining reaches 0.  This function will not be called if enrollment fails. See
+         * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)}
+         * @param remaining the number of remaining steps.
+         */
+        public abstract void onEnrollmentProgress(int remaining);
+    };
+
+    /**
+     * Callback structure provided to {@link FingerprintManager#remove(int). Users of
+     * {@link #FingerprintManager()} may optionally provide an implementation of this to
+     * {@link FingerprintManager#remove(int, int, RemovalCallback)} for listening to
+     * fingerprint template removal events.
+     */
+    public static abstract class RemovalCallback {
+        /**
+         * Called when the given fingerprint can't be removed.
+         * @param fp the fingerprint that the call attempted to remove.
+         * @param errMsgId an associated error message id.
+         * @param errString an error message indicating why the fingerprint id can't be removed.
+         */
+        public abstract void onRemovalError(Fingerprint fp, int errMsgId, CharSequence errString);
+
+        /**
+         * Called when a given fingerprint is successfully removed.
+         * @param fingerprint the fingerprint template that was removed.
+         */
+        public abstract void onRemovalSucceeded(Fingerprint fingerprint);
+    };
+
+    /**
+     * Request authentication of a crypto object.  This call warms up the fingerprint hardware
+     * and starts scanning for a fingerprint.  It terminates when
+     * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
+     * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult) is called, at
+     * which point the object is no longer valid. The operation can be canceled by using the
+     * provided cancel object.
+     *
+     * @param crypto object associated with the call or null if none required.
+     * @param callback an object to receive authentication events
+     * @param cancel an object that can be used to cancel authentication
+     * @param flags optional flags
+     */
+    public void authenticate(CryptoObject crypto, AuthenticationCallback callback,
+            CancellationSignal cancel, int flags) {
+        if (callback == null) {
+            throw new IllegalArgumentException("Must supply an authentication callback");
+        }
+
+        // TODO: handle cancel
+
+        if (mService != null) try {
+            mAuthenticationCallback = callback;
+            mCryptoObject = crypto;
+            long sessionId = 0; // TODO: get from crypto object
+            startListening();
+            mService.authenticate(mToken, sessionId, getCurrentUserId(), flags);
+        } catch (RemoteException e) {
+            Log.v(TAG, "Remote exception while authenticating: ", e);
+            stopListening();
+        }
+    }
+
+    /**
+     * Request fingerprint enrollment. This call warms up the fingerprint hardware
+     * and starts scanning for fingerprints. Progress will be indicated by callbacks to the
+     * {@link EnrollmentCallback} object. It terminates when
+     * {@link EnrollmentCallback#onEnrollmentError(int, CharSequence)} or
+     * {@link EnrollmentCallback#onEnrollmentProgress(int) is called with remaining == 0, at
+     * which point the object is no longer valid. The operation can be canceled by using the
+     * provided cancel object.
+     * @param challenge a unique id provided by a recent verification of device credentials
+     *     (e.g. pin, pattern or password).
+     * @param callback an object to receive enrollment events
+     * @param cancel an object that can be used to cancel enrollment
+     * @param flags optional flags
+     */
+    public void enroll(long challenge, EnrollmentCallback callback,
+            CancellationSignal cancel, int flags) {
+        if (callback == null) {
+            throw new IllegalArgumentException("Must supply an enrollment callback");
+        }
+
+        // TODO: handle cancel
+
+        if (mService != null) try {
+            mEnrollmentCallback = callback;
+            startListening();
+            mService.enroll(mToken, getCurrentUserId(), flags);
+        } catch (RemoteException e) {
+            Log.v(TAG, "Remote exception in enroll: ", e);
+            stopListening();
+        }
+    }
+
+    /**
+     * Remove given fingerprint template from fingerprint hardware and/or protected storage.
+     * @param fp the fingerprint item to remove
+     * @param callback an optional callback to verify that fingerprint templates have been
+     * successfully removed.  May be null of no callback is required.
+     * @hide
+     */
+    public void remove(Fingerprint fp, RemovalCallback callback) {
+        if (mService != null) try {
+            mRemovalCallback = callback;
+            mRemovalFingerprint = fp;
+            startListening();
+            mService.remove(mToken, fp.getFingerId(), getCurrentUserId());
+        } catch (RemoteException e) {
+            Log.v(TAG, "Remote in remove: ", e);
+            stopListening();
+        }
+    }
+
+    /**
+     * Renames the given fingerprint template
+     * @param fpId the fingerprint id
+     * @param newName the new name
+     * @hide
+     */
+    public void rename(int fpId, String newName) {
+        // Renames the given fpId
+        if (mService != null) {
+            try {
+                mService.rename(fpId, getCurrentUserId(), newName);
+            } catch (RemoteException e) {
+                Log.v(TAG, "Remote exception in rename(): ", e);
+            }
+        } else {
+            Log.w(TAG, "rename(): Service not connected!");
+        }
+    }
+
+    /**
+     * Obtain the list of enrolled fingerprints templates.
+     * @return list of current fingerprint items
+     */
+    public List<Fingerprint> getEnrolledFingerprints() {
+        if (mService != null) try {
+            return mService.getEnrolledFingerprints(getCurrentUserId());
+        } catch (RemoteException e) {
+            Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+        }
+        return null;
+    }
+
+    /**
+     * Determine if fingerprint hardware is present and functional.
+     * @return true if hardware is present and functional, false otherwise.
+     * @hide
+     */
+    public boolean isHardwareDetected() {
+        if (mService != null) {
+            try {
+                long deviceId = 0; /* TODO: plumb hardware id to FPMS */
+                return mService.isHardwareDetected(deviceId);
+            } catch (RemoteException e) {
+                Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
+            }
+        } else {
+            Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
+        }
+        return false;
+    }
 
     private Handler mHandler = new Handler() {
         public void handleMessage(android.os.Message msg) {
-            if (mClientReceiver != null) {
-                switch(msg.what) {
-                    case MSG_ENROLL_RESULT:
-                        mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
-                        break;
-                    case MSG_ACQUIRED:
-                        mClientReceiver.onAcquired(msg.arg1);
-                        break;
-                    case MSG_PROCESSED:
-                        mClientReceiver.onProcessed(msg.arg1);
-                        break;
-                    case MSG_ERROR:
-                        mClientReceiver.onError(msg.arg1);
-                        break;
-                    case MSG_REMOVED:
-                        mClientReceiver.onRemoved(msg.arg1);
+            switch(msg.what) {
+                case MSG_ENROLL_RESULT:
+                    sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
+                    break;
+                case MSG_ACQUIRED:
+                    sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
+                    break;
+                case MSG_PROCESSED:
+                    sendProcessedResult((Fingerprint) msg.obj);
+                    break;
+                case MSG_ERROR:
+                    sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
+                    break;
+                case MSG_REMOVED:
+                    sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
+                            msg.arg2 /* groupId */);
+            }
+        }
+
+        private void sendRemovedResult(long deviceId, int fingerId, int groupId) {
+            if (mRemovalCallback != null) {
+                int reqFingerId = mRemovalFingerprint.getFingerId();
+                int reqGroupId = mRemovalFingerprint.getGroupId();
+                if (fingerId != reqFingerId) {
+                    Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
                 }
+                if (fingerId != reqFingerId) {
+                    Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
+                }
+                mRemovalCallback.onRemovalSucceeded(mRemovalFingerprint);
+            }
+        }
+
+        private void sendErrorResult(long deviceId, int errMsgId) {
+            if (mEnrollmentCallback != null) {
+                mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
+            } else if (mAuthenticationCallback != null) {
+                mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
+            } else if (mRemovalCallback != null) {
+                mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
+                        getErrorString(errMsgId));
+            }
+        }
+
+        private void sendEnrollResult(Fingerprint fp, int remaining) {
+            if (mEnrollmentCallback != null) {
+                mEnrollmentCallback.onEnrollmentProgress(remaining);
+            }
+        }
+
+        private void sendProcessedResult(Fingerprint fp) {
+            if (mAuthenticationCallback != null) {
+                AuthenticationResult result = new AuthenticationResult(mCryptoObject, fp);
+                mAuthenticationCallback.onAuthenticationSucceeded(result);
+            }
+        }
+
+        private void sendAcquiredResult(long deviceId, int acquireInfo) {
+            final String msg = getAcquiredString(acquireInfo);
+            if (msg == null) return;
+
+            if (mEnrollmentCallback != null) {
+                mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
+            } else if (mAuthenticationCallback != null) {
+                mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
+            }
+        }
+
+        private String getErrorString(int errMsg) {
+            switch (errMsg) {
+                case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
+                    return mContext.getString(
+                        com.android.internal.R.string.fingerprint_error_unable_to_process);
+                case FINGERPRINT_ERROR_HW_UNAVAILABLE:
+                    return mContext.getString(
+                        com.android.internal.R.string.fingerprint_error_hw_not_available);
+                case FINGERPRINT_ERROR_NO_SPACE:
+                    return mContext.getString(
+                        com.android.internal.R.string.fingerprint_error_no_space);
+                case FINGERPRINT_ERROR_TIMEOUT:
+                    return mContext.getString(
+                        com.android.internal.R.string.fingerprint_error_timeout);
+                default:
+                    if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
+                        int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
+                        String[] msgArray = mContext.getResources().getStringArray(
+                                com.android.internal.R.array.fingerprint_error_vendor);
+                        if (msgNumber < msgArray.length) {
+                            return msgArray[msgNumber];
+                        }
+                    }
+                    return null;
+            }
+        }
+
+        private String getAcquiredString(int acquireInfo) {
+            switch (acquireInfo) {
+                case FINGERPRINT_ACQUIRED_GOOD:
+                    return null;
+                case FINGERPRINT_ACQUIRED_PARTIAL:
+                    return mContext.getString(
+                        com.android.internal.R.string.fingerprint_acquired_partial);
+                case FINGERPRINT_ACQUIRED_INSUFFICIENT:
+                    return mContext.getString(
+                        com.android.internal.R.string.fingerprint_acquired_insufficient);
+                case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
+                    return mContext.getString(
+                        com.android.internal.R.string.fingerprint_acquired_imager_dirty);
+                case FINGERPRINT_ACQUIRED_TOO_SLOW:
+                    return mContext.getString(
+                        com.android.internal.R.string.fingerprint_acquired_too_slow);
+                case FINGERPRINT_ACQUIRED_TOO_FAST:
+                    return mContext.getString(
+                        com.android.internal.R.string.fingerprint_acquired_too_fast);
+                default:
+                    if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
+                        int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
+                        String[] msgArray = mContext.getResources().getStringArray(
+                                com.android.internal.R.array.fingerprint_acquired_vendor);
+                        if (msgNumber < msgArray.length) {
+                            return msgArray[msgNumber];
+                        }
+                    }
+                    return null;
             }
         }
     };
 
-    public static final class FingerprintItem {
-        public CharSequence name;
-        public int id;
-        FingerprintItem(CharSequence name, int id) {
-            this.name = name;
-            this.id = id;
-        }
-    }
-
     /**
      * @hide
      */
@@ -117,99 +490,6 @@
         }
     }
 
-    private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
-
-        public void onEnrollResult(int fingerprintId,  int remaining) {
-            mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
-        }
-
-        public void onAcquired(int acquireInfo) {
-            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0).sendToTarget();
-        }
-
-        public void onProcessed(int fingerprintId) {
-            mHandler.obtainMessage(MSG_PROCESSED, fingerprintId, 0).sendToTarget();
-        }
-
-        public void onError(int error) {
-            mHandler.obtainMessage(MSG_ERROR, error, 0).sendToTarget();
-        }
-
-        public void onRemoved(int fingerprintId) {
-            mHandler.obtainMessage(MSG_REMOVED, fingerprintId, 0).sendToTarget();
-        }
-    };
-
-    /**
-     * Determine whether the user has at least one fingerprint enrolled and enabled.
-     *
-     * @return true if at least one is enrolled and enabled
-     */
-    public boolean enrolledAndEnabled() {
-        ContentResolver res = mContext.getContentResolver();
-        return Settings.Secure.getInt(res, "fingerprint_enabled", 0) != 0
-                && FingerprintUtils.getFingerprintIdsForUser(res, getCurrentUserId()).length > 0;
-    }
-
-    /**
-     * Start the enrollment process.  Timeout dictates how long to wait for the user to
-     * enroll a fingerprint.
-     *
-     * @param timeout
-     */
-    public void enroll(long timeout) {
-        if (mServiceReceiver == null) {
-            sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
-            return;
-        }
-        if (mService != null) try {
-            mService.enroll(mToken, timeout, getCurrentUserId());
-        } catch (RemoteException e) {
-            Log.v(TAG, "Remote exception while enrolling: ", e);
-            sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
-        }
-    }
-
-    /**
-     * Remove the given fingerprintId from the system.  FingerprintId of 0 has special meaning
-     * which is to delete all fingerprint data for the current user. Use with caution.
-     * @param fingerprintId
-     */
-    public void remove(int fingerprintId) {
-        if (mServiceReceiver == null) {
-            sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
-            return;
-        }
-        if (mService != null) {
-            try {
-                mService.remove(mToken, fingerprintId, getCurrentUserId());
-            } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
-            }
-        } else {
-            Log.w(TAG, "remove(): Service not connected!");
-            sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
-        }
-    }
-
-    /**
-     * Starts listening for fingerprint events.  When a finger is scanned or recognized, the
-     * client will be notified via the callback.
-     */
-    public void startListening(FingerprintManagerReceiver receiver) {
-        mClientReceiver = receiver;
-        if (mService != null) {
-            try {
-                mService.startListening(mToken, mServiceReceiver, getCurrentUserId());
-            } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in startListening(): ", e);
-            }
-        } else {
-            Log.w(TAG, "startListening(): Service not connected!");
-            sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
-        }
-    }
-
     private int getCurrentUserId() {
         try {
             return ActivityManagerNative.getDefault().getCurrentUser().id;
@@ -222,92 +502,62 @@
     /**
      * Stops the client from listening to fingerprint events.
      */
-    public void stopListening() {
+    private void stopListening() {
         if (mService != null) {
             try {
-                mService.stopListening(mToken, getCurrentUserId());
-                mClientReceiver = null;
+                if (mListening) {
+                    mService.removeListener(mToken, mServiceReceiver);
+                    mListening = false;
+                }
             } catch (RemoteException e) {
                 Log.v(TAG, "Remote exception in stopListening(): ", e);
             }
         } else {
             Log.w(TAG, "stopListening(): Service not connected!");
-            sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
         }
     }
 
-    public void enrollCancel() {
-        if (mServiceReceiver == null) {
-            sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
-            return;
-        }
-        if (mService != null) {
-            try {
-                mService.enrollCancel(mToken, getCurrentUserId());
-                mClientReceiver = null;
-            } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in enrollCancel(): ", e);
-                sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
-            }
-        } else {
-            Log.w(TAG, "enrollCancel(): Service not connected!");
-        }
-    }
-
-    private void sendError(int msg, int arg1, int arg2) {
-        mHandler.obtainMessage(msg, arg1, arg2);
-    }
-
     /**
-     * @return list of current fingerprint items
-     * @hide
+     * Starts listening for fingerprint events for this client.
      */
-    public List<FingerprintItem> getEnrolledFingerprints() {
-        int[] ids = FingerprintUtils.getFingerprintIdsForUser(mContext.getContentResolver(),
-                getCurrentUserId());
-        List<FingerprintItem> result = new ArrayList<FingerprintItem>();
-        for (int i = 0; i < ids.length; i++) {
-            // TODO: persist names in Settings
-            FingerprintItem item = new FingerprintItem("Finger" + ids[i], ids[i]);
-            result.add(item);
-        }
-        return result;
-    }
-
-    /**
-     * Determine if fingerprint hardware is present and functional.
-     * @return true if hardware is present and functional, false otherwise.
-     * @hide
-     */
-    public boolean isHardwareDetected() {
+    private void startListening() {
         if (mService != null) {
             try {
-                return mService.isHardwareDetected();
+                if (!mListening) {
+                    mService.addListener(mToken, mServiceReceiver, getCurrentUserId());
+                    mListening = true;
+                }
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
+                Log.v(TAG, "Remote exception in startListening(): ", e);
             }
         } else {
-            Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
+            Log.w(TAG, "startListening(): Service not connected!");
         }
-        return false;
     }
 
-    /**
-     * Renames the given fingerprint template
-     * @param fpId the fingerprint id
-     * @param newName the new name
-     * @hide
-     */
-    public void rename(int fpId, String newName) {
-        // Renames the given fpId
-        if (mService != null) {
-            try {
-                mService.rename(fpId, newName);
-            } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in rename(): ", e);
-            }
-        } else {
-            Log.w(TAG, "rename(): Service not connected!");
+    private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
+
+        public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
+            mHandler.obtainMessage(MSG_ENROLL_RESULT, remaining, 0,
+                    new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
         }
-    }
+
+        public void onAcquired(long deviceId, int acquireInfo) {
+            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
+        }
+
+        public void onProcessed(long deviceId, int fingerId, int groupId) {
+            mHandler.obtainMessage(MSG_PROCESSED,
+                    new Fingerprint(null, groupId, fingerId, deviceId)).sendToTarget();
+        }
+
+        public void onError(long deviceId, int error) {
+            mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
+        }
+
+        public void onRemoved(long deviceId, int fingerId, int groupId) {
+            mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
+        }
+    };
+
 }
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java b/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
deleted file mode 100644
index 85677ba..0000000
--- a/core/java/android/service/fingerprint/FingerprintManagerReceiver.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package android.service.fingerprint;
-/**
- * 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.
- */
-
-/**
- * @hide
- */
-public class FingerprintManagerReceiver {
-    /**
-     * Fingerprint enrollment progress update. Enrollment is considered complete if
-     * remaining hits 0 without {@link #onError(int)} being called.
-     *
-     * @param fingerprintId the fingerprint we're currently enrolling
-     * @param remaining the number of samples required to complete enrollment. It's up to
-     * the hardware to define what each step in enrollment means. Some hardware
-     * requires multiple samples of the same part of the finger.  Others require sampling of
-     * different parts of the finger.  The enrollment flow can use remaining to
-     * mean "step x" of the process or "just need another sample."
-     */
-    public void onEnrollResult(int fingerprintId,  int remaining) { }
-
-    /**
-     * Fingerprint touch detected, but not processed yet. Clients will use this message to
-     * determine a good or bad scan before the fingerprint is processed.  This is meant for the
-     * client to provide feedback about the scan or alert the user that recognition is to follow.
-     *
-     * @param acquiredInfo one of:
-     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_GOOD},
-     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_PARTIAL},
-     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_INSUFFICIENT},
-     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_IMAGER_DIRTY},
-     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_SLOW},
-     * {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_FAST}
-     */
-    public void onAcquired(int acquiredInfo) { }
-
-    /**
-     * Fingerprint has been detected and processed.  A non-zero return indicates a valid
-     * fingerprint was detected.
-     *
-     * @param fingerprintId the finger id, or 0 if not recognized.
-     */
-    public void onProcessed(int fingerprintId) { }
-
-    /**
-     * An error was detected during scan or enrollment.  One of
-     * {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
-     * {@link FingerprintManager#FINGERPRINT_ERROR_UNABLE_TO_PROCESS} or
-     * {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
-     * {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
-     *
-     * @param error one of the above error codes
-     */
-    public void onError(int error) { }
-
-    /**
-     * The given fingerprint template was successfully removed by the driver.
-     * See {@link FingerprintManager#remove(int)}
-     *
-     * @param fingerprintId id of template to remove.
-     */
-    public void onRemoved(int fingerprintId) { }
-}
\ No newline at end of file
diff --git a/core/java/android/service/fingerprint/FingerprintUtils.java b/core/java/android/service/fingerprint/FingerprintUtils.java
index cc17b99..62acbb9 100644
--- a/core/java/android/service/fingerprint/FingerprintUtils.java
+++ b/core/java/android/service/fingerprint/FingerprintUtils.java
@@ -67,7 +67,7 @@
         return toIntArray(tmp);
     }
 
-    public static void addFingerprintIdForUser(int fingerId, ContentResolver res, int userId) {
+    public static void addFingerprintIdForUser(ContentResolver res, int fingerId, int userId) {
         // FingerId 0 has special meaning.
         if (fingerId == 0) {
             Log.w(TAG, "Tried to add fingerId 0");
diff --git a/core/java/android/service/fingerprint/IFingerprintService.aidl b/core/java/android/service/fingerprint/IFingerprintService.aidl
index 9b4750b..e5d3ad4 100644
--- a/core/java/android/service/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintService.aidl
@@ -17,31 +17,42 @@
 
 import android.os.Bundle;
 import android.service.fingerprint.IFingerprintServiceReceiver;
+import android.service.fingerprint.Fingerprint;
+import java.util.List;
 
 /**
  * Communication channel from client to the fingerprint service.
  * @hide
  */
 interface IFingerprintService {
-    // Any errors resulting from this call will be returned to the listener
-    void enroll(IBinder token, long timeout, int userId);
+    // Authenticate the given sessionId with a fingerprint
+    void authenticate(IBinder token, long sessionId, int groupId, int flags);
+
+    // Start fingerprint enrollment
+    void enroll(IBinder token, int groupId, int flags);
 
     // Any errors resulting from this call will be returned to the listener
-    void enrollCancel(IBinder token, int userId);
+    void remove(IBinder token, int fingerId, int groupId);
 
-    // Any errors resulting from this call will be returned to the listener
-    void remove(IBinder token, int fingerprintId, int userId);
+    // Rename the fingerprint specified by fingerId and groupId to the given name
+    void rename(int fingerId, int groupId, String name);
 
-    // Start listening for fingerprint events.  This has the side effect of starting
-    // the hardware if not already started.
-    void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId);
+    // Get a list of enrolled fingerprints in the given group.
+    List<Fingerprint> getEnrolledFingerprints(int groupId);
 
-    // Stops listening for fingerprints
-    void stopListening(IBinder token, int userId);
+    // Register listener for an instance of FingerprintManager
+    void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId);
+
+    // Unregister listener for an instance of FingerprintManager
+    void removeListener(IBinder token, IFingerprintServiceReceiver receiver);
 
     // Determine if HAL is loaded and ready
-    boolean isHardwareDetected();
+    boolean isHardwareDetected(long deviceId);
 
-    // Rename the given fingerprint id
-    void rename(int fpId, String name);
+    // Gets the number of hardware devices
+    // int getHardwareDeviceCount();
+
+    // Gets the unique device id for hardware enumerated at i
+    // long getHardwareDevice(int i);
+
 }
diff --git a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
index af4128f..f025064 100644
--- a/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/service/fingerprint/IFingerprintServiceReceiver.aidl
@@ -23,9 +23,9 @@
  * @hide
  */
 oneway interface IFingerprintServiceReceiver {
-    void onEnrollResult(int fingerprintId,  int remaining);
-    void onAcquired(int acquiredInfo);
-    void onProcessed(int fingerprintId);
-    void onError(int error);
-    void onRemoved(int fingerprintId);
+    void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
+    void onAcquired(long deviceId, int acquiredInfo);
+    void onProcessed(long deviceId, int fingerId, int groupId);
+    void onError(long deviceId, int error);
+    void onRemoved(long deviceId, int fingerId, int groupId);
 }
diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java
index d29bfb6..0669b6f 100644
--- a/core/java/android/text/style/URLSpan.java
+++ b/core/java/android/text/style/URLSpan.java
@@ -16,6 +16,7 @@
 
 package android.text.style;
 
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
@@ -23,6 +24,7 @@
 import android.provider.Browser;
 import android.text.ParcelableSpan;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.View;
 
 public class URLSpan extends ClickableSpan implements ParcelableSpan {
@@ -59,6 +61,10 @@
         Context context = widget.getContext();
         Intent intent = new Intent(Intent.ACTION_VIEW, uri);
         intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
-        context.startActivity(intent);
+        try {
+            context.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString());
+        }
     }
 }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 59ec058..ad34f02 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -723,6 +723,12 @@
             mSurface.release();
         }
         mSurface = surfaceTexture;
+
+        // If the view is visible, update the listener in the new surface to use
+        // the existing listener in the view.
+        if (((mViewFlags & VISIBILITY_MASK) == VISIBLE)) {
+            mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
+        }
         mUpdateSurface = true;
         invalidateParentIfNeeded();
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8538609..db8109f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -83,6 +83,7 @@
 import android.view.accessibility.AccessibilityEventSource;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityNodeProvider;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -5814,6 +5815,8 @@
                     | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD
                     | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH);
         }
+
+        info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN);
     }
 
     private View findLabelForView(View view, int labeledId) {
@@ -8261,6 +8264,13 @@
                     return true;
                 }
             } break;
+            case R.id.accessibility_action_show_on_screen: {
+                if (mAttachInfo != null) {
+                    final Rect r = mAttachInfo.mTmpInvalRect;
+                    getDrawingRect(r);
+                    return requestRectangleOnScreen(r, true);
+                }
+            } break;
         }
         return false;
     }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 6096d7d..77082b0 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -29,6 +29,8 @@
 import android.util.Pools.SynchronizedPool;
 import android.view.View;
 
+import com.android.internal.R;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -3402,6 +3404,15 @@
                 new AccessibilityAction(
                         AccessibilityNodeInfo.ACTION_SET_TEXT, null);
 
+        /**
+         * Action that requests the node make its bounding rectangle visible
+         * on the screen, scrolling if necessary just enough.
+         *
+         * @see View#requestRectangleOnScreen(Rect)
+         */
+        public static final AccessibilityAction ACTION_SHOW_ON_SCREEN =
+                new AccessibilityAction(R.id.accessibility_action_show_on_screen, null);
+
         private static final ArraySet<AccessibilityAction> sStandardActions = new ArraySet<AccessibilityAction>();
         static {
             sStandardActions.add(ACTION_FOCUS);
@@ -3426,6 +3437,7 @@
             sStandardActions.add(ACTION_COLLAPSE);
             sStandardActions.add(ACTION_DISMISS);
             sStandardActions.add(ACTION_SET_TEXT);
+            sStandardActions.add(ACTION_SHOW_ON_SCREEN);
         }
 
         private final int mActionId;
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index af5a8bf..b187c1c 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1209,13 +1209,13 @@
         switch (keyCode) {
             
         case KeyEvent.KEYCODE_DPAD_LEFT:
-            if (movePrevious()) {
+            if (moveDirection(-1)) {
                 playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
                 return true;
             }
             break;
         case KeyEvent.KEYCODE_DPAD_RIGHT:
-            if (moveNext()) {
+            if (moveDirection(1)) {
                 playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
                 return true;
             }
@@ -1255,18 +1255,12 @@
         return super.onKeyUp(keyCode, event);
     }
     
-    boolean movePrevious() {
-        if (mItemCount > 0 && mSelectedPosition > 0) {
-            scrollToChild(mSelectedPosition - mFirstPosition - 1);
-            return true;
-        } else {
-            return false;
-        }
-    }
+    boolean moveDirection(int direction) {
+        direction = isLayoutRtl() ? -direction : direction;
+        int targetPosition = mSelectedPosition + direction;
 
-    boolean moveNext() {
-        if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) {
-            scrollToChild(mSelectedPosition - mFirstPosition + 1);
+        if (mItemCount > 0 && targetPosition >= 0 && targetPosition < mItemCount) {
+            scrollToChild(targetPosition - mFirstPosition);
             return true;
         } else {
             return false;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index eaa0dc7..2c34ded 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -109,7 +109,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 121 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 122 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -494,8 +494,7 @@
      * Used as a buffer for reading in data from /proc/wakelocks before it is processed and added
      * to mKernelWakelockStats.
      */
-    private final Map<String, KernelWakelockStats> mProcWakelockFileStats =
-            new HashMap<String, KernelWakelockStats>();
+    private final Map<String, KernelWakelockStats> mProcWakelockFileStats = new HashMap<>();
 
     private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory();
     private NetworkStats mCurMobileSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 50);
@@ -4607,17 +4606,17 @@
         }
 
         @Override
-        public Map<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
+        public ArrayMap<String, ? extends BatteryStats.Uid.Wakelock> getWakelockStats() {
             return mWakelockStats.getMap();
         }
 
         @Override
-        public Map<String, ? extends BatteryStats.Timer> getSyncStats() {
+        public ArrayMap<String, ? extends BatteryStats.Timer> getSyncStats() {
             return mSyncStats.getMap();
         }
 
         @Override
-        public Map<String, ? extends BatteryStats.Timer> getJobStats() {
+        public ArrayMap<String, ? extends BatteryStats.Timer> getJobStats() {
             return mJobStats.getMap();
         }
 
@@ -4627,12 +4626,12 @@
         }
 
         @Override
-        public Map<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
+        public ArrayMap<String, ? extends BatteryStats.Uid.Proc> getProcessStats() {
             return mProcessStats;
         }
 
         @Override
-        public Map<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
+        public ArrayMap<String, ? extends BatteryStats.Uid.Pkg> getPackageStats() {
             return mPackageStats;
         }
 
@@ -6153,40 +6152,20 @@
          */
         public final class Pkg extends BatteryStats.Uid.Pkg implements TimeBaseObs {
             /**
-             * Number of times this package has done something that could wake up the
-             * device from sleep.
+             * Number of times wakeup alarms have occurred for this app.
              */
-            int mWakeups;
-
-            /**
-             * Number of things that could wake up the device loaded from a
-             * previous save.
-             */
-            int mLoadedWakeups;
-
-            /**
-             * Number of things that could wake up the device as of the
-             * last run.
-             */
-            int mLastWakeups;
-
-            /**
-             * Number of things that could wake up the device as of the
-             * last run.
-             */
-            int mUnpluggedWakeups;
+            ArrayMap<String, Counter> mWakeupAlarms = new ArrayMap<>();
 
             /**
              * The statics we have collected for this package's services.
              */
-            final HashMap<String, Serv> mServiceStats = new HashMap<String, Serv>();
+            final ArrayMap<String, Serv> mServiceStats = new ArrayMap<>();
 
             Pkg() {
                 mOnBatteryScreenOffTimeBase.add(this);
             }
 
             public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
-                mUnpluggedWakeups = mWakeups;
             }
 
             public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
@@ -6197,10 +6176,12 @@
             }
 
             void readFromParcelLocked(Parcel in) {
-                mWakeups = in.readInt();
-                mLoadedWakeups = in.readInt();
-                mLastWakeups = 0;
-                mUnpluggedWakeups = in.readInt();
+                int numWA = in.readInt();
+                mWakeupAlarms.clear();
+                for (int i=0; i<numWA; i++) {
+                    String tag = in.readString();
+                    mWakeupAlarms.put(tag, new Counter(mOnBatteryTimeBase, in));
+                }
 
                 int numServs = in.readInt();
                 mServiceStats.clear();
@@ -6214,34 +6195,39 @@
             }
 
             void writeToParcelLocked(Parcel out) {
-                out.writeInt(mWakeups);
-                out.writeInt(mLoadedWakeups);
-                out.writeInt(mUnpluggedWakeups);
+                int numWA = mWakeupAlarms.size();
+                out.writeInt(numWA);
+                for (int i=0; i<numWA; i++) {
+                    out.writeString(mWakeupAlarms.keyAt(i));
+                    mWakeupAlarms.valueAt(i).writeToParcel(out);
+                }
 
-                out.writeInt(mServiceStats.size());
-                for (Map.Entry<String, Uid.Pkg.Serv> servEntry : mServiceStats.entrySet()) {
-                    out.writeString(servEntry.getKey());
-                    Uid.Pkg.Serv serv = servEntry.getValue();
-
+                final int NS = mServiceStats.size();
+                out.writeInt(NS);
+                for (int i=0; i<NS; i++) {
+                    out.writeString(mServiceStats.keyAt(i));
+                    Uid.Pkg.Serv serv = mServiceStats.valueAt(i);
                     serv.writeToParcelLocked(out);
                 }
             }
 
             @Override
-            public Map<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
-                return mServiceStats;
+            public ArrayMap<String, ? extends BatteryStats.Counter> getWakeupAlarmStats() {
+                return mWakeupAlarms;
+            }
+
+            public void noteWakeupAlarmLocked(String tag) {
+                Counter c = mWakeupAlarms.get(tag);
+                if (c == null) {
+                    c = new Counter(mOnBatteryTimeBase);
+                    mWakeupAlarms.put(tag, c);
+                }
+                c.stepAtomic();
             }
 
             @Override
-            public int getWakeups(int which) {
-                int val = mWakeups;
-                if (which == STATS_CURRENT) {
-                    val -= mLoadedWakeups;
-                } else if (which == STATS_SINCE_UNPLUGGED) {
-                    val -= mUnpluggedWakeups;
-                }
-
-                return val;
+            public ArrayMap<String, ? extends BatteryStats.Uid.Pkg.Serv> getServiceStats() {
+                return mServiceStats;
             }
 
             /**
@@ -6483,14 +6469,6 @@
                 }
             }
 
-            public BatteryStatsImpl getBatteryStats() {
-                return BatteryStatsImpl.this;
-            }
-
-            public void incWakeupsLocked() {
-                mWakeups++;
-            }
-
             final Serv newServiceStatsLocked() {
                 return new Serv();
             }
@@ -8938,7 +8916,18 @@
             for (int ip = 0; ip < NP; ip++) {
                 String pkgName = in.readString();
                 Uid.Pkg p = u.getPackageStatsLocked(pkgName);
-                p.mWakeups = p.mLoadedWakeups = in.readInt();
+                final int NWA = in.readInt();
+                if (NWA > 1000) {
+                    Slog.w(TAG, "File corrupt: too many wakeup alarms " + NWA);
+                    return;
+                }
+                p.mWakeupAlarms.clear();
+                for (int iwa=0; iwa<NWA; iwa++) {
+                    String tag = in.readString();
+                    Counter c = new Counter(mOnBatteryTimeBase);
+                    c.readSummaryFromParcelLocked(in);
+                    p.mWakeupAlarms.put(tag, c);
+                }
                 NS = in.readInt();
                 if (NS > 1000) {
                     Slog.w(TAG, "File corrupt: too many services " + NS);
@@ -9263,20 +9252,22 @@
                     : u.mPackageStats.entrySet()) {
                     out.writeString(ent.getKey());
                     Uid.Pkg ps = ent.getValue();
-                    out.writeInt(ps.mWakeups);
+                    final int NWA = ps.mWakeupAlarms.size();
+                    out.writeInt(NWA);
+                    for (int iwa=0; iwa<NWA; iwa++) {
+                        out.writeString(ps.mWakeupAlarms.keyAt(iwa));
+                        ps.mWakeupAlarms.valueAt(iwa).writeSummaryFromParcelLocked(out);
+                    }
                     NS = ps.mServiceStats.size();
                     out.writeInt(NS);
-                    if (NS > 0) {
-                        for (Map.Entry<String, BatteryStatsImpl.Uid.Pkg.Serv> sent
-                                : ps.mServiceStats.entrySet()) {
-                            out.writeString(sent.getKey());
-                            BatteryStatsImpl.Uid.Pkg.Serv ss = sent.getValue();
-                            long time = ss.getStartTimeToNowLocked(
-                                    mOnBatteryTimeBase.getUptime(NOW_SYS));
-                            out.writeLong(time);
-                            out.writeInt(ss.mStarts);
-                            out.writeInt(ss.mLaunches);
-                        }
+                    for (int is=0; is<NS; is++) {
+                        out.writeString(ps.mServiceStats.keyAt(is));
+                        BatteryStatsImpl.Uid.Pkg.Serv ss = ps.mServiceStats.valueAt(is);
+                        long time = ss.getStartTimeToNowLocked(
+                                mOnBatteryTimeBase.getUptime(NOW_SYS));
+                        out.writeLong(time);
+                        out.writeInt(ss.mStarts);
+                        out.writeInt(ss.mLaunches);
                     }
                 }
             }
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index d9ebc25..a106f48 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -52,6 +52,7 @@
     public static final int BASE_WIFI_RTT_SERVICE                                   = 0x00027300;
     public static final int BASE_WIFI_PASSPOINT_MANAGER                             = 0x00028000;
     public static final int BASE_WIFI_PASSPOINT_SERVICE                             = 0x00028100;
+    public static final int BASE_WIFI_LOGGER                                        = 0x00028300;
     public static final int BASE_DHCP                                               = 0x00030000;
     public static final int BASE_DATA_CONNECTION                                    = 0x00040000;
     public static final int BASE_DATA_CONNECTION_AC                                 = 0x00041000;
diff --git a/core/jni/android_server_FingerprintManager.cpp b/core/jni/android_server_FingerprintManager.cpp
index 853425c..f22c857 100644
--- a/core/jni/android_server_FingerprintManager.cpp
+++ b/core/jni/android_server_FingerprintManager.cpp
@@ -47,14 +47,15 @@
 
 class CallbackHandler : public MessageHandler {
     int type;
-    int arg1, arg2;
+    int arg1, arg2, arg3;
 public:
-    CallbackHandler(int type, int arg1, int arg2) : type(type), arg1(arg1), arg2(arg2) { }
+    CallbackHandler(int type, int arg1, int arg2, int arg3)
+        : type(type), arg1(arg1), arg2(arg2), arg3(arg3) { }
 
     virtual void handleMessage(const Message& message) {
         //ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
         JNIEnv* env = AndroidRuntime::getJNIEnv();
-        env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2);
+        env->CallVoidMethod(gCallback, gFingerprintServiceClassInfo.notify, type, arg1, arg2, arg3);
     }
 };
 
@@ -62,6 +63,7 @@
 static void hal_notify_callback(fingerprint_msg_t msg) {
     uint32_t arg1 = 0;
     uint32_t arg2 = 0;
+    uint32_t arg3 = 0;
     switch (msg.type) {
         case FINGERPRINT_ERROR:
             arg1 = msg.data.error;
@@ -71,13 +73,16 @@
             break;
         case FINGERPRINT_PROCESSED:
             arg1 = msg.data.processed.finger.fid;
+            arg2 = msg.data.processed.finger.gid;
             break;
         case FINGERPRINT_TEMPLATE_ENROLLING:
             arg1 = msg.data.enroll.finger.fid;
-            arg2 = msg.data.enroll.samples_remaining;
+            arg2 = msg.data.enroll.finger.gid;
+            arg3 = msg.data.enroll.samples_remaining;
             break;
         case FINGERPRINT_TEMPLATE_REMOVED:
             arg1 = msg.data.removed.finger.fid;
+            arg2 = msg.data.removed.finger.gid;
             break;
         default:
             ALOGE("fingerprint: invalid msg: %d", msg.type);
@@ -86,7 +91,7 @@
     // This call potentially comes in on a thread not owned by us. Hand it off to our
     // looper so it runs on our thread when calling back to FingerprintService.
     // CallbackHandler object is reference-counted, so no cleanup necessary.
-    gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2), Message());
+    gLooper->sendMessage(new CallbackHandler(msg.type, arg1, arg2, arg3), Message());
 }
 
 static void nativeInit(JNIEnv *env, jobject clazz, jobject mQueue, jobject callbackObj) {
@@ -95,9 +100,15 @@
     gLooper = android_os_MessageQueue_getMessageQueue(env, mQueue)->getLooper();
 }
 
-static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
-    ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
-    int ret = gContext.device->enroll(gContext.device, 0, timeout);
+static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout, jint groupId) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll(gid=%d, timeout=%d)\n", groupId, timeout);
+    int ret = gContext.device->enroll(gContext.device, groupId, timeout);
+    return reinterpret_cast<jint>(ret);
+}
+
+static jint nativeAuthenticate(JNIEnv* env, jobject clazz, jlong sessionId, jint groupId) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeAuthenticate(sid=%ld, gid=%d)\n", sessionId, groupId);
+    int ret = gContext.device->authenticate(gContext.device, sessionId, groupId);
     return reinterpret_cast<jint>(ret);
 }
 
@@ -107,11 +118,11 @@
     return reinterpret_cast<jint>(ret);
 }
 
-static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
-    ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId);
+static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerId, jint groupId) {
+    ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(fid=%d, gid=%d)\n", fingerId, groupId);
     fingerprint_finger_id_t finger;
-    finger.gid = 0;
-    finger.fid = fingerprintId;
+    finger.fid = fingerId;
+    finger.gid = groupId;
     int ret = gContext.device->remove(gContext.device, finger);
     return reinterpret_cast<jint>(ret);
 }
@@ -172,9 +183,10 @@
 
 // TODO: clean up void methods
 static const JNINativeMethod g_methods[] = {
-    { "nativeEnroll", "(I)I", (void*)nativeEnroll },
+    { "nativeAuthenticate", "(JI)I", (void*)nativeAuthenticate },
+    { "nativeEnroll", "(II)I", (void*)nativeEnroll },
     { "nativeEnrollCancel", "()I", (void*)nativeEnrollCancel },
-    { "nativeRemove", "(I)I", (void*)nativeRemove },
+    { "nativeRemove", "(II)I", (void*)nativeRemove },
     { "nativeOpenHal", "()I", (void*)nativeOpenHal },
     { "nativeCloseHal", "()I", (void*)nativeCloseHal },
     { "nativeInit","(Landroid/os/MessageQueue;"
@@ -185,7 +197,7 @@
     jclass clazz = FindClassOrDie(env, FINGERPRINT_SERVICE);
     gFingerprintServiceClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
     gFingerprintServiceClassInfo.notify =
-            GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(III)V");
+            GetMethodIDOrDie(env, gFingerprintServiceClassInfo.clazz,"notify", "(IIII)V");
     int result = RegisterMethodsOrDie(env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
     ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
     return result;
diff --git a/core/res/res/values-mcc310-mnc260/strings.xml b/core/res/res/values-mcc310-mnc260/strings.xml
index 5cadc2a..75b1b53 100644
--- a/core/res/res/values-mcc310-mnc260/strings.xml
+++ b/core/res/res/values-mcc310-mnc260/strings.xml
@@ -29,4 +29,6 @@
     <string-array name="wfcOperatorErrorMessages">
         <item>Wi-Fi Calling isn\&apos;t available. Contact your carrier to enable Wi-Fi Calling.</item>
     </string-array>
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 37c9598..1b2e952 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1112,6 +1112,18 @@
          device does not support multiple advertisement-->
     <integer translatable="false" name="config_bluetooth_max_advertisers">0</integer>
 
+    <!-- Idle current for bluetooth controller. 0 by default-->
+    <integer translatable="false" name="config_bluetooth_idle_cur_ma">1</integer>
+
+    <!-- Rx current for bluetooth controller. 0 by default-->
+    <integer translatable="false" name="config_bluetooth_rx_cur_ma">2</integer>
+
+    <!-- Tx current for bluetooth controller. 0 by default-->
+    <integer translatable="false" name="config_bluetooth_tx_cur_ma">3</integer>
+
+    <!-- Operating volatage for bluetooth controller. 0 by default-->
+    <integer translatable="false" name="config_bluetooth_operating_voltage_mv">4</integer>
+
     <!-- The default data-use polling period. -->
     <integer name="config_datause_polling_period_sec">600</integer>
 
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 6108b27..7e963954 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -93,4 +93,5 @@
   <item type="id" name="undo" />
   <item type="id" name="redo" />
   <item type="id" name="replaceText" />
+  <item type="id" name="accessibility_action_show_on_screen" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7672e93..88225bd 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -251,6 +251,8 @@
     <string-array name="wfcOperatorErrorCodes" translatable="false" />
     <!-- WFC Operator Error Messages -->
     <string-array name="wfcOperatorErrorMessages" />
+    <!-- Template for showing cellular network operator name while WFC is active -->
+    <string name="wfcSpnFormat">%s</string>
 
     <!--
         {0} is one of "bearerServiceCode*"
@@ -2226,6 +2228,36 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_useFingerprint">Allows the app to use fingerprint hardware for authentication</string>
 
+    <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
+    <string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string>
+    <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
+    <string name="fingerprint_acquired_insufficient">Couldn\'t process fingerprint. Please try again.</string>
+    <!-- Message shown during fingerprint acquisision when the fingerprint sensor needs cleaning -->
+    <string name="fingerprint_acquired_imager_dirty">Fingerprint sensor is dirty. Please clean and try again.</string>
+    <!-- Message shown during fingerprint acquisision when the user removes their finger from the sensor too quickly -->
+    <string name="fingerprint_acquired_too_fast">Finger moved to fast. Please try again.</string>
+    <!-- Message shown during fingerprint acquisision when the user moves their finger too slowly -->
+    <string name="fingerprint_acquired_too_slow">Finger moved to slow. Please try again.</string>
+    <!-- Array containing custom messages shown during fingerprint acquisision from vendor.  Vendor is expected to add and translate these strings -->
+    <string-array name="fingerprint_acquired_vendor">
+        <item>Vendor-specific acquisition error message 0</item>
+    </string-array>
+
+    <!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
+    <string name="fingerprint_error_unable_to_process">Unable to process. Try again.</string>
+    <!-- Error message shown when the fingerprint hardware can't be accessed -->
+    <string name="fingerprint_error_hw_not_available">Hardware not available.</string>
+    <!-- Error message shown when the fingerprint hardware has run out of room for storing fingerprints -->
+    <string name="fingerprint_error_no_space">Fingerprint can\'t be stored. Please remove an existing fingerprint.</string>
+    <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
+    <string name="fingerprint_error_timeout">Fingerprint time out reached. Try again.</string>
+    <!-- Error message shown when the fingerprint hardware timer has expired and the user needs to restart the operation. -->
+    <string name="fingerprint_error_vendor">Fingerprint time out reached. Try again.</string>
+    <!-- Array containing custom error messages from vendor.  Vendor is expected to add and translate these strings -->
+    <string-array name="fingerprint_error_vendor">
+        <item>Vendor-specifc error message.</item>
+    </string-array>
+
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_readSyncSettings">read sync settings</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c4e9e8e..fcf9ff4 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -349,6 +349,10 @@
   <java-symbol type="integer" name="config_burnInProtectionMinVerticalOffset" />
   <java-symbol type="integer" name="config_burnInProtectionMaxVerticalOffset" />
   <java-symbol type="integer" name="config_burnInProtectionMaxRadius" />
+  <java-symbol type="integer" name="config_bluetooth_idle_cur_ma" />
+  <java-symbol type="integer" name="config_bluetooth_rx_cur_ma" />
+  <java-symbol type="integer" name="config_bluetooth_tx_cur_ma" />
+  <java-symbol type="integer" name="config_bluetooth_operating_voltage_mv" />
   <java-symbol type="integer" name="config_cursorWindowSize" />
   <java-symbol type="integer" name="config_drawLockTimeoutMillis" />
   <java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
@@ -756,6 +760,7 @@
   <java-symbol type="string" name="wfcRegErrorTitle" />
   <java-symbol type="array" name="wfcOperatorErrorCodes" />
   <java-symbol type="array" name="wfcOperatorErrorMessages" />
+  <java-symbol type="string" name="wfcSpnFormat" />
   <java-symbol type="string" name="policydesc_disableCamera" />
   <java-symbol type="string" name="policydesc_encryptedStorage" />
   <java-symbol type="string" name="policydesc_expirePassword" />
@@ -2061,6 +2066,19 @@
   <!-- From KeyguardServiceDelegate -->
   <java-symbol type="string" name="config_keyguardComponent" />
 
+  <!-- Fingerprint messages -->
+  <java-symbol type="string" name="fingerprint_error_unable_to_process" />
+  <java-symbol type="string" name="fingerprint_error_hw_not_available" />
+  <java-symbol type="string" name="fingerprint_error_no_space" />
+  <java-symbol type="string" name="fingerprint_error_timeout" />
+  <java-symbol type="array" name="fingerprint_error_vendor" />
+  <java-symbol type="string" name="fingerprint_acquired_partial" />
+  <java-symbol type="string" name="fingerprint_acquired_insufficient" />
+  <java-symbol type="string" name="fingerprint_acquired_imager_dirty" />
+  <java-symbol type="string" name="fingerprint_acquired_too_slow" />
+  <java-symbol type="string" name="fingerprint_acquired_too_fast" />
+  <java-symbol type="array" name="fingerprint_acquired_vendor" />
+
   <!-- From various Material changes -->
   <java-symbol type="attr" name="titleTextAppearance" />
   <java-symbol type="attr" name="subtitleTextAppearance" />
@@ -2174,4 +2192,6 @@
   <java-symbol type="style" name="TextAppearance.Material.Widget.Calendar.Day" />
   <java-symbol type="dimen" name="day_picker_padding_top"/>
   <java-symbol type="dimen" name="date_picker_day_of_week_height"/>
+
+  <java-symbol type="id" name="accessibility_action_show_on_screen" />
 </resources>
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index bfbf028..957e3c1 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -25,6 +25,7 @@
 import android.security.keymaster.ExportResult;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterBlob;
 import android.security.keymaster.OperationResult;
 import android.util.Log;
 
@@ -403,7 +404,7 @@
         return generateKey(alias, args, UID_SELF, flags, outCharacteristics);
     }
 
-    public int getKeyCharacteristics(String alias, byte[] clientId, byte[] appId,
+    public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
             KeyCharacteristics outCharacteristics) {
         try {
             return mBinder.getKeyCharacteristics(alias, clientId, appId, outCharacteristics);
@@ -429,7 +430,8 @@
         return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
     }
 
-    public ExportResult exportKey(String alias, int format, byte[] clientId, byte[] appId) {
+    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
+            KeymasterBlob appId) {
         try {
             return mBinder.exportKey(alias, format, clientId, appId);
         } catch (RemoteException e) {
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index f0b07a6..f755bb0 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -25,6 +25,7 @@
 import android.security.keymaster.ExportResult;
 import android.security.keymaster.KeyCharacteristics;
 import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterBlob;
 import android.security.keymaster.KeymasterDefs;
 import android.security.keymaster.OperationResult;
 import android.test.ActivityUnitTestCase;
@@ -712,10 +713,8 @@
         args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
         args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
-        args.addBlob(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
-                RSAKeyGenParameterSpec.F4.toByteArray());
+        args.addLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
+                RSAKeyGenParameterSpec.F4.longValue());
 
         KeyCharacteristics outCharacteristics = new KeyCharacteristics();
         int result = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -744,6 +743,7 @@
 
     public void testAppId() throws Exception {
         String name = "test";
+        byte[] id = new byte[] {0x01, 0x02, 0x03};
         KeymasterArguments args = new KeymasterArguments();
         args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
         args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
@@ -751,10 +751,9 @@
         args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
         args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
         args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, new byte[] {0x01, 0x02, 0x03});
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
-        args.addBlob(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
-                RSAKeyGenParameterSpec.F4.toByteArray());
+        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, id);
+        args.addLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT,
+                RSAKeyGenParameterSpec.F4.longValue());
 
         KeyCharacteristics outCharacteristics = new KeyCharacteristics();
         int result = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -764,7 +763,7 @@
                 mKeyStore.getKeyCharacteristics(name, null, null, outCharacteristics));
         assertEquals("getKeyCharacteristics should succeed with application ID",
                 KeyStore.NO_ERROR,
-                mKeyStore.getKeyCharacteristics(name, new byte[] {0x01, 0x02, 0x03}, null,
+                mKeyStore.getKeyCharacteristics(name, new KeymasterBlob(id), null,
                     outCharacteristics));
     }
 
@@ -789,8 +788,6 @@
         args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
         args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
         args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
 
         KeyCharacteristics outCharacteristics = new KeyCharacteristics();
         int rc = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -798,8 +795,6 @@
 
         KeymasterArguments out = new KeymasterArguments();
         args = new KeymasterArguments();
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
         OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
                 true, args, out);
         IBinder token = result.token;
@@ -888,8 +883,6 @@
         args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
         args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
         args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
 
         KeyCharacteristics outCharacteristics = new KeyCharacteristics();
         int rc = mKeyStore.generateKey(name, args, 0, outCharacteristics);
@@ -897,8 +890,6 @@
 
         KeymasterArguments out = new KeymasterArguments();
         args = new KeymasterArguments();
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_ID, null);
-        args.addBlob(KeymasterDefs.KM_TAG_APPLICATION_DATA, null);
         OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
                 true, args, out);
         assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 66de333..d9d06bf 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -380,6 +380,7 @@
         const Vector3& lightCenter, float lightRadius) {
     ShadowDescription key(casterPerimeter, drawTransform);
 
+    if (mShadowCache.get(key)) return;
     sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
             casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
     if (mShadowProcessor == nullptr) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 5fa0dd1..c9805ae 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -40,6 +40,7 @@
 
 import android.media.AudioManager;
 import android.os.BatteryManager;
+import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IRemoteCallback;
 import android.os.Message;
@@ -51,9 +52,11 @@
 import com.android.internal.telephony.IccCardConstants.State;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
+
 import android.service.fingerprint.FingerprintManager;
-import android.service.fingerprint.FingerprintManagerReceiver;
+import android.service.fingerprint.FingerprintManager.AuthenticationCallback;
 import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.FingerprintManager.AuthenticationResult;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
@@ -109,10 +112,11 @@
     private static final int MSG_SCREEN_TURNED_ON = 319;
     private static final int MSG_SCREEN_TURNED_OFF = 320;
     private static final int MSG_KEYGUARD_BOUNCER_CHANGED = 322;
-    private static final int MSG_FINGERPRINT_PROCESSED = 323;
-    private static final int MSG_FINGERPRINT_ACQUIRED = 324;
-    private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 325;
-    private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 326;
+    private static final int MSG_FINGERPRINT_AUTHENTICATED = 323;
+    private static final int MSG_FINGERPRINT_ERROR = 324;
+    private static final int MSG_FINGERPRINT_HELP = 325;
+    private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 326;
+    private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 327;
 
     private static KeyguardUpdateMonitor sInstance;
 
@@ -201,11 +205,14 @@
                 case MSG_SCREEN_TURNED_ON:
                     handleScreenTurnedOn();
                     break;
-                case MSG_FINGERPRINT_ACQUIRED:
-                    handleFingerprintAcquired(msg.arg1);
+                case MSG_FINGERPRINT_AUTHENTICATED:
+                    handleFingerprintAuthenticated(msg.arg1, msg.arg2);
                     break;
-                case MSG_FINGERPRINT_PROCESSED:
-                    handleFingerprintProcessed(msg.arg1);
+                case MSG_FINGERPRINT_HELP:
+                    handleFingerprintHelp(msg.arg1 /* msgId */, (String) msg.obj /* errString */);
+                    break;
+                case MSG_FINGERPRINT_ERROR:
+                    handleFingerprintError(msg.arg1 /* msgId */, (String) msg.obj /* errString */);
                     break;
                 case MSG_FACE_UNLOCK_STATE_CHANGED:
                     handleFaceUnlockStateChanged(msg.arg1 != 0, msg.arg2);
@@ -227,7 +234,7 @@
 
     private SparseBooleanArray mUserHasTrust = new SparseBooleanArray();
     private SparseBooleanArray mUserTrustIsManaged = new SparseBooleanArray();
-    private SparseBooleanArray mUserFingerprintRecognized = new SparseBooleanArray();
+    private SparseBooleanArray mUserFingerprintAuthenticated = new SparseBooleanArray();
     private SparseBooleanArray mUserFaceUnlockRunning = new SparseBooleanArray();
 
     @Override
@@ -314,18 +321,18 @@
         }
     }
 
-    private void onFingerprintRecognized(int userId) {
-        mUserFingerprintRecognized.put(userId, true);
+    private void onFingerprintAuthenticated(int userId) {
+        mUserFingerprintAuthenticated.put(userId, true);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onFingerprintRecognized(userId);
+                cb.onFingerprintAuthenticated(userId);
             }
         }
     }
 
-    private void handleFingerprintProcessed(int fingerprintId) {
-        if (fingerprintId == 0) return; // not a valid fingerprint
+    private void handleFingerprintAuthenticated(int fingerId, int groupId) {
+        if (fingerId == 0) return; // not a valid fingerprint
 
         final int userId;
         try {
@@ -341,17 +348,28 @@
         final ContentResolver res = mContext.getContentResolver();
         final int ids[] = FingerprintUtils.getFingerprintIdsForUser(res, userId);
         for (int i = 0; i < ids.length; i++) {
-            if (ids[i] == fingerprintId) {
-                onFingerprintRecognized(userId);
+            // TODO: fix once HAL supports storing group id
+            final boolean isCorrectUser = true || (groupId == userId);
+            if (ids[i] == fingerId && isCorrectUser) {
+                onFingerprintAuthenticated(userId);
             }
         }
     }
 
-    private void handleFingerprintAcquired(int info) {
+    private void handleFingerprintHelp(int msgId, String helpString) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onFingerprintAcquired(info);
+                cb.onFingerprintHelp(msgId, helpString);
+            }
+        }
+    }
+
+    private void handleFingerprintError(int msgId, String errString) {
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onFingerprintError(msgId, errString);
             }
         }
     }
@@ -387,7 +405,7 @@
 
     public boolean getUserHasTrust(int userId) {
         return !isTrustDisabled(userId) && mUserHasTrust.get(userId)
-                || mUserFingerprintRecognized.get(userId);
+                || mUserFingerprintAuthenticated.get(userId);
     }
 
     public boolean getUserTrustIsManaged(int userId) {
@@ -464,23 +482,29 @@
             }
         }
     };
-    private FingerprintManagerReceiver mFingerprintManagerReceiver =
-            new FingerprintManagerReceiver() {
-        @Override
-        public void onProcessed(int fingerprintId) {
-            mHandler.obtainMessage(MSG_FINGERPRINT_PROCESSED, fingerprintId, 0).sendToTarget();
-        };
+
+    private FingerprintManager.AuthenticationCallback mAuthenticationCallback
+            = new AuthenticationCallback() {
 
         @Override
-        public void onAcquired(int info) {
-            mHandler.obtainMessage(MSG_FINGERPRINT_ACQUIRED, info, 0).sendToTarget();
+        public void onAuthenticationSucceeded(AuthenticationResult result) {
+            mHandler.obtainMessage(MSG_FINGERPRINT_AUTHENTICATED,
+                    result.getFingerprint().getFingerId(),
+                    result.getFingerprint().getGroupId()).sendToTarget();
         }
 
         @Override
-        public void onError(int error) {
-            if (DEBUG) Log.w(TAG, "FingerprintManager reported error: " + error);
+        public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
+            mHandler.obtainMessage(MSG_FINGERPRINT_HELP, helpMsgId, 0, helpString).sendToTarget();
+        }
+
+        @Override
+        public void onAuthenticationError(int errMsgId, CharSequence errString) {
+            mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, errMsgId, 0, errString);
         }
     };
+    private CancellationSignal mFingerprintCancelSignal;
+    private FingerprintManager mFpm;
 
     /**
      * When we receive a
@@ -606,6 +630,7 @@
                 cb.onScreenTurnedOn();
             }
         }
+        startListeningForFingerprint(mContext);
     }
 
     protected void handleScreenTurnedOff(int arg1) {
@@ -617,6 +642,7 @@
                 cb.onScreenTurnedOff(arg1);
             }
         }
+        stopListeningForFingerprint();
     }
 
     /**
@@ -705,9 +731,25 @@
         TrustManager trustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
         trustManager.registerTrustListener(this);
 
-        FingerprintManager fpm;
-        fpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
-        fpm.startListening(mFingerprintManagerReceiver);
+        mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
+        startListeningForFingerprint(context);
+    }
+
+    private void startListeningForFingerprint(Context context) {
+        if (mFpm != null && mFpm.isHardwareDetected()) {
+            if (mFingerprintCancelSignal == null) {
+                mFingerprintCancelSignal = new CancellationSignal();
+            } else {
+                mFingerprintCancelSignal.cancel();
+            }
+            mFpm.authenticate(null, mAuthenticationCallback, mFingerprintCancelSignal, 0);
+        }
+    }
+
+    private void stopListeningForFingerprint() {
+        if (mFingerprintCancelSignal != null) {
+            mFingerprintCancelSignal.cancel();
+        }
     }
 
     private boolean isDeviceProvisionedInSettingsDb() {
@@ -1152,7 +1194,7 @@
     }
 
     public void clearFingerprintRecognized() {
-        mUserFingerprintRecognized.clear();
+        mUserFingerprintAuthenticated.clear();
     }
 
     public void reportFailedUnlockAttempt() {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index f0e2389..c2462e0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -19,6 +19,7 @@
 import android.graphics.Bitmap;
 import android.media.AudioManager;
 import android.os.SystemClock;
+import android.service.fingerprint.FingerprintManager;
 import android.telephony.TelephonyManager;
 import android.view.WindowManagerPolicy;
 
@@ -176,14 +177,24 @@
 
     /**
      * Called when a fingerprint is recognized.
-     * @param userId
+     * @param userId the user id for which the fingerprint was authenticated
      */
-    public void onFingerprintRecognized(int userId) { }
+    public void onFingerprintAuthenticated(int userId) { }
 
     /**
-     * Called when fingerprint is acquired but not yet recognized
+     * Called when fingerprint provides help string (e.g. "Try again")
+     * @param msgId
+     * @param helpString
      */
-    public void onFingerprintAcquired(int info) { }
+    public void onFingerprintHelp(int msgId, String helpString) { }
+
+    /**
+     * Called when fingerprint provides an semi-permanent error message
+     * (e.g. "Hardware not available").
+     * @param msgId one of the error messages listed in {@link FingerprintManager}
+     * @param errString
+     */
+    public void onFingerprintError(int msgId, String errString) { }
 
     /**
      * Called when the state of face unlock changed.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 49bdfda..dd28734 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -436,7 +436,8 @@
             }
         }
 
-        public void onFingerprintRecognized(int userId) {
+        @Override
+        public void onFingerprintAuthenticated(int userId) {
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mViewMediatorCallback.keyguardDone(true);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 5ef345b..65cd268 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -125,7 +125,7 @@
         }
 
         @Override
-        public void onFingerprintRecognized(int userId) {
+        public void onFingerprintAuthenticated(int userId) {
             update(false /* updateAlways */);
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 78bd15d..3b779b7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6326,31 +6326,38 @@
         }
         try {
             PendingIntentRecord res = (PendingIntentRecord)pendingResult;
-            Intent intent = res.key.requestIntent;
-            if (intent != null) {
-                if (res.lastTag != null && res.lastTagPrefix == prefix && (res.lastTagPrefix == null
-                        || res.lastTagPrefix.equals(prefix))) {
-                    return res.lastTag;
-                }
-                res.lastTagPrefix = prefix;
-                StringBuilder sb = new StringBuilder(128);
-                if (prefix != null) {
-                    sb.append(prefix);
-                }
-                if (intent.getAction() != null) {
-                    sb.append(intent.getAction());
-                } else if (intent.getComponent() != null) {
-                    intent.getComponent().appendShortString(sb);
-                } else {
-                    sb.append("?");
-                }
-                return res.lastTag = sb.toString();
+            synchronized (this) {
+                return getTagForIntentSenderLocked(res, prefix);
             }
         } catch (ClassCastException e) {
         }
         return null;
     }
 
+    String getTagForIntentSenderLocked(PendingIntentRecord res, String prefix) {
+        final Intent intent = res.key.requestIntent;
+        if (intent != null) {
+            if (res.lastTag != null && res.lastTagPrefix == prefix && (res.lastTagPrefix == null
+                    || res.lastTagPrefix.equals(prefix))) {
+                return res.lastTag;
+            }
+            res.lastTagPrefix = prefix;
+            final StringBuilder sb = new StringBuilder(128);
+            if (prefix != null) {
+                sb.append(prefix);
+            }
+            if (intent.getAction() != null) {
+                sb.append(intent.getAction());
+            } else if (intent.getComponent() != null) {
+                intent.getComponent().appendShortString(sb);
+            } else {
+                sb.append("?");
+            }
+            return res.lastTag = sb.toString();
+        }
+        return null;
+    }
+
     @Override
     public void setProcessLimit(int max) {
         enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
@@ -10479,17 +10486,21 @@
         if (!(sender instanceof PendingIntentRecord)) {
             return;
         }
-        BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+        final PendingIntentRecord rec = (PendingIntentRecord)sender;
+        final String tag;
+        synchronized (this) {
+            tag = getTagForIntentSenderLocked(rec, "*walarm*:");
+        }
+        final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
         synchronized (stats) {
             if (mBatteryStatsService.isOnBattery()) {
                 mBatteryStatsService.enforceCallingPermission();
-                PendingIntentRecord rec = (PendingIntentRecord)sender;
                 int MY_UID = Binder.getCallingUid();
                 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
                 BatteryStatsImpl.Uid.Pkg pkg =
                     stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
                             sourcePkg != null ? sourcePkg : rec.key.packageName);
-                pkg.incWakeupsLocked();
+                pkg.noteWakeupAlarmLocked(tag);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 197b51d..80101f5 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -772,12 +772,11 @@
 
     private void dumpHelp(PrintWriter pw) {
         pw.println("Battery stats (batterystats) dump options:");
-        pw.println("  [--checkin] [--history] [--history-start] [--unplugged] [--charged] [-c]");
+        pw.println("  [--checkin] [--history] [--history-start] [--charged] [-c]");
         pw.println("  [--daily] [--reset] [--write] [--new-daily] [--read-daily] [-h] [<package.name>]");
         pw.println("  --checkin: format output for a checkin report.");
         pw.println("  --history: show only history data.");
         pw.println("  --history-start <num>: show only history data starting at given time offset.");
-        pw.println("  --unplugged: only output data since last unplugged.");
         pw.println("  --charged: only output data since last charged.");
         pw.println("  --daily: only output full daily data.");
         pw.println("  --reset: reset the stats, clearing all current data.");
@@ -856,8 +855,6 @@
                 } else if ("-c".equals(arg)) {
                     useCheckinFormat = true;
                     flags |= BatteryStats.DUMP_INCLUDE_HISTORY;
-                } else if ("--unplugged".equals(arg)) {
-                    flags |= BatteryStats.DUMP_UNPLUGGED_ONLY;
                 } else if ("--charged".equals(arg)) {
                     flags |= BatteryStats.DUMP_CHARGED_ONLY;
                 } else if ("--daily".equals(arg)) {
@@ -931,8 +928,7 @@
         if (reqUid >= 0) {
             // By default, if the caller is only interested in a specific package, then
             // we only dump the aggregated data since charged.
-            if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_UNPLUGGED_ONLY
-                    |BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
+            if ((flags&(BatteryStats.DUMP_HISTORY_ONLY|BatteryStats.DUMP_CHARGED_ONLY)) == 0) {
                 flags |= BatteryStats.DUMP_CHARGED_ONLY;
                 // Also if they are doing -c, we don't want history.
                 flags &= ~BatteryStats.DUMP_INCLUDE_HISTORY;
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index b398f41..ab56b34 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.fingerprint;
 
+import android.content.ContentResolver;
 import android.content.Context;
 import android.os.Handler;
 import android.os.IBinder;
@@ -29,12 +30,16 @@
 import com.android.server.SystemService;
 
 import android.service.fingerprint.FingerprintUtils;
+import android.service.fingerprint.Fingerprint;
 import android.service.fingerprint.IFingerprintService;
 import android.service.fingerprint.IFingerprintServiceReceiver;
+
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 import static android.Manifest.permission.USE_FINGERPRINT;
 
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -50,11 +55,14 @@
 
     private static final int MSG_NOTIFY = 10;
 
+    private static final int ENROLLMENT_TIMEOUT_MS = 60 * 1000; // 1 minute
+
     Handler mHandler = new Handler() {
         public void handleMessage(android.os.Message msg) {
             switch (msg.what) {
                 case MSG_NOTIFY:
-                    handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
+                    FpHalMsg m = (FpHalMsg) msg.obj;
+                    handleNotify(m.type, m.arg1, m.arg2, m.arg3);
                     break;
 
                 default:
@@ -66,7 +74,7 @@
     private int mHalDeviceId;
 
     private static final int STATE_IDLE = 0;
-    private static final int STATE_LISTENING = 1;
+    private static final int STATE_AUTHENTICATING = 1;
     private static final int STATE_ENROLLING = 2;
     private static final int STATE_REMOVING = 3;
     private static final long MS_PER_SEC = 1000;
@@ -76,7 +84,10 @@
         int state;
         int userId;
         public TokenWatcher tokenWatcher;
-        IBinder getToken() { return tokenWatcher.getToken(); }
+
+        IBinder getToken() {
+            return tokenWatcher.getToken();
+        }
     }
 
     private class TokenWatcher implements IBinder.DeathRecipient {
@@ -86,7 +97,10 @@
             this.token = new WeakReference<IBinder>(token);
         }
 
-        IBinder getToken() { return token.get(); }
+        IBinder getToken() {
+            return token.get();
+        }
+
         public void binderDied() {
             mClients.remove(token);
             this.token = null;
@@ -112,21 +126,42 @@
 
     // TODO: Move these into separate process
     // JNI methods to communicate from FingerprintManagerService to HAL
-    static native int nativeEnroll(int timeout);
+    static native int nativeEnroll(int timeout, int groupId);
+
+    static native int nativeAuthenticate(long sessionId, int groupId);
+
     static native int nativeEnrollCancel();
-    static native int nativeRemove(int fingerprintId);
+
+    static native int nativeRemove(int fingerId, int groupId);
+
     static native int nativeOpenHal();
+
     static native int nativeCloseHal();
+
     static native void nativeInit(MessageQueue queue, FingerprintService service);
 
-    // JNI methods for communicating from HAL to clients
-    void notify(int msg, int arg1, int arg2) {
-        mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
+    static final class FpHalMsg {
+        int type; // Type of the message. One of the constants in fingerprint.h
+        int arg1; // optional arguments
+        int arg2;
+        int arg3;
+
+        FpHalMsg(int type, int arg1, int arg2, int arg3) {
+            this.type = type;
+            this.arg1 = arg1;
+            this.arg2 = arg2;
+            this.arg3 = arg3;
+        }
     }
 
-    void handleNotify(int msg, int arg1, int arg2) {
-        Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")"
-                + ", " + mClients.size() + " clients");
+    // JNI methods for communicating from HAL to clients
+    void notify(int type, int arg1, int arg2, int arg3) {
+        mHandler.obtainMessage(MSG_NOTIFY, new FpHalMsg(type, arg1, arg2, arg3)).sendToTarget();
+    }
+
+    void handleNotify(int type, int arg1, int arg2, int arg3) {
+        Slog.v(TAG, "handleNotify(type=" + type + ", arg1=" + arg1 + ", arg2=" + arg2 + ")" + ", "
+                + mClients.size() + " clients");
         for (int i = 0; i < mClients.size(); i++) {
             if (DEBUG) Slog.v(TAG, "Client[" + i + "] binder token: " + mClients.keyAt(i));
             ClientData clientData = mClients.valueAt(i);
@@ -134,21 +169,20 @@
                 if (DEBUG) Slog.v(TAG, "clientData is invalid!!");
                 continue;
             }
-            switch (msg) {
+            ContentResolver contentResolver = mContext.getContentResolver();
+            switch (type) {
                 case FingerprintManager.FINGERPRINT_ERROR: {
-                    final int error = arg1;
                     try {
-                        clientData.receiver.onError(error);
+                        clientData.receiver.onError(mHalDeviceId, arg1 /* error */);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "can't send message to client. Did it die?", e);
                         mClients.remove(mClients.keyAt(i));
                     }
                 }
-                break;
+                    break;
                 case FingerprintManager.FINGERPRINT_ACQUIRED: {
-                    final int acquireInfo = arg1;
                     try {
-                        clientData.receiver.onAcquired(acquireInfo);
+                        clientData.receiver.onAcquired(mHalDeviceId, arg1 /* acquireInfo */);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "can't send message to client. Did it die?", e);
                         mClients.remove(mClients.keyAt(i));
@@ -156,9 +190,9 @@
                     break;
                 }
                 case FingerprintManager.FINGERPRINT_PROCESSED: {
-                    final int fingerId = arg1;
                     try {
-                        clientData.receiver.onProcessed(fingerId);
+                        clientData.receiver
+                                .onProcessed(mHalDeviceId, arg1 /* fingerId */, arg2 /* groupId */);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "can't send message to client. Did it die?", e);
                         mClients.remove(mClients.keyAt(i));
@@ -167,11 +201,13 @@
                 }
                 case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
                     final int fingerId = arg1;
-                    final int remaining = arg2;
+                    final int groupId = arg2;
+                    final int remaining = arg3;
                     if (clientData.state == STATE_ENROLLING) {
                         // Only send enroll updates to clients that are actually enrolling
                         try {
-                            clientData.receiver.onEnrollResult(fingerId, remaining);
+                            clientData.receiver.onEnrollResult(mHalDeviceId, fingerId, groupId,
+                                    remaining);
                         } catch (RemoteException e) {
                             Slog.e(TAG, "can't send message to client. Did it die?", e);
                             mClients.remove(mClients.keyAt(i));
@@ -179,8 +215,8 @@
                         // Update the database with new finger id.
                         // TODO: move to client code (Settings)
                         if (remaining == 0) {
-                            FingerprintUtils.addFingerprintIdForUser(fingerId,
-                                    mContext.getContentResolver(), clientData.userId);
+                            FingerprintUtils.addFingerprintIdForUser(contentResolver, fingerId,
+                                    clientData.userId);
                             clientData.state = STATE_IDLE; // Nothing left to do
                         }
                     } else {
@@ -191,30 +227,50 @@
                 }
                 case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
                     int fingerId = arg1;
-                    if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
-                    FingerprintUtils.removeFingerprintIdForUser(fingerId,
-                            mContext.getContentResolver(), clientData.userId);
+                    int groupId = arg2;
+                    if (fingerId == 0) {
+                        throw new IllegalStateException("Got illegal id from HAL");
+                    }
+                    FingerprintUtils.removeFingerprintIdForUser(fingerId, contentResolver,
+                            clientData.userId);
                     if (clientData.receiver != null) {
                         try {
-                            clientData.receiver.onRemoved(fingerId);
+                            clientData.receiver.onRemoved(mHalDeviceId, fingerId, groupId);
                         } catch (RemoteException e) {
                             Slog.e(TAG, "can't send message to client. Did it die?", e);
                             mClients.remove(mClients.keyAt(i));
                         }
                     }
-                    clientData.state = STATE_LISTENING;
+                    clientData.state = STATE_IDLE;
                 }
-                break;
+                    break;
             }
         }
     }
 
-    void startEnroll(IBinder token, long timeout, int userId) {
+    void startEnroll(IBinder token, int groupId, int flags) {
         ClientData clientData = mClients.get(token);
         if (clientData != null) {
-            if (clientData.userId != userId) throw new IllegalStateException("Bad user");
+            if (clientData.userId != groupId) {
+                throw new IllegalStateException("Bad user");
+            }
             clientData.state = STATE_ENROLLING;
-            nativeEnroll((int) (timeout / MS_PER_SEC));
+            final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
+            nativeEnroll(timeout, groupId);
+        } else {
+            Slog.w(TAG, "enroll(): No listener registered");
+        }
+    }
+
+    void startAuthenticate(IBinder token, long sessionId, int groupId, int flags) {
+        ClientData clientData = mClients.get(token);
+        if (clientData != null) {
+            if (clientData.userId != groupId) {
+                throw new IllegalStateException("Bad user");
+            }
+            clientData.state = STATE_AUTHENTICATING;
+            final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC);
+            nativeAuthenticate(sessionId, groupId);
         } else {
             Slog.w(TAG, "enroll(): No listener registered");
         }
@@ -224,7 +280,7 @@
         ClientData clientData = mClients.get(token);
         if (clientData != null) {
             if (clientData.userId != userId) throw new IllegalStateException("Bad user");
-            clientData.state = STATE_LISTENING;
+            clientData.state = STATE_IDLE;
             nativeEnrollCancel();
         } else {
             Slog.w(TAG, "enrollCancel(): No listener registered");
@@ -238,7 +294,7 @@
             if (clientData.userId != userId) throw new IllegalStateException("Bad user");
             clientData.state = STATE_REMOVING;
             // The fingerprint id will be removed when we get confirmation from the HAL
-            int result = nativeRemove(fingerId);
+            int result = nativeRemove(fingerId, userId);
             if (result != 0) {
                 Slog.w(TAG, "Error removing fingerprint with id = " + fingerId);
             }
@@ -251,7 +307,7 @@
         if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")");
         if (mClients.get(token) == null) {
             ClientData clientData = new ClientData();
-            clientData.state = STATE_LISTENING;
+            clientData.state = STATE_IDLE;
             clientData.receiver = receiver;
             clientData.userId = userId;
             clientData.tokenWatcher = new TokenWatcher(token);
@@ -266,7 +322,7 @@
         }
     }
 
-    void removeListener(IBinder token, int userId) {
+    void removeListener(IBinder token, IFingerprintServiceReceiver receiver) {
         if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")");
         ClientData clientData = mClients.get(token);
         if (clientData != null) {
@@ -278,61 +334,91 @@
         mClients.remove(token);
     }
 
+    public List<Fingerprint> getEnrolledFingerprints(int groupId) {
+        ContentResolver resolver = mContext.getContentResolver();
+        int[] ids = FingerprintUtils.getFingerprintIdsForUser(resolver, groupId);
+        List<Fingerprint> result = new ArrayList<Fingerprint>();
+        for (int i = 0; i < ids.length; i++) {
+            // TODO: persist names in Settings
+            CharSequence name = "Finger" + ids[i];
+            final int group = 0; // TODO
+            final int fingerId = ids[i];
+            final long deviceId = 0; // TODO
+            Fingerprint item = new Fingerprint(name, 0, ids[i], 0);
+            result.add(item);
+        }
+        return result;
+    }
+
     void checkPermission(String permission) {
-        getContext().enforceCallingOrSelfPermission(permission, "Must have "
-                + permission + " permission.");
+        getContext().enforceCallingOrSelfPermission(permission,
+                "Must have " + permission + " permission.");
     }
 
     private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
-        @Override // Binder call
-        public void enroll(IBinder token, long timeout, int userId) {
+        @Override
+        // Binder call
+        public void enroll(IBinder token, int groupId, int flags) {
             checkPermission(MANAGE_FINGERPRINT);
-            startEnroll(token, timeout, userId);
+            startEnroll(token, groupId, flags);
         }
 
-        @Override // Binder call
-        public void enrollCancel(IBinder token,int userId) {
-            checkPermission(MANAGE_FINGERPRINT);
-            startEnrollCancel(token, userId);
-        }
-
-        @Override // Binder call
-        public void remove(IBinder token, int fingerprintId, int userId) {
-            checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
-            startRemove(token, fingerprintId, userId);
-        }
-
-        @Override // Binder call
-        public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)
-        {
+        @Override 
+        // Binder call
+        public void authenticate(IBinder token, long sessionId, int groupId, int flags) {
             checkPermission(USE_FINGERPRINT);
-            addListener(token, receiver, userId);
-        }
-
-        @Override // Binder call
-        public void stopListening(IBinder token, int userId) {
-            checkPermission(USE_FINGERPRINT);
-            removeListener(token, userId);
-        }
-
-        @Override // Binder call
-        public boolean isHardwareDetected() {
-            checkPermission(USE_FINGERPRINT);
-            return mHalDeviceId != 0;
+            startAuthenticate(token, sessionId, groupId, flags);
         }
 
         @Override
-        public void rename(int fpId, String name) {
+        // Binder call
+        public void remove(IBinder token, int fingerId, int groupId) {
+            checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
+            startRemove(token, fingerId, groupId);
+        }
+
+        @Override
+        // Binder call
+        public void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
+            checkPermission(USE_FINGERPRINT);
+            FingerprintService.this.addListener(token, receiver, userId);
+        }
+
+        @Override
+        // Binder call
+        public void removeListener(IBinder token, IFingerprintServiceReceiver receiver) {
+            checkPermission(USE_FINGERPRINT);
+            FingerprintService.this.removeListener(token, receiver);
+        }
+
+        @Override
+        // Binder call
+        public boolean isHardwareDetected(long deviceId) {
+            checkPermission(USE_FINGERPRINT);
+            return mHalDeviceId != 0; // TODO
+        }
+
+        @Override
+        // Binder call
+        public void rename(int fingerId, int groupId, String name) {
             checkPermission(MANAGE_FINGERPRINT);
+            Slog.w(TAG, "rename id=" + fingerId + ",gid=" + groupId + ",name=" + name);
             // TODO
         }
+
+        @Override
+        // Binder call
+        public List<Fingerprint> getEnrolledFingerprints(int groupId) {
+            checkPermission(USE_FINGERPRINT);
+            return FingerprintService.this.getEnrolledFingerprints(groupId);
+        }
     }
 
     @Override
     public void onStart() {
-       publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
-       mHalDeviceId = nativeOpenHal();
-       if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
+        publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
+        mHalDeviceId = nativeOpenHal();
+        if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
     }
 
 }
diff --git a/services/core/jni/com_android_server_UsbMidiDevice.cpp b/services/core/jni/com_android_server_UsbMidiDevice.cpp
index 94853b8..cb70144 100644
--- a/services/core/jni/com_android_server_UsbMidiDevice.cpp
+++ b/services/core/jni/com_android_server_UsbMidiDevice.cpp
@@ -94,9 +94,20 @@
     return fds;
 }
 
+static void
+android_server_UsbMidiDevice_close(JNIEnv *env, jobject /* thiz */, jobjectArray fds)
+{
+    int count = env->GetArrayLength(fds);
+    for (int i = 0; i < count; i++) {
+        jobject fd = env->GetObjectArrayElement(fds, i);
+        close(jniGetFDFromFileDescriptor(env, fd));
+    }
+}
+
 static JNINativeMethod method_table[] = {
     { "nativeGetSubdeviceCount", "(II)I", (void*)android_server_UsbMidiDevice_get_subdevice_count },
     { "nativeOpen", "(III)[Ljava/io/FileDescriptor;", (void*)android_server_UsbMidiDevice_open },
+    { "nativeClose", "([Ljava/io/FileDescriptor;)V", (void*)android_server_UsbMidiDevice_close },
 };
 
 int register_android_server_UsbMidiDevice(JNIEnv *env)
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 23e1970..c041029 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -459,7 +459,7 @@
     }
 
    /* package */ void setPeripheralMidiState(boolean enabled, int card, int device) {
-        if (enabled) {
+        if (enabled && mPeripheralMidiDevice == null) {
             Bundle properties = new Bundle();
             Resources r = mContext.getResources();
             properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, r.getString(
@@ -469,7 +469,7 @@
             properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, card);
             properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_DEVICE, device);
             mPeripheralMidiDevice = UsbMidiDevice.create(mContext, properties, card, device);
-        } else if (mPeripheralMidiDevice != null) {
+        } else if (!enabled && mPeripheralMidiDevice != null) {
             IoUtils.closeQuietly(mPeripheralMidiDevice);
             mPeripheralMidiDevice = null;
         }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 41cf2ef..fe002a0 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -126,6 +126,8 @@
     private boolean mAdbEnabled;
     private boolean mAudioSourceEnabled;
     private boolean mMidiEnabled;
+    private int mMidiCard;
+    private int mMidiDevice;
     private Map<String, List<Pair<String, String>>> mOemModeMap;
     private String[] mAccessoryStrings;
     private UsbDebuggingManager mDebuggingManager;
@@ -623,26 +625,24 @@
         private void updateMidiFunction() {
             boolean enabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI);
             if (enabled != mMidiEnabled) {
-                int card = -1;
-                int device = -1;
-
                 if (enabled) {
                     Scanner scanner = null;
                     try {
                         scanner = new Scanner(new File(MIDI_ALSA_PATH));
-                        card = scanner.nextInt();
-                        device = scanner.nextInt();
+                        mMidiCard = scanner.nextInt();
+                        mMidiDevice = scanner.nextInt();
                     } catch (FileNotFoundException e) {
                         Slog.e(TAG, "could not open MIDI PCM file", e);
+                        enabled = false;
                     } finally {
                         if (scanner != null) {
                             scanner.close();
                         }
                     }
                 }
-                mUsbAlsaManager.setPeripheralMidiState(enabled, card, device);
                 mMidiEnabled = enabled;
             }
+            mUsbAlsaManager.setPeripheralMidiState(mMidiEnabled && mConfigured, mMidiCard, mMidiDevice);
         }
 
         @Override
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index f23bb93..3b65709 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -47,6 +47,8 @@
 
     private static final int BUFFER_SIZE = 512;
 
+    private final FileDescriptor[] mFileDescriptors;
+
     // for polling multiple FileDescriptors for MIDI events
     private final StructPollfd[] mPollFDs;
     // streams for reading from ALSA driver
@@ -69,7 +71,7 @@
             return null;
         }
 
-        UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors, fileDescriptors);
+        UsbMidiDevice midiDevice = new UsbMidiDevice(fileDescriptors);
         if (!midiDevice.register(context, properties)) {
             IoUtils.closeQuietly(midiDevice);
             Log.e(TAG, "createDeviceServer failed");
@@ -78,14 +80,15 @@
         return midiDevice;
     }
 
-    private UsbMidiDevice(FileDescriptor[] inputFiles, FileDescriptor[] outputFiles) {
-        int inputCount = inputFiles.length;
-        int outputCount = outputFiles.length;
+    private UsbMidiDevice(FileDescriptor[] fileDescriptors) {
+        mFileDescriptors = fileDescriptors;
+        int inputCount = fileDescriptors.length;
+        int outputCount = fileDescriptors.length;
 
         mPollFDs = new StructPollfd[inputCount];
         mInputStreams = new FileInputStream[inputCount];
         for (int i = 0; i < inputCount; i++) {
-            FileDescriptor fd = inputFiles[i];
+            FileDescriptor fd = fileDescriptors[i];
             StructPollfd pollfd = new StructPollfd();
             pollfd.fd = fd;
             pollfd.events = (short)OsConstants.POLLIN;
@@ -95,7 +98,7 @@
 
         mOutputStreams = new FileOutputStream[outputCount];
         for (int i = 0; i < outputCount; i++) {
-            mOutputStreams[i] = new FileOutputStream(outputFiles[i]);
+            mOutputStreams[i] = new FileOutputStream(fileDescriptors[i]);
         }
 
         mInputPortReceivers = new MidiReceiver[inputCount];
@@ -176,8 +179,10 @@
         for (int i = 0; i < mOutputStreams.length; i++) {
             mOutputStreams[i].close();
         }
+        nativeClose(mFileDescriptors);
     }
 
     private static native int nativeGetSubdeviceCount(int card, int device);
     private static native FileDescriptor[] nativeOpen(int card, int device, int subdeviceCount);
+    private static native void nativeClose(FileDescriptor[] fileDescriptors);
 }
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 22b7bb1..6fa653d 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -223,7 +223,7 @@
 
         //**********************************************************************************************
         // Next CAPABILITY value: 0x00080000
-        //**********************************************************************************************
+        //******************************************************************************************
 
         private final Uri mHandle;
         private final int mHandlePresentation;
@@ -323,7 +323,7 @@
                 builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
             }
             if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
-                builder.append(" CAPABILITY_SPEED_UP_IMS_MT_AUDIO");
+                builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
             }
             builder.append("]");
             return builder.toString();
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index a335e47..082474b 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -171,7 +171,7 @@
      * Connection is using WIFI.
      * @hide
      */
-    public static final int CAPABILITY_WIFI = 0x000010000;
+    public static final int CAPABILITY_WIFI = 0x00010000;
 
     /**
      * Indicates that the current device callback number should be shown.
@@ -292,7 +292,7 @@
             builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
         }
         if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
-            builder.append(" CAPABILITY_SPEED_UP_IMS_MT_AUDIO");
+            builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
         }
         builder.append("]");
         return builder.toString();
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b44fa6c..386b6aa 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4057,6 +4057,34 @@
    }
 
    /**
+    * Returns the Status of Volte
+    *@hide
+    */
+   public boolean isVolteEnabled() {
+       try {
+           return getITelephony().isVolteEnabled();
+       } catch (RemoteException ex) {
+           return false;
+       } catch (NullPointerException ex) {
+           return false;
+       }
+   }
+
+   /**
+    * Returns the Status of Wi-Fi Calling
+    *@hide
+    */
+   public boolean isWifiCallingEnabled() {
+       try {
+           return getITelephony().isWifiCallingEnabled();
+       } catch (RemoteException ex) {
+           return false;
+       } catch (NullPointerException ex) {
+           return false;
+       }
+   }
+
+   /**
     * Set TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC for the default phone.
     *
     * @hide
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index f9e15f3..c18e3b6 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -901,6 +901,18 @@
     boolean isImsRegistered();
 
     /**
+     * Returns the Status of Wi-Fi Calling
+     *@hide
+     */
+    boolean isWifiCallingEnabled();
+
+     /**
+     * Returns the Status of Volte
+     *@hide
+     */
+    boolean isVolteEnabled();
+
+    /**
       * Returns the unique device ID of phone, for example, the IMEI for
       * GSM and the MEID for CDMA phones. Return null if device ID is not available.
       *
diff --git a/wifi/java/android/net/wifi/IRttManager.aidl b/wifi/java/android/net/wifi/IRttManager.aidl
index d929f55..90f66c4 100644
--- a/wifi/java/android/net/wifi/IRttManager.aidl
+++ b/wifi/java/android/net/wifi/IRttManager.aidl
@@ -15,8 +15,8 @@
  */
 
 package android.net.wifi;
-
 import android.os.Messenger;
+import android.net.wifi.RttManager;
 
 /**
  * {@hide}
@@ -24,4 +24,5 @@
 interface IRttManager
 {
     Messenger getMessenger();
+    RttManager.RttCapabilities getRttCapabilities();
 }
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index bc95a36..5342494 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -155,6 +155,10 @@
 
     void setAllowScansWithTraffic(int enabled);
 
+    boolean getAllowScansWhileAssociated();
+
+    void setAllowScansWhileAssociated(boolean enabled);
+
     WifiConnectionStatistics getConnectionStatistics();
 
     void disableEphemeralNetwork(String SSID);
diff --git a/wifi/java/android/net/wifi/RttManager.aidl b/wifi/java/android/net/wifi/RttManager.aidl
new file mode 100644
index 0000000..5c6d447
--- /dev/null
+++ b/wifi/java/android/net/wifi/RttManager.aidl
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2015, 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.net.wifi;
+parcelable RttManager.RttCapabilities;
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 57343c5..65ecf5d 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -26,10 +26,19 @@
     private static final boolean DBG = true;
     private static final String TAG = "RttManager";
 
-    public static final int RTT_TYPE_UNSPECIFIED    = 0;
-    public static final int RTT_TYPE_ONE_SIDED      = 1;
-    public static final int RTT_TYPE_11_V           = 2;
-    public static final int RTT_TYPE_11_MC          = 4;
+    /** @deprecated Type must be specified*/
+    @Deprecated
+    public static final int RTT_TYPE_UNSPECIFIED        = 0;
+    public static final int RTT_TYPE_ONE_SIDED          = 1;
+
+    /** @deprecated It is not supported*/
+    @Deprecated
+    public static final int RTT_TYPE_11_V               = 2;
+    public static final int RTT_TYPE_TWO_SIDED          = 4;
+
+    /** @deprecated It is not supported*/
+    @Deprecated
+    public static final int RTT_TYPE_11_MC              = 4;
 
     public static final int RTT_PEER_TYPE_UNSPECIFIED    = 0;
     public static final int RTT_PEER_TYPE_AP             = 1;
@@ -42,6 +51,9 @@
     public static final int RTT_CHANNEL_WIDTH_80P80   = 4;
     public static final int RTT_CHANNEL_WIDTH_5       = 5;
     public static final int RTT_CHANNEL_WIDTH_10      = 6;
+
+    /** @deprecated channel info must be specified*/
+    @Deprecated
     public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1;
 
     public static final int RTT_STATUS_SUCCESS                  = 0;
@@ -53,6 +65,12 @@
     public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL  = 6;
     public static final int RTT_STATUS_FAIL_NO_CAPABILITY       = 7;
     public static final int RTT_STATUS_ABORTED                  = 8;
+    //if the T1-T4 or TOD/TOA Timestamp is illegal
+    public static final int RTT_STATUS_FAIL_INVALID_TS          = 9;
+    //11mc protocol failed, eg, unrecognized FTMR/FTM
+    public static final int RTT_STATUS_FAIL_PROTOCOL            = 10;
+    public static final int RTT_STATUS_FAIL_SCHEDULE            = 11;
+    public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER      = 12;
 
     public static final int REASON_UNSPECIFIED              = -1;
     public static final int REASON_NOT_AVAILABLE            = -2;
@@ -61,41 +79,269 @@
 
     public static final String DESCRIPTION_KEY  = "android.net.wifi.RttManager.Description";
 
+    /**
+     * RTT BW supported bit mask
+     */
+    public static final int RTT_BW_5_SUPPORT   = 0x1;
+    public static final int RTT_BW_10_SUPPORT  = 0x2;
+    public static final int RTT_BW_20_SUPPORT  = 0x4;
+    public static final int RTT_BW_40_SUPPORT  = 0x8;
+    public static final int RTT_BW_80_SUPPORT  = 0x10;
+    public static final int RTT_BW_160_SUPPORT = 0x20;
+
+    /**
+     * RTT Preamble Support bit mask
+     */
+    public static final int PREAMBLE_LEGACY  = 0x1;
+    public static final int PREAMBLE_HT      = 0x2;
+    public static final int PREAMBLE_VHT     = 0x4;
+
+    /** @deprecated It has been replaced by RttCapabilities*/
+    @Deprecated
     public class Capabilities {
         public int supportedType;
         public int supportedPeerType;
     }
 
+    /** @deprecated It has been replaced by getRttCapabilities*/
+    @Deprecated
     public Capabilities getCapabilities() {
         return new Capabilities();
     }
 
+    /**
+     * This class describe the RTT capability of the Hardware
+     */
+    public static class RttCapabilities implements Parcelable {
+        /** @deprecated It is not supported*/
+        @Deprecated
+        public boolean supportedType;
+        /** @deprecated It is not supported*/
+        @Deprecated
+        public boolean supportedPeerType;
+        //1-sided rtt measurement is supported
+        public boolean oneSidedRttSupported;
+        //11mc 2-sided rtt measurement is supported
+        public boolean twoSided11McRttSupported;
+        //location configuration information supported
+        public boolean lciSupported;
+        //location civic records supported
+        public boolean lcrSupported;
+        //preamble supported, see bit mask definition above
+        public int preambleSupported;
+        //RTT bandwidth supported
+        public int bwSupported;
+
+        @Override
+        public String toString() {
+            StringBuffer sb = new StringBuffer();
+            sb.append("oneSidedRtt ").
+            append(oneSidedRttSupported ? "is Supported. " : "is not supported. ").
+            append("twoSided11McRtt ").
+            append(twoSided11McRttSupported ? "is Supported. " : "is not supported. ").
+            append("lci ").
+            append(lciSupported ? "is Supported. " : "is not supported. ").
+            append("lcr ").
+            append(lcrSupported ? "is Supported. " : "is not supported. ");
+
+            if ((preambleSupported & PREAMBLE_LEGACY) != 0) {
+                sb.append("Legacy ");
+            }
+
+            if ((preambleSupported & PREAMBLE_HT) != 0) {
+                sb.append("HT ");
+            }
+
+            if ((preambleSupported & PREAMBLE_VHT) != 0) {
+                sb.append("VHT ");
+            }
+
+            sb.append("is supported. \n");
+
+            if ((bwSupported & RTT_BW_5_SUPPORT) != 0) {
+                sb.append("5 MHz ");
+            }
+
+            if ((bwSupported & RTT_BW_10_SUPPORT) != 0) {
+                sb.append("10 MHz ");
+            }
+
+            if ((bwSupported & RTT_BW_20_SUPPORT) != 0) {
+                sb.append("20 MHz ");
+            }
+
+            if ((bwSupported & RTT_BW_40_SUPPORT) != 0) {
+                sb.append("40 MHz ");
+            }
+
+            if ((bwSupported & RTT_BW_80_SUPPORT) != 0) {
+                sb.append("80 MHz ");
+            }
+
+            if ((bwSupported & RTT_BW_160_SUPPORT) != 0) {
+                sb.append("160 MHz ");
+            }
+
+            sb.append("is supported.");
+
+            return sb.toString();
+        }
+        /** Implement the Parcelable interface {@hide} */
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(oneSidedRttSupported ? 1 : 0);
+            dest.writeInt(twoSided11McRttSupported ? 1 : 0);
+            dest.writeInt(lciSupported ? 1 : 0);
+            dest.writeInt(lcrSupported ? 1 : 0);
+            dest.writeInt(preambleSupported);
+            dest.writeInt(bwSupported);
+
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<RttCapabilities> CREATOR =
+            new Creator<RttCapabilities>() {
+               public RttCapabilities createFromParcel(Parcel in) {
+                    RttCapabilities capabilities = new RttCapabilities();
+                    capabilities.oneSidedRttSupported = in.readInt() == 1 ? true : false;
+                        capabilities.twoSided11McRttSupported = in.readInt() == 1 ? true : false;
+                        capabilities.lciSupported = in.readInt() == 1 ? true : false;
+                        capabilities.lcrSupported = in.readInt() == 1 ? true : false;
+                        capabilities.preambleSupported = in.readInt();
+                        capabilities.bwSupported = in.readInt();
+                        return capabilities;
+                    }
+                /** Implement the Parcelable interface {@hide} */
+                @Override
+                public RttCapabilities[] newArray(int size) {
+                    return new RttCapabilities[size];
+                }
+             };
+    }
+
+    public RttCapabilities getRttCapabilities() {
+        synchronized (sCapabilitiesLock) {
+            if (mRttCapabilities == null) {
+                try {
+                    mRttCapabilities = mService.getRttCapabilities();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Can not get RTT Capabilities");
+                }
+            }
+            return mRttCapabilities;
+        }
+    }
+
     /** specifies parameters for RTT request */
     public static class RttParams {
-
-        /** type of device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA */
+        /**
+         * type of destination device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA
+         */
         public int deviceType;
 
-        /** type of RTT being sought; one of RTT_TYPE_ONE_SIDED
-         *  RTT_TYPE_11_V or RTT_TYPE_11_MC or RTT_TYPE_UNSPECIFIED */
+        /**
+         * type of RTT measurement method; one of RTT_TYPE_ONE_SIDED or RTT_TYPE_TWO_SIDED.
+         */
         public int requestType;
 
         /** mac address of the device being ranged */
         public String bssid;
 
-        /** channel frequency that the device is on; optional */
+        /**
+         * The primary 20 MHz frequency (in MHz) of the channel over which the client is
+         * communicating with the access point.Similar as ScanResult.frequency
+         */
         public int frequency;
 
-        /** optional channel width. wider channels result in better accuracy,
-         *  but they take longer time, and even get aborted may times; use
-         *  RTT_CHANNEL_WIDTH_UNSPECIFIED if not specifying */
+        /**
+         * channel width used for RTT measurement. User need verify the highest BW the destination
+         * support (from scan result etc) before set this value. Wider channels result usually give
+         * better accuracy. However, the frame loss can increase. Similar as ScanResult.channelWidth
+         */
         public int channelWidth;
 
-        /** number of samples to be taken */
+        /**
+         * Not used if the AP bandwidth is 20 MHz
+         * If the AP use 40, 80 or 160 MHz, this is the center frequency
+         * if the AP use 80 + 80 MHz, this is the center frequency of the first segment
+         * similar as ScanResult.centerFreq0
+         */
+         public int centerFreq0;
+
+         /**
+          * Only used if the AP bandwidth is 80 + 80 MHz
+          * if the AP use 80 + 80 MHz, this is the center frequency of the second segment
+          * similar as ScanResult.centerFreq1
+          */
+          public int centerFreq1;
+        /**
+         * number of samples to be taken
+         * @deprecated  It has been replaced by numSamplesPerBurst
+         */
+        @Deprecated
         public int num_samples;
 
-        /** number of retries if a sample fails */
+        /**
+         * number of retries if a sample fails
+         * @deprecated It has been replaced by numRetriesPerMeasurementFrame
+         */
+        @Deprecated
         public int num_retries;
+
+        /** Number of burst. fixed to 1 for single side RTT*/
+        public int numberBurst;
+
+        /** valid only if numberBurst > 1, interval between burst(ms). Not used by singe side RTT */
+        public int interval;
+
+        /** number of samples to be taken in one burst*/
+        public int numSamplesPerBurst;
+
+        /** number of retries for each measurement frame if a sample fails
+         *  Only used by single side RTT
+         */
+        public int numRetriesPerMeasurementFrame;
+
+        /** number of retries for FTMR frame if fails Only used by 80211MC double side RTT */
+        public int numRetriesPerFTMR;
+
+        /** Request LCI information */
+        public boolean LCIRequest;
+
+        /** Request LCR information */
+        public boolean LCRRequest;
+
+        /** Timeout for each burst, unit of 250 us*/
+        public int burstTimeout;
+
+        /** preamble used for RTT measurement
+         *  should be one of PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT
+         */
+        public int preamble;
+
+        /** bandWidth used for RTT measurement.User need verify the highest BW the destination
+         * support (from scan result etc) before set this value. Wider channels result usually give
+         * better accuracy. However, the frame loss can increase too.
+         * should be one of RTT_CHANNEL_WIDTH_20 to RTT_CHANNEL_WIDTH_80
+         */
+        public int bandwidth;
+
+        public RttParams() {
+            //provide initial value for RttParams
+            deviceType = RTT_PEER_TYPE_AP;
+            numberBurst = 1;
+            numSamplesPerBurst = 8;
+            numRetriesPerMeasurementFrame  = 0;
+            burstTimeout = 40 + numSamplesPerBurst *4;
+            preamble = PREAMBLE_LEGACY;
+            bandwidth = RTT_CHANNEL_WIDTH_20;
+        }
     }
 
     /** pseudo-private class used to parcel arguments */
@@ -121,10 +367,20 @@
                     dest.writeInt(params.deviceType);
                     dest.writeInt(params.requestType);
                     dest.writeString(params.bssid);
-                    dest.writeInt(params.frequency);
                     dest.writeInt(params.channelWidth);
-                    dest.writeInt(params.num_samples);
-                    dest.writeInt(params.num_retries);
+                    dest.writeInt(params.frequency);
+                    dest.writeInt(params.centerFreq0);
+                    dest.writeInt(params.centerFreq1);
+                    dest.writeInt(params.numberBurst);
+                    dest.writeInt(params.interval);
+                    dest.writeInt(params.numSamplesPerBurst);
+                    dest.writeInt(params.numRetriesPerMeasurementFrame);
+                    dest.writeInt(params.numRetriesPerFTMR);
+                    dest.writeInt(params.LCIRequest ? 1 : 0);
+                    dest.writeInt(params.LCRRequest ? 1 : 0);
+                    dest.writeInt(params.burstTimeout);
+                    dest.writeInt(params.preamble);
+                    dest.writeInt(params.bandwidth);
                 }
             } else {
                 dest.writeInt(0);
@@ -148,11 +404,20 @@
                             params[i].deviceType = in.readInt();
                             params[i].requestType = in.readInt();
                             params[i].bssid = in.readString();
-                            params[i].frequency = in.readInt();
                             params[i].channelWidth = in.readInt();
-                            params[i].num_samples = in.readInt();
-                            params[i].num_retries = in.readInt();
-
+                            params[i].frequency = in.readInt();
+                            params[i].centerFreq0 = in.readInt();
+                            params[i].centerFreq1 = in.readInt();
+                            params[i].numberBurst = in.readInt();
+                            params[i].interval = in.readInt();
+                            params[i].numSamplesPerBurst = in.readInt();
+                            params[i].numRetriesPerMeasurementFrame = in.readInt();
+                            params[i].numRetriesPerFTMR = in.readInt();
+                            params[i].LCIRequest = in.readInt() == 1 ? true : false;
+                            params[i].LCRRequest = in.readInt() == 1 ? true : false;
+                            params[i].burstTimeout = in.readInt();
+                            params[i].preamble = in.readInt();
+                            params[i].bandwidth = in.readInt();
                         }
 
                         ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
@@ -165,46 +430,143 @@
                 };
     }
 
+    public class wifiInformationElement {
+        /** Information Element ID*/
+        public int id;
+        public String data;
+    }
     /** specifies RTT results */
     public static class RttResult {
         /** mac address of the device being ranged */
         public String bssid;
 
+        /** # of burst for this measurement*/
+        public int burstNumber;
+
+        /** total number of measurement frames in this measurement*/
+        public int measurementFrameNumber;
+
+        /** total successful number of measurement frames in this measurement*/
+        public int successMeasurementFrameNumber;
+
+        /** Maximum number of frames per burst supported by peer */
+        public int frameNumberPerBurstPeer;
+
         /** status of the request */
         public int status;
 
-        /** type of the request used */
+        /**
+         * type of the request used
+         * @deprecated It has been replaced by measurementType
+         */
+        @Deprecated
         public int requestType;
 
+        /** RTT measurement method type used, shoudl be one of RTT_TYPE_ONE_SIDED or
+         *  RTT_TYPE_TWO_SIDED.
+         */
+        public int measurementType;
+
+        /** please retry RTT measurement after this S since peer indicate busy at ths moment*/
+        public int retryAfterDuration;
+
         /** timestamp of completion, in microsecond since boot */
         public long ts;
 
-        /** average RSSI observed */
+        /** average RSSI observed, unit of 0.5 dB */
         public int rssi;
 
-        /** RSSI spread (i.e. max - min) */
+        /**
+         * RSSI spread (i.e. max - min)
+         * @deprecated It has been replaced by rssi_spread
+         */
+        @Deprecated
         public int rssi_spread;
 
-        /** average transmit rate */
+        /**RSSI spread (i.e. max - min), unit of 0.5 dB */
+        public int rssiSpread;
+
+        /**
+         * average transmit rate
+         * @deprecated It has been replaced by txRate
+         */
+        @Deprecated
         public int tx_rate;
 
-        /** average round trip time in nano second */
+        /** average transmit rate */
+        public int txRate;
+
+        /** average receiving rate */
+        public int rxRate;
+
+       /**
+        * average round trip time in nano second
+        * @deprecated  It has been replaced by rtt
+        */
+        @Deprecated
         public long rtt_ns;
 
-        /** standard deviation observed in round trip time */
+        /** average round trip time in 0.1 nano second */
+        public long rtt;
+
+        /**
+         * standard deviation observed in round trip time
+         * @deprecated It has been replaced by rttStandardDeviation
+         */
+        @Deprecated
         public long rtt_sd_ns;
 
-        /** spread (i.e. max - min) round trip time */
+        /** standard deviation of RTT in 0.1 ns */
+        public long rttStandardDeviation;
+
+        /**
+         * spread (i.e. max - min) round trip time
+         * @deprecated It has been replaced by rttSpread
+         */
+        @Deprecated
         public long rtt_spread_ns;
 
-        /** average distance in centimeter, computed based on rtt_ns */
+        /** spread (i.e. max - min) RTT in 0.1 ns */
+        public long rttSpread;
+
+        /**
+         * average distance in centimeter, computed based on rtt_ns
+         * @deprecated It has been replaced by distance
+         */
+        @Deprecated
         public int distance_cm;
 
-        /** standard deviation observed in distance */
+        /** average distance in cm, computed based on rtt */
+        public int distance;
+
+        /**
+         * standard deviation observed in distance
+         * @deprecated It has been replaced with distanceStandardDeviation
+         */
+        @Deprecated
         public int distance_sd_cm;
 
-        /** spread (i.e. max - min) distance */
+        /** standard deviation observed in distance in cm*/
+        public int distanceStandardDeviation;
+
+        /**
+         * spread (i.e. max - min) distance
+         * @deprecated It has been replaced by distanceSpread
+         */
+        @Deprecated
         public int distance_spread_cm;
+
+        /** spread (i.e. max - min) distance in cm */
+        public int distanceSpread;
+
+        /** the duration of this measurement burst*/
+        public int burstDuration;
+
+        /** LCI information Element*/
+        wifiInformationElement LCI;
+
+        /** LCR information Element*/
+        wifiInformationElement LCR;
     }
 
 
@@ -228,18 +590,28 @@
                 dest.writeInt(mResults.length);
                 for (RttResult result : mResults) {
                     dest.writeString(result.bssid);
+                    dest.writeInt(result.burstNumber);
+                    dest.writeInt(result.measurementFrameNumber);
+                    dest.writeInt(result.successMeasurementFrameNumber);
+                    dest.writeInt(result.frameNumberPerBurstPeer);
                     dest.writeInt(result.status);
-                    dest.writeInt(result.requestType);
+                    dest.writeInt(result.measurementType);
+                    dest.writeInt(result.retryAfterDuration);
                     dest.writeLong(result.ts);
                     dest.writeInt(result.rssi);
-                    dest.writeInt(result.rssi_spread);
-                    dest.writeInt(result.tx_rate);
-                    dest.writeLong(result.rtt_ns);
-                    dest.writeLong(result.rtt_sd_ns);
-                    dest.writeLong(result.rtt_spread_ns);
-                    dest.writeInt(result.distance_cm);
-                    dest.writeInt(result.distance_sd_cm);
-                    dest.writeInt(result.distance_spread_cm);
+                    dest.writeInt(result.rssiSpread);
+                    dest.writeInt(result.txRate);
+                    dest.writeLong(result.rtt);
+                    dest.writeLong(result.rttStandardDeviation);
+                    dest.writeLong(result.rttSpread);
+                    dest.writeInt(result.distance);
+                    dest.writeInt(result.distanceStandardDeviation);
+                    dest.writeInt(result.distanceSpread);
+                    dest.writeInt(result.burstDuration);
+                    //dest.writeInt(result.LCI.id);
+                    //dest.writeString(result.LCI.data);
+                    //dest.writeInt(result.LCR.id);
+                    //dest.writeString(result.LCR.data);
                 }
             } else {
                 dest.writeInt(0);
@@ -261,18 +633,28 @@
                         for (int i = 0; i < num; i++) {
                             results[i] = new RttResult();
                             results[i].bssid = in.readString();
+                            results[i].burstNumber = in.readInt();
+                            results[i].measurementFrameNumber = in.readInt();
+                            results[i].successMeasurementFrameNumber = in.readInt();
+                            results[i].frameNumberPerBurstPeer = in.readInt();
                             results[i].status = in.readInt();
-                            results[i].requestType = in.readInt();
+                            results[i].measurementType = in.readInt();
+                            results[i].retryAfterDuration = in.readInt();
                             results[i].ts = in.readLong();
                             results[i].rssi = in.readInt();
-                            results[i].rssi_spread = in.readInt();
-                            results[i].tx_rate = in.readInt();
-                            results[i].rtt_ns = in.readLong();
-                            results[i].rtt_sd_ns = in.readLong();
-                            results[i].rtt_spread_ns = in.readLong();
-                            results[i].distance_cm = in.readInt();
-                            results[i].distance_sd_cm = in.readInt();
-                            results[i].distance_spread_cm = in.readInt();
+                            results[i].rssiSpread = in.readInt();
+                            results[i].txRate = in.readInt();
+                            results[i].rtt = in.readLong();
+                            results[i].rttStandardDeviation = in.readLong();
+                            results[i].rttSpread = in.readLong();
+                            results[i].distance = in.readInt();
+                            results[i].distanceStandardDeviation = in.readInt();
+                            results[i].distanceSpread = in.readInt();
+                            results[i].burstDuration = in.readInt();
+                            //results[i].LCI.id = in.readInt();
+                            //results[i].LCI.data = in.readString();
+                            //results[i].LCR.id = in.readInt();
+                            //results[i].LCR.data = in.readString();
                         }
 
                         ParcelableRttResults parcelableResults = new ParcelableRttResults(results);
@@ -292,7 +674,70 @@
         public void onAborted();
     }
 
+    private boolean rttParamSanity(RttParams params, int index) {
+        if (mRttCapabilities == null) {
+            if(getRttCapabilities() == null) {
+                Log.e(TAG, "Can not get RTT capabilities");
+                //throw new IllegalStateException("RTT chip is not working");
+            }
+        }
+
+        if (params.deviceType != RTT_PEER_TYPE_AP) {
+            return false;
+        } else if (params.requestType != RTT_TYPE_ONE_SIDED && params.requestType !=
+                RTT_TYPE_TWO_SIDED) {
+            Log.e(TAG, "Request " + index + ": Illegal Request Type: " + params.requestType);
+            return false;
+        } else if (params.requestType == RTT_TYPE_ONE_SIDED &&
+                !mRttCapabilities.oneSidedRttSupported) {
+            Log.e(TAG, "Request " + index + ": One side RTT is not supported");
+            return false;
+        } else if (params.requestType == RTT_TYPE_TWO_SIDED &&
+                !mRttCapabilities.twoSided11McRttSupported) {
+            Log.e(TAG, "Request " + index + ": two side RTT is not supported");
+            return false;
+        } else if ( params.numberBurst <= 0 ) {
+            Log.e(TAG, "Request " + index + ": Illegal number of burst: " + params.numberBurst);
+            return false;
+        } else if (params.numberBurst >  1 && params.interval <= 0) {
+            Log.e(TAG, "Request " + index + ": Illegal interval value: " + params.interval);
+            return false;
+        } else if (params.numSamplesPerBurst <= 0) {
+            Log.e(TAG, "Request " + index + ": Illegal sample number per burst: " +
+                    params.numSamplesPerBurst);
+            return false;
+        } else if (params.numRetriesPerMeasurementFrame < 0 || params.numRetriesPerFTMR < 0) {
+            Log.e(TAG, "Request " + index + ": Illegal retry number");
+            return false;
+        } else if (params.LCIRequest && !mRttCapabilities.lciSupported) {
+            Log.e(TAG, "Request " + index + ": LCI is not supported");
+            return false;
+        } else if (params.LCRRequest && !mRttCapabilities.lcrSupported) {
+            Log.e(TAG, "Request " + index + ": LCR is not supported");
+            return false;
+        } else if (params.burstTimeout <= 0){
+            Log.e(TAG, "Request " + index + ": Illegal burst timeout: " + params.burstTimeout);
+            return false;
+        } else if ((params.preamble & mRttCapabilities.preambleSupported) == 0) {
+            Log.e(TAG, "Request " + index + ": Do not support this preamble: " + params.preamble);
+            return false;
+        } else if ((params.bandwidth & mRttCapabilities.bwSupported) == 0) {
+            Log.e(TAG, "Request " + index + ": Do not support this bandwidth: " + params.bandwidth);
+            return false;
+        }
+
+        return true;
+    }
+
     public void startRanging(RttParams[] params, RttListener listener) {
+        int index  = 0;
+        for(RttParams rttParam : params) {
+            if (!rttParamSanity(rttParam, index)) {
+                throw new IllegalArgumentException("RTT Request Parameter Illegal");
+            }
+            index++;
+        }
+
         validateChannel();
         ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
         sAsyncChannel.sendMessage(CMD_OP_START_RANGING,
@@ -315,12 +760,14 @@
 
     private Context mContext;
     private IRttManager mService;
+    private RttCapabilities mRttCapabilities;
 
     private static final int INVALID_KEY = 0;
     private static int sListenerKey = 1;
 
     private static final SparseArray sListenerMap = new SparseArray();
     private static final Object sListenerMapLock = new Object();
+    private static final Object sCapabilitiesLock = new Object();
 
     private static AsyncChannel sAsyncChannel;
     private static CountDownLatch sConnected;
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index b4f4927..e8a51e3 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -16,8 +16,6 @@
 
 package android.net.wifi;
 
-import android.net.wifi.passpoint.WifiPasspointInfo;
-import android.net.wifi.passpoint.WifiPasspointManager;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -215,11 +213,19 @@
     public int distanceSdCm;
 
     /**
-     * Passpoint ANQP information. This is not fetched automatically.
-     * Use {@link WifiPasspointManager#requestAnqpInfo} to request ANQP info.
-     * {@hide}
+     * Indicates if the scan result represents a passpoint AP
      */
-    public WifiPasspointInfo passpoint;
+    public boolean passpointNetwork;
+
+    /**
+     * Indicates if venue name
+     */
+    public String venueName;
+
+    /**
+     * Indicates operator name
+     */
+    public String operatorFriendlyName;
 
     /**
      * {@hide}
@@ -292,6 +298,7 @@
         this.centerFreq0 = UNSPECIFIED;
         this.centerFreq1 = UNSPECIFIED;
         this.is80211McRTTResponder = false;
+        this.passpointNetwork = false;
     }
 
     /** {@hide} */
@@ -310,6 +317,7 @@
         this.centerFreq0 = UNSPECIFIED;
         this.centerFreq1 = UNSPECIFIED;
         this.is80211McRTTResponder = false;
+        this.passpointNetwork = false;
     }
 
     /** {@hide} */
@@ -329,6 +337,7 @@
         this.centerFreq0 = centerFreq0;
         this.centerFreq1 = centerFreq1;
         this.is80211McRTTResponder = is80211McRTTResponder;
+        this.passpointNetwork = false;
     }
 
     /** copy constructor {@hide} */
@@ -348,13 +357,15 @@
             distanceCm = source.distanceCm;
             distanceSdCm = source.distanceSdCm;
             seen = source.seen;
-            passpoint = source.passpoint;
             autoJoinStatus = source.autoJoinStatus;
             untrusted = source.untrusted;
             numConnection = source.numConnection;
             numUsage = source.numUsage;
             numIpConfigFailures = source.numIpConfigFailures;
             isAutoJoinCandidate = source.isAutoJoinCandidate;
+            passpointNetwork = source.passpointNetwork;
+            venueName = source.venueName;
+            operatorFriendlyName = source.operatorFriendlyName;
         }
     }
 
@@ -388,7 +399,7 @@
         sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
                 append("(cm)");
 
-        sb.append(", passpoint: ").append(passpoint != null ? "yes" : "no");
+        sb.append(", passpoint: ").append(passpointNetwork ? "yes" : "no");
         if (autoJoinStatus != 0) {
             sb.append(", status: ").append(autoJoinStatus);
         }
@@ -431,12 +442,10 @@
         dest.writeInt(numUsage);
         dest.writeInt(numIpConfigFailures);
         dest.writeInt(isAutoJoinCandidate);
-        if (passpoint != null) {
-            dest.writeInt(1);
-            passpoint.writeToParcel(dest, flags);
-        } else {
-            dest.writeInt(0);
-        }
+        dest.writeInt(passpointNetwork ? 1 : 0);
+        dest.writeString(venueName);
+        dest.writeString(operatorFriendlyName);
+
         if (informationElements != null) {
             dest.writeInt(informationElements.length);
             for (int i = 0; i < informationElements.length; i++) {
@@ -478,9 +487,9 @@
                 sr.numUsage = in.readInt();
                 sr.numIpConfigFailures = in.readInt();
                 sr.isAutoJoinCandidate = in.readInt();
-                if (in.readInt() == 1) {
-                    sr.passpoint = WifiPasspointInfo.CREATOR.createFromParcel(in);
-                }
+                sr.passpointNetwork = in.readInt() == 1;
+                sr.venueName = in.readString();
+                sr.operatorFriendlyName = in.readString();
                 int n = in.readInt();
                 if (n != 0) {
                     sr.informationElements = new InformationElement[n];
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 7e04f2b..11bdebb 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -973,13 +973,18 @@
             }
         }
 
-        if (FQDN != null) {
-            /* must have a providerFriendlyName */
-            if (providerFriendlyName == null) {
+        if (TextUtils.isEmpty(FQDN) == false) {
+            /* this is passpoint configuration; it must not have an SSID */
+            if (TextUtils.isEmpty(SSID) == false) {
+                return false;
+            }
+            /* this is passpoint configuration; it must have a providerFriendlyName */
+            if (TextUtils.isEmpty(providerFriendlyName)) {
                 return false;
             }
             /* this is passpoint configuration; it must have enterprise config */
-            if (enterpriseConfig == null) {
+            if (enterpriseConfig == null
+                    || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
                 return false;
             }
         }
@@ -989,6 +994,16 @@
     }
 
     /**
+     * Identify if this configuration represents a passpoint network
+     */
+    public boolean isPasspoint() {
+        return !TextUtils.isEmpty(FQDN)
+                && !TextUtils.isEmpty(providerFriendlyName)
+                && enterpriseConfig != null
+                && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
+    }
+
+    /**
      * Helper function, identify if a configuration is linked
      * @hide
      */
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index b292c22..e1460ef 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2598,6 +2598,27 @@
         }
     }
 
+    /**
+     * Set setting for allowing Scans when infrastructure is associated
+     * @hide
+     */
+    public void setAllowScansWhileAssociated(boolean enabled) {
+        try {
+            mService.setAllowScansWhileAssociated(enabled);
+        } catch (RemoteException e) {
 
+        }
+    }
 
+    /**
+     * Get setting for allowing Scans when infrastructure is associated
+     * @hide
+     */
+    public boolean getAllowScansWhileAssociated() {
+        try {
+            return mService.getAllowScansWhileAssociated();
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
 }
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
index b9b17eb..0245a3d 100644
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -262,7 +262,7 @@
                 for (ScanResult sr : mAnqpRequest)
                     if (sr.BSSID.equals(result.bssid)) {
                         Log.d(TAG, "find hit " + result.bssid);
-                        sr.passpoint = result;
+                        /* sr.passpoint = result; */
                         mAnqpRequest.remove(sr);
                         Log.d(TAG, "mAnqpRequest.len=" + mAnqpRequest.size());
                         break;